15
14
-include("../rtl/hipe_literals.hrl").
18
%% make_pass starts a pass over an icodecfg. The purpose of the pass
19
%% It creates a list of basic blocks that are members of a binary match
20
%% Then it calculates the maximal heap need of this binary match. Finally
21
%% it creates a new bit syntax operation create space that makes
22
%% sure that there is enough space on the heap for each binary match
24
%% The lists of basic blocks that are members of binary matches are also used
25
%% to give all bit syntax operations the state parameters as arguments and destinations.
27
CFG=make_bs_ops_end_basic_blocks(CFG0),
28
StartLabel = hipe_icode_cfg:start(CFG),
29
Vis0 = hipe_icode_cfg:none_visited(CFG),
16
%%--------------------------------------------------------------------
18
%% @spec make_pass(IcodeCFG::icode_cfg()) -> icode_cfg()
20
%% @type icode_cfg() = term()
22
%% @doc Makes a pass over an IcodeCFG so as to create a list of basic
23
%% blocks that are members of a binary match. Then it calculates the
24
%% maximal heap need of this binary match. Finally, it creates a new
25
%% bit syntax operation which makes sure that there is enough space on
26
%% the heap for each binary match.
28
%% <p> The lists of basic blocks which are members of binary matches
29
%% are also used to give all bit syntax operations the state
30
%% parameters as arguments and destinations. </p>
33
make_pass(IcodeCFG0) ->
34
CFG = make_bs_ops_end_basic_blocks(IcodeCFG0),
35
StartLabel = hipe_icode_cfg:start_label(CFG),
36
Vis0 = hipe_icode_cfg:none_visited(),
30
37
EmptyBinChunks = [],
31
38
FinalBinChunks = make_pass(CFG, [StartLabel], Vis0, EmptyBinChunks),
32
CFG1=add_code(FinalBinChunks,CFG),
33
copy_state(FinalBinChunks,CFG1).
39
CFG1 = add_code(FinalBinChunks, CFG),
40
copy_state(FinalBinChunks, CFG1).
35
42
make_bs_ops_end_basic_blocks(CFG) ->
36
LinIcode = hipe_icode_cfg:linearize(CFG),
43
LinIcode = hipe_icode_cfg:cfg_to_linear(CFG),
37
44
Code = hipe_icode:icode_code(LinIcode),
38
NewCode=lists:foldr(fun break_block/2, [], Code),
45
NewCode = lists:foldr(fun break_block/2, [], Code),
39
46
NewLinIcode = hipe_icode:icode_code_update(LinIcode, NewCode),
40
hipe_icode_cfg:init(NewLinIcode).
47
hipe_icode_cfg:linear_to_cfg(NewLinIcode).
42
49
break_block(Instr, Acc) ->
43
50
case hipe_icode:is_call(Instr) of
45
52
case hipe_icode:call_fun(Instr) of
53
{hipe_bs_primop, _} ->
47
54
case hipe_icode:call_continuation(Instr) of
49
56
ContLbl = hipe_icode:mk_new_label(),
115
124
{bs_put_integer, Size, _, _} ->
117
126
{bs_put_string, _, SizeInBytes} ->
118
Size = SizeInBytes * 8
127
Size = SizeInBytes bsl 3; % SizeInBytes * 8
128
{bs_put_string, _, SizeInBytes, _} ->
129
Size = SizeInBytes bsl 3 % SizeInBytes * 8
120
Next=hipe_icode:call_continuation(LastInstr),
131
Next = hipe_icode:call_continuation(LastInstr),
121
132
case {hipe_icode:call_args(LastInstr), Size} of
123
NewFailLbl=hipe_icode:call_fail(LastInstr),
134
NewFailLbl = hipe_icode:call_fail_label(LastInstr),
124
135
case acceptable(CurrentBB, Arg) of
126
extract_binary_creation(CFG, Next, Start, [Label|Labels], [{all, Arg}|Sizes], NewFailLbl);
137
extract_binary_creation(CFG, Next, Start,
138
[Label|Labels], [{all, Arg1}|Sizes],
139
NewVarMap, NewFailLbl);
128
extract_binary_creation(CFG, Next, Start, [Label|Labels], [fail|Sizes], FailLbl)
141
extract_binary_creation(CFG, Next, Start,
142
[Label|Labels], [fail|Sizes],
131
extract_binary_creation(CFG, Next, Start, [Label|Labels], [{const, Size}|Sizes], FailLbl);
146
extract_binary_creation(CFG, Next, Start,
147
[Label|Labels], [{const, Size}|Sizes],
133
extract_binary_creation(CFG, Next, Start, [Label|Labels], [{const, Size}|Sizes], FailLbl);
135
NewFailLbl=hipe_icode:call_fail(LastInstr),
136
extract_binary_creation(CFG, Next, Start, [Label|Labels], [{Size, SizeVar}|Sizes], NewFailLbl)
150
extract_binary_creation(CFG, Next, Start,
151
[Label|Labels], [{const, Size}|Sizes],
154
RealSizeVar = translate_sizevar(SizeVar, NewVarMap),
155
NewFailLbl = hipe_icode:call_fail_label(LastInstr),
156
extract_binary_creation(CFG, Next, Start, [Label|Labels],
157
[{Size, RealSizeVar}|Sizes],
158
NewVarMap, NewFailLbl)
140
%%Extract binaries creates the lists of basic blocks that belongs to each binary match
163
update_varmap([Instr|Rest], VarMap) ->
164
case hipe_icode:is_move(Instr) of
166
Src = hipe_icode:move_src(Instr),
167
Dst = hipe_icode:move_dst(Instr),
168
case hipe_icode:is_var(Src) andalso hipe_icode:is_var(Dst) of
170
case gb_trees:lookup(Src, VarMap) of
172
update_varmap(Rest, gb_trees:insert(Dst, Val, VarMap));
174
update_varmap(Rest, gb_trees:insert(Dst, Src, VarMap))
177
update_varmap(Rest, VarMap)
180
update_varmap(Rest, VarMap)
182
update_varmap([], VarMap) ->
185
translate_sizevar(SizeVar, VarMap) ->
186
case gb_trees:lookup(SizeVar, VarMap) of
193
%% Extract binaries creates the lists of basic blocks that belong to
142
196
acceptable(BB, Arg) ->
143
Code=hipe_bb:butlast(BB),
144
case get_last(Code) of
197
Code = hipe_bb:butlast(BB),
148
case hipe_icode:is_mov(Instr) of
202
Instr = lists:last(Code),
203
case hipe_icode:is_move(Instr) of
150
case hipe_icode:mov_dst(Instr) of
205
case hipe_icode:move_dst(Instr) of
207
Src = hipe_icode:move_src(Instr),
208
case hipe_icode:is_var(Src) of
163
get_last([_|Rest]) ->
167
222
extract_binary_matches(CFG, Label) ->
168
223
CurrentBB = hipe_icode_cfg:bb(CFG, Label),
169
Exit_set0 = hipe_icode_cfg:none_visited(CFG),
224
Exit_set0 = hipe_icode_cfg:none_visited(),
170
225
Bin_match_call = hipe_bb:last(CurrentBB),
171
Exit_set = hipe_icode_cfg:visit(pass_by_restore_catch(hipe_icode:call_fail(Bin_match_call),CFG), Exit_set0),
172
Chunk = [{Label, 0, Successors = [hipe_icode:call_continuation(Bin_match_call)] }],
226
Exit_set = hipe_icode_cfg:visit(pass_by_begin_handler(hipe_icode:call_fail_label(Bin_match_call),CFG), Exit_set0),
227
Successors = [hipe_icode:call_continuation(Bin_match_call)],
228
Chunk = [{Label, 0, Successors}],
173
229
{Label, extract_binary_matches(CFG, Successors, Exit_set, Chunk)}.
175
231
extract_binary_matches(CFG, [Label | Labels], Exit_set0, Chunk0) ->
186
242
case hipe_icode:call_fun(LastInstr) of
187
243
{_, {bs_test_tail,_}} ->
188
hipe_icode_cfg:visit(hipe_icode:call_continuation(LastInstr), Exit_set0);
244
hipe_icode_cfg:visit(hipe_icode:call_continuation(LastInstr),
195
PossibleLabels = pass_by_restore_catch(hipe_icode_cfg:succ(CFG, Label), CFG, []),
252
PossibleLabels = pass_by_begin_handler(hipe_icode_cfg:succ(CFG, Label), CFG, []),
196
253
AcceptableLabels = remove_members(PossibleLabels, Exit_set1),
197
254
Chunk1 = [{Label, Size, AcceptableLabels} | Chunk0],
198
255
extract_binary_matches(CFG, AcceptableLabels, Exit_set1, Chunk1)
200
257
extract_binary_matches(CFG, Labels, Exit_set, Chunk);
202
258
extract_binary_matches(_CFG, [], Exit_set0, Chunk0) ->
203
259
{Exit_set0, Chunk0}.
205
pass_by_restore_catch([Label| Labels], CFG, Acc) ->
206
pass_by_restore_catch(Labels, CFG, [pass_by_restore_catch(Label, CFG)|Acc]);
207
pass_by_restore_catch([],_CFG, Acc) ->
261
pass_by_begin_handler([Label| Labels], CFG, Acc) ->
262
pass_by_begin_handler(Labels, CFG, [pass_by_begin_handler(Label, CFG)|Acc]);
263
pass_by_begin_handler([], _CFG, Acc) ->
209
pass_by_restore_catch(Label, CFG) ->
266
pass_by_begin_handler(Label, CFG) ->
210
267
CurrentBB = hipe_icode_cfg:bb(CFG, Label),
211
[First | _] = hipe_bb:code(CurrentBB),
212
case hipe_icode:is_restore_catch(First) of
214
hipe_icode:goto_label(hipe_bb:last(CurrentBB));
268
[First|_] = hipe_bb:code(CurrentBB),
269
case hipe_icode:is_begin_handler(First) of
270
true -> hipe_icode:goto_label(hipe_bb:last(CurrentBB));
218
274
heap_need(Instruction) ->
219
case {hipe_icode:is_call(Instruction), hipe_icode:call_fun(Instruction)} of
220
{true, {hipe_bs_primop, Name}} ->
222
{bs_get_integer,Size,_} ->
223
case hipe_icode:call_args(Instruction) of
275
case hipe_icode:is_call(Instruction) of
277
case hipe_icode:call_fun(Instruction) of
278
{hipe_bs_primop, Name} ->
280
{bs_get_integer,Size,_} ->
281
case hipe_icode:call_args(Instruction) of
292
{bs_get_float,_,_} ->
294
{bs_get_binary,_Size,Flag} ->
299
trunc(?MAX_HEAP_BIN_SIZE/4)+2
301
{bs_get_binary_all, _} ->
234
{bs_get_float,_,_} ->
236
{bs_get_binary,_Size,Flag} ->
241
trunc(?MAX_HEAP_BIN_SIZE/4) +2
243
{bs_get_binary_all, _} ->
254
313
remove_members(Labels, Set) ->
255
314
remove_members(Labels, Set, []).
257
316
remove_members([Label | Labels], Set, Ok) ->
258
case hipe_icode_cfg:visited(Label, Set) of
317
case hipe_icode_cfg:is_visited(Label, Set) of
260
319
remove_members(Labels, Set, Ok);
262
remove_members(Labels, Set, [Label |Ok])
321
remove_members(Labels, Set, [Label|Ok])
265
remove_members([], _Set, Ok) ->
323
remove_members([], _Set, Ok) ->
326
calculate_need({Chunk, Hash}, Start) ->
327
case gb_trees:lookup(Start, Hash) of
329
{Val, {Chunk, Hash}};
331
{value,{Start,Need,Succ}} = lists:keysearch(Start,1,Chunk),
332
{NewValue, {Chunk, NewHash}} = calculate_need(Chunk, Succ, Need, Hash),
333
NewerHash = gb_trees:enter(Start, NewValue, NewHash),
334
{NewValue, {Chunk, NewerHash}}
268
336
calculate_need(Chunk, Start) ->
269
{value,{Start,Need,Succ}}=lists:keysearch(Start,1,Chunk),
270
calculate_need(Chunk, Succ, Need).
272
calculate_need(_Chunk, [], Need) ->
275
calculate_need(Chunk, Succ, Need) ->
276
{Resultlist, _} = lists:mapfoldl(fun(X, Ch)->{calculate_need(Ch,X), Ch} end, Chunk, Succ),
277
lists:max(Resultlist)+Need.
280
add_code([{match,{Start,{_Exitset,Chunk}}}|Rest],CFG) ->
281
Need=calculate_need(Chunk, Start),
282
{Shifts, Args}= runtime_effects(Chunk, CFG),
283
StartBlock=hipe_icode_cfg:bb(CFG,Start),
284
ResultBB=hipe_bb:code_update(StartBlock, hipe_bb:butlast(StartBlock) ++ [hipe_icode:mk_primop([],{hipe_bs_primop,{bs_create_space, Need, Shifts}},Args), hipe_bb:last(StartBlock)]),
285
CFG1=hipe_icode_cfg:bb_update(CFG, Start, ResultBB),
337
{Need,_} = calculate_need({Chunk, gb_trees:empty()}, Start),
340
calculate_need(Chunk, [], Need, Hash) ->
341
{Need, {Chunk, Hash}};
343
calculate_need(Chunk, Succ, Need, Hash) ->
344
{Resultlist,NewAccu} = lists:mapfoldl(fun(X, Ch)-> calculate_need(Ch, X) end,
346
{lists:max(Resultlist)+Need, NewAccu}.
348
add_code([{match,{Start,{_Exitset,Chunk}}}|Rest], CFG) ->
349
Need = calculate_need(Chunk, Start),
350
{Shifts,Args} = runtime_effects(Chunk, CFG),
351
StartBlock = hipe_icode_cfg:bb(CFG,Start),
352
ResultBB = hipe_bb:code_update(StartBlock, hipe_bb:butlast(StartBlock) ++ [hipe_icode:mk_primop([],{hipe_bs_primop,{bs_create_space, Need, Shifts}},Args), hipe_bb:last(StartBlock)]),
353
CFG1 = hipe_icode_cfg:bb_add(CFG, Start, ResultBB),
286
354
add_code(Rest,CFG1);
288
355
add_code([{create,{Start, Sizes, Labels, FailLbl}}|Rest], CFG) ->
289
StartBlock=hipe_icode_cfg:bb(CFG,Start),
290
Init=hipe_bb:last(StartBlock),
291
{NewBlock, State} = update_init(Init, StartBlock, Sizes, FailLbl),
292
CFG1= hipe_icode_cfg:bb_update(CFG, Start, NewBlock),
293
CFG2= add_state(Labels, State, CFG1),
356
StartBlock = hipe_icode_cfg:bb(CFG,Start),
357
Init = hipe_bb:last(StartBlock),
358
{NewBlock,State} = update_init(Init, StartBlock, Sizes, FailLbl),
359
CFG1 = hipe_icode_cfg:bb_add(CFG, Start, NewBlock),
360
CFG2 = add_state(Labels, State, CFG1),
294
361
add_code(Rest, CFG2);
299
365
update_init(Init, StartBlock, Sizes, FailLbl) ->
300
Base=hipe_icode:mk_new_reg(),
301
Offset=hipe_icode:mk_new_reg(),
366
Base = hipe_icode:mk_new_reg(),
367
Offset = hipe_icode:mk_new_reg(),
303
369
case condense_sizes(Sizes) of
304
370
{Const, Units, SizeArgs} ->
305
Init1=hipe_icode:call_fun_update(Init, {hipe_bs_primop,{bs_init,{Const, Units}}}),
306
Init2=hipe_icode:call_dst_update(Init1, [Base, Offset]),
307
Init3=hipe_icode:call_args_update(Init2, SizeArgs),
308
hipe_icode:call_set_fail(Init3, FailLbl);
371
Init1 = hipe_icode:call_fun_update(Init, {hipe_bs_primop,{bs_init,{Const, Units}}}),
372
Init2 = hipe_icode:call_dstlist_update(Init1, [Base, Offset]),
373
Init3 = hipe_icode:call_args_update(Init2, SizeArgs),
374
hipe_icode:call_set_fail_label(Init3, FailLbl);
310
Init1=hipe_icode:call_fun_update(Init, {hipe_bs_primop,{bs_init,fail}}),
311
hipe_icode:call_dst_update(Init1, [Base, Offset])
376
Init1 = hipe_icode:call_fun_update(Init, {hipe_bs_primop,{bs_init,fail}}),
377
hipe_icode:call_dstlist_update(Init1, [Base, Offset])
313
NewBlock=hipe_bb:code_update(StartBlock, hipe_bb:butlast(StartBlock) ++ [NewInit]),
314
{NewBlock, [Base, Offset]}.
379
NewBlock = hipe_bb:code_update(StartBlock, hipe_bb:butlast(StartBlock) ++ [NewInit]),
380
{NewBlock,[Base,Offset]}.
316
382
add_state([Label|Rest], State, CFG) ->
317
383
Block = hipe_icode_cfg:bb(CFG, Label),
318
384
Instr = hipe_bb:last(Block),
319
385
Instr1 = add_state_to_instr(Instr, State),
320
386
NewBB = hipe_bb:code_update(Block, hipe_bb:butlast(Block)++[Instr1]),
321
CFG1 = hipe_icode_cfg:bb_update(CFG, Label, NewBB),
387
CFG1 = hipe_icode_cfg:bb_add(CFG, Label, NewBB),
322
388
add_state(Rest, State, CFG1);
323
389
add_state([], _State, CFG) ->
325
392
add_state_to_instr(Instruction, State=[_Base, Offset]) ->
326
393
case hipe_icode:is_call(Instruction) of
328
395
case hipe_icode:call_fun(Instruction) of
330
396
{hipe_bs_primop, Name} ->
331
397
OldArgs = hipe_icode:call_args(Instruction),
332
OldDsts = hipe_icode:call_dst(Instruction),
398
OldDsts = hipe_icode:call_dstlist(Instruction),
333
399
{NewArgs, NewDsts} =
336
402
{OldArgs, State};
337
403
{bs_put_string, _, _} ->
338
404
{OldArgs++State, [Offset]};
405
{bs_put_string, _, _, _} ->
406
{OldArgs++State, [Offset]};
339
407
{bs_put_integer, _, _, _} ->
340
408
{OldArgs++State, [Offset]};
341
409
{bs_put_float, _, _, _} ->
419
486
add_state_to_bs_primops(Rest, CFG1, State);
421
487
add_state_to_bs_primops([], CFG, _State) ->
490
get_local_mapping(Code) ->
491
get_local_mapping(Code, gb_trees:empty()).
493
get_local_mapping([Instr|Instrs], Map) ->
494
case hipe_icode:is_move(Instr) of
496
Dst = hipe_icode:move_dst(Instr),
497
Src = hipe_icode:move_src(Instr),
498
get_local_mapping(Instrs, gb_trees:enter(Dst, Src, Map));
500
get_local_mapping(Instrs, Map)
502
get_local_mapping([], Map) ->
505
get_alias(Arg, Map) ->
506
case gb_trees:lookup(Arg, Map) of
424
511
runtime_effects(Chunk, CFG) ->
425
512
{Vars, Bin}=find_results(Chunk, CFG),
426
513
runtime_effects(Chunk, CFG, [], [], Vars, Bin).
428
515
runtime_effects([{Label,_,_}|Rest], CFG, Shifts, Args, Vars, Bin) ->
429
Instruction=hipe_bb:last(hipe_icode_cfg:bb(CFG, Label)),
516
BB = hipe_icode_cfg:bb(CFG, Label),
517
LocalMapping = get_local_mapping(hipe_bb:code(BB)),
518
Instruction = hipe_bb:last(BB),
430
519
case hipe_icode:is_call(Instruction) of
432
521
case hipe_icode:call_fun(Instruction) of
433
522
{hipe_bs_primop, {bs_get_integer, Size,_}} ->
434
523
{Shifts1, Args1} =
435
case hipe_icode:call_args(Instruction) of
437
case lists:member(Arg, Vars) of
439
{[size|Shifts], [Bin|Args]};
441
{[rooflog2(Size)|Shifts], [Arg|Args]}
524
case hipe_icode:call_args(Instruction) of
526
RealArg = get_alias(Arg, LocalMapping),
527
case lists:member(RealArg, Vars) of
529
{[size|Shifts], [Bin|Args]};
531
{[rooflog2(Size)|Shifts], [RealArg|Args]}
446
536
runtime_effects(Rest, CFG, Shifts1, Args1, Vars, Bin);
448
538
runtime_effects(Rest, CFG, Shifts, Args, Vars, Bin)