📄 hipe_rtl_to_ppc.erl
字号:
conv_alub_cond(Cond) -> % only signed case Cond of eq -> 'eq'; ne -> 'ne'; gt -> 'gt'; ge -> 'ge'; lt -> 'lt'; le -> 'le'; overflow -> 'so'; not_overflow -> 'ns'; _ -> exit({?MODULE,conv_alub_cond,Cond}) end.mk_alub(Dst, Src1, RtlAluOp, Src2, BCond) -> case hipe_ppc:is_temp(Src1) of true -> case hipe_ppc:is_temp(Src2) of true -> mk_alub_rr(Dst, Src1, RtlAluOp, Src2, BCond); _ -> mk_alub_ri(Dst, Src1, RtlAluOp, Src2, BCond) end; _ -> case hipe_ppc:is_temp(Src2) of true -> mk_alub_ir(Dst, Src1, RtlAluOp, Src2, BCond); _ -> mk_alub_ii(Dst, Src1, RtlAluOp, Src2, BCond) end end.mk_alub_ii(Dst, Src1, RtlAluOp, Src2, BCond) -> io:format("~w: RTL alub with two immediates\n", [?MODULE]), Tmp = new_untagged_temp(), mk_li(Tmp, Src1, mk_alub_ri(Dst, Tmp, RtlAluOp, Src2, BCond)).mk_alub_ir(Dst, Src1, RtlAluOp, Src2, BCond) -> case rtl_aluop_commutes(RtlAluOp) of true -> mk_alub_ri(Dst, Src2, RtlAluOp, Src1, BCond); _ -> Tmp = new_untagged_temp(), mk_li(Tmp, Src1, mk_alub_rr(Dst, Tmp, RtlAluOp, Src2, BCond)) end.mk_alub_ri(Dst, Src1, RtlAluOp, Src2, BCond) -> true = is_integer(Src2), case BCond of 'so' -> mk_alub_ri_OE(Dst, Src1, RtlAluOp, Src2); 'ns' -> mk_alub_ri_OE(Dst, Src1, RtlAluOp, Src2); _ -> mk_alub_ri_Rc(Dst, Src1, RtlAluOp, Src2) end.mk_alub_ri_OE(Dst, Src1, RtlAluOp, Src2) -> %% Only 'add', 'sub', and 'mul' apply here, and 'sub' becomes 'add'. %% 'add' and 'mul' have no immediate+Rc+OE forms. %% Rewrite to reg/reg form. Sigh. Tmp = new_untagged_temp(), mk_li(Tmp, Src2, mk_alub_rr_OE(Dst, Src1, RtlAluOp, Tmp)).mk_alub_ri_Rc(Dst, Src1, RtlAluOp, Src2) -> case RtlAluOp of 'sub' -> % there is no 'subi.' mk_alub_ri_Rc_addi(Dst, Src1, -Src2); 'add' -> % 'addic.' has a 16-bit simm operand mk_alub_ri_Rc_addi(Dst, Src1, Src2); 'mul' -> % there is no 'mulli.' mk_alub_ri_Rc_rr(Dst, Src1, 'mullw.', Src2); 'or' -> % there is no 'ori.' mk_alub_ri_Rc_rr(Dst, Src1, 'or.', Src2); 'xor' -> % there is no 'xori.' mk_alub_ri_Rc_rr(Dst, Src1, 'xor.', Src2); 'and' -> % 'andi.' has a 16-bit uimm operand case rlwinm_mask(Src2) of {MB,ME} -> [hipe_ppc:mk_unary({'rlwinm.',0,MB,ME}, Dst, Src1)]; _ -> mk_alub_ri_Rc_andi(Dst, Src1, Src2) end; _ -> % shift ops have 5-bit uimm operands mk_alub_ri_Rc_shift(Dst, Src1, RtlAluOp, Src2) end.mk_alub_ri_Rc_addi(Dst, Src1, Src2) -> if is_integer(Src2), -32768 =< Src2, Src2 < 32768 -> [hipe_ppc:mk_alu('addic.', Dst, Src1, hipe_ppc:mk_simm16(Src2))]; true -> mk_alub_ri_Rc_rr(Dst, Src1, 'add.', Src2) end.mk_alub_ri_Rc_andi(Dst, Src1, Src2) -> if Src2 < 65536, Src2 >= 0 -> [hipe_ppc:mk_alu('andi.', Dst, Src1, hipe_ppc:mk_uimm16(Src2))]; true -> mk_alub_ri_Rc_rr(Dst, Src1, 'and.', Src2) end.mk_alub_ri_Rc_shift(Dst, Src1, RtlAluOp, Src2) -> if Src2 < 32, Src2 >= 0 -> AluOp = case RtlAluOp of 'sll' -> 'slwi.'; % alias for rlwinm. 'srl' -> 'srwi.'; % alias for rlwinm. 'sra' -> 'srawi.' end, [hipe_ppc:mk_alu(AluOp, Dst, Src1, hipe_ppc:mk_uimm16(Src2))]; true -> AluOp = case RtlAluOp of 'sll' -> 'slw.'; 'srl' -> 'srw.'; 'sra' -> 'sraw.' end, mk_alub_ri_Rc_rr(Dst, Src1, AluOp, Src2) end.mk_alub_ri_Rc_rr(Dst, Src1, AluOp, Src2) -> Tmp = new_untagged_temp(), mk_li(Tmp, Src2, [hipe_ppc:mk_alu(AluOp, Dst, Src1, Tmp)]).mk_alub_rr(Dst, Src1, RtlAluOp, Src2, BCond) -> case BCond of 'so' -> mk_alub_rr_OE(Dst, Src1, RtlAluOp, Src2); 'ns' -> mk_alub_rr_OE(Dst, Src1, RtlAluOp, Src2); _ -> mk_alub_rr_Rc(Dst, Src1, RtlAluOp, Src2) end.mk_alub_rr_OE(Dst, Src1, RtlAluOp, Src2) -> case RtlAluOp of 'sub' -> % PPC weirdness [hipe_ppc:mk_alu('subfo.', Dst, Src2, Src1)]; 'add' -> [hipe_ppc:mk_alu('addo.', Dst, Src1, Src2)]; 'mul' -> [hipe_ppc:mk_alu('mullwo.', Dst, Src1, Src2)] %% fail for or, and, xor, sll, srl, sra end.mk_alub_rr_Rc(Dst, Src1, RtlAluOp, Src2) -> %% XXX: identical to mk_alu_rr/4, except for the '.' in the instruction names case RtlAluOp of 'sub' -> % PPC weirdness [hipe_ppc:mk_alu('subf.', Dst, Src2, Src1)]; _ -> AluOp = case RtlAluOp of 'add' -> 'add.'; 'mul' -> 'mullw.'; 'or' -> 'or.'; 'and' -> 'and.'; 'xor' -> 'xor.'; 'sll' -> 'slw.'; 'srl' -> 'srw.'; 'sra' -> 'sraw.' end, [hipe_ppc:mk_alu(AluOp, Dst, Src1, Src2)] end.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), {BCond,Sign} = conv_branch_cond(hipe_rtl:branch_cond(I)), I2 = mk_branch(Src1, BCond, Sign, Src2, hipe_rtl:branch_true_label(I), hipe_rtl:branch_false_label(I), hipe_rtl:branch_pred(I)), {I2, Map1, Data}.conv_branch_cond(Cond) -> % may be unsigned case Cond of gtu -> {'gt', 'unsigned'}; geu -> {'ge', 'unsigned'}; ltu -> {'lt', 'unsigned'}; leu -> {'le', 'unsigned'}; _ -> {conv_alub_cond(Cond), 'signed'} end. mk_branch(Src1, BCond, Sign, Src2, TrueLab, FalseLab, Pred) -> case hipe_ppc:is_temp(Src1) of true -> case hipe_ppc:is_temp(Src2) of true -> mk_branch_rr(Src1, BCond, Sign, Src2, TrueLab, FalseLab, Pred); _ -> mk_branch_ri(Src1, BCond, Sign, Src2, TrueLab, FalseLab, Pred) end; _ -> case hipe_ppc:is_temp(Src2) of true -> NewBCond = commute_bcond(BCond), mk_branch_ri(Src2, NewBCond, Sign, Src1, TrueLab, FalseLab, Pred); _ -> mk_branch_ii(Src1, BCond, Sign, Src2, TrueLab, FalseLab, Pred) end end.commute_bcond(BCond) -> % if x BCond y, then y commute_bcond(BCond) x case BCond of 'eq' -> 'eq'; % ==, == 'ne' -> 'ne'; % !=, != 'gt' -> 'lt'; % >, < 'ge' -> 'le'; % >=, <= 'lt' -> 'gt'; % <, > 'le' -> 'ge'; % <=, >= %% so/ns: n/a _ -> exit({?MODULE,commute_bcond,BCond}) end.mk_branch_ii(Src1, BCond, Sign, Src2, TrueLab, FalseLab, Pred) -> io:format("~w: RTL branch with two immediates\n", [?MODULE]), Tmp = new_untagged_temp(), mk_li(Tmp, Src1, mk_branch_ri(Tmp, BCond, Sign, Src2, TrueLab, FalseLab, Pred)).mk_branch_ri(Src1, BCond, Sign, Src2, TrueLab, FalseLab, Pred) -> {FixSrc2,NewSrc2,CmpOp} = case Sign of 'signed' -> if is_integer(Src2), -32768 =< Src2, Src2 < 32768 -> {[], hipe_ppc:mk_simm16(Src2), 'cmpi'}; true -> Tmp = new_untagged_temp(), {mk_li(Tmp, Src2), Tmp, 'cmp'} end; 'unsigned' -> if is_integer(Src2), 0 =< Src2, Src2 < 65536 -> {[], hipe_ppc:mk_uimm16(Src2), 'cmpli'}; true -> Tmp = new_untagged_temp(), {mk_li(Tmp, Src2), Tmp, 'cmpl'} end end, FixSrc2 ++ mk_cmp_bc(CmpOp, Src1, NewSrc2, BCond, TrueLab, FalseLab, Pred).mk_branch_rr(Src1, BCond, Sign, Src2, TrueLab, FalseLab, Pred) -> CmpOp = case Sign of 'signed' -> 'cmp'; 'unsigned' -> 'cmpl' end, mk_cmp_bc(CmpOp, Src1, Src2, BCond, TrueLab, FalseLab, Pred).mk_cmp_bc(CmpOp, Src1, Src2, BCond, TrueLab, FalseLab, Pred) -> [hipe_ppc:mk_cmp(CmpOp, Src1, Src2) | mk_pseudo_bc(BCond, 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_ppc: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_ppc:prim_prim(Prim) of 'extsh' -> mk_extsh_call(Dsts, Args, ContLab, ExnLab, Linkage); 'lhbrx' -> mk_lhbrx_call(Dsts, Args, ContLab, ExnLab, Linkage); 'lwbrx' -> mk_lwbrx_call(Dsts, Args, ContLab, ExnLab, Linkage); _ -> mk_general_call(Dsts, Prim, Args, ContLab, ExnLab, Linkage) end.mk_extsh_call([Dst], [Src], [], [], not_remote) -> true = hipe_ppc:is_temp(Src), [hipe_ppc:mk_unary('extsh', Dst, Src)].mk_lhbrx_call(Dsts, [Base,Offset], [], [], not_remote) -> case Dsts of [Dst] -> mk_loadx('lhbrx', Dst, Base, Offset); [] -> [] % result unused, cancel the operation end.mk_lwbrx_call([Dst], [Base,Offset], [], [], not_remote) -> mk_loadx('lwbrx', Dst, Base, Offset).mk_loadx(LdxOp, Dst, Base, Offset) -> true = hipe_ppc:is_temp(Base), {FixOff,NewOff} = case hipe_ppc:is_temp(Offset) of true -> {[], Offset}; false -> Tmp = new_untagged_temp(), {mk_li(Tmp, Offset), Tmp} end, FixOff ++ [hipe_ppc:mk_loadx(LdxOp, Dst, Base, NewOff)].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(ppc), {NewContLab, [hipe_ppc: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(ppc), case ContLab of [] -> %% This is just a fallthrough %% No jump back after the moves. {NewContLab, [hipe_ppc:mk_label(NewContLab) | Moves]}; _ -> %% The call has a continuation. Jump to it. {NewContLab, [hipe_ppc:mk_label(NewContLab) | Moves ++ [hipe_ppc:mk_b_label(ContLab)]]} end end, SDesc = hipe_ppc:mk_sdesc(ExnLab, 0, length(Args), {}), {FixFunC,FunC} = fix_func(Fun), CallInsn = hipe_ppc:mk_pseudo_call(FunC, SDesc, RealContLab, Linkage), {RegArgs,StkArgs} = split_args(Args), FixFunC ++ mk_push_args(StkArgs, move_actuals(RegArgs, [CallInsn | Tail])).mk_call_results([]) -> [];mk_call_results([Dst]) -> RV = hipe_ppc:mk_temp(hipe_ppc_registers:return_value(), 'tagged'), [hipe_ppc:mk_pseudo_move(Dst, RV)];mk_call_results(Dsts) -> exit({?MODULE,mk_call_results,Dsts}).fix_func(Fun) -> case hipe_ppc:is_temp(Fun) of true -> {[hipe_ppc:mk_mtspr('ctr', Fun)], 'ctr'}; _ -> {[], Fun} end.mk_push_args(StkArgs, Tail) -> case length(StkArgs) of 0 -> Tail; NrStkArgs -> [hipe_ppc: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_ppc:is_temp(Arg) of true -> {Arg, []}; _ -> Tmp = new_tagged_temp(), {Tmp, mk_li(Tmp, Arg)} end, Store = hipe_ppc:mk_store('stw', Src, Offset, mk_sp()), mk_store_args(Args, Offset, FixSrc ++ [Store | Tail]);mk_store_args([], _, Tail) -> Tail.conv_comment(I, Map, Data) -> I2 = [hipe_ppc:mk_comment(hipe_rtl:comment_text(I))], {I2, Map, Data}.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -