1
%% -*- erlang-indent-level: 2 -*-
2
%% ====================================================================
3
%% Filename : hipe_sparc_opt_frame.erl
4
%% Module : hipe_sparc_opt_frame
5
%% Purpose : To minimize loads and stores to stack frames by
6
%% propagating information about what is stored on the
7
%% stack and in registers.
8
%% This is done in two steps:
9
%% 1. Forward copy propagation:
10
%% Information about copies of registers in other regs
11
%% and on the stack is propagated through the CFG.
12
%% If a store to a stack slot is redundant
13
%% (i.e the value to store is already in that slot)
14
%% the store is removed.
15
%% 2. Backward dead code elimination.
16
%% Liveness information is propagated backward through
17
%% each basic block. If a load (or a move) to a dead
18
%% temporary is encountered, the instruction is deleted.
20
%% Notes : This propagation is designed to go after the regalloc
21
%% phase but before the code has been rewritten to use
22
%% physical registers. This means that the propagation
23
%% has to be a bit conservative in order to not extend
24
%% live ranges of temporaries, causing conflict in register
26
%% History : * 2001-12-04 Erik Johansson (happi@csd.uu.se):
30
%% $Date: 2007/12/18 09:18:22 $
32
%% ====================================================================
33
%% Exports : cfg/1 - Takes a SPARC CFG and rewrites it.
35
%% TODO : More efficent data structure.
36
%% Turn on the fixpoint iteration.
37
%% Extend to handle alu instructions better...
38
%% Turn commented print_code into ifdef debug.
40
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
42
-module(hipe_sparc_opt_frame).
45
-include("../main/hipe.hrl").
46
-include("hipe_sparc.hrl").
48
-import(hipe_sparc_prop_env,
49
[end_of_bb/1, find_hpos/2, find_spos/2,
50
kill/2, kill_all/2, kill_hp/1, kill_phys_regs/1, kill_sp/1,
51
kill_uses/2, lookup/2, new_genv/1, set_active_block/2, succ/1,
52
zap_heap/1, zap_stack/1, bind_spos/3]).
54
%% ____________________________________________________________________
57
%% hipe_sparc_cfg:pp(CFG),
58
Lbls = [hipe_sparc_cfg:start_label(CFG)],
60
%% Forward prop to get rid of stores.
61
{CFG0,_GEnv0} = prop_bbs(Lbls, CFG, new_genv(CFG),[]),
62
%% hipe_sparc_cfg:pp(CFG0),
63
CFG1 = CFG0, %% prop(Lbls, CFG0, GEnv0,100),
65
%% Backward prop to get rid of loads.
66
CFG2 = remove_dead(CFG1),
69
%% ____________________________________________________________________
72
Liveness = hipe_sparc_liveness:analyze(CFG),
73
Lbls = hipe_sparc_cfg:labels(CFG),
74
bwd_prop(Lbls, CFG, Liveness).
76
bwd_prop([L|Lbls], CFG, Liveness) ->
77
BB = hipe_sparc_cfg:bb(CFG, L),
78
LiveOut = hipe_sparc_liveness:liveout(Liveness, L),
79
{NewCode,_} = bwd_prop_bb(hipe_bb:code(BB),LiveOut),
80
NewBB = hipe_bb:code_update(BB, NewCode),
81
NewCFG = hipe_sparc_cfg:bb_add(CFG, L, NewBB),
82
bwd_prop(Lbls, NewCFG, Liveness);
86
bwd_prop_bb([I|Is], LiveOut) ->
87
{NewIs, NewLiveOut} = bwd_prop_bb(Is,LiveOut),
88
{NewI,Out} = bwd_prop_i(I,NewLiveOut),
90
bwd_prop_bb([], LiveOut) -> {[], LiveOut}.
93
Uses = ordsets:from_list(hipe_sparc:uses(I)),
99
|| X <- hipe_sparc_registers:allocatable()];
100
_ -> hipe_sparc:defines(I)
103
case ordsets:intersection(Defines,Live) of
105
%% Nothing defined is live -- potentialy dead
108
{hipe_sparc:comment_create({"Removed instr",I}),
112
ordsets:union(ordsets:subtract(Live,Defines),Uses)}
114
_ -> %% The result is needed.
115
{I,ordsets:union(ordsets:subtract(Live,Defines),Uses)}
119
%% TODO: Expand this function.
122
%% io:format("hipe_sparc_opt_frame:can_kill/1 -> pseudo_unspill"),
123
Dst = hipe_sparc:pseudo_unspill_reg(I),
124
case hipe_sparc:is_reg(Dst) of
126
case hipe_sparc_registers:is_precoloured(hipe_sparc:reg_nr(Dst)) of
130
false -> %% is fp_reg
134
%% hipe_sparc:pp_instr(I),
135
%% io:format("hipe_sparc_opt_frame:can_kill/1 -> move"),
136
Dest = hipe_sparc:move_dest(I),
137
case hipe_sparc:is_reg(Dest) of
139
case hipe_sparc_registers:is_precoloured(hipe_sparc:reg_nr(Dest)) of
150
%% ____________________________________________________________________
152
%% Fixpoint iteration.
153
% prop(_Start,CFG,_Env,0) ->
154
% %% io:format("Limit hit\n"),
156
% prop(Start,CFG,Env,N) ->
157
% case hipe_sparc_prop_env:genv__changed(Env) of
159
% {CFG0,GEnv0} = prop_bbs(Start, CFG, hipe_sparc_prop_env:genv__changed_clear(Env), []),
160
% prop(Start,CFG0, GEnv0, N-1);
166
%% ____________________________________________________________________
169
%% Iterate over the basic blocks of a cfg.
171
prop_bbs([], CFG, GEnv,_) ->
173
prop_bbs([BB|BBs], CFG, GEnv,Vis) ->
174
{Succs, CFG0,GEnv0, NewVis} = prop_bb(BB, GEnv, CFG,Vis),
175
prop_bbs(BBs++Succs, CFG0, GEnv0, NewVis).
179
%% If Lbl is a member of the extended block Ebb. Then propagate info
180
%% and continue with its successors.
183
prop_bb(Lbl, GEnv, CFG, Vis) ->
184
case lists:member(Lbl, Vis) of
185
true -> {[],CFG, GEnv, Vis};
187
BB = hipe_sparc_cfg:bb(CFG, Lbl),
188
%% io:format("\n~w:\n========\n~p\n",[Lbl,hipe_sparc_prop_env:genv__env(set_active_block(Lbl,GEnv))]),
189
{NewCode, NewGEnv} = prop_instrs(hipe_bb:code(BB),
190
set_active_block(Lbl,GEnv)),
191
NewBB = hipe_bb:code_update(BB, NewCode),
192
NewCFG = hipe_sparc_cfg:bb_add(CFG, Lbl, NewBB),
193
Succ = succ(NewGEnv),
194
%% io:format("Succs: ~w\n",[Succ]),
195
{Succ, NewCFG, NewGEnv,[Lbl|Vis]}
199
%% prop_succ([], GEnv, CFG, Vis) ->
201
%% prop_succ([BB|BBs], GEnv, CFG, Vis) ->
202
%% {NewCFG,NewGEnv, NewVis} = prop_bb(BB, GEnv, CFG, Vis),
203
%% prop_succ(BBs, NewGEnv, NewCFG, NewVis).
206
prop_instrs([], GEnv) ->
207
{[], end_of_bb(GEnv)};
208
prop_instrs([I|Is], GEnv) ->
209
{NewI, Env0} = prop_instr(I, GEnv),
211
%% io:format("REWRITE\n"),
212
%% hipe_sparc_pp:pp_instr(NewI),
216
GEnv0 = hipe_sparc_prop_env:genv__env_update(Env0,GEnv),
217
{NewIs, NewEnv} = prop_instrs(Is, GEnv0),
218
{[NewI|NewIs], NewEnv}.
222
%% Propagate copies and constants for one instruction.
225
prop_instr(I, Env) ->
227
%% hipe_sparc_pp:pp_instr(I),
230
Srcs = [hipe_sparc:move_src(I)],
231
Dsts = [hipe_sparc:move_dest(I)],
232
{_I0,Env0} = bind_all(Srcs, Dsts, I, hipe_sparc_prop_env:genv__env(Env)),
233
{I, kill_uses(hipe_sparc:defines(I), Env0)};
235
NewEnv = kill_all(hipe_sparc:defines(I), hipe_sparc_prop_env:genv__env(Env)),
236
Srcs = hipe_sparc:multimove_src(I),
237
Dsts = hipe_sparc:multimove_dest(I),
238
{_I0,Env0} = bind_all(Srcs, Dsts, I, NewEnv),
241
eval(I, hipe_sparc_prop_env:genv__env(Env))
245
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
247
%% Evaluate an instruction. Returns {NewI, NewEnv}.
252
#store{} -> prop_store(I,Env);
253
#load{} -> prop_load(I,Env);
254
#pseudo_spill{} -> prop_spill(I,Env);
255
#pseudo_unspill{} -> prop_unspill(I,Env);
256
%% #cmov_cc{} -> prop_cmov_cc(I,Env);
257
%% #cmov_r{} -> prop_cmov_r(I,Env);
258
#alu{} -> prop_alu(I,Env);
259
%% #alu_cc{} -> prop_alu_cc(I,Env);
260
%% #sethi{} -> prop_sethi(I,Env);
262
%% #load_atom{} -> prop_load_atom(I,Env);
263
%% #load_word_index{} -> prop_word_index(I,Env);
264
%% #load_address{} -> prop_load_address(I,Env);
266
%% #b{} -> prop_b(I,Env);
267
%% #br{} -> prop_br(I,Env);
268
%% #goto{} -> prop_got(I,Env);
269
%% #jmp{} -> prop_jmp(I,Env);
271
#call_link{} -> prop_call_link(I,Env);
275
#comment{} -> {I,Env};
278
NewEnv = kill_all(hipe_sparc:defines(I), Env),
282
%% ____________________________________________________________________
285
Base = hipe_sparc:store_dest(I),
286
Offset = hipe_sparc:store_off(I),
287
Src = hipe_sparc:store_src(I),
288
SP = hipe_sparc:mk_reg(hipe_sparc_registers:stack_pointer()),
289
HP = hipe_sparc:mk_reg(hipe_sparc_registers:heap_pointer()),
292
prop_stack_store(I,Env,Offset,Src);
294
prop_heap_store(I,Env,Offset,Src);
296
?EXIT({dont_use_sp_as_offset,I});
298
?EXIT({dont_use_hp_as_offset,I});
300
%% A store off stack and heap (Probably PCB).
301
%% We assume there is no interference here!!!
306
Pos = hipe_sparc:imm_value(hipe_sparc:pseudo_spill_pos(I)) bsl ?log2_wordsize,
307
Src = hipe_sparc:pseudo_spill_reg(I),
308
case find_spos(Pos, Env) of
311
NewI = hipe_sparc:comment_create({"Removed spill",I}),
315
NewEnv = bind_spos(Pos, Src, Env),
319
prop_unspill(I,Env) ->
320
Pos = hipe_sparc:imm_value(hipe_sparc:pseudo_unspill_pos(I)) bsl ?log2_wordsize,
321
Dest = hipe_sparc:pseudo_unspill_reg(I),
322
case find_spos(Pos, Env) of
326
bind_all([Val],[Dest],I,Env)
329
prop_stack_store(I,Env,Offset,Src) ->
330
case hipe_sparc_prop_env:env__sp(Env) of
332
%% We are updating via unknown SP.
335
case hipe_sparc:is_imm(Offset) of
337
%% We are updating the stack via a reg...
338
%% TODO: Check wehter the the reg is bound to a const...
339
%% We have to zap the stack...
342
Pos = hipe_sparc:imm_value(Offset) + SOff,
343
NewEnv = bind_spos(Pos, Src, Env),
344
%% TODO: Indicate that Src is copied on stack.
349
prop_heap_store(I,Env,Offset,Src) ->
350
case hipe_sparc_prop_env:env__hp(Env) of
352
%% We are updating via unknown HP.
355
case hipe_sparc:is_imm(Offset) of
357
%% We are updating the heap via a reg...
358
%% TODO: Check wehter the the reg is bound to a const...
359
%% We have to zap the heap...
362
Pos = hipe_sparc:imm_value(Offset) + HOff,
363
NewEnv = hipe_sparc_prop_env:bind_hpos(Pos, Src, Env),
364
%% TODO: Indicate that Src is copied on heap.
370
Base = hipe_sparc:load_src(I),
371
Offset = hipe_sparc:load_off(I),
372
Dest = hipe_sparc:load_dest(I),
373
SP = hipe_sparc:mk_reg(hipe_sparc_registers:stack_pointer()),
374
HP = hipe_sparc:mk_reg(hipe_sparc_registers:heap_pointer()),
377
prop_stack_load(I,Env,Offset,Dest);
379
prop_heap_load(I,Env,Offset,Dest);
381
?EXIT({dont_use_sp_as_offset,I});
383
?EXIT({dont_use_hp_as_offset,I});
385
%% A load off stack and heap (Probably PCB).
386
%% We assume there is no interference here!!!
387
NewEnv = kill(Dest,Env),
391
prop_stack_load(I,Env,Offset,Dest) ->
392
case hipe_sparc_prop_env:env__sp(Env) of
396
case hipe_sparc:is_imm(Offset) of
398
%% We are reading the stack via a reg...
399
%% TODO: Check wehter the the reg is bound to a const...
402
Pos = hipe_sparc:imm_value(Offset) + SOff,
404
case find_spos(Pos, Env) of
408
case lookup(Dest, Env) of
409
Val -> {hipe_sparc:comment_create("Removed load"),
412
bind_all([Val],[Dest],I,kill_uses([Dest],Env))
418
prop_heap_load(I,Env,Offset,Dest) ->
419
case hipe_sparc_prop_env:env__hp(Env) of
423
case hipe_sparc:is_imm(Offset) of
425
%% We are reading the heap via a reg...
426
%% TODO: Check wehter the the reg is bound to a const...
429
Pos = hipe_sparc:imm_value(Offset) + HOff,
431
case find_hpos(Pos, Env) of
435
bind_all([Val],[Dest],I,kill_uses([Dest],Env))
440
%% ____________________________________________________________________
443
OP = hipe_sparc:alu_operator(I),
444
Src1 = hipe_sparc:alu_src1(I),
445
Src2 = hipe_sparc:alu_src2(I),
446
Dest = hipe_sparc:alu_dest(I),
447
SP = hipe_sparc:mk_reg(hipe_sparc_registers:stack_pointer()),
448
HP = hipe_sparc:mk_reg(hipe_sparc_registers:heap_pointer()),
453
prop_sp_op(I,Env,OP,Src2);
455
%% TODO: handle SP = x op SP
456
%% unknown update of SP.
457
{I,kill_sp(zap_stack(Env))}
462
prop_hp_op(I,Env,OP,Src2);
464
%% TODO: handle HP = x op HP
465
%% unknown update of HP.
466
{I,kill_hp(zap_heap(Env))}
469
%% TODO: Fold consts ...
473
prop_sp_op(I,Env,'+',Src) ->
474
case hipe_sparc:is_imm(Src) of
476
{I, hipe_sparc_prop_env:inc_sp(Env,hipe_sparc:imm_value(Src))};
478
{I, kill_sp(zap_stack(Env))}
480
prop_sp_op(I,Env,'-',Src) ->
481
case hipe_sparc:is_imm(Src) of
483
{I, hipe_sparc_prop_env:inc_sp(Env, - hipe_sparc:imm_value(Src))};
485
{I, kill_sp(zap_stack(Env))}
487
prop_sp_op(I,Env,_Op,_Src) ->
488
%% Dont know how to handle other ops...
489
{I,kill_sp(zap_stack(Env))}.
491
prop_hp_op(I,Env,'+',Src) ->
492
case hipe_sparc:is_imm(Src) of
494
{I, hipe_sparc_prop_env:inc_hp(Env,hipe_sparc:imm_value(Src))};
496
{I, kill_sp(zap_stack(Env))}
498
prop_hp_op(I,Env,'-',Src) ->
499
case hipe_sparc:is_imm(Src) of
501
{I, hipe_sparc_prop_env:inc_hp(Env, - hipe_sparc:imm_value(Src))};
503
{I, kill_sp(zap_stack(Env))}
505
prop_hp_op(I,Env,_Op,_Src) ->
506
%% Dont know how to handle other ops...
507
{I,kill_hp(zap_heap(Env))}.
509
%% ____________________________________________________________________
511
prop_call_link(I,Env) ->
512
Dests = hipe_sparc:call_link_dests(I),
513
Env1 = kill_uses(Dests,kill_phys_regs(Env)),
514
NoArgs = length(hipe_sparc:call_link_args(I)),
515
ArgsInRegs = hipe_sparc_registers:register_args(),
516
case NoArgs > ArgsInRegs of
518
StackAdjust = NoArgs - ArgsInRegs,
519
Env2 = hipe_sparc_prop_env:inc_sp(Env1, - (StackAdjust bsl ?log2_wordsize)),
525
%% ____________________________________________________________________
528
bind_all(Srcs, Dsts, I, Env) ->
529
bind_all(Srcs, Dsts, I, Env, Env).
532
%% We have two envs, Env where we do lookups and
533
%% NewEnv where the new bindings are entered.
534
bind_all([Src|Srcs], [Dst|Dsts], I, Env, NewEnv) ->
535
case hipe_sparc:is_imm(Src) of
537
bind_all(Srcs, Dsts, I, Env,
538
hipe_sparc_prop_env:bind(NewEnv, Dst, Src));
539
false -> %% its a variable
540
SrcVal = lookup(Src, Env),
541
%% Uncomment this and only constants will be propagated
542
%% case hipe_rtl:is_imm(SrcVal) of
544
NewI = hipe_sparc:subst_uses(I,[{Src, SrcVal}]),
545
bind_all(Srcs, Dsts, NewI, Env,
546
hipe_sparc_prop_env:bind(NewEnv, Dst, SrcVal))
548
%% bind_all(Srcs, Dsts, I, Env, NewEnv)
551
bind_all([], [], I, _, Env) ->
554
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%