diff options
Diffstat (limited to 'lib/hipe/ppc/hipe_ppc.erl')
-rw-r--r-- | lib/hipe/ppc/hipe_ppc.erl | 415 |
1 files changed, 415 insertions, 0 deletions
diff --git a/lib/hipe/ppc/hipe_ppc.erl b/lib/hipe/ppc/hipe_ppc.erl new file mode 100644 index 0000000000..047e86c45b --- /dev/null +++ b/lib/hipe/ppc/hipe_ppc.erl @@ -0,0 +1,415 @@ +%% -*- erlang-indent-level: 2 -*- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + + +-module(hipe_ppc). +-export([ + mk_temp/2, + mk_new_temp/1, + mk_new_nonallocatable_temp/1, + is_temp/1, + temp_reg/1, + temp_type/1, + temp_is_allocatable/1, + temp_is_precoloured/1, + + mk_simm16/1, + mk_uimm16/1, + + mk_mfa/3, + + mk_prim/1, + is_prim/1, + prim_prim/1, + + mk_sdesc/4, + + mk_alu/4, + + mk_b_fun/2, + + mk_b_label/1, + + mk_bc/3, + + mk_bctr/1, + + mk_bctrl/1, + + mk_bl/3, + + mk_blr/0, + + mk_cmp/3, + + mk_comment/1, + + mk_label/1, + is_label/1, + label_label/1, + + mk_li/2, + mk_li/3, + mk_addi/4, + + mk_load/4, + mk_loadx/4, + mk_load/6, + ldop_to_ldxop/1, + + mk_mfspr/2, + + mk_mtcr/1, + + mk_mtspr/2, + + mk_pseudo_bc/4, + negate_bcond/1, + + mk_pseudo_call/4, + pseudo_call_contlab/1, + pseudo_call_func/1, + pseudo_call_sdesc/1, + pseudo_call_linkage/1, + + mk_pseudo_call_prepare/1, + pseudo_call_prepare_nrstkargs/1, + + mk_pseudo_li/2, + + mk_pseudo_move/2, + is_pseudo_move/1, + pseudo_move_dst/1, + pseudo_move_src/1, + + mk_pseudo_tailcall/4, + pseudo_tailcall_func/1, + pseudo_tailcall_stkargs/1, + pseudo_tailcall_linkage/1, + + mk_pseudo_tailcall_prepare/0, + + mk_store/4, + mk_storex/4, + mk_store/6, + stop_to_stxop/1, + + mk_unary/3, + + mk_lfd/3, + mk_lfdx/3, + mk_fload/4, + + %% mk_stfd/3, + mk_stfdx/3, + mk_fstore/4, + + mk_fp_binary/4, + + mk_fp_unary/3, + + mk_pseudo_fmove/2, + is_pseudo_fmove/1, + pseudo_fmove_dst/1, + pseudo_fmove_src/1, + + mk_defun/8, + defun_mfa/1, + defun_formals/1, + defun_is_closure/1, + defun_is_leaf/1, + defun_code/1, + defun_data/1, + defun_var_range/1]). + +-include("hipe_ppc.hrl"). + +mk_temp(Reg, Type, Allocatable) -> + #ppc_temp{reg=Reg, type=Type, allocatable=Allocatable}. +mk_temp(Reg, Type) -> mk_temp(Reg, Type, true). +mk_new_temp(Type, Allocatable) -> + mk_temp(hipe_gensym:get_next_var(ppc), Type, Allocatable). +mk_new_temp(Type) -> mk_new_temp(Type, true). +mk_new_nonallocatable_temp(Type) -> mk_new_temp(Type, false). +is_temp(X) -> case X of #ppc_temp{} -> true; _ -> false end. +temp_reg(#ppc_temp{reg=Reg}) -> Reg. +temp_type(#ppc_temp{type=Type}) -> Type. +temp_is_allocatable(#ppc_temp{allocatable=A}) -> A. +temp_is_precoloured(#ppc_temp{reg=Reg,type=Type}) -> + case Type of + 'double' -> hipe_ppc_registers:is_precoloured_fpr(Reg); + _ -> hipe_ppc_registers:is_precoloured_gpr(Reg) + end. + +mk_simm16(Value) -> #ppc_simm16{value=Value}. +mk_uimm16(Value) -> #ppc_uimm16{value=Value}. + +mk_mfa(M, F, A) -> #ppc_mfa{m=M, f=F, a=A}. + +mk_prim(Prim) -> #ppc_prim{prim=Prim}. +is_prim(X) -> case X of #ppc_prim{} -> true; _ -> false end. +prim_prim(#ppc_prim{prim=Prim}) -> Prim. + +mk_sdesc(ExnLab, FSize, Arity, Live) -> + #ppc_sdesc{exnlab=ExnLab, fsize=FSize, arity=Arity, live=Live}. + +mk_alu(AluOp, Dst, Src1, Src2) -> + #alu{aluop=AluOp, dst=Dst, src1=Src1, src2=Src2}. + +mk_b_fun(Fun, Linkage) -> #b_fun{'fun'=Fun, linkage=Linkage}. + +mk_b_label(Label) -> #b_label{label=Label}. + +mk_bc(BCond, Label, Pred) -> #bc{bcond=BCond, label=Label, pred=Pred}. + +mk_bctr(Labels) -> #bctr{labels=Labels}. + +mk_bctrl(SDesc) -> #bctrl{sdesc=SDesc}. + +mk_bl(Fun, SDesc, Linkage) -> #bl{'fun'=Fun, sdesc=SDesc, linkage=Linkage}. + +mk_blr() -> #blr{}. + +mk_cmp(CmpOp, Src1, Src2) -> #cmp{cmpop=CmpOp, src1=Src1, src2=Src2}. + +mk_comment(Term) -> #comment{term=Term}. + +mk_label(Label) -> #label{label=Label}. +is_label(I) -> case I of #label{} -> true; _ -> false end. +label_label(#label{label=Label}) -> Label. + +%%% Load an integer constant into a register. +mk_li(Dst, Value) -> mk_li(Dst, Value, []). + +mk_li(Dst, Value, Tail) -> + R0 = mk_temp(0, 'untagged'), + mk_addi(Dst, R0, Value, Tail). + +mk_addi(Dst, R0, Value, Tail) -> + Low = at_l(Value), + High = at_ha(Value), + case High of + 0 -> + [mk_alu('addi', Dst, R0, mk_simm16(Low)) | + Tail]; + _ -> + case Low of + 0 -> + [mk_alu('addis', Dst, R0, mk_simm16(High)) | + Tail]; + _ -> + [mk_alu('addi', Dst, R0, mk_simm16(Low)), + mk_alu('addis', Dst, Dst, mk_simm16(High)) | + Tail] + end + end. + +at_l(Value) -> + simm16sext(Value band 16#FFFF). + +at_ha(Value) -> + simm16sext(((Value + 16#8000) bsr 16) band 16#FFFF). + +simm16sext(Value) -> + if Value >= 32768 -> (-1 bsl 16) bor Value; + true -> Value + end. + +mk_li_new(Dst, Value, Tail) -> % Dst may be R0 + R0 = mk_temp(0, 'untagged'), + case at_ha(Value) of + 0 -> + %% Value[31:16] are the sign-extension of Value[15]. + %% Use a single addi to load and sign-extend 16 bits. + [mk_alu('addi', Dst, R0, mk_simm16(at_l(Value))) | + Tail]; + _ -> + %% Use addis to load the high 16 bits, followed by an + %% optional ori to load non sign-extended low 16 bits. + High = simm16sext((Value bsr 16) band 16#FFFF), + [mk_alu('addis', Dst, R0, mk_simm16(High)) | + case (Value band 16#FFFF) of + 0 -> Tail; + Low -> + [mk_alu('ori', Dst, Dst, mk_uimm16(Low)) | + Tail] + end] + end. + +mk_load(LDop, Dst, Disp, Base) -> + #load{ldop=LDop, dst=Dst, disp=Disp, base=Base}. + +mk_loadx(LdxOp, Dst, Base1, Base2) -> + #loadx{ldxop=LdxOp, dst=Dst, base1=Base1, base2=Base2}. + +mk_load(LdOp, Dst, Offset, Base, Scratch, Rest) when is_integer(Offset) -> + if Offset >= -32768, Offset =< 32767 -> + [mk_load(LdOp, Dst, Offset, Base) | Rest]; + true -> + LdxOp = ldop_to_ldxop(LdOp), + Index = + begin + DstReg = temp_reg(Dst), + BaseReg = temp_reg(Base), + if DstReg =/= BaseReg -> Dst; + true -> mk_scratch(Scratch) + end + end, + mk_li_new(Index, Offset, + [mk_loadx(LdxOp, Dst, Base, Index) | Rest]) + end. + +ldop_to_ldxop(LdOp) -> + case LdOp of + 'lbz' -> 'lbzx'; + 'lha' -> 'lhax'; + 'lhz' -> 'lhzx'; + 'lwz' -> 'lwzx' + end. + +mk_scratch(Scratch) -> + case Scratch of + 0 -> mk_temp(0, 'untagged'); + 'new' -> mk_new_temp('untagged') + end. + +mk_mfspr(Dst, Spr) -> #mfspr{dst=Dst, spr=Spr}. + +mk_mtcr(Src) -> #mtcr{src=Src}. + +mk_mtspr(Spr, Src) -> #mtspr{spr=Spr, src=Src}. + +mk_pseudo_bc(BCond, TrueLab, FalseLab, Pred) -> + if Pred >= 0.5 -> + mk_pseudo_bc_simple(negate_bcond(BCond), FalseLab, + TrueLab, 1.0-Pred); + true -> + mk_pseudo_bc_simple(BCond, TrueLab, FalseLab, Pred) + end. + +mk_pseudo_bc_simple(BCond, TrueLab, FalseLab, Pred) when Pred =< 0.5 -> + #pseudo_bc{bcond=BCond, true_label=TrueLab, + false_label=FalseLab, pred=Pred}. + +negate_bcond(BCond) -> + case BCond of + 'lt' -> 'ge'; + 'ge' -> 'lt'; + 'gt' -> 'le'; + 'le' -> 'gt'; + 'eq' -> 'ne'; + 'ne' -> 'eq'; + 'so' -> 'ns'; + 'ns' -> 'so' + end. + +mk_pseudo_call(FunC, SDesc, ContLab, Linkage) -> + #pseudo_call{func=FunC, sdesc=SDesc, contlab=ContLab, linkage=Linkage}. +pseudo_call_func(#pseudo_call{func=FunC}) -> FunC. +pseudo_call_sdesc(#pseudo_call{sdesc=SDesc}) -> SDesc. +pseudo_call_contlab(#pseudo_call{contlab=ContLab}) -> ContLab. +pseudo_call_linkage(#pseudo_call{linkage=Linkage}) -> Linkage. + +mk_pseudo_call_prepare(NrStkArgs) -> + #pseudo_call_prepare{nrstkargs=NrStkArgs}. +pseudo_call_prepare_nrstkargs(#pseudo_call_prepare{nrstkargs=NrStkArgs}) -> + NrStkArgs. + +mk_pseudo_li(Dst, Imm) -> #pseudo_li{dst=Dst, imm=Imm}. + +mk_pseudo_move(Dst, Src) -> #pseudo_move{dst=Dst, src=Src}. +is_pseudo_move(I) -> case I of #pseudo_move{} -> true; _ -> false end. +pseudo_move_dst(#pseudo_move{dst=Dst}) -> Dst. +pseudo_move_src(#pseudo_move{src=Src}) -> Src. + +mk_pseudo_tailcall(FunC, Arity, StkArgs, Linkage) -> + #pseudo_tailcall{func=FunC, arity=Arity, stkargs=StkArgs, linkage=Linkage}. +pseudo_tailcall_func(#pseudo_tailcall{func=FunC}) -> FunC. +pseudo_tailcall_stkargs(#pseudo_tailcall{stkargs=StkArgs}) -> StkArgs. +pseudo_tailcall_linkage(#pseudo_tailcall{linkage=Linkage}) -> Linkage. + +mk_pseudo_tailcall_prepare() -> #pseudo_tailcall_prepare{}. + +mk_store(STop, Src, Disp, Base) -> + #store{stop=STop, src=Src, disp=Disp, base=Base}. + +mk_storex(StxOp, Src, Base1, Base2) -> + #storex{stxop=StxOp, src=Src, base1=Base1, base2=Base2}. + +mk_store(StOp, Src, Offset, Base, Scratch, Rest)when is_integer(Offset) -> + if Offset >= -32768, Offset =< 32767 -> + [mk_store(StOp, Src, Offset, Base) | Rest]; + true -> + StxOp = stop_to_stxop(StOp), + Index = mk_scratch(Scratch), + mk_li_new(Index, Offset, + [mk_storex(StxOp, Src, Base, Index) | Rest]) + end. + +stop_to_stxop(StOp) -> + case StOp of + 'stb' -> 'stbx'; + 'sth' -> 'sthx'; + 'stw' -> 'stwx' + end. + +mk_unary(UnOp, Dst, Src) -> #unary{unop=UnOp, dst=Dst, src=Src}. + +mk_lfd(Dst, Disp, Base) -> #lfd{dst=Dst, disp=Disp, base=Base}. +mk_lfdx(Dst, Base1, Base2) -> #lfdx{dst=Dst, base1=Base1, base2=Base2}. +mk_fload(Dst, Offset, Base, Scratch) when is_integer(Offset) -> + if Offset >= -32768, Offset =< 32767 -> + [mk_lfd(Dst, Offset, Base)]; + true -> + Index = mk_scratch(Scratch), + mk_li_new(Index, Offset, [mk_lfdx(Dst, Base, Index)]) + end. + +mk_stfd(Src, Disp, Base) -> #stfd{src=Src, disp=Disp, base=Base}. +mk_stfdx(Src, Base1, Base2) -> #stfdx{src=Src, base1=Base1, base2=Base2}. +mk_fstore(Src, Offset, Base, Scratch) when is_integer(Offset) -> + if Offset >= -32768, Offset =< 32767 -> + [mk_stfd(Src, Offset, Base)]; + true -> + Index = mk_scratch(Scratch), + mk_li_new(Index, Offset, [mk_stfdx(Src, Base, Index)]) + end. + +mk_fp_binary(FpBinOp, Dst, Src1, Src2) -> + #fp_binary{fp_binop=FpBinOp, dst=Dst, src1=Src1, src2=Src2}. + +mk_fp_unary(FpUnOp, Dst, Src) -> #fp_unary{fp_unop=FpUnOp, dst=Dst, src=Src}. + +mk_pseudo_fmove(Dst, Src) -> #pseudo_fmove{dst=Dst, src=Src}. +is_pseudo_fmove(I) -> case I of #pseudo_fmove{} -> true; _ -> false end. +pseudo_fmove_dst(#pseudo_fmove{dst=Dst}) -> Dst. +pseudo_fmove_src(#pseudo_fmove{src=Src}) -> Src. + +mk_defun(MFA, Formals, IsClosure, IsLeaf, Code, Data, VarRange, LabelRange) -> + #defun{mfa=MFA, formals=Formals, code=Code, data=Data, + isclosure=IsClosure, isleaf=IsLeaf, + var_range=VarRange, label_range=LabelRange}. +defun_mfa(#defun{mfa=MFA}) -> MFA. +defun_formals(#defun{formals=Formals}) -> Formals. +defun_is_closure(#defun{isclosure=IsClosure}) -> IsClosure. +defun_is_leaf(#defun{isleaf=IsLeaf}) -> IsLeaf. +defun_code(#defun{code=Code}) -> Code. +defun_data(#defun{data=Data}) -> Data. +defun_var_range(#defun{var_range=VarRange}) -> VarRange. |