1
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
%% Copyright (c) 2001 by Erik Johansson. All Rights Reserved
3
%% -*- erlang-indent-level: 2 -*-
4
%% ====================================================================
5
%% Filename : hipe_sparc_prop.erl
6
%% Module : hipe_sparc_prop
9
%% History : * 2001-12-04 Erik Johansson (happi@csd.uu.se):
12
%% $Author: richardc $
13
%% $Date: 2002/10/01 12:47:16 $
15
%% ====================================================================
18
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
20
-module(hipe_sparc_pre_ra_prop).
22
-include("../main/hipe.hrl").
25
%% hipe_sparc_cfg:pp(CFG),
26
Lbls = [hipe_sparc_cfg:start(CFG)],
27
{CFG0,GEnv0} = prop_bbs(Lbls, CFG, new_genv(CFG),[]),
28
%% hipe_sparc_cfg:pp(CFG0),
29
CFG1 = prop(Lbls, CFG0, GEnv0,100),
30
CFG2 = remove_dead(CFG1),
34
Liveness = hipe_sparc_liveness:analyze(CFG),
35
Lbls = hipe_sparc_cfg:labels(CFG),
36
bwd_prop(Lbls, CFG, Liveness).
38
bwd_prop([L|Lbls], CFG, Liveness) ->
39
BB = hipe_sparc_cfg:bb(CFG, L),
40
LiveOut = hipe_sparc_liveness:liveout(Liveness, L),
41
{NewCode,_} = bwd_prop_bb(hipe_bb:code(BB),LiveOut),
42
NewBB = hipe_bb:code_update(BB, NewCode),
43
NewCFG = hipe_sparc_cfg:bb_update(CFG, L, NewBB),
44
bwd_prop(Lbls, NewCFG, Liveness);
48
bwd_prop_bb([I|Is], LiveOut) ->
49
{NewIs, NewLiveOut} = bwd_prop_bb(Is,LiveOut),
50
{NewI,Out} = bwd_prop_i(I,NewLiveOut),
52
bwd_prop_bb([], LiveOut) -> {[], LiveOut}.
55
Uses = ordsets:from_list(hipe_sparc:uses(I)),
58
case hipe_sparc:type(I) of
61
|| X <- hipe_sparc_registers:allocatable()];
62
_ -> hipe_sparc:defines(I)
65
case ordsets:union(Defines,Live) of
67
%% Nothing defined is live -- potentialy dead
70
{hipe_sparc:comment_create({"Removed instr",I},[I]),
74
ordsets:union(ordsets:subtract(Live,Defines),Uses)}
76
_ -> %% The result is needed.
77
{I,ordsets:union(ordsets:subtract(Live,Defines),Uses)}
81
%% TODO: Expand this function.
82
case hipe_sparc:type(I) of
84
Dest = hipe_sparc:reg_nr(hipe_sparc:pseudo_spill_reg(I)),
85
case hipe_sparc_registers:is_precolored(Dest) of
90
Dest = hipe_sparc:reg_nr(hipe_sparc:move_dest(I)),
91
case hipe_sparc_registers:is_precolored(Dest) of
101
prop(Start,CFG,Env,0) ->
102
io:format("Limit hit\n"),
104
prop(Start,CFG,Env,N) ->
107
{CFG0,GEnv0} = prop_bbs(Start, CFG, clear_changed(Env), []),
108
prop(Start,CFG0, GEnv0, N-1);
114
%% Iterate over the basic blocks of a cfg.
117
prop_bbs([], CFG, GEnv,_) ->
119
prop_bbs([BB|BBs], CFG, GEnv,Vis) ->
120
{Succs, CFG0,GEnv0, NewVis} = prop_bb(BB, GEnv, CFG,Vis),
121
prop_bbs(BBs++Succs, CFG0, GEnv0, NewVis).
126
%% If Lbl is a member of the extended block Ebb. Then propagate info
127
%% and continue with its successors.
130
prop_bb(Lbl, GEnv, CFG, Vis) ->
131
case lists:member(Lbl, Vis) of
132
true -> {[],CFG, GEnv, Vis};
134
BB = hipe_sparc_cfg:bb(CFG, Lbl),
135
%% io:format("\n~w:\n========\n~p\n",[Lbl,env(set_active_block(Lbl,GEnv))]),
136
{NewCode, NewGEnv} = prop_instrs(hipe_bb:code(BB),
137
set_active_block(Lbl,GEnv)),
138
NewBB = hipe_bb:code_update(BB, NewCode),
139
NewCFG = hipe_sparc_cfg:bb_update(CFG, Lbl, NewBB),
140
Succ = succ(NewGEnv),
141
%% io:format("Succs: ~w\n",[Succ]),
142
{Succ, NewCFG, NewGEnv,[Lbl|Vis]}
146
% prop_succ([], GEnv, CFG, Vis) ->
148
% prop_succ([BB|BBs], GEnv, CFG, Vis) ->
149
% {NewCFG,NewGEnv, NewVis} = prop_bb(BB, GEnv, CFG, Vis),
150
% prop_succ(BBs, NewGEnv, NewCFG, NewVis).
153
prop_instrs([], GEnv) ->
154
{[], end_of_bb(GEnv)};
155
prop_instrs([I|Is], GEnv) ->
156
{NewI, Env0} = prop_instr(I, GEnv),
158
%% io:format("REWRITE\n"),
159
%% hipe_sparc_pp:pp_instr(NewI),
163
GEnv0 = set_env(Env0,GEnv),
164
{NewIs, NewEnv} = prop_instrs(Is, GEnv0),
167
[_|_] -> {NewI++NewIs, NewEnv}; %% alub -> [move, goto]
168
_ -> {[NewI|NewIs], NewEnv}
173
%% Propagate copies and constants for one instruction.
176
prop_instr(I, Env) ->
178
%% hipe_sparc_pp:pp_instr(I),
181
case hipe_sparc:type(I) of
183
Srcs = [hipe_sparc:move_src(I)],
184
Dsts = [hipe_sparc:move_dest(I)],
185
{I0,Env0} = bind_all(Srcs, Dsts, I, env(Env)),
186
{I, kill_uses(hipe_sparc:defines(I0), Env0)};
188
NewEnv = unbind(hipe_sparc:defines(I), env(Env)),
189
Srcs = hipe_sparc:multimove_src(I),
190
Dsts = hipe_sparc:multimove_dest(I),
191
bind_all(Srcs, Dsts, I, NewEnv);
193
%% Uses = hipe_sparc:uses(I),
194
%% %% Map = [{U, lookup(U, Env)} || U <- Uses],
195
%% Map = map_all(Uses, env(Env)),
196
%% NewI = hipe_sparc:subst_uses(I,Map),
197
%% eval(NewI, env(Env))
202
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
204
%% Evaluate an instruction. Returns {NewI, NewEnv}.
208
case hipe_sparc:type(I) of
209
store -> prop_store(I,Env);
210
load -> prop_load(I,Env);
211
pseudo_spill -> prop_spill(I,Env);
212
pseudo_unspill -> prop_unspill(I,Env);
213
% cmov_cc -> prop_cmov_cc(I,Env);
214
% cmov_r -> prop_cmov_r(I,Env);
215
alu -> prop_alu(I,Env);
216
% alu_cc -> prop_alu_cc(I,Env);
217
% sethi -> prop_sethi(I,Env);
219
% load_atom -> prop_load_atom(I,Env);
220
% load_word_index -> prop_word_index(I,Env);
221
% load_address -> prop_load_address(I,Env);
224
% b -> prop_b(I,Env);
225
% br -> prop_br(I,Env);
226
% goto -> prop_got(I,Env);
227
% jmp -> prop_jmp(I,Env);
229
call_link -> prop_call_link(I,Env);
235
NewEnv = unbind(hipe_sparc:defines(I), Env),
243
Base = hipe_sparc:store_dest(I),
244
Offset = hipe_sparc:store_off(I),
245
Src = hipe_sparc:store_src(I),
246
SP = hipe_sparc:mk_reg(hipe_sparc_registers:stack_pointer()),
247
HP = hipe_sparc:mk_reg(hipe_sparc_registers:heap_pointer()),
250
prop_stack_store(I,Env,Offset,Src);
252
prop_heap_store(I,Env,Offset,Src);
254
?EXIT({dont_use_sp_as_offset,I});
256
?EXIT({dont_use_hp_as_offset,I});
258
%% A store off stack and heap (Probably PCB).
259
%% We assume there is no interference here!!!
264
Pos = hipe_sparc:imm_value(hipe_sparc:pseudo_spill_pos(I))*4,
265
Src = hipe_sparc:pseudo_spill_reg(I),
266
case find_spos(Pos, Env) of
269
NewI = hipe_sparc:comment_create({"Removed spill",I},[]),
273
NewEnv = bind_spos(Pos, Src, Env),
277
prop_unspill(I,Env) ->
278
Pos = hipe_sparc:imm_value(hipe_sparc:pseudo_unspill_pos(I))*4,
279
Dest = hipe_sparc:pseudo_unspill_reg(I),
280
case find_spos(Pos, Env) of
284
bind_all([Val],[Dest],I,Env)
290
prop_stack_store(I,Env,Offset,Src) ->
293
%% We are updating via unknown SP.
296
case hipe_sparc:is_imm(Offset) of
298
%% We are updating the stack via a reg...
299
%% TODO: Check wehter the the reg is bound to a const...
300
%% We have to zap the stack...
303
Pos = hipe_sparc:imm_value(Offset) + SOff,
304
NewEnv = bind_spos(Pos, Src, Env),
305
%% TODO: Indicate that Src is copied on stack.
310
prop_heap_store(I,Env,Offset,Src) ->
314
%% We are updating via unknown HP.
317
case hipe_sparc:is_imm(Offset) of
319
%% We are updating the heap via a reg...
320
%% TODO: Check wehter the the reg is bound to a const...
321
%% We have to zap the heap...
324
Pos = hipe_sparc:imm_value(Offset) + HOff,
325
NewEnv = bind_hpos(Pos, Src, Env),
326
%% TODO: Indicate that Src is copied on heap.
332
Base = hipe_sparc:load_src(I),
333
Offset = hipe_sparc:load_off(I),
334
Dest = hipe_sparc:load_dest(I),
335
SP = hipe_sparc:mk_reg(hipe_sparc_registers:stack_pointer()),
336
HP = hipe_sparc:mk_reg(hipe_sparc_registers:heap_pointer()),
339
prop_stack_load(I,Env,Offset,Dest);
341
prop_heap_load(I,Env,Offset,Dest);
343
?EXIT({dont_use_sp_as_offset,I});
345
?EXIT({dont_use_hp_as_offset,I});
347
%% A load off stack and heap (Probably PCB).
348
%% We assume there is no interference here!!!
349
NewEnv = kill(Dest,Env),
353
prop_stack_load(I,Env,Offset,Dest) ->
358
case hipe_sparc:is_imm(Offset) of
360
%% We are reading the stack via a reg...
361
%% TODO: Check wehter the the reg is bound to a const...
364
Pos = hipe_sparc:imm_value(Offset) + SOff,
366
case find_spos(Pos, Env) of
370
bind_all([Val],[Dest],I,kill_uses([Dest],Env))
375
prop_heap_load(I,Env,Offset,Dest) ->
380
case hipe_sparc:is_imm(Offset) of
382
%% We are reading the heap via a reg...
383
%% TODO: Check wehter the the reg is bound to a const...
386
Pos = hipe_sparc:imm_value(Offset) + HOff,
388
case find_hpos(Pos, Env) of
392
bind_all([Val],[Dest],I,kill_uses([Dest],Env))
398
%% ____________________________________________________________________
401
OP = hipe_sparc:alu_operator(I),
402
Src1 = hipe_sparc:alu_src1(I),
403
Src2 = hipe_sparc:alu_src2(I),
404
Dest = hipe_sparc:alu_dest(I),
405
SP = hipe_sparc:mk_reg(hipe_sparc_registers:stack_pointer()),
406
HP = hipe_sparc:mk_reg(hipe_sparc_registers:heap_pointer()),
411
prop_sp_op(I,Env,OP,Src2);
413
%% TODO: handle SP = x op SP
414
%% unknown update of SP.
415
{I,kill_sp(zap_stack(Env))}
420
prop_hp_op(I,Env,OP,Src2);
422
%% TODO: handle HP = x op HP
423
%% unknown update of HP.
424
{I,kill_hp(zap_heap(Env))}
427
%% TODO: Fold consts ...
431
prop_sp_op(I,Env,'+',Src) ->
432
case hipe_sparc:is_imm(Src) of
434
{I, inc_sp(Env,hipe_sparc:imm_value(Src))};
436
{I,kill_sp(zap_stack(Env))}
438
prop_sp_op(I,Env,'-',Src) ->
439
case hipe_sparc:is_imm(Src) of
441
{I, inc_sp(Env, - hipe_sparc:imm_value(Src))};
443
{I,kill_sp(zap_stack(Env))}
445
prop_sp_op(I,Env,Op,Src) ->
446
%% Dont know how to handle other ops...
447
{I,kill_sp(zap_stack(Env))}.
449
prop_hp_op(I,Env,'+',Src) ->
450
case hipe_sparc:is_imm(Src) of
452
{I,inc_hp(Env,hipe_sparc:imm_value(Src))};
454
{I,kill_sp(zap_stack(Env))}
456
prop_hp_op(I,Env,'-',Src) ->
457
case hipe_sparc:is_imm(Src) of
459
{I, inc_hp(Env, - hipe_sparc:imm_value(Src))};
461
{I,kill_sp(zap_stack(Env))}
463
prop_hp_op(I,Env,Op,Src) ->
464
%% Dont know how to handle other ops...
465
{I,kill_hp(zap_heap(Env))}.
467
%% ____________________________________________________________________
469
prop_call_link(I,Env) ->
470
Dests = hipe_sparc:call_link_dests(I),
471
Env1 = kill_uses(Dests,kill_phys_regs(Env)),
475
%% ____________________________________________________________________
477
% map_all([], Env) ->
479
% map_all([V|Vs], Env) ->
480
% [{V, lookup(V, Env)} | map_all(Vs, Env)].
483
bind_all(Srcs, Dsts, I, Env) ->
484
bind_all(Srcs, Dsts, I, Env, Env).
487
%% We have two envs, Env where we do lookups and
488
%% NewEnv where the new bindings are entered.
489
bind_all([Src|Srcs], [Dst|Dsts], I, Env, NewEnv) ->
490
case hipe_sparc:is_imm(Src) of
492
bind_all(Srcs, Dsts, I, Env, bind(NewEnv, Dst, Src));
493
false -> %% its a variable
494
SrcVal = lookup(Src, Env),
495
%% Uncomment this and only constants will be propagated
496
%% case hipe_rtl:is_imm(SrcVal) of
498
NewI = hipe_sparc:subst_uses(I,[{Src, SrcVal}]),
499
bind_all(Srcs, Dsts, NewI, Env, bind(NewEnv, Dst, SrcVal))
501
%% bind_all(Srcs, Dsts, I, Env, NewEnv)
504
bind_all([], [], I, _, Env) ->
506
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
509
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
510
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
512
%% the environment, Rewrite if we go global.
513
%% {Regs,SP,HP, Stack, Heap}
514
-record(genv,{block,cfg,succ_map,pred_map,env,envs,changed}).
517
succ_map=hipe_sparc_cfg:succ_map(CFG),
518
pred_map=hipe_sparc_cfg:pred_map(CFG),
528
case plookup(L, GEnv#genv.envs) of
529
undefined ->new_env();
534
hipe_sparc_cfg:pred(GEnv#genv.pred_map,L).
537
hipe_sparc_cfg:succ(GEnv#genv.succ_map, GEnv#genv.block).
542
Envs = GEnv#genv.envs,
543
case plookup(L,Envs) of
546
GEnv#genv{envs=[{L,Env}|Envs], changed=true}
552
clear_changed(GEnv) ->
553
GEnv#genv{changed=false}.
556
set_active_block(L, GEnv) ->
557
case preds(L,GEnv) of
559
GEnv#genv{block=L, env=env(Pred,GEnv)};
561
case plookup(Pred, GEnv#genv.envs) of
562
undefined -> GEnv#genv{block=L, env=new_env()};
564
%% io:format("Joining: L:~w\n",[Pred]),
566
Env = join(Preds,E, GEnv),
567
GEnv#genv{block=L, env=Env}
570
GEnv#genv{block=L, env=new_env()}
573
join([L|Ls], Env, GEnv) ->
574
%% io:format("Joining: L:~w\n",[L]),
575
case plookup(L, GEnv#genv.envs) of
576
undefined -> new_env();
579
join(Ls,merge(E,Env), GEnv)
582
%% io:format("Join:\n"),
586
%% ____________________________________________________________________
588
-record(env,{regs=[],sp=0,hp=0,stack=[],heap=[]}).
590
regs(Env)-> Env#env.regs.
591
sp(Env)-> Env#env.sp.
592
hp(Env)-> Env#env.hp.
593
stack(Env)-> Env#env.stack.
594
heap(Env)-> Env#env.heap.
597
Env0 = #env{regs=m(regs(E1),regs(E2))},
599
case sp(E1) =:= sp(E2) of
601
Stack = m(stack(E1),stack(E2)),
602
Env0#env{sp=sp(E1),stack= Stack};
606
case hp(E1) =:= hp(E2) of
608
Heap = m(heap(E1),heap(E2)),
609
Env1#env{hp=hp(E1),heap=Heap};
615
[{X,Y} || {X,Y} <- R1, {value, {X,Y}} =:= lists:keysearch(X, 1, R2)].
624
pp_mem(sp(Env),stack(Env),"STACK"),
625
pp_mem(hp(Env),heap(Env)," HEAP").
627
pp_regs([{X,Y}|Regs]) ->
628
case hipe_sparc:is_reg(X) of
630
?EXIT({bad_reg_in_environment,{X,Y}});
632
hipe_sparc_pp:pp_arg(standard_io,X),
634
hipe_sparc_pp:pp_arg(standard_io,Y),
640
pp_mem(unknown,_,_) ->
644
pp_mem(Pointer,Mem,What) ->
645
io:format("~s:\n",[What]),
646
case lists:sort(Mem) of
649
pp_slots(min(element(1,First),Pointer),Pointer,Slots,What),
650
io:format(" |-----|\n")
653
min(X,Y) when X =< Y ->
659
pp_slots(Cur, Pointer, Slots = [{Next,V}|Rest], What) ->
660
if Cur =:= Pointer ->
661
io:format("~s_P -> ",[What]);
665
io:format("~3w | ",[Cur]),
667
hipe_sparc_pp:pp_arg(standard_io, V),
669
pp_slots(Cur+4, Pointer, Rest, What);
672
pp_slots(Cur+4, Pointer, Slots, What)
674
pp_slots(Cur,Pointer,[],What) ->
676
pp_empty_slots(Cur,Pointer,What);
681
pp_empty_slots(Cur,Pointer,What) ->
682
if Cur =:= Pointer ->
683
io:format("~s_P -> ~3w | |\n",[What,Cur]);
687
io:format(" ~3w | |\n",[Cur]),
688
pp_empty_slots(Cur+4,Pointer,What)
693
zap_stack(Env)-> Env#env{stack=[]}.
694
zap_heap(Env)-> Env#env{heap=[]}.
695
kill_sp(Env)->Env#env{sp=unknown}.
696
kill_hp(Env)->Env#env{hp=unknown}.
697
kill_phys_regs(Env)->
698
Env0 = Env#env{regs=[{X,Y}||{X,Y} <- regs(Env),
699
not_physical(X), not_physical(Y)]},
700
Env1 = Env0#env{stack=[{X,Y}||{X,Y} <- stack(Env0),
702
Env2 = Env1#env{heap=[{X,Y}||{X,Y} <- heap(Env1),
707
case hipe_sparc:is_reg(R) of
710
not hipe_sparc_registers:is_precolored(hipe_sparc:reg_nr(R))
718
Env#env{sp=PrevVal+Val}
725
Env#env{hp=PrevVal+Val}
729
%% Bind a value/reg to a stack position
730
bind_spos(Pos, Val, Env) ->
731
Env#env{stack=[{Pos,Val}| lists:keydelete(Pos,1,Env#env.stack)]}.
733
%% Bind a value/reg to a heap position
734
bind_hpos(Pos, Val, Env) ->
735
Env#env{heap=[{Pos,Val}| lists:keydelete(Pos,1,Env#env.heap)]}.
737
%% Find a value on a stackpos
738
find_spos(Pos, Env) ->
739
plookup(Pos,Env#env.stack).
741
%% Find a value on a heappos
742
find_hpos(Pos, Env) ->
743
plookup(Pos,Env#env.heap).
746
%% Find what memory pos P is bound to.
747
%% As a last resort undefined is returned.
751
plookup(P, [{P, Y}|_]) ->
753
plookup(P, [_|Map]) ->
757
%% Bind reg X to Y in Map
762
Map#env{regs=[{X, Y} | lists:keydelete(X,1,Regs)]}.
765
%% Find what X is bound to (as a last restort varaibles are bound
770
mlookup(X,regs(Env)).
774
mlookup(X, [{X, Y}|_]) ->
776
mlookup(X, [_|Map]) ->
780
%% Kill bindings with references to register X
783
Env1 = Env0#env{regs=mkill(X,regs(Env0))},
784
Env2 = Env1#env{stack=mkill(X,stack(Env1))},
785
Env3 = Env2#env{heap=mkill(X,heap(Env2))}.
789
mkill(X, [{X,_}|Xs]) ->
791
mkill(X, [{_,X}|Xs]) ->
797
Env#env{regs=munbind(X,regs(Env))}.
801
munbind([V|Vs], Map) ->
802
munbind(Vs, mkill(V, Map)).
807
kill_use(X, [{_,X}|Xs]) ->
809
kill_use(X, [D|Xs]) ->
810
[D | kill_use(X,Xs)].
812
kill_uses([X|Xs],Env0) ->
813
Env1 = Env0#env{regs=kill_use(X,regs(Env0))},
814
Env2 = Env1#env{stack=kill_use(X,stack(Env1))},
815
Env3 = Env2#env{heap=kill_use(X,heap(Env2))},
817
kill_uses([], Env) -> Env.