1
%% -*- erlang-indent-level: 2 -*-
2
%% ====================================================================
3
%% Filename : hipe_sparc_frame.erl
4
%% Module : hipe_sparc_frame
7
%% The code may only have spilled registers in
8
%% the pseudo instructions:
10
%% pseudo_spill t1, t2 ; spills t1 to spillpos of t2
11
%% pseudo_unspill t1, t2 ; loads t1 from spillpos of t2
13
%% The TempMap must contain mappings from all used temps
14
%% to physical registers or spill positions.
16
%% XXX: New immediates are introduced as stack offsets.
17
%% If more than 1024 stack slots are needed,
18
%% the immediate offsets will be to big for a
20
%% This can happen with the naive allocator.
21
%% A special pass called from hipe_main
22
%% rectifies this situation.
24
%% History : * 2001-10-25 Erik Johansson (happi@csd.uu.se):
28
%% $Date: 2007/12/18 09:18:21 $
30
%% ====================================================================
35
%% Handle multiple return values
38
%% hipe:c({len,len,2},[pp_rtl,{regalloc,naive}]).
39
%% hipe:c({len,len,2},[pp_sparc,{regalloc,lfls}]).
40
%% hipe:c({late,t,0},[pp_sparc,{regalloc,lfls}]).
41
%% hipe:c({late,seven,7},[pp_sparc,{regalloc,lfls}]).
42
%% hipe:c({late,test_enter,7},[pp_sparc,{regalloc,lfls}]).
43
%% hipe:c({trivial_19,test,0},[pp_sparc,{regalloc,lfls}]).
46
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
48
-module(hipe_sparc_frame).
51
%% -define(DO_ASSERT,true).
52
-include("../main/hipe.hrl").
53
-include("hipe_sparc.hrl").
54
-include("../rtl/hipe_literals.hrl").
56
-define(MK_CP_REG(),(hipe_sparc:mk_reg(hipe_sparc_registers:return_address()))).
57
-define(MK_SP_REG(),(hipe_sparc:mk_reg(hipe_sparc_registers:stack_pointer()))).
58
-define(MK_TEMP_REG(),(hipe_sparc:mk_reg(hipe_sparc_registers:temp0()))).
59
-define(MK_TEMP_FPREG(),(hipe_sparc:mk_fpreg(0))).
60
-define(IS_SPILLED(Reg,Map),hipe_temp_map:is_spilled(hipe_sparc:reg_nr(Reg),Map)).
62
frame(Cfg, TempMap, FpMap, NextSpillPos, _Options) ->
63
%% io:format("~p\n",[TempMap]),
64
rewrite(Cfg, TempMap, FpMap, NextSpillPos).
66
rewrite(Cfg, TempMap, FpMap, NextSpillPos) ->
67
%% hipe_sparc_cfg:pp(Cfg),
68
Sparc = hipe_sparc_cfg:linearize(Cfg),
69
Arity = hipe_sparc:sparc_arity(Sparc),
70
Code = hipe_sparc:sparc_code(Sparc),
71
%% ConvNeed is added if there are any conv_fp instructions.
73
case get(hipe_inline_fp) of
75
lists:foldl(fun(I, Acc) ->
76
case hipe_sparc:is_conv_fp(I) of true -> 1; _ -> Acc end
82
%% Need is stack positions for spills
83
Need = NextSpillPos + 1 + ConvNeed,
84
%% +1 for CP, not realy needed for leaf functions...
86
%% ExtraNeed is room for arguments in calls.
87
ExtraNeed = extra_stack_need(Code, Need, Arity),
88
StackNeed = Need + ExtraNeed,
92
NewStart = hipe_sparc:label_create_new(),
94
{StackTestCode, StackIncCode} =
95
gen_stack_test(StackNeed, SP, CP, Arity, Cfg),
96
NeedInBytes = Need bsl ?log2_wordsize,
97
AllocCode = gen_alloc_code(NeedInBytes, SP),
101
StackTestCode, %% (We will flatten the list later.)
105
{RetCode,RetLabel} = gen_ret(Need, Arity),
109
%% Rewrite instructions to use physical registers
111
%% Also, handle pseudo instructions.
112
if is_tuple(TempMap) -> % XXX: can someone please explain the logic here?
113
[rewrite_instr(I, TempMap, FpMap, Need, Arity, RetLabel) || I <- Code];
115
rewrite_instrs(Code, [], TempMap, FpMap, Need, Arity, RetLabel)
118
%% code to call increment stack.
122
NewSparc = hipe_sparc:sparc_code_update(Sparc, lists:flatten(NewCode)),
123
CFG0 = hipe_sparc_cfg:init(NewSparc),
124
%% io:format("\n\n\n\n\n\n\n\nAfter frame\n"),
125
%% hipe_sparc_cfg:pp(CFG1),
128
rewrite_instrs([I|Is], TempMap, TempMaps, FpMap, Need, Arity, RetLabel) ->
130
case hipe_sparc:is_label(I) of
132
%% io:format("~w\n",[hipe_vectors:get(TempMaps, hipe_sparc:label_name(I)-1)]),
133
hipe_vectors:get(TempMaps, hipe_sparc:label_name(I)-1);
137
[rewrite_instr(I, NewMap, FpMap, Need, Arity, RetLabel) |
138
rewrite_instrs(Is, NewMap, TempMaps, FpMap, Need, Arity, RetLabel)];
139
rewrite_instrs([], _, _, _, _, _, _) ->
142
rewrite_instr(I, TempMap, FpMap, Need, Arity, RetLabel) ->
143
%% io:format("\n\n~w -> \n",[I]),
144
I1 = remap_fp_regs(I, FpMap),
145
I2 = rewrite_instr2(I1, TempMap, FpMap,Need, Arity, RetLabel),
146
%% io:format("~w\n",[I2]),
149
remap_fp_regs(I, FpMap) ->
151
%% These instructions handle their own remapping.
153
#pseudo_spill{} -> I;
154
#pseudo_unspill{} -> I;
156
Defs = hipe_sparc:fp_reg_defines(I),
157
NewI = remap_fp(remap_fp(I, Defs, FpMap),
158
hipe_sparc:fp_reg_uses(I),
163
rewrite_instr2(I, TempMap, FpMap, Need, Arity, RetLabel) ->
166
%% ?EXIT({pseudo_push, not_supported_any_more, I});
168
Temp = hipe_sparc:pseudo_pop_reg(I),
169
Reg = map(Temp,TempMap),
170
%% Arg position on stack = -(arg index + need)*4
171
ArgIndex = hipe_sparc:imm_value(hipe_sparc:pseudo_pop_index(I)),
172
Pos = - ((ArgIndex + Need) bsl ?log2_wordsize),
173
gen_stack_load(Pos, Reg);
175
rewrite_move(I, TempMap);
177
rewrite_spill(I, TempMap, FpMap);
179
rewrite_unspill(I, TempMap, FpMap);
181
rewrite_call(I, TempMap, Need, Arity);
183
%% Note we assume that the arguments to return have been
184
%% mapped to physical register in the translation RTL->SPARC.
186
%% XXX: Fix if we start using multiple return values
187
%% Acctually just fix gen_ret/2 to annotate the
188
%% jmp with the live registers...
189
case length(hipe_sparc:pseudo_return_regs(I)) =:= 1 of
190
true -> %% Just one retval all is ok
191
hipe_sparc:goto_create(RetLabel);
193
%% Number of retvalues not 1.
194
?EXIT({multiple_retvals_not_handled,I})
197
rewrite_enter(I, TempMap, Need, Arity);
199
rewrite_fmove(I, TempMap, FpMap);
201
rewrite_load_fp(I, TempMap);
203
rewrite_store_fp(I, TempMap);
205
NewI = map_temps(I, TempMap),
206
Source = hipe_sparc:conv_fp_src(NewI),
207
Dest = hipe_sparc:conv_fp_dest(NewI),
208
Off = hipe_sparc:mk_imm(get_offset(Need - 1)),
209
SP = hipe_sparc:mk_reg(hipe_sparc_registers:stack_pointer()),
210
[hipe_sparc:store_create(SP, Off, w, Source),
211
hipe_sparc:load_fp_create(Dest, 32, single, SP, Off),
212
hipe_sparc:conv_fp_create(Dest, Dest)];
214
%% All other instructions.
215
%% No special handling, just map the temps to regs or spill positions.
216
map_temps(I, TempMap)
220
rewrite_enter(I, TempMap, Need, Arity) ->
221
%% Calculate number of args (to current fun) on stack
222
%% Consider moving this out of the loop.
223
NoRegArgs = hipe_sparc_registers:register_args(),
225
if Arity > NoRegArgs -> Arity - NoRegArgs;
229
%% Get arguments to enter.
230
Args = hipe_sparc:pseudo_enter_args(I),
231
RegArgs = lists:sublist(Args, 1, NoRegArgs),
232
%% Get target (closure or address).
233
T = hipe_sparc:pseudo_enter_target(I),
235
case hipe_sparc:pseudo_enter_is_known(I) of
237
{map(T, TempMap),[]};
240
TT = case hipe_sparc:pseudo_enter_type(I) of
241
remote -> remote_function;
242
not_remote -> local_function
244
TI = hipe_sparc:load_address_create(TR, T, TT),
249
%% The code for enter.
251
%% Restore CP from stack
252
%% TODO: Do this only in non-leaf functions.
253
gen_stack_load(-(Need bsl ?log2_wordsize), CP),
255
%% If arguments to the called function spill over to the
256
%% stack, do some shuffling.
257
%% Otherwise just adjust the stackpointer.
258
case length(Args) > NoRegArgs of
260
enter_stack_args(Args, Need, TempMap, ArgsOnStack);
262
gen_dealloc_code((ArgsOnStack+Need) bsl ?log2_wordsize)
265
%% Jump to the target function.
267
hipe_sparc:jmp_create(Target, hipe_sparc:mk_imm(0),
268
[map(R,TempMap)||R <- RegArgs] , [])].
270
map_temps(I, TempMap) ->
271
Defs = hipe_sparc:keep_registers(hipe_sparc:defines(I)),
272
Uses = hipe_sparc:keep_registers(hipe_sparc:uses(I)),
273
remap(remap(I, Defs, TempMap), Uses, TempMap).
275
rewrite_call(Call, TempMap, Need, Arity) ->
276
I = set_stack_size(Call,Need, Arity),
277
Args = hipe_sparc:call_link_args(I),
278
PushCode = push_call_args(Args, TempMap),
279
NewI = remap_call_regs(I, TempMap),
283
remap_call_regs(I, TempMap) ->
284
Defs = hipe_sparc:keep_registers(hipe_sparc:defines(I)),
285
ArgsInRegs = lists:sublist(hipe_sparc:call_link_args(I),
286
hipe_sparc_registers:register_args()),
287
case hipe_sparc:call_link_is_known(I) of
289
Target = hipe_sparc:call_link_target(I),
290
case ?IS_SPILLED(Target,TempMap) of
292
RemappedCall = remap(I, Defs ++ ArgsInRegs, TempMap),
293
Temp = ?MK_TEMP_REG(),
294
Pos = get_spill_offset(hipe_temp_map:find(hipe_sparc:reg_nr(Target), TempMap)),
295
[gen_stack_load(Pos, Temp),
296
hipe_sparc:call_link_target_update(RemappedCall, Temp)];
298
remap(I, [Target | (Defs ++ ArgsInRegs)], TempMap)
301
remap(I, Defs ++ ArgsInRegs, TempMap)
305
%% ____________________________________________________________________
310
%% ____________________________________________________________________
311
rewrite_move(I, TempMap) ->
312
Src = hipe_sparc:move_src(I),
313
Dest = hipe_sparc:move_dest(I),
314
DestReg = hipe_sparc:reg_nr(Dest),
316
case hipe_sparc:is_reg(Src) of
318
case hipe_temp_map:is_spilled(DestReg,TempMap) of
320
Pos = get_spill_offset(hipe_temp_map:find(DestReg, TempMap)),
321
Reg = ?MK_TEMP_REG(),
322
[hipe_sparc:move_dest_update(I,Reg)|
323
gen_stack_store(Pos, Reg)];
325
remap(I, [Dest], TempMap)
328
SrcReg = hipe_sparc:reg_nr(Src),
329
case {hipe_temp_map:is_spilled(SrcReg,TempMap),
330
hipe_temp_map:is_spilled(DestReg,TempMap)} of
331
{false,true} -> %% spill
332
Pos = get_spill_offset(hipe_temp_map:find(DestReg, TempMap)),
333
Reg = map(Src,TempMap),
334
gen_stack_store(Pos, Reg);
335
{true,false} -> %% unspill
336
Pos = get_spill_offset(hipe_temp_map:find(SrcReg, TempMap)),
337
Reg = map(Dest,TempMap),
338
gen_stack_load(Pos, Reg);
340
remap(I, [Src,Dest], TempMap);
342
Pos1 = get_spill_offset(hipe_temp_map:find(SrcReg, TempMap)),
343
Pos2 = get_spill_offset(hipe_temp_map:find(DestReg, TempMap)),
344
Reg = ?MK_TEMP_REG(),
345
[gen_stack_load(Pos1, Reg),
346
gen_stack_store(Pos2, Reg)]
350
%% ____________________________________________________________________
355
%% ____________________________________________________________________
356
rewrite_spill(I, TempMap, FpMap) ->
357
SrcReg = hipe_sparc:pseudo_spill_reg(I),
358
Pos = get_spill_offset(hipe_sparc:pseudo_spill_pos(I)),
360
case hipe_sparc:is_fpreg(SrcReg) of
362
SrcFpRegNr = hipe_sparc:fpreg_nr(SrcReg),
363
case hipe_temp_map:in_fp_reg(SrcFpRegNr,FpMap) of
365
%% Spilling a spilled reg...
366
?ASSERT(check_spill(SrcFpRegNr,FpMap,Pos,I)),
367
hipe_sparc:comment_create({already_spilled,I});
368
true -> %% Not spilled...
369
Reg = map_fp(SrcReg, FpMap),
370
gen_stack_store_fp(Pos, Reg)
373
SrcRegNr = hipe_sparc:reg_nr(SrcReg),
374
case hipe_temp_map:in_reg(SrcRegNr,TempMap) of
376
%% Spilling a spilled reg...
377
?ASSERT(check_spill(SrcRegNr,TempMap,Pos,I)),
378
hipe_sparc:comment_create({already_spilled,I});
379
true -> %% Not spilled...
380
Reg = map(SrcReg,TempMap),
381
gen_stack_store(Pos, Reg)
385
%% --------------------------------------------------------------------
389
%% --------------------------------------------------------------------
391
rewrite_unspill(I, TempMap, FpMap) ->
392
DstReg = hipe_sparc:pseudo_unspill_reg(I),
393
Pos = get_spill_offset(hipe_sparc:pseudo_unspill_pos(I)),
394
case hipe_sparc:is_fpreg(DstReg) of
396
DstFpRegNr = hipe_sparc:fpreg_nr(DstReg),
397
case hipe_temp_map:in_fp_reg(DstFpRegNr,FpMap) of
399
%% Unspilling to a spilled fpreg...
400
?ASSERT(check_spill(DstFpRegNr,FpMap,Pos,I)),
401
hipe_sparc:comment_create({already_unspilled,I});
402
true -> %% Not spilled...
403
Reg = map_fp(DstReg, FpMap),
404
gen_stack_load_fp(Pos, Reg)
407
DstRegNr = hipe_sparc:reg_nr(DstReg),
408
case hipe_temp_map:in_reg(DstRegNr,TempMap) of
409
false -> %% Unspilling to a spilled reg.
410
?ASSERT(check_spill(DstRegNr,TempMap,Pos,I)),
411
hipe_sparc:comment_create({already_unspilled,I});
412
true -> %% Not spilled.
413
Reg = map(DstReg,TempMap),
414
gen_stack_load(Pos,Reg)
419
check_spill(RegNr,TempMap,Pos,I) ->
420
case (catch hipe_temp_map:find(RegNr, TempMap)) of
422
DPos -> (get_spill_offset(DPos) =:= Pos)
426
rewrite_fmove(I0, TempMap, FpMap)->
427
I = map_temps(I0, TempMap),
428
Src = hipe_sparc:fmove_src(I),
429
Dest = hipe_sparc:fmove_dest(I),
430
DestReg = hipe_sparc:fpreg_nr(Dest),
432
case hipe_sparc:is_fpreg(Src) of
433
false -> %% Can this happen?
434
case hipe_temp_map:is_spilled(DestReg,FpMap) of
436
Pos = get_spill_offset(hipe_temp_map:find(DestReg, FpMap)),
437
Reg = ?MK_TEMP_FPREG(),
438
[hipe_sparc:fmove_dest_update(I,Reg)|
439
gen_stack_store_fp(Pos, Reg)];
441
remap_fp(I, [Dest], FpMap)
444
SrcReg = hipe_sparc:fpreg_nr(Src),
446
case {hipe_temp_map:is_spilled(SrcReg,FpMap),
447
hipe_temp_map:is_spilled(DestReg,FpMap)} of
448
{false,true} -> %% spill
449
Pos = get_spill_offset(hipe_temp_map:find(DestReg, FpMap)),
450
Reg = map_fp(Src,FpMap),
451
gen_stack_store_fp(Pos, Reg);
452
{true,false} -> %% unspill
453
Pos = get_spill_offset(hipe_temp_map:find(SrcReg, FpMap)),
454
Reg = map_fp(Dest,FpMap),
455
gen_stack_load_fp(Pos, Reg);
457
remap_fp(I, [Src,Dest], FpMap);
459
Pos1 = get_spill_offset(hipe_temp_map:find(SrcReg, FpMap)),
460
Pos2 = get_spill_offset(hipe_temp_map:find(DestReg, FpMap)),
461
Reg = ?MK_TEMP_FPREG(),
462
[gen_stack_load_fp(Pos1, Reg),
463
gen_stack_store_fp(Pos2, Reg)]
467
rewrite_load_fp(I, TempMap)->
468
NewI = map_temps(I, TempMap),
469
Source = hipe_sparc:load_fp_src(NewI),
470
Dest = hipe_sparc:load_fp_dest(NewI),
471
Off = hipe_sparc:load_fp_off(NewI),
472
Align = hipe_sparc:load_fp_align(NewI),
473
case hipe_sparc:load_fp_type(NewI) of
475
Dest2 = hipe_sparc:mk_fpreg(hipe_sparc:fpreg_nr(Dest) + 1),
476
case hipe_sparc:is_imm(Off) of
478
Off2 = hipe_sparc:mk_imm(hipe_sparc:imm_value(Off) + 4),
479
[hipe_sparc:load_fp_create(Dest, Align, single, Source, Off),
480
hipe_sparc:load_fp_create(Dest2, Align, single, Source, Off2)];
481
_ -> %% The offset is a register
482
[hipe_sparc:load_fp_create(Dest, Align, single, Source, Off),
483
hipe_sparc:alu_create(Off, Off, '+', hipe_sparc:mk_imm(4)),
484
hipe_sparc:load_fp_create(Dest2, Align, single, Source, Off),
485
hipe_sparc:alu_create(Off, Off, '-', hipe_sparc:mk_imm(4))]
491
rewrite_store_fp(I, TempMap)->
492
NewI = map_temps(I, TempMap),
493
Source = hipe_sparc:store_fp_src(NewI),
494
Dest = hipe_sparc:store_fp_dest(NewI),
495
Off = hipe_sparc:store_fp_off(NewI),
496
Align = hipe_sparc:store_fp_align(NewI),
497
case hipe_sparc:store_fp_type(NewI) of
499
Source2 = hipe_sparc:mk_fpreg(hipe_sparc:fpreg_nr(Source) + 1),
500
case hipe_sparc:is_imm(Off) of
502
Off2 = hipe_sparc:mk_imm(hipe_sparc:imm_value(Off) + 4),
503
[hipe_sparc:store_fp_create(Dest, Off, single, Align, Source),
504
hipe_sparc:store_fp_create(Dest, Off2, single, Align, Source2)];
506
[hipe_sparc:store_fp_create(Dest, Off, single, Align, Source),
507
hipe_sparc:alu_create(Off, Off, '+', hipe_sparc:mk_imm(4)),
508
hipe_sparc:store_fp_create(Dest, Off, single, Align, Source2),
509
hipe_sparc:alu_create(Off, Off, '-', hipe_sparc:mk_imm(4))]
515
get_offset(O) when is_integer(O) ->
521
get_spill_offset(T) ->
522
get_spill_pos(element(2,T)).
524
enter_stack_args(Args, Need, TempMap, ArgsOnStack) ->
525
enter_stack_args(0, hipe_sparc_registers:register_args(), Args,
526
Need, TempMap, ArgsOnStack).
529
%% The stack on SPARC grows uppwards (At least now...)
531
%% Assume a function f with Arity = j is doing a tail-call to
532
%% a function g with arity k.
533
%% Also assume the current function has spilled i temps.
535
%% Current stack frame:
542
%% | Dead CP | (Read to %o7)
545
%% | Arg 6 | (Currently 5 args in reg)
548
%% Stack just before call to target:
557
%% | Arg' 6 | (Currently 5 args in reg)
560
%% The arguments to g might be on the stack
561
%% If they are in the dangezone (the area overwritten by the arguments)
562
%% They have to be moved.
563
%% e.g. ( d marks the dangerzone)
567
%% | Spill 1 | SP ->| |
568
%% d | Spill 2 | | Spill 1 |
569
%% d | Spill 3 | | Spill 2 |
570
%% d | Dead CP | | Spill 3 |
571
%% d | Arg 7 | | Arg 6 |
572
%% d | Arg 6 | | t1 |
573
%% |OLD FRAME| |OLD FRAME|
575
%% The DangerZone is SP - 2 to SP - 6
576
%% We go through the arguments to g bottom up:
578
%% DZ ARG POSITION SAVE
580
%% < -6, t1 : in reg -> OK
581
%% < -5, Arg 6 : SP-6 -> in DZ, Save = [SP-6]
582
%% < -4, Spill 2: SP-2 -> OK
583
%% < -3, Spill 3: SP-1 -> OK
584
%% < -2, Spill 1: SP-3 -> in DZ, Save = [SP-3, SP-6]
586
%% Then we copy the positions in Save to the top of the stack.
597
%% Now we can rewrite the stack safely:
608
%% TODO: Verify that this really is correct.
610
enter_stack_args(ArgNo, ArgNo, Args, Need, TempMap, ArgsOnStack) ->
611
%% How many args has to be spilled to the stack?
612
NoNewArgsOnStack = length(Args),
614
%% Where does the first arg end up?
615
%% SP - (Need + ArgsOnStack)*4
616
Base = -(Need + ArgsOnStack),
618
{ToSave,RealArgs} = args_in_danger(Args, Base-1, [], 0, [], TempMap),
620
TempReg = ?MK_TEMP_REG(),
621
SaveCode = save(ToSave,0, TempReg),
622
PushCode = pushem(RealArgs, Base, TempReg),
624
AdjustOffset = (ArgsOnStack + Need - NoNewArgsOnStack) bsl ?log2_wordsize,
625
AdjustSP = gen_dealloc_code(AdjustOffset),
626
[SaveCode, PushCode, AdjustSP];
627
enter_stack_args(No, NoRegArgs, [_Arg|Args], Need, TempMap, ArgsOnStack) ->
628
enter_stack_args(No+1, NoRegArgs, Args, Need, TempMap, ArgsOnStack).
630
args_in_danger([Arg|Args], DangerZone, ToSave, SavePos, MappedArgs, TempMap) ->
631
case hipe_sparc:is_reg(Arg) of
633
case hipe_temp_map:find(hipe_sparc:reg_nr(Arg), TempMap) of
634
{reg, Reg} -> %% Arg in reg all cool.
635
args_in_danger(Args, DangerZone+1, ToSave, SavePos,
636
[{reg, Reg}|MappedArgs], TempMap);
637
{spill, Pos} when is_integer(Pos) ->
638
if -Pos < DangerZone -> %% Spill in dangerzone
639
args_in_danger(Args, DangerZone+1, [-Pos|ToSave], SavePos+1,
640
[{spill, SavePos}|MappedArgs], TempMap);
642
args_in_danger(Args, DangerZone+1, ToSave, SavePos,
643
[{spill, -(Pos+1)}|MappedArgs], TempMap)
647
case hipe_sparc:is_imm(Arg) of
649
args_in_danger(Args, DangerZone+1, ToSave, SavePos,
650
[{imm, hipe_sparc:imm_value(Arg)}|MappedArgs],
653
%% TODO: XXX: Dont handle fpreg ...
654
?EXIT({do_no_handle,Arg})
657
args_in_danger([],_,ToSave,_,Args,_) ->
658
{lists:reverse(ToSave),lists:reverse(Args)}.
660
save([Pos|Poses], Offset, TempReg) ->
661
ToPos = Offset bsl ?log2_wordsize,
662
FromPos = get_offset(Pos+1),
663
[gen_stack_load(FromPos, TempReg),
664
gen_stack_store(ToPos, TempReg)
665
| save(Poses, Offset+1, TempReg)];
668
pushem([{reg,R}|Args], Pos, Temp) ->
669
ToPos = Pos bsl ?log2_wordsize,
670
[gen_stack_store(ToPos, hipe_sparc:mk_reg(R)) | pushem(Args,Pos+1, Temp)];
671
pushem([{spill,P}|Args], Pos, Temp) ->
672
FromPos = P bsl ?log2_wordsize,
673
ToPos = Pos bsl ?log2_wordsize,
674
[gen_stack_load(FromPos, Temp),
675
gen_stack_store(ToPos, Temp) |
676
pushem(Args,Pos+1, Temp)];
677
pushem([{imm,I}|Args], Pos, Temp) ->
678
ToPos = Pos bsl ?log2_wordsize,
679
[hipe_sparc:move_create(Temp, hipe_sparc:mk_imm(I)),
680
gen_stack_store(ToPos, Temp) |
681
pushem(Args, Pos+1, Temp)];
682
pushem([], _, _) -> [].
684
find_reg(Temp,Map) ->
685
case hipe_temp_map:find(hipe_sparc:reg_nr(Temp), Map) of
688
Where -> ?EXIT({temp_assumed_in_reg,Temp,Where})
691
find_fpreg(Temp,Map) ->
692
case hipe_temp_map:find(hipe_sparc:fpreg_nr(Temp), Map) of
695
Where -> ?EXIT({temp_assumed_in_fpreg,Temp,Where})
698
%%find_pos(Temp,Map) ->
699
%% case hipe_temp_map:find(hipe_sparc:reg_nr(Temp), Map) of
702
%% Where -> ?EXIT({temp_assumed_on_stack,Temp,Where})
705
remap(I, Temps, Map) ->
706
%% io:format("\n\n~w~w\n~w\n",[I,Temps,Map]),
707
Substs = [{Temp, hipe_sparc:mk_reg(find_reg(Temp,Map))} || Temp <- Temps],
708
hipe_sparc:subst(I, Substs).
710
remap_fp(I, Temps, Map) ->
711
%% io:format("\n\n~w~w\n~w\n",[I,Temps,Map]),
713
[{Temp, hipe_sparc:mk_fpreg(find_fpreg(Temp,Map))} || Temp <- Temps],
714
hipe_sparc:subst(I, Substs).
717
case hipe_sparc:is_fpreg(Temp) of
719
hipe_sparc:mk_fpreg(find_fpreg(Temp, Map));
725
case hipe_sparc:is_reg(Temp) of
727
hipe_sparc:mk_reg(find_reg(Temp, Map));
732
max(P, A) when is_integer(P), is_integer(A) ->
737
min(P, A) when is_integer(P), is_integer(A) ->
742
push_call_args(Args, TempMap) ->
743
ArgsOnStack = args_on_stack(hipe_sparc_registers:register_args(), Args),
744
NoArgs = length(ArgsOnStack),
748
case hipe_sparc:is_reg(Arg) of
750
case hipe_temp_map:find(hipe_sparc:reg_nr(Arg), TempMap) of
751
{reg, Reg} -> {reg,Reg};
752
{spill, Pos} -> {spill, -(1+Pos+NoArgs)}
755
case hipe_sparc:is_imm(Arg) of
757
{imm,hipe_sparc:imm_value(Arg)};
759
%% TODO: XXX: Dont handle fpreg ...
760
?EXIT({do_no_handle,Arg})
763
|| Arg <- ArgsOnStack],
765
TempReg = ?MK_TEMP_REG(),
766
AdjustSP = hipe_sparc:alu_create(SP,SP,'+',hipe_sparc:mk_imm(4*NoArgs)),
767
PushCode = pushem(MappedArgs,-NoArgs,TempReg),
770
[] %% No args on the stack.
773
args_on_stack(0, [_|_] = Args) ->
775
args_on_stack(N, [_Arg|Args]) ->
776
args_on_stack(N-1, Args);
777
args_on_stack(_N, []) ->
780
extra_stack_need(Code, Need, Arity) when is_integer(Need) ->
781
%% Calculate number of args (to current fun) on stack
782
NoRegArgs = hipe_sparc_registers:register_args(),
784
if Arity > NoRegArgs -> Arity - NoRegArgs;
787
PrevSPLevel = ArgsOnStack + Need,
788
lists:foldl(fun (I, Max) ->
789
max(stack_need(I, PrevSPLevel), Max)
794
stack_need(I, PrevSPLevel) ->
795
%% io:format("\n\n~w\n~w\n",[I,TempMap]),
798
Argneed = call_args_need(hipe_sparc:call_link_args(I)),
801
NoArgs = length(hipe_sparc:pseudo_enter_args(I)),
802
NoRegArgs = hipe_sparc_registers:register_args(),
803
%% stack, do some shuffling.
804
%% Otherwise just adjust the stack pointer.
805
case NoArgs > NoRegArgs of
807
%% Arguments to the called function spill
808
NewOnStack = NoArgs - NoRegArgs,
809
case NewOnStack > PrevSPLevel of
810
true -> NewOnStack - PrevSPLevel;
813
false -> %% All arguments on stack...
817
%% All other instructions no extra need.
821
call_args_need(Args) ->
822
length(args_on_stack(hipe_sparc_registers:register_args(), Args)).
824
set_stack_size(Call, Size, Arity) ->
825
SD = hipe_sparc:call_link_stack_desc(Call),
826
NewSD = hipe_sparc:sdesc_size_update(SD, Size),
827
NewSD2 = hipe_sparc:sdesc_arity_update(NewSD, Arity),
828
hipe_sparc:call_link_stack_desc_update(Call, NewSD2).
830
gen_stack_test(StackNeed, SP, CP, Arity, Cfg) when is_integer(StackNeed) ->
831
Leaf = hipe_sparc_cfg:is_leaf(Cfg),
832
TempReg = ?MK_TEMP_REG(),
833
TempReg1 = hipe_sparc:mk_reg(hipe_sparc_registers:temp1()),
834
if StackNeed =:= 0 ->
836
StackNeed < ?SPARC_LEAF_WORDS, Leaf =:= true ->
839
Zero = hipe_sparc:mk_reg(hipe_sparc_registers:zero()),
840
SL = hipe_sparc:mk_reg(hipe_sparc_registers:stack_limit()),
842
OverflowLbl = hipe_sparc:label_create_new(),
843
StartLbl = hipe_sparc:label_create_new(),
844
TestLbl = hipe_sparc:label_create_new(),
845
RetLbl = hipe_sparc:label_create_new(),
846
OverflowName = hipe_rtl:label_name(OverflowLbl),
847
StartName = hipe_rtl:label_name(StartLbl),
848
TestName = hipe_rtl:label_name(TestLbl),
849
ByteNeed = (?SPARC_LEAF_WORDS+StackNeed) bsl ?log2_wordsize,
851
if ByteNeed > 16#fff -> %% Max in simm13.
853
hipe_sparc:alu_create(TempReg, SL, '-', SP),
854
hipe_sparc:sethi_create(TempReg1,
855
hipe_sparc:mk_imm(high22(ByteNeed))),
856
hipe_sparc:alu_create(TempReg1, TempReg1, 'or',
857
hipe_sparc:mk_imm(low10(ByteNeed))),
858
hipe_sparc:alu_cc_create(Zero, TempReg, '-', TempReg1),
859
hipe_sparc:b_create(l, OverflowName, StartName, Pred, na),
862
[hipe_sparc:alu_create(TempReg, SL, '-', SP),
863
hipe_sparc:alu_cc_create(Zero, TempReg, '-',
864
hipe_sparc:mk_imm(ByteNeed)),
865
hipe_sparc:b_create(l, OverflowName, StartName, Pred, na),
868
CPSAVE = hipe_sparc:mk_reg(hipe_sparc_registers:cpsave()),
869
{[hipe_sparc:goto_create(TestName),
872
hipe_sparc:move_create(CPSAVE, CP),
873
hipe_sparc:call_link_create(inc_stack_fun(Arity),
876
hipe_rtl:label_name(RetLbl), [], not_remote),
878
hipe_sparc:move_create(CP, CPSAVE),
879
hipe_sparc:goto_create(TestName)]
883
inc_stack_fun(Arity) ->
884
ArgsInRegs = min(Arity, hipe_sparc_registers:register_args()),
885
list_to_atom("inc_stack_" ++ integer_to_list(ArgsInRegs) ++ "args_0").
887
gen_alloc_code(NeededBytes,SP) ->
888
TempReg = ?MK_TEMP_REG(),
889
%% Alloc space on stack for spills
890
if NeededBytes > 4092 -> %% Too big for imm
891
[hipe_sparc:sethi_create(TempReg,
892
hipe_sparc:mk_imm(high22(NeededBytes))),
893
hipe_sparc:alu_create(TempReg, TempReg, 'or',
894
hipe_sparc:mk_imm(low10(NeededBytes))),
895
hipe_sparc:alu_create(SP,SP,'+',TempReg)];
897
[hipe_sparc:alu_create(SP,SP,'+',hipe_sparc:mk_imm(NeededBytes))]
900
gen_dealloc_code(Bytes) ->
901
TempReg = ?MK_TEMP_REG(),
903
%% dealloc space on stack.
904
if Bytes > 4092 -> %% Too big for imm
905
[hipe_sparc:sethi_create(TempReg,
906
hipe_sparc:mk_imm(high22(Bytes))),
907
hipe_sparc:alu_create(TempReg, TempReg, 'or',
908
hipe_sparc:mk_imm(low10(Bytes))),
909
hipe_sparc:alu_create(SP,SP,'-',TempReg)];
911
[hipe_sparc:alu_create(SP,SP,'-',hipe_sparc:mk_imm(Bytes))]
916
Offset = get_offset(Need),
917
gen_stack_store(Offset,CP).
919
gen_ret(Need, Arity) ->
920
%% Generate code for stack cleanup and return.
922
%% XXX: Fix if we start using multiple return values
923
RegArgs = [hipe_sparc:mk_reg(hipe_sparc_registers:ret(0))],
925
%% Calculate number of args (to current fun) on stack
926
%% Consider moving this out of the loop.
927
NoRegArgs = hipe_sparc_registers:register_rets(),
929
if Arity > NoRegArgs -> Arity - NoRegArgs;
932
RetLabel = hipe_sparc:label_create_new(),
934
StackAdjust = (ArgsOnStack+Need) bsl ?log2_wordsize,
936
gen_stack_load(get_offset(Need),CP),
937
gen_dealloc_code(StackAdjust),
938
hipe_sparc:jmp_create(CP, hipe_sparc:mk_imm(8), RegArgs, [])
940
hipe_sparc:label_name(RetLabel)}.
942
high22(X) -> X bsr 10.
944
low10(X) -> X band 16#3ff.
946
gen_stack_load(Offset, DestReg) ->
948
load_huge_spillpos(Offset,DestReg);
951
ImmOffset = hipe_sparc:mk_imm(Offset),
952
[hipe_sparc:load_create(DestReg, uw, SP, ImmOffset)]
955
gen_stack_store(Offset, Reg) ->
957
store_huge_spillpos(Offset,Reg);
960
ImmOffset = hipe_sparc:mk_imm(Offset),
961
[hipe_sparc:store_create(SP,ImmOffset, w, Reg)]
964
store_huge_spillpos(Offset, RegToSave) ->
966
{DecCode, IncCode, NewOffset} = adjust(Offset,SP),
968
hipe_sparc:store_create(SP, hipe_sparc:mk_imm(NewOffset), RegToSave),
971
load_huge_spillpos(Offset, RegToLoad) ->
973
{DecCode, _IncCode, NewOffset} = adjust(Offset, RegToLoad),
974
[hipe_sparc:move_create(RegToLoad, SP),
976
hipe_sparc:load_create(RegToLoad, RegToLoad,
977
hipe_sparc:mk_imm(NewOffset))].
979
gen_stack_load_fp(Offset, DestReg) ->
980
Offset2 = Offset - 4,
981
if Offset2 < -4092 ->
982
load_huge_spillpos_fp(Offset2, DestReg);
984
DestRegNr = hipe_sparc:fpreg_nr(DestReg),
985
DestReg2 = hipe_sparc:mk_fpreg(DestRegNr + 1),
987
[hipe_sparc:load_fp_create(DestReg, 32, single, SP,
988
hipe_sparc:mk_imm(Offset)),
989
hipe_sparc:load_fp_create(DestReg2, 32, single, SP,
990
hipe_sparc:mk_imm(Offset2))]
993
gen_stack_store_fp(Offset, SrcReg) ->
994
Offset2 = Offset - 4,
995
if Offset2 < -4092 ->
996
store_huge_spillpos_fp(Offset2, SrcReg);
998
SrcRegNr = hipe_sparc:fpreg_nr(SrcReg),
999
SrcReg2 = hipe_sparc:mk_fpreg(SrcRegNr + 1),
1001
[hipe_sparc:store_fp_create(SP, hipe_sparc:mk_imm(Offset),
1002
single, 32, SrcReg),
1003
hipe_sparc:store_fp_create(SP, hipe_sparc:mk_imm(Offset2),
1004
single, 32, SrcReg2)]
1007
store_huge_spillpos_fp(Offset2, RegToSave) ->
1008
RegNr = hipe_sparc:fpreg_nr(RegToSave),
1009
RegToSave2 = hipe_sparc:mk_fpreg(RegNr+ 1),
1011
{DecCode, IncCode, NewOffset2} = adjust(Offset2,SP),
1013
hipe_sparc:store_fp_create(SP, hipe_sparc:mk_imm(NewOffset2+4),
1014
single, 32, RegToSave),
1015
hipe_sparc:store_fp_create(SP, hipe_sparc:mk_imm(NewOffset2),
1016
single, 32, RegToSave2),
1019
load_huge_spillpos_fp(Offset2, RegToLoad) ->
1020
RegNr = hipe_sparc:fpreg_nr(RegToLoad),
1021
RegToLoad2 = hipe_sparc:mk_fpreg(RegNr + 1),
1023
{DecCode, IncCode, NewOffset2} = adjust(Offset2,SP),
1025
hipe_sparc:load_fp_create(RegToLoad, 32, single, SP,
1026
hipe_sparc:mk_imm(NewOffset2+4)),
1027
hipe_sparc:load_fp_create(RegToLoad2, 32, single, SP,
1028
hipe_sparc:mk_imm(NewOffset2)),
1031
adjust(Offset, Reg) ->
1032
adjust(Offset, Reg, [], []).
1034
adjust(Offset, _Reg, Dec,Inc) when Offset > -4092 ->
1036
adjust(Offset, Reg, Dec,Inc) ->
1037
NewOffset = Offset + 4092,
1038
Step = hipe_sparc:mk_imm(4092),
1039
adjust(NewOffset, Reg,
1040
[hipe_sparc:alu_create(Reg,Reg,'-',Step)| Dec],
1041
[hipe_sparc:alu_create(Reg,Reg,'+',Step)| Inc]).