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 + -
显示快捷键?