diff options
Diffstat (limited to 'lib/hipe/sparc/hipe_sparc.erl')
-rw-r--r-- | lib/hipe/sparc/hipe_sparc.erl | 407 |
1 files changed, 407 insertions, 0 deletions
diff --git a/lib/hipe/sparc/hipe_sparc.erl b/lib/hipe/sparc/hipe_sparc.erl new file mode 100644 index 0000000000..9fcb94afb6 --- /dev/null +++ b/lib/hipe/sparc/hipe_sparc.erl @@ -0,0 +1,407 @@ +%% -*- erlang-indent-level: 2 -*- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-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_sparc). +-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_g0/0, + mk_ra/0, + mk_rv/0, + mk_sp/0, + mk_temp1/0, + mk_temp2/0, + + mk_simm13/1, + mk_uimm5/1, + + mk_mfa/3, + + mk_prim/1, + is_prim/1, + prim_prim/1, + + mk_sdesc/4, + + mk_alu/4, + mk_mov/2, + mk_load/6, + + mk_bp/3, + mk_b_label/1, + + %% mk_br/4, + + mk_call_rec/3, + + mk_call_tail/2, + + mk_comment/1, + + mk_label/1, + is_label/1, + label_label/1, + + mk_jmp/3, + mk_jmpl/2, + + mk_pseudo_bp/4, + negate_cond/1, + + %% mk_pseudo_br/5, + %% negate_rcond/1, + + mk_pseudo_call/4, + pseudo_call_contlab/1, + pseudo_call_funv/1, + pseudo_call_linkage/1, + pseudo_call_sdesc/1, + + mk_pseudo_call_prepare/1, + pseudo_call_prepare_nrstkargs/1, + + mk_pseudo_move/2, + is_pseudo_move/1, + pseudo_move_dst/1, + pseudo_move_src/1, + + mk_pseudo_ret/0, + + mk_pseudo_set/2, + + mk_pseudo_tailcall/4, + pseudo_tailcall_funv/1, + pseudo_tailcall_linkage/1, + pseudo_tailcall_stkargs/1, + + mk_pseudo_tailcall_prepare/0, + + mk_rdy/1, + + %% mk_sethi/2, + mk_nop/0, + mk_set/2, + mk_set/3, + mk_addi/4, + + mk_store/4, + mk_store/6, + + mk_fp_binary/4, + + mk_fp_unary/3, + + mk_pseudo_fload/4, + mk_fload/4, + + mk_pseudo_fmove/2, + is_pseudo_fmove/1, + pseudo_fmove_src/1, + pseudo_fmove_dst/1, + + mk_pseudo_fstore/3, + mk_fstore/4, + + mk_defun/8, + defun_code/1, + defun_data/1, + defun_formals/1, + defun_is_closure/1, + defun_is_leaf/1, + defun_mfa/1, + defun_var_range/1 + ]). + +-include("hipe_sparc.hrl"). + +mk_temp(Reg, Type, Allocatable) -> + #sparc_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(sparc), 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 #sparc_temp{} -> true; _ -> false end. +temp_reg(#sparc_temp{reg=Reg}) -> Reg. +temp_type(#sparc_temp{type=Type}) -> Type. +temp_is_allocatable(#sparc_temp{allocatable=A}) -> A. +temp_is_precoloured(#sparc_temp{reg=Reg,type=Type}) -> + case Type of + %% 'double' -> hipe_sparc_registers:is_precoloured_fpr(Reg); + _ -> hipe_sparc_registers:is_precoloured_gpr(Reg) + end. + +mk_g0() -> mk_temp(hipe_sparc_registers:g0(), 'untagged'). +mk_ra() -> mk_temp(hipe_sparc_registers:return_address(), 'untagged'). +mk_rv() -> mk_temp(hipe_sparc_registers:return_value(), 'tagged'). +mk_sp() -> mk_temp(hipe_sparc_registers:stack_pointer(), 'untagged'). +mk_temp1() -> mk_temp(hipe_sparc_registers:temp1(), 'untagged'). +mk_temp2() -> mk_temp(hipe_sparc_registers:temp2(), 'untagged'). + +mk_simm13(Value) -> #sparc_simm13{value=Value}. +mk_uimm5(Value) -> #sparc_uimm5{value=Value}. +mk_uimm22(Value) -> #sparc_uimm22{value=Value}. + +mk_mfa(M, F, A) -> #sparc_mfa{m=M, f=F, a=A}. + +mk_prim(Prim) -> #sparc_prim{prim=Prim}. +is_prim(X) -> case X of #sparc_prim{} -> true; _ -> false end. +prim_prim(#sparc_prim{prim=Prim}) -> Prim. + +mk_sdesc(ExnLab, FSize, Arity, Live) -> + #sparc_sdesc{exnlab=ExnLab, fsize=FSize, arity=Arity, live=Live}. + +mk_alu(AluOp, Src1, Src2, Dst) -> + #alu{aluop=AluOp, src1=Src1, src2=Src2, dst=Dst}. +mk_mov(Src, Dst) -> mk_alu('or', mk_g0(), Src, Dst). + +mk_bp(Cond, Label, Pred) -> #bp{'cond'=Cond, label=Label, pred=Pred}. +mk_b_label(Label) -> mk_bp('a', Label, 1.0). + +-ifdef(notdef). % XXX: only for sparc64, alas +mk_br(RCond, Src, Label, Pred) -> + #br{rcond=RCond, src=Src, label=Label, pred=Pred}. +-endif. + +mk_call_rec(Fun, SDesc, Linkage) -> + #call_rec{'fun'=Fun, sdesc=SDesc, linkage=Linkage}. + +mk_call_tail(Fun, Linkage) -> #call_tail{'fun'=Fun, linkage=Linkage}. + +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. + +mk_jmp(Src1, Src2, Labels) -> #jmp{src1=Src1, src2=Src2, labels=Labels}. + +mk_jmpl(Src, SDesc) -> #jmpl{src=Src, sdesc=SDesc}. + +mk_pseudo_bp(Cond, TrueLab, FalseLab, Pred) -> + if Pred >= 0.5 -> + mk_pseudo_bp_simple(negate_cond(Cond), FalseLab, + TrueLab, 1.0-Pred); + true -> + mk_pseudo_bp_simple(Cond, TrueLab, FalseLab, Pred) + end. + +mk_pseudo_bp_simple(Cond, TrueLab, FalseLab, Pred) when Pred =< 0.5 -> + #pseudo_bp{'cond'=Cond, true_label=TrueLab, + false_label=FalseLab, pred=Pred}. + +negate_cond(Cond) -> + case Cond of + 'l' -> 'ge'; % <, >= + 'ge' -> 'l'; % >=, < + 'g' -> 'le'; % >, <= + 'le' -> 'g'; % <=, > + 'e' -> 'ne'; % ==, != + 'ne' -> 'e'; % !=, == + 'gu' -> 'leu'; % >u, <=u + 'leu'-> 'gu'; % <=u, >u + 'geu'-> 'lu'; % >=u, <u + 'lu' -> 'geu'; % <u, >=u + 'vs' -> 'vc'; % overflow, not_overflow + 'vc' -> 'vs' % not_overflow, overflow + end. + +-ifdef(notdef). % XXX: only for sparc64, alas +mk_pseudo_br(RCond, Src, TrueLab, FalseLab, Pred) -> + if Pred >= 0.5 -> + mk_pseudo_br_simple(negate_rcond(RCond), Src, FalseLab, + TrueLab, 1.0-Pred); + true -> + mk_pseudo_br_simple(RCond, Src, TrueLab, FalseLab, Pred) + end. + +mk_pseudo_br_simple(RCond, Src, TrueLab, FalseLab, Pred) when Pred =< 0.5 -> + #pseudo_br{rcond=RCond, src=Src, true_label=TrueLab, + false_label=FalseLab, pred=Pred}. + +negate_rcond(RCond) -> + case RCond of + 'z' -> 'nz'; % ==, != + 'nz' -> 'z'; % !=, == + 'gz' -> 'lez'; % >, <= + 'lez' -> 'gz'; % <=, > + 'gez' -> 'lz'; % >=, < + 'lz' -> 'gez' % <, >= + end. +-endif. + +mk_pseudo_call(FunV, SDesc, ContLab, Linkage) -> + #pseudo_call{funv=FunV, sdesc=SDesc, contlab=ContLab, linkage=Linkage}. +pseudo_call_funv(#pseudo_call{funv=FunV}) -> FunV. +pseudo_call_contlab(#pseudo_call{contlab=ContLab}) -> ContLab. +pseudo_call_linkage(#pseudo_call{linkage=Linkage}) -> Linkage. +pseudo_call_sdesc(#pseudo_call{sdesc=SDesc}) -> SDesc. + +mk_pseudo_call_prepare(NrStkArgs) -> + #pseudo_call_prepare{nrstkargs=NrStkArgs}. +pseudo_call_prepare_nrstkargs(#pseudo_call_prepare{nrstkargs=NrStkArgs}) -> + NrStkArgs. + +mk_pseudo_move(Src, Dst) -> #pseudo_move{src=Src, dst=Dst}. +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_ret() -> #pseudo_ret{}. + +mk_pseudo_set(Imm, Dst) -> #pseudo_set{imm=Imm, dst=Dst}. + +mk_pseudo_tailcall(FunV, Arity, StkArgs, Linkage) -> + #pseudo_tailcall{funv=FunV, arity=Arity, stkargs=StkArgs, linkage=Linkage}. +pseudo_tailcall_funv(#pseudo_tailcall{funv=FunV}) -> FunV. +pseudo_tailcall_linkage(#pseudo_tailcall{linkage=Linkage}) -> Linkage. +pseudo_tailcall_stkargs(#pseudo_tailcall{stkargs=StkArgs}) -> StkArgs. + +mk_pseudo_tailcall_prepare() -> #pseudo_tailcall_prepare{}. + +mk_rdy(Dst) -> #rdy{dst=Dst}. + +mk_sethi(UImm22, Dst) -> #sethi{uimm22=UImm22, dst=Dst}. +mk_nop() -> mk_sethi(mk_uimm22(0), mk_g0()). + +%%% Load an integer constant into a register. +mk_set(Value, Dst) -> mk_set(Value, Dst, []). + +mk_set(Value, Dst, Tail) -> + if -4096 =< Value, Value < 4096 -> + [mk_alu('or', mk_g0(), mk_simm13(Value), Dst) | Tail]; + true -> + Hi22 = mk_uimm22((Value bsr 10) band 16#003FFFFF), + case (Value band 16#3FF) of + 0 -> + [mk_sethi(Hi22, Dst) | Tail]; + Lo10 -> + [mk_sethi(Hi22, Dst), + mk_alu('or', Dst, mk_simm13(Lo10), Dst) | + Tail] + end + end. + +%%% Add an integer constant. Dst may equal Src, +%%% in which case temp2 may be clobbered. +mk_addi(Src, Value, Dst, Tail) -> + if -4096 =< Value, Value < 4096 -> + [mk_alu('add', Src, mk_simm13(Value), Dst) | Tail]; + true -> + Tmp = + begin + DstReg = temp_reg(Dst), + SrcReg = temp_reg(Src), + if DstReg =:= SrcReg -> mk_temp2(); + true -> Dst + end + end, + mk_set(Value, Tmp, [mk_alu('add', Src, Tmp, Dst) | Tail]) + end. + +mk_store(StOp, Src, Base, Disp) -> + #store{stop=StOp, src=Src, base=Base, disp=Disp}. + +mk_store(StOp, Src, Base, Offset, Scratch, Rest) when is_integer(Offset) -> + if -4096 =< Offset, Offset < 4096 -> + [mk_store(StOp, Src, Base, mk_simm13(Offset)) | Rest]; + true -> + Index = mk_scratch(Scratch), + mk_set(Offset, Index, [mk_store(StOp, Src, Base, Index) | Rest]) + end. + +mk_load(LdOp, Base, Disp, Dst) -> + mk_alu(LdOp, Base, Disp, Dst). + +mk_load(LdOp, Base, Offset, Dst, Scratch, Rest) when is_integer(Offset) -> + if -4096 =< Offset, Offset < 4096 -> + [mk_load(LdOp, Base, mk_simm13(Offset), Dst) | Rest]; + true -> + Index = + begin + DstReg = temp_reg(Dst), + BaseReg = temp_reg(Base), + if DstReg =/= BaseReg -> Dst; + true -> mk_scratch(Scratch) + end + end, + mk_set(Offset, Index, [mk_load(LdOp, Base, Index, Dst) | Rest]) + end. + +mk_scratch(Scratch) -> + case Scratch of + 'temp2' -> mk_temp2(); + 'new' -> mk_new_temp('untagged') + end. + +mk_fp_binary(FpBinOp, Src1, Src2, Dst) -> + #fp_binary{fp_binop=FpBinOp, src1=Src1, src2=Src2, dst=Dst}. + +mk_fp_unary(FpUnOp, Src, Dst) -> #fp_unary{fp_unop=FpUnOp, src=Src, dst=Dst}. + +mk_pseudo_fload(Base, Disp, Dst, IsSingle) -> + #pseudo_fload{base=Base, disp=Disp, dst=Dst, is_single=IsSingle}. + +mk_fload(Base, Disp, Dst, Scratch) when is_integer(Disp) -> + if -4096 =< Disp, Disp < (4096-4) -> + [mk_pseudo_fload(Base, mk_simm13(Disp), Dst, false)]; + true -> + Tmp = mk_scratch(Scratch), + mk_set(Disp, Tmp, + [mk_alu('add', Tmp, Base, Tmp), + mk_pseudo_fload(Tmp, mk_simm13(0), Dst, false)]) + end. + +mk_pseudo_fmove(Src, Dst) -> #pseudo_fmove{src=Src, dst=Dst}. +is_pseudo_fmove(I) -> case I of #pseudo_fmove{} -> true; _ -> false end. +pseudo_fmove_src(#pseudo_fmove{src=Src}) -> Src. +pseudo_fmove_dst(#pseudo_fmove{dst=Dst}) -> Dst. + +mk_pseudo_fstore(Src, Base, Disp) -> + #pseudo_fstore{src=Src, base=Base, disp=Disp}. + +mk_fstore(Src, Base, Disp, Scratch) when is_integer(Disp) -> + if -4096 =< Disp, Disp < (4096-4) -> + [mk_pseudo_fstore(Src, Base, hipe_sparc:mk_simm13(Disp))]; + true -> + Tmp = mk_scratch(Scratch), + mk_set(Disp, Tmp, + [mk_alu('add', Tmp, Base, Tmp), + mk_pseudo_fstore(Src, Tmp, mk_simm13(0))]) + end. + +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_code(#defun{code=Code}) -> Code. +defun_data(#defun{data=Data}) -> Data. +defun_formals(#defun{formals=Formals}) -> Formals. +defun_is_closure(#defun{isclosure=IsClosure}) -> IsClosure. +defun_is_leaf(#defun{isleaf=IsLeaf}) -> IsLeaf. +defun_mfa(#defun{mfa=MFA}) -> MFA. +defun_var_range(#defun{var_range=VarRange}) -> VarRange. |