hipe_rtl_to_arm.erl

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

ERL
805
字号
%%% -*- erlang-indent-level: 2 -*-%%% $Id$-module(hipe_rtl_to_arm).-export([translate/1]).-include("../rtl/hipe_rtl.hrl").translate(RTL) ->  hipe_gensym:init(arm),  hipe_gensym:set_var(arm, hipe_arm_registers:first_virtual()),  hipe_gensym:set_label(arm, hipe_gensym:get_label(rtl)),  Map0 = vmap_empty(),  {Formals, Map1} = conv_formals(hipe_rtl:rtl_params(RTL), Map0),  OldData = hipe_rtl:rtl_data(RTL),  {Code0, NewData} = conv_insn_list(hipe_rtl:rtl_code(RTL), Map1, OldData),  {RegFormals,_} = split_args(Formals),  Code =    case RegFormals of      [] -> Code0;      _ -> [hipe_arm:mk_label(hipe_gensym:get_next_label(arm)) |	    move_formals(RegFormals, Code0)]    end,  IsClosure = hipe_rtl:rtl_is_closure(RTL),  IsLeaf = hipe_rtl:rtl_is_leaf(RTL),  hipe_arm:mk_defun(conv_mfa(hipe_rtl:rtl_fun(RTL)),		    Formals,		    IsClosure,		    IsLeaf,		    Code,		    NewData,		    [], 		    []).conv_insn_list([H|T], Map, Data) ->  {NewH, NewMap, NewData1} = conv_insn(H, Map, Data),  %% io:format("~w \n  ==>\n ~w\n- - - - - - - - -\n",[H,NewH]),  {NewT, NewData2} = conv_insn_list(T, NewMap, NewData1),  {NewH ++ NewT, NewData2};conv_insn_list([], _, Data) ->  {[], Data}.conv_insn(I, Map, Data) ->  case I of    #alu{} -> conv_alu(I, Map, Data);    #alub{} -> conv_alub(I, Map, Data);    #branch{} -> conv_branch(I, Map, Data);    #call{} -> conv_call(I, Map, Data);    #comment{} -> conv_comment(I, Map, Data);    #enter{} -> conv_enter(I, Map, Data);    #goto{} -> conv_goto(I, Map, Data);    #label{} -> conv_label(I, Map, Data);    #load{} -> conv_load(I, Map, Data);    #load_address{} -> conv_load_address(I, Map, Data);    #load_atom{} -> conv_load_atom(I, Map, Data);    #move{} -> conv_move(I, Map, Data);    #return{} -> conv_return(I, Map, Data);    #store{} -> conv_store(I, Map, Data);    #switch{} -> conv_switch(I, Map, Data);    _ -> exit({?MODULE,conv_insn,I})  end.conv_alu(I, Map, Data) ->  %% dst = src1 aluop src2  {Dst, Map0} = conv_dst(hipe_rtl:alu_dst(I), Map),  {Src1, Map1} = conv_src(hipe_rtl:alu_src1(I), Map0),  {Src2, Map2} = conv_src(hipe_rtl:alu_src2(I), Map1),  RtlAluOp = hipe_rtl:alu_op(I),  S = false,  I2 = mk_alu(S, Dst, Src1, RtlAluOp, Src2),  {I2, Map2, Data}.conv_shift(RtlShiftOp) ->  case RtlShiftOp of    'sll' -> 'lsl';    'srl' -> 'lsr';    'sra' -> 'asr'  end.conv_arith(RtlAluOp) -> % RtlAluOp \ RtlShiftOp -> ArmArithOp  case RtlAluOp of    'add' -> 'add';    'sub' -> 'sub';    'mul' -> 'mul';    'or'  -> 'orr';    'and' -> 'and';    'xor' -> 'eor'  end.commute_arithop(ArithOp) ->  case ArithOp of    'sub' -> 'rsb';    _ -> ArithOp  end.mk_alu(S, Dst, Src1, RtlAluOp, Src2) ->  case hipe_rtl:is_shift_op(RtlAluOp) of    true ->      mk_shift(S, Dst, Src1, conv_shift(RtlAluOp), Src2);    false ->      mk_arith(S, Dst, Src1, conv_arith(RtlAluOp), Src2)  end.mk_shift(S, Dst, Src1, ShiftOp, Src2) ->  case hipe_arm:is_temp(Src1) of    true ->      case hipe_arm:is_temp(Src2) of	true ->	  mk_shift_rr(S, Dst, Src1, ShiftOp, Src2);	_ ->	  mk_shift_ri(S, Dst, Src1, ShiftOp, Src2)      end;    _ ->      case hipe_arm:is_temp(Src2) of	true ->	  mk_shift_ir(S, Dst, Src1, ShiftOp, Src2);	_ ->	  mk_shift_ii(S, Dst, Src1, ShiftOp, Src2)      end  end.mk_shift_ii(S, Dst, Src1, ShiftOp, Src2) ->  io:format("~w: RTL alu with two immediates\n", [?MODULE]),  Tmp = new_untagged_temp(),  mk_li(Tmp, Src1,	mk_shift_ri(S, Dst, Tmp, ShiftOp, Src2)).mk_shift_ir(S, Dst, Src1, ShiftOp, Src2) ->  Tmp = new_untagged_temp(),  mk_li(Tmp, Src1,	mk_shift_rr(S, Dst, Tmp, ShiftOp, Src2)).mk_shift_ri(S, Dst, Src1, ShiftOp, Src2) when is_integer(Src2) ->  if Src2 >= 0, Src2 < 32 -> [];     true -> io:format("~w: excessive immediate shift ~w\n", [?MODULE,Src2])  end,  Am1 = {Src1,ShiftOp,Src2},  [hipe_arm:mk_move(S, Dst, Am1)].mk_shift_rr(S, Dst, Src1, ShiftOp, Src2) ->  Am1 = {Src1,ShiftOp,Src2},  [hipe_arm:mk_move(S, Dst, Am1)].mk_arith(S, Dst, Src1, ArithOp, Src2) ->  case hipe_arm:is_temp(Src1) of    true ->      case hipe_arm:is_temp(Src2) of	true ->	  mk_arith_rr(S, Dst, Src1, ArithOp, Src2);	_ ->	  mk_arith_ri(S, Dst, Src1, ArithOp, Src2)      end;    _ ->      case hipe_arm:is_temp(Src2) of	true ->	  mk_arith_ir(S, Dst, Src1, ArithOp, Src2);	_ ->	  mk_arith_ii(S, Dst, Src1, ArithOp, Src2)      end  end.mk_arith_ii(S, Dst, Src1, ArithOp, Src2) ->  io:format("~w: RTL alu with two immediates\n", [?MODULE]),  Tmp = new_untagged_temp(),  mk_li(Tmp, Src1,	mk_arith_ri(S, Dst, Tmp, ArithOp, Src2)).mk_arith_ir(S, Dst, Src1, ArithOp, Src2) ->  mk_arith_ri(S, Dst, Src2, commute_arithop(ArithOp), Src1).mk_arith_ri(S, Dst, Src1, ArithOp, Src2) ->  case ArithOp of    'mul' -> % mul/smull only take reg/reg operands      Tmp = new_untagged_temp(),      mk_li(Tmp, Src2,	    mk_arith_rr(S, Dst, Src1, ArithOp, Tmp));    _ -> % add/sub/orr/and/eor have reg/am1 operands      {FixAm1,NewArithOp,Am1} = fix_aluop_imm(ArithOp, Src2),      FixAm1 ++ [hipe_arm:mk_alu(NewArithOp, S, Dst, Src1, Am1)]  end.mk_arith_rr(S, Dst, Src1, ArithOp, Src2) ->  case {ArithOp,S} of    {'mul',true} ->      %% To check for overflow in 32x32->32 multiplication:      %% smull Dst,TmpHi,Src1,Src2      %% mov TmpSign,Dst,ASR #31      %% cmp TmpSign,TmpHi      %% [bne OverflowLabel]      TmpHi = new_untagged_temp(),      TmpSign = new_untagged_temp(),      [hipe_arm:mk_smull(Dst, TmpHi, Src1, Src2),       hipe_arm:mk_move(TmpSign, {Dst,'asr',31}),       hipe_arm:mk_cmp('cmp', TmpSign, TmpHi)];    _ ->      [hipe_arm:mk_alu(ArithOp, S, Dst, Src1, Src2)]  end.fix_aluop_imm(AluOp, Imm) -> % {FixAm1,NewAluOp,Am1}  case hipe_arm:try_aluop_imm(AluOp, Imm) of    {NewAluOp,Am1} -> {[], NewAluOp, Am1};    [] ->      Tmp = new_untagged_temp(),      {mk_li(Tmp, Imm), AluOp, Tmp}  end.conv_alub(I, Map, Data) ->  %% dst = src1 aluop src2; if COND goto label  {Dst, Map0} = conv_dst(hipe_rtl:alub_dst(I), Map),  {Src1, Map1} = conv_src(hipe_rtl:alub_src1(I), Map0),  {Src2, Map2} = conv_src(hipe_rtl:alub_src2(I), Map1),  RtlAluOp = hipe_rtl:alub_op(I),  Cond0 = conv_alub_cond(hipe_rtl:alub_cond(I)),  Cond =    case {RtlAluOp,Cond0} of      {'mul','vs'} -> 'ne';	% overflow becomes not-equal      {'mul','vc'} -> 'eq';	% no-overflow becomes equal      {'mul',_} -> exit({?MODULE,I});      {_,_} -> Cond0    end,  I2 = mk_pseudo_bc(	  Cond,	  hipe_rtl:alub_true_label(I),	  hipe_rtl:alub_false_label(I),	  hipe_rtl:alub_pred(I)),  S = true,  I1 = mk_alu(S, Dst, Src1, RtlAluOp, Src2),  {I1 ++ I2, Map2, Data}.conv_branch(I, Map, Data) ->  %% <unused> = src1 - src2; if COND goto label  {Src1, Map0} = conv_src(hipe_rtl:branch_src1(I), Map),  {Src2, Map1} = conv_src(hipe_rtl:branch_src2(I), Map0),  Cond = conv_branch_cond(hipe_rtl:branch_cond(I)),  I2 = mk_branch(Src1, Cond, Src2,		 hipe_rtl:branch_true_label(I),		 hipe_rtl:branch_false_label(I),		 hipe_rtl:branch_pred(I)),  {I2, Map1, Data}.mk_branch(Src1, Cond, Src2, TrueLab, FalseLab, Pred) ->  case hipe_arm:is_temp(Src1) of    true ->      case hipe_arm:is_temp(Src2) of	true ->	  mk_branch_rr(Src1, Src2, Cond, TrueLab, FalseLab, Pred);	_ ->	  mk_branch_ri(Src1, Cond, Src2, TrueLab, FalseLab, Pred)      end;    _ ->      case hipe_arm:is_temp(Src2) of	true ->	  NewCond = commute_cond(Cond),	  mk_branch_ri(Src2, NewCond, Src1, TrueLab, FalseLab, Pred);	_ ->	  mk_branch_ii(Src1, Cond, Src2, TrueLab, FalseLab, Pred)      end  end.mk_branch_ii(Imm1, Cond, Imm2, TrueLab, FalseLab, Pred) ->  io:format("~w: RTL branch with two immediates\n", [?MODULE]),  Tmp = new_untagged_temp(),  mk_li(Tmp, Imm1,	mk_branch_ri(Tmp, Cond, Imm2,		     TrueLab, FalseLab, Pred)).mk_branch_ri(Src, Cond, Imm, TrueLab, FalseLab, Pred) ->  {FixAm1,NewCmpOp,Am1} = fix_aluop_imm('cmp', Imm),  FixAm1 ++ mk_cmp_bc(NewCmpOp, Src, Am1, Cond, TrueLab, FalseLab, Pred).mk_branch_rr(Src1, Src2, Cond, TrueLab, FalseLab, Pred) ->  mk_cmp_bc('cmp', Src1, Src2, Cond, TrueLab, FalseLab, Pred).mk_cmp_bc(CmpOp, Src, Am1, Cond, TrueLab, FalseLab, Pred) ->  [hipe_arm:mk_cmp(CmpOp, Src, Am1) |   mk_pseudo_bc(Cond, TrueLab, FalseLab, Pred)].conv_call(I, Map, Data) ->  {Args, Map0} = conv_src_list(hipe_rtl:call_arglist(I), Map),  {Dsts, Map1} = conv_dst_list(hipe_rtl:call_dstlist(I), Map0),  {Fun, Map2} = conv_fun(hipe_rtl:call_fun(I), Map1),  ContLab = hipe_rtl:call_continuation(I),  ExnLab = hipe_rtl:call_fail(I),  Linkage = hipe_rtl:call_type(I),  I2 = mk_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage),  {I2, Map2, Data}.mk_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage) ->  case hipe_arm:is_prim(Fun) of    true ->      mk_primop_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage);    false ->      mk_general_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage)  end.mk_primop_call(Dsts, Prim, Args, ContLab, ExnLab, Linkage) ->  case hipe_arm:prim_prim(Prim) of    %% no ARM-specific primops defined yet    _ ->      mk_general_call(Dsts, Prim, Args, ContLab, ExnLab, Linkage)  end.mk_general_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage) ->  %% The backend does not support pseudo_calls without a  %% continuation label, so we make sure each call has one.  {RealContLab, Tail} =    case mk_call_results(Dsts) of      [] ->	%% Avoid consing up a dummy basic block if the moves list	%% is empty, as is typical for calls to suspend/0.	%% This should be subsumed by a general "optimise the CFG"	%% module, and could probably be removed.	case ContLab of	  [] ->	    NewContLab = hipe_gensym:get_next_label(arm),	    {NewContLab, [hipe_arm:mk_label(NewContLab)]};	  _ ->	    {ContLab, []}	end;      Moves ->	%% Change the call to continue at a new basic block.	%% In this block move the result registers to the Dsts,	%% then continue at the call's original continuation.	NewContLab = hipe_gensym:get_next_label(arm),	case ContLab of	  [] ->	    %% This is just a fallthrough	    %% No jump back after the moves.	    {NewContLab,	     [hipe_arm:mk_label(NewContLab) |	      Moves]};	  _ ->	    %% The call has a continuation. Jump to it.	    {NewContLab,	     [hipe_arm:mk_label(NewContLab) |	      Moves ++	      [hipe_arm:mk_b_label(ContLab)]]}	end    end,  SDesc = hipe_arm:mk_sdesc(ExnLab, 0, length(Args), {}),  CallInsn = hipe_arm:mk_pseudo_call(Fun, SDesc, RealContLab, Linkage),  {RegArgs,StkArgs} = split_args(Args),  mk_push_args(StkArgs, move_actuals(RegArgs, [CallInsn | Tail])).mk_call_results([]) ->  [];mk_call_results([Dst]) ->  RV = hipe_arm:mk_temp(hipe_arm_registers:return_value(), 'tagged'),  [hipe_arm:mk_pseudo_move(Dst, RV)];mk_call_results(Dsts) ->  exit({?MODULE,mk_call_results,Dsts}).mk_push_args(StkArgs, Tail) ->  case length(StkArgs) of    0 ->      Tail;    NrStkArgs ->      [hipe_arm:mk_pseudo_call_prepare(NrStkArgs) |       mk_store_args(StkArgs, NrStkArgs * word_size(), Tail)]  end.  mk_store_args([Arg|Args], PrevOffset, Tail) ->  Offset = PrevOffset - word_size(),  {Src,FixSrc} =    case hipe_arm:is_temp(Arg) of      true ->	{Arg, []};      _ ->	Tmp = new_tagged_temp(),	{Tmp, mk_li(Tmp, Arg)}    end,  NewTail = hipe_arm:mk_store('str', Src, mk_sp(), Offset, 'new', Tail),  mk_store_args(Args, Offset, FixSrc ++ NewTail);mk_store_args([], _, Tail) ->  Tail.conv_comment(I, Map, Data) ->  I2 = [hipe_arm:mk_comment(hipe_rtl:comment_text(I))],  {I2, Map, Data}.conv_enter(I, Map, Data) ->  {Args, Map0} = conv_src_list(hipe_rtl:enter_arglist(I), Map),  {Fun, Map1} = conv_fun(hipe_rtl:enter_fun(I), Map0),  I2 = mk_enter(Fun, Args, hipe_rtl:enter_type(I)),  {I2, Map1, Data}.mk_enter(Fun, Args, Linkage) ->  Arity = length(Args),  {RegArgs,StkArgs} = split_args(Args),  move_actuals(RegArgs,	       [hipe_arm:mk_pseudo_tailcall_prepare(),		hipe_arm:mk_pseudo_tailcall(Fun, Arity, StkArgs, Linkage)]).conv_goto(I, Map, Data) ->  I2 = [hipe_arm:mk_b_label(hipe_rtl:goto_label(I))],  {I2, Map, Data}.conv_label(I, Map, Data) ->  I2 = [hipe_arm:mk_label(hipe_rtl:label_name(I))],  {I2, Map, Data}.conv_load(I, Map, Data) ->  {Dst, Map0} = conv_dst(hipe_rtl:load_dst(I), Map),

⌨️ 快捷键说明

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