1
1
%% -*- erlang-indent-level: 2 -*-
2
2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4
%% Semi-local copy propagation, constant propagation, constant folding
4
%% Semi-local copy propagation, constant propagation, constant folding,
5
5
%% and dead code removal.
7
7
%% Works on extended basic blocks. No iteration is done at this point.
9
%% The environment binds (rtl) variables to:
9
%% The environment binds (RTL) variables to:
14
14
-module(hipe_rtl_prop).
15
-export([cfg/1, do/1]).
16
17
-include("../main/hipe.hrl").
19
?opt_start_timer("Rtl Prop"),
20
?opt_start_timer("EBBs"),
21
EBBs = hipe_rtl_ebb:cfg(CFG),
22
?opt_stop_timer("EBBs"),
23
?opt_start_timer("Prop"),
24
CFG0 = prop_ebbs(EBBs, CFG),
25
?opt_stop_timer("Prop"),
26
?opt_start_timer("Liveness"),
27
Liveness = hipe_rtl_liveness:analyze(CFG0),
28
?opt_stop_timer("Liveness"),
29
?opt_start_timer("Dead code"),
30
EBBs2 = hipe_rtl_ebb:cfg(CFG0),
31
CFG1 = dead_code_ebbs(EBBs2, CFG0, Liveness),
32
?opt_stop_timer("Dead code"),
33
?opt_stop_timer("RtlProp"),
38
%% Iterate over the extended basic blocks of a cfg.
43
prop_ebbs([Ebb|Ebbs], CFG) ->
44
CFG0 = prop_ebb(Ebb, new_env(), CFG),
45
prop_ebbs(Ebbs, CFG0).
49
%% If Lbl is a member of the extended block Ebb. Then propagate info
50
%% and continue with its successors.
53
prop_ebb(Ebb, Env, CFG) ->
54
case hipe_rtl_ebb:type(Ebb) of
56
Lbl = hipe_rtl_ebb:node_label(Ebb),
57
BB = hipe_rtl_cfg:bb(CFG, Lbl),
58
{NewCode, NewEnv} = prop_instrs(hipe_bb:code(BB), Env),
59
NewBB = hipe_bb:code_update(BB, NewCode),
60
NewCFG = hipe_rtl_cfg:bb_update(CFG, Lbl, NewBB),
61
Succ = hipe_rtl_ebb:node_successors(Ebb),
62
prop_succ(Succ, NewEnv, NewCFG);
68
prop_succ([], _Env, CFG) ->
70
prop_succ([EBB|EBBs], Env, CFG) ->
71
NewCFG = prop_ebb(EBB, Env, CFG),
72
prop_succ(EBBs, Env, NewCFG).
74
prop_instrs(Is, Env) ->
75
{NewIs, NewEnv} = lists:mapfoldl(fun prop_instr/2, Env, Is),
76
{lists:flatten(NewIs), NewEnv}.
79
%prop_instrs([], Env) ->
81
%prop_instrs([I|Is], Env) ->
82
% {NewI, Env0} = prop_instr(I, Env),
83
% {NewIs, NewEnv} = prop_instrs(Is, Env0),
84
% %% io:format("I ~w to ~w\n",[I,NewI]),
86
% [_|_] -> {NewI++NewIs, NewEnv}; %% alub -> [move, goto]
87
% _ -> {[NewI|NewIs], NewEnv}
18
-include("hipe_rtl.hrl").
20
-record(aliased_var, {name}).
22
%%=====================================================================
25
%% io:format("%%------------- RTL code in beginning of rtl_prop -----------\n"),
26
%% hipe_rtl_cfg:pp(CFG),
28
%% io:format("%%------------- After prop -----------\n"),
29
%% hipe_rtl_cfg:pp(CFG1),
30
CFG2 = hipe_rtl_cfg:remove_trivial_bbs(CFG1),
31
%% io:format("%%------------- After remove_trivial_bbs -----------\n"),
32
Liveness = hipe_rtl_liveness:analyze(CFG2),
33
EBBs2 = hipe_rtl_ebb:cfg(CFG2),
34
CFG3 = dead_code_ebbs(EBBs2, CFG2, Liveness),
35
%% io:format("%%------------- After dead_code_ebbs -----------\n"),
36
%% hipe_rtl_cfg:pp(CFG3),
37
CFG4 = remove_loads(CFG3),
38
%% io:format("%%------------- After remove_loads -----------\n"),
39
%% hipe_rtl_cfg:pp(CFG4),
40
CFG5 = hipe_rtl_cfg:remove_unreachable_code(CFG4),
41
%% io:format("%%------------- After remove_unreachable_code -----------\n"),
42
%% hipe_rtl_cfg:pp(CFG5),
43
CFG6 = hipe_rtl_cfg:remove_trivial_bbs(CFG5),
44
%% io:format("%%------------- After remove_trivial_bbs -----------\n"),
45
%% hipe_rtl_cfg:pp(CFG6),
46
CFG7 = remove_stores(CFG6),
47
%% io:format("%%------------- After remove_stores -----------\n"),
48
%% hipe_rtl_cfg:pp(CFG7),
52
Start = hipe_rtl_cfg:start_label(CFG),
53
Tree = gb_trees:empty(),
54
PredMap = hipe_rtl_cfg:pred_map(CFG),
55
Info = fix_point([Start], CFG, PredMap, Tree),
56
pass_through([Start], CFG, PredMap, Info, gb_sets:singleton(Start)).
92
59
%% Propagate copies and constants for one instruction.
318
272
simplify_mm(Ss, Ds, LiveOut) ->
319
273
simplify_mm(Ss, Ds, [], [], LiveOut).
321
simplify_mm([S|Srcs],[S|Dsts], SAcc, DAcc, LiveOut) ->
275
simplify_mm([S|Srcs], [S|Dsts], SAcc, DAcc, LiveOut) ->
322
276
simplify_mm(Srcs, Dsts, SAcc, DAcc, LiveOut);
323
simplify_mm([S|Srcs],[D|Dsts], SAcc, DAcc, LiveOut) ->
277
simplify_mm([S|Srcs], [D|Dsts], SAcc, DAcc, LiveOut) ->
324
278
case gb_sets:is_element(D, LiveOut) of
325
279
true -> %% The dest is live after the instruction.
326
simplify_mm(Srcs, Dsts, [S|SAcc] , [D|DAcc],LiveOut);
280
simplify_mm(Srcs, Dsts, [S|SAcc], [D|DAcc],LiveOut);
327
281
false -> %% The dest is dead, move unnecessary.
328
282
simplify_mm(Srcs, Dsts, SAcc, DAcc, LiveOut)
361
314
bind({Map1,Map2}, X, Y) ->
363
case gb_trees:lookup(Y,Map2) of
364
none -> gb_trees:enter(Y,[X],Map2);
366
gb_trees:enter(Y,[X|Ys],Map2)
316
case gb_trees:lookup(Y,Map2) of
318
gb_trees:enter(Y,[X],Map2);
320
gb_trees:enter(Y,[X|Ys],Map2)
368
{gb_trees:enter(X,Y,Map1),
322
{gb_trees:enter(X,Y,Map1),NewMap2}.
374
325
%% Kill bindings with references to X
376
328
kill(X,M = {Map1,Map2}) ->
377
329
%% First check if anyting is bound to X.
379
331
case gb_trees:lookup(X,Map2) of
381
333
{value,Y1s} -> %% All Y1s bound to X
384
gb_trees:delete_any(Y1,MapAcc)
334
{lists:foldl(fun (Y1,MapAcc) ->
335
gb_trees:delete_any(Y1,MapAcc)
386
337
gb_trees:delete(X,Map2)}
388
339
%% Now check if X is bound to anything.
390
341
{value,Y2} -> %% X bound to Y2
391
342
{gb_trees:delete(X,M11),
392
343
case gb_trees:lookup(Y2,M12) of
395
gb_trees:enter(Y2,lists:delete(X,Y2s),M12)
347
gb_trees:enter(Y2,lists:delete(X,Y2s),M12)
402
353
unbind([], Map) ->
404
355
unbind([V|Vs], Map) ->
405
356
unbind(Vs, kill(V, Map)).
409
CFG2=hipe_rtl_cfg:remove_dead_code(CFG1),
410
Liveness = hipe_rtl_liveness:analyze(CFG2),
411
EBBs2 = hipe_rtl_ebb:cfg(CFG2),
412
CFG3=dead_code_ebbs(EBBs2, CFG2, Liveness),
417
Start=hipe_rtl_cfg:start(CFG),
418
Tree=gb_trees:empty(),
419
PredMap = hipe_rtl_cfg:pred_map(CFG),
420
Info = fix_point([Start], CFG, PredMap, Tree),
421
pass_through([Start], CFG, PredMap, Info, gb_sets:singleton(Start)).
423
358
pass_through([Label|Labels], CFG, PredMap, Info, Passed) ->
424
Pred=hipe_rtl_cfg:pred(PredMap,Label),
425
InfoIn= join(Pred, Info),
359
Pred = hipe_rtl_cfg:pred(PredMap,Label),
360
InfoIn = join(Pred, Info),
426
361
CurrentBB = hipe_rtl_cfg:bb(CFG, Label),
427
362
OldCode = hipe_bb:code(CurrentBB),
428
363
{NewCode, _NewInfoOut} = prop2_instrs(OldCode, InfoIn),
429
364
NewBB = hipe_bb:mk_bb(NewCode),
430
NewCFG = hipe_rtl_cfg:bb_update(CFG, Label, NewBB),
365
NewCFG = hipe_rtl_cfg:bb_add(CFG, Label, NewBB),
431
366
NewSuccMap = hipe_rtl_cfg:succ_map(NewCFG),
432
367
Succ = hipe_rtl_cfg:succ(NewSuccMap, Label),
433
368
{NewLbls, NewPassed} = not_members_of_set(Succ, Passed),
434
369
NewPredMap = hipe_rtl_cfg:pred_map(NewCFG),
435
370
pass_through(Labels ++ NewLbls, NewCFG, NewPredMap, Info, NewPassed);
437
371
pass_through([], CFG, _PredMap, _Info, _Passed) ->
543
476
PredMap = hipe_rtl_cfg:pred_map(CFG),
544
477
SuccMap = hipe_rtl_cfg:succ_map(CFG),
545
478
Info = gb_trees:empty(),
546
Start = hipe_rtl_cfg:start(CFG),
479
Start = hipe_rtl_cfg:start_label(CFG),
547
480
NewInfo=fix_remove([Start], CFG, PredMap, SuccMap, Info),
548
481
Labels = hipe_rtl_cfg:reverse_postorder(CFG),
549
482
update_cfg(Labels, CFG, PredMap, NewInfo).
551
484
update_cfg([Label|Labels], CFG, PredMap, Info) ->
552
Pred=hipe_rtl_cfg:pred(PredMap,Label),
553
InfoIn= join_load(Pred, Info),
485
Pred = hipe_rtl_cfg:pred(PredMap,Label),
486
InfoIn = join_load(Pred, Info),
554
487
CurrentBB = hipe_rtl_cfg:bb(CFG, Label),
555
488
OldCode = hipe_bb:code(CurrentBB),
556
489
case spread_info(OldCode, InfoIn) of
558
491
update_cfg(Labels, CFG, PredMap, Info);
560
NewBB=hipe_bb:code_update(CurrentBB, NewCode),
561
NewCFG=hipe_rtl_cfg:bb_update(CFG, Label, NewBB),
562
NewPredMap=hipe_rtl_cfg:pred_map(NewCFG),
493
NewBB = hipe_bb:code_update(CurrentBB, NewCode),
494
NewCFG = hipe_rtl_cfg:bb_add(CFG, Label, NewBB),
495
NewPredMap = hipe_rtl_cfg:pred_map(NewCFG),
563
496
update_cfg(Labels, NewCFG, NewPredMap, Info)
565
498
update_cfg([], CFG, _PredMap, _Info) ->
568
501
fix_remove([Label|Labels], CFG, PredMap, SuccMap, Info) ->
569
Pred=hipe_rtl_cfg:pred(PredMap,Label),
570
InfoIn= join_load(Pred, Info),
502
Pred = hipe_rtl_cfg:pred(PredMap,Label),
503
InfoIn = join_load(Pred, Info),
572
505
case gb_trees:lookup(Label, Info) of
592
524
lists:foldl(fun do_instr/2, {[],Info}, Code).
594
526
do_instr(Instr, {Acc,Info}) ->
595
case hipe_rtl:type(Instr) of
597
{Acc++[Instr],new_load_env()};
599
{Acc++[Instr],new_load_env()};
529
{Acc++[Instr], new_load_env()};
531
{Acc++[Instr], new_load_env()};
601
533
Dst = hipe_rtl:load_dst(Instr),
602
534
LoadType = {Dst, hipe_rtl:load_src(Instr), hipe_rtl:load_offset(Instr),
603
535
hipe_rtl:load_size(Instr), hipe_rtl:load_sign(Instr)},
605
537
case get_aliased_var(LoadType, Info) of
538
#aliased_var{name=Var} ->
607
539
hipe_rtl:mk_move(Dst, Var);
611
Defs=hipe_rtl:defines(Instr),
543
Defs = hipe_rtl:defines(Instr),
612
544
CleanInfo = remove_loads(Defs, Info),
613
{Acc++[NewInstr],gb_sets:add(LoadType, CleanInfo)};
545
{Acc++[NewInstr], gb_sets:add(LoadType, CleanInfo)};
615
Defs=hipe_rtl:defines(Instr),
616
{Acc++[Instr],remove_loads(Defs, Info)}
547
Defs = hipe_rtl:defines(Instr),
548
{Acc++[Instr], remove_loads(Defs, Info)}
619
551
remove_loads([Def|Defs], Info) ->
620
NewInfo=gb_sets:filter(fun(X) -> not_part(X, Def) end, Info),
552
NewInfo = gb_sets:filter(fun(X) -> not_part(X, Def) end, Info),
621
553
remove_loads(Defs, NewInfo);
622
554
remove_loads([], Info) ->
557
remove_stores(CFG) ->
558
Labels = hipe_rtl_cfg:labels(CFG),
559
remove_stores(Labels, CFG).
561
remove_stores([Label|Labels], CFG) ->
562
BB = hipe_rtl_cfg:bb(CFG, Label),
563
OldCode = hipe_bb:code(BB),
564
case remove_store_from_bb(OldCode) of
566
remove_stores(Labels, CFG);
568
NewBB = hipe_bb:code_update(BB, NewCode),
569
NewCFG = hipe_rtl_cfg:bb_add(CFG, Label, NewBB),
570
remove_stores(Labels, NewCFG)
572
remove_stores([], CFG) ->
575
remove_store_from_bb(Code) ->
576
remove_store_from_bb(lists:reverse(Code), new_load_env(), []).
578
remove_store_from_bb([Instr|Instrs], Env, Acc) ->
582
{[Instr|Acc],new_load_env()};
584
Base = hipe_rtl:store_base(Instr),
585
Offset = hipe_rtl:store_offset(Instr),
586
Size = hipe_rtl:store_size(Instr),
587
StoreType = {Base, Offset, Size},
588
case store_already_done(StoreType, Env) of
592
{[Instr|Acc], gb_sets:add(StoreType, Env)}
595
{[Instr|Acc],new_load_env()};
597
Defs = hipe_rtl:defines(Instr),
598
{[Instr|Acc], update_store_env(Defs, Env)}
600
remove_store_from_bb(Instrs, NewEnv, NewAcc);
601
remove_store_from_bb([], _Env, Acc) ->
604
update_store_env([Def|Defs], Env) ->
605
NewEnv = gb_sets:filter(fun(X) -> not_part_of_store(X, Def) end, Env),
606
update_store_env(Defs, NewEnv);
607
update_store_env([], Env) ->
610
store_already_done(StoreType, Env) ->
611
Iterator = gb_sets:iterator(Env),
612
check_store(StoreType, Iterator).
614
check_store(StoreType, Iterator) ->
615
case gb_sets:next(Iterator) of
621
check_store(StoreType, Next)
624
not_part_of_store({Def,_,_}, Def) -> false;
625
not_part_of_store({_,Def,_}, Def) -> false;
626
not_part_of_store(_, _Def) -> true.
625
628
not_part({Def,_,_,_,_}, Def) ->
627
630
not_part({_,Def,_,_,_}, Def) ->