1
%%%-------------------------------------------------------------------
2
%%% File : hipe_icode_split_arith.erl
3
%%% Author : Tobias Lindahl <tobiasl@csd.uu.se>
6
%%% Created : 12 Nov 2003 by Tobias Lindahl <tobiasl@csd.uu.se>
7
%%%-------------------------------------------------------------------
8
-module(hipe_icode_split_arith).
12
-include("hipe_icode.hrl").
14
-define(MIN_RATIO, 0.005).
16
%%-define(UNSAFE, true).
17
-define(UNSAFE, false).
20
case preprocess(Cfg) of
21
{do_not_split, _Ratio} ->
22
%%io:format("split(Cfg): NOT Reasonable to split ~w.Ratio: ~.3f\n",
25
{split, _Ratio, NewCfg} ->
26
%%hipe_icode_cfg:pp(Cfg),
27
%%io:format("split(Cfg):Reasonable to split ~w. Ratio: ~.2f\n",
29
NewCfg0 = split(NewCfg),
30
NewCfg1 = cleanup(NewCfg0),
31
%%hipe_icode_cfg:pp(NewCfg1),
36
Icode=hipe_icode_cfg:cfg_to_linear(Cfg),
37
LinearCode = hipe_icode:icode_code(Icode),
38
NewLinearCode=cleanup_code(LinearCode),
39
NewIcode = hipe_icode:icode_code_update(Icode, NewLinearCode),
40
hipe_icode_cfg:linear_to_cfg(NewIcode).
42
cleanup_code([I|Is]) ->
45
case hipe_icode:call_fail_label(I) of
49
case hipe_icode:call_continuation(I) of
51
NewLabel = hipe_icode:mk_new_label(),
52
NewLabelName = hipe_icode:label_name(NewLabel),
53
NewI=hipe_icode:call_set_continuation(I, NewLabelName),
54
[NewI, NewLabel|cleanup_code(Is)];
62
cleanup_code([]) -> [].
65
Icode = hipe_icode_cfg:cfg_to_linear(Cfg),
66
LinearCode = hipe_icode:icode_code(Icode),
67
{NofArith, NofIns, NewLinearCode} = preprocess_code(LinearCode),
68
case NofArith / NofIns of
69
X when X >= ?MIN_RATIO ->
70
NewIcode = hipe_icode:icode_code_update(Icode, NewLinearCode),
71
{split, X, hipe_icode_cfg:linear_to_cfg(NewIcode)};
76
preprocess_code([H|Code])->
77
preprocess_code(Code, 0, 0, [H]).
79
preprocess_code([I|Left], NofArith, NofIns,CodeAcc = [HdCode|TlCodeAcc])->
84
case hipe_icode:is_label(HdCode) of
86
preprocess_code(Left, NofArith + 1, NofIns + 1,[I|CodeAcc]);
88
NewLabel = hipe_icode:mk_new_label(),
89
NewLabelName = hipe_icode:label_name(NewLabel),
91
case hipe_icode:is_call(HdCode) of
95
hipe_icode:call_set_continuation(HdCode, NewLabelName)|
100
hipe_icode:mk_goto(hipe_icode:label_name(NewLabel))|
103
preprocess_code(Left, NofArith + 1, NofIns + 1, NewCodeAcc)
106
case hipe_icode:is_label(I) of % Don't count labels as intructions.
108
preprocess_code(Left, NofArith, NofIns, [I|CodeAcc]);
110
preprocess_code(Left, NofArith, NofIns + 1, [I|CodeAcc])
114
preprocess_code(Left, NofArith, NofIns + 1, [I|CodeAcc])
116
preprocess_code([], NofArith, NofIns, CodeAcc) ->
117
{NofArith, NofIns, lists:reverse(CodeAcc)}.
121
AllLabels = hipe_icode_cfg:reverse_postorder(Cfg),
122
{OldToNewMap, NewToOldMap} = new_label_maps(AllLabels),
123
%%io:format("split(Cfg): Adding fixnum trace ...\n", []),
124
NewCfg = add_fixnum_trace(AllLabels, OldToNewMap, Cfg),
125
%%io:format("split(Cfg): Adding fixnum trace: Done\n", []),
126
%%io:format("split(Cfg): Inserting tests\n", []),
129
Start = hipe_icode_cfg:start_label(NewCfg),
130
NewStart = gb_trees:get(Start, OldToNewMap),
131
hipe_icode_cfg:start_label_update(NewCfg, NewStart);
134
insert_tests(NewCfg, [gb_trees:get(X, OldToNewMap)||X<-AllLabels],
135
NewToOldMap, OldToNewMap),
136
%%io:format("split(Cfg): Inserting testsL Done\n", []),
140
add_fixnum_trace([Lbl|Left], LabelMap, Cfg)->
141
NewLbl = gb_trees:get(Lbl, LabelMap),
142
Code = hipe_bb:code(hipe_icode_cfg:bb(Cfg, Lbl)),
143
NewCode = map_code(Code, Lbl, LabelMap),
144
NewBB = hipe_bb:mk_bb(NewCode),
145
NewCfg = hipe_icode_cfg:bb_add(Cfg, NewLbl, NewBB),
146
add_fixnum_trace(Left, LabelMap, NewCfg);
147
add_fixnum_trace([], _LabelMap, Cfg) ->
150
map_code(Ins, ArithFail, LabelMap) ->
151
map_code(Ins, ArithFail, LabelMap, []).
153
map_code([I|Left], ArithFail, LabelMap, Acc) ->
158
case hipe_icode:defines(I) of
160
map_code(Left, ArithFail, LabelMap, [redirect(I, LabelMap)|Acc]);
162
NewOp = arithop_to_unsafe(hipe_icode:call_fun(I)),
163
NewI1 = hipe_icode:call_fun_update(I, NewOp),
164
NewI2 = redirect(NewI1, LabelMap),
166
case hipe_icode:call_fail_label(NewI2) of
170
false -> hipe_icode:call_set_fail_label(NewI2, ArithFail)
174
map_code(Left, ArithFail, LabelMap, [NewI3|Acc])
177
map_code(Left, ArithFail, LabelMap, [redirect(I, LabelMap)|Acc])
180
map_code(Left, ArithFail, LabelMap, [redirect(I, LabelMap)|Acc])
182
map_code([], _ArithFail, _LabelMap, Acc) ->
185
insert_tests(Cfg, Labels,NewToOldMap, OldToNewMap) ->
186
InfoMap = infomap_init(Labels),
187
%%io:format("insert_tests/3: Finding testpoints ...\n", []),
188
NewInfoMap = find_testpoints(Cfg, Labels, InfoMap),
189
%%io:format("insert_tests/3: Finding testpoints: Done\n", []),
190
%%io:format("insert_tests/3: Infomap: ~w\n", [gb_trees:to_list(NewInfoMap)]),
191
make_tests(Cfg, NewInfoMap, NewToOldMap, OldToNewMap).
193
find_testpoints(Cfg, Labels, InfoMap) ->
194
case find_testpoints(Labels, InfoMap, Cfg, false) of
195
{dirty, NewInfoMap} ->
196
%%io:format("find_testpoints/3: Looping\n", []),
197
find_testpoints(Cfg, Labels, NewInfoMap);
202
find_testpoints([Lbl|Left], InfoMap, Cfg, Dirty)->
203
Code = hipe_bb:code(hipe_icode_cfg:bb(Cfg, Lbl)),
204
InfoOut = join_info(hipe_icode_cfg:succ(Cfg, Lbl), InfoMap),
205
OldInfoIn = infomap_get_all(Lbl, InfoMap),
206
NewInfoIn = traverse_code(lists:reverse(Code), InfoOut),
207
case (gb_sets:is_subset(OldInfoIn, NewInfoIn) andalso
208
gb_sets:is_subset(NewInfoIn, OldInfoIn)) of
210
find_testpoints(Left, InfoMap, Cfg, Dirty);
212
%%io:format("find_testpoints/4: Label: ~w: OldMap ~w\nNewMap: ~w\n",
213
%% [Lbl, gb_sets:to_list(OldInfoIn), gb_sets:to_list(NewInfoIn)]),
214
NewInfoMap = gb_trees:update(Lbl, NewInfoIn, InfoMap),
215
find_testpoints(Left, NewInfoMap, Cfg, true)
217
find_testpoints([], InfoMap, _Cfg, Dirty) ->
218
if Dirty -> {dirty, InfoMap};
222
traverse_code([I|Left], Info)->
223
NewInfo = kill_defines(I, Info),
226
case is_unsafe_arith(I) of
228
%% The dst is sure to be a fixnum. Remove the 'killed' mark.
229
Dst = hd(hipe_icode:call_dstlist(I)),
230
NewInfo1 = gb_sets:delete_any({killed, Dst}, NewInfo),
232
gb_sets:union(NewInfo1, gb_sets:from_list(hipe_icode:uses(I))),
233
traverse_code(Left, NewInfo2);
235
traverse_code(Left, NewInfo)
238
Dst = hipe_icode:move_dst(I),
239
case gb_sets:is_member(Dst, Info) of
241
%% The dst is an argument to an arith op. Transfer the test
242
%% to the src and remove the 'killed' mark from the dst.
243
NewInfo1 = gb_sets:delete({killed, Dst}, NewInfo),
244
Src = hipe_icode:move_src(I),
245
case hipe_icode:is_const(Src) of
247
traverse_code(Left, NewInfo1);
249
NewInfo2 = gb_sets:add(Src, NewInfo1),
250
traverse_code(Left, NewInfo2)
253
traverse_code(Left, NewInfo)
256
traverse_code(Left, NewInfo)
258
traverse_code([], Info) ->
261
kill_defines(I, Info)->
262
Defines = hipe_icode:defines(I),
263
case [X||X<-Defines, gb_sets:is_member(X, Info)] of
264
List when length(List)>0 ->
265
TmpInfo = gb_sets:difference(Info, gb_sets:from_list(List)),
266
gb_sets:union(gb_sets:from_list([{killed, X}||X<-List]), TmpInfo);
271
make_tests(Cfg, InfoMap, NewToOldMap, OldToNewMap)->
272
%%io:format("make_tests 0:\n",[]),
273
WorkList = make_worklist(gb_trees:keys(NewToOldMap), InfoMap,
274
NewToOldMap, Cfg, []),
275
%%io:format("make_tests 1:Worklist: ~w\n",[WorkList]),
276
NewCfg = make_tests(WorkList, Cfg),
277
%%io:format("make_tests 2\n",[]),
278
%% If the arguments to this function are used in unsafe arith
279
%% they should be marked as killed by a new start block.
280
Args = hipe_icode_cfg:params(NewCfg),
281
Start = hipe_icode_cfg:start_label(NewCfg),
282
AltStart = gb_trees:get(Start, OldToNewMap),
283
UnsafeIn = gb_sets:to_list(infomap_get(AltStart, InfoMap)),
284
case [X || X<-UnsafeIn, Y<-Args, X=:=Y] of
286
hipe_icode_cfg:start_label_update(NewCfg, AltStart);
288
NewStart = hipe_icode:label_name(hipe_icode:mk_new_label()),
289
NewCfg1 = insert_test_block(NewStart, AltStart,
292
hipe_icode_cfg:start_label_update(NewCfg1, NewStart)
297
make_worklist([Lbl|Left], InfoMap, LabelMap, Cfg, Acc)->
298
case infomap_get_killed(Lbl, InfoMap) of
299
[] -> make_worklist(Left, InfoMap, LabelMap, Cfg, Acc);
301
%%io:format("make_worklist 1 ~w\n",[Vars]),
303
[{Lbl, Succ, gb_trees:get(Succ, LabelMap), Vars}
304
|| Succ<-hipe_icode_cfg:succ(Cfg, Lbl)] ++ Acc,
305
%%io:format("make_worklist 2\n",[]),
306
make_worklist(Left, InfoMap, LabelMap, Cfg, NewAcc)
308
make_worklist([], _InfoMap, _LabelMap, _Cfg, Acc) ->
311
make_tests([{FromLbl, ToLbl, FailLbl, Vars}|Left], Cfg)->
312
NewLbl = hipe_icode:label_name(hipe_icode:mk_new_label()),
313
TmpCfg = insert_test_block(NewLbl, ToLbl, FailLbl, Vars, Cfg),
314
NewCfg = hipe_icode_cfg:redirect(TmpCfg, FromLbl, ToLbl, NewLbl),
315
make_tests(Left, NewCfg);
316
make_tests([], Cfg) ->
319
insert_test_block(NewLbl, Succ, FailLbl, Vars, Cfg)->
320
Code = [hipe_icode:mk_type(Vars, fixnum, Succ, FailLbl, 0.99)],
321
BB = hipe_bb:mk_bb(Code),
322
hipe_icode_cfg:bb_add(Cfg, NewLbl, BB).
326
infomap_init(Labels)->
327
infomap_init(Labels, gb_trees:empty()).
329
infomap_init([Lbl|Left], Map)->
330
infomap_init(Left, gb_trees:insert(Lbl, gb_sets:empty(), Map));
331
infomap_init([], Map) ->
334
join_info(Labels, Map)->
335
join_info(Labels, Map, gb_sets:empty()).
337
join_info([Lbl|Left], Map, Set) ->
338
join_info(Left, Map, gb_sets:union(Set, infomap_get(Lbl, Map)));
339
join_info([], _Map, Set) ->
343
infomap_get(Lbl, Map)->
344
case gb_trees:lookup(Lbl, Map) of
345
none -> gb_sets:empty();
347
gb_sets:filter(fun(X)->case X of
355
infomap_get_all(Lbl, Map)->
356
case gb_trees:lookup(Lbl, Map) of
357
none -> gb_sets:empty();
361
infomap_get_killed(Lbl, Map)->
362
case gb_trees:lookup(Lbl, Map) of
367
{killed, Var} -> [Var|Acc];
371
lists:foldl(Fun, [], gb_sets:to_list(Val))
375
case hipe_icode:call_fun(I) of
386
case hipe_icode:call_fun(I) of
396
arithop_to_unsafe(Op)->
400
'band' -> unsafe_band;
402
'bxor' -> unsafe_bxor;
403
'bnot' -> unsafe_bnot
406
redirect(I, LabelMap)->
407
case hipe_icode:successors(I) of
411
RedirectMap = [{X, gb_trees:get(X, LabelMap)}||X<-Succ],
412
redirect_1(RedirectMap, I)
415
redirect_1([{From, To}|Left], I)->
416
redirect_1(Left, hipe_icode:redirect_jmp(I, From, To));
420
new_label_maps(Labels)->
421
new_label_maps(Labels, gb_trees:empty(), gb_trees:empty()).
423
new_label_maps([Lbl|Left], Map1, Map2)->
424
NewLabel = hipe_icode:label_name(hipe_icode:mk_new_label()),
425
NewMap1 = gb_trees:insert(Lbl, NewLabel, Map1),
426
NewMap2 = gb_trees:insert(NewLabel, Lbl, Map2),
427
new_label_maps(Left, NewMap1, NewMap2);
428
new_label_maps([], Map1, Map2) ->