hipe_arm_assemble.erl

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

ERL
650
字号
%%% -*- erlang-indent-level: 2 -*-%%% $Id$%%%-module(hipe_arm_assemble).-export([assemble/4]).-include("../main/hipe.hrl").	% for VERSION_STRING, when_option-include("hipe_arm.hrl").-include("../../kernel/src/hipe_ext_format.hrl").-include("../rtl/hipe_literals.hrl").-undef(ASSERT).-define(ASSERT(G), if G -> [] ; true -> exit({assertion_failed,?MODULE,?LINE,??G}) end).assemble(CompiledCode, Closures, Exports, Options) ->  print("****************** Assembling *******************\n", [], Options),  %%  Code = [{MFA,	   hipe_arm:defun_code(Defun),	   hipe_arm:defun_data(Defun)}	  || {MFA, Defun} <- CompiledCode],  %%  {ConstAlign,ConstSize,ConstMap,RefsFromConsts} =    hipe_pack_constants:pack_constants(Code, 4),  %%  {CodeSize,CodeBinary,AccRefs,LabelMap,ExportMap} =    encode(translate(Code, ConstMap), Options),  print("Total num bytes=~w\n", [CodeSize], Options),  %%  SC = hipe_pack_constants:slim_constmap(ConstMap),  DataRelocs = mk_data_relocs(RefsFromConsts, LabelMap),  SSE = slim_sorted_exportmap(ExportMap,Closures,Exports),  SlimRefs = hipe_pack_constants:slim_refs(AccRefs),  Bin = term_to_binary([{?VERSION_STRING(),?HIPE_SYSTEM_CRC},			ConstAlign, ConstSize,			SC,			DataRelocs, % nee LM, LabelMap			SSE,			CodeSize,CodeBinary,SlimRefs,			0,[] % ColdCodeSize, SlimColdRefs		       ]),  %%  Bin.%%%%%% Assembly Pass 1.%%% Process initial {MFA,Code,Data} list.%%% Translate each MFA's body, choosing operand & instruction kinds.%%% Manage placement of large immediates in the code segment. (ARM-specific)%%%%%% Assembly Pass 2.%%% Perform short/long form optimisation for jumps.%%% (Trivial on ARM.)%%%%%% Result is {MFA,NewCode,CodeSize,LabelMap} list.%%%translate(Code, ConstMap) ->  translate_mfas(Code, ConstMap, []).translate_mfas([{MFA,Insns,_Data}|Code], ConstMap, NewCode) ->  {NewInsns,CodeSize,LabelMap} = translate_insns(Insns, MFA, ConstMap),  translate_mfas(Code, ConstMap, [{MFA,NewInsns,CodeSize,LabelMap}|NewCode]);translate_mfas([], _ConstMap, NewCode) ->  lists:reverse(NewCode).translate_insns(Insns, MFA, ConstMap) ->  translate_insns(Insns, MFA, ConstMap, gb_trees:empty(), 0, [],		  previous_empty(), pending_empty()).translate_insns([I|Insns], MFA, ConstMap, LabelMap, Address, NewInsns, PrevImms, PendImms) ->  IsNotFallthroughInsn = is_not_fallthrough_insn(I),  MustFlushPending = must_flush_pending(PendImms, Address),  {NewIs,Insns1,PendImms1,DoFlushPending} =    case {MustFlushPending,IsNotFallthroughInsn} of      {true,false} ->	%% To avoid having to create new symbolic labels, which is problematic	%% in the assembler, we emit a forward branch with an offset computed	%% from the size of the pending literals.	N = pending_size(PendImms),	% N >= 1 since MustFlushPending is true	BranchOffset = N - 1,		% in units of 32-bit words!	NewIs0 = [{b, {do_cond('al'),{imm24,BranchOffset}}, #comment{term='skip'}}],	%% io:format("~w: forced flush of pending literals in ~w at ~w\n", [?MODULE,MFA,Address]),	{NewIs0,[I|Insns],PendImms,true};      {_,_} ->	{NewIs0,PendImms0} = translate_insn(I, MFA, ConstMap, Address, PrevImms, PendImms),	{NewIs0,Insns,PendImms0,IsNotFallthroughInsn}    end,  add_insns(NewIs, Insns1, MFA, ConstMap, LabelMap, Address, NewInsns, PrevImms, PendImms1, DoFlushPending);translate_insns([], _MFA, _ConstMap, LabelMap, Address, NewInsns, PrevImms, PendImms) ->  {LabelMap1, Address1, NewInsns1, _PrevImms1} = % at end-of-function we ignore PrevImms1    flush_pending(PendImms, LabelMap, Address, NewInsns, PrevImms),  {lists:reverse(NewInsns1), Address1, LabelMap1}.add_insns([I|Is], Insns, MFA, ConstMap, LabelMap, Address, NewInsns, PrevImms, PendImms, DoFlushPending) ->  NewLabelMap =    case I of      {'.label',L,_} ->	gb_trees:insert(L, Address, LabelMap);      _ ->	LabelMap    end,  Address1 = Address + insn_size(I),  add_insns(Is, Insns, MFA, ConstMap, NewLabelMap, Address1, [I|NewInsns], PrevImms, PendImms, DoFlushPending);add_insns([], Insns, MFA, ConstMap, LabelMap, Address, NewInsns, PrevImms, PendImms, DoFlushPending) ->  {LabelMap1, Address1, NewInsns1, PrevImms1, PendImms1} =    case DoFlushPending of      true ->	{LabelMap0,Address0,NewInsns0,PrevImms0} =	  flush_pending(PendImms, LabelMap, Address, NewInsns, PrevImms),	{LabelMap0,Address0,NewInsns0,PrevImms0,pending_empty()};      false ->	PrevImms0 = expire_previous(PrevImms, Address),	{LabelMap,Address,NewInsns,PrevImms0,PendImms}    end,  translate_insns(Insns, MFA, ConstMap, LabelMap1, Address1, NewInsns1, PrevImms1, PendImms1).must_flush_pending(PendImms, Address) ->  case pending_firstref(PendImms) of    [] -> false;    LP0 ->      Distance = Address - LP0,      %% In "LP0: ldr R,[PC +/- imm12]", the PC value is LP0+8 so the      %% range for the ldr is [LP0-4084, LP0+4100] (32-bit alignment!).      %% LP0+4096 is the last point where we can emit a branch (4 bytes)      %% followed by the pending immediates.      %%      %% The translation of an individual instruction must not advance      %% . by more than 4 bytes, because that could cause us to miss      %% the point where PendImms must be flushed.      ?ASSERT(Distance =< 4096),      Distance =:= 4096  end.flush_pending(PendImms, LabelMap, Address, Insns, PrevImms) ->  Address1 = Address + 4*pending_size(PendImms),  PrevImms1 = expire_previous(PrevImms, Address1),  {LabelMap1,Address1,Insns1,PrevImms2} =    flush_pending2(pending_to_list(PendImms), LabelMap, Address, Insns, PrevImms1),  PrevImms3 = expire_previous(PrevImms2, Address1),  {LabelMap1,Address1,Insns1,PrevImms3}.flush_pending2([{Lab,RelocOrInt,Imm}|Imms], LabelMap, Address, Insns, PrevImms) ->  PrevImms1 = previous_append(PrevImms, Address, Lab, Imm),  LabelMap1 = gb_trees:insert(Lab, Address, LabelMap),  {RelocOpt,LongVal} =    if is_integer(RelocOrInt) ->	{[],RelocOrInt};       true ->	{[RelocOrInt],0}    end,  Insns1 =    [{'.long', LongVal, #comment{term=Imm}} |     RelocOpt ++     [{'.label', Lab, #comment{term=Imm}} |      Insns]],  flush_pending2(Imms, LabelMap1, Address+4, Insns1, PrevImms1);flush_pending2([], LabelMap, Address, Insns, PrevImms) ->  {LabelMap, Address, Insns, PrevImms}.expire_previous(PrevImms, CodeAddress) ->  case previous_findmin(PrevImms) of    [] -> PrevImms;    {ImmAddress,_Imm} ->      if CodeAddress - ImmAddress > 4084 ->	  expire_previous(previous_delmin(PrevImms), CodeAddress);	 true ->	  PrevImms      end  end.is_not_fallthrough_insn(I) ->  case I of    #b_fun{} -> true;    #b_label{'cond'='al'} -> true;    %% bl and blx are not included since they return to ".+4"    %% a load to PC was originally a pseudo_switch insn    #load{dst=#arm_temp{reg=15,type=Type}} when Type =/= 'double' -> true;    %% a move to PC was originally a pseudo_blr or pseudo_bx insn    #move{dst=#arm_temp{reg=15,type=Type}} when Type =/= 'double' -> true;    _ -> false  end.insn_size(I) ->  case I of    {'.label',_,_} -> 0;    {'.reloc',_,_} -> 0;    _ -> 4  end.translate_insn(I, MFA, ConstMap, Address, PrevImms, PendImms) ->  case I of    %% pseudo_li is the only insn using MFA, ConstMap, Address, PrevImms, or PendLits    #pseudo_li{} -> do_pseudo_li(I, MFA, ConstMap, Address, PrevImms, PendImms);    _ -> {translate_insn(I), PendImms}  end.translate_insn(I) ->	% -> [{Op,Opnd,OrigI}]  case I of    #alu{} -> do_alu(I);    #b_fun{} -> do_b_fun(I);    #b_label{} -> do_b_label(I);    #bl{} -> do_bl(I);    #blx{} -> do_blx(I);    #cmp{} -> do_cmp(I);    #comment{} -> [];    #label{} -> do_label(I);    #load{} -> do_load(I);    #ldrsb{} -> do_ldrsb(I);    #move{} -> do_move(I);    %% pseudo_b: eliminated by finalise    %% pseudo_blr: eliminated by finalise    %% pseudo_call: eliminated by finalise    %% pseudo_call_prepare: eliminated by frame    %% pseudo_li: handled separately    %% pseudo_move: eliminated by frame    %% pseudo_switch: eliminated by finalise    %% pseudo_tailcall: eliminated by frame    %% pseudo_tailcall_prepare: eliminated by finalise    #smull{} -> do_smull(I);    #store{} -> do_store(I)  end.do_alu(I) ->  #alu{aluop=AluOp,s=S,dst=Dst,src=Src,am1=Am1} = I,  NewCond = do_cond('al'),  NewS = do_s(S),  NewDst = do_reg(Dst),  NewSrc = do_reg(Src),  NewAm1 = do_am1(Am1),  {NewI,NewOpnds} = {AluOp, {NewCond,NewS,NewDst,NewSrc,NewAm1}},  [{NewI, NewOpnds, I}].do_b_fun(I) ->  #b_fun{'fun'=Fun,linkage=Linkage} = I,  [{'.reloc', {b_fun,Fun,Linkage}, #comment{term='fun'}},   {b, {do_cond('al'),{imm24,0}}, I}].do_b_label(I) ->  #b_label{'cond'=Cond,label=Label} = I,  [{b, {do_cond(Cond),do_label_ref(Label)}, I}].do_bl(I) ->  #bl{'fun'=Fun,sdesc=SDesc,linkage=Linkage} = I,  [{'.reloc', {b_fun,Fun,Linkage}, #comment{term='fun'}},   {bl, {do_cond('al'),{imm24,0}}, I},   {'.reloc', {sdesc,SDesc}, #comment{term=sdesc}}].do_blx(I) ->  #blx{src=Src,sdesc=SDesc} = I,  [{blx, {do_cond('al'),do_reg(Src)}, I},   {'.reloc', {sdesc,SDesc}, #comment{term=sdesc}}].do_cmp(I) ->  #cmp{cmpop=CmpOp,src=Src,am1=Am1} = I,  NewCond = do_cond('al'),  NewSrc = do_reg(Src),  NewAm1 = do_am1(Am1),  [{CmpOp, {NewCond,NewSrc,NewAm1}, I}].do_label(I) ->  #label{label=Label} = I,  [{'.label', Label, I}].do_load(I) ->  #load{ldop=LdOp,dst=Dst,am2=Am2} = I,  NewCond = do_cond('al'),  NewDst = do_reg(Dst),  NewAm2 = do_am2(Am2),  [{LdOp, {NewCond,NewDst,NewAm2}, I}].do_ldrsb(I) ->  #ldrsb{dst=Dst,am3=Am3} = I,  NewCond = do_cond('al'),  NewDst = do_reg(Dst),  NewAm3 = do_am3(Am3),  [{'ldrsb', {NewCond,NewDst,NewAm3}, I}].do_move(I) ->  #move{movop=MovOp,s=S,dst=Dst,am1=Am1} = I,  NewCond = do_cond('al'),  NewS = do_s(S),  NewDst = do_reg(Dst),  NewAm1 = do_am1(Am1),  [{MovOp, {NewCond,NewS,NewDst,NewAm1}, I}].do_pseudo_li(I, MFA, ConstMap, Address, PrevImms, PendImms) ->  #pseudo_li{dst=Dst,imm=Imm,label=Label0} = I,  {Label1,PendImms1} =    case previous_lookup(PrevImms, Imm) of      {value,Lab} -> {Lab,PendImms};      none ->	case pending_lookup(PendImms, Imm) of	  {value,Lab} -> {Lab,PendImms};	  none ->	    RelocOrInt =	      if is_integer(Imm) ->		  %% This is for immediates that require too much work		  %% to reconstruct using only arithmetic instructions.		  Imm;		 true ->		  RelocData =		    case Imm of		      Atom when is_atom(Atom) ->			{load_atom, Atom};		      {Label,constant} ->			ConstNo = find_const({MFA,Label}, ConstMap),			{load_address, {constant,ConstNo}};		      {Label,closure} ->			{load_address, {closure,Label}};		      {Label,c_const} ->			{load_address, {c_const,Label}}		    end,		  {'.reloc', RelocData, #comment{term=reloc}}	      end,	    Lab = Label0, % preallocated: creating labels in the assembler doesn't work	    {Lab, pending_append(PendImms, Address, Lab, RelocOrInt, Imm)}	end    end,  NewDst = do_reg(Dst),  {[{'.pseudo_li', {NewDst,do_label_ref(Label1)}, I}], PendImms1}.do_smull(I) ->  #smull{dstlo=DstLo,dsthi=DstHi,src1=Src1,src2=Src2} = I,  NewCond = do_cond('al'),

⌨️ 快捷键说明

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