~ubuntu-branches/debian/squeeze/erlang/squeeze

« back to all changes in this revision

Viewing changes to lib/hipe/icode/hipe_icode_range_an.erl

  • Committer: Bazaar Package Importer
  • Author(s): Erlang Packagers, Sergei Golovan
  • Date: 2006-12-03 17:07:44 UTC
  • mfrom: (2.1.11 feisty)
  • Revision ID: james.westby@ubuntu.com-20061203170744-rghjwupacqlzs6kv
Tags: 1:11.b.2-4
[ Sergei Golovan ]
Fixed erlang-base and erlang-base-hipe prerm scripts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
%% -*- erlang-indent-level: 2 -*-
 
2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
3
%%
 
4
%% @doc This module performs integer range analysis on ICode.
 
5
%%
 
6
%% <h3>Purpose</h3>
 
7
%%
 
8
%% <p>iterating, fixing and adding in a happily manner.</p>
 
9
%%
 
10
%% @end
 
11
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
12
 
 
13
-module(hipe_icode_range_an).
 
14
 
 
15
-export([init/4]).
 
16
-export([to_string/1]).
 
17
 
 
18
 
 
19
-define(LABELITERATIONS, 10).
 
20
-define(PHIWIDENING, 4). %< LABELITERATIONS
 
21
-define(FUNCTION_FIXPOINT_DEPTH, 5).
 
22
 
 
23
%-define(not_done_debug, fun(X, Y) -> io:format(X, Y) end).
 
24
-define(not_done_debug, fun(_, _) -> ok end).
 
25
 
 
26
%-define(call_or_enter_debug, fun(X, Y) -> io:format(X, Y) end).
 
27
-define(call_or_enter_debug, fun(_, _) -> ok end).
 
28
 
 
29
%todo snodd
 
30
-define(TAG_IMMED1_SIZE, 4).
 
31
 
 
32
-define(BITS, (hipe_rtl_arch:word_size() bsl 3) - ?TAG_IMMED1_SIZE).
 
33
-define(FIXNUM_UPPER, ((1 bsl (?BITS - 1)) - 1)).
 
34
-define(FIXNUM_LOWER, -(1 bsl (?BITS - 1))).
 
35
-define(MAX_BYTE, 255).
 
36
-define(MAX_CHAR, 16#10ffff).
 
37
 
 
38
-include("hipe_icode.hrl").
 
39
-include("../main/hipe.hrl").
 
40
 
 
41
 
 
42
%-define(DEBUG, false).
 
43
 
 
44
 
 
45
%% This record is used when returning information
 
46
-record(range_info, {live_labels, 
 
47
                     in_label_range_trees,
 
48
                     out_label_range_trees,
 
49
                     return_points,
 
50
                     warn
 
51
                    }). 
 
52
 
 
53
%% This record is used by the range analyser
 
54
-record(info_struct, {worklist, 
 
55
                      phi_values=gb_trees:empty(), 
 
56
                      range_trees=gb_trees:empty(),
 
57
                      pred_trees=gb_trees:empty(),
 
58
                      current_range_tree=gb_trees:empty(),
 
59
                      current_label,
 
60
                      is_recursive=false,
 
61
                      current_mfa,
 
62
                      current_mfa_not_done=false,
 
63
                      label_counters=gb_trees:empty(),
 
64
                      return_vars=[],
 
65
                      predmap,
 
66
                      liveness,
 
67
                      live_labels=gb_sets:empty(),
 
68
                      startlabel,
 
69
                      wideningvalues=[posinf, neginf], 
 
70
                      server,
 
71
                      warn
 
72
                     }).
 
73
 
 
74
%% This is the representation of a range.
 
75
-record(var_range, {var_name,
 
76
                    range=empty,
 
77
                    other
 
78
                   }).
 
79
 
 
80
%%
 
81
%% Init
 
82
%%
 
83
%% Initializes the analysis
 
84
%%
 
85
 
 
86
init(IC, Options, Server, MFA) ->  
 
87
  %%io:format("analysing ~p ~n", [MFA]),
 
88
  %%hipe_icode_pp:pp(hipe_icode_cfg:cfg_to_linear(IC)),
 
89
  case info_struct__init(IC, Server, Options, MFA) of
 
90
    break ->
 
91
      none;
 
92
    Info ->
 
93
      Info2 = analyse_icode(IC, Info),
 
94
      case info_struct__current_mfa_not_done(Info2) of 
 
95
        true ->
 
96
          server__update_return_value(Info2),
 
97
          not_fixpoint;
 
98
        false ->
 
99
          server__update_return_value(Info2), % I Know :)
 
100
          Range_info = range_info_from_info_struct(Info2),      
 
101
          %% Specialization
 
102
          SpecIC = specialize_IC(IC, Range_info),
 
103
          %% Optional annotation phase controlled by a compiler option
 
104
          case proplists:get_bool(icode_range_analysis_annotate, Options) of
 
105
            true ->
 
106
              NewIC = annotate_IC(SpecIC, Range_info),
 
107
              print_icode_to_file(NewIC, Info2);
 
108
            false ->
 
109
              ok
 
110
          end,
 
111
          case proplists:get_bool(icode_range_analysis_insn_count, Options) of
 
112
            true ->
 
113
              Old = hipe_icode_instruction_counter:cfg(IC, MFA, Options),
 
114
              New = hipe_icode_instruction_counter:cfg(SpecIC, MFA, Options),
 
115
              hipe_icode_instruction_counter:compare(MFA, Old, New);
 
116
            false ->
 
117
              ok
 
118
          end,    
 
119
          SpecIC
 
120
      end
 
121
  end.
 
122
 
 
123
%%
 
124
%% Server
 
125
%%
 
126
%% Handles communication with the information server
 
127
%%
 
128
 
 
129
server__update_return_value(Info) ->
 
130
  Return_range = return_range(Info),
 
131
  Return_range_is_not_set = var_range__is_empty(Return_range) andalso var_range__is_not_other(Return_range),
 
132
  MFA = info_struct__current_mfa(Info),
 
133
  Not_done = info_struct__current_mfa_not_done(Info),
 
134
  Server = info_struct__server(Info),
 
135
  %%io:format("MFA ~p ~p ~n", [MFA, Return_range]),
 
136
  if not Return_range_is_not_set ->
 
137
      %% We are performing an update
 
138
 
 
139
 
 
140
      Wideningvalues = info_struct__wideningvalues(Info),
 
141
 
 
142
      Fun = fun (MessageTree) ->
 
143
                Key = {MFA, return_range},
 
144
                {State, Prev_return_range} = 
 
145
                  case gb_trees:lookup(Key, MessageTree) of
 
146
                    none ->
 
147
                      {0, range_init(return_range, empty, false)};
 
148
                    {value, {Lookup_return_range, Prev_state}} ->
 
149
                      {Prev_state, Lookup_return_range}
 
150
                  end,
 
151
                Fixed_return_range = 
 
152
                  if (State > ?FUNCTION_FIXPOINT_DEPTH) ->
 
153
                      range_widening(Prev_return_range, Return_range, 
 
154
                                     Wideningvalues);
 
155
                     true ->
 
156
                      Return_range
 
157
                  end, 
 
158
                Is_not_updated = var_range__is_equal(Fixed_return_range, 
 
159
                                                     Prev_return_range),
 
160
                A= 
 
161
                if Is_not_updated -> 
 
162
                    MessageTree;
 
163
                   true -> 
 
164
                    gb_trees:enter(Key, {Fixed_return_range, State + 1}, 
 
165
                                   MessageTree)
 
166
                end,
 
167
                %%io:format("A ~p ~n", [A]),
 
168
                A
 
169
            end,
 
170
      Server ! {self(), {transaction, Fun}};
 
171
    not Not_done ->
 
172
      Fun = fun(MessageTree) ->
 
173
                
 
174
                Key = {MFA, return_range},
 
175
                Any = range_init(return_range, {neginf, posinf}, true),
 
176
                  case gb_trees:lookup(Key, MessageTree) of
 
177
                    none ->
 
178
                      %%io:format("no returnpoints ~p ~n", [MFA]),
 
179
                      gb_trees:enter(Key, {Any, 1}, 
 
180
                                     MessageTree);
 
181
                    {value, _Val} ->
 
182
                      MessageTree
 
183
                  end
 
184
            end,
 
185
      Server ! {self(), {transaction, Fun}};
 
186
     true ->
 
187
      ok
 
188
  end.
 
189
 
 
190
server__update_call_args(MFA, Args, Info) -> %% TODO Needs comments
 
191
  Server = info_struct__server(Info),
 
192
  Server ! {self(), {load, message, {MFA, args}}},
 
193
  Rename_fun = fun(Arg) -> 
 
194
                   var_range__copy(get_range_from_arg(Arg, Info), param) 
 
195
               end,
 
196
  receive
 
197
    none ->
 
198
      Lookup_state = 0,
 
199
      Args_updated = true,
 
200
      Insert_args = lists:map(Rename_fun, Args);
 
201
    {value, {Lookup_args, Lookup_state}} ->
 
202
      %% io:format("Lookup_args ~p ~n MFA ~p ~n", [Lookup_args, MFA]),
 
203
      Arg_ranges = lists:map(Rename_fun, Args), %% this isn't needed
 
204
      Tuple_args_list = lists:zipwith(fun(X, Y) -> [X,Y] end,
 
205
                                      Arg_ranges, Lookup_args),
 
206
      %% io:format("Tuple ~p ~n", [Tuple_args_list]),
 
207
      Union_args = lists:map(fun(Ranges) -> range_union(param, Ranges) end,
 
208
                             Tuple_args_list),
 
209
      %% io:format("Lookup state ~p ~n", [Lookup_state]),
 
210
      Insert_args = 
 
211
        if Lookup_state > ?FUNCTION_FIXPOINT_DEPTH ->
 
212
            Widening_range_list = lists:zip(Lookup_args, Union_args),
 
213
            Wideningvalues = info_struct__wideningvalues(Info),
 
214
            Widened_ranges = lists:map(
 
215
                  fun({Old_range, New_range}) ->
 
216
                      range_widening(Old_range, New_range, Wideningvalues)
 
217
                  end,
 
218
                  Widening_range_list),
 
219
            %% io:format("New_wided ~p ~n", [R]),
 
220
            Widened_ranges;
 
221
           true ->
 
222
            Union_args
 
223
        end,
 
224
      Range_tuple_list = lists:zip(Insert_args, Lookup_args),
 
225
      Args_updated = lists:foldl(
 
226
                       fun({Range1, Range2}, Bool) ->
 
227
                           (Range1 =/= Range2) or Bool
 
228
                       end,
 
229
                       false,
 
230
                       Range_tuple_list)
 
231
  end,
 
232
  %% io:format("~p Insert_args: ~p ~n Args_updated ~p ~n", [MFA, Insert_args, Args_updated]),
 
233
  New_info=
 
234
    if Args_updated ->
 
235
        ?not_done_debug("server_update_args break ~n", []),
 
236
        %%io:format("~p insert args ~p ~n", [MFA, Insert_args]),
 
237
        Server ! {self(), {message, {MFA, args}, {Insert_args, Lookup_state + 1}}},
 
238
        
 
239
        info_struct__set_current_mfa_not_done(Info, true);
 
240
       true ->
 
241
        Info
 
242
    end,
 
243
  New_info.
 
244
 
 
245
 
 
246
%%--------------------------------------------------------------------------
 
247
%% Icode helper functions
 
248
%%--------------------------------------------------------------------------
 
249
 
 
250
unannotate_var(An_var) ->
 
251
  case hipe_icode:is_annotated_var(An_var) of
 
252
    true ->
 
253
      hipe_icode:unannotate_var(An_var);
 
254
    false ->
 
255
      An_var
 
256
  end.
 
257
 
 
258
name_from_icode_var(An_var) ->
 
259
  Var = unannotate_var(An_var),
 
260
  case hipe_icode:is_var(Var) of
 
261
    true ->
 
262
      hipe_icode:var_name(Var);
 
263
    false ->
 
264
      case Var of 
 
265
        {reg, N} ->
 
266
          {reg, N};
 
267
        {const, _} ->
 
268
          const;
 
269
        _ ->
 
270
          {f, hipe_icode:fvar_name(Var)}
 
271
      end
 
272
      %% constants??
 
273
  end.
 
274
 
 
275
get_range_from_args(Arglist, Info) ->
 
276
  lists:map(fun (Arg) -> get_range_from_arg(Arg, Info) end, Arglist).
 
277
 
 
278
get_range_from_arg(Arg, Info) ->
 
279
  %% TODO: Constants annotated ??
 
280
  UnannoArg = unannotate_var(Arg),
 
281
  case hipe_icode:is_const(UnannoArg) of
 
282
    true ->
 
283
      Value = hipe_icode:const_value(UnannoArg),
 
284
      case is_integer(Value) of
 
285
        true ->
 
286
          range_init(const, {Value, Value}, false);
 
287
        false ->
 
288
          range_init(const, empty, true)
 
289
      end;
 
290
    false -> % It is a variable
 
291
      case hipe_icode:is_fvar(Arg) of
 
292
        true ->
 
293
          range_init(Arg, empty, true);
 
294
        false ->        
 
295
          Var_name = name_from_icode_var(UnannoArg),
 
296
          info_struct__get_range(Var_name, Info)
 
297
      end
 
298
  end.
 
299
        
 
300
int_range_from_number_val(Number) ->
 
301
  case Number of 
 
302
    any ->
 
303
      {neginf, posinf};
 
304
    N when is_integer(N) ->
 
305
      {N, N};
 
306
    none ->
 
307
      empty
 
308
  end.
 
309
 
 
310
int_range_from_number_vals([]) -> empty;
 
311
int_range_from_number_vals([First_number|Numbers]) ->
 
312
  The_union =
 
313
    fun(Number_val, Acc) ->
 
314
        case Acc of
 
315
          {Min2, Max2} ->
 
316
            case int_range_from_number_val(Number_val) of
 
317
              {Min1, Max1} ->
 
318
                New_min = inf_min([Min1, Min2]),
 
319
                New_max = inf_max([Max1, Max2]),
 
320
                {New_min, New_max};
 
321
              empty ->
 
322
                {Min2, Max2}
 
323
            end;
 
324
          empty ->
 
325
            case int_range_from_number_val(Number_val) of
 
326
              {Min1, Max1} ->
 
327
                {Min1, Max1};
 
328
              empty ->
 
329
                empty
 
330
            end
 
331
        end
 
332
    end,
 
333
  lists:foldl(The_union, int_range_from_number_val(First_number), Numbers);
 
334
int_range_from_number_vals(Number) ->
 
335
  int_range_from_number_val(Number).
 
336
 
 
337
get_range_from_annotation(Arg_info, Key) ->
 
338
  Is_byte = erl_types:t_is_byte(Arg_info),
 
339
  Is_char = erl_types:t_is_char(Arg_info),
 
340
  Is_integer = erl_types:t_is_integer(Arg_info),
 
341
  {Int_range, Other} = 
 
342
  if Is_byte ->
 
343
      {{0, ?MAX_BYTE}, false};
 
344
     Is_char ->
 
345
      {{0, ?MAX_CHAR}, false};
 
346
     Is_integer ->
 
347
      {{neginf, posinf}, false};
 
348
     true ->
 
349
      Number_vals = erl_types:t_number_vals(Arg_info),
 
350
      Arg = 
 
351
        case Arg_info of 
 
352
          [_|_] ->
 
353
            [erl_types:t_integer()|Arg_info];
 
354
          _ ->
 
355
            [erl_types:t_integer(),Arg_info]
 
356
        end,
 
357
      Is_only_int = erl_types:t_is_integer(erl_types:t_sup(Arg)),
 
358
      {int_range_from_number_vals(Number_vals), not Is_only_int} 
 
359
  end,
 
360
  range_init(Key, Int_range, Other).
 
361
 
 
362
keep_vars(Vars)->
 
363
  [V || V <- Vars, hipe_icode:is_var(unannotate_var(V))].
 
364
 
 
365
dont_keep_vars(Vars)->
 
366
  [V || V <- Vars, not hipe_icode:is_var(unannotate_var(V))].
 
367
 
 
368
defines(I)->
 
369
  keep_vars(hipe_icode:defines(I)).
 
370
 
 
371
uses(I)->
 
372
  keep_vars(hipe_icode:uses(I)).
 
373
 
 
374
consts(I) ->
 
375
  dont_keep_vars(hipe_icode:args(I)).
 
376
 
 
377
%%
 
378
%% Icode analysis
 
379
%%
 
380
%% Propagates range information using Icode.
 
381
%%
 
382
 
 
383
analyse_icode(IC, Info) ->
 
384
  {Work, Info2} = info_struct__get_work(Info),
 
385
  case Work of
 
386
    {value, Label} ->
 
387
      case info_struct__set_new_current_tree(Label, Info2) of
 
388
        break ->
 
389
          analyse_icode(IC, Info2);
 
390
        Info3 ->
 
391
          %% io:format("Analysing ~p ~n", [Label]),
 
392
          BB = hipe_icode_cfg:bb(IC, Label),
 
393
          Code = hipe_bb:code(BB),
 
394
          %% hipe_icode_pp:pp_block(Code),
 
395
          Info4 = analyse_BB(Code, Info3),
 
396
          analyse_icode(IC, Info4)
 
