aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hipe/x86/hipe_x86.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/hipe/x86/hipe_x86.erl')
-rw-r--r--lib/hipe/x86/hipe_x86.erl496
1 files changed, 496 insertions, 0 deletions
diff --git a/lib/hipe/x86/hipe_x86.erl b/lib/hipe/x86/hipe_x86.erl
new file mode 100644
index 0000000000..3298151366
--- /dev/null
+++ b/lib/hipe/x86/hipe_x86.erl
@@ -0,0 +1,496 @@
+%%
+%% %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%
+%%
+%% representation of 2-address pseudo-amd64 code
+
+-module(hipe_x86).
+
+-include("hipe_x86.hrl").
+
+%% Commented out are interface functions which are currently not used.
+-export([mk_temp/2,
+ %% mk_nonallocatable_temp/2,
+ mk_new_temp/1,
+ mk_new_nonallocatable_temp/1,
+ is_temp/1,
+ temp_reg/1,
+ temp_type/1,
+ temp_is_allocatable/1,
+
+ mk_imm/1,
+ mk_imm_from_addr/2,
+ mk_imm_from_atom/1,
+ is_imm/1,
+ %% imm_value/1,
+
+ mk_mem/3,
+ %% is_mem/1,
+ %% mem_base/1,
+ %% mem_off/1,
+ mem_type/1,
+
+ mk_fpreg/1,
+ mk_fpreg/2,
+ %% is_fpreg/1,
+ %% fpreg_is_pseudo/1,
+ %% fpreg_reg/1,
+
+ mk_mfa/3,
+ %% is_mfa/1,
+
+ mk_prim/1,
+ is_prim/1,
+ prim_prim/1,
+
+ mk_sdesc/4,
+
+ %% insn_type/1,
+
+ mk_alu/3,
+ %% is_alu/1,
+ alu_op/1,
+ alu_src/1,
+ alu_dst/1,
+
+ mk_call/3,
+ %% is_call/1,
+ call_fun/1,
+ call_sdesc/1,
+ call_linkage/1,
+
+ %% mk_cmovcc/3,
+ %% is_cmovcc/1,
+ cmovcc_cc/1,
+ cmovcc_src/1,
+ cmovcc_dst/1,
+
+ mk_cmp/2,
+ %% is_cmp/1,
+ cmp_src/1,
+ cmp_dst/1,
+
+ mk_comment/1,
+ %% is_comment/1,
+ %% comment_term/1,
+
+ mk_fmove/2,
+ is_fmove/1,
+ fmove_src/1,
+ fmove_dst/1,
+
+ mk_fp_unop/2,
+ %% is_fp_unop/1,
+ fp_unop_arg/1,
+ fp_unop_op/1,
+
+ mk_fp_binop/3,
+ %% is_fp_binop/1,
+ fp_binop_src/1,
+ fp_binop_dst/1,
+ fp_binop_op/1,
+
+ mk_imul/3,
+ imul_imm_opt/1,
+ imul_src/1,
+ imul_temp/1,
+
+ mk_jcc/2,
+ %% is_jcc/1,
+ jcc_cc/1,
+ jcc_label/1,
+
+ mk_jmp_fun/2,
+ %% is_jmp_fun/1,
+ jmp_fun_fun/1,
+ jmp_fun_linkage/1,
+
+ mk_jmp_label/1,
+ %% is_jmp_label/1,
+ jmp_label_label/1,
+
+ mk_jmp_switch/3,
+ %% is_jmp_switch/1,
+ jmp_switch_temp/1,
+ jmp_switch_jtab/1,
+ %% jmp_switch_labels/1,
+
+ mk_label/1,
+ is_label/1,
+ label_label/1,
+
+ mk_lea/2,
+ %% is_lea/1,
+ lea_mem/1,
+ lea_temp/1,
+
+ mk_move/2,
+ is_move/1,
+ move_src/1,
+ move_dst/1,
+ mk_move64/2,
+ %% is_move64/1,
+ move64_src/1,
+ move64_dst/1,
+
+ mk_movsx/2,
+ %% is_movsx/1,
+ movsx_src/1,
+ movsx_dst/1,
+
+ mk_movzx/2,
+ %% is_movzx/1,
+ movzx_src/1,
+ movzx_dst/1,
+
+ mk_pseudo_call/4,
+ %% is_pseudo_call/1,
+ pseudo_call_fun/1,
+ pseudo_call_sdesc/1,
+ pseudo_call_contlab/1,
+ pseudo_call_linkage/1,
+
+ mk_pseudo_jcc/4,
+ %% is_pseudo_jcc/1,
+ %% pseudo_jcc_cc/1,
+ %% pseudo_jcc_true_label/1,
+ %% pseudo_jcc_false_label/1,
+ %% pseudo_jcc_pred/1,
+
+ mk_pseudo_spill/1,
+
+ mk_pseudo_tailcall/4,
+ %% is_pseudo_tailcall/1,
+ pseudo_tailcall_fun/1,
+ %% pseudo_tailcall_arity/1,
+ pseudo_tailcall_stkargs/1,
+ pseudo_tailcall_linkage/1,
+
+ mk_pseudo_tailcall_prepare/0,
+ %% is_pseudo_tailcall_prepare/1,
+
+ mk_push/1,
+ %% is_push/1,
+ push_src/1,
+
+ %% mk_pop/1,
+ pop_dst/1,
+
+ mk_ret/1,
+ %% is_ret/1,
+ ret_npop/1,
+
+ mk_shift/3,
+ %% is_shift/1,
+ shift_op/1,
+ shift_src/1,
+ shift_dst/1,
+
+ %% mk_test/2,
+ test_src/1,
+ test_dst/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
+ %% defun_label_range/1,
+
+ %% highest_temp/1
+ ]).
+
+%%%
+%%% Low-level accessors.
+%%%
+
+mk_temp(Reg, Type) when is_integer(Reg) ->
+ #x86_temp{reg=Reg, type=Type, allocatable=true}.
+mk_nonallocatable_temp(Reg, Type) when is_integer(Reg) ->
+ #x86_temp{reg=Reg, type=Type, allocatable=false}.
+mk_new_temp(Type) ->
+ mk_temp(hipe_gensym:get_next_var(x86), Type).
+mk_new_nonallocatable_temp(Type) ->
+ mk_nonallocatable_temp(hipe_gensym:get_next_var(x86), Type).
+is_temp(X) -> case X of #x86_temp{} -> true; _ -> false end.
+temp_reg(#x86_temp{reg=Reg}) when is_integer(Reg) -> Reg.
+temp_type(#x86_temp{type=Type}) -> Type.
+temp_is_allocatable(#x86_temp{allocatable=A}) -> A.
+
+mk_imm(Value) -> #x86_imm{value=Value}.
+mk_imm_from_addr(Addr, Type) ->
+ mk_imm({Addr, Type}).
+mk_imm_from_atom(Atom) ->
+ mk_imm(Atom).
+is_imm(X) -> case X of #x86_imm{} -> true; _ -> false end.
+%% imm_value(#x86_imm{value=Value}) -> Value.
+
+mk_mem(Base, Off, Type) -> #x86_mem{base=Base, off=Off, type=Type}.
+%% is_mem(X) -> case X of #x86_mem{} -> true; _ -> false end.
+%% mem_base(#x86_mem{base=Base}) -> Base.
+%% mem_off(#x86_mem{off=Off}) -> Off.
+mem_type(#x86_mem{type=Type}) -> Type.
+
+mk_fpreg(Reg) -> #x86_fpreg{reg=Reg, pseudo=true}.
+mk_fpreg(Reg, Pseudo) -> #x86_fpreg{reg=Reg, pseudo=Pseudo}.
+%% is_fpreg(F) -> case F of #x86_fpreg{} -> true;_ -> false end.
+%% fpreg_is_pseudo(#x86_fpreg{pseudo=Pseudo}) -> Pseudo.
+%% fpreg_reg(#x86_fpreg{reg=Reg}) -> Reg.
+
+mk_mfa(M, F, A) -> #x86_mfa{m=M, f=F, a=A}.
+%% is_mfa(X) -> case X of #x86_mfa{} -> true; _ -> false end.
+
+mk_prim(Prim) -> #x86_prim{prim=Prim}.
+is_prim(X) -> case X of #x86_prim{} -> true; _ -> false end.
+prim_prim(#x86_prim{prim=Prim}) -> Prim.
+
+mk_sdesc(ExnLab, FSize, Arity, Live) ->
+ #x86_sdesc{exnlab=ExnLab, fsize=FSize, arity=Arity, live=Live}.
+
+insn_type(Insn) ->
+ element(1, Insn).
+
+is_insn_type(Insn, Type) ->
+ case insn_type(Insn) of
+ Type -> true;
+ _ -> false
+ end.
+
+mk_alu(Op, Src, Dst) -> #alu{aluop=Op, src=Src, dst=Dst}.
+%% is_alu(Insn) -> is_insn_type(Insn, alu).
+alu_op(#alu{aluop=Op}) -> Op.
+alu_src(#alu{src=Src}) -> Src.
+alu_dst(#alu{dst=Dst}) -> Dst.
+
+mk_call(Fun, SDesc, Linkage) ->
+ check_linkage(Linkage),
+ #call{'fun'=Fun, sdesc=SDesc, linkage=Linkage}.
+%% is_call(Insn) -> is_insn_type(Insn, call).
+call_fun(#call{'fun'=Fun}) -> Fun.
+call_sdesc(#call{sdesc=SDesc}) -> SDesc.
+call_linkage(#call{linkage=Linkage}) -> Linkage.
+
+check_linkage(Linkage) ->
+ case Linkage of
+ remote -> [];
+ not_remote -> []
+ end.
+
+%% mk_cmovcc(Cc, Src, Dst) -> #cmovcc{cc=Cc, src=Src, dst=Dst}.
+%% is_cmovcc(Insn) -> is_insn_type(Insn, cmovcc).
+cmovcc_cc(#cmovcc{cc=Cc}) -> Cc.
+cmovcc_src(#cmovcc{src=Src}) -> Src.
+cmovcc_dst(#cmovcc{dst=Dst}) -> Dst.
+
+mk_cmp(Src, Dst) -> #cmp{src=Src, dst=Dst}.
+%% is_cmp(Insn) -> is_insn_type(Insn, cmp).
+cmp_src(#cmp{src=Src}) -> Src.
+cmp_dst(#cmp{dst=Dst}) -> Dst.
+
+%% mk_test(Src, Dst) -> #test{src=Src, dst=Dst}.
+test_src(#test{src=Src}) -> Src.
+test_dst(#test{dst=Dst}) -> Dst.
+
+mk_comment(Term) -> #comment{term=Term}.
+%% is_comment(Insn) -> is_insn_type(Insn, comment).
+%% comment_term(#comment{term=Term}) -> Term.
+
+mk_fmove(Src, Dst) -> #fmove{src=Src, dst=Dst}.
+is_fmove(F) -> is_insn_type(F, fmove).
+fmove_src(#fmove{src=Src}) -> Src.
+fmove_dst(#fmove{dst=Dst}) -> Dst.
+
+mk_fp_unop(Op, Arg) -> #fp_unop{op=Op, arg=Arg}.
+%% is_fp_unop(F) -> is_insn_type(F, fp_unop).
+fp_unop_arg(#fp_unop{arg=Arg}) -> Arg.
+fp_unop_op(#fp_unop{op=Op}) -> Op.
+
+mk_fp_binop(Op, Src, Dst) -> #fp_binop{op=Op, src=Src, dst=Dst}.
+%% is_fp_binop(F) -> is_insn_type(F, fp_binop).
+fp_binop_src(#fp_binop{src=Src}) -> Src.
+fp_binop_dst(#fp_binop{dst=Dst}) -> Dst.
+fp_binop_op(#fp_binop{op=Op}) -> Op.
+
+mk_imul(ImmOpt, Src, Temp) -> #imul{imm_opt=ImmOpt, src=Src, temp=Temp}.
+imul_imm_opt(#imul{imm_opt=ImmOpt}) -> ImmOpt.
+imul_src(#imul{src=Src}) -> Src.
+imul_temp(#imul{temp=Temp}) -> Temp.
+
+mk_jcc(Cc, Label) -> #jcc{cc=Cc, label=Label}.
+%% is_jcc(Insn) -> is_insn_type(Insn, jcc).
+jcc_cc(#jcc{cc=Cc}) -> Cc.
+jcc_label(#jcc{label=Label}) -> Label.
+
+mk_jmp_fun(Fun, Linkage) ->
+ check_linkage(Linkage),
+ #jmp_fun{'fun'=Fun, linkage=Linkage}.
+%% is_jmp_fun(Insn) -> is_insn_type(Insn, jmp_fun).
+jmp_fun_fun(#jmp_fun{'fun'=Fun}) -> Fun.
+jmp_fun_linkage(#jmp_fun{linkage=Linkage}) -> Linkage.
+
+mk_jmp_label(Label) -> #jmp_label{label=Label}.
+%% is_jmp_label(Insn) -> is_insn_type(Insn, jmp_label).
+jmp_label_label(#jmp_label{label=Label}) -> Label.
+
+mk_jmp_switch(Temp, JTab, Labels) ->
+ #jmp_switch{temp=Temp, jtab=JTab, labels=Labels}.
+%% is_jmp_switch(Insn) -> is_insn_type(Insn, jmp_switch).
+jmp_switch_temp(#jmp_switch{temp=Temp}) -> Temp.
+jmp_switch_jtab(#jmp_switch{jtab=JTab}) -> JTab.
+%% jmp_switch_labels(#jmp_switch{labels=Labels}) -> Labels.
+
+mk_label(Label) -> #label{label=Label}.
+is_label(Insn) -> is_insn_type(Insn, label).
+label_label(#label{label=Label}) -> Label.
+
+mk_lea(Mem, Temp) -> #lea{mem=Mem, temp=Temp}.
+%% is_lea(Insn) -> is_insn_type(Insn, lea).
+lea_mem(#lea{mem=Mem}) -> Mem.
+lea_temp(#lea{temp=Temp}) -> Temp.
+
+mk_move(Src, Dst) -> #move{src=Src, dst=Dst}.
+is_move(Insn) -> is_insn_type(Insn, move).
+move_src(#move{src=Src}) -> Src.
+move_dst(#move{dst=Dst}) -> Dst.
+
+mk_move64(Imm, Dst) -> #move64{imm=Imm, dst=Dst}.
+%% is_move64(Insn) -> is_insn_type(Insn, move64).
+move64_src(#move64{imm=Imm}) -> Imm.
+move64_dst(#move64{dst=Dst}) -> Dst.
+
+mk_movsx(Src, Dst) -> #movsx{src=Src, dst=Dst}.
+%% is_movsx(Insn) -> is_insn_type(Insn, movsx).
+movsx_src(#movsx{src=Src}) -> Src.
+movsx_dst(#movsx{dst=Dst}) -> Dst.
+
+mk_movzx(Src, Dst) -> #movzx{src=Src, dst=Dst}.
+%% is_movzx(Insn) -> is_insn_type(Insn, movzx).
+movzx_src(#movzx{src=Src}) -> Src.
+movzx_dst(#movzx{dst=Dst}) -> Dst.
+
+mk_pseudo_call(Fun, SDesc, ContLab, Linkage) ->
+ check_linkage(Linkage),
+ #pseudo_call{'fun'=Fun, sdesc=SDesc, contlab=ContLab, linkage=Linkage}.
+%% is_pseudo_call(Insn) -> is_insn_type(Insn, pseudo_call).
+pseudo_call_fun(#pseudo_call{'fun'=Fun}) -> Fun.
+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_jcc(Cc, TrueLabel, FalseLabel, Pred) -> % 'smart' constructor
+ if Pred >= 0.5 ->
+ mk_pseudo_jcc_simple(neg_cc(Cc), FalseLabel, TrueLabel, 1.0-Pred);
+ true ->
+ mk_pseudo_jcc_simple(Cc, TrueLabel, FalseLabel, Pred)
+ end.
+neg_cc(Cc) ->
+ case Cc of
+ 'e' -> 'ne'; % ==, !=
+ 'ne' -> 'e'; % !=, ==
+ 'g' -> 'le'; % >, <=
+ 'a' -> 'be'; % >u, <=u
+ 'ge' -> 'l'; % >=, <
+ 'ae' -> 'b'; % >=u, <u
+ 'l' -> 'ge'; % <, >=
+ 'b' -> 'ae'; % <u, >=u
+ 'le' -> 'g'; % <=, >
+ 'be' -> 'a'; % <=u, >u
+ 'o' -> 'no'; % overflow, not_overflow
+ 'no' -> 'o'; % not_overflow, overflow
+ _ -> exit({?MODULE, {"unknown cc", Cc}})
+ end.
+mk_pseudo_jcc_simple(Cc, TrueLabel, FalseLabel, Pred) ->
+ #pseudo_jcc{cc=Cc, true_label=TrueLabel, false_label=FalseLabel, pred=Pred}.
+%% is_pseudo_jcc(Insn) -> is_insn_type(Insn, pseudo_jcc).
+%% pseudo_jcc_cc(#pseudo_jcc{cc=Cc}) -> Cc.
+%% pseudo_jcc_true_label(#pseudo_jcc{true_label=TrueLabel}) -> TrueLabel.
+%% pseudo_jcc_false_label(#pseudo_jcc{false_label=FalseLabel}) -> FalseLabel.
+%% pseudo_jcc_pred(#pseudo_jcc{pred=Pred}) -> Pred.
+
+mk_pseudo_spill(List) ->
+ #pseudo_spill{args=List}.
+
+mk_pseudo_tailcall(Fun, Arity, StkArgs, Linkage) ->
+ check_linkage(Linkage),
+ #pseudo_tailcall{'fun'=Fun, arity=Arity, stkargs=StkArgs, linkage=Linkage}.
+%% is_pseudo_tailcall(Insn) -> is_insn_type(Insn, pseudo_tailcall).
+pseudo_tailcall_fun(#pseudo_tailcall{'fun'=Fun}) -> Fun.
+%% pseudo_tailcall_arity(#pseudo_tailcall{arity=Arity}) -> Arity.
+pseudo_tailcall_stkargs(#pseudo_tailcall{stkargs=StkArgs}) -> StkArgs.
+pseudo_tailcall_linkage(#pseudo_tailcall{linkage=Linkage}) -> Linkage.
+
+mk_pseudo_tailcall_prepare() -> #pseudo_tailcall_prepare{}.
+%% is_pseudo_tailcall_prepare(Insn) -> is_insn_type(Insn, pseudo_tailcall_prepare).
+
+mk_push(Src) -> #push{src=Src}.
+%% is_push(Insn) -> is_insn_type(Insn, push).
+push_src(#push{src=Src}) -> Src.
+
+%% mk_pop(Dst) -> #pop{dst=Dst}.
+%% is_push(Insn) -> is_insn_type(Insn, push).
+pop_dst(#pop{dst=Dst}) -> Dst.
+
+mk_ret(NPop) -> #ret{npop=NPop}.
+%% is_ret(Insn) -> is_insn_type(Insn, ret).
+ret_npop(#ret{npop=NPop}) -> NPop.
+
+mk_shift(ShiftOp, Src, Dst) ->
+ #shift{shiftop=ShiftOp, src=Src, dst=Dst}.
+%% is_shift(Insn) -> is_insn_type(Insn, shift).
+shift_op(#shift{shiftop=ShiftOp}) -> ShiftOp.
+shift_src(#shift{src=Src}) -> Src.
+shift_dst(#shift{dst=Dst}) -> Dst.
+
+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.
+%% defun_label_range(#defun{label_range=LabelRange}) -> LabelRange.
+
+%% highest_temp(Code) ->
+%% highest_temp(Code,0).
+%%
+%% highest_temp([I|Is],Max) ->
+%% Defs = hipe_x86_defuse:insn_def(I),
+%% Uses = hipe_x86_defuse:insn_use(I),
+%% highest_temp(Is,new_max(Defs++Uses,Max));
+%% highest_temp([],Max) ->
+%% Max.
+%%
+%% new_max([V|Vs],Max) ->
+%% case is_temp(V) of
+%% true ->
+%% TReg = temp_reg(V),
+%% if TReg > Max ->
+%% new_max(Vs, TReg);
+%% true ->
+%% new_max(Vs, Max)
+%% end;
+%% false ->
+%% new_max(Vs, Max)
+%% end;
+%% new_max([],Max) -> Max.