📄 hipe_rtl_to_ppc.erl
字号:
%%% -*- erlang-indent-level: 2 -*-%%% $Id$%%%%%% The PowerPC instruction set is quite irregular.%%% The following quirks must be handled by the translation:%%%%%% - The instruction names are different for reg/reg and reg/imm%%% source operands. For some operations, completely different%%% instructions handle the reg/reg and reg/imm cases.%%% - The name of an arithmetic instruction depends on whether any%%% condition codes are to be set or not. Overflow is treated%%% separately from other conditions.%%% - Some combinations or RTL ALU operations, source operand shapes,%%% and requested conditions have no direct correspondence in the%%% PowerPC instruction set.%%% - The tagging of immediate operands as simm16 or uimm16 depends%%% on the actual instruction.%%% - Conditional branches have no unsigned conditions. Instead there%%% are signed and unsigned versions of the compare instruction.%%% - The arithmetic overflow flag XER[SO] is sticky: once set it%%% remains set until explicitly cleared.-module(hipe_rtl_to_ppc).-export([translate/1]).-include("../rtl/hipe_rtl.hrl").translate(RTL) -> hipe_gensym:init(ppc), hipe_gensym:set_var(ppc, hipe_ppc_registers:first_virtual()), hipe_gensym:set_label(ppc, 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_ppc:mk_label(hipe_gensym:get_next_label(ppc)) | move_formals(RegFormals, Code0)] end, IsClosure = hipe_rtl:rtl_is_closure(RTL), IsLeaf = hipe_rtl:rtl_is_leaf(RTL), hipe_ppc: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); #fconv{} -> conv_fconv(I, Map, Data); #fmove{} -> conv_fmove(I, Map, Data); #fload{} -> conv_fload(I, Map, Data); #fstore{} -> conv_fstore(I, Map, Data); #fp{} -> conv_fp_binary(I, Map, Data); #fp_unop{} -> conv_fp_unary(I, Map, Data); _ -> exit({?MODULE,conv_insn,I}) end.conv_fconv(I, Map, Data) -> %% Dst := (double)Src, where Dst is FP reg and Src is int reg {Dst, Map0} = conv_fpreg(hipe_rtl:fconv_dst(I), Map), {Src, Map1} = conv_src(hipe_rtl:fconv_src(I), Map0), % exclude imm src I2 = mk_fconv(Dst, Src), {I2, Map1, Data}.mk_fconv(Dst, Src) -> CSP = hipe_ppc:mk_temp(1, 'untagged'), R0 = hipe_ppc:mk_temp(0, 'untagged'), RTmp1 = hipe_ppc:mk_new_temp('untagged'), RTmp2 = hipe_ppc:mk_new_temp('untagged'), RTmp3 = hipe_ppc:mk_new_temp('untagged'), FTmp1 = hipe_ppc:mk_new_temp('double'), FTmp2 = hipe_ppc:mk_new_temp('double'), [hipe_ppc:mk_pseudo_li(RTmp1, {fconv_constant,c_const}), hipe_ppc:mk_lfd(FTmp1, 0, RTmp1), hipe_ppc:mk_alu('xoris', RTmp2, Src, hipe_ppc:mk_uimm16(16#8000)), hipe_ppc:mk_store('stw', RTmp2, 28, CSP), hipe_ppc:mk_alu('addis', RTmp3, R0, hipe_ppc:mk_simm16(16#4330)), hipe_ppc:mk_store('stw', RTmp3, 24, CSP), hipe_ppc:mk_lfd(FTmp2, 24, CSP), hipe_ppc:mk_fp_binary('fsub', Dst, FTmp2, FTmp1)].conv_fmove(I, Map, Data) -> %% Dst := Src, where both Dst and Src are FP regs {Dst, Map0} = conv_fpreg(hipe_rtl:fmove_dst(I), Map), {Src, Map1} = conv_fpreg(hipe_rtl:fmove_src(I), Map0), I2 = mk_fmove(Dst, Src), {I2, Map1, Data}.mk_fmove(Dst, Src) -> [hipe_ppc:mk_pseudo_fmove(Dst, Src)].conv_fload(I, Map, Data) -> %% Dst := MEM[Base+Off], where Dst is FP reg {Dst, Map0} = conv_fpreg(hipe_rtl:fload_dst(I), Map), {Base1, Map1} = conv_src(hipe_rtl:fload_src(I), Map0), {Base2, Map2} = conv_src(hipe_rtl:fload_offset(I), Map1), I2 = mk_fload(Dst, Base1, Base2), {I2, Map2, Data}.mk_fload(Dst, Base1, Base2) -> case hipe_ppc:is_temp(Base1) of true -> case hipe_ppc:is_temp(Base2) of true -> mk_fload_rr(Dst, Base1, Base2); _ -> mk_fload_ri(Dst, Base1, Base2) end; _ -> case hipe_ppc:is_temp(Base2) of true -> mk_fload_ri(Dst, Base2, Base1); _ -> mk_fload_ii(Dst, Base1, Base2) end end.mk_fload_ii(Dst, Base1, Base2) -> io:format("~w: RTL fload with two immediates\n", [?MODULE]), Tmp = new_untagged_temp(), mk_li(Tmp, Base1, mk_fload_ri(Dst, Tmp, Base2)).mk_fload_ri(Dst, Base, Disp) -> hipe_ppc:mk_fload(Dst, Disp, Base, 'new').mk_fload_rr(Dst, Base1, Base2) -> [hipe_ppc:mk_lfdx(Dst, Base1, Base2)].conv_fstore(I, Map, Data) -> %% MEM[Base+Off] := Src, where Src is FP reg {Base1, Map0} = conv_dst(hipe_rtl:fstore_base(I), Map), {Src, Map1} = conv_fpreg(hipe_rtl:fstore_src(I), Map0), {Base2, Map2} = conv_src(hipe_rtl:fstore_offset(I), Map1), I2 = mk_fstore(Src, Base1, Base2), {I2, Map2, Data}.mk_fstore(Src, Base1, Base2) -> case hipe_ppc:is_temp(Base2) of true -> mk_fstore_rr(Src, Base1, Base2); _ -> mk_fstore_ri(Src, Base1, Base2) end.mk_fstore_ri(Src, Base, Disp) -> hipe_ppc:mk_fstore(Src, Disp, Base, 'new').mk_fstore_rr(Src, Base1, Base2) -> [hipe_ppc:mk_stfdx(Src, Base1, Base2)].conv_fp_binary(I, Map, Data) -> {Dst, Map0} = conv_fpreg(hipe_rtl:fp_dst(I), Map), {Src1, Map1} = conv_fpreg(hipe_rtl:fp_src1(I), Map0), {Src2, Map2} = conv_fpreg(hipe_rtl:fp_src2(I), Map1), RtlFpOp = hipe_rtl:fp_op(I), I2 = mk_fp_binary(Dst, Src1, RtlFpOp, Src2), {I2, Map2, Data}.mk_fp_binary(Dst, Src1, RtlFpOp, Src2) -> FpBinOp = case RtlFpOp of 'fadd' -> 'fadd'; 'fdiv' -> 'fdiv'; 'fmul' -> 'fmul'; 'fsub' -> 'fsub' end, [hipe_ppc:mk_fp_binary(FpBinOp, Dst, Src1, Src2)].conv_fp_unary(I, Map, Data) -> {Dst, Map0} = conv_fpreg(hipe_rtl:fp_unop_dst(I), Map), {Src, Map1} = conv_fpreg(hipe_rtl:fp_unop_src(I), Map0), RtlFpUnOp = hipe_rtl:fp_unop_op(I), I2 = mk_fp_unary(Dst, Src, RtlFpUnOp), {I2, Map1, Data}.mk_fp_unary(Dst, Src, RtlFpUnOp) -> FpUnOp = case RtlFpUnOp of 'fchs' -> 'fneg' end, [hipe_ppc:mk_fp_unary(FpUnOp, Dst, Src)].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), I2 = mk_alu(Dst, Src1, RtlAluOp, Src2), {I2, Map2, Data}.mk_alu(Dst, Src1, RtlAluOp, Src2) -> case hipe_ppc:is_temp(Src1) of true -> case hipe_ppc:is_temp(Src2) of true -> mk_alu_rr(Dst, Src1, RtlAluOp, Src2); _ -> mk_alu_ri(Dst, Src1, RtlAluOp, Src2) end; _ -> case hipe_ppc:is_temp(Src2) of true -> mk_alu_ir(Dst, Src1, RtlAluOp, Src2); _ -> mk_alu_ii(Dst, Src1, RtlAluOp, Src2) end end.mk_alu_ii(Dst, Src1, RtlAluOp, Src2) -> io:format("~w: RTL alu with two immediates (~w ~w ~w)\n", [?MODULE, Src1, RtlAluOp, Src2]), Tmp = new_untagged_temp(), mk_li(Tmp, Src1, mk_alu_ri(Dst, Tmp, RtlAluOp, Src2)).mk_alu_ir(Dst, Src1, RtlAluOp, Src2) -> case rtl_aluop_commutes(RtlAluOp) of true -> mk_alu_ri(Dst, Src2, RtlAluOp, Src1); _ -> Tmp = new_untagged_temp(), mk_li(Tmp, Src1, mk_alu_rr(Dst, Tmp, RtlAluOp, Src2)) end.mk_alu_ri(Dst, Src1, RtlAluOp, Src2) -> case RtlAluOp of 'sub' -> % there is no 'subi' mk_alu_ri_addi(Dst, Src1, -Src2); 'add' -> % 'addi' has a 16-bit simm operand mk_alu_ri_addi(Dst, Src1, Src2); 'mul' -> % 'mulli' has a 16-bit simm operand mk_alu_ri_simm16(Dst, Src1, RtlAluOp, 'mulli', 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_alu_ri_bitop(Dst, Src1, RtlAluOp, 'andi.', Src2) end; 'or' -> % 'ori' has a 16-bit uimm operand mk_alu_ri_bitop(Dst, Src1, RtlAluOp, 'ori', Src2); 'xor' -> % 'xori' has a 16-bit uimm operand mk_alu_ri_bitop(Dst, Src1, RtlAluOp, 'xori', Src2); _ -> % shift ops have 5-bit uimm operands mk_alu_ri_shift(Dst, Src1, RtlAluOp, Src2) end.rlwinm_mask(Imm) -> Res1 = rlwinm_mask2(Imm), case Res1 of {_MB,_ME} -> Res1; [] -> case rlwinm_mask2(bnot Imm) of {MB,ME} -> {ME+1,MB-1}; [] -> [] end end.rlwinm_mask2(Imm) -> case Imm band 16#ffffffff of 0 -> []; Word -> MB = lsb_log2(Word), % first 1 bit case bnot(Word bsr MB) band 16#ffffffff of 0 -> []; % Imm was all-bits-one XXX: we should handle this Word1 -> ME1 = lsb_log2(Word1),% first 0 bit after the 1s case Word bsr (MB+ME1) of 0 -> ME = MB+ME1-1, % last 1 bit {31-ME, 31-MB}; % convert to PPC sick and twisted bit numbers _ -> [] end end end.lsb_log2(Word) -> % PRE: Word =/= 0 bitN_log2(Word band -Word, 0).bitN_log2(BitN, ShiftN) -> if BitN > 16#ffff -> bitN_log2(BitN bsr 16, ShiftN + 16); true -> ShiftN + hweight16(BitN - 1) end.hweight16(Word) -> % PRE: 0 <= Word <= 16#ffff Res1 = (Word band 16#5555) + ((Word bsr 1) band 16#5555), Res2 = (Res1 band 16#3333) + ((Res1 bsr 2) band 16#3333), Res3 = (Res2 band 16#0F0F) + ((Res2 bsr 4) band 16#0F0F), (Res3 band 16#00FF) + ((Res3 bsr 8) band 16#00FF).mk_alu_ri_addi(Dst, Src1, Src2) -> mk_alu_ri_simm16(Dst, Src1, 'add', 'addi', Src2).mk_alu_ri_simm16(Dst, Src1, RtlAluOp, AluOp, Src2) -> if is_integer(Src2), -32768 =< Src2, Src2 < 32768 -> [hipe_ppc:mk_alu(AluOp, Dst, Src1, hipe_ppc:mk_simm16(Src2))]; true -> mk_alu_ri_rr(Dst, Src1, RtlAluOp, Src2) end.mk_alu_ri_bitop(Dst, Src1, RtlAluOp, AluOp, Src2) -> if is_integer(Src2), 0 =< Src2, Src2 < 65536 -> [hipe_ppc:mk_alu(AluOp, Dst, Src1, hipe_ppc:mk_uimm16(Src2))]; true -> mk_alu_ri_rr(Dst, Src1, RtlAluOp, Src2) end.mk_alu_ri_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 -> mk_alu_ri_rr(Dst, Src1, RtlAluOp, Src2) end.mk_alu_ri_rr(Dst, Src1, RtlAluOp, Src2) -> Tmp = new_untagged_temp(), mk_li(Tmp, Src2, mk_alu_rr(Dst, Src1, RtlAluOp, Tmp)).mk_alu_rr(Dst, Src1, RtlAluOp, Src2) -> 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_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), BCond = conv_alub_cond(hipe_rtl:alub_cond(I)), I2 = mk_pseudo_bc(BCond, hipe_rtl:alub_true_label(I), hipe_rtl:alub_false_label(I), hipe_rtl:alub_pred(I)), RtlAluOp = hipe_rtl:alub_op(I), I1 = mk_alub(Dst, Src1, RtlAluOp, Src2, BCond), {I1 ++ I2, Map2, Data}.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -