diff options
Diffstat (limited to 'lib/hipe/x86/hipe_x86_pp.erl')
-rw-r--r-- | lib/hipe/x86/hipe_x86_pp.erl | 350 |
1 files changed, 350 insertions, 0 deletions
diff --git a/lib/hipe/x86/hipe_x86_pp.erl b/lib/hipe/x86/hipe_x86_pp.erl new file mode 100644 index 0000000000..555e21a446 --- /dev/null +++ b/lib/hipe/x86/hipe_x86_pp.erl @@ -0,0 +1,350 @@ +%%% -*- 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% +%%% +%%% x86 pretty-printer + +-ifdef(HIPE_AMD64). +-define(HIPE_X86_PP, hipe_amd64_pp). +-define(HIPE_X86_REGISTERS, hipe_amd64_registers). +-else. +-define(HIPE_X86_PP, hipe_x86_pp). +-define(HIPE_X86_REGISTERS, hipe_x86_registers). +-endif. + +-module(?HIPE_X86_PP). +-export([% pp/1, pp/2, + pp_insn/1, optional_pp/3]). +-include("../x86/hipe_x86.hrl"). + +optional_pp(Defun, MFA, Options) -> + case proplists:get_value(pp_native, Options) of + true -> + pp(Defun); + {only,Lst} when is_list(Lst) -> + case lists:member(MFA, Lst) of + true -> pp(Defun); + false -> ok + end; + {only,MFA} -> + pp(Defun); + {file,FileName} -> + {ok, File} = file:open(FileName, [write,append]), + pp(File, Defun), + ok = file:close(File); + _ -> + ok + end. + +pp(Defun) -> + pp(standard_io, Defun). + +pp(Dev, #defun{mfa={M,F,A}, code=Code, data=Data}) -> + Fname = atom_to_list(M)++"_"++atom_to_list(F)++"_"++integer_to_list(A), + io:format(Dev, "\t.text\n", []), + io:format(Dev, "\t.align 4\n", []), + io:format(Dev, "\t.global ~s\n", [Fname]), + io:format(Dev, "~s:\n", [Fname]), + pp_insns(Dev, Code, Fname), + io:format(Dev, "\t.rodata\n", []), + io:format(Dev, "\t.align 4\n", []), + hipe_data_pp:pp(Dev, Data, x86, Fname), + io:format(Dev, "\n", []). + +pp_insns(Dev, [I|Is], Fname) -> + pp_insn(Dev, I, Fname), + pp_insns(Dev, Is, Fname); +pp_insns(_, [], _) -> + ok. + +pp_insn(I) -> + pp_insn(standard_io, I, ""). + +pp_insn(Dev, I, Pre) -> + case I of + #alu{aluop=AluOp, src=Src, dst=Dst} -> + io:format(Dev, "\t~s ", [alu_op_name(AluOp)]), + pp_src(Dev, Src), + io:format(Dev, ", ", []), + pp_dst(Dev, Dst), + io:format(Dev, "\n", []); + #call{'fun'=Fun, sdesc=SDesc, linkage=Linkage} -> + io:format(Dev, "\tcall ", []), + pp_fun(Dev, Fun), + io:format(Dev, " #", []), + pp_sdesc(Dev, Pre, SDesc), + io:format(Dev, " ~w\n", [Linkage]); + #cmovcc{cc=Cc, src=Src, dst=Dst} -> + io:format(Dev, "\tcmov~s ", [cc_name(Cc)]), + pp_src(Dev, Src), + io:format(Dev, ", ", []), + pp_dst(Dev, Dst), + io:format(Dev, "\n", []); + #cmp{src=Src, dst=Dst} -> + io:format(Dev, "\tcmp ", []), + pp_src(Dev, Src), + io:format(Dev, ", ", []), + pp_dst(Dev, Dst), + io:format(Dev, "\n", []); + #comment{term=Term} -> + io:format(Dev, "\t# ~p\n", [Term]); + #imul{imm_opt=ImmOpt, src=Src, temp=Temp} -> + io:format(Dev, "\timul ", []), + case ImmOpt of + [] -> ok; + Imm -> + pp_imm(Dev, Imm, true), + io:format(Dev, ", ", []) + end, + pp_src(Dev, Src), + io:format(Dev, ", ", []), + pp_temp(Dev, Temp), + io:format(Dev, "\n", []); + #jcc{cc=Cc, label=Label} -> + io:format(Dev, "\tj~s .~s_~w\n", [cc_name(Cc), Pre, Label]); + #jmp_fun{'fun'=Fun, linkage=Linkage} -> + io:format(Dev, "\tjmp ", []), + pp_fun(Dev, Fun), + io:format(Dev, " ~w\n", [Linkage]); + #jmp_label{label=Label} -> + io:format(Dev, "\tjmp .~s_~w\n", [Pre, Label]); + #jmp_switch{temp=Temp, jtab=JTab, labels=Labels} -> + io:format(Dev, "\tjmp *{constant,~w}(,", [JTab]), + pp_temp(Dev, Temp), + io:format(Dev, ",4) #", []), + pp_labels(Dev, Labels, Pre), + io:format(Dev, "\n", []); + #label{label=Label} -> + io:format(Dev, ".~s_~w:~n", [Pre, Label]); + #lea{mem=Mem, temp=Temp} -> + io:format(Dev, "\tlea ", []), + pp_mem(Dev, Mem), + io:format(Dev, ", ", []), + pp_temp(Dev, Temp), + io:format(Dev, "\n", []); + #move{src=Src, dst=Dst} -> + io:format(Dev, "\tmov ", []), + pp_src(Dev, Src), + io:format(Dev, ", ", []), + pp_dst(Dev, Dst), + io:format(Dev, "\n", []); + #move64{} -> + pp_move64(Dev, I); + #movsx{src=Src, dst=Dst} -> + io:format(Dev, "\tmovsx ", []), + pp_src(Dev, Src), + io:format(Dev, ", ", []), + pp_dst(Dev, Dst), + io:format(Dev, "\n", []); + #movzx{src=Src, dst=Dst} -> + io:format(Dev, "\tmovzx ", []), + pp_src(Dev, Src), + io:format(Dev, ", ", []), + pp_dst(Dev, Dst), + io:format(Dev, "\n", []); + #pseudo_call{'fun'=Fun, sdesc=SDesc, contlab=ContLab, linkage=Linkage} -> + io:format(Dev, "\tpseudo_call ", []), + pp_fun(Dev, Fun), + io:format(Dev, " # contlab .~s_~w", [Pre, ContLab]), + pp_sdesc(Dev, Pre, SDesc), + io:format(Dev, " ~w\n", [Linkage]); + #pseudo_jcc{cc=Cc, true_label=TrueLab, false_label=FalseLab, pred=Pred} -> + io:format(Dev, "\tpseudo_j~s ", [cc_name(Cc)]), + io:format(Dev, ".~s_~w # .~s_~w ~.2f\n", + [Pre, TrueLab, Pre, FalseLab, Pred]); + #pseudo_tailcall{'fun'=Fun, arity=Arity, stkargs=StkArgs, linkage=Linkage} -> + io:format(Dev, "\tpseudo_tailcall ", []), + pp_fun(Dev, Fun), + io:format(Dev, "~w (", [Arity]), + pp_args(Dev, StkArgs), + io:format(Dev, ") ~w\n", [Linkage]); + #pseudo_tailcall_prepare{} -> + io:format(Dev, "\tpseudo_tailcall_prepare\n", []); + #push{src=Src} -> + io:format(Dev, "\tpush ", []), + pp_src(Dev, Src), + io:format(Dev, "\n", []); + #ret{npop=NPop} -> + io:format(Dev, "\tret $~s\n", [to_hex(NPop)]); + #shift{shiftop=ShiftOp, src=Src, dst=Dst} -> + io:format(Dev, "\t~s ", [alu_op_name(ShiftOp)]), + pp_src(Dev, Src), + io:format(Dev, ", ", []), + pp_dst(Dev, Dst), + io:format(Dev, "\n", []); + #fp_binop{src=Src, dst=Dst, op=Op} -> + io:format(Dev, "\t~s ", [Op]), + pp_dst(Dev, Dst), + io:format(Dev, ", ", []), + pp_src(Dev, Src), + io:format(Dev, "\n", []); + #fp_unop{arg=Arg, op=Op} -> + io:format(Dev, "\t~s ", [Op]), + case Arg of + []-> + io:format(Dev, "\n", []); + _ -> + pp_args(Dev, [Arg]), + io:format(Dev, "\n", []) + end; + #fmove{src=Src, dst=Dst} -> + io:format(Dev, "\tfmove ", []), + pp_src(Dev, Src), + io:format(Dev, ", ", []), + pp_dst(Dev, Dst), + io:format(Dev, "\n", []); + _ -> + exit({?MODULE, pp_insn, {"unknown x86 instruction", I}}) + end. + +-ifdef(HIPE_AMD64). +pp_move64(Dev, I) -> + #move64{imm=Src, dst=Dst} = I, + io:format(Dev, "\tmov64 ", []), + pp_src(Dev, Src), + io:format(Dev, ", ", []), + pp_dst(Dev, Dst), + io:format(Dev, "\n", []). +-else. +pp_move64(_Dev, I) -> exit({?MODULE, I}). +-endif. + +to_hex(N) -> + io_lib:format("~.16x", [N, "0x"]). + +pp_sdesc(Dev, Pre, #x86_sdesc{exnlab=ExnLab,fsize=FSize,arity=Arity,live=Live}) -> + pp_sdesc_exnlab(Dev, Pre, ExnLab), + io:format(Dev, " ~s ~w [", [to_hex(FSize), Arity]), + pp_sdesc_live(Dev, Live), + io:format(Dev, "]", []). + +pp_sdesc_exnlab(Dev, _, []) -> io:format(Dev, " []", []); +pp_sdesc_exnlab(Dev, Pre, ExnLab) -> io:format(Dev, " .~s_~w", [Pre, ExnLab]). + +pp_sdesc_live(_, {}) -> ok; +pp_sdesc_live(Dev, Live) -> pp_sdesc_live(Dev, Live, 1). + +pp_sdesc_live(Dev, Live, I) -> + io:format(Dev, "~s", [to_hex(element(I, Live))]), + if I < tuple_size(Live) -> + io:format(Dev, ",", []), + pp_sdesc_live(Dev, Live, I+1); + true -> ok + end. + +pp_labels(Dev, [Label|Labels], Pre) -> + io:format(Dev, " .~s_~w", [Pre, Label]), + pp_labels(Dev, Labels, Pre); +pp_labels(_, [], _) -> + ok. + +pp_fun(Dev, Fun) -> + case Fun of + #x86_mfa{m=M, f=F, a=A} -> + io:format(Dev, "~w:~w/~w", [M, F, A]); + #x86_prim{prim=Prim} -> + io:format(Dev, "~w", [Prim]); + _ -> % temp or mem + io:format(Dev, "*", []), + pp_dst(Dev, Fun) + end. + +alu_op_name(Op) -> Op. + +cc_name(Cc) -> Cc. + +pp_hard_reg(Dev, Reg) -> + io:format(Dev, "~s", [?HIPE_X86_REGISTERS:reg_name(Reg)]). + +type_tag('tagged') -> "t"; +type_tag('untagged') -> "u"; +type_tag('double') -> "d". + +pp_temp(Dev, #x86_temp{reg=Reg, type=Type}) -> + case Type of + double -> + Tag = type_tag(Type), + io:format(Dev, "~s~w", [Tag, Reg]); + _ -> + case ?HIPE_X86_REGISTERS:is_precoloured(Reg) of + true -> + pp_hard_reg(Dev, Reg); + false -> + Tag = type_tag(Type), + io:format(Dev, "~s~w", [Tag, Reg]) + end + end. + +pp_fpreg(Dev, #x86_fpreg{reg=Reg, pseudo=Pseudo})-> + case Pseudo of + true -> io:format(Dev, "pseudo_fp(~w)", [Reg]); + _ -> io:format(Dev, "st(~w)", [Reg]) + end. + +pp_imm(Dev, #x86_imm{value=Value}, Dollar) -> + if Dollar =:= true -> io:format(Dev, [$$], []); + true -> ok + end, + if is_integer(Value) -> io:format(Dev, "~s", [to_hex(Value)]); + true -> io:format(Dev, "~w", [Value]) + end. + +pp_mem(Dev, #x86_mem{base=Base, off=Off}) -> + pp_off(Dev, Off), + case Base of + [] -> + ok; + _ -> + io:format(Dev, "(", []), + pp_temp(Dev, Base), + io:format(Dev, ")", []) + end. + +pp_off(Dev, Off) -> + pp_src(Dev, Off, false). + +pp_src(Dev, Src) -> + pp_src(Dev, Src, true). + +pp_src(Dev, Src, Dollar) -> + case Src of + #x86_temp{} -> + pp_temp(Dev, Src); + #x86_imm{} -> + pp_imm(Dev, Src, Dollar); + #x86_mem{} -> + pp_mem(Dev, Src); + #x86_fpreg{} -> + pp_fpreg(Dev, Src) + end. + +pp_dst(Dev, Dst) -> + pp_src(Dev, Dst). + +pp_args(Dev, [A|As]) -> + pp_src(Dev, A), + pp_comma_args(Dev, As); +pp_args(_, []) -> + ok. + +pp_comma_args(Dev, [A|As]) -> + io:format(Dev, ", ", []), + pp_src(Dev, A), + pp_comma_args(Dev, As); +pp_comma_args(_, []) -> + ok. |