hipe_arm_frame.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 630 行 · 第 1/2 页

ERL
630
字号
%%% -*- erlang-indent-level: 2 -*-%%% $Id$-module(hipe_arm_frame).-export([frame/1]).-include("hipe_arm.hrl").-include("../rtl/hipe_literals.hrl").-define(LIVENESS_ALL, hipe_arm_liveness_gpr). % since we have no FP yetframe(Defun) ->  Formals = fix_formals(hipe_arm:defun_formals(Defun)),  Temps0 = all_temps(hipe_arm:defun_code(Defun), Formals),  MinFrame = defun_minframe(Defun),  Temps = ensure_minframe(MinFrame, Temps0),  ClobbersLR = clobbers_lr(hipe_arm:defun_code(Defun)),  CFG0 = hipe_arm_cfg:init(Defun),  Liveness = ?LIVENESS_ALL:analyse(CFG0),  CFG1 = do_body(CFG0, Liveness, Formals, Temps, ClobbersLR),  hipe_arm_cfg:linearise(CFG1).fix_formals(Formals) ->  fix_formals(hipe_arm_registers:nr_args(), Formals).fix_formals(0, Rest) -> Rest;fix_formals(N, [_|Rest]) -> fix_formals(N-1, Rest);fix_formals(_, []) -> [].do_body(CFG0, Liveness, Formals, Temps, ClobbersLR) ->  Context = mk_context(Liveness, Formals, Temps, ClobbersLR),  CFG1 = do_blocks(CFG0, Context),  do_prologue(CFG1, Context).do_blocks(CFG, Context) ->  Labels = hipe_arm_cfg:labels(CFG),  do_blocks(Labels, CFG, Context).do_blocks([Label|Labels], CFG, Context) ->  Liveness = context_liveness(Context),  LiveOut = ?LIVENESS_ALL:liveout(Liveness, Label),  Block = hipe_arm_cfg:bb(CFG, Label),  Code = hipe_bb:code(Block),  NewCode = do_block(Code, LiveOut, Context),  NewBlock = hipe_bb:code_update(Block, NewCode),  NewCFG = hipe_arm_cfg:bb_add(CFG, Label, NewBlock),  do_blocks(Labels, NewCFG, Context);do_blocks([], CFG, _) ->  CFG.do_block(Insns, LiveOut, Context) ->  do_block(Insns, LiveOut, Context, context_framesize(Context), []).do_block([I|Insns], LiveOut, Context, FPoff0, RevCode) ->  {NewIs, FPoff1} = do_insn(I, LiveOut, Context, FPoff0),  do_block(Insns, LiveOut, Context, FPoff1, lists:reverse(NewIs, RevCode));do_block([], _, Context, FPoff, RevCode) ->  FPoff0 = context_framesize(Context),  if FPoff =:= FPoff0 -> [];     true -> exit({?MODULE,do_block,FPoff})  end,  lists:reverse(RevCode, []).do_insn(I, LiveOut, Context, FPoff) ->  case I of    #pseudo_blr{} ->      {do_pseudo_blr(I, Context, FPoff), context_framesize(Context)};    #pseudo_call{} ->      do_pseudo_call(I, LiveOut, Context, FPoff);    #pseudo_call_prepare{} ->      do_pseudo_call_prepare(I, FPoff);    #pseudo_move{} ->      {do_pseudo_move(I, Context, FPoff), FPoff};    #pseudo_tailcall{} ->      {do_pseudo_tailcall(I, Context), context_framesize(Context)};    _ ->      {[I], FPoff}  end.%%%%%% Moves, with Dst or Src possibly a pseudo%%%do_pseudo_move(I, Context, FPoff) ->  Dst = hipe_arm:pseudo_move_dst(I),  Src = hipe_arm:pseudo_move_src(I),  case temp_is_pseudo(Dst) of    true ->      Offset = pseudo_offset(Dst, FPoff, Context),      mk_store('str', Src, Offset, mk_sp(), []);    _ ->      case temp_is_pseudo(Src) of	true ->	  Offset = pseudo_offset(Src, FPoff, Context),	  mk_load('ldr', Dst, Offset, mk_sp(), []);	_ ->	  [hipe_arm:mk_move(Dst, Src)]      end  end.pseudo_offset(Temp, FPoff, Context) ->  FPoff + context_offset(Context, Temp).%%%%%% Return - deallocate frame and emit 'ret $N' insn.%%%do_pseudo_blr(I, Context, FPoff) ->  %% XXX: perhaps use explicit pseudo_move;mtlr,  %% avoiding the need to hard-code Temp1 here  %% XXX: typically only one instruction between  %% the mtlr and the blr, ouch  restore_lr(FPoff, Context,	     adjust_sp(FPoff + word_size() * context_arity(Context),		       [I])).restore_lr(FPoff, Context, Rest) ->  case context_clobbers_lr(Context) of    false -> Rest;    true ->      LR = hipe_arm:mk_lr(),      mk_load('ldr', LR, FPoff - word_size(), mk_sp(),	      Rest)  end.adjust_sp(N, Rest) ->  if N =:= 0 ->      Rest;     true ->      SP = mk_sp(),      hipe_arm:mk_addi(SP, SP, N, Rest)  end.%%%%%% Recursive calls.%%%do_pseudo_call_prepare(I, FPoff0) ->  %% Create outgoing arguments area on the stack.  NrStkArgs = hipe_arm:pseudo_call_prepare_nrstkargs(I),  Offset = NrStkArgs * word_size(),  {adjust_sp(-Offset, []), FPoff0 + Offset}.do_pseudo_call(I, LiveOut, Context, FPoff0) ->  #arm_sdesc{exnlab=ExnLab,arity=OrigArity} = hipe_arm:pseudo_call_sdesc(I),  FunV = hipe_arm:pseudo_call_funv(I),  LiveTemps = [Temp || Temp <- LiveOut, temp_is_pseudo(Temp)],  SDesc = mk_sdesc(ExnLab, Context, LiveTemps),  ContLab = hipe_arm:pseudo_call_contlab(I),  Linkage = hipe_arm:pseudo_call_linkage(I),  CallCode = [hipe_arm:mk_pseudo_call(FunV, SDesc, ContLab, Linkage)],  StkArity = max(0, OrigArity - hipe_arm_registers:nr_args()),  context_need_stack(Context, stack_need(FPoff0, StkArity, FunV)),  ArgsBytes = word_size() * StkArity,  {CallCode, FPoff0 - ArgsBytes}.stack_need(FPoff, StkArity, FunV) ->  case FunV of    #arm_prim{} -> FPoff;    #arm_mfa{m=M,f=F,a=A} ->      case erlang:is_builtin(M, F, A) of	true -> FPoff;	false -> stack_need_general(FPoff, StkArity)      end;    _ -> stack_need_general(FPoff, StkArity)  end.stack_need_general(FPoff, StkArity) ->  max(FPoff, FPoff + (?ARM_LEAF_WORDS - StkArity) * word_size()).%%%%%% Create stack descriptors for call sites.%%%mk_sdesc(ExnLab, Context, Temps) ->	% for normal calls  Temps0 = only_tagged(Temps),  Live = mk_live(Context, Temps0),  Arity = context_arity(Context),  FSize = context_framesize(Context),  hipe_arm:mk_sdesc(ExnLab, (FSize div word_size())-1, Arity,                    list_to_tuple(Live)).only_tagged(Temps)->  [X || X <- Temps, hipe_arm:temp_type(X) =:= 'tagged'].mk_live(Context, Temps) ->  lists:sort([temp_to_slot(Context, Temp) || Temp <- Temps]).temp_to_slot(Context, Temp) ->  (context_framesize(Context) + context_offset(Context, Temp))    div word_size().mk_minimal_sdesc(Context) ->		% for inc_stack_0 calls  hipe_arm:mk_sdesc([], 0, context_arity(Context), {}).%%%%%% Tailcalls.%%%do_pseudo_tailcall(I, Context) -> % always at FPoff=context_framesize(Context)  Arity = context_arity(Context),  Args = hipe_arm:pseudo_tailcall_stkargs(I),  FunV = hipe_arm:pseudo_tailcall_funv(I),  Linkage = hipe_arm:pseudo_tailcall_linkage(I),  {Insns, FPoff1} = do_tailcall_args(Args, Context),  context_need_stack(Context, FPoff1),  StkArity = length(Args),  FPoff2 = FPoff1 + (Arity - StkArity) * word_size(),  context_need_stack(Context, stack_need(FPoff2, StkArity, FunV)),  I2 =    case FunV of      #arm_temp{} ->	hipe_arm:mk_bx(FunV);      Fun ->	hipe_arm:mk_b_fun(Fun, Linkage)    end,  %% XXX: break out the LR restore, just like for pseudo_blr?  restore_lr(context_framesize(Context), Context,	     Insns ++ adjust_sp(FPoff2, [I2])).do_tailcall_args(Args, Context) ->  FPoff0 = context_framesize(Context),  Arity = context_arity(Context),  FrameTop = word_size()*Arity,  DangerOff = FrameTop - word_size()*length(Args),  %%  Moves = mk_moves(Args, FrameTop, []),  %%  {Stores, Simple, Conflict} =    split_moves(Moves, Context, DangerOff, [], [], []),  %% sanity check (shouldn't trigger any more)  if DangerOff < -FPoff0 ->      exit({?MODULE,do_tailcall_args,DangerOff,-FPoff0});     true -> []  end,  FPoff1 = FPoff0,  %%  {Pushes, Pops, FPoff2} = split_conflict(Conflict, FPoff1, [], []),  %%  TempReg = hipe_arm_registers:temp1(),  %%  {adjust_sp(-(FPoff2 - FPoff1),	     simple_moves(Pushes, FPoff2, TempReg,			  store_moves(Stores, FPoff2, TempReg,				      simple_moves(Simple, FPoff2, TempReg,						   simple_moves(Pops, FPoff2, TempReg,								[]))))),   FPoff2}.mk_moves([Arg|Args], Off, Moves) ->  Off1 = Off - word_size(),  mk_moves(Args, Off1, [{Arg,Off1}|Moves]);mk_moves([], _, Moves) ->  Moves.split_moves([Move|Moves], Context, DangerOff, Stores, Simple, Conflict) ->  {Src,DstOff} = Move,  case src_is_pseudo(Src) of    false ->      split_moves(Moves, Context, DangerOff, [Move|Stores],		  Simple, Conflict);    true ->      SrcOff = context_offset(Context, Src),      Type = typeof_temp(Src),      if SrcOff =:= DstOff ->	  split_moves(Moves, Context, DangerOff, Stores,		      Simple, Conflict);	 SrcOff >= DangerOff ->	  split_moves(Moves, Context, DangerOff, Stores,		      Simple, [{SrcOff,DstOff,Type}|Conflict]);	 true ->	  split_moves(Moves, Context, DangerOff, Stores,		      [{SrcOff,DstOff,Type}|Simple], Conflict)      end  end;split_moves([], _, _, Stores, Simple, Conflict) ->  {Stores, Simple, Conflict}.split_conflict([{SrcOff,DstOff,Type}|Conflict], FPoff, Pushes, Pops) ->  FPoff1 = FPoff + word_size(),  Push = {SrcOff,-FPoff1,Type},  Pop = {-FPoff1,DstOff,Type},  split_conflict(Conflict, FPoff1, [Push|Pushes], [Pop|Pops]);split_conflict([], FPoff, Pushes, Pops) ->  {lists:reverse(Pushes), Pops, FPoff}.simple_moves([{SrcOff,DstOff,Type}|Moves], FPoff, TempReg, Rest) ->  Temp = hipe_arm:mk_temp(TempReg, Type),  SP = mk_sp(),  LoadOff = FPoff+SrcOff,  StoreOff = FPoff+DstOff,  simple_moves(Moves, FPoff, TempReg,	       mk_load('ldr', Temp, LoadOff, SP,		       mk_store('str', Temp, StoreOff, SP,				Rest)));simple_moves([], _, _, Rest) ->  Rest.store_moves([{Src,DstOff}|Moves], FPoff, TempReg, Rest) ->  %%Type = typeof_temp(Src),  SP = mk_sp(),  StoreOff = FPoff+DstOff,  {NewSrc,FixSrc} =    case hipe_arm:is_temp(Src) of      true ->	{Src, []};      _ ->	Temp = hipe_arm:mk_temp(TempReg, 'untagged'),	{Temp, hipe_arm:mk_li(Temp, Src)}    end,  store_moves(Moves, FPoff, TempReg,	      FixSrc ++ mk_store('str', NewSrc, StoreOff, SP, Rest));store_moves([], _, _, Rest) ->  Rest.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?