%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% 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_spill_fmove/3,
is_pseudo_spill_fmove/1,
mk_pseudo_spill_move/3,
is_pseudo_spill_move/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
]).
%% Other utilities
-export([neg_cc/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_spill_fmove(Src, Temp, Dst) ->
#pseudo_spill_fmove{src=Src, temp=Temp, dst=Dst}.
is_pseudo_spill_fmove(I) -> is_record(I, pseudo_spill_fmove).
mk_pseudo_spill_move(Src, Temp, Dst) ->
#pseudo_spill_move{src=Src, temp=Temp, dst=Dst}.
is_pseudo_spill_move(I) -> is_record(I, pseudo_spill_move).
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.