hipe_arm_frame.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 630 行 · 第 1/2 页
ERL
630 行
%%%%%% Contexts%%%-record(context, {liveness, framesize, arity, map, clobbers_lr, ref_maxstack}).mk_context(Liveness, Formals, Temps, ClobbersLR) -> {Map, MinOff} = mk_temp_map(Formals, ClobbersLR, Temps), FrameSize = (-MinOff), RefMaxStack = hipe_bifs:ref(FrameSize), Context = #context{liveness=Liveness, framesize=FrameSize, arity=length(Formals), map=Map, clobbers_lr=ClobbersLR, ref_maxstack=RefMaxStack}, Context.context_need_stack(#context{ref_maxstack=RM}, N) -> M = hipe_bifs:ref_get(RM), if N > M -> hipe_bifs:ref_set(RM, N); true -> [] end.context_maxstack(#context{ref_maxstack=RM}) -> hipe_bifs:ref_get(RM).context_arity(#context{arity=Arity}) -> Arity.context_framesize(#context{framesize=FrameSize}) -> FrameSize.context_liveness(#context{liveness=Liveness}) -> Liveness.context_offset(#context{map=Map}, Temp) -> tmap_lookup(Map, Temp).context_clobbers_lr(#context{clobbers_lr=ClobbersLR}) -> ClobbersLR.mk_temp_map(Formals, ClobbersLR, Temps) -> {Map, 0} = enter_vars(Formals, word_size() * length(Formals), tmap_empty()), TempsList = tset_to_list(Temps), AllTemps = case ClobbersLR of false -> TempsList; true -> RA = hipe_arm:mk_new_temp('untagged'), [RA|TempsList] end, enter_vars(AllTemps, 0, Map).enter_vars([V|Vs], PrevOff, Map) -> Off = case hipe_arm:temp_type(V) of 'double' -> PrevOff - 2*word_size(); _ -> PrevOff - word_size() end, enter_vars(Vs, Off, tmap_bind(Map, V, Off));enter_vars([], Off, Map) -> {Map, Off}.tmap_empty() -> gb_trees:empty().tmap_bind(Map, Key, Val) -> gb_trees:insert(Key, Val, Map).tmap_lookup(Map, Key) -> gb_trees:get(Key, Map).%%%%%% do_prologue: prepend stack frame allocation code.%%%%%% NewStart:%%% temp1 = *(P + P_SP_LIMIT)%%% temp2 = SP - MaxStack%%% cmp temp2, Temp1%%% if (ltu) goto IncStack else goto AllocFrame%%% AllocFrame:%%% SP -= FrameSize%%% *(SP + FrameSize-WordSize) = LR [if ClobbersLR]%%% goto OldStart%%% OldStart:%%% ...%%% IncStack:%%% temp1 = LR%%% bl inc_stack%%% LR = temp1%%% goto NewStartdo_prologue(CFG, Context) -> MaxStack = context_maxstack(Context), if MaxStack > 0 -> FrameSize = context_framesize(Context), OldStartLab = hipe_arm_cfg:start_label(CFG), NewStartLab = hipe_gensym:get_next_label(arm), %% P = hipe_arm:mk_temp(hipe_arm_registers:proc_pointer(), 'untagged'), Temp1 = mk_temp1(), SP = mk_sp(), %% LR = hipe_arm:mk_lr(), ClobbersLR = context_clobbers_lr(Context), GotoOldStartCode = [hipe_arm:mk_b_label(OldStartLab)], AllocFrameCodeTail = case ClobbersLR of false -> GotoOldStartCode; true -> mk_store('str', LR, FrameSize-word_size(), SP, GotoOldStartCode) end, %% Arity = context_arity(Context), Guaranteed = max(0, (?ARM_LEAF_WORDS - Arity) * word_size()), %% {CFG1,NewStartCode} = if MaxStack =< Guaranteed -> %% io:format("~w: MaxStack ~w =< Guaranteed ~w :-)\n", [?MODULE,MaxStack,Guaranteed]), AllocFrameCode = adjust_sp(-FrameSize, AllocFrameCodeTail), NewStartCode0 = AllocFrameCode, % no mflr needed {CFG,NewStartCode0}; true -> %% io:format("~w: MaxStack ~w > Guaranteed ~w :-(\n", [?MODULE,MaxStack,Guaranteed]), AllocFrameLab = hipe_gensym:get_next_label(arm), IncStackLab = hipe_gensym:get_next_label(arm), Temp2 = mk_temp2(), %% NewStartCodeTail2 = [hipe_arm:mk_pseudo_bc('lo', IncStackLab, AllocFrameLab, 0.01)], NewStartCodeTail1 = NewStartCodeTail2, % no mflr needed NewStartCode0 = mk_load('ldr', Temp1, ?P_NSP_LIMIT, P, hipe_arm:mk_addi(Temp2, SP, -MaxStack, [hipe_arm:mk_cmp('cmp', Temp2, Temp1) | NewStartCodeTail1])), %% AllocFrameCode = if MaxStack =:= FrameSize -> %% io:format("~w: MaxStack =:= FrameSize =:= ~w :-)\n", [?MODULE,MaxStack]), [hipe_arm:mk_move(SP, Temp2) | AllocFrameCodeTail]; true -> %% io:format("~w: MaxStack ~w =/= FrameSize ~w :-(\n", [?MODULE,MaxStack,FrameSize]), adjust_sp(-FrameSize, AllocFrameCodeTail) end, %% IncStackCodeTail = [hipe_arm:mk_bl(hipe_arm:mk_prim('inc_stack_0'), mk_minimal_sdesc(Context), not_remote), hipe_arm:mk_mtlr(Temp1), hipe_arm:mk_b_label(NewStartLab)], IncStackCode = [hipe_arm:mk_mflr(Temp1) | IncStackCodeTail], % mflr always needed %% CFG0a = hipe_arm_cfg:bb_add(CFG, AllocFrameLab, hipe_bb:mk_bb(AllocFrameCode)), CFG0b = hipe_arm_cfg:bb_add(CFG0a, IncStackLab, hipe_bb:mk_bb(IncStackCode)), %% {CFG0b,NewStartCode0} end, %% CFG2 = hipe_arm_cfg:bb_add(CFG1, NewStartLab, hipe_bb:mk_bb(NewStartCode)), hipe_arm_cfg:start_label_update(CFG2, NewStartLab); true -> CFG end.%%% Create a load instruction.%%% May clobber Dst early for large offsets. In principle we could%%% clobber TEMP2 if Dst =:= Base, but Dst =/= Base here in frame.mk_load(LdOp, Dst, Offset, Base, Rest) -> hipe_arm:mk_load(LdOp, Dst, Base, Offset, 'error', Rest).%%% Create a store instruction.%%% May clobber TEMP2 for large offsets.mk_store(StOp, Src, Offset, Base, Rest) -> hipe_arm:mk_store(StOp, Src, Base, Offset, 'temp2', Rest).%%% typeof_temp -- what's temp's type?typeof_temp(Temp) -> hipe_arm:temp_type(Temp).%%% Cons up an 'SP' Temp.mk_sp() -> hipe_arm:mk_temp(hipe_arm_registers:stack_pointer(), 'untagged').%%% Cons up a 'TEMP1' Temp.mk_temp1() -> hipe_arm:mk_temp(hipe_arm_registers:temp1(), 'untagged').%%% Cons up a 'TEMP2' Temp.mk_temp2() -> hipe_arm:mk_temp(hipe_arm_registers:temp2(), 'untagged').%%% Check if an operand is a pseudo-Temp.src_is_pseudo(Src) -> case hipe_arm:is_temp(Src) of true -> temp_is_pseudo(Src); _ -> false end.temp_is_pseudo(Temp) -> not(hipe_arm:temp_is_precoloured(Temp)).%%%%%% Detect if a Defun's body clobbers LR.%%%clobbers_lr(Insns) -> LRreg = hipe_arm_registers:lr(), LRtagged = hipe_arm:mk_temp(LRreg, 'tagged'), LRuntagged = hipe_arm:mk_temp(LRreg, 'untagged'), clobbers_lr(Insns, LRtagged, LRuntagged).clobbers_lr([I|Insns], LRtagged, LRuntagged) -> Defs = hipe_arm_defuse:insn_def_gpr(I), case lists:member(LRtagged, Defs) of true -> true; false -> case lists:member(LRuntagged, Defs) of true -> true; false -> clobbers_lr(Insns, LRtagged, LRuntagged) end end;clobbers_lr([], _LRtagged, _LRuntagged) -> false.%%%%%% Build the set of all temps used in a Defun's body.%%%all_temps(Code, Formals) -> S0 = find_temps(Code, tset_empty()), S1 = tset_del_list(S0, Formals), S2 = tset_filter(S1, fun(T) -> temp_is_pseudo(T) end), S2.find_temps([I|Insns], S0) -> S1 = tset_add_list(S0, hipe_arm_defuse:insn_def_all(I)), S2 = tset_add_list(S1, hipe_arm_defuse:insn_use_all(I)), find_temps(Insns, S2);find_temps([], S) -> S.tset_empty() -> gb_sets:new().tset_size(S) -> gb_sets:size(S).tset_insert(S, T) -> gb_sets:add_element(T, S).tset_add_list(S, Ts) -> gb_sets:union(S, gb_sets:from_list(Ts)).tset_del_list(S, Ts) -> gb_sets:subtract(S, gb_sets:from_list(Ts)).tset_filter(S, F) -> gb_sets:filter(F, S).tset_to_list(S) -> gb_sets:to_list(S).%%%%%% Compute minimum permissible frame size, ignoring spilled temps.%%% This is done to ensure that we won't have to adjust the frame size%%% in the middle of a tailcall.%%%defun_minframe(Defun) -> MaxTailArity = body_mta(hipe_arm:defun_code(Defun), 0), MyArity = length(fix_formals(hipe_arm:defun_formals(Defun))), max(MaxTailArity - MyArity, 0).body_mta([I|Code], MTA) -> body_mta(Code, insn_mta(I, MTA));body_mta([], MTA) -> MTA.insn_mta(I, MTA) -> case I of #pseudo_tailcall{arity=Arity} -> max(MTA, Arity - hipe_arm_registers:nr_args()); _ -> MTA end.max(X, Y) -> % why isn't max/2 a standard BIF? if X > Y -> X; true -> Y end.%%%%%% Ensure that we have enough temps to satisfy the minimum frame size,%%% if necessary by prepending unused dummy temps.%%%ensure_minframe(MinFrame, Temps) -> ensure_minframe(MinFrame, tset_size(Temps), Temps).ensure_minframe(MinFrame, Frame, Temps) -> if MinFrame > Frame -> Temp = hipe_arm:mk_new_temp('untagged'), ensure_minframe(MinFrame, Frame+1, tset_insert(Temps, Temp)); true -> Temps end.word_size() -> 4.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?