5
5
%%% Mapping to fp variables and creation of fp ebbs.
7
7
%%% Created : 23 Apr 2003 by Tobias Lindahl <tobiasl@it.uu.se>
11
%%% $Date: 2006/07/24 22:12:25 $
8
13
%%%-------------------------------------------------------------------
9
15
-module(hipe_icode_fp).
14
-export([print_state_info/1]).
19
-include("hipe_icode.hrl").
21
-record(state, {info, block_map, edge_map, cfg}).
28
24
%%hipe_icode_cfg:pp(Cfg),
30
%%print_state_info(State),
25
NewCfg = annotate_fclearerror(Cfg),
26
State = new_state(NewCfg),
31
27
NewState = place_fp_blocks(State),
32
NewCfg = state__cfg(NewState),
33
%%hipe_icode_cfg:pp(NewCfg),
28
%%hipe_icode_cfg:pp(state__cfg(NewState)),
29
NewState2 = finalize(NewState),
30
NewCfg1 = state__cfg(NewState2),
31
%%hipe_icode_cfg:pp(NewCfg1),
32
NewCfg2 = unannotate_fclearerror(NewCfg1),
37
State = new_state(Cfg, InfoMap),
38
NewState = place_fp_blocks(State),
39
NewCfg = state__cfg(NewState),
40
%%hipe_icode_cfg:pp(NewCfg),
43
36
%%____________________________________________________________
45
%% Single pass analysis that only focus on floats.
38
%% Annotate fclearerror with information of the fail label of the
39
%% corresponding fcheckerror.
49
State = new_state(Cfg),
50
Labels = hipe_icode_cfg:reverse_postorder(Cfg),
51
analyse_blocks(Labels, State).
53
analyse_blocks(Labels, State)->
54
analyse_blocks(Labels, Labels, State).
56
analyse_blocks(Labels, [Label|Left], State)->
57
Info = state__info_in(State, Label),
58
NewState = analyse_block(Label, Info, State),
59
analyse_blocks(Labels, Left, NewState);
60
analyse_blocks(_Labels, [], State) ->
63
analyse_block(Label, InfoIn, State)->
64
%%io:format("Handling ~w\n", [Label]),
65
BB = state__bb(State, Label),
66
Code = hipe_bb:code(BB),
67
Last = hipe_bb:last(BB),
68
NewInfoIn = analyse_insns(Code, InfoIn),
69
NewState = state__info_out_update(State, Label, NewInfoIn),
71
case hipe_icode:type(Last) of
73
UpdateInfo = do_type(Last, NewInfoIn),
74
%%io:format("Update info for ~w:\n~w", [Label, UpdateInfo]),
75
do_updates(NewState, UpdateInfo);
77
UpdateInfo = [{X, NewInfoIn}||X<-state__succ(NewState, Label)],
78
%%io:format("Update info for ~w:\n~w", [Label, UpdateInfo]),
79
do_updates(NewState, UpdateInfo)
82
analyse_insns([I|Insns], Info)->
84
case hipe_icode:type(I) of
90
Type = join_list(uses(I), Info),
91
enter_defines(I, Type, Info);
93
enter_defines(I, t_any(), Info)
95
analyse_insns(Insns, NewInfo);
96
analyse_insns([], Info) ->
100
%% Can't use uses/1 since we must keep constants.
101
Src = hipe_icode:mov_src(I),
102
case const_type(Src) of
104
%% Make the destination point to the source.
105
enter_defines(I, Src, Info);
107
enter_defines(I, ConstType, Info)
111
case hipe_icode:call_type(I) of
113
case hipe_icode:call_fun(I) of
115
ArgTypes = lookup_type_list(uses(I), Info),
116
Type = erl_bif_types:type(M, F, A, ArgTypes),
117
enter_defines(I, Type, Info);
122
case lists:keysearch(dst_type, 1, hipe_icode:info(I)) of
124
enter_defines(I, t_any(), Info);
125
{value,{_, [Type]}}->
126
enter_defines(I, Type, Info)
129
Fun = hipe_icode:call_fun(I),
130
ArgType = lookup_type_list(uses(I), Info),
131
DstType = hipe_rtl_primops:type(Fun, ArgType),
132
enter_defines(I, DstType, Info)
137
VarInfo = lookup_type(I, Info),
138
TrueLab = hipe_icode:type_true_label(I),
139
FalseLab = hipe_icode:type_false_label(I),
141
case hipe_icode:type_type(I) of
143
TrueType = t_inf(t_float(), VarInfo),
144
TrueInfo = enter(Var, TrueType, Info),
145
FalseInfo = enter(Var, t_any(), Info),
146
[{TrueLab, TrueInfo}, {FalseLab, FalseInfo}];
148
[{TrueLab, Info}, {FalseLab, Info}]
151
do_updates(State, [{Label, Info}|Tail])->
152
case state__info_in_update(State, Label, Info) of
154
do_updates(State, Tail);
156
do_updates(NewState, Tail)
158
do_updates(State, []) ->
42
annotate_fclearerror(Cfg) ->
43
Labels = hipe_icode_cfg:reverse_postorder(Cfg),
44
annotate_fclearerror(Labels, Cfg).
46
annotate_fclearerror([Label|Left], Cfg) ->
47
BB = hipe_icode_cfg:bb(Cfg, Label),
48
Code = hipe_bb:code(BB),
49
NewCode = annotate_fclearerror1(Code, Label, Cfg, []),
50
NewBB = hipe_bb:code_update(BB, NewCode),
51
NewCfg = hipe_icode_cfg:bb_add(Cfg, Label, NewBB),
52
annotate_fclearerror(Left, NewCfg);
53
annotate_fclearerror([], Cfg) ->
56
annotate_fclearerror1([I|Left], Label, Cfg, Acc) ->
59
case hipe_icode:call_fun(I) of
61
Fail = lookahead_for_fcheckerror(Left, Label, Cfg),
62
NewI = hipe_icode:call_fun_update(I, {fclearerror, Fail}),
63
annotate_fclearerror1(Left, Label, Cfg, [NewI|Acc]);
65
annotate_fclearerror1(Left, Label, Cfg, [I|Acc])
68
annotate_fclearerror1(Left, Label, Cfg, [I|Acc])
70
annotate_fclearerror1([], _Label, _Cfg, Acc) ->
73
lookahead_for_fcheckerror([I|Left], Label, Cfg) ->
76
case hipe_icode:call_fun(I) of
78
hipe_icode:call_fail_label(I);
80
lookahead_for_fcheckerror(Left, Label, Cfg)
83
lookahead_for_fcheckerror(Left, Label, Cfg)
85
lookahead_for_fcheckerror([], Label, Cfg) ->
86
case hipe_icode_cfg:succ(hipe_icode_cfg:succ_map(Cfg), Label) of
87
[] -> exit("Unterminated fp ebb");
90
Code = hipe_bb:code(hipe_icode_cfg:bb(Cfg, Label)),
91
lookahead_for_fcheckerror(Code, Succ, Cfg)
94
unannotate_fclearerror(Cfg) ->
95
Labels = hipe_icode_cfg:reverse_postorder(Cfg),
96
unannotate_fclearerror(Labels, Cfg).
98
unannotate_fclearerror([Label|Left], Cfg) ->
99
BB = hipe_icode_cfg:bb(Cfg, Label),
100
Code = hipe_bb:code(BB),
101
NewCode = unannotate_fclearerror1(Code, []),
102
NewBB = hipe_bb:code_update(BB, NewCode),
103
NewCfg = hipe_icode_cfg:bb_add(Cfg, Label, NewBB),
104
unannotate_fclearerror(Left, NewCfg);
105
unannotate_fclearerror([], Cfg) ->
108
unannotate_fclearerror1([I|Left], Acc) ->
111
case hipe_icode:call_fun(I) of
112
{fclearerror, _Fail} ->
113
NewI = hipe_icode:call_fun_update(I, fclearerror),
114
unannotate_fclearerror1(Left, [NewI|Acc]);
116
unannotate_fclearerror1(Left, [I|Acc])
119
unannotate_fclearerror1(Left, [I|Acc])
121
unannotate_fclearerror1([], Acc) ->
161
125
%%____________________________________________________________
166
130
place_fp_blocks(State)->
131
WorkList = new_worklist(State),
132
transform_block(WorkList, State).
134
transform_block(WorkList, State) ->
135
case get_work(WorkList) of
138
{Label, NewWorkList} ->
139
%%io:format("Handling ~w \n", [Label]),
140
BB = state__bb(State, Label),
141
Code = hipe_bb:code(BB),
142
NofPreds = length(state__pred(State, Label)),
143
Map = state__map(State, Label),
144
FilteredMap = filter_map(Map, NofPreds),
145
%%io:format("Label: ~w\nPhiMap: ~p\nFilteredMap ~p\n",
146
%% [Label, gb_trees:to_list(Map), gb_trees:to_list(FilteredMap)]),
147
{Prelude, NewFilteredMap} = do_prelude(FilteredMap),
149
transform_instrs(Code, Map, NewFilteredMap, []),
150
NewBB = hipe_bb:code_update(BB, Prelude++NewCode),
151
NewState = state__bb_add(State, Label, NewBB),
152
case state__map_update(NewState, Label, NewMap) of
154
transform_block(NewWorkList, NewState);
156
Succ = state__succ(NewState1, Label),
157
NewWorkList1 = add_work(NewWorkList, Succ),
158
transform_block(NewWorkList1, NewState1)
163
transform_instrs([I|Left], PhiMap, Map, Acc) ->
164
Defines = hipe_icode:defines(I),
165
NewMap = delete_all(Defines, Map),
166
NewPhiMap = delete_all(Defines, PhiMap),
170
Uses = hipe_icode:uses(I),
171
case [X || X <- Uses, lookup(X, PhiMap) =/= none] of
173
%% No ordinary variables from the argument has been untagged.
174
transform_instrs(Left, NewPhiMap, NewMap, [I|Acc]);
176
%% All arguments are untagged. Let's untag the destination.
177
Dst = hipe_icode:phi_dst(I),
178
NewDst = hipe_icode:mk_new_fvar(),
179
NewMap1 = gb_trees:enter(Dst, NewDst, NewMap),
180
NewI = subst_phi_uncond(I, NewDst, PhiMap),
181
transform_instrs(Left, NewPhiMap, NewMap1, [NewI|Acc]);
183
%% Some arguments are untagged. Keep the destination.
184
Dst = hipe_icode:phi_dst(I),
185
NewI = subst_phi(I, Dst, PhiMap),
186
transform_instrs(Left, NewPhiMap, NewMap, [NewI|Acc])
189
case hipe_icode:call_fun(I) of
190
X when X =:= unsafe_untag_float; X =:= conv_to_float ->
191
[Dst] = hipe_icode:defines(I),
192
case hipe_icode:uses(I) of
194
transform_instrs(Left, NewPhiMap, NewMap, [I|Acc]);
196
case lookup(Src, Map) of
198
NewMap1 = gb_trees:enter(Src, {assigned, Dst}, NewMap),
199
transform_instrs(Left, NewPhiMap, NewMap1, [I|Acc]);
201
%% This is the instruction that untagged the variable.
203
transform_instrs(Left, NewPhiMap, Map, [I|Acc]);
205
%% The variable was already untagged.
206
%% This instruction can be changed to a fmove.
207
NewI = hipe_icode:mk_fmove(Dst, FVar),
208
case hipe_icode:call_continuation(I) of
210
transform_instrs(Left,NewPhiMap,NewMap,[NewI|Acc]);
212
Goto = hipe_icode:mk_goto(ContLbl),
213
transform_instrs(Left, NewPhiMap, NewMap,
219
[Dst] = hipe_icode:defines(I),
220
[Src] = hipe_icode:uses(I),
221
NewMap1 = gb_trees:enter(Dst, {assigned, Src}, NewMap),
222
transform_instrs(Left, NewPhiMap, NewMap1,[I|Acc]);
224
{NewMap1, NewAcc} = check_for_fop_candidates(I, NewMap, Acc),
225
transform_instrs(Left, NewPhiMap, NewMap1, NewAcc)
228
NewIns = handle_untagged_arguments(I, NewMap),
229
transform_instrs(Left, NewPhiMap, NewMap, NewIns ++ Acc)
231
transform_instrs([], _PhiMap, Map, Acc) ->
232
{Map, lists:reverse(Acc)}.
234
check_for_fop_candidates(I, Map, Acc)->
235
case is_fop_cand(I) of
237
NewIs = handle_untagged_arguments(I, Map),
240
Fail = hipe_icode:call_fail_label(I),
241
Cont = hipe_icode:call_continuation(I),
242
Op = fun_to_fop(hipe_icode:call_fun(I)),
245
Args = hipe_icode:args(I),
246
ConstArgs = [X || X <- Args, hipe_icode:is_const(X)],
247
case catch [float(hipe_icode:const_value(X)) || X <- ConstArgs] of
249
%% This instruction will fail at runtime. The warning
250
%% should already have happened in hipe_icode_type.
251
NewIs = handle_untagged_arguments(I, Map),
254
%%io:format("Changing ~w to ~w\n", [hipe_icode:call_fun(I), Op]),
255
Uses = hipe_icode:uses(I),
256
Defines = hipe_icode:defines(I),
257
Convs = [X||X <- remove_duplicates(Uses), lookup(X, Map) =:= none],
258
NewMap0 = add_new_bindings_assigned(Convs, Map),
259
NewMap = add_new_bindings_unassigned(Defines, NewMap0),
260
ConvIns = get_conv_instrs(Convs, NewMap),
261
NewI = hipe_icode:mk_primop(lookup_list(Defines, NewMap), Op,
262
lookup_list_keep_consts(Args,NewMap),
264
NewI2 = conv_consts(ConstArgs, NewI),
265
{NewMap, [NewI2|ConvIns]++Acc}
267
_ -> %% Bailing out! Can't handle instructions in catches (yet).
268
NewIs = handle_untagged_arguments(I, Map),
274
%% If this is an instruction that needs to operate on tagged values,
275
%% which currently are untagged, we must tag the values and perhaps
278
handle_untagged_arguments(I, Map)->
279
case lists:filter(fun(X)-> must_be_tagged(X, Map) end, hipe_icode:uses(I)) of
284
[hipe_icode:mk_primop([Dst], unsafe_tag_float,
285
[gb_trees:get(Dst, Map)]) || Dst<-Tag],
289
%% Add phi nodes for untagged fp values.
292
case gb_trees:lookup(phi, Map) of
296
%%io:format("Adding phi: ~w\n", [List]),
297
Fun = fun({FVar, Bindings}, Acc) ->
298
[hipe_icode:mk_phi(FVar, Bindings)|Acc]
300
{lists:foldl(Fun, [], List), gb_trees:delete(phi, Map)}
304
split_code(Code, []).
306
split_code([I], Acc) ->
307
{lists:reverse(Acc), I};
308
split_code([I|Left], Acc)->
309
split_code(Left, [I|Acc]).
312
%% When all code is mapped to fp instructions we must make sure that
313
%% the fp ebb information goin in to each block is the same as the
314
%% information coming out of each predecessor. Otherwise, we must add
315
%% a block in between.
318
Worklist = new_worklist(State),
319
NewState = place_error_handling(Worklist, State),
320
Edges = needs_fcheckerror(NewState),
321
finalize(Edges, NewState).
323
finalize([{From, To}|Left], State) ->
324
NewState = add_fp_ebb_fixup(From, To, State),
325
finalize(Left, NewState);
326
finalize([], State) ->
329
needs_fcheckerror(State) ->
167
330
Cfg = state__cfg(State),
168
Labels = hipe_icode_cfg:reverse_postorder(Cfg),
169
transform_block(Labels, gb_sets:empty(), State).
171
transform_block([Label|Left], BackEdgeSucc, State)->
172
BB = state__bb(State, Label),
331
Labels = hipe_icode_cfg:labels(Cfg),
332
needs_fcheckerror(Labels, State, []).
334
needs_fcheckerror([Label|Left], State, Acc) ->
335
case state__get_in_block_in(State, Label) of
337
needs_fcheckerror(Left, State, Acc);
339
Pred = state__pred(State, Label),
340
case [X || X <- Pred, state__get_in_block_out(State, X) =/= false] of
342
needs_fcheckerror(Left, State, Acc);
344
case length(Pred) =:= length(NeedsFcheck) of
346
%% All edges needs fcheckerror. Add this to the
347
%% beginning of the block instead.
348
needs_fcheckerror(Left, State, [{none, Label}|Acc]);
350
Edges = [{X, Label} || X <- NeedsFcheck],
351
needs_fcheckerror(Left, State, Edges ++ Acc)
355
needs_fcheckerror([], _State, Acc) ->
358
add_fp_ebb_fixup('none', To, State) ->
359
%% Add the fcheckerror to the start of the block.
360
BB = state__bb(State, To),
173
361
Code = hipe_bb:code(BB),
174
Info = state__info_out(State, Label),
175
{Prelude, Map} = do_prelude(State, Label),
176
InBlock = state__in_block(State, Label),
177
{NewMap, NewCode, NewInBlock} =
178
transform_instrs(Code, Map, Info, InBlock, []),
179
NewBB = hipe_bb:code_update(BB, Prelude++NewCode),
180
NewState0 = state__bb_update(State, Label, NewBB),
181
NewState1 = state__map_update(NewState0, Label, NewMap, NewInBlock),
182
case state__succ(NewState1, Label) of
362
Phis = lists:takewhile(fun(X) -> hipe_icode:is_phi(X) end, Code),
363
TailCode = lists:dropwhile(fun(X) -> hipe_icode:is_phi(X) end, Code),
364
FC = hipe_icode:mk_primop([], fcheckerror, []),
365
NewCode = Phis ++ [FC|TailCode],
366
state__bb_add(State, To, hipe_bb:code_update(BB, NewCode));
367
add_fp_ebb_fixup(From, To, State) ->
368
FCCode = [hipe_icode:mk_primop([], fcheckerror, [], To, [])],
369
FCBB = hipe_bb:mk_bb(FCCode),
370
FCLabel = hipe_icode:label_name(hipe_icode:mk_new_label()),
371
NewState = state__bb_add(State, FCLabel, FCBB),
372
NewState1 = state__redirect(NewState, From, To, FCLabel),
373
ToBB = state__bb(NewState, To),
374
ToCode = hipe_bb:code(ToBB),
375
NewToCode = redirect_phis(ToCode, From, FCLabel),
376
NewToBB = hipe_bb:code_update(ToBB, NewToCode),
377
state__bb_add(NewState1, To, NewToBB).
379
redirect_phis(Code, OldFrom, NewFrom)->
380
redirect_phis(Code, OldFrom, NewFrom, []).
382
redirect_phis([I|Left], OldFrom, NewFrom, Acc)->
385
NewI = hipe_icode:phi_redirect_pred(I, OldFrom, NewFrom),
386
redirect_phis(Left, OldFrom, NewFrom, [NewI|Acc]);
388
lists:reverse(Acc)++[I|Left]
390
redirect_phis([], _OldFrom, _NewFrom, Acc) ->
393
subst_phi(I, Dst, Map) ->
394
ArgList = subst_phi_uses0(hipe_icode:phi_arglist(I), Map, []),
395
hipe_icode:mk_phi(Dst, ArgList).
397
subst_phi_uses0([{Pred, Var}|Left], Map, Acc) ->
398
case gb_trees:lookup(Var, Map) of
400
case lists:keysearch(Pred, 1, List) of
401
{value, {Pred, {assigned, _NewVar}}} ->
402
%% The variable is untagged, but it has been assigned. Keep it!
403
subst_phi_uses0(Left, Map, [{Pred, Var}|Acc]);
404
{value, {Pred, NewVar}}->
405
%% The variable is untagged and it has never been assigned as tagged.
406
subst_phi_uses0(Left, Map, [{Pred, NewVar}|Acc]);
408
%% The variable is not untagged.
409
subst_phi_uses0(Left, Map, [{Pred, Var}|Acc])
412
%% The variable is not untagged.
413
subst_phi_uses0(Left, Map, [{Pred, Var}|Acc])
415
subst_phi_uses0([], _Map, Acc) ->
418
subst_phi_uncond(I, Dst, Map) ->
419
ArgList = subst_phi_uses_uncond0(hipe_icode:phi_arglist(I), Map, []),
420
hipe_icode:mk_phi(Dst, ArgList).
422
subst_phi_uses_uncond0([{Pred, Var}|Left], Map, Acc) ->
423
case gb_trees:lookup(Var, Map) of
425
case lists:keysearch(Pred, 1, List) of
426
{value, {Pred, {assigned, NewVar}}} ->
427
%% The variable is untagged!
428
subst_phi_uses_uncond0(Left, Map, [{Pred, NewVar}|Acc]);
429
{value, {Pred, NewVar}}->
430
%% The variable is untagged!
431
subst_phi_uses_uncond0(Left, Map, [{Pred, NewVar}|Acc]);
433
%% The variable is not untagged.
434
subst_phi_uses_uncond0(Left, Map, [{Pred, Var}|Acc])
437
%% The variable is not untagged.
438
subst_phi_uses_uncond0(Left, Map, [{Pred, Var}|Acc])
440
subst_phi_uses_uncond0([], _Map, Acc) ->
444
place_error_handling(WorkList, State) ->
445
case get_work(WorkList) of
448
{Label, NewWorkList} ->
449
BB = state__bb(State, Label),
450
Code = hipe_bb:code(BB),
451
case state__join_in_block(State, Label) of
453
place_error_handling(NewWorkList, State);
454
{NewState, NewInBlock} ->
455
{NewCode1, InBlockOut} = place_error(Code, NewInBlock, []),
456
Succ = state__succ(NewState, Label),
457
NewCode2 = handle_unchecked_end(Succ, NewCode1, InBlockOut),
458
NewBB = hipe_bb:code_update(BB, NewCode2),
459
NewState1 = state__bb_add(NewState, Label, NewBB),
460
NewState2 = state__in_block_out_update(NewState1, Label, InBlockOut),
461
NewWorkList1 = add_work(NewWorkList, Succ),
462
place_error_handling(NewWorkList1, NewState2)
466
place_error([I|Left], InBlock, Acc) ->
469
case hipe_icode:call_fun(I) of
470
X when X =:= fp_add; X =:= fp_sub;
471
X =:= fp_mul; X =:= fp_div; X =:= fnegate ->
474
Clear = hipe_icode:mk_primop([], {fclearerror, []}, []),
475
place_error(Left, {true, []}, [I, Clear|Acc]);
477
place_error(Left, InBlock, [I|Acc])
482
Check = hipe_icode:mk_primop([], fcheckerror, [], [], Fail),
483
place_error(Left, false, [I, Check|Acc]);
485
place_error(Left, InBlock, [I|Acc])
487
{fclearerror, Fail} ->
490
%% We can remove this fclearerror!
491
case hipe_icode:call_continuation(I) of
493
place_error(Left, InBlock, Acc);
495
place_error(Left, InBlock, [hipe_icode:mk_goto(Cont)|Acc])
497
{true, _OtherFail} ->
498
%% TODO: This can be handled but it requires breaking up
499
%% the BB in two. Currently this should not happen.
500
exit("Starting fp ebb with different fail label");
502
place_error(Left, {true, Fail}, [I|Acc])
505
case {true, hipe_icode:call_fail_label(I)} of
508
place_error(Left, false, [I|Acc]);
510
exit({"Fcheckerror has the wrong fail label",
511
InBlock, NewInblock})
513
X when X =:= conv_to_float; X =:= unsafe_untag_float ->
514
place_error(Left, InBlock, [I|Acc]);
516
case hipe_icode_primops:fails(hipe_icode:call_fun(I)) of
518
place_error(Left, InBlock, [I|Acc]);
522
Check = hipe_icode:mk_primop([], fcheckerror, [], [], Fail),
523
place_error(Left, false, [I, Check|Acc]);
525
place_error(Left, InBlock, [I|Acc])
530
place_error_1(I, Left, InBlock, Acc);
532
place_error_1(I, Left, InBlock, Acc);
534
place_error_1(I, Left, InBlock, Acc);
536
case instr_allowed_in_fp_ebb(Other) of
538
place_error(Left, InBlock, [I|Acc]);
542
Check = hipe_icode:mk_primop([], fcheckerror, []),
543
place_error(Left, false, [I, Check|Acc]);
545
exit({"Illegal instruction in caught fp ebb", I});
547
place_error(Left, InBlock, [I|Acc])
551
place_error([], InBlock, Acc) ->
552
{lists:reverse(Acc), InBlock}.
554
place_error_1(I, Left, InBlock, Acc) ->
557
Check = hipe_icode:mk_primop([], fcheckerror, []),
558
place_error(Left, false, [I,Check|Acc]);
560
exit({"End of control flow in caught fp ebb", I});
562
place_error(Left, InBlock, [I|Acc])
565
%% If the block has no successors and we still are in a fp ebb we must
566
%% end it to make sure we don't have any unchecked fp exceptions.
568
handle_unchecked_end(Succ, Code, InBlock) ->
184
transform_block(Left, BackEdgeSucc, NewState1);
186
BackEdge = [X||X<-Succ, not lists:member(X, Left)],
187
NewBackEdgeSucc = lists:foldl(fun(X, Acc)->gb_sets:add(X, Acc)end,
188
BackEdgeSucc, BackEdge),
189
transform_block(Left, NewBackEdgeSucc, NewState1)
191
transform_block([], BackEdgeSucc, State) ->
192
handle_back_edges(gb_sets:to_list(BackEdgeSucc), State).
194
transform_instrs([I|Left], Map, Info, InBlock, Acc)->
195
case is_fop_cand(I, Info) of
197
{NewMap, NewAcc, NewInBlock} = end_block(I, Map, Acc, InBlock),
198
transform_instrs(Left, NewMap, Info, NewInBlock, NewAcc);
201
Defines = defines(I),
202
Convs = [X||X <- remove_duplicates(Uses), lookup(X, Map)==none],
203
NewMap0 = add_new_bindings_assigned(Convs, Map),
204
NewMap = add_new_bindings_unassigned(Defines, NewMap0),
205
ConvIns = get_conv_instrs(Convs, NewMap, Info),
206
{Op, Cont, Fail} = get_info(I),
207
NewI = hipe_icode:mk_primop(lookup_list(Defines, NewMap), Op,
208
lookup_list(Uses, NewMap), Cont, Fail),
210
{true, Fail} -> %% We can continue the block
211
transform_instrs(Left, NewMap, Info, InBlock, [NewI|ConvIns]++Acc);
212
{true, _NewFail} -> %% Must end previous block and start a new one.
213
%% TODO: Find out if this ever happens. If so, handle it!
214
exit('Different catches');
573
{TopCode, Last} = split_code(Code),
574
NewI = hipe_icode:mk_primop([], fcheckerror, []),
575
TopCode++[NewI, Last];
216
BlockStart = hipe_icode:mk_primop([], fclearerror, []),
217
transform_instrs(Left, NewMap, Info, {true, Fail},
218
[NewI, BlockStart|ConvIns]++Acc)
221
transform_instrs([], Map, _Info, InBlock, Acc) ->
222
{Map, lists:reverse(Acc), InBlock}.
224
end_block(I, Map, Code, InBlock)->
225
%% If there is instructions that need to operate on tagged values
226
%% that currently are untagged, we must end the block (if necessary)
227
%% and tag the values .
228
case hipe_icode:type(I) of
231
case [{X, Y}||X<-Uses, (Y=lookup(X, Map))/=none] of
233
{Map, [I|Code], InBlock};
235
Defines = defines(I),
236
NewMap = add_new_bindings_assigned(Defines, Map),
238
Subst = [{Dst, lookup(Dst, NewMap)}|Subst0],
239
NewI = hipe_icode:subst(Subst, I),
240
{NewMap, [NewI|Code], InBlock}
246
case hipe_icode:call_type(I) of
253
case lists:filter(fun(X)->must_be_tagged(X, Map)end, uses(I)) of
255
case LocalCallEndsBlock of
257
Fcheck = hipe_icode:mk_primop([], fcheckerror, [],
259
{Map, [I, Fcheck|Code], false};
261
{Map, [I|Code], InBlock}
264
TagIntrs = mk_tags(Tag, Map),
265
NewMap = lists:foldl(fun(X,Tree)->gb_trees:delete(X, Tree)end,
269
Fcheck = hipe_icode:mk_primop([], fcheckerror, [],
271
{NewMap, [I|TagIntrs]++[Fcheck|Code], false};
273
{NewMap, [I|TagIntrs]++Code, InBlock}
279
[hipe_icode:mk_primop([Dst], unsafe_tag_float, [gb_trees:get(Dst, Map)])||
282
%% We make a difference between values that has been assigned as
283
%% tagged variables and those that has got a 'virtual' binding.
285
add_new_bindings_unassigned([Var|Left], Map)->
286
FVar = hipe_icode:mk_new_fvar(),
287
add_new_bindings_unassigned(Left, gb_trees:insert(Var, FVar, Map));
288
add_new_bindings_unassigned([], Map) ->
291
add_new_bindings_assigned([Var|Left], Map)->
292
case lookup(Var, Map) of
294
FVar = hipe_icode:mk_new_fvar(),
295
NewMap = gb_trees:insert(Var, {assigned, FVar}, Map),
296
add_new_bindings_assigned(Left, NewMap);
298
add_new_bindings_assigned(Left, Map)
300
add_new_bindings_assigned([], Map) ->
304
get_conv_instrs(Vars, Map, Info)->
305
get_conv_instrs(Vars, Map, Info, []).
307
get_conv_instrs([Var|Left], Map, Info, Acc)->
308
{_, Dst} = gb_trees:get(Var, Map),
310
case t_is_float(lookup_type(Var, Info)) of
312
hipe_icode:mk_primop([Dst],unsafe_untag_float,[Var]);
314
hipe_icode:mk_primop([Dst],conv_to_float,[Var])
316
get_conv_instrs(Left, Map, Info, [NewI|Acc]);
317
get_conv_instrs([], _, _, Acc) ->
320
do_prelude(State, Label)->
321
%% Add phi nodes for untagged fp values.
322
Map = state__map(State, Label),
323
case state__pred(State, Label) of
324
List when length(List)>1 ->
325
{Ins, NewMap} = lists:foldl(fun(X, Acc)->get_phi(X, List, Acc)end,
326
{[], Map}, gb_trees:to_list(Map)),
327
{Ins, init_map(NewMap)};
328
_ -> {[], init_map(Map)}
331
get_phi({Var, PredList}, Preds, {InsAcc, Map})->
332
case all_args_equal(PredList) of
336
FVar = hipe_icode:mk_new_fvar(),
337
NewMap = gb_trees:enter(Var, FVar, Map),
338
Phi0 = hipe_icode:mk_phi(FVar, Preds),
339
Phi1 = lists:foldl(fun(X, Ins)->
341
{Pred, {assigned, Val}}->
342
hipe_icode:subst_phi_arg(Ins, Pred, Val);
344
hipe_icode:subst_phi_arg(Ins, Pred, Val)
348
{[Phi1|InsAcc], NewMap}
351
all_args_equal([{_, FVar}|Left])->
352
all_args_equal(Left, FVar).
354
all_args_equal([{_, FVar1}|Left], FVar2) when FVar1 == FVar2 ->
355
all_args_equal(Left, FVar2);
356
all_args_equal([], _) ->
358
all_args_equal(_, _) ->
361
handle_back_edges([Label|Left], State)->
362
%% When there is a back edge we must make sure that any phi nodes
363
%% has the rigth arguments since untagging might have occured after
364
%% the block was processed.
365
BB = state__bb(State, Label),
366
Code = hipe_bb:code(BB),
367
Map = init_map(state__map(State, Label)),
368
NewCode = lists:map(fun(X)->subst_phi_uses(X, Map)end, Code),
369
NewBB = hipe_bb:code_update(BB, NewCode),
370
NewState = state__bb_update(State, Label, NewBB),
371
handle_back_edges(Left, NewState);
372
handle_back_edges([], State) ->
375
subst_phi_uses(I, Map)->
376
case hipe_icode:type(I) of
379
case [{X, Y}||X<-Uses, (Y=lookup(X, Map))/=none] of
383
hipe_icode:subst(Subst, I)
583
instr_allowed_in_fp_ebb(Instr) ->
591
#begin_handler{} -> true;
592
#switch_tuple_arity{} -> true;
593
#switch_val{} -> true;
390
599
%%____________________________________________________________
392
%% Information handling help functions
396
case gb_trees:lookup(Key, Tree) of
398
{value, {assigned, Val}} -> Val;
402
lookup_type(Var, Tree)->
403
case gb_trees:lookup(Var, Tree) of
407
case hipe_icode:is_var(Val) of
415
lookup_type_list(List, Info)->
416
lookup_list(List, fun lookup_type/2, Info, []).
418
lookup_list(List, Info)->
604
%% ------------------------------------------------------------
605
%% Handling the gb_tree
610
delete_all([Key|Left], Tree) ->
611
delete_all(Left, gb_trees:delete_any(Key, Tree));
612
delete_all([], Tree) ->
615
lookup_list(List, Info) ->
419
616
lookup_list(List, fun lookup/2, Info, []).
421
lookup_list([H|T], Fun, Info, Acc)->
618
lookup_list([H|T], Fun, Info, Acc) ->
422
619
lookup_list(T, Fun, Info, [Fun(H, Info)|Acc]);
423
620
lookup_list([], _, _, Acc) ->
424
621
lists:reverse(Acc).
426
enter([Key], Value, Tree)->
427
enter(Key, Value, Tree);
428
enter(Key, Value, Tree)->
429
case t_is_any(Value) of
433
enter_to_leaf(Key, Value, Tree)
436
enter_to_leaf(Key, Value, Tree)->
437
case gb_trees:lookup(Key, Tree) of
441
case hipe_icode:is_var(Val) of
443
enter_to_leaf(Val, Value, Tree);
445
gb_trees:enter(Key, Value, Tree)
448
gb_trees:insert(Key, Value, Tree)
451
enter_defines(I, Types, Info)when is_list(Types)->
456
lists:foldl(fun(X, {Info, [Type|Tail]})->
457
{enter(X,Type,Info), Tail}end,
461
enter_defines(I, Type, Info)->
465
lists:foldl(fun(X, Acc)->enter(X, Type, Acc)end, Info, Def)
468
join_list(List, Info)->
469
join_list(List, Info, t_undefined()).
471
join_list([H|T], Info, Acc)->
472
Type = t_sup(lookup_type(H, Info), Acc),
473
join_list(T, Info, Type);
474
join_list([], _, Acc) ->
477
join_info_in([{Var, Type}|Tail], InfoIn)->
478
case gb_trees:lookup(Var, InfoIn) of
480
join_info_in(Tail, enter(Var, Type, InfoIn));
482
join_info_in(Tail, InfoIn);
484
join_info_in(Tail, enter(Var, t_sup(OldType, Type), InfoIn))
486
join_info_in([], InfoIn) ->
489
join_maps(Pred, BlockMap)->
490
join_maps(Pred, BlockMap, empty()).
492
join_maps([Pred|Left], BlockMap, Map)->
624
case hipe_icode:is_const(Key) of
625
%% This can be true if the same constant has been
626
%% untagged more than once
629
case gb_trees:lookup(Key, Tree) of
631
{value, {assigned, Val}} -> Val;
636
lookup_list_keep_consts(List, Info) ->
637
lookup_list(List, fun lookup_keep_consts/2, Info, []).
639
lookup_keep_consts(Key, Tree) ->
640
case hipe_icode:is_const(Key) of
643
case gb_trees:lookup(Key, Tree) of
645
{value, {assigned, Val}} -> Val;
651
case hipe_icode:is_const(Var) of
652
true -> erl_types:t_from_term(hipe_icode:const_value(Var));
654
case hipe_icode:is_annotated_var(Var) of
655
true -> hipe_icode:var_annotation(Var)
656
%%% false -> erl_types:t_any()
660
%% ------------------------------------------------------------
661
%% Handling the map from variables to fp-variables
663
join_maps(Preds, BlockMap) ->
664
join_maps(Preds, BlockMap, empty()).
666
join_maps([Pred|Left], BlockMap, Map) ->
493
667
case gb_trees:lookup(Pred, BlockMap) of
495
join_maps(Left, BlockMap, Map);
669
%%join_maps(Left, BlockMap, Map);
670
%% All predecessors have not been handled. Use empty map.
496
672
{value, OldMap} ->
497
673
NewMap = join_maps0(gb_trees:to_list(OldMap), Pred, Map),
498
674
join_maps(Left, BlockMap, NewMap)
653
873
state__pred(#state{cfg=Cfg}, Label)->
654
874
hipe_icode_cfg:pred(hipe_icode_cfg:pred_map(Cfg), Label).
876
state__redirect(S=#state{cfg=Cfg}, From, ToOld, ToNew)->
877
NewCfg = hipe_icode_cfg:redirect(Cfg, From, ToOld, ToNew),
656
880
state__bb(#state{cfg=Cfg}, Label)->
657
881
hipe_icode_cfg:bb(Cfg, Label).
659
state__bb_update(S=#state{cfg=Cfg}, Label, BB)->
660
NewCfg = hipe_icode_cfg:bb_update(Cfg, Label, BB),
883
state__bb_add(S=#state{cfg=Cfg}, Label, BB)->
884
NewCfg = hipe_icode_cfg:bb_add(Cfg, Label, BB),
661
885
S#state{cfg=NewCfg}.
663
state__info_in(S, Label)->
664
state__info(S, {Label, in}).
666
state__info_out(S, Label)->
667
state__info(S, {Label, out}).
669
state__info(#state{info_map=IM}, Label)->
670
case gb_trees:lookup(Label, IM) of
671
{value, Info}-> Info;
675
state__info_in_update(S=#state{info_map=IM}, Label, Info)->
676
case gb_trees:lookup({Label, in}, IM) of
678
S#state{info_map=gb_trees:enter({Label, in}, Info, IM)};
682
NewInfo = join_info_in(gb_trees:to_list(OldInfo), Info),
683
S#state{info_map=gb_trees:enter({Label, in}, NewInfo, IM)}
686
state__info_out_update(S=#state{info_map=IM}, Label, Info)->
687
S#state{info_map=gb_trees:enter({Label, out}, Info, IM)}.
689
887
state__map(S=#state{block_map=BM}, Label)->
690
888
join_maps(state__pred(S, Label), BM).
692
state__map_update(S=#state{block_map=BM}, Label, Map, InBlock)->
693
NewBM0 = gb_trees:enter(Label, Map, BM),
890
state__map_update(S=#state{block_map=BM}, Label, Map)->
892
case gb_trees:lookup(Label, BM) of
893
{value, Map1} -> not match(Map1, Map);
898
NewBM = gb_trees:enter(Label, Map, BM),
899
S#state{block_map = NewBM};
904
state__join_in_block(S=#state{edge_map = Map}, Label)->
905
Pred = state__pred(S, Label),
906
Edges = [{X, Label} || X <- Pred],
907
NewInBlock = join_in_block([gb_trees:lookup(X, Map) || X <- Edges]),
908
case gb_trees:lookup({inblock_in, Label}, Map) of
910
NewMap = gb_trees:insert({inblock_in, Label}, NewInBlock, Map),
911
{S#state{edge_map = NewMap}, NewInBlock};
912
{value, NewInBlock} ->
915
NewMap = gb_trees:update({inblock_in, Label}, NewInBlock, Map),
916
{S#state{edge_map = NewMap}, NewInBlock}
919
state__in_block_out_update(S=#state{edge_map = Map}, Label, NewInBlock)->
694
920
Succ = state__succ(S, Label),
695
Fun = fun(X, Acc)->gb_trees:enter({X, inblock}, InBlock, Acc)end,
696
NewBM = lists:foldl(Fun, NewBM0, Succ),
697
S#state{block_map=NewBM}.
699
state__in_block(#state{block_map=BM}, Label)->
700
case gb_trees:lookup({Label, inblock}, BM) of
921
Edges = [{Label, X} || X <- Succ],
922
NewMap = update_edges(Edges, NewInBlock, Map),
923
NewMap1 = gb_trees:enter({inblock_out, Label}, NewInBlock, NewMap),
924
S#state{edge_map = NewMap1}.
926
update_edges([Edge|Left], NewInBlock, Map)->
927
NewMap = gb_trees:enter(Edge, NewInBlock, Map),
928
update_edges(Left, NewInBlock, NewMap);
929
update_edges([], _NewInBlock, NewMap) ->
934
join_in_block([none|_])->
936
join_in_block([{value, InBlock}|Left]) ->
937
join_in_block(Left, InBlock).
939
join_in_block([none|_], _Current)->
941
join_in_block([{value, InBlock}|Left], Current) ->
942
if Current =:= InBlock -> join_in_block(Left, Current);
943
Current =:= false -> false;
944
InBlock =:= false -> false;
945
true -> exit("Basic block is in two different fp ebb:s")
947
join_in_block([], Current) ->
951
state__get_in_block_in(#state{edge_map=Map}, Label)->
952
gb_trees:get({inblock_in, Label}, Map).
954
state__get_in_block_out(#state{edge_map=Map}, Label)->
955
gb_trees:get({inblock_out, Label}, Map).
958
new_worklist(#state{cfg=Cfg})->
959
Start = hipe_icode_cfg:start_label(Cfg),
960
{[Start], [], gb_sets:insert(Start, gb_sets:empty())}.
962
get_work({[Label|Left], List, Set})->
963
{Label, {Left, List, gb_sets:delete(Label, Set)}};
964
get_work({[], [], _Set}) ->
966
get_work({[], List, Set}) ->
967
get_work({lists:reverse(List), [], Set}).
969
add_work({List1, List2, Set}, [Label|Left])->
970
case gb_sets:is_member(Label, Set) of
972
add_work({List1, List2, Set}, Left);
974
%%io:format("Added work: ~w\n", [Label]),
975
NewSet = gb_sets:insert(Label, Set),
976
add_work({List1, [Label|List2], NewSet}, Left)
978
add_work(WorkList, []) ->
982
match(Tree1, Tree2)->
983
match_1(gb_trees:to_list(Tree1), Tree2) andalso
984
match_1(gb_trees:to_list(Tree2), Tree1).
986
match_1([{Key, Val}|Left], Tree2)->
987
case gb_trees:lookup(Key, Tree2) of
989
match_1(Left, Tree2);