397
      end;
 
398
    none ->
 
399
      Info2
 
400
  end.  
 
401
 
 
402
analyse_BB([Last], Info) ->
 
403
  analyse_last_insn(Last, Info);
 
404
analyse_BB([Insn|InsnList], Info) ->
 
405
  case analyse_insn(Insn, Info) of
 
406
    {break, NewInfo} ->
 
407
      ?not_done_debug("analyse_BB break ~n", []),
 
408
      info_struct__set_current_mfa_not_done(NewInfo, true); 
 
409
    NewInfo = #info_struct{} ->
 
410
      analyse_BB(InsnList, NewInfo)
 
411
  end.
 
412
 
 
413
analyse_insn(Insn, Info) ->
 
414
  %% hipe_icode_pp:pp_block([Insn]),
 
415
  case Insn of 
 
416
    #call{} -> analyse_call(Insn, Info);
 
417
    #move{} -> analyse_move(Insn, Info);
 
418
    #phi{} -> analyse_phi(Insn, Info);
 
419
    #fmove{} -> analyse_fmove(Insn, Info);
 
420
    #begin_handler{} -> analyse_begin_handler(Insn, Info)
 
421
  end.
 
422
 
 
423
analyse_last_insn(Insn, Info) ->
 
424
  %% hipe_icode_pp:pp_block([Insn]),
 
425
  Case_return = case Insn of 
 
426
                  #return{} -> analyse_return(Insn, Info);
 
427
                  #enter{} -> analyse_enter(Insn, Info);
 
428
                  #switch_val{} -> analyse_switch_val(Insn, Info);
 
429
                  #'if'{} -> analyse_if(Insn, Info);
 
430
                  #goto{} -> analyse_goto(Insn, Info);  
 
431
                  #type{} -> analyse_type(Insn, Info);
 
432
                  #fail{} -> analyse_fail(Insn, Info);
 
433
                  #call{} -> analyse_last_call(Insn, Info);
 
434
                  #switch_tuple_arity{} -> 
 
435
                    analyse_switch_tuple_arity(Insn, Info);
 
436
                  #begin_try{} -> analyse_begin_try(Insn, Info)
 
437
%%                #begin_handler{} -> analyse_begin_handler(Insn, Info) %% last insn??
 
438
                end,
 
439
  case Case_return of
 
440
    {break, Updated_info} ->
 
441
      ?not_done_debug("analyse_last_insn break ~p ~n", [Insn]),
 
442
      info_struct__set_current_mfa_not_done(Updated_info, true);
 
443
    Updated_info = #info_struct{} -> %TODO ordning p�� labelar ... vad??
 
444
      {_, Return_info} = info_struct__save_current_range_tree({out_tree, info_struct__current_label(Updated_info)}, Updated_info),
 
445
 
 
446
      Return_info
 
447
  end.
 
448
 
 
449
%%---------------------------------------------------------------------------
 
450
%% Analysis for all icode instructions
 
451
%%---------------------------------------------------------------------------
 
452
 
 
453
analyse_call(Call, Info) ->
 
454
  Args = hipe_icode:args(Call),
 
455
  Dsts = hipe_icode:call_dstlist(Call),
 
456
  %% io:format("Calltype: ~p ~n", [Call]),
 
457
  Key = 
 
458
    case Dsts of
 
459
      [] ->
 
460
        undef; %%todo asumption that no real var name can be undef
 
461
      [Dst|_] ->
 
462
        name_from_icode_var(Dst)
 
463
    end,
 
464
  Fun = hipe_icode:call_fun(Call),
 
465
  Type = hipe_icode:call_type(Call),
 
466
  Analysis_result = analyse_call_or_enter_fun(Fun, Args, Key, Dsts, Info, Type),
 
467
  case Analysis_result of
 
468
    {break, Analyse_info} ->
 
469
      {break, Analyse_info};
 
470
    Dst_range = #var_range{} ->
 
471
%      info_struct__insert_range(Dst_range, Info);
 
472
      if Key =/= undef ->
 
473
          Annotation_range = get_range_from_dst_annotation(Key, Dsts),
 
474
          Cut_range = range_cut(Key, [Dst_range, Annotation_range]),
 
475
          Is_different = not var_range__is_equal(Dst_range, Cut_range),
 
476
          if Is_different ->
 
477
              Warn = info_struct__warn(Info),
 
478
              warning(Cut_range, Dst_range, Warn);
 
479
          true ->
 
480
            ok
 
481
          end,
 
482
          info_struct__insert_range(Cut_range, Info);
 
483
         true ->
 
484
          Info
 
485
      end;
 
486
    New_Info = #info_struct{} -> New_Info
 
487
  end.
 
488
 
 
489
%Analyses a call that is last in an BB.
 
490
analyse_last_call(Call, Info) ->
 
491
  %% hipe_icode_pp:pp_block([Insn]),
 
492
  case analyse_call(Call, Info) of
 
493
    {break, Info2} ->
 
494
      {break, Info2};
 
495
    Info2 = #info_struct{} ->
 
496
      Continuation = hipe_icode:call_continuation(Call),
 
497
      Current_label = info_struct__current_label(Info2),
 
498
      {Updated_edges, Info3} = info_struct__save_current_range_tree({Current_label, Continuation}, Info2),
 
499
      {_, Labels} = lists:unzip(Updated_edges),
 
500
      {Upd_fail_edge, Info4} = 
 
501
        case hipe_icode:call_fail_label(Call) of
 
502
          [] -> {[], Info3};
 
503
          Label when is_integer(Label) -> 
 
504
            info_struct__save_current_range_tree({Current_label, Label}, Info3)
 
505
        end,
 
506
      Info5 = info_struct__add_work(Info4, Labels),
 
507
      {_, Upd_fail_label} = lists:unzip(Upd_fail_edge),
 
508
      info_struct__add_work(Info5, Upd_fail_label)
 
509
  end.
 
510
 
 
511
analyse_fmove(Insn, Info) ->
 
512
  Dst_name = hipe_icode:fmove_dst(Insn),
 
513
  Dst_range = range_init(Dst_name, empty, true),
 
514
  info_struct__insert_range(Dst_range, Info).
 
515
 
 
516
analyse_move(Insn, Info) ->
 
517
  Src = hipe_icode:move_src(Insn),
 
518
  Dst = hipe_icode:move_dst(Insn),
 
519
  Dst_name = name_from_icode_var(Dst),
 
520
  Dst_range = var_range__copy(get_range_from_arg(Src, Info), Dst_name),
 
521
  info_struct__insert_range(Dst_range, Info).
 
522
 
 
523
 
 
524
phi_widening(Union_range, Info) ->
 
525
  Name = var_range__name(Union_range),
 
526
  Old_range = info_struct__get_phi_range(Name, Info),
 
527
  Dont_wid_min=inf_geq(var_range__min(Union_range), var_range__min(Old_range)),
 
528
  Dont_wid_max=inf_geq(var_range__max(Old_range), var_range__max(Union_range)),
 
529
  Min = 
 
530
    case Dont_wid_min of
 
531
      true ->
 
532
        inf_min([var_range__min(Union_range),var_range__min(Old_range)]);
 
533
      false ->
 
534
        neginf
 
535
    end,
 
536
  Max =   
 
537
    case Dont_wid_max of
 
538
      true ->
 
539
        inf_max([var_range__max(Union_range), var_range__max(Old_range)]);
 
540
      false ->
 
541
        posinf
 
542
    end,
 
543
  Range_range = 
 
544
  case (Min =:= empty) or (Max =:= empty) of
 
545
    true ->
 
546
      empty;
 
547
    false ->
 
548
      {Min, Max}
 
549
  end,
 
550
  range_init(Name, Range_range, var_range__other(Union_range)).
 
551
 
 
552
 
 
553
analyse_phi(Phi, Info) ->
 
554
  {_, Args} = lists:unzip(hipe_icode:phi_arglist(Phi)),
 
555
  Dst = hipe_icode:phi_dst(Phi),
 
556
  Dst_name = name_from_icode_var(Dst),
 
557
  Arg_ranges = get_range_from_args(Args, Info),
 
558
  %io:format("Phi-Arg_ranges: ~p ~n", [Arg_ranges]),
 
559
  Temp_dst_range = range_union(Dst_name, Arg_ranges),
 
560
  Label = info_struct__current_label(Info),
 
561
  Counter = info_struct__counter_from_label(Info, Label),
 
562
  Dst_range = 
 
563
    if Counter > ?PHIWIDENING ->
 
564
      phi_widening(Temp_dst_range, Info);
 
565
    true ->
 
566
      Temp_dst_range
 
567
    end,
 
568
  %io:format("Phi_Dst_range: ~p ~n", [Dst_range]),
 
569
  Info2 = info_struct__set_phi_range(Dst_range, Info),  
 
570
  info_struct__insert_range(Dst_range, Info2).
 
571
 
 
572
analyse_return(Insn, Info) ->
 
573
  [Var] = hipe_icode:return_vars(Insn),
 
574
  Variable = name_from_icode_var(Var),
 
575
  Info2 = info_struct__add_return_var(Variable, Info),
 
576
  Current_label = info_struct__current_label(Info),
 
577
  {_, Info3} = info_struct__save_current_range_tree({Current_label, return}, Info2),
 
578
  Info3.
 
579
 
 
580
analyse_enter(Insn, Info) -> 
 
581
  Current_label = info_struct__current_label(Info),
 
582
  Key = enter_return,
 
583
  %% io:format("Enter ~p ~n", [Insn]),
 
584
  Args = hipe_icode:enter_args(Insn),
 
585
  Fun = hipe_icode:enter_fun(Insn),
 
586
  Analysis_result = analyse_call_or_enter_fun(Fun, Args, Key, [undef], Info, local), 
 
587
  case Analysis_result of
 
588
    {break, Analyse_info} ->
 
589
      {break, Analyse_info};
 
590
    Dst_range = #var_range{} ->
 
591
      Dst_range#var_range{var_name = Key}, %% Assert
 
592
      Info3 = info_struct__insert_range(Dst_range, Info),
 
593
      Info4 = info_struct__add_return_var(Key, Info3),
 
594
      {_, Info5} = info_struct__save_current_range_tree({Current_label, return}, Info4),
 
595
      Info5;
 
596
    Info3 -> %fcall
 
597
      Info4 = info_struct__add_return_var(Key, Info3),
 
598
      {_, Info5} = info_struct__save_current_range_tree({Current_label, return}, Info4),
 
599
      Info5
 
600
  end.
 
601
 
 
602
analyse_begin_try(Insn, Info) ->
 
603
  Label = hipe_icode:begin_try_label(Insn),
 
604
  Successor = hipe_icode:begin_try_successor(Insn),
 
605
  Labels = [Label|[Successor]],
 
606
  %% io:format("begin try labels ~p ~n", [Labels]),
 
607
  {Updated_edges, Info2} = info_struct__save_trees_on_edges(Labels, Info, []),
 
608
  {_, Updated_Labels} = lists:unzip(Updated_edges),
 
609
  info_struct__add_work(Info2, Updated_Labels). 
 
610
 
 
611
analyse_begin_handler(Handler, Info) ->
 
612
  lists:foldl(
 
613
    fun (Var, InfoAcc) ->
 
614
        Var_range = range_init(
 
615
                      name_from_icode_var(Var), {neginf, posinf}, true),
 
616
        info_struct__insert_range(Var_range, InfoAcc)
 
617
    end,
 
618
    Info,
 
619
    hipe_icode:begin_handler_dstlist(Handler)).
 
620
 
 
621
analyse_switch_tuple_arity(Switch, Info) -> 
 
622
  Cases = hipe_icode:switch_tuple_arity_cases(Switch),
 
623
  Fail = hipe_icode:switch_tuple_arity_fail_label(Switch),
 
624
  {_, Case_labels} = lists:unzip(Cases),
 
625
  Labels = [Fail|Case_labels],
 
626
  %% io:format("switch labels ~p ~n", [Labels]),
 
627
  {Updated_edges, Info2} = info_struct__save_trees_on_edges(Labels, Info, []),
 
628
  {_, Updated_labels} = lists:unzip(Updated_edges),
 
629
  info_struct__add_work(Info2, Updated_labels). 
 
630
 
 
631
analyse_switch_val(Switch, Info) -> 
 
632
  Switch_range = get_range_from_arg(hipe_icode:switch_val_arg(Switch), Info),
 
633
  Cases = hipe_icode:switch_val_cases(Switch),
 
634
  %io:format("switch ~p ~p ~n", [Switch, Cases]), 
 
635
  {_, Labels} = lists:unzip(Cases),
 
636
  {Fail_range, Range_label_list} = get_range_label_list(Switch_range, Cases, Info, [], []),
 
637
  Fail_label = hipe_icode:switch_val_fail_label(Switch), 
 
638
  {Updated_edges, Info2} = info_struct__save_spec_range_trees(Info, [{Fail_range, Fail_label}|Range_label_list], [Fail_label|Labels]),
 
639
  {_, To_labels} = lists:unzip(Updated_edges),
 
640
  Info3 = Info2,
 
641
  info_struct__add_work(Info3, To_labels).
 
642
 
 
643
analyse_sane_if(If, Info, [Range_1, Range_2]) ->
 
644
  case hipe_icode:if_op(If) of
 
645
    '>' ->
 
646
      {True_range_2, True_range_1, False_range_2, False_range_1} = 
 
647
        range_inequality_propagation(Range_2, Range_1);
 
648
    '==' -> 
 
649
      {Temp_true_range_1, Temp_true_range_2, False_range_1, False_range_2}=
 
650
        range_equality_propagation(Range_1, Range_2),
 
651
      True_range_1 = var_range__set_other(Temp_true_range_1, 
 
652
                                          var_range__other(Range_1)),
 
653
      True_range_2 = var_range__set_other(Temp_true_range_2, 
 
654
                                          var_range__other(Range_2));
 
655
    '<' ->
 
656
      {True_range_1, True_range_2, False_range_1, False_range_2} = 
 
657
        range_inequality_propagation(Range_1, Range_2);
 
658
    '>=' ->
 
659
      {False_range_1, False_range_2, True_range_1, True_range_2} =
 
660
        range_inequality_propagation(Range_1, Range_2);
 
661
    '=<' ->
 
662
      {False_range_2, False_range_1, True_range_2, True_range_1} = 
 
663
        range_inequality_propagation(Range_2, Range_1);
 
664
    '=:=' ->
 
665
      {True_range_1, True_range_2, False_range_1, False_range_2}=
 
666
        range_equality_propagation(Range_1, Range_2);
 
667
    '=/=' ->
 
668
      {False_range_1, False_range_2, True_range_1, True_range_2} =
 
669
        range_equality_propagation(Range_1, Range_2);
 
670
    '/=' -> 
 
671
      {Temp_false_range_1, Temp_false_range_2, True_range_1, True_range_2}=
 
672
        range_equality_propagation(Range_1, Range_2),
 
673
      False_range_1 = var_range__set_other(Temp_false_range_1, 
 
674
                                           var_range__other(Range_1)),
 
675
      False_range_2 = var_range__set_other(Temp_false_range_2, 
 
676
                                           var_range__other(Range_2))
 
677
  end,
 
678
  
 
679
  %% io:format("~nrange_1: ~p, ~nrange_2: ~p ~n if op: ~p ~ntrue_1: ~p, ~ntrue_2: ~p, ~nfalse_1: ~p, ~nfalse_2: ~p ~n", [Range_1, Range_2, hipe_icode:if_op(If), True_range_1, True_range_2, False_range_1, False_range_2]),
 
680
 
 
681
  True_label = hipe_icode:if_true_label(If),
 
682
  False_label = hipe_icode:if_false_label(If),
 
683
  
 
684
  Substitute_list = [{True_range_1, True_label}, {True_range_2, True_label}, 
 
685
                     {False_range_1, False_label}, {False_range_2, False_label}],
 
686
  {Updated_edges, Info2} = info_struct__save_spec_range_trees(Info, Substitute_list, [True_label, False_label]),
 
687
  {_, To_labels} = lists:unzip(Updated_edges),
 
688
  %% io:format("If ~p ~n", [To_labels]),
 
689
  
 
690
%%  Old_vals = [var_range__min(Range_1), var_range__max(Range_1), var_range__min(Range_2), var_range__max(Range_2)], 
 
691
        
 
692
%%   Info3 = lists:foldl(fun (Val, Info) ->
 
693
%%                        info_struct__add_wideningvalue(Val, Info)
 
694
%%                    end,
 
695
%%                    Info2,
 
696
%%                    Old_vals),
 
697
  info_struct__add_work(Info2, To_labels).
 
698
 
 
699
analyse_if(If, Info) ->
 
700
  %% hipe_icode_pp:pp_block([If]),
 
701
  Args = hipe_icode:if_args(If),        
 
702
  %% io:format("if args ~p ~n~p ~n", [get_range_from_args(Args, Info), Args]),
 
703
  %% io:format("ifop ~p ~n", [hipe_icode:if_op(If)]),
 
704
  case get_range_from_args(Args, Info) of
 
705
    [] ->       
 
706
      Current_label = info_struct__current_label(Info),
 
707
      New_work = [hipe_icode:if_true_label(If), hipe_icode:if_false_label(If)],
 
708
      lists:foldl(
 
709
        fun (Label, InfoAcc) ->
 
710
            {Updated_edges, InfoAcc2} = info_struct__save_current_range_tree({Current_label, Label}, InfoAcc),
 
711
            {_, To_labels} = lists:unzip(Updated_edges),
 
712
            info_struct__add_work(InfoAcc2, To_labels)
 
713
        end,
 
714
        Info,
 
715
        New_work);
 
716
    [_Range_1, _Range_2] = Ranges ->
 
717
      analyse_sane_if(If, Info, Ranges)
 
718
  end.
 
719
 
 
720
analyse_goto(Insn, Info) ->
 
721
  Goto_label = hipe_icode:goto_label(Insn),
 
722
  Current_label = info_struct__current_label(Info),
 
723
  {Updated_edges, Info2} = info_struct__save_current_range_tree({Current_label, Goto_label}, Info),
 
724
  {_, To_labels} = lists:unzip(Updated_edges),
 
725
  info_struct__add_work(Info2, To_labels).
 
726
 
 
727
analyse_type(Type, Info) ->
 
728
  Type_type = hipe_icode:type_type(Type),
 
729
  [First_arg|_] = hipe_icode:type_args(Type),
 
730
  Var_name = name_from_icode_var(First_arg),
 
731
  Old_var_range = info_struct__get_range(Var_name, Info),
 
732
  case Type_type of
 
733
    {integer, N} -> 
 
734
      True_range = range_cut(Var_name, 
 
735
                             [range_init(Var_name, {N, N}, false),
 
736
                              Old_var_range]),
 
737
      %% False range
 
738
      False_int_range = 
 
739
      case var_range__range(Old_var_range) of
 
740
        {Min, Max} ->
 
741
          New_small = inf_geq(Min, N),
 
742
          New_large = inf_geq(N, Max),
 
743
          if New_small ->
 
744
            {N + 1, Max};
 
745
          New_large ->
 
746
            {Min, N - 1};
 
747
          true -> 
 
748
            {Min, Max}
 
749
          end;
 
750
        Not_tuple ->
 
751
          Not_tuple
 
752
      end,
 
753
      
 
754
      False_range = 
 
755
        range_init(
 
756
          Var_name,
 
757
          False_int_range, 
 
758
          var_range__other(Old_var_range)
 
759
        );
 
760
 
 
761
%%      info_struct__add_wideningvalue(N, Info);
 
762
    
 
763
    integer -> 
 
764
      True_range = var_range__set_other(Old_var_range, false),
 
765
      False_range = range_init(Var_name, empty, var_range__other(Old_var_range));
 
766
    _ -> 
 
767
      True_range = var_range__set_other(Old_var_range, true), %%Todo assert, cut
 
768
      False_range = Old_var_range
 
769
  end,
 
770
  
 
771
  True_label = hipe_icode:type_true_label(Type),
 
772
  False_label = hipe_icode:type_false_label(Type),
 
773
  Updates = [{True_range, True_label}, {False_range, False_label}], 
 
774
  Labels = [True_label, False_label],
 
775
  {Updated_edges, Info2} = info_struct__save_spec_range_trees(Info, Updates, Labels),
 
776
  {_, To_labels} = lists:unzip(Updated_edges),
 
777
  info_struct__add_work(Info2, To_labels).
 
778
 
 
779
 
 
780
analyse_fail(_Fail, Info) ->
 
781
  Current_label = info_struct__current_label(Info),
 
782
  {_, Info2} = info_struct__save_current_range_tree({Current_label, return}, Info),
 
783
  Info2.
 
784
 
 
785
 
 
786
%%---------------------------------------------------------------------------
 
787
%% Helper functions for icode instructions
 
788
%%---------------------------------------------------------------------------
 
789
 
 
790
analyse_other_module_fcall(Key, {M,F,A}, Info, Args) -> 
 
791
  %% io:format("fcall to other module ~p ~n", [{M,F,A}]),
 
792
  Mfa_type = erl_bif_types:type(M,F,A),
 
793
  Info2 = 
 
794
    case erl_bif_types:arg_types(M,F,A) of
 
795
      any -> Info;
 
796
      List -> 
 
797
        New_arg_ranges = 
 
798
          lists:zipwith(
 
799
            fun (Arg, Arg_type) ->
 
800
                Prop_range = get_range_from_arg(Arg, Info),
 
801
                Name = name_from_icode_var(Arg),
 
802
                Anno_range = get_range_from_annotation(Arg_type, Name),
 
803
                range_cut(Name, [Prop_range, Anno_range])
 
804
            end,
 
805
            Args, List),
 
806
        lists:foldl(
 
807
          fun (Range, InfoAcc) ->
 
808
              info_struct__insert_range(Range, InfoAcc)
 
809
          end,
 
810
          Info,
 
811
          New_arg_ranges)
 
812
    end,
 
813
  Return_range = get_range_from_annotation(Mfa_type, Key), 
 
814
  info_struct__insert_range(Return_range, Info2).
 
815
 
 
816
analyse_fcall(Key, {M,F,A}, Info, Args) ->
 
817
  %io:format("~p fcall ~p ~n", [self(), {M,F,A}]),
 
818
  Current_mfa = info_struct__current_mfa(Info), 
 
819
  Server = info_struct__server(Info),
 
820
  Info2 = 
 
821
  if (Current_mfa =:= {M,F,A}) ->
 
822
    info_struct__set_is_recursive(true, Info);
 
823
  true ->
 
824
    Info
 
825
  end,
 
826
  Server ! {self(), {load, message, {{M,F,A}, return_range}}},
 
827
  receive
 
828
    none ->
 
829
      case Current_mfa of
 
830
        {M,_,_} ->
 
831
          %% is_recursive h��r??
 
832
          %?not_done_debug("need info ~p ~n", [{M,F,A}]),
 
833
          Info3 = server__update_call_args({M,F,A}, Args, Info2),
 
834
          Range = range_init(Key, {neginf, posinf}, true),
 
835
          info_struct__insert_range(Range, Info3);
 
836
          %{break, Info3};
 
837
        _ -> 
 
838
          %% doesn't save args info about function in other module
 
839
          analyse_other_module_fcall(Key, {M,F,A}, Info2, Args)
 
840
      end;
 
841
    {value, {Lookup_range, _Final}} ->
 
842
      Info3 = server__update_call_args({M,F,A}, Args, Info2),
 
843
      Range = var_range__copy(Lookup_range, Key),
 
844
      info_struct__insert_range(Range, Info3)
 
845
  end.
 
846
 
 
847
analyse_bs_get_integer_funs(Size, Flags, true) ->
 
848
  Signed = Flags band 4,
 
849
  if Signed =:= 0 ->
 
850
      Max = round(math:pow(2, Size)) - 1,
 
851
      Min = 0;
 
852
     true ->
 
853
      Max = posinf,
 
854
      Min = neginf
 
855
  end,
 
856
  {Min, Max};
 
857
 
 
858
analyse_bs_get_integer_funs(_Size, _Flags, false) -> {neginf, posinf}.
 
859
 
 
860
 
 
861
get_range_from_dst_annotation(Key, Dsts) ->
 
862
  case Dsts of
 
863
    [undef] ->
 
864
      range_init(Key, {neginf, posinf}, true);
 
865
    [] -> 
 
866
      range_init(Key, {neginf, posinf}, true);
 
867
    [Dst|_] -> %todo the others are what??
 
868
      case hipe_icode:is_annotated_var(Dst) of
 
869
        true ->
 
870
          get_range_from_annotation(hipe_icode:var_annotation(Dst), Key);
 
871
        false ->
 
872
          range_init(Key, {neginf, posinf}, true)
 
873
      end
 
874
  end.
 
875
 
 
876
lasy_type(Fun) ->
 
877
  ?call_or_enter_debug("fun type ~p ~n", [Fun]),
 
878
  basic_type(Fun).
 
879
 
 
880
analyse_call_or_enter_fun(Fun, Args, Key, Dsts, Info, CallType) ->
 
881
  %% io:format("Fun ~p ~n", [Fun]),
 
882
  case lasy_type(Fun) of
 
883
    {bin, Operation} ->
 
884
      ?call_or_enter_debug("bin", []),
 
885
      [Arg_range1|[Arg_range2|[]]] = get_range_from_args(Args, Info),
 
886
      A1_is_empty = var_range__is_empty(Arg_range1),
 
887
      A2_is_empty = var_range__is_empty(Arg_range2),
 
888
      if A1_is_empty or A2_is_empty ->
 
889
          Other = var_range__other(Arg_range1) or var_range__other(Arg_range1),
 
890
          range_init(Key, empty, Other);
 
891
         true ->
 
892
          Operation(Key, Arg_range1, Arg_range2)
 
893
      end;
 
894
    {unary, Operation} ->
 
895
      ?call_or_enter_debug("unary", []),
 
896
      [Arg_range] = get_range_from_args(Args, Info),
 
897
      case var_range__is_empty(Arg_range) of
 
898
        true ->
 
899
          range_init(Key, empty, true);
 
900
        false ->
 
901
          Operation(Key, Arg_range)
 
902
      end;
 
903
    {fcall, {M,F,A}} ->
 
904
      ?call_or_enter_debug("fcall", []),
 
905
      case CallType of
 
906
        local ->
 
907
          case analyse_fcall(Key, {M,F,A}, Info, Args) of
 
908
            Fcallinfo = #info_struct{} ->
 
909
              Fcall_range = info_struct__get_range(Key, Fcallinfo),
 
910
              Annotation_range = get_range_from_dst_annotation(Key, Dsts),
 
911
              New_range = range_cut(Key, [Fcall_range, Annotation_range]),
 
912
              info_struct__insert_range(New_range, Fcallinfo);
 
913
            Other ->
 
914
              Other
 
915
          end;
 
916
        remote ->
 
917
          analyse_other_module_fcall(Key, {M,F,A}, Info, Args)
 
918
%       primops ->
 
919
%         get_range_from_dst_annotation(Key, Dsts)
 
920
      end;
 
921
    not_int ->
 
922
      ?call_or_enter_debug("not int", []),
 
923
      range_init(Key, empty, true);
 
924
%%    range_cut(Key, 
 
925
%%              [range_init(Key, empty, true), 
 
926
%%               get_range_from_dst_annotation(Key, Dsts)]);
 
927
      
 
928
    not_analysed -> 
 
929
      ?call_or_enter_debug("not analysed", []),
 
930
      get_range_from_dst_annotation(Key, Dsts);
 
931
    {hipe_bs_primop, {bs_get_integer, Size, Flags}} ->
 
932
      ?call_or_enter_debug("bs1", []),
 
933
      {Min, Max} = analyse_bs_get_integer_funs(Size, Flags, length(Args) =:= 4),
 
934
      range_init(Key, {Min, Max}, false);
 
935
    {hipe_bs_primop, {bs_get_integer_2, Size, Flags}} ->
 
936
      ?call_or_enter_debug("bs2", []),
 
937
      {Min, Max} = analyse_bs_get_integer_funs(Size, Flags, length(Args) =:= 1),                                        
 
938
      range_init(Key, {Min, Max}, false);
 
939
    {hipe_bs_primop, _} = Primop ->
 
940
      ?call_or_enter_debug("bs3 ~p ~n", [Primop]),
 
941
      Type = hipe_icode_primops:type(Primop),
 
942
      get_range_from_annotation(Type, Key);
 
943
    {hipe_bsi_primop, {bs_get_integer, Size, Flags}} ->
 
944
      ?call_or_enter_debug("bs4", []),
 
945
      {Min, Max} = analyse_bs_get_integer_funs(Size, Flags, true),
 
946
      range_init(Key, {Min, Max}, false)
 
947
  end.
 
948
 
 
949
%% @doc
 
950
%%   basic_type/1 specifies how to analyze a call or enter fun
 
951
%% @end
 
952
 
 
953
%% Arithmetic operations
 
954
basic_type('+') -> {bin, fun(Name, R1, R2) -> range_add(Name, R1, R2) end};
 
955
basic_type('-') -> {bin, fun(Name, R1, R2) -> range_sub(Name, R1, R2) end};
 
956
basic_type('*') -> {bin, fun(Name, R1, R2) -> range_mult(Name, R1, R2) end};
 
957
basic_type('/') -> not_int;
 
958
basic_type('div') -> {bin, fun(Name, R1, R2) -> range_div(Name, R1, R2) end};
 
959
basic_type('rem') -> {bin, fun(Name, R1, R2) -> range_rem(Name, R1, R2) end};
 
960
basic_type('bor') -> {bin, fun(Name, R1, R2) -> range_bor(Name, R1, R2) end};
 
961
basic_type('band') -> {bin, fun(Name, R1, R2) -> range_band(Name, R1, R2) end};
 
962
basic_type('bxor') -> {bin, fun(Name, R1, R2) -> range_bxor(Name, R1, R2) end};
 
963
basic_type('bnot') -> {unary, fun(Name, R1) -> range_bnot(Name, R1) end};
 
964
basic_type('bsl') -> {bin, fun(Name, R1, R2) -> range_bsl(Name, R1, R2) end};
 
965
basic_type('bsr') -> {bin, fun(Name, R1, R2) -> range_bsr(Name, R1, R2) end};
 
966
 
 
967
basic_type('unsafe_bor') ->  
 
968
  {bin, fun(Name, R1, R2) -> range_bor(Name, R1, R2) end};
 
969
basic_type('unsafe_band') ->
 
970
  {bin, fun(Name, R1, R2) -> range_band(Name, R1, R2) end};
 
971
basic_type('unsafe_bxor') ->
 
972
  {bin, fun(Name, R1, R2) -> range_bxor(Name, R1, R2) end};
 
973
basic_type('unsafe_bnot') ->
 
974
  {unary, fun(Name, R1) -> range_bnot(Name, R1) end};
 
975
 
 
976
basic_type('unsafe_bsl') ->
 
977
  {bin, fun(Name, R1, R2) -> range_bsl(Name, R1, R2) end};
 
978
basic_type('unsafe_bsr') ->
 
979
  {bin, fun(Name, R1, R2) -> range_bsr(Name, R1, R2) end};
 
980
 
 
981
basic_type('unsafe_add') ->
 
982
  {bin, fun(Name, R1, R2) -> range_add(Name, R1, R2) end};
 
983
basic_type('unsafe_sub') ->
 
984
  {bin, fun(Name, R1, R2) -> range_sub(Name, R1, R2) end};
 
985
basic_type('extra_unsafe_add') ->
 
986
  {bin, fun(Name, R1, R2) -> range_add(Name, R1, R2) end};
 
987
basic_type('extra_unsafe_sub') ->
 
988
  {bin, fun(Name, R1, R2) -> range_sub(Name, R1, R2) end};
 
989
 
 
990
%% Binaries
 
991
basic_type({hipe_bs_primop, Todo}) -> {hipe_bs_primop, Todo};
 
992
basic_type({hipe_bs_primop2, Todo}) -> {hipe_bs_primop, Todo};
 
993
basic_type({hipe_bsi_primop,{bs_get_integer, Size, _B, Flags}}) -> 
 
994
  {hipe_bsi_primop,{bs_get_integer, Size, Flags}}; 
 
995
basic_type({hipe_bsi_primop,bs_get_orig}) -> not_analysed;
 
996
basic_type({hipe_bsi_primop,bs_get_orig_offset}) -> not_analysed;
 
997
basic_type({hipe_bsi_primop,bs_get_size}) -> not_analysed;
 
998
basic_type({hipe_bsi_primop,bs_add}) -> not_analysed;
 
999
basic_type({hipe_bsi_primop,bs_div_test}) -> not_analysed;
 
1000
basic_type({hipe_bsi_primop,bs_size_test_all}) -> not_analysed;
 
1001
basic_type({hipe_bsi_primop,{bs_get_binary_all,_A,_B}}) -> not_analysed;
 
1002
basic_type({hipe_bsi_primop,{bs_make_size,_A}}) -> not_analysed;
 
1003
basic_type({hipe_bsi_primop,bs_size_test}) -> not_analysed;
 
1004
basic_type({hipe_bsi_primop,{bs_get_binary,_A,_B,_C}}) -> not_analysed;
 
1005
basic_type({hipe_bsi_primop,{bs_get_binary,_A,_B}}) -> not_analysed;
 
1006
 
 
1007
%% Unknown, other
 
1008
basic_type(call_fun) -> not_analysed;
 
1009
basic_type({closure_element, _N}) -> not_analysed; 
 
1010
basic_type('redtest') -> not_analysed;
 
1011
basic_type({gc_test, _}) -> not_analysed;
 
1012
basic_type(clear_timeout) -> not_analysed;
 
1013
basic_type(set_timeout) -> not_analysed;
 
1014
basic_type({apply_N, _N}) -> not_analysed;
 
1015
 
 
1016
%% Message handling
 
1017
basic_type(check_get_msg) -> not_analysed; 
 
1018
basic_type(select_msg) -> not_analysed; 
 
1019
basic_type(next_msg) -> not_analysed; 
 
1020
basic_type(suspend_msg) -> not_analysed;
 
1021
 
 
1022
%% Functions
 
1023
basic_type({mkfun, _Fun, _N1, _N2}) -> not_int;
 
1024
basic_type({M,F,A}) -> {fcall, {M,F,A}}; 
 
1025
basic_type(enter_fun) -> not_analysed;
 
1026
 
 
1027
%% Floats
 
1028
basic_type(conv_to_float) -> not_int;
 
1029
basic_type(fclearerror) -> not_analysed;
 
1030
basic_type(fp_add) -> not_int;
 
1031
basic_type(fp_mul) -> not_int;
 
1032
basic_type(fp_div) -> not_int;
 
1033
basic_type(fcheckerror) -> not_analysed;
 
1034
basic_type(unsafe_tag_float) -> not_int;
 
1035
basic_type(unsafe_untag_float) -> not_int;
 
1036
basic_type(fp_sub) -> not_int;
 
1037
basic_type(fnegate) -> not_int;
 
1038
 
 
1039
%% Lists, tuples, records
 
1040
basic_type(mktuple) -> not_int;
 
1041
basic_type(cons) -> not_int;
 
1042
basic_type({unsafe_element, _N}) -> not_analysed;
 
1043
basic_type(unsafe_hd) -> not_analysed;
 
1044
basic_type(unsafe_tl) -> not_int;
 
1045
basic_type({element, _Elems}) -> not_analysed;
 
1046
basic_type({unsafe_update_element, _N}) -> not_analysed.
 
1047
 
 
1048
 
 
1049
%% todo rename switch_val
 
1050
get_range_label_list(Range, [], _Info, Range_label_list, []) ->
 
1051
  {Range, Range_label_list};
 
1052
get_range_label_list(Range, [], _Info, Range_label_list, Constants_to_cut) ->
 
1053
  Sorted_constants = lists:sort(Constants_to_cut),
 
1054
  [Smallest|_] = Sorted_constants,
 
1055
  Largest = lists:last(Sorted_constants),
 
1056
  Min_value = var_range__min(Range),
 
1057
  if Min_value >= Smallest ->
 
1058
      Sorted_constants_to_cut = Sorted_constants;
 
1059
     true ->
 
1060
      Sorted_constants_to_cut = lists:reverse(Sorted_constants)
 
1061
  end,  
 
1062
  New_temp_range = 
 
1063
    lists:foldl(
 
1064
      fun(Const, Acc_range) ->
 
1065
        Const_range = range_init(const, {Const, Const}, false),
 
1066
        range_remove_constant(Acc_range, Const_range)
 
1067
      end,
 
1068
      Range,
 
1069
      Sorted_constants_to_cut),
 
1070
  New_range_range = 
 
1071
  case var_range__range(New_temp_range) of 
 
1072
    {Min, Max} ->
 
1073
      New_small = inf_geq(Smallest, Max),
 
1074
      New_large = inf_geq(Min, Largest),
 
1075
      New_max = 
 
1076
        if New_small -> Smallest - 1;
 
1077
           true-> Max
 
1078
        end,
 
1079
      New_min =
 
1080
        if New_large -> Largest + 1;
 
1081
           true -> Min
 
1082
        end,
 
1083
      {New_min, New_max};
 
1084
    Not_tuple ->
 
1085
      Not_tuple
 
1086
  end,
 
1087
      
 
1088
  %io:format("Range ~p ~n", [New_range_range]),
 
1089
  New_range = range_init(var_range__name(Range), New_range_range, var_range__other(Range)), 
 
1090
  {New_range, Range_label_list}; 
 
1091
get_range_label_list(Range, [Case|Cases], Info, Range_label_list, Constants_to_cut) ->
 
1092
  {Arg, Label} = Case,
 
1093
  Arg_range = get_range_from_arg(Arg, Info),
 
1094
  Cut_range = range_cut(var_range__name(Range), [Arg_range, Range]),
 
1095
  Arg_name = var_range__name(Arg_range),
 
1096
  Is_const = var_range__is_constant(Arg_range),
 
1097
  Is_empty_arg = var_range__is_empty(Cut_range),
 
1098
  New_constants_to_cut =
 
1099
    if Is_const ->
 
1100
        {Constant_value, Constant_value} = var_range__range(Arg_range),
 
1101
        [Constant_value|Constants_to_cut];
 
1102
       true ->
 
1103
        Constants_to_cut
 
1104
    end,
 
1105
  if not Is_empty_arg ->
 
1106
      Arg_cut_range = var_range__copy(Cut_range, Arg_name),
 
1107
      get_range_label_list(Range, Cases, Info, [{Arg_cut_range, Label},{Cut_range, Label}|Range_label_list], New_constants_to_cut);
 
1108
     true ->
 
1109
      get_range_label_list(Range, Cases, Info, Range_label_list, New_constants_to_cut)
 
1110
  end.
 
1111
 
 
1112
%%
 
1113
%% Icode annotation and pritty print
 
1114
%%
 
1115
%% Annotates icode with range information
 
1116
%%
 
1117
 
 
1118
annotate_IC(IC, Range_info) ->
 
1119
  Label_list = hipe_icode_cfg:labels(IC),
 
1120
  lists:foldl(
 
1121
    fun (Label, ICAcc) ->
 
1122
        case range_info__is_live(Range_info, Label) of
 
1123
          true ->
 
1124
            BB = hipe_icode_cfg:bb(ICAcc, Label),
 
1125
            Code = hipe_bb:code(BB),
 
1126
            NewCode = annotate_BB(Code, Range_info, Label),
 
1127
            NewBB = hipe_bb:code_update(BB, NewCode),
 
1128
            hipe_icode_cfg:bb_add(ICAcc, Label, NewBB);
 
1129
          false ->
 
1130
            ICAcc
 
1131
        end
 
1132
    end,
 
1133
    IC,
 
1134
    Label_list).
 
1135
 
 
1136
annotate_BB(Insts, Range_info, Label) ->
 
1137
  lists:map(fun (Inst) -> annotate_insn(Inst, Range_info, Label) end, Insts).
 
1138
 
 
1139
annotate_insn(Insn, Range_info, Current_label) ->
 
1140
  Def = defines(Insn),
 
1141
  Use = uses(Insn),
 
1142
  Fun = fun (X, Y) -> hipe_icode:annotate_var(X, Y) end,
 
1143
  Lookup_def = fun (Info, Label, Var) ->
 
1144
                   range_info__def_range(Info, Label, name_from_icode_var(Var))
 
1145
               end,
 
1146
  Lookup_use = fun (Info, Label, Var) ->
 
1147
                   range_info__use_range(Info, Label, name_from_icode_var(Var))
 
1148
               end,
 
1149
  Old_anno = fun (X) -> case hipe_icode:is_annotated_var(X) of
 
1150
                          true ->
 
1151
                            hipe_icode:var_annotation(X);
 
1152
                          false ->
 
1153
                            any
 
1154
                        end
 
1155
             end,
 
1156
  DefSubst = [{X, Fun(X, {Old_anno(X), Lookup_def(Range_info, Current_label, X)})}||X<-Def],
 
1157
  UseSubst = [{X, Fun(X, {Old_anno(X), Lookup_use(Range_info, Current_label, X)})}||X<-Use],
 
1158
  case DefSubst ++ UseSubst of
 
1159
    [] ->
 
1160
      Insn;
 
1161
    Subst ->
 
1162
      hipe_icode:subst(Subst, Insn)
 
1163
  end.
 
1164
 
 
1165
pp_args([]) -> []; %%lists_map ??
 
1166
pp_args([Param]) -> to_string(Param);
 
1167
pp_args([Param|Params]) ->
 
1168
  to_string(Param) ++ ", " ++ pp_args(Params).  
 
1169
 
 
1170
pp_function_info(Info, File) ->
 
1171
  Return_range = return_range(Info),
 
1172
  Range = var_range__range(Return_range),
 
1173
  Params = input_range(Info),
 
1174
  R_other = 
 
1175
    case var_range__other(Return_range) of
 
1176
      true -> "may return other";
 
1177
      false -> "only integer return values"
 
1178
    end,        
 
1179
  {M, F, _A} = info_struct__current_mfa(Info),
 
1180
  ParamsString = lists:flatten(pp_args(Params)),
 
1181
  io:format(File, "~p:~p/(~s) -> ~p, ~s ~n~n",
 
1182
            [M, F, ParamsString, Range, R_other]).
 
1183
 
 
1184
-ifdef(DEBUG).
 
1185
pp_range_tree(Info) ->
 
1186
  List = gb_trees:to_list(info_struct__range_tree(Info)),
 
1187
  io:format("Range List, Label ~p: ~n", [info_struct__current_label(Info)]),
 
1188
  pp_range_list(List).
 
1189
-endif.
 
1190
 
 
1191
-ifdef(DEBUG).
 
1192
pp_range_list(List) ->
 
1193
  lists:foreach(fun(R) -> pp_range(R) end, List).
 
1194
-endif.
 
1195
 
 
1196
-ifdef(DEBUG).
 
1197
pp_range(Range) -> 
 
1198
  Int_range = var_range__range(Range),
 
1199
  Other = var_range__other(Range),
 
1200
  Name = var_range__name(Range),
 
1201
  io:format("~w, ~w ~w ~n", [Name, Int_range, Other]).
 
1202
-endif.
 
1203
 
 
1204
print_icode_to_file(IC, Info) ->
 
1205
  {M,F,A} = info_struct__current_mfa(Info),
 
1206
  FileName = atom_to_list(M) ++ "_" ++ atom_to_list(F) ++ "_" ++ integer_to_list(A) ++ ".anno",
 
1207
  %% io:format("filename ~p ~n", [FileName]),
 
1208
  case file:open(FileName, write) of
 
1209
    {ok, File} ->
 
1210
      pp_function_info(Info, File),
 
1211
      hipe_icode_pp:pp(File, hipe_icode_cfg:cfg_to_linear(IC)),
 
1212
      file:close(File);
 
1213
    {error, _Reason} ->
 
1214
      %% probably a fun
 
1215
      %% todo
 
1216
      ok
 
1217
  end.
 
1218
 
 
1219
%%
 
1220
%% Icode specialization
 
1221
%%
 
1222
%% Modifies calls to arithmetic operations
 
1223
%%
 
1224
 
 
1225
specialize_IC(IC, Range_info) ->
 
1226
  Label_list = hipe_icode_cfg:labels(IC),
 
1227
  lists:foldl(
 
1228
    fun (Label, ICAcc) ->
 
1229
        %% hipe_icode_pp:pp_block(Code),
 
1230
        case range_info__is_live(Range_info, Label) of
 
1231
          true ->
 
1232
            BB = hipe_icode_cfg:bb(ICAcc, Label),
 
1233
            Code = hipe_bb:code(BB),
 
1234
            NewCode = specialize_BB(Code, Range_info, Label),
 
1235
            NewBB = hipe_bb:code_update(BB, NewCode),
 
1236
            hipe_icode_cfg:bb_add(ICAcc, Label, NewBB);
 
1237
          false ->
 
1238
            Warn = range_info__warn(Range_info),
 
1239
            warning("Dead code", Label, Warn),
 
1240
            ICAcc
 
1241
        end
 
1242
    end,
 
1243
    IC,
 
1244
    Label_list).
 
1245
 
 
1246
specialize_BB(Insts, Range_info, Label) ->
 
1247
  lists:map(fun (Insn) -> specialize_insn(Insn, Range_info, Label) end, Insts).
 
1248
 
 
1249
specialize_insn(Insn, Range_info, Label) ->
 
1250
  %% hipe_icode_pp:pp_block([Insn]),
 
1251
  New_insn = 
 
1252
  case Insn of
 
1253
    #call{} ->
 
1254
      specialize_call(Insn, Range_info, Label);
 
1255
    #enter{} ->
 
1256
      specialize_enter(Insn, Range_info, Label);
 
1257
    #'if'{} ->
 
1258
      specialize_if(Insn, Range_info, Label);
 
1259
    Other ->
 
1260
      Other
 
1261
  end,
 
1262
  New_insn.
 
1263
 
 
1264
%% specialized_op(op, specialization)
 
1265
specialized_op('+', safe, _) -> '+';
 
1266
specialized_op('+', unsafe, _) -> 'unsafe_add';
 
1267
specialized_op('+', extra_unsafe, _) -> 'extra_unsafe_add';
 
1268
 
 
1269
specialized_op('-', safe, _) -> '-';
 
1270
specialized_op('-', unsafe, _) -> 'unsafe_sub'; %%??
 
1271
specialized_op('-', extra_unsafe, _) -> 'extra_unsafe_sub'; %extra
 
1272
 
 
1273
specialized_op('*', safe, _) -> '*';
 
1274
specialized_op('*', unsafe, Warn) -> 
 
1275
  warning('could be unsafe_mult', '*', Warn),
 
1276
  '*';
 
1277
specialized_op('*', extra_unsafe, Warn) -> 
 
1278
  warning('could be extra_unsafe_mult', '*', Warn),
 
1279
  '*';
 
1280
 
 
1281
specialized_op('band', safe, _) -> 'band';
 
1282
specialized_op('band', unsafe, _) ->
 
1283
  io:format("band(Fix, Fix) -> Big ~n"), exit(1);
 
1284
specialized_op('band', extra_unsafe, _) -> 'unsafe_band';
 
1285
 
 
1286
specialized_op('bor', safe, _) -> 'bor';
 
1287
specialized_op('bor', unsafe, _) ->
 
1288
  io:format("bor(Fix, Fix) -> Big ~n"), exit(1);
 
1289
specialized_op('bor', extra_unsafe, _) -> 'unsafe_bor';
 
1290
 
 
1291
specialized_op('bxor', safe, _) -> 'bxor';
 
1292
specialized_op('bxor', unsafe, _) ->
 
1293
  io:format("bxor(Fix, Fix) -> Big ~n"), exit(1);
 
1294
specialized_op('bxor', extra_unsafe, _) -> 'unsafe_bxor';
 
1295
 
 
1296
specialized_op('bnot', safe, _) -> 'bnot';
 
1297
specialized_op('bnot', unsafe, _) -> 'bnot'; %% todo correct?
 
1298
specialized_op('bnot', extra_unsafe, _) -> 'unsafe_bnot';
 
1299
 
 
1300
specialized_op('bsl', safe, _) -> 'bsl';
 
1301
specialized_op('bsl', unsafe, _) -> 'bsl';
 
1302
specialized_op('bsl', extra_unsafe, _) -> 'unsafe_bsl';
 
1303
 
 
1304
specialized_op('bsr', safe, _) -> 'bsr';
 
1305
specialized_op('bsr', unsafe, _) -> 'bsr';
 
1306
specialized_op('bsr', extra_unsafe, _) -> 'unsafe_bsr';
 
1307
 
 
1308
specialized_op('unsafe_add', safe, Warn) -> 
 
1309
  warning('unsafe_add', safe, Warn), 'unsafe_add';
 
1310
specialized_op('unsafe_add', unsafe, _) -> 'unsafe_add';
 
1311
specialized_op('unsafe_add', extra_unsafe, _) -> 'extra_unsafe_add';
 
1312
 
 
1313
specialized_op('unsafe_sub', safe, Warn) ->
 
1314
  warning('unsafe_sub', safe, Warn), 'unsafe_sub';
 
1315
specialized_op('unsafe_sub', unsafe, _) -> 'unsafe_sub';
 
1316
specialized_op('unsafe_sub', extra_unsafe, _) -> 'unsafe_sub';
 
1317
 
 
1318
%% TODO: remove when not needed
 
1319
specialized_op('extra_unsafe_add', safe, Warn) ->
 
1320
  warning('extra_unsafe_add', safe, Warn), 'extra_unsafe_add';
 
1321
specialized_op('extra_unsafe_add', unsafe, Warn) ->
 
1322
  warning('extra_unsafe_add', unsafe, Warn), 'extra_unsafe_add';
 
1323
specialized_op('extra_unsafe_add', extra_unsafe, _) -> 'extra_unsafe_add';
 
1324
 
 
1325
specialized_op(Op, _, _) -> Op.
 
1326
 
 
1327
 
 
1328
specialized_if_op('<', true) -> 'fixnum_lt';
 
1329
specialized_if_op('=<', true) -> 'fixnum_le';
 
1330
specialized_if_op('>', true) -> 'fixnum_gt';
 
1331
specialized_if_op('>=', true) -> 'fixnum_ge';
 
1332
specialized_if_op('=:=', true) -> 'fixnum_eq';
 
1333
specialized_if_op('=/=', true) -> 'fixnum_neq';
 
1334
specialized_if_op(Op, _) -> Op.
 
1335
 
 
1336
%% this is not sane
 
1337
make_const({reg, N}, Range_info, Label) ->
 
1338
  range_info__def_range(Range_info, Label, {reg, N}); 
 
1339
make_const({const, {flat, N}}, _, _) when is_integer(N) -> 
 
1340
  range_init(const, {N, N}, false);
 
1341
make_const({const, _}, _, _) -> range_init(const, empty, true);
 
1342
make_const({fvar, _}, _, _) -> range_init(const, empty, true).
 
1343
 
 
1344
specialize_if(If, Range_info, Label) ->
 
1345
  IfOp = hipe_icode:if_op(If),
 
1346
  Use_ranges = lists:map(fun (Var) ->
 
1347
                             range_info__use_range(Range_info, Label,
 
1348
                                                   name_from_icode_var(Var))
 
1349
                         end, uses(If)),
 
1350
  Use_constants = lists:map(fun (Const) ->
 
1351
                                make_const(Const, Range_info, Label)
 
1352
                            end, consts(If)), 
 
1353
  RangeFun = fun(Range) -> 
 
1354
                 var_range__is_fixnum(Range) andalso
 
1355
                 (var_range__other(Range) =:= false) 
 
1356
             end,
 
1357
  New_if_op = specialized_if_op(IfOp, 
 
1358
                             lists:all(RangeFun, Use_ranges ++ Use_constants)),
 
1359
  hipe_icode:if_op_update(If, New_if_op).
 
1360
  
 
1361
  
 
1362
 
 
1363
specialize_call(Call, Range_info, Label) ->
 
1364
  Fun = hipe_icode:call_fun(Call),
 
1365
  New_fun = specialize_call_or_enter(Fun, Call, Range_info, Label),
 
1366
  hipe_icode:call_fun_update(Call, New_fun).
 
1367
 
 
1368
specialize_enter(Enter, Range_info, Label) ->
 
1369
  Fun = hipe_icode:enter_fun(Enter),
 
1370
  New_fun = specialize_call_or_enter(Fun, Enter, Range_info, Label),
 
1371
  hipe_icode:enter_fun_update(Enter, New_fun).
 
1372
 
 
1373
%% todo dont do unnecessary work
 
1374
specialize_call_or_enter(Fun, Operation, Range_info, Label) ->
 
1375
  Warn = range_info__warn(Range_info),
 
1376
  Use_ranges = lists:map(fun (Var) ->
 
1377
                             range_info__use_range(Range_info, Label,
 
1378
                                                   name_from_icode_var(Var))
 
1379
                         end, uses(Operation)),
 
1380
  Use_constants = lists:map(fun (Const) ->
 
1381
                                make_const(Const, Range_info, Label)
 
1382
                            end, consts(Operation)), 
 
1383
  Def_ranges = lists:map(fun (Var) ->
 
1384
                             range_info__def_range(Range_info, Label,
 
1385
                                                   name_from_icode_var(Var))
 
1386
                         end, defines(Operation)),
 
1387
  %% Range_list = Use_ranges ++ Def_ranges,
 
1388
  %% io:format("Fun ~p, ~nRange_list: ~p ~n", [Fun, Use_ranges ++ Def_ranges]),
 
1389
  %% pp_range_list(Range_list),
 
1390
  RangeFun = fun(Range) -> 
 
1391
                 var_range__is_fixnum(Range) andalso
 
1392
                 (var_range__other(Range) =:= false) 
 
1393
             end,
 
1394
  Use_fixnum = lists:all(RangeFun, Use_ranges ++ Use_constants),
 
1395
  Def_fixnum = lists:all(RangeFun, Def_ranges),
 
1396
  %% todo remove when tired of it.
 
1397
  lists:map(fun(Range) -> 
 
1398
                case var_range__is_constant(Range) of
 
1399
                  true ->
 
1400
                    warning('Found constant range', {Range, Label}, Warn);
 
1401
                  false ->
 
1402
                    ok
 
1403
                end
 
1404
            end,
 
1405
            Use_ranges ++ Def_ranges),
 
1406
  Fixnums = 
 
1407
    if Use_fixnum and Def_fixnum ->
 
1408
        extra_unsafe;
 
1409
       Use_fixnum ->
 
1410
        unsafe;
 
1411
       true ->
 
1412
        safe
 
1413
    end,
 
1414
  New_fun = specialized_op(Fun, Fixnums, Warn),
 
1415
  if New_fun =/= Fun ->
 
1416
    info(New_fun, Fun, Warn);
 
1417
  true ->
 
1418
    ok
 
1419
  end,
 
1420
  New_fun.
 
1421
 
 
1422
 
 
1423
%%
 
1424
%% Info struct
 
1425
%%
 
1426
%% Functionallity for the info struct
 
1427
%%
 
1428
 
 
1429
%%---------------------------------------------------------------------------
 
1430
%% Init
 
1431
%%---------------------------------------------------------------------------
 
1432
 
 
1433
info_struct__init(IC, Server, Options, Current_mfa = {_M, F, A}) ->
 
1434
  Exports = proplists:get_value(exports, Options),
 
1435
  Current_fa = {F,A},
 
1436
  Is_exported = lists:member(Current_fa, Exports),
 
1437
  StartLabel = hipe_icode_cfg:start_label(IC),
 
1438
  Params = hipe_icode_cfg:params(IC),
 
1439
  Liveness = hipe_icode_liveness:analyze(hipe_icode_type:unannotate_cfg(IC)), %todo
 
1440
  Pred_map = hipe_icode_cfg:pred_map(IC),
 
1441
  Is_closure = hipe_icode_cfg:is_closure(IC),
 
1442
  Warn = proplists:get_bool(icode_range_analysis_warn, Options),
 
1443
  %% io:format("~p analysing ~p ~n", [self(), Current_mfa]),
 
1444
  Info = #info_struct{current_mfa=Current_mfa,
 
1445
                      startlabel = StartLabel,
 
1446
                      predmap = Pred_map,
 
1447
                      liveness = Liveness,
 
1448
                      worklist = init_work(),
 
1449
                      server = Server,
 
1450
                      warn = Warn
 
1451
                     },
 
1452
  Server ! {self(), {load, message, {Current_mfa, args}}},
 
1453
  Arg_ranges = 
 
1454
    receive
 
1455
      none ->
 
1456
        [];
 
1457
      %% only if exported
 
1458
      {value, {Lookup_args, _Lookup_state}} ->
 
1459
        Lookup_args
 
1460
    end,
 
1461
  %% io:format("MFA: ~p Params: ~p Args: ~p ~n", [info_struct__current_mfa(Info), Params, Arg_ranges]),
 
1462
  case info_struct__add_params(Params, Info, Arg_ranges, Is_exported, Is_closure) of
 
1463
    break ->
 
1464
      break;
 
1465
    Info2 ->
 
1466
      info_struct__add_work(Info2, [info_struct__startlabel(Info2)])
 
1467
  end.
 
1468
 
 
1469
%%---------------------------------------------------------------------------
 
1470
%% Set/Get functions
 
1471
%%---------------------------------------------------------------------------
 
1472
 
 
1473
info_struct__get_range_tree(Tree_name, Info) ->
 
1474
  case gb_trees:lookup(Tree_name, info_struct__range_trees(Info)) of
 
1475
    {value, Tree} ->
 
1476
      Tree;
 
1477
    none ->
 
1478
      gb_trees:empty()
 
1479
  end.
 
1480
 
 
1481
%%info_struct__add_wideningvalue(_Value, Info) ->
 
1482
%%  Wideningvalues = info_struct__wideningvalues(Info),
 
1483
%%  New_wideningvalues = insert_ordered(Wideningvalues, Value),
 
1484
%%  Info#info_struct{wideningvalues=New_wideningvalues}.
 
1485
%%  Info.
 
1486
 
 
1487
info_struct__wideningvalues(#info_struct{wideningvalues = Values}) -> Values.
 
1488
 
 
1489
info_struct__insert_range(Var_range,Info) ->
 
1490
  Key = var_range__name(Var_range),             
 
1491
  Tree = info_struct__range_tree(Info),
 
1492
  Info#info_struct{current_range_tree=gb_trees:enter(Key, Var_range, Tree)}.
 
1493
 
 
1494
info_struct__live_labels(#info_struct{live_labels=Labels}) -> Labels.
 
1495
 
 
1496
info_struct__server(#info_struct{server=Server}) -> Server.
 
1497
 
 
1498
info_struct__live_vars(#info_struct{liveness=Liveness}, Label) -> 
 
1499
  hipe_icode_liveness:livein(Liveness, Label).
 
1500
 
 
1501
info_struct__increment_label_counter(Info = #info_struct{label_counters = Counters}, Label) ->
 
1502
  case gb_trees:lookup(Label, Counters) of
 
1503
    none ->
 
1504
      NewCounter = 1;
 
1505
    {value, Counter} ->
 
1506
      NewCounter = Counter + 1
 
1507
  end,
 
1508
  New_label_counter_tree = gb_trees:enter(Label, NewCounter, Counters),
 
1509
  Info#info_struct{label_counters = New_label_counter_tree}.
 
1510
 
 
1511
info_struct__counter_from_label(#info_struct{label_counters = Counters}, Label) ->
 
1512
  case gb_trees:lookup(Label, Counters) of
 
1513
    none ->
 
1514
      0;
 
1515
    {value, Counter} ->
 
1516
      Counter
 
1517
  end.
 
1518
 
 
1519
info_struct__get_phi_range(Dst_name, #info_struct{phi_values=Tree}) ->
 
1520
  case gb_trees:lookup(Dst_name, Tree) of
 
1521
    none ->
 
1522
      range_init(Dst_name, empty, false);
 
1523
    {value, Range} ->
 
1524
      Range
 
1525
  end.
 
1526
 
 
1527
info_struct__set_phi_range(Range, #info_struct{phi_values=Tree} = Info) ->
 
1528
  New_tree = gb_trees:enter(var_range__name(Range), Range, Tree),
 
1529
  Info#info_struct{phi_values=New_tree}.
 
1530
 
 
1531
info_struct__current_mfa(#info_struct{current_mfa=Mfa}) -> Mfa.
 
1532
 
 
1533
info_struct__set_current_mfa_not_done(Info, Bool) ->
 
1534
  Info#info_struct{current_mfa_not_done=Bool}.
 
1535
 
 
1536
info_struct__current_mfa_not_done(#info_struct{current_mfa_not_done=NotDone, 
 
1537
                                  current_mfa = MFA,
 
1538
                                  server = Server,
 
1539
                                  is_recursive = Recursive} = Info) ->
 
1540
 
 
1541
 
 
1542
  NotDone and 
 
1543
  if Recursive ->
 
1544
    Server ! {self(), {load, message, {MFA, return_range}}},
 
1545
    Old_return = 
 
1546
    receive
 
1547
      none ->
 
1548
        range_init(return_range, empty, false);
 
1549
      {value, {Lookup_range, _Final}} ->
 
1550
        Lookup_range
 
1551
    end,
 
1552
    not var_range__is_equal(return_range(Info), Old_return);
 
1553
  true ->
 
1554
    true
 
1555
  end.
 
1556
 
 
1557
info_struct__predmap(#info_struct{predmap=Pred}) -> Pred.
 
1558
 
 
1559
info_struct__range_tree(#info_struct{current_range_tree=Tree}) -> Tree.
 
1560
 
 
1561
info_struct__range_trees(#info_struct{range_trees=Tree}) -> Tree.
 
1562
 
 
1563
info_struct__return_vars(#info_struct{return_vars=Vars}) -> Vars.
 
1564
 
 
1565
info_struct__startlabel(#info_struct{startlabel=StartLabel}) -> StartLabel.
 
1566
 
 
1567
info_struct__worklist(#info_struct{worklist=List}) -> List. 
 
1568
 
 
1569
info_struct__add_live_labels(Info, Label_list) ->
 
1570
  lists:foldl(fun(Label, InfoAcc) ->
 
1571
                  Labels = info_struct__live_labels(InfoAcc),
 
1572
                  Info#info_struct{live_labels = gb_sets:add(Label, Labels)}
 
1573
              end,
 
1574
              Info,
 
1575
              Label_list).
 
1576
 
 
1577
info_struct__add_work(Info, NewWork) ->
 
1578
  %% io:format("NewWork ~p ~n", [NewWork]),
 
1579
  Worklist = info_struct__worklist(Info),
 
1580
  New_worklist = add_work(Worklist, NewWork),
 
1581
  Info2 = info_struct__add_live_labels(Info, NewWork),
 
1582
  Info2#info_struct{worklist = New_worklist}.
 
1583
 
 
1584
info_struct__current_label(#info_struct{current_label=Label}) -> Label.
 
1585
 
 
1586
info_struct__add_params([], Info, _, _, _) -> 
 
1587
  StartLabel = info_struct__startlabel(Info),
 
1588
  {_, Info2} = info_struct__save_current_range_tree({params, StartLabel}, Info),
 
1589
  Info2;
 
1590
info_struct__add_params([Param|ParamList], Info, Arg_range_list,
 
1591
                        Is_exported, Is_closure) ->
 
1592
  Key = name_from_icode_var(Param),
 
1593
  {List, Range_info} =
 
1594
    if Is_exported or Is_closure ->
 
1595
        {[], range_init(Key, {neginf, posinf}, true)};
 
1596
       true ->
 
1597
        case Arg_range_list of
 
1598
          [Arg_range|Arg_range_tail] -> %% var_range__copy ??
 
1599
            Int_range = var_range__range(Arg_range),
 
1600
            Other = var_range__other(Arg_range),
 
1601
            New_arg_range = range_init(Key, Int_range, Other),
 
1602
            {Arg_range_tail, New_arg_range};
 
1603
          [] ->
 
1604
            ?not_done_debug("In add params ~n", []),
 
1605
            {[], break}
 
1606
        end
 
1607
    end,
 
1608
  case Range_info of
 
1609
    break ->
 
1610
      break;
 
1611
    Range ->
 
1612
      %% `io:format("MFA: ~p arg: ~p ~n", [info_struct__current_mfa(Info), New_range]), 
 
1613
      %% io:format("Param ~p range: ~p ~n", [Param, New_range]),
 
1614
      NewInfo = info_struct__insert_range(Range, Info),
 
1615
      info_struct__add_params(ParamList, NewInfo, List, Is_exported, Is_closure)
 
1616
  end.
 
1617
 
 
1618
info_struct__add_return_var(Variable, Info) -> 
 
1619
  Return_list = info_struct__return_vars(Info),
 
1620
  Label = info_struct__current_label(Info),
 
1621
  Key = {Variable, Label},
 
1622
  case lists:member(Key, Return_list) of
 
1623
    true ->     
 
1624
      Info;
 
1625
    false ->
 
1626
      Info#info_struct{return_vars = [Key|Return_list]}
 
1627
  end.
 
1628
 
 
1629
info_struct__get_range(Var, Info) ->
 
1630
  case gb_trees:lookup(Var, info_struct__range_tree(Info)) of
 
1631
    none ->
 
1632
      range_init(Var, empty, false);
 
1633
    {_, Range} ->
 
1634
      Range
 
1635
  end.
 
1636
 
 
1637
%info_struct__is_recursive(#info_struct{is_recursive = Bool}) -> Bool.
 
1638
 
 
1639
 
 
1640
info_struct__set_is_recursive(Bool, Info) -> 
 
1641
  Info#info_struct{is_recursive = Bool}.
 
1642
 
 
1643
info_struct__warn(#info_struct{warn = Warn}) ->
 
1644
  Warn.
 
1645
 
 
1646
%%---------------------------------------------------------------------------
 
1647
%% Loading / Savinging range trees
 
1648
%%---------------------------------------------------------------------------
 
1649
 
 
1650
info_struct__set_new_current_tree(Label, Info) ->
 
1651
  New_range_tree = 
 
1652
  case info_struct__pred_tree(Label, Info) of
 
1653
    none ->
 
1654
      [];
 
1655
    {value, Tree} ->
 
1656
      Tree
 
1657
  end,
 
1658
  Range_list = gb_trees:values(New_range_tree),
 
1659
  No_not_set = lists:all(
 
1660
                 fun (Range) ->
 
1661
                     not (var_range__is_empty(Range) andalso
 
1662
                          var_range__is_not_other(Range))
 
1663
                 end,
 
1664
                 Range_list),
 
1665
  case No_not_set of
 
1666
    true ->
 
1667
      Counter = info_struct__counter_from_label(Info, Label),
 
1668
      %% io:format("Counter ~p, Label ~p~n", [Counter, Label]),
 
1669
      if Counter > ?LABELITERATIONS ->
 
1670
          MFA = info_struct__current_mfa(Info),
 
1671
          Label = info_struct__current_label(Info),
 
1672
          Warn = info_struct__warn(Info),
 
1673
          warning('taking forever', {MFA, Label}, Warn);
 
1674
         true ->
 
1675
          ok
 
1676
      end,
 
1677
      Info#info_struct{current_range_tree = New_range_tree};
 
1678
    false ->
 
1679
      ?not_done_debug("set new current tree ~n", []),
 
1680
      break
 
1681
  end.
 
1682
 
 
1683
%% TODO: byt updatelist till updateset ??
 
1684
info_struct__save_spec_range_tree(Info, {Range, To_label}, Update_list) ->
 
1685
  %% io:format("Spec_tree Update_list ~p ~n", [Update_list]),
 
1686
  Current_label = info_struct__current_label(Info),
 
1687
  Edge = {Current_label, To_label},
 
1688
  Range_name = var_range__name(Range),
 
1689
  %% io:format("Range_name, Edge: ~p, ~p ~n", [Range_name, Edge]),
 
1690
  case lists:keysearch({Range_name, Edge}, 1, Update_list) of
 
1691
    {value, {_, Old_range}} -> 
 
1692
      Insert_range = range_union(Range_name, [Old_range, Range]),
 
1693
      lists:keyreplace({Range_name, Edge}, 1, Update_list, {{Range_name, Edge}, Insert_range});
 
1694
    false ->
 
1695
      [{{Range_name, Edge}, Range}|Update_list]
 
1696
  end.
 
1697
  
 
1698
 
 
1699
%
 
1700
% Update_list is a list of ranges that has been updated on 
 
1701
%
 
1702
%
 
1703
save_other_ranges(Info, _Update_list, [], Updated_edges) -> 
 
1704
  {Updated_edges, Info};
 
1705
save_other_ranges(Info, Update_list, [Label|Labels], Updated_edges_list) ->
 
1706
  Current_range_tree = info_struct__range_tree(Info),
 
1707
  %% io:format("Update_list ~p ~n", [Update_list]),
 
1708
  New_range_tree = 
 
1709
    lists:foldl(
 
1710
      fun({{Range_name, {_From_label, To_label}}, Range}, Tree) ->
 
1711
          if (To_label =:= Label)  ->
 
1712
              gb_trees:enter(Range_name, Range, Tree); %%Todo union?
 
1713
             true ->
 
1714
              Tree
 
1715
          end
 
1716
      end,
 
1717
      Current_range_tree,
 
1718
      Update_list),
 
1719
  {Updated_edges, NewInfo} = info_struct__save_range_tree({info_struct__current_label(Info), Label}, New_range_tree, Info),
 
1720
  save_other_ranges(NewInfo, Update_list, Labels, 
 
1721
                    Updated_edges_list ++ Updated_edges).
 
1722
 
 
1723
info_struct__save_spec_range_trees(Info, List, Labels) ->
 
1724
  info_struct__save_spec_range_trees(Info, List, [], Labels).
 
1725
 
 
1726
info_struct__save_spec_range_trees(Info, [], Update_list, Labels) -> 
 
1727
  save_other_ranges(Info, Update_list, Labels, []);
 
1728
info_struct__save_spec_range_trees(Info, [{Range, Label}|List], Update_list, Labels) ->
 
1729
  New_update_list = info_struct__save_spec_range_tree(Info, {Range, Label}, Update_list),
 
1730
  info_struct__save_spec_range_trees(Info, List, New_update_list, Labels).
 
1731
 
 
1732
info_struct__save_trees_on_edges([], Info, Updated_edges_list) -> {Updated_edges_list, Info};
 
1733
info_struct__save_trees_on_edges([To_label|To_label_list], Info, Updated_edges_list) ->
 
1734
  Current_label = info_struct__current_label(Info), 
 
1735
  {Updated_edges, NewInfo} = info_struct__save_current_range_tree({Current_label, To_label}, Info),
 
1736
  %% io:format("Updated_edges ~p ~n", [Updated_edges]),
 
1737
  info_struct__save_trees_on_edges(To_label_list, NewInfo, Updated_edges ++ Updated_edges_list).
 
1738
 
 
1739
live_ranges({out_tree, _}, Range_tree, _) -> Range_tree;
 
1740
live_ranges({_, return}, Range_tree, _) -> Range_tree;
 
1741
live_ranges({_From_label, To_label}, Range_tree, Info) ->
 
1742
  Livelist = info_struct__live_vars(Info, To_label),
 
1743
  Liveset = gb_sets:from_list(Livelist), %%not linear search todo performance?
 
1744
  Range_list = gb_trees:to_list(Range_tree),
 
1745
  Live_range_list  =
 
1746
    lists:filter(
 
1747
      fun({Name, _Range}) -> %%TODO assert:Name should be same as var_range_name
 
1748
          gb_sets:is_element({var, Name}, Liveset)
 
1749
      end,
 
1750
      Range_list),
 
1751
  gb_trees:from_orddict(Live_range_list).
 
1752
 
 
1753
info_struct__pred_tree(Label, #info_struct{pred_trees = Trees}) ->
 
1754
  gb_trees:lookup(Label, Trees).
 
1755
 
 
1756
info_struct__set_pred_tree(Label, Pred_tree, #info_struct{pred_trees = Trees} = Info) ->
 
1757
  Info#info_struct{pred_trees = gb_trees:enter(Label, Pred_tree, Trees)}.
 
1758
 
 
1759
info_struct__save_current_range_tree(Edge, Info) ->
 
1760
  Current_range_tree = info_struct__range_tree(Info),   
 
1761
  info_struct__save_range_tree(Edge, Current_range_tree, Info).
 
1762
 
 
1763
info_struct__save_range_tree(Edge, Insert_tree, Info) ->
 
1764
  {_, To_label} = Edge, 
 
1765
  Live_tree = live_ranges(Edge, Insert_tree, Info),
 
1766
  {Update_value, New_range_tree, New_pred_tree} = 
 
1767
    case info_struct__pred_tree(To_label, Info) of
 
1768
      none ->
 
1769
        {true, Live_tree, Live_tree};
 
1770
      {value, Old_pred_tree} ->
 
1771
        Union_pred_tree = range_tree_union([Old_pred_tree, 
 
1772
                                        Live_tree]),
 
1773
        {range_tree_is_different(Old_pred_tree, Union_pred_tree), Insert_tree, Union_pred_tree}
 
1774
    end,
 
1775
  
 
1776
  Final_range_trees = gb_trees:enter(Edge, New_range_tree, info_struct__range_trees(Info)),
 
1777
  Info2 = Info#info_struct{range_trees = Final_range_trees},
 
1778
  if Update_value =:= true ->
 
1779
      {[Edge], info_struct__set_pred_tree(To_label, New_pred_tree, Info2)};
 
1780
     true ->
 
1781
      {[], Info2}
 
1782
  end.
 
1783
 
 
1784
%%
 
1785
%% Helper functions
 
1786
%%
 
1787
 
 
1788
%% Range tree
 
1789
 
 
1790
range_tree_is_different(Range_tree1, Range_tree2) ->
 
1791
  case gb_trees:size(Range_tree1) =:= gb_trees:size(Range_tree2) of
 
1792
    true ->
 
1793
      Range_list1 = gb_trees:values(Range_tree1),
 
1794
      Range_list2 = gb_trees:values(Range_tree2),
 
1795
      Range_tuple_list = lists:zip(Range_list1, Range_list2),
 
1796
      lists:any(
 
1797
        fun({Range1, Range2}) -> not var_range__is_equal(Range1, Range2) end, 
 
1798
        Range_tuple_list
 
1799
      );
 
1800
    false ->
 
1801
      true
 
1802
  end.
 
1803
 
 
1804
get_edge_tree_list(PredList, Label, Version, Info) ->
 
1805
  lists:map(
 
1806
    fun(Pred) ->
 
1807
      Search_pattern = 
 
1808
        if Version =:= old ->
 
1809
          {old, {Pred, Label}};
 
1810
        true ->
 
1811
          {Pred, Label}
 
1812
        end,
 
1813
      info_struct__get_range_tree(Search_pattern, Info)
 
1814
    end,
 
1815
    PredList).
 
1816
 
 
1817
info_struct__merge_pred_range_trees(Label, Version, Info) ->
 
1818
  StartLabel = info_struct__startlabel(Info),
 
1819
  Predmap = info_struct__predmap(Info),
 
1820
  %% io:format("PredMap: ~p, Label: ~p,", [Predmap, Label]),
 
1821
  Pred = hipe_icode_cfg:pred(Predmap, Label),
 
1822
  Pred_range_trees = get_edge_tree_list(Pred, Label, Version, Info),
 
1823
  if Label =:= StartLabel ->
 
1824
      [Params] = get_edge_tree_list([params], Label, Version, Info),
 
1825
      New_pred_range_trees = [Params|Pred_range_trees];
 
1826
     true ->
 
1827
      New_pred_range_trees = Pred_range_trees
 
1828
  end,
 
1829
  range_tree_union(New_pred_range_trees).
 
1830
 
 
1831
range_tree_union([]) -> gb_trees:empty();
 
1832
range_tree_union([Range_tree]) -> 
 
1833
  Range_tree;
 
1834
range_tree_union([Range_tree|Range_tree_list]) ->
 
1835
  Range_List = gb_trees:to_list(Range_tree),
 
1836
  range_tree_range_list_union(Range_List, range_tree_union(Range_tree_list)).
 
1837
 
 
1838
range_tree_range_list_union([], Tree) -> Tree;
 
1839
range_tree_range_list_union([{Name, Range}|Range_list], Tree) ->
 
1840
  case gb_trees:lookup(Name, Tree) of
 
1841
    none ->
 
1842
      NewTree = gb_trees:insert(Name, Range, Tree);
 
1843
    {_Name2, Range2} ->
 
1844
      NewRange = range_union(Name, [Range,Range2]),
 
1845
      NewTree = gb_trees:update(Name, NewRange, Tree)
 
1846
  end,
 
1847
  range_tree_range_list_union(Range_list, NewTree).
 
1848
 
 
1849
in_range_trees_from_info_struct_1(_Info, [], Label_range_tree) ->
 
1850
  Label_range_tree;
 
1851
in_range_trees_from_info_struct_1(Info, [Label|Labels], Label_range_tree) ->
 
1852
  Range_tree = info_struct__merge_pred_range_trees(Label, new, Info),
 
1853
  %% io:format("Label ~p, ~nIn_Range_tree ~p ~n", [Label, gb_trees:values(Range_tree)]),
 
1854
  New_label_range_tree = gb_trees:insert(Label, Range_tree, Label_range_tree),
 
1855
  in_range_trees_from_info_struct_1(Info, Labels, New_label_range_tree).
 
1856
 
 
1857
in_range_trees_from_info_struct(Info, Live_labels) ->
 
1858
  Live_labels_list = gb_sets:to_list(Live_labels),
 
1859
  in_range_trees_from_info_struct_1(Info, Live_labels_list, gb_trees:empty()).
 
1860
 
 
1861
out_range_trees_from_info_struct_1(_Info, [], Label_range_tree) ->
 
1862
  Label_range_tree;
 
1863
out_range_trees_from_info_struct_1(Info, [Label|Labels], Label_range_tree) ->
 
1864
  Range_tree = info_struct__get_range_tree({out_tree, Label}, Info),
 
1865
  %% io:format("Label ~p, ~nOut_range_tree ~p ~n", [Label, gb_trees:values(Range_tree)]),
 
1866
  %% info_struct__merge_succ_range_trees(Label, Info),
 
1867
  New_label_range_tree = gb_trees:insert(Label, Range_tree, Label_range_tree),
 
1868
  out_range_trees_from_info_struct_1(Info, Labels, New_label_range_tree).
 
1869
 
 
1870
out_range_trees_from_info_struct(Info, Live_labels) ->
 
1871
  Live_labels_list = gb_sets:to_list(Live_labels),
 
1872
  out_range_trees_from_info_struct_1(Info, Live_labels_list, gb_trees:empty()).
 
1873
 
 
1874
%%-----------------------------------------------------------------------------
 
1875
%% Worklist
 
1876
%%-----------------------------------------------------------------------------
 
1877
 
 
1878
init_work() ->
 
1879
  {[], [], gb_sets:empty()}.
 
1880
 
 
1881
get_work({[Label|Left], List, Set}) ->
 
1882
  NewWork = {Left, List, gb_sets:delete(Label, Set)},
 
1883
  {Label, NewWork};
 
1884
get_work({[], [], _Set}) ->
 
1885
  fixpoint;
 
1886
get_work({[], List, Set}) ->
 
1887
  get_work({lists:reverse(List), [], Set}).
 
1888
 
 
1889
add_work(Work = {List1, List2, Set},[Label|Left])->
 
1890
  case gb_sets:is_member(Label, Set) of
 
1891
    true ->
 
1892
      add_work(Work, Left);
 
1893
    false ->
 
1894
      %% io:format("Adding work: ~w\n", [Label]),
 
1895
      add_work({List1, [Label|List2], gb_sets:insert(Label, Set)}, Left)
 
1896
  end;
 
1897
add_work(Work, []) ->
 
1898
  Work.
 
1899
 
 
1900
info_struct__get_work(Info) ->
 
1901
  Worklist = info_struct__worklist(Info),
 
1902
  %% io:format("Worklist ~p ~n", [Worklist]),
 
1903
  case get_work(Worklist) of 
 
1904
    fixpoint ->
 
1905
      {none, Info};
 
1906
    {Label, New_worklist} ->
 
1907
      NewWork = {value, Label},
 
1908
      Info2 = Info#info_struct{current_label=Label},
 
1909
      Work = New_worklist,
 
1910
      Info3 = info_struct__increment_label_counter(Info2, Label),
 
1911
      {NewWork, Info3#info_struct{worklist=Work}}
 
1912
  end.
 
1913
 
 
1914
 
 
1915
%% Other
 
1916
 
 
1917
input_range(Info) ->
 
1918
  StartLabel = info_struct__startlabel(Info),
 
1919
  Params = info_struct__get_range_tree({params, StartLabel}, Info),
 
1920
  gb_trees:values(Params).
 
1921
 
 
1922
return_range(Info) ->
 
1923
  Return_info = info_struct__return_vars(Info),
 
1924
  {Return_variables, Return_labels} = lists:unzip(Return_info),
 
1925
  Trees = get_edge_tree_list(Return_labels, return, new, Info), 
 
1926
  Return_ranges = return_ranges(Return_variables, Trees, Info),
 
1927
  range_union(return_range, Return_ranges).     
 
1928
 
 
1929
return_ranges([], [], _) -> []; %% lists:map ??
 
1930
return_ranges([Variable|VariableList], [Tree|TreeList], Info) ->
 
1931
  Range = gb_trees:get(Variable, Tree),
 
1932
  [Range | return_ranges(VariableList, TreeList, Info)].
 
1933
 
 
1934
 
 
1935
%%
 
1936
%% Range struct
 
1937
%%
 
1938
%% Functionallity for the range struct
 
1939
%%
 
1940
 
 
1941
-ifdef(DEBUG).
 
1942
var_range__is_correct(#var_range{range=empty}) -> true;
 
1943
var_range__is_correct(#var_range{range={Min, Max}}) when (Min =/= empty),
 
1944
                                                         (Max =/= empty) ->
 
1945
  true.
 
1946
-endif.
 
1947
 
 
1948
is_max(posinf) -> true;
 
1949
is_max(N) when is_integer(N) -> true.
 
1950
 
 
1951
is_min(neginf) -> true;
 
1952
is_min(N) when is_integer(N) -> true.
 
1953
    
 
1954
 
 
1955
range_init_1(Name, empty) ->
 
1956
  #var_range{var_name = Name, range=empty};
 
1957
range_init_1(Name, {Min, Max}) -> 
 
1958
  true = is_max(Max),
 
1959
  true = is_min(Min),
 
1960
  IsNotEmpty = inf_geq(Max, Min),
 
1961
  if not IsNotEmpty ->
 
1962
      #var_range{var_name=Name, range=empty};
 
1963
     (Min =/= empty) and (Max =/= empty) ->
 
1964
      #var_range{var_name=Name, range={Min, Max}}
 
1965
  end.
 
1966
 
 
1967
range_init(Name, empty, Other) -> 
 
1968
  Var_range = range_init_1(Name, empty),
 
1969
  Var_range#var_range{other = Other};
 
1970
range_init(Name, {Min, Max} = Range, Other) when (Min =/= empty),
 
1971
                                                 (Max =/= empty) ->
 
1972
  Var_range = range_init_1(Name, Range),
 
1973
  Var_range#var_range{other = Other}.
 
1974
 
 
1975
var_range__other(#var_range{other = Other}) -> Other.
 
1976
var_range__name(#var_range{var_name=Name}) -> Name.
 
1977
 
 
1978
var_range__is_empty(#var_range{range=empty}) -> true;
 
1979
var_range__is_empty(#var_range{range={Min, Max}})  
 
1980
  when (Min =/= empty), (Max =/= empty) -> false. %% force tuple
 
1981
 
 
1982
var_range__is_not_other(#var_range{other=Bool}) -> not Bool.
 
1983
 
 
1984
var_range__range(#var_range{range=Range}) -> Range.
 
1985
 
 
1986
var_range__set_other(Range, Other) ->
 
1987
  Range#var_range{other = Other}.
 
1988
 
 
1989
var_range__max(#var_range{range=empty}) -> empty;
 
1990
var_range__max(#var_range{range={_, Max}}) when Max =/= empty -> Max.
 
1991
 
 
1992
var_range__min(#var_range{range=empty}) -> empty;
 
1993
var_range__min(#var_range{range={Min, _}}) when Min =/= empty -> Min.
 
1994
 
 
1995
var_range__is_equal(#var_range{range=empty, other=Bool},
 
1996
                    #var_range{range=empty, other=Bool}) -> true;
 
1997
var_range__is_equal(#var_range{range={Min, Max}, other=Bool},
 
1998
                    #var_range{range={Min, Max}, other=Bool}) -> true;
 
1999
var_range__is_equal(#var_range{}, #var_range{}) -> false.
 
2000
 
 
2001
var_range__copy(Range, Name) ->
 
2002
  Range#var_range{var_name = Name}.
 
2003
 
 
2004
var_range__is_constant(#var_range{range={Min,Max}}) 
 
2005
  when (Min =/= empty), (Max =/= empty) -> Min =:= Max;
 
2006
var_range__is_constant(#var_range{range=empty}) -> false.
 
2007
 
 
2008
to_string(#var_range{range = empty, other=false}) ->
 
2009
  "no posible value";
 
2010
to_string(#var_range{range = empty, other=_Other}) ->
 
2011
  "[empty]"; %, other: " ++ atom_to_list(Other);
 
2012
to_string(Range) ->
 
2013
  Min = var_range__min(Range),
 
2014
  Max = var_range__max(Range),
 
2015
  if is_atom(Min) ->
 
2016
      P_Min = atom_to_list(Min);
 
2017
     true ->
 
2018
      P_Min = integer_to_list(Min)
 
2019
  end,
 
2020
  if is_atom(Max) ->
 
2021
      P_Max = atom_to_list(Max);
 
2022
     true ->
 
2023
      P_Max = integer_to_list(Max)
 
2024
  end,
 
2025
  "[" ++ P_Min ++ ", " ++ P_Max ++ "]". 
 
2026
%% "[" ++ P_Min ++ ", " ++ P_Max ++ "], other: " ++ atom_to_list(Other). 
 
2027
 
 
2028
var_range__is_fixnum(Range) ->
 
2029
  Min = var_range__min(Range),
 
2030
  Max = var_range__max(Range),
 
2031
  if is_integer(Min), is_integer(Max) ->
 
2032
      hipe_tagscheme:is_fixnum(Min) andalso hipe_tagscheme:is_fixnum(Max);
 
2033
     true ->
 
2034
      false
 
2035
  end.
 
2036
 
 
2037
%%---------------------------------------------------------------------------
 
2038
%% Range operations
 
2039
%%---------------------------------------------------------------------------
 
2040
 
 
2041
%% Arithmetic
 
2042
 
 
2043
range_add(Name, Range1, Range2) ->
 
2044
  NewMin = inf_add(var_range__min(Range1), var_range__min(Range2)),
 
2045
  NewMax = inf_add(var_range__max(Range1), var_range__max(Range2)),
 
2046
  Other = var_range__other(Range1) orelse var_range__other(Range2),
 
2047
  range_init(Name, {NewMin, NewMax}, Other).
 
2048
 
 
2049
 
 
2050
range_sub(Name, Range1, Range2) ->
 
2051
  Min_sub = inf_min([inf_inv(var_range__max(Range2)), inf_inv(var_range__min(Range2))]),
 
2052
  Max_sub = inf_max([inf_inv(var_range__max(Range2)), inf_inv(var_range__min(Range2))]),
 
2053
  NewMin = inf_add(var_range__min(Range1), Min_sub),
 
2054
  NewMax = inf_add(var_range__max(Range1), Max_sub),
 
2055
  Other = var_range__other(Range1) orelse var_range__other(Range2),
 
2056
  range_init(Name, {NewMin, NewMax}, Other).
 
2057
 
 
2058
 
 
2059
range_mult(Name, #var_range{range = empty, other = true}, _Range2) ->
 
2060
  range_init(Name, empty, true); 
 
2061
range_mult(Name, _Range1, #var_range{range = empty, other = true}) ->
 
2062
  range_init(Name, empty, true); 
 
2063
range_mult(Name, Range1, Range2) ->
 
2064
  Min1 = var_range__min(Range1),
 
2065
  Min2 = var_range__min(Range2),
 
2066
  Max1 = var_range__max(Range1),
 
2067
  Max2 = var_range__max(Range2),
 
2068
  GreaterMin1 = inf_greater_zero(Min1),
 
2069
  GreaterMin2 = inf_greater_zero(Min2),
 
2070
  GreaterMax1 = inf_greater_zero(Max1),
 
2071
  GreaterMax2 = inf_greater_zero(Max2),
 
2072
  Range = 
 
2073
    if GreaterMin1 -> % Kolumn 3
 
2074
        if GreaterMin2 -> % <3,3>
 
2075
            {inf_mult(Min1, Min2), inf_mult(Max1, Max2)};
 
2076
           GreaterMax2 -> % <3,2>
 
2077
            {inf_mult(Min2, Max1), inf_mult(Max2, Max1)};
 
2078
           true -> % <3,1>
 
2079
            {inf_mult(Min2, Max1), inf_mult(Max2, Min1)}
 
2080
        end;
 
2081
       %% Kolumn 1 eller 2
 
2082
       GreaterMin2 -> % Kolumn 1 eller 2 rad 3
 
2083
        var_range__range(range_mult(Name, Range2, Range1));
 
2084
       GreaterMax1 -> %Kolumn 2 Rad 1 eller 2
 
2085
        if GreaterMax2 -> % Kolumn 2 Rad 2
 
2086
            NewMin = inf_min([inf_mult(Min2, Max1), inf_mult(Max2, Min1)]),
 
2087
            NewMax = inf_max([inf_mult(Min2, Min1), inf_mult(Max2, Max1)]),
 
2088
            {NewMin, NewMax};
 
2089
           true -> % Kolumn 2 Rad 1
 
2090
            {inf_mult(Min2, Max1), inf_mult(Min2, Min1)}
 
2091
        end;
 
2092
       GreaterMax2 -> % Kolumn 1 Rad 2  
 
2093
        var_range__range(range_mult(Name, Range2, Range1));
 
2094
       true -> % Kolumn 1 Rad 1 
 
2095
        inf_mult(Min2, Max1)
 
2096
    end,
 
2097
  Other = var_range__other(Range1) orelse var_range__other(Range2),
 
2098
  range_init(Name, Range, Other).
 
2099
 
 
2100
 
 
2101
extreme_divisors(#var_range{range={0,0}}) -> {0,0};
 
2102
extreme_divisors(#var_range{range={0,Max}}) -> {1,Max};
 
2103
extreme_divisors(#var_range{range={Min,0}}) -> {Min,-1};
 
2104
extreme_divisors(#var_range{range={Min,Max}}) ->
 
2105
  case inf_geq(Min, 0) of 
 
2106
    true -> {Min, Max};
 
2107
    false -> %Min < 0
 
2108
      case inf_geq(0, Max) of
 
2109
        true -> {Min,Max}; %Max < 0
 
2110
        false -> {-1,1} %Max > 0
 
2111
      end
 
2112
  end.
 
2113
 
 
2114
%% this is div, not /.
 
2115
range_div(Name, _, #var_range{range={0,0}}) ->
 
2116
  range_init(Name, empty, false);
 
2117
range_div(Name, #var_range{range=empty}, _) ->
 
2118
  range_init(Name, empty, false);
 
2119
range_div(Name, Range1, Den) ->
 
2120
  Min1 = var_range__min(Range1),
 
2121
  Max1 = var_range__max(Range1),
 
2122
  {Min2, Max2} = extreme_divisors(Den),
 
2123
  Min_max_list = [inf_div(Min1, Min2), inf_div(Min1, Max2), inf_div(Max1, Min2), inf_div(Max1, Max2)],
 
2124
  range_init(Name, {inf_min(Min_max_list), inf_max(Min_max_list)}, false).
 
2125
  
 
2126
range_rem(Name, Range1, Range2) ->
 
2127
  %% Range1 desides the sign of the answer.
 
2128
  Min1 = var_range__min(Range1),
 
2129
  Max1 = var_range__max(Range1),
 
2130
  Min2 = var_range__min(Range2),
 
2131
  Max2 = var_range__max(Range2),
 
2132
  Min1_geq_zero = inf_geq(Min1, 0),
 
2133
  Max1_leq_zero = inf_geq(0, Max1),
 
2134
  Max_range2 = inf_max([inf_abs(Min2), inf_abs(Max2)]),
 
2135
  Max_range2_leq_zero = inf_geq(0, Max_range2),
 
2136
  New_min = 
 
2137
    if Min1_geq_zero ->
 
2138
        0;
 
2139
       Max_range2_leq_zero ->
 
2140
        Max_range2;
 
2141
       true ->
 
2142
        inf_inv(Max_range2)
 
2143
    end,
 
2144
  New_max = 
 
2145
    if Max1_leq_zero ->
 
2146
        0;
 
2147
       Max_range2_leq_zero -> %% Max_range2 =:= 0 ??
 
2148
        inf_inv(Max_range2);
 
2149
       true ->
 
2150
        Max_range2
 
2151
    end,
 
2152
  range_init(Name, {New_min, New_max}, false).
 
2153
 
 
2154
%% Bit operations       
 
2155
 
 
2156
range_bsr(Name, Range1, Range2=#var_range{range={Min, Max}}) -> %% todo do not match on {Min, Max}, or??
 
2157
  New_Range2 = range_init(var_range__name(Range2), {inf_inv(Max), inf_inv(Min)}, var_range__other(Range2)), 
 
2158
  range_bsl(Name, Range1, New_Range2).
 
2159
 
 
2160
range_bsl(Name, Range1, Range2) ->
 
2161
  Min1 = var_range__min(Range1),
 
2162
  Min2 = var_range__min(Range2),
 
2163
  Max1 = var_range__max(Range1),
 
2164
  Max2 = var_range__max(Range2),
 
2165
  %%TODO inte >= 0 !!!
 
2166
  %% io:format("Min1 ~p, Max1 ~p, Min2 ~p, Max2 ~p~n", [Min1, Max1, Min2, Max2]),
 
2167
  %% Not_fixed_return_range = 
 
2168
  {Min, Max} = 
 
2169
    if Min1 >= 0 ->
 
2170
        {inf_bsl(Min1, Min2), inf_bsl(Max1, Max2)};
 
2171
       true ->
 
2172
        if Max1 < 0 ->
 
2173
            {inf_bsl(Min1, Max2), inf_bsl(Max1, Min2)};
 
2174
           true ->
 
2175
            {inf_bsl(Min1, Max2), inf_bsl(Max1, Max2)}
 
2176
        end
 
2177
    end,
 
2178
  true = is_min(Min),
 
2179
  true = is_max(Max),
 
2180
  range_init(Name, {Min, Max}, false).
 
2181
 
 
2182
range_bnot(Name, Range) ->
 
2183
  Minus_one = range_init(const, {-1,-1}, false),
 
2184
  range_add(Name, range_mult(Name, Range, Minus_one), Minus_one).
 
2185
 
 
2186
width({Min, Max}) -> inf_max([width(Min), width(Max)]);
 
2187
width(posinf) -> posinf;
 
2188
width(neginf) -> posinf;
 
2189
width(X) when X >= 0 ->
 
2190
  poswidth(X, 0);
 
2191
width(X) when X < 0 ->
 
2192
  negwidth(X, 0).
 
2193
 
 
2194
poswidth(X, N) ->
 
2195
  case X < (1 bsl N) of
 
2196
    true ->
 
2197
      N;
 
2198
    false ->
 
2199
      poswidth(X, N+1)
 
2200
  end.
 
2201
 
 
2202
negwidth(X, N) ->
 
2203
  case X > (-1 bsl N) of
 
2204
    true ->
 
2205
      N;
 
2206
    false ->
 
2207
      negwidth(X, N+1)
 
2208
  end.
 
2209
 
 
2210
range_band(Name, R1, R2) ->
 
2211
  {Min1, Max1} = var_range__range(R1),
 
2212
  {Min2, Max2} = var_range__range(R2),
 
2213
  Width = inf_min([width({Min1, Max1}), width({Min2, Max2})]),
 
2214
  true = inf_geq(Width, 0),
 
2215
  Min =
 
2216
    case inf_geq(0, Min1) and inf_geq(0, Min2) of
 
2217
      true ->
 
2218
        inf_bsl(-1, Width);
 
2219
      false ->
 
2220
        0
 
2221
    end,
 
2222
  Max =
 
2223
    case inf_geq(0, Max1) and inf_geq(0, Max2) of
 
2224
      true ->
 
2225
        0;
 
2226
      false ->
 
2227
        inf_bsl(1, Width)
 
2228
    end,
 
2229
  true = is_min(Min),
 
2230
  true = is_max(Max),
 
2231
  range_init(Name, {Min, Max}, false).
 
2232
 
 
2233
range_bor(Name, R1, R2) ->
 
2234
  {Min1, Max1} = var_range__range(R1),
 
2235
  {Min2, Max2} = var_range__range(R2),
 
2236
  Width = width({width({Min1, Max1}), width({Min2, Max2})}),
 
2237
  Min =
 
2238
    case inf_geq(Max1, 0) and inf_geq(Max2, 0) of
 
2239
      true ->
 
2240
        0;
 
2241
      false ->
 
2242
        inf_bsl(-1, Width)
 
2243
    end,          
 
2244
  Max =
 
2245
    case inf_geq(Max1, 0) or inf_geq(Max2, 0) of
 
2246
      true ->
 
2247
        inf_bsl(1, Width);
 
2248
      false ->
 
2249
        -1
 
2250
    end,
 
2251
  true = is_min(Min),
 
2252
  true = is_max(Max),
 
2253
  range_init(Name, {Min, Max}, false).
 
2254
 
 
2255
range_bxor(Name, R1, R2) ->
 
2256
  {Min1, Max1} = var_range__range(R1),
 
2257
  {Min2, Max2} = var_range__range(R2),
 
2258
  Width = width({width({Min1, Max1}), width({Min2, Max2})}),
 
2259
  Min =
 
2260
    case inf_geq(Max1, 0) and inf_geq(Max2, 0) of
 
2261
      true ->
 
2262
        0;
 
2263
      false ->
 
2264
        inf_bsl(-1, Width)
 
2265
    end,          
 
2266
  Max =
 
2267
    case inf_geq(Max1, 0) or inf_geq(Max2, 0) of
 
2268
      true ->
 
2269
        inf_bsl(1, Width);
 
2270
      false ->
 
2271
        -1
 
2272
    end,
 
2273
  true = is_min(Min),
 
2274
  true = is_max(Max),
 
2275
  range_init(Name, {Min, Max}, false).
 
2276
 
 
2277
%% Propagation
 
2278
 
 
2279
range_remove_constant(Range1, #var_range{range=empty}) ->
 
2280
  Range1;
 
2281
range_remove_constant(Range1, #var_range{range={Const, Const}}) when is_integer(Const) ->
 
2282
  Old_min = var_range__min(Range1),
 
2283
  Old_max = var_range__max(Range1),
 
2284
  if Old_min =:= Const ->
 
2285
      New_min = Old_min + 1;
 
2286
     true ->
 
2287
      New_min = Old_min
 
2288
  end,
 
2289
  if Old_max =:= Const ->
 
2290
      New_max = Old_max - 1;
 
2291
     true ->
 
2292
      New_max = Old_max
 
2293
  end,
 
2294
  Range_range = 
 
2295
    if (New_min =:= empty) or (New_max =:= empty) ->
 
2296
        empty;
 
2297
       true ->
 
2298
        {New_min, New_max}
 
2299
    end,
 
2300
  %%TODO
 
2301
  range_init(var_range__name(Range1), Range_range, var_range__other(Range1)).
 
2302
 
 
2303
 
 
2304
%% range_diff(Name, Range1, #var_range{range = empty}) ->
 
2305
%%      var_range__copy(Range1, Name);  
 
2306
%% range_diff(Name, Range1, Range2) ->
 
2307
%%      Min1 = var_range__min(Range1),
 
2308
%%      Max1 = var_range__max(Range1),
 
2309
%%      Min2 = var_range__min(Range2),
 
2310
%%      Max2 = var_range__max(Range2),  
 
2311
%%      %io:format("Min1 ~p, Max1 ~p, Min2 ~p, Max2 ~p ~n", [Min1, Max1, Min2, Max2]),
 
2312
%%      if (Min1 =:= empty) ->
 
2313
%%              Int_range = empty;
 
2314
%%      true ->
 
2315
%%              case inf_geq(Min1, Min2) of
 
2316
%%                      true ->
 
2317
%%                              Min = inf_max([Min1, inf_add(Max2,1)]);
 
2318
%%                      false ->
 
2319
%%                              Min = Min1
 
2320
%%              end,
 
2321
%%              case inf_geq(Max2, Max1) of
 
2322
%%                      true ->
 
2323
%%                              Max = inf_min([Max1, inf_add(Min2,-1)]);
 
2324
%%                      false ->
 
2325
%%                              Max = Max1
 
2326
%%              end,
 
2327
%%              Int_range = {Min, Max}
 
2328
%%      end,
 
2329
%%      Other = var_range__other(Range1),
 
2330
%%      
 
2331
%%      Min_fixed = var_range__min_fixed(Range1) and var_range__min_fixed(Range2),
 
2332
%%      Max_fixed = var_range__max_fixed(Range1) and var_range__max_fixed(Range2),
 
2333
%%      R = range_init(Name, Int_range, {Min_fixed, Max_fixed}, Other),
 
2334
%%      io:format("range diff ~p ~p ~n", [R, Int_range]),
 
2335
%%      R.
 
2336
 
 
2337
%% todo ska det f��rsta fallet finnas?
 
2338
%% range_cut(Name, []) -> #var_range{var_name=Name};
 
2339
range_cut(Name, [#var_range{range=empty, other=false}|_]) ->
 
2340
  range_init(Name, empty, false);
 
2341
range_cut(Name, [Range|Rangelist]) ->
 
2342
  range_cut(Name, Rangelist, Range).
 
2343
 
 
2344
range_cut(Name, [], Dst_range) -> 
 
2345
  var_range__copy(Dst_range, Name);
 
2346
range_cut(Name, [#var_range{range = empty, other = Other1}|_],
 
2347
          #var_range{other = Other2}) ->
 
2348
  range_init(Name, empty, Other1 and Other2);
 
2349
range_cut(Name, [Range|Rangelist], Dst_range) ->
 
2350
  Min1 = var_range__min(Range),
 
2351
  Max1 = var_range__max(Range),
 
2352
  Min2 = var_range__min(Dst_range),
 
2353
  Max2 = var_range__max(Dst_range),
 
2354
  if (Min1 =:= empty) orelse (Min2 =:= empty) ->
 
2355
      Int_range = empty;
 
2356
     true ->
 
2357
      Min = inf_max([Min1, Min2]),
 
2358
      Max = inf_min([Max1, Max2]),
 
2359
      Int_range = {Min, Max}
 
2360
  end,  
 
2361
  Other = var_range__other(Range) andalso var_range__other(Dst_range),
 
2362
  range_cut(Name, Rangelist, range_init(Name, Int_range, Other)).
 
2363
 
 
2364
range_union(Name, []) ->
 
2365
  range_init(Name, empty, false); %#var_range{var_name=Name};
 
2366
range_union(Name, [Range|Range_list]) ->
 
2367
  %% io:format("range: ~p ~n rangelist: ~p ~n", [Range, Range_list]),
 
2368
  range_union(Name, Range_list, Range).
 
2369
 
 
2370
range_union(Name, [], Dst_range) -> 
 
2371
  %% io:format("dstRange: ~p ~n", [DstRange]),
 
2372
  var_range__copy(Dst_range, Name);
 
2373
range_union(Name, [Range|Rangelist], Dst_range) ->
 
2374
  %% io:format("Range: ~p, DstRange ~p ->", [Range, DstRange]),
 
2375
  Min1 = var_range__min(Range),
 
2376
  Max1 = var_range__max(Range),
 
2377
  Min2 = var_range__min(Dst_range),
 
2378
  Max2 = var_range__max(Dst_range),
 
2379
  Min = inf_min([Min1, Min2]),
 
2380
  Max = inf_max([Max1, Max2]),
 
2381
  Int_range = 
 
2382
    if (Min =:= empty) or (Max =:= empty) ->
 
2383
        empty;
 
2384
       true ->
 
2385
        {Min, Max}
 
2386
    end,
 
2387
  Other = var_range__other(Range) orelse var_range__other(Dst_range),
 
2388
  %% io:format("{~p, ~p} ~n", [Min, Max]),
 
2389
  range_union(Name, Rangelist, 
 
2390
              range_init(Name, Int_range, Other)).
 
2391
 
 
2392
range_equality_propagation(Range_1, Range_2) ->  
 
2393
  True_range_1 = range_cut(var_range__name(Range_1), [Range_1, Range_2]),
 
2394
  True_range_2 = range_cut(var_range__name(Range_2), [Range_1, Range_2]),
 
2395
  False_range_2 =
 
2396
    case var_range__range(Range_1) of
 
2397
      {Min1, Max1} ->
 
2398
        if Min1 =:= Max1 ->
 
2399
            range_remove_constant(Range_2, Range_1);
 
2400
           true ->
 
2401
            Range_2
 
2402
        end;
 
2403
      empty ->
 
2404
        Range_2
 
2405
    end,
 
2406
  False_range_1 = 
 
2407
    case var_range__range(Range_2) of
 
2408
      {Min2, Max2} ->
 
2409
        if Min2 =:= Max2 ->
 
2410
            range_remove_constant(Range_1, Range_2);
 
2411
           true ->
 
2412
            Range_1
 
2413
        end;
 
2414
      empty ->
 
2415
        Range_1
 
2416
    end,
 
2417
  {True_range_1, True_range_2, False_range_1, False_range_2}.
 
2418
 
 
2419
%% Range1 < Range2
 
2420
range_inequality_propagation(Range1, Range2) ->
 
2421
  %% io:format("Range1 ~p, Range2 ~p ~n", [Range1, Range2]),
 
2422
  R1_name = var_range__name(Range1),
 
2423
  R2_name = var_range__name(Range2),
 
2424
  R1_min = var_range__min(Range1),
 
2425
  R2_min = var_range__min(Range2),
 
2426
  R1_max = var_range__max(Range1),
 
2427
  R2_max = var_range__max(Range2),
 
2428
  R1_other = var_range__other(Range1),
 
2429
  R2_other = var_range__other(Range2),
 
2430
  
 
2431
  R1_is_empty = var_range__is_empty(Range1),
 
2432
  R2_is_empty = var_range__is_empty(Range2),
 
2433
  
 
2434
  {R1_true_range, R1_false_range} = 
 
2435
    if R1_is_empty ->
 
2436
        {empty, empty};
 
2437
       R2_is_empty ->
 
2438
        Range1_range = var_range__range(Range1),
 
2439
        {Range1_range, Range1_range};
 
2440
       true ->
 
2441
        R1_true_max = inf_min([R1_max, inf_add(R2_max, -1)]),
 
2442
        R1_false_min = inf_max([R1_min, R2_min]),
 
2443
        {{R1_min, R1_true_max}, {R1_false_min, R1_max}}
 
2444
    end,        
 
2445
  
 
2446
  {R2_true_range, R2_false_range} = 
 
2447
    if R2_is_empty ->
 
2448
        {empty, empty};
 
2449
       R1_is_empty ->
 
2450
        Range2_range = var_range__range(Range2),
 
2451
        {Range2_range, Range2_range};
 
2452
       true ->
 
2453
        R2_true_min = inf_max([inf_add(R1_min,1),R2_min]),
 
2454
        R2_false_max = inf_min([R1_max, R2_max]),
 
2455
        {{R2_true_min, R2_max}, {R2_min, R2_false_max}}
 
2456
    end,        
 
2457
  
 
2458
  R1_true = range_init(R1_name, R1_true_range, R1_other),
 
2459
  R2_true = range_init(R2_name, R2_true_range, R2_other),
 
2460
  R1_false = range_init(R1_name, R1_false_range, R1_other),
 
2461
  R2_false = range_init(R2_name, R2_false_range, R2_other),
 
2462
  %% io:format("R1T ~p, R1F ~p ~n, R2T ~p, R2F ~p  ~n", [R1_true_range, R1_false_range, R2_true_range, R2_false_range]),
 
2463
        
 
2464
  {R1_true, R2_true, R1_false, R2_false}.
 
2465
 
 
2466
%% Range widening
 
2467
 
 
2468
 
 
2469
get_larger_value(Value, List) ->
 
2470
  get_larger_value_1(Value, lists:reverse(List)).
 
2471
 
 
2472
get_larger_value_1(Value, []) -> Value;
 
2473
get_larger_value_1(Value, [Head|Tail]) ->
 
2474
  case inf_geq(Head, Value) of
 
2475
    true ->
 
2476
      Head;
 
2477
    false ->
 
2478
      get_larger_value_1(Value, Tail)
 
2479
  end.
 
2480
 
 
2481
get_smaller_value(Value, List) ->
 
2482
  get_smaller_value_1(Value, List).
 
2483
 
 
2484
get_smaller_value_1(Value, []) -> Value;
 
2485
get_smaller_value_1(Value, [Head|Tail]) ->
 
2486
  case inf_geq(Head, Value) and (Head =/= Value) of
 
2487
    true ->
 
2488
      get_smaller_value_1(Value, Tail);
 
2489
    false ->
 
2490
      Head
 
2491
  end.
 
2492
 
 
2493
range_widening(Old_range, New_range, Wideningvalues) ->
 
2494
New_min_fixed = inf_geq(var_range__min(New_range), var_range__min(Old_range)),
 
2495
New_max_fixed = inf_geq(var_range__max(Old_range), var_range__max(New_range)), 
 
2496
  
 
2497
  Old_empty = var_range__is_empty(Old_range),
 
2498
 
 
2499
  New_min = 
 
2500
    if New_min_fixed or Old_empty ->
 
2501
        var_range__min(New_range);
 
2502
       true ->
 
2503
        Min = var_range__min(New_range),
 
2504
        get_smaller_value(Min, Wideningvalues)
 
2505
    end,
 
2506
  New_max = 
 
2507
    if New_max_fixed or Old_empty ->
 
2508
        var_range__max(New_range);
 
2509
       true ->
 
2510
        Max = var_range__max(New_range),
 
2511
        get_larger_value(Max, Wideningvalues)
 
2512
    end,
 
2513
  Range_range = 
 
2514
    if (New_min =:= empty) or (New_max =:= empty) ->
 
2515
        empty;
 
2516
       true ->
 
2517
        {New_min, New_max}
 
2518
    end,
 
2519
  New_other = var_range__other(New_range),
 
2520
  R = range_init(var_range__name(New_range), Range_range, New_other),
 
2521
%  io:format("Range widening ~p~n", [R]),
 
2522
  R.
 
2523
 
 
2524
%%---------------------------------------------------------------------------
 
2525
%% Inf operations
 
2526
%%---------------------------------------------------------------------------
 
2527
 
 
2528
inf_max([]) -> empty;
 
2529
inf_max([H|T])->
 
2530
  if H =:= empty ->
 
2531
      inf_max(T);
 
2532
     true ->
 
2533
      lists:foldl(
 
2534
        fun(Elem, Max) ->
 
2535
            Geq = inf_geq(Elem, Max),
 
2536
            if not Geq or (Elem =:= empty) ->
 
2537
                Max;
 
2538
               true ->
 
2539
                Elem
 
2540
            end
 
2541
        end,
 
2542
        H,
 
2543
        T)
 
2544
  end. 
 
2545
 
 
2546
inf_min([]) -> empty;
 
2547
inf_min([H|T])->
 
2548
  if H =:= empty ->
 
2549
      inf_min(T);
 
2550
     true ->
 
2551
      lists:foldl(fun(Elem, Min) ->
 
2552
                      Geq = inf_geq(Elem, Min),
 
2553
                      if Geq or (Elem =:= empty) ->
 
2554
                          Min;
 
2555
                         true ->
 
2556
                          Elem
 
2557
                      end
 
2558
                  end,
 
2559
                  H,
 
2560
                  T)
 
2561
  end. 
 
2562
 
 
2563
inf_abs(posinf) -> posinf;
 
2564
inf_abs(neginf) -> posinf;
 
2565
inf_abs(Number) when is_integer(Number), (Number < 0) -> - Number;
 
2566
inf_abs(Number) when is_integer(Number) -> Number.
 
2567
 
 
2568
inf_add(posinf, _Number) -> posinf;
 
2569
inf_add(neginf, _Number) -> neginf;
 
2570
inf_add(_Number, posinf) -> posinf;
 
2571
inf_add(_Number, neginf) -> neginf;
 
2572
inf_add(Number1, Number2) when is_integer(Number1), is_integer(Number2) ->
 
2573
  Number1 + Number2.
 
2574
 
 
2575
inf_inv(posinf) -> neginf;
 
2576
inf_inv(neginf) -> posinf;
 
2577
inf_inv(Number) -> -Number.
 
2578
 
 
2579
inf_geq(posinf, _) -> true;
 
2580
inf_geq(_, posinf) -> false;
 
2581
inf_geq(_, neginf) -> true;
 
2582
inf_geq(neginf, _) -> false;
 
2583
inf_geq(A, B) -> A >= B.
 
2584
 
 
2585
inf_greater_zero(posinf) -> true;
 
2586
inf_greater_zero(neginf) -> false;
 
2587
inf_greater_zero(Number) when Number >= 0 -> true;
 
2588
inf_greater_zero(Number) when Number < 0 -> false.
 
2589
 
 
2590
inf_div(Number, 0) ->
 
2591
  Greater = inf_greater_zero(Number),
 
2592
  if Greater ->
 
2593
      posinf;
 
2594
        true ->
 
2595
      neginf
 
2596
  end;
 
2597
inf_div(posinf, Number) ->
 
2598
  Greater = inf_greater_zero(Number),
 
2599
  if Greater ->
 
2600
      posinf;
 
2601
     true ->
 
2602
      neginf
 
2603
  end;
 
2604
inf_div(neginf, Number) ->
 
2605
  Greater = inf_greater_zero(Number),
 
2606
  if Greater ->
 
2607
      neginf;
 
2608
     true ->
 
2609
      posinf
 
2610
  end;
 
2611
inf_div(Number, posinf) -> 
 
2612
  Greater = inf_greater_zero(Number),
 
2613
  if Greater ->
 
2614
      posinf;
 
2615
     true ->
 
2616
      neginf
 
2617
  end;
 
2618
inf_div(Number, neginf) ->
 
2619
  Greater = inf_greater_zero(Number),
 
2620
  if Greater ->
 
2621
      neginf;
 
2622
     true ->
 
2623
      posinf
 
2624
  end;
 
2625
inf_div(Number1, Number2) -> Number1 div Number2.
 
2626
 
 
2627
inf_mult(neginf, Number) -> 
 
2628
  Greater = inf_greater_zero(Number), 
 
2629
  if Greater -> neginf;
 
2630
     true -> posinf
 
2631
  end;
 
2632
inf_mult(posinf, Number) -> 
 
2633
  Greater = inf_greater_zero(Number),
 
2634
  if Greater -> posinf;
 
2635
     true -> neginf
 
2636
  end;
 
2637
inf_mult(Number, posinf) -> inf_mult(posinf, Number);
 
2638
inf_mult(Number, neginf) -> inf_mult(neginf, Number);
 
2639
inf_mult(Number1, Number2) -> Number1 * Number2.
 
2640
 
 
2641
inf_bsl(posinf, _) -> posinf;
 
2642
inf_bsl(neginf, _) -> neginf;
 
2643
inf_bsl(Number, posinf) when Number >= 0 -> posinf;
 
2644
inf_bsl(_, posinf) -> neginf;
 
2645
inf_bsl(Number, neginf) when Number >= 0 -> 0;
 
2646
inf_bsl(_Number, neginf) -> -1;
 
2647
inf_bsl(Number1, Number2) -> 
 
2648
  Bits = ?BITS,
 
2649
  if Number2 > (Bits bsl 1) ->  % (Bits * 2)
 
2650
      inf_bsl(Number1, posinf);
 
2651
     Number2 < (-Bits bsl 1) -> % (-Bits * 2)
 
2652
      inf_bsl(Number1, neginf);
 
2653
     true ->
 
2654
      Number1 bsl Number2
 
2655
  end.
 
2656
 
 
2657
%%---------------------------------------------------------------------------
 
2658
%% Range info
 
2659
%%---------------------------------------------------------------------------
 
2660
 
 
2661
range_info_from_info_struct(Info) ->
 
2662
  Live_labels = info_struct__live_labels(Info),
 
2663
  %% io:format("in_label_range_trees = ~p ~n", [in_range_trees_from_info_struct(Info, Live_labels)]),
 
2664
  %% io:format("out_label_range_trees = ~p ~n", [out_range_trees_from_info_struct(Info, Live_labels)]),
 
2665
  #range_info{live_labels = Live_labels,
 
2666
              in_label_range_trees = in_range_trees_from_info_struct(Info, Live_labels), 
 
2667
              out_label_range_trees = out_range_trees_from_info_struct(Info, Live_labels),              
 
2668
              return_points = info_struct__return_vars(Info),
 
2669
              warn = info_struct__warn(Info)
 
2670
             }.
 
2671
 
 
2672
range_info__def_range(#range_info{out_label_range_trees = Label_tree}, Label, Variable) ->
 
2673
  %% io:format("Def: Label ~p, Var ~p ~n", [Label, Variable]),
 
2674
  Range_tree = gb_trees:get(Label, Label_tree),
 
2675
  case gb_trees:lookup(Variable, Range_tree) of
 
2676
    {value, Range} ->
 
2677
      %% io:format("use_range ~p ~n", [Range]),
 
2678
      Range;
 
2679
    none ->
 
2680
      range_init(Variable, empty, false)
 
2681
  end.
 
2682
 
 
2683
range_info__use_range(Range_info = #range_info{in_label_range_trees = Label_tree}, Label, Variable) ->
 
2684
  %% io:format("Use: Label ~p, Var ~p ~n", [Label, Variable]),
 
2685
  Range_tree = gb_trees:get(Label, Label_tree),
 
2686
  case gb_trees:lookup(Variable, Range_tree) of
 
2687
    {value, Range} ->
 
2688
      %% io:format("use_range ~p ~n", [Range]),
 
2689
      Range;
 
2690
    none ->
 
2691
      range_info__def_range(Range_info, Label, Variable)
 
2692
  end. 
 
2693
 
 
2694
range_info__is_live(#range_info{live_labels = Labels}, Label) ->
 
2695
  gb_sets:is_member(Label, Labels).
 
2696
 
 
2697
range_info__warn(#range_info{warn = Warn}) ->
 
2698
  Warn.
 
2699
 
 
2700
%%---------------------------------------------------------------------------
 
2701
%% Print out messages
 
2702
%%---------------------------------------------------------------------------
 
2703
 
 
2704
warning(Op, Spec, true) ->
 
2705
  Text = "Icode range analysis not good (~w, ~w)\n", 
 
2706
  Args = [Op,Spec],
 
2707
  ?msg(Text,Args);
 
2708
warning(_, _, false) ->
 
2709
  ok.
 
2710
 
 
2711
info(New, Old, true) ->
 
2712
  Text = "Icode range analysis found info (~w, ~w)\n", 
 
2713
  Args = [New, Old],
 
2714
  ?msg(Text,Args);
 
2715
info(_, _, false) ->
 
2716
  ok. 
 
2717
 
 
2718
%%---------------------------------------------------------------------------
 
2719
%% Print out messages
 
2720
%%---------------------------------------------------------------------------
 
2721
 
 
2722
test() ->
 
2723
  ok.
 
2724
 
 
2725
% vim: set tabstop=2 ft=erlang