1%% -*- erlang-indent-level: 2 -*- 2%% 3%% Licensed under the Apache License, Version 2.0 (the "License"); 4%% you may not use this file except in compliance with the License. 5%% You may obtain a copy of the License at 6%% 7%% http://www.apache.org/licenses/LICENSE-2.0 8%% 9%% Unless required by applicable law or agreed to in writing, software 10%% distributed under the License is distributed on an "AS IS" BASIS, 11%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12%% See the License for the specific language governing permissions and 13%% limitations under the License. 14 15-module(hipe_sparc_frame). 16-export([frame/1]). 17 18-include("hipe_sparc.hrl"). 19-include("../rtl/hipe_literals.hrl"). 20 21frame(CFG) -> 22 Formals = fix_formals(hipe_sparc_cfg:params(CFG)), 23 Temps0 = all_temps(CFG, Formals), 24 MinFrame = defun_minframe(CFG), 25 Temps = ensure_minframe(MinFrame, Temps0), 26 ClobbersRA = clobbers_ra(CFG), 27 Liveness = hipe_sparc_liveness_all:analyse(CFG), 28 do_body(CFG, Liveness, Formals, Temps, ClobbersRA). 29 30fix_formals(Formals) -> 31 fix_formals(hipe_sparc_registers:nr_args(), Formals). 32 33fix_formals(0, Rest) -> Rest; 34fix_formals(N, [_|Rest]) -> fix_formals(N-1, Rest); 35fix_formals(_, []) -> []. 36 37do_body(CFG0, Liveness, Formals, Temps, ClobbersRA) -> 38 Context = mk_context(Liveness, Formals, Temps, ClobbersRA), 39 CFG1 = do_blocks(CFG0, Context), 40 do_prologue(CFG1, Context). 41 42do_blocks(CFG, Context) -> 43 Labels = hipe_sparc_cfg:labels(CFG), 44 do_blocks(Labels, CFG, Context). 45 46do_blocks([Label|Labels], CFG, Context) -> 47 Liveness = context_liveness(Context), 48 LiveOut = hipe_sparc_liveness_all:liveout(Liveness, Label), 49 Block = hipe_sparc_cfg:bb(CFG, Label), 50 Code = hipe_bb:code(Block), 51 NewCode = do_block(Code, LiveOut, Context), 52 NewBlock = hipe_bb:code_update(Block, NewCode), 53 NewCFG = hipe_sparc_cfg:bb_add(CFG, Label, NewBlock), 54 do_blocks(Labels, NewCFG, Context); 55do_blocks([], CFG, _) -> 56 CFG. 57 58do_block(Insns, LiveOut, Context) -> 59 do_block(Insns, LiveOut, Context, context_framesize(Context), []). 60 61do_block([I|Insns], LiveOut, Context, FPoff0, RevCode) -> 62 {NewIs, FPoff1} = do_insn(I, LiveOut, Context, FPoff0), 63 do_block(Insns, LiveOut, Context, FPoff1, lists:reverse(NewIs, RevCode)); 64do_block([], _, Context, FPoff, RevCode) -> 65 FPoff0 = context_framesize(Context), 66 if FPoff =:= FPoff0 -> []; 67 true -> exit({?MODULE,do_block,FPoff}) 68 end, 69 lists:reverse(RevCode, []). 70 71do_insn(I, LiveOut, Context, FPoff) -> 72 case I of 73 #pseudo_call{} -> 74 do_pseudo_call(I, LiveOut, Context, FPoff); 75 #pseudo_call_prepare{} -> 76 do_pseudo_call_prepare(I, FPoff); 77 #pseudo_move{} -> 78 {do_pseudo_move(I, Context, FPoff), FPoff}; 79 #pseudo_ret{} -> 80 {do_pseudo_ret(I, Context, FPoff), context_framesize(Context)}; 81 #pseudo_tailcall{} -> 82 {do_pseudo_tailcall(I, Context), context_framesize(Context)}; 83 #pseudo_fmove{} -> 84 {do_pseudo_fmove(I, Context, FPoff), FPoff}; 85 #pseudo_spill_move{} -> 86 {do_pseudo_spill_move(I, Context, FPoff), FPoff}; 87 #pseudo_spill_fmove{} -> 88 {do_pseudo_spill_fmove(I, Context, FPoff), FPoff}; 89 _ -> 90 {[I], FPoff} 91 end. 92 93%%% 94%%% Moves, with Dst or Src possibly a pseudo 95%%% 96 97do_pseudo_move(I, Context, FPoff) -> 98 Dst = hipe_sparc:pseudo_move_dst(I), 99 Src = hipe_sparc:pseudo_move_src(I), 100 case temp_is_pseudo(Dst) of 101 true -> 102 Offset = pseudo_offset(Dst, FPoff, Context), 103 mk_store(Src, hipe_sparc:mk_sp(), Offset, []); 104 _ -> 105 case temp_is_pseudo(Src) of 106 true -> 107 Offset = pseudo_offset(Src, FPoff, Context), 108 mk_load(hipe_sparc:mk_sp(), Offset, Dst, []); 109 _ -> 110 case hipe_sparc:temp_reg(Dst) =:= hipe_sparc:temp_reg(Src) of 111 true -> []; 112 false -> [hipe_sparc:mk_mov(Src, Dst)] 113 end 114 end 115 end. 116 117do_pseudo_spill_move(I, Context, FPoff) -> 118 #pseudo_spill_move{src=Src,temp=Temp,dst=Dst} = I, 119 case temp_is_pseudo(Src) andalso temp_is_pseudo(Dst) of 120 false -> % Register allocator changed its mind, turn back to move 121 do_pseudo_move(hipe_sparc:mk_pseudo_move(Src, Dst), Context, FPoff); 122 true -> 123 SrcOffset = pseudo_offset(Src, FPoff, Context), 124 DstOffset = pseudo_offset(Dst, FPoff, Context), 125 case SrcOffset =:= DstOffset of 126 true -> []; % omit move-to-self 127 false -> 128 mk_load(hipe_sparc:mk_sp(), SrcOffset, Temp, 129 mk_store(Temp, hipe_sparc:mk_sp(), DstOffset, [])) 130 end 131 end. 132 133do_pseudo_fmove(I, Context, FPoff) -> 134 Dst = hipe_sparc:pseudo_fmove_dst(I), 135 Src = hipe_sparc:pseudo_fmove_src(I), 136 case temp_is_pseudo(Dst) of 137 true -> 138 Offset = pseudo_offset(Dst, FPoff, Context), 139 mk_fstore(Src, hipe_sparc:mk_sp(), Offset); 140 _ -> 141 case temp_is_pseudo(Src) of 142 true -> 143 Offset = pseudo_offset(Src, FPoff, Context), 144 mk_fload(hipe_sparc:mk_sp(), Offset, Dst); 145 _ -> 146 [hipe_sparc:mk_fp_unary('fmovd', Src, Dst)] 147 end 148 end. 149 150do_pseudo_spill_fmove(I, Context, FPoff) -> 151 #pseudo_spill_fmove{src=Src,temp=Temp,dst=Dst} = I, 152 case temp_is_pseudo(Src) andalso temp_is_pseudo(Dst) of 153 false -> % Register allocator changed its mind, turn back to fmove 154 do_pseudo_fmove(hipe_sparc:mk_pseudo_fmove(Src, Dst), Context, FPoff); 155 true -> 156 SrcOffset = pseudo_offset(Src, FPoff, Context), 157 DstOffset = pseudo_offset(Dst, FPoff, Context), 158 case SrcOffset =:= DstOffset of 159 true -> []; % omit move-to-self 160 false -> 161 mk_fload(hipe_sparc:mk_sp(), SrcOffset, Temp) 162 ++ mk_fstore(Temp, hipe_sparc:mk_sp(), DstOffset) 163 end 164 end. 165 166pseudo_offset(Temp, FPoff, Context) -> 167 FPoff + context_offset(Context, Temp). 168 169%%% 170%%% Return - deallocate frame and emit 'ret $N' insn. 171%%% 172 173do_pseudo_ret(I, Context, FPoff) -> 174 %% XXX: typically only one instruction between 175 %% the move-to-RA and the jmp-via-RA, ouch 176 restore_ra(FPoff, Context, 177 adjust_sp(FPoff + word_size() * context_arity(Context), 178 [I])). 179 180restore_ra(FPoff, Context, Rest) -> 181 case context_clobbers_ra(Context) of 182 false -> Rest; 183 true -> 184 RA = hipe_sparc:mk_ra(), 185 mk_load(hipe_sparc:mk_sp(), FPoff - word_size(), RA, Rest) 186 end. 187 188adjust_sp(N, Rest) -> 189 if N =:= 0 -> 190 Rest; 191 true -> 192 SP = hipe_sparc:mk_sp(), 193 hipe_sparc:mk_addi(SP, N, SP, Rest) 194 end. 195 196%%% 197%%% Recursive calls. 198%%% 199 200do_pseudo_call_prepare(I, FPoff0) -> 201 %% Create outgoing arguments area on the stack. 202 NrStkArgs = hipe_sparc:pseudo_call_prepare_nrstkargs(I), 203 Offset = NrStkArgs * word_size(), 204 {adjust_sp(-Offset, []), FPoff0 + Offset}. 205 206do_pseudo_call(I, LiveOut, Context, FPoff0) -> 207 #sparc_sdesc{exnlab=ExnLab,arity=OrigArity} = hipe_sparc:pseudo_call_sdesc(I), 208 FunV = hipe_sparc:pseudo_call_funv(I), 209 LiveTemps = [Temp || Temp <- LiveOut, temp_is_pseudo(Temp)], 210 SDesc = mk_sdesc(ExnLab, Context, LiveTemps), 211 ContLab = hipe_sparc:pseudo_call_contlab(I), 212 Linkage = hipe_sparc:pseudo_call_linkage(I), 213 CallCode = [hipe_sparc:mk_pseudo_call(FunV, SDesc, ContLab, Linkage)], 214 StkArity = erlang:max(0, OrigArity - hipe_sparc_registers:nr_args()), 215 context_need_stack(Context, stack_need(FPoff0, StkArity, FunV)), 216 ArgsBytes = word_size() * StkArity, 217 {CallCode, FPoff0 - ArgsBytes}. 218 219stack_need(FPoff, StkArity, FunV) -> 220 case FunV of 221 #sparc_prim{} -> FPoff; 222 #sparc_mfa{m=M,f=F,a=A} -> 223 case erlang:is_builtin(M, F, A) of 224 true -> FPoff; 225 false -> stack_need_general(FPoff, StkArity) 226 end; 227 _ -> stack_need_general(FPoff, StkArity) 228 end. 229 230stack_need_general(FPoff, StkArity) -> 231 erlang:max(FPoff, FPoff + (?SPARC_LEAF_WORDS - StkArity) * word_size()). 232 233%%% 234%%% Create stack descriptors for call sites. 235%%% 236 237mk_sdesc(ExnLab, Context, Temps) -> % for normal calls 238 Temps0 = only_tagged(Temps), 239 Live = mk_live(Context, Temps0), 240 Arity = context_arity(Context), 241 FSize = context_framesize(Context), 242 hipe_sparc:mk_sdesc(ExnLab, (FSize div word_size())-1, Arity, 243 list_to_tuple(Live)). 244 245only_tagged(Temps)-> 246 [X || X <- Temps, hipe_sparc:temp_type(X) =:= 'tagged']. 247 248mk_live(Context, Temps) -> 249 lists:sort([temp_to_slot(Context, Temp) || Temp <- Temps]). 250 251temp_to_slot(Context, Temp) -> 252 (context_framesize(Context) + context_offset(Context, Temp)) 253 div word_size(). 254 255mk_minimal_sdesc(Context) -> % for inc_stack_0 calls 256 hipe_sparc:mk_sdesc([], 0, context_arity(Context), {}). 257 258%%% 259%%% Tailcalls. 260%%% 261 262do_pseudo_tailcall(I, Context) -> % always at FPoff=context_framesize(Context) 263 Arity = context_arity(Context), 264 Args = hipe_sparc:pseudo_tailcall_stkargs(I), 265 FunV = hipe_sparc:pseudo_tailcall_funv(I), 266 Linkage = hipe_sparc:pseudo_tailcall_linkage(I), 267 {Insns, FPoff1} = do_tailcall_args(Args, Context), 268 context_need_stack(Context, FPoff1), 269 StkArity = length(Args), 270 FPoff2 = FPoff1 + (Arity - StkArity) * word_size(), 271 context_need_stack(Context, stack_need(FPoff2, StkArity, FunV)), 272 I2 = 273 case FunV of 274 #sparc_temp{} -> 275 hipe_sparc:mk_jmp(FunV, hipe_sparc:mk_simm13(0), []); 276 Fun -> 277 hipe_sparc:mk_call_tail(Fun, Linkage) 278 end, 279 %% XXX: break out the RA restore, just like for pseudo_ret? 280 restore_ra(context_framesize(Context), Context, 281 Insns ++ adjust_sp(FPoff2, [I2])). 282 283do_tailcall_args(Args, Context) -> 284 FPoff0 = context_framesize(Context), 285 Arity = context_arity(Context), 286 FrameTop = word_size()*Arity, 287 DangerOff = FrameTop - word_size()*length(Args), 288 %% 289 Moves = mk_moves(Args, FrameTop, []), 290 %% 291 {Stores, Simple, Conflict} = 292 split_moves(Moves, Context, DangerOff, [], [], []), 293 %% sanity check (shouldn't trigger any more) 294 if DangerOff < -FPoff0 -> 295 exit({?MODULE,do_tailcall_args,DangerOff,-FPoff0}); 296 true -> [] 297 end, 298 FPoff1 = FPoff0, 299 %% 300 {Pushes, Pops, FPoff2} = split_conflict(Conflict, FPoff1, [], []), 301 %% 302 TempReg = hipe_sparc_registers:temp1(), 303 %% 304 {adjust_sp(-(FPoff2 - FPoff1), 305 simple_moves(Pushes, FPoff2, TempReg, 306 store_moves(Stores, FPoff2, TempReg, 307 simple_moves(Simple, FPoff2, TempReg, 308 simple_moves(Pops, FPoff2, TempReg, 309 []))))), 310 FPoff2}. 311 312mk_moves([Arg|Args], Off, Moves) -> 313 Off1 = Off - word_size(), 314 mk_moves(Args, Off1, [{Arg,Off1}|Moves]); 315mk_moves([], _, Moves) -> 316 Moves. 317 318split_moves([Move|Moves], Context, DangerOff, Stores, Simple, Conflict) -> 319 {Src,DstOff} = Move, 320 case src_is_pseudo(Src) of 321 false -> 322 split_moves(Moves, Context, DangerOff, [Move|Stores], 323 Simple, Conflict); 324 true -> 325 SrcOff = context_offset(Context, Src), 326 Type = typeof_temp(Src), 327 if SrcOff =:= DstOff -> 328 split_moves(Moves, Context, DangerOff, Stores, 329 Simple, Conflict); 330 SrcOff >= DangerOff -> 331 split_moves(Moves, Context, DangerOff, Stores, 332 Simple, [{SrcOff,DstOff,Type}|Conflict]); 333 true -> 334 split_moves(Moves, Context, DangerOff, Stores, 335 [{SrcOff,DstOff,Type}|Simple], Conflict) 336 end 337 end; 338split_moves([], _, _, Stores, Simple, Conflict) -> 339 {Stores, Simple, Conflict}. 340 341split_conflict([{SrcOff,DstOff,Type}|Conflict], FPoff, Pushes, Pops) -> 342 FPoff1 = FPoff + word_size(), 343 Push = {SrcOff,-FPoff1,Type}, 344 Pop = {-FPoff1,DstOff,Type}, 345 split_conflict(Conflict, FPoff1, [Push|Pushes], [Pop|Pops]); 346split_conflict([], FPoff, Pushes, Pops) -> 347 {lists:reverse(Pushes), Pops, FPoff}. 348 349simple_moves([{SrcOff,DstOff,Type}|Moves], FPoff, TempReg, Rest) -> 350 Temp = hipe_sparc:mk_temp(TempReg, Type), 351 SP = hipe_sparc:mk_sp(), 352 LoadOff = FPoff+SrcOff, 353 StoreOff = FPoff+DstOff, 354 simple_moves(Moves, FPoff, TempReg, 355 mk_load(SP, LoadOff, Temp, 356 mk_store(Temp, SP, StoreOff, 357 Rest))); 358simple_moves([], _, _, Rest) -> 359 Rest. 360 361store_moves([{Src,DstOff}|Moves], FPoff, TempReg, Rest) -> 362 %% Type = typeof_temp(Src), 363 SP = hipe_sparc:mk_sp(), 364 StoreOff = FPoff+DstOff, 365 {NewSrc,FixSrc} = 366 case hipe_sparc:is_temp(Src) of 367 true -> 368 {Src, []}; 369 _ -> 370 Temp = hipe_sparc:mk_temp(TempReg, 'untagged'), 371 {Temp, hipe_sparc:mk_set(Src, Temp)} 372 end, 373 store_moves(Moves, FPoff, TempReg, 374 FixSrc ++ mk_store(NewSrc, SP, StoreOff, Rest)); 375store_moves([], _, _, Rest) -> 376 Rest. 377 378%%% 379%%% Contexts 380%%% 381 382-record(context, {liveness, framesize, arity, map, clobbers_ra, ref_maxstack}). 383 384mk_context(Liveness, Formals, Temps, ClobbersRA) -> 385 {Map, MinOff} = mk_temp_map(Formals, ClobbersRA, Temps), 386 FrameSize = (-MinOff), 387 RefMaxStack = hipe_bifs:ref(FrameSize), 388 #context{liveness=Liveness, 389 framesize=FrameSize, arity=length(Formals), 390 map=Map, clobbers_ra=ClobbersRA, ref_maxstack=RefMaxStack}. 391 392context_need_stack(#context{ref_maxstack=RM}, N) -> 393 M = hipe_bifs:ref_get(RM), 394 if N > M -> hipe_bifs:ref_set(RM, N); 395 true -> [] 396 end. 397 398context_maxstack(#context{ref_maxstack=RM}) -> 399 hipe_bifs:ref_get(RM). 400 401context_arity(#context{arity=Arity}) -> 402 Arity. 403 404context_framesize(#context{framesize=FrameSize}) -> 405 FrameSize. 406 407context_liveness(#context{liveness=Liveness}) -> 408 Liveness. 409 410context_offset(#context{map=Map}, Temp) -> 411 tmap_lookup(Map, Temp). 412 413context_clobbers_ra(#context{clobbers_ra=ClobbersRA}) -> ClobbersRA. 414 415mk_temp_map(Formals, ClobbersRA, Temps) -> 416 {Map, 0} = enter_vars(Formals, word_size() * length(Formals), 417 tmap_empty()), 418 TempsList = tset_to_list(Temps), 419 AllTemps = 420 case ClobbersRA of 421 false -> TempsList; 422 true -> 423 RA = hipe_sparc:mk_new_temp('untagged'), 424 [RA|TempsList] 425 end, 426 enter_vars(AllTemps, 0, Map). 427 428enter_vars([V|Vs], PrevOff, Map) -> 429 Off = 430 case hipe_sparc:temp_type(V) of 431 'double' -> PrevOff - 2*word_size(); % XXX: sparc64: 1*word_size() 432 _ -> PrevOff - word_size() 433 end, 434 enter_vars(Vs, Off, tmap_bind(Map, V, Off)); 435enter_vars([], Off, Map) -> 436 {Map, Off}. 437 438tmap_empty() -> 439 gb_trees:empty(). 440 441tmap_bind(Map, Key, Val) -> 442 gb_trees:insert(Key, Val, Map). 443 444tmap_lookup(Map, Key) -> 445 gb_trees:get(Key, Map). 446 447%%% 448%%% do_prologue: prepend stack frame allocation code. 449%%% 450%%% NewStart: 451%%% temp1 = *(P + P_SP_LIMIT) 452%%% temp2 = SP - MaxStack 453%%% cmp temp2, temp1 454%%% if (ltu) goto IncStack else goto AllocFrame 455%%% AllocFrame: 456%%% SP = temp2 [if FrameSize == MaxStack] 457%%% SP -= FrameSize [if FrameSize != MaxStack] 458%%% *(SP + FrameSize-WordSize) = RA [if ClobbersRA] 459%%% goto OldStart 460%%% OldStart: 461%%% ... 462%%% IncStack: 463%%% temp1 = RA 464%%% call inc_stack; nop 465%%% RA = temp1 466%%% goto NewStart 467 468do_prologue(CFG, Context) -> 469 MaxStack = context_maxstack(Context), 470 if MaxStack > 0 -> 471 FrameSize = context_framesize(Context), 472 OldStartLab = hipe_sparc_cfg:start_label(CFG), 473 NewStartLab = hipe_gensym:get_next_label(sparc), 474 %% 475 P = hipe_sparc:mk_temp(hipe_sparc_registers:proc_pointer(), 'untagged'), 476 Temp1 = hipe_sparc:mk_temp1(), 477 SP = hipe_sparc:mk_sp(), 478 %% 479 RA = hipe_sparc:mk_ra(), 480 ClobbersRA = context_clobbers_ra(Context), 481 GotoOldStartCode = [hipe_sparc:mk_b_label(OldStartLab)], 482 AllocFrameCodeTail = 483 case ClobbersRA of 484 false -> GotoOldStartCode; 485 true -> mk_store(RA, SP, FrameSize-word_size(), GotoOldStartCode) 486 end, 487 %% 488 Arity = context_arity(Context), 489 Guaranteed = erlang:max(0, (?SPARC_LEAF_WORDS - Arity) * word_size()), 490 %% 491 {CFG1,NewStartCode} = 492 if MaxStack =< Guaranteed -> 493 %% io:format("~w: MaxStack ~w =< Guaranteed ~w :-)\n", [?MODULE,MaxStack,Guaranteed]), 494 AllocFrameCode = adjust_sp(-FrameSize, AllocFrameCodeTail), 495 NewStartCode0 = AllocFrameCode, % no mflr needed 496 {CFG,NewStartCode0}; 497 true -> 498 %% io:format("~w: MaxStack ~w > Guaranteed ~w :-(\n", [?MODULE,MaxStack,Guaranteed]), 499 AllocFrameLab = hipe_gensym:get_next_label(sparc), 500 IncStackLab = hipe_gensym:get_next_label(sparc), 501 Temp2 = hipe_sparc:mk_temp2(), 502 %% 503 NewStartCodeTail2 = 504 [hipe_sparc:mk_pseudo_bp('lu', IncStackLab, AllocFrameLab, 0.01)], 505 NewStartCodeTail1 = NewStartCodeTail2, % no mflr needed 506 NewStartCode0 = 507 mk_load(P, ?P_NSP_LIMIT, Temp1, 508 hipe_sparc:mk_addi(SP, -MaxStack, Temp2, 509 [hipe_sparc:mk_alu('subcc', Temp2, Temp1, hipe_sparc:mk_g0()) | 510 NewStartCodeTail1])), 511 %% 512 AllocFrameCode = 513 if MaxStack =:= FrameSize -> 514 %% io:format("~w: MaxStack =:= FrameSize =:= ~w :-)\n", [?MODULE,MaxStack]), 515 [hipe_sparc:mk_mov(Temp2, SP) | 516 AllocFrameCodeTail]; 517 true -> 518 %% io:format("~w: MaxStack ~w =/= FrameSize ~w :-(\n", [?MODULE,MaxStack,FrameSize]), 519 adjust_sp(-FrameSize, AllocFrameCodeTail) 520 end, 521 %% 522 IncStackCodeTail = 523 [hipe_sparc:mk_call_rec(hipe_sparc:mk_prim('inc_stack_0'), 524 mk_minimal_sdesc(Context), not_remote), 525 hipe_sparc:mk_mov(Temp1, RA), 526 hipe_sparc:mk_b_label(NewStartLab)], 527 IncStackCode = 528 [hipe_sparc:mk_mov(RA, Temp1) | IncStackCodeTail], % mflr always needed 529 %% 530 CFG0a = hipe_sparc_cfg:bb_add(CFG, AllocFrameLab, 531 hipe_bb:mk_bb(AllocFrameCode)), 532 CFG0b = hipe_sparc_cfg:bb_add(CFG0a, IncStackLab, 533 hipe_bb:mk_bb(IncStackCode)), 534 %% 535 {CFG0b,NewStartCode0} 536 end, 537 %% 538 CFG2 = hipe_sparc_cfg:bb_add(CFG1, NewStartLab, 539 hipe_bb:mk_bb(NewStartCode)), 540 hipe_sparc_cfg:start_label_update(CFG2, NewStartLab); 541 true -> 542 CFG 543 end. 544 545%%% Create a load instruction. 546%%% May clobber Dst early for large offsets. In principle we could 547%%% clobber TEMP2 if Dst =:= Base, but Dst =/= Base here in frame. 548 549mk_load(Base, Offset, Dst, Rest) -> 550 LdOp = 'lduw', % XXX: sparc64: ldx 551 hipe_sparc:mk_load(LdOp, Base, Offset, Dst, 'error', Rest). 552 553mk_fload(Base, Offset, Dst) -> 554 hipe_sparc:mk_fload(Base, Offset, Dst, 'temp2'). 555 556%%% Create a store instruction. 557%%% May clobber TEMP2 for large offsets. 558 559mk_store(Src, Base, Offset, Rest) -> 560 StOp = 'stw', % XXX: sparc64: stx 561 hipe_sparc:mk_store(StOp, Src, Base, Offset, 'temp2', Rest). 562 563mk_fstore(Src, Base, Offset) -> 564 hipe_sparc:mk_fstore(Src, Base, Offset, 'temp2'). 565 566%%% typeof_temp -- what's temp's type? 567 568typeof_temp(Temp) -> 569 hipe_sparc:temp_type(Temp). 570 571%%% Check if an operand is a pseudo-Temp. 572 573src_is_pseudo(Src) -> 574 hipe_sparc:is_temp(Src) andalso temp_is_pseudo(Src). 575 576temp_is_pseudo(Temp) -> 577 not(hipe_sparc:temp_is_precoloured(Temp)). 578 579%%% 580%%% Detect if a Defun's body clobbers RA. 581%%% 582 583clobbers_ra(CFG) -> 584 any_insn(fun(#pseudo_call{}) -> true; 585 (_) -> false 586 end, CFG). 587 588any_insn(Pred, CFG) -> 589 %% Abuse fold to do an efficient "any"-operation using nonlocal control flow 590 FoundSatisfying = make_ref(), 591 try fold_insns(fun (I, _) -> 592 case Pred(I) of 593 true -> throw(FoundSatisfying); 594 false -> false 595 end 596 end, false, CFG) 597 of _ -> false 598 catch FoundSatisfying -> true 599 end. 600 601%%% 602%%% Build the set of all temps used in a Defun's body. 603%%% 604 605all_temps(CFG, Formals) -> 606 S0 = fold_insns(fun find_temps/2, tset_empty(), CFG), 607 S1 = tset_del_list(S0, Formals), 608 tset_filter(S1, fun(T) -> temp_is_pseudo(T) end). 609 610find_temps(I, S0) -> 611 S1 = tset_add_list(S0, hipe_sparc_defuse:insn_def_all(I)), 612 tset_add_list(S1, hipe_sparc_defuse:insn_use_all(I)). 613 614fold_insns(Fun, InitAcc, CFG) -> 615 hipe_sparc_cfg:fold_bbs( 616 fun(_, BB, Acc0) -> lists:foldl(Fun, Acc0, hipe_bb:code(BB)) end, 617 InitAcc, CFG). 618 619tset_empty() -> 620 gb_sets:new(). 621 622tset_size(S) -> 623 gb_sets:size(S). 624 625tset_insert(S, T) -> 626 gb_sets:add_element(T, S). 627 628tset_add_list(S, Ts) -> 629 gb_sets:union(S, gb_sets:from_list(Ts)). 630 631tset_del_list(S, Ts) -> 632 gb_sets:subtract(S, gb_sets:from_list(Ts)). 633 634tset_filter(S, F) -> 635 gb_sets:filter(F, S). 636 637tset_to_list(S) -> 638 gb_sets:to_list(S). 639 640%%% 641%%% Compute minimum permissible frame size, ignoring spilled temps. 642%%% This is done to ensure that we won't have to adjust the frame size 643%%% in the middle of a tailcall. 644%%% 645 646defun_minframe(CFG) -> 647 MaxTailArity = fold_insns(fun insn_mta/2, 0, CFG), 648 MyArity = length(fix_formals(hipe_sparc_cfg:params(CFG))), 649 erlang:max(MaxTailArity - MyArity, 0). 650 651insn_mta(I, MTA) -> 652 case I of 653 #pseudo_tailcall{arity=Arity} -> 654 erlang:max(MTA, Arity - hipe_sparc_registers:nr_args()); 655 _ -> MTA 656 end. 657 658%%% 659%%% Ensure that we have enough temps to satisfy the minimum frame size, 660%%% if necessary by prepending unused dummy temps. 661%%% 662 663ensure_minframe(MinFrame, Temps) -> 664 ensure_minframe(MinFrame, tset_size(Temps), Temps). 665 666ensure_minframe(MinFrame, Frame, Temps) -> 667 if MinFrame > Frame -> 668 Temp = hipe_sparc:mk_new_temp('untagged'), 669 ensure_minframe(MinFrame, Frame+1, tset_insert(Temps, Temp)); 670 true -> Temps 671 end. 672 673word_size() -> 674 hipe_rtl_arch:word_size(). 675