aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hipe/rtl/hipe_icode2rtl.erl
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/hipe/rtl/hipe_icode2rtl.erl
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/hipe/rtl/hipe_icode2rtl.erl')
-rw-r--r--lib/hipe/rtl/hipe_icode2rtl.erl727
1 files changed, 727 insertions, 0 deletions
diff --git a/lib/hipe/rtl/hipe_icode2rtl.erl b/lib/hipe/rtl/hipe_icode2rtl.erl
new file mode 100644
index 0000000000..034153a3cb
--- /dev/null
+++ b/lib/hipe/rtl/hipe_icode2rtl.erl
@@ -0,0 +1,727 @@
+%% -*- 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%
+%%
+%%=======================================================================
+%% File : hipe_icode2rtl.erl
+%% Author(s) : Erik Johansson
+%% Description : Translates Icode to RTL
+%%=======================================================================
+%%
+%% $Id$
+%%
+%% TODO: Better handling of switches...
+
+-module(hipe_icode2rtl).
+
+-export([translate/2]).
+-export([translate_instrs/4]). %% used in hipe_rtl_mk_switch
+
+%%-------------------------------------------------------------------------
+
+%% -define(DEBUG,1). % used by hipe.hrl below
+
+-include("../main/hipe.hrl").
+-include("../icode/hipe_icode.hrl").
+-include("hipe_literals.hrl").
+
+%%-------------------------------------------------------------------------
+
+%% @spec translate(IcodeRecord::#icode{}, Options::options()) -> term()
+%%
+%% options() = [option()]
+%% option() = term()
+%%
+%% @doc Translates a linear form of Icode for a single function to a
+%% linear form of RTL-code.
+%%
+translate(IcodeRecord = #icode{}, Options) ->
+ ?IF_DEBUG_LEVEL(2, put(hipe_mfa, hipe_icode:icode_fun(IcodeRecord)), ok),
+ %% hipe_icode_pp:pp(Fun),
+
+ %% Initialize gensym and varmap
+ {Args, VarMap} = hipe_rtl_varmap:init(IcodeRecord),
+ %% Get the name and other info of the function to translate.
+ MFA = hipe_icode:icode_fun(IcodeRecord),
+ ConstTab = hipe_consttab:new(), % hipe_icode:icode_data(IcodeRecord),
+ %% io:format("~w\n", [ConstTab]),
+ Icode = hipe_icode:icode_code(IcodeRecord),
+ IsClosure = hipe_icode:icode_is_closure(IcodeRecord),
+ IsLeaf = hipe_icode:icode_is_leaf(IcodeRecord),
+ IcodeInfo = hipe_icode:icode_info(IcodeRecord),
+
+ %% Translate Icode instructions to RTL instructions
+ ?opt_start_timer("Icode to nested RTL"),
+ {Code, _VarMap1, ConstTab1} =
+ translate_instrs(Icode, VarMap, ConstTab, Options),
+ ?opt_stop_timer("Icode to nested RTL"),
+ %% We build the code as list of lists of...
+ %% in order to avoid appends.
+ ?opt_start_timer("Flatten RTL"),
+ Code1 = lists:flatten(Code),
+ ?opt_stop_timer("Flatten RTL"),
+ %% Build the RTL structure.
+ Rtl = hipe_rtl:mk_rtl(MFA,
+ Args,
+ IsClosure,
+ IsLeaf,
+ Code1,
+ ConstTab1,
+ {1, hipe_gensym:get_var(rtl)},
+ {1, hipe_gensym:get_label(rtl)}),
+ %% hipe_rtl:pp(Rtl),
+ %% Propagate info from Icode to RTL.
+ hipe_rtl:rtl_info_update(Rtl, IcodeInfo).
+
+%%-------------------------------------------------------------------------
+
+%%
+%% @doc Translates a list of Icode instructions to a list of RTL instructions.
+%%
+translate_instrs(Is, VarMap, ConstTab, Options) ->
+ translate_instrs(Is, VarMap, [], ConstTab, Options).
+
+translate_instrs([], VarMap, RTL_Code, ConstTab, _Options) ->
+ {RTL_Code, VarMap, ConstTab};
+translate_instrs([I|Is], VarMap, AccCode, ConstTab, Options) ->
+ %% Translate one instruction.
+ {Code, VarMap0, ConstTab0} =
+ translate_instruction(I, VarMap, ConstTab, Options),
+ %% ?IF_DEBUG_LEVEL(3,?msg(" To Instr: ~w~n",[Code]),no_debug),
+ ?IF_DEBUG(?when_option(rtl_show_translation, Options,
+ ?msg(" To Instr: ~w~n", [Code])), ok),
+ translate_instrs(Is, VarMap0, [AccCode,Code], ConstTab0, Options).
+
+%%
+%% @doc Translates an Icode instruction to one or more RTL instructions.
+%%
+
+translate_instruction(I, VarMap, ConstTab, Options) ->
+ %% ?IF_DEBUG_LEVEL(3,?msg("From Instr: ~w~n",[I]),no_debug),
+ ?IF_DEBUG(?when_option(rtl_show_translation, Options,
+ ?msg("From Instr: ~w~n", [I])), ok),
+ case I of
+ #icode_call{} ->
+ gen_call(I, VarMap, ConstTab);
+ #icode_comment{} ->
+ {hipe_rtl:mk_comment(hipe_icode:comment_text(I)), VarMap, ConstTab};
+ #icode_enter{} ->
+ gen_enter(I, VarMap, ConstTab);
+ #icode_fail{} ->
+ gen_fail(I, VarMap, ConstTab);
+ #icode_goto{} ->
+ gen_goto(I, VarMap, ConstTab);
+ #icode_if{} ->
+ gen_if(I, VarMap, ConstTab);
+ #icode_label{} ->
+ gen_label(I, VarMap, ConstTab);
+ #icode_move{} ->
+ gen_move(I, VarMap, ConstTab);
+ #icode_begin_handler{} ->
+ hipe_rtl_exceptions:gen_begin_handler(I, VarMap, ConstTab);
+ #icode_return{} ->
+ gen_return(I, VarMap, ConstTab);
+ #icode_switch_val{} ->
+ gen_switch_val(I, VarMap, ConstTab, Options);
+ #icode_switch_tuple_arity{} ->
+ gen_switch_tuple(I, VarMap, ConstTab, Options);
+ #icode_type{} ->
+ gen_type(I, VarMap, ConstTab);
+ X ->
+ exit({?MODULE,{"unknown Icode instruction",X}})
+ end.
+
+%%-------------------------------------------------------------------------
+
+%%
+%% CALL
+%%
+
+gen_call(I, VarMap, ConstTab) ->
+ Fun = hipe_icode:call_fun(I),
+ {Dst, VarMap0} = hipe_rtl_varmap:ivs2rvs(hipe_icode:call_dstlist(I), VarMap),
+ Fail = hipe_icode:call_fail_label(I),
+
+ {Args, VarMap1, ConstTab1, InitCode} =
+ args_to_vars(hipe_icode:call_args(I), VarMap0, ConstTab),
+
+ IsGuard = hipe_icode:call_in_guard(I),
+
+ {FailLblName, VarMap3} =
+ case Fail of
+ [] -> %% Not in a catch
+ {[], VarMap1};
+ _ ->
+ {FLbl, VarMap2} =
+ hipe_rtl_varmap:icode_label2rtl_label(Fail, VarMap1),
+ {hipe_rtl:label_name(FLbl), VarMap2}
+ end,
+
+ {ContLblName, ContLbl, VarMap4} =
+ case hipe_icode:call_continuation(I) of
+ [] -> %% This call does not end a BB.
+ CLbl = hipe_rtl:mk_new_label(),
+ {hipe_rtl:label_name(CLbl), CLbl, VarMap3};
+ Cont ->
+ {CLbl, NewVarMap} =
+ hipe_rtl_varmap:icode_label2rtl_label(Cont, VarMap3),
+ {hipe_rtl:label_name(CLbl), [], NewVarMap}
+ end,
+
+ {Code, ConstTab2} =
+ case hipe_icode:call_type(I) of
+ primop ->
+ hipe_rtl_primops:gen_primop(
+ {Fun, Dst, Args, ContLblName, FailLblName},
+ IsGuard, ConstTab1);
+ Type ->
+ Call = gen_call_1(Fun, Dst, Args, IsGuard, ContLblName,
+ FailLblName, Type),
+ {Call, ConstTab1}
+ end,
+ {[InitCode,Code,ContLbl], VarMap4, ConstTab2}.
+
+%% This catches those standard functions that we inline expand
+
+gen_call_1(Fun={_M,_F,_A}, Dst, Args, IsGuard, Cont, Fail, Type) ->
+ case hipe_rtl_primops:gen_call_builtin(Fun, Dst, Args, IsGuard, Cont,
+ Fail) of
+ [] ->
+ hipe_rtl:mk_call(Dst, Fun, Args, Cont, Fail, conv_call_type(Type));
+ Code ->
+ Code
+ end.
+
+conv_call_type(remote) -> remote;
+conv_call_type(local) -> not_remote.
+
+%% --------------------------------------------------------------------
+
+%%
+%% ENTER
+%%
+
+gen_enter(I, VarMap, ConstTab) ->
+ Fun = hipe_icode:enter_fun(I),
+ {Args, VarMap1, ConstTab1, InitCode} =
+ args_to_vars(hipe_icode:enter_args(I), VarMap, ConstTab),
+ {Code1, ConstTab2} =
+ case hipe_icode:enter_type(I) of
+ primop ->
+ IsGuard = false, % enter can not happen in a guard
+ hipe_rtl_primops:gen_enter_primop({Fun, Args}, IsGuard, ConstTab1);
+ Type ->
+ Call = gen_enter_1(Fun, Args, Type),
+ {Call, ConstTab1}
+ end,
+ {[InitCode,Code1], VarMap1, ConstTab2}.
+
+%% This catches those standard functions that we inline expand
+
+gen_enter_1(Fun, Args, Type) ->
+ case hipe_rtl_primops:gen_enter_builtin(Fun, Args) of
+ [] ->
+ hipe_rtl:mk_enter(Fun, Args, conv_call_type(Type));
+ Code ->
+ Code
+ end.
+
+%% --------------------------------------------------------------------
+
+%%
+%% FAIL
+%%
+
+gen_fail(I, VarMap, ConstTab) ->
+ Fail = hipe_icode:fail_label(I),
+ {Label, VarMap0} =
+ if Fail =:= [] ->
+ %% not in a catch
+ {[], VarMap};
+ true ->
+ {Lbl, Map} = hipe_rtl_varmap:icode_label2rtl_label(Fail, VarMap),
+ {hipe_rtl:label_name(Lbl), Map}
+ end,
+ {Args, VarMap1, ConstTab1, InitCode} =
+ args_to_vars(hipe_icode:fail_args(I), VarMap0, ConstTab),
+ Class = hipe_icode:fail_class(I),
+ FailCode = hipe_rtl_exceptions:gen_fail(Class, Args, Label),
+ {[InitCode, FailCode], VarMap1, ConstTab1}.
+
+%% --------------------------------------------------------------------
+
+%%
+%% GOTO
+%%
+
+gen_goto(I, VarMap, ConstTab) ->
+ {Label, Map0} =
+ hipe_rtl_varmap:icode_label2rtl_label(hipe_icode:goto_label(I), VarMap),
+ {hipe_rtl:mk_goto(hipe_rtl:label_name(Label)), Map0, ConstTab}.
+
+%% --------------------------------------------------------------------
+
+%%
+%% IF
+%%
+
+gen_if(I, VarMap, ConstTab) ->
+ {Args, VarMap1, ConstTab1, InitCode} =
+ args_to_vars(hipe_icode:if_args(I), VarMap, ConstTab),
+ {TrueLbl, VarMap2} =
+ hipe_rtl_varmap:icode_label2rtl_label(hipe_icode:if_true_label(I), VarMap1),
+ {FalseLbl, VarMap3} =
+ hipe_rtl_varmap:icode_label2rtl_label(hipe_icode:if_false_label(I),VarMap2),
+ CondCode =
+ gen_cond(hipe_icode:if_op(I),
+ Args,
+ hipe_rtl:label_name(TrueLbl),
+ hipe_rtl:label_name(FalseLbl),
+ hipe_icode:if_pred(I)),
+ {[InitCode,CondCode], VarMap3, ConstTab1}.
+
+
+%% --------------------------------------------------------------------
+
+%%
+%% LABEL
+%%
+
+gen_label(I, VarMap, ConstTab) ->
+ LabelName = hipe_icode:label_name(I),
+ {NewLabel,Map0} = hipe_rtl_varmap:icode_label2rtl_label(LabelName, VarMap),
+ {NewLabel,Map0,ConstTab}.
+
+%% --------------------------------------------------------------------
+
+%%
+%% MOVE
+%%
+
+gen_move(I, VarMap, ConstTab) ->
+ MovedSrc = hipe_icode:move_src(I),
+ {Dst, VarMap0} =
+ hipe_rtl_varmap:icode_var2rtl_var(hipe_icode:move_dst(I), VarMap),
+ case hipe_icode:is_const(MovedSrc) of
+ true ->
+ {Code, NewConstMap} = gen_const_move(Dst, MovedSrc, ConstTab),
+ {[Code], VarMap0, NewConstMap};
+ false ->
+ {Src, VarMap1} = hipe_rtl_varmap:icode_var2rtl_var(MovedSrc, VarMap0),
+ Code =
+ case hipe_icode:is_fvar(MovedSrc) of
+ true ->
+ hipe_rtl:mk_fmove(Dst, Src);
+ false -> % It is a var or reg
+ hipe_rtl:mk_move(Dst, Src)
+ end,
+ {[Code], VarMap1, ConstTab}
+ end.
+
+%% --------------------------------------------------------------------
+
+%%
+%% RETURN
+%%
+
+gen_return(I, VarMap, ConstTab) ->
+ {RetVars, VarMap0, ConstTab0, Code} =
+ args_to_vars(hipe_icode:return_vars(I), VarMap, ConstTab),
+ {Code ++ [hipe_rtl:mk_return(RetVars)], VarMap0, ConstTab0}.
+
+%% --------------------------------------------------------------------
+
+%%
+%% SWITCH
+%%
+
+%%
+%% Rewrite switch_val to the equivalent Icode if-then-else sequence,
+%% then translate that sequence instead.
+%% Doing this at the RTL level would generate the exact same code,
+%% but would also require _a_lot_ more work.
+%% (Don't believe me? Try it. I did, and threw the code away in disgust.
+%% The main ugliness comes from (1) maintaining ConstTab for the constants
+%% that may be added there [switch_val is not limited to immediates!],
+%% (2) maintaining Map for the translated labels, and (3) expanding
+%% equality tests to eq-or-call-primop-exact_eqeq_2.)
+%%
+%% TODO:
+%% - separate immediate and non-immediate cases,
+%% and translate each list separately
+%%
+-ifdef(usesjumptable).
+-define(uumess,?msg("~w Use jtab: ~w\n",
+ [Options,proplists:get_bool(use_jumptable, Options)])).
+-else.
+-define(uumess,ok).
+-endif.
+
+gen_switch_val(I, VarMap, ConstTab, Options) ->
+ %% If you want to see whether jumptables are used or not...
+ ?uumess,
+ hipe_rtl_mk_switch:gen_switch_val(I, VarMap, ConstTab, Options).
+
+gen_switch_tuple(I, Map, ConstTab, Options) ->
+ hipe_rtl_mk_switch:gen_switch_tuple(I, Map, ConstTab, Options).
+
+%% --------------------------------------------------------------------
+
+%%
+%% TYPE
+%%
+
+gen_type(I, VarMap, ConstTab) ->
+ {Vars, Map0, NewConstTab, Code1} =
+ args_to_vars(hipe_icode:type_args(I), VarMap, ConstTab),
+ {TrueLbl, Map1} =
+ hipe_rtl_varmap:icode_label2rtl_label(hipe_icode:type_true_label(I), Map0),
+ {FalseLbl, Map2} =
+ hipe_rtl_varmap:icode_label2rtl_label(hipe_icode:type_false_label(I), Map1),
+ {Code2, NewConstTab1} = gen_type_test(Vars, hipe_icode:type_test(I),
+ hipe_rtl:label_name(TrueLbl),
+ hipe_rtl:label_name(FalseLbl),
+ hipe_icode:type_pred(I),
+ NewConstTab),
+ {Code1 ++ Code2, Map2, NewConstTab1}.
+
+%% --------------------------------------------------------------------
+
+%%
+%% Generate code for a type test. If X is not of type Type then goto Label.
+%%
+
+gen_type_test([X], Type, TrueLbl, FalseLbl, Pred, ConstTab) ->
+ case Type of
+ atom ->
+ {hipe_tagscheme:test_atom(X, TrueLbl, FalseLbl, Pred), ConstTab};
+ bignum ->
+ {hipe_tagscheme:test_bignum(X, TrueLbl, FalseLbl, Pred), ConstTab};
+ binary ->
+ {hipe_tagscheme:test_binary(X, TrueLbl, FalseLbl, Pred), ConstTab};
+ bitstr ->
+ {hipe_tagscheme:test_bitstr(X, TrueLbl, FalseLbl, Pred), ConstTab};
+ boolean ->
+ TmpT = hipe_rtl:mk_new_var(),
+ TmpF = hipe_rtl:mk_new_var(),
+ Lbl = hipe_rtl:mk_new_label(),
+ {[hipe_rtl:mk_load_atom(TmpT, true),
+ hipe_rtl:mk_branch(X, eq, TmpT, TrueLbl,hipe_rtl:label_name(Lbl),Pred),
+ Lbl,
+ hipe_rtl:mk_load_atom(TmpF, false),
+ hipe_rtl:mk_branch(X, eq, TmpF, TrueLbl, FalseLbl, Pred)], ConstTab};
+ cons ->
+ {hipe_tagscheme:test_cons(X, TrueLbl, FalseLbl, Pred), ConstTab};
+ constant ->
+ {hipe_tagscheme:test_constant(X, TrueLbl, FalseLbl, Pred), ConstTab};
+ fixnum ->
+ {hipe_tagscheme:test_fixnum(X, TrueLbl, FalseLbl, Pred), ConstTab};
+ float ->
+ {hipe_tagscheme:test_flonum(X, TrueLbl, FalseLbl, Pred), ConstTab};
+ function ->
+ {hipe_tagscheme:test_fun(X, TrueLbl, FalseLbl, Pred), ConstTab};
+ integer ->
+ {hipe_tagscheme:test_integer(X, TrueLbl, FalseLbl, Pred), ConstTab};
+ list ->
+ {hipe_tagscheme:test_list(X, TrueLbl, FalseLbl, Pred), ConstTab};
+ nil ->
+ {hipe_tagscheme:test_nil(X, TrueLbl, FalseLbl, Pred), ConstTab};
+ number ->
+ {hipe_tagscheme:test_number(X, TrueLbl, FalseLbl, Pred), ConstTab};
+ pid ->
+ {hipe_tagscheme:test_any_pid(X, TrueLbl, FalseLbl, Pred), ConstTab};
+ port ->
+ {hipe_tagscheme:test_any_port(X, TrueLbl, FalseLbl, Pred), ConstTab};
+ reference ->
+ {hipe_tagscheme:test_ref(X, TrueLbl, FalseLbl, Pred), ConstTab};
+ tuple ->
+ {hipe_tagscheme:test_tuple(X, TrueLbl, FalseLbl, Pred), ConstTab};
+ {atom, Atom} ->
+ Tmp = hipe_rtl:mk_new_var(),
+ {[hipe_rtl:mk_load_atom(Tmp, Atom),
+ hipe_rtl:mk_branch(X, eq, Tmp, TrueLbl, FalseLbl, Pred)], ConstTab};
+ {integer, N} when is_integer(N) ->
+ %% XXX: warning, does not work for bignums
+ case hipe_tagscheme:is_fixnum(N) of
+ true ->
+ Int = hipe_tagscheme:mk_fixnum(N),
+ {hipe_rtl:mk_branch(X, eq, hipe_rtl:mk_imm(Int),
+ TrueLbl, FalseLbl, Pred),
+ ConstTab};
+ false ->
+ BignumLbl = hipe_rtl:mk_new_label(),
+ RetLbl = hipe_rtl:mk_new_label(),
+ BigN = hipe_rtl:mk_new_var(),
+ Tmp = hipe_rtl:mk_new_var(),
+ {BigCode,NewConstTab} = gen_big_move(BigN, N, ConstTab),
+ {[hipe_tagscheme:test_fixnum(X, FalseLbl,
+ hipe_rtl:label_name(BignumLbl),1-Pred),
+ BignumLbl, BigCode]
+ ++
+ [hipe_rtl:mk_call([Tmp], op_exact_eqeq_2 , [X,BigN],
+ hipe_rtl:label_name(RetLbl),[],not_remote),
+ RetLbl,
+ hipe_rtl:mk_branch(Tmp, ne, hipe_rtl:mk_imm(0),
+ TrueLbl, FalseLbl, Pred)],
+ NewConstTab}
+ end;
+ {record, A, S} ->
+ TupleLbl = hipe_rtl:mk_new_label(),
+ TupleLblName = hipe_rtl:label_name(TupleLbl),
+ AtomLab = hipe_rtl:mk_new_label(),
+ AtomLabName = hipe_rtl:label_name(AtomLab),
+ TagVar = hipe_rtl:mk_new_var(),
+ TmpAtomVar = hipe_rtl:mk_new_var(),
+ {UntagCode, ConstTab1} =
+ hipe_rtl_primops:gen_primop({{unsafe_element,1},[TagVar],[X],
+ AtomLabName,[]},
+ false, ConstTab),
+ Code =
+ hipe_tagscheme:test_tuple_N(X, S, TupleLblName, FalseLbl, Pred) ++
+ [TupleLbl|UntagCode] ++
+ [AtomLab,
+ hipe_rtl:mk_load_atom(TmpAtomVar, A),
+ hipe_rtl:mk_branch(TagVar, eq, TmpAtomVar, TrueLbl, FalseLbl, Pred)],
+ {Code,
+ ConstTab1};
+ {tuple, N} ->
+ {hipe_tagscheme:test_tuple_N(X, N, TrueLbl, FalseLbl, Pred), ConstTab};
+ Other ->
+ exit({?MODULE,{"unknown type",Other}})
+ end;
+gen_type_test(Z = [X,Y], Type, TrueLbl, FalseLbl, Pred, ConstTab) ->
+ case Type of
+ function2 ->
+ {hipe_tagscheme:test_fun2(X, Y, TrueLbl, FalseLbl, Pred), ConstTab};
+ fixnum ->
+ {hipe_tagscheme:test_fixnums(Z, TrueLbl, FalseLbl, Pred), ConstTab};
+ Other ->
+ exit({?MODULE,{"unknown type",Other}})
+ end;
+gen_type_test(X, Type, TrueLbl, FalseLbl, Pred, ConstTab) ->
+ case Type of
+ fixnum ->
+ {hipe_tagscheme:test_fixnums(X, TrueLbl, FalseLbl, Pred), ConstTab};
+ Other ->
+ exit({?MODULE,{"type cannot have several arguments",Other}})
+ end.
+
+
+%% --------------------------------------------------------------------
+%%
+%% Generate code for the if-conditional.
+%%
+
+gen_cond(CondOp, Args, TrueLbl, FalseLbl, Pred) ->
+ Tmp = hipe_rtl:mk_new_reg_gcsafe(),
+ GenLbl = hipe_rtl:mk_new_label(),
+ TestRetLbl = hipe_rtl:mk_new_label(),
+ TestRetName = hipe_rtl:label_name(TestRetLbl),
+
+ case CondOp of
+ 'fixnum_eq' ->
+ [Arg1, Arg2] = Args,
+ [hipe_rtl:mk_branch(Arg1, eq, Arg2, TrueLbl,
+ FalseLbl, Pred)];
+ '=:=' ->
+ [Arg1, Arg2] = Args,
+ [hipe_rtl:mk_branch(Arg1, eq, Arg2, TrueLbl,
+ hipe_rtl:label_name(GenLbl), Pred),
+ GenLbl,
+ hipe_rtl:mk_call([Tmp], op_exact_eqeq_2, Args,
+ TestRetName, [], not_remote),
+ TestRetLbl,
+ hipe_rtl:mk_branch(Tmp, ne, hipe_rtl:mk_imm(0),
+ TrueLbl, FalseLbl, Pred)];
+ 'fixnum_neq' ->
+ [Arg1, Arg2] = Args,
+ [hipe_rtl:mk_branch(Arg1, eq, Arg2, FalseLbl,
+ TrueLbl, 1-Pred)];
+ '=/=' ->
+ [Arg1, Arg2] = Args,
+ [hipe_rtl:mk_branch(Arg1, eq, Arg2, FalseLbl,
+ hipe_rtl:label_name(GenLbl), 1-Pred),
+ GenLbl,
+ hipe_rtl:mk_call([Tmp], op_exact_eqeq_2, Args,
+ TestRetName, [], not_remote),
+ TestRetLbl,
+ hipe_rtl:mk_branch(Tmp, ne, hipe_rtl:mk_imm(0),
+ FalseLbl, TrueLbl, Pred)];
+ '==' ->
+ [Arg1, Arg2] = Args,
+ [hipe_rtl:mk_branch(Arg1, eq, Arg2,
+ TrueLbl, hipe_rtl:label_name(GenLbl), Pred),
+ GenLbl,
+ hipe_rtl:mk_call([Tmp], cmp_2, Args, TestRetName, [], not_remote),
+ TestRetLbl,
+ hipe_rtl:mk_branch(Tmp, eq, hipe_rtl:mk_imm(0),
+ TrueLbl, FalseLbl, Pred)];
+ '/=' ->
+ [Arg1, Arg2] = Args,
+ [hipe_rtl:mk_branch(Arg1, eq, Arg2,
+ FalseLbl, hipe_rtl:label_name(GenLbl), 1-Pred),
+ GenLbl,
+ hipe_rtl:mk_call([Tmp], cmp_2, Args, TestRetName, [], not_remote),
+ TestRetLbl,
+ hipe_rtl:mk_branch(Tmp, ne, hipe_rtl:mk_imm(0),
+ TrueLbl, FalseLbl, Pred)];
+ 'fixnum_gt' ->
+ [Arg1, Arg2] = Args,
+ [hipe_tagscheme:fixnum_gt(Arg1, Arg2, TrueLbl, FalseLbl, Pred)];
+ 'fixnum_ge' ->
+ [Arg1, Arg2] = Args,
+ [hipe_tagscheme:fixnum_ge(Arg1, Arg2, TrueLbl, FalseLbl, Pred)];
+ 'fixnum_lt' ->
+ [Arg1, Arg2] = Args,
+ [hipe_tagscheme:fixnum_lt(Arg1, Arg2, TrueLbl, FalseLbl, Pred)];
+ 'fixnum_le' ->
+ [Arg1, Arg2] = Args,
+ [hipe_tagscheme:fixnum_le(Arg1, Arg2, TrueLbl, FalseLbl, Pred)];
+ '>' ->
+ [Arg1, Arg2] = Args,
+ [hipe_tagscheme:test_two_fixnums(Arg1, Arg2,
+ hipe_rtl:label_name(GenLbl)),
+ hipe_tagscheme:fixnum_gt(Arg1, Arg2, TrueLbl, FalseLbl, Pred),
+ GenLbl,
+ hipe_rtl:mk_call([Tmp], cmp_2, Args, TestRetName, [], not_remote),
+ TestRetLbl,
+ hipe_rtl:mk_branch(Tmp, gt, hipe_rtl:mk_imm(0),
+ TrueLbl, FalseLbl, Pred)];
+ '<' ->
+ [Arg1, Arg2] = Args,
+ [hipe_tagscheme:test_two_fixnums(Arg1, Arg2,
+ hipe_rtl:label_name(GenLbl)),
+ hipe_tagscheme:fixnum_lt(Arg1, Arg2, TrueLbl, FalseLbl, Pred),
+ GenLbl,
+ hipe_rtl:mk_call([Tmp], cmp_2, Args, TestRetName, [], not_remote),
+ TestRetLbl,
+ hipe_rtl:mk_branch(Tmp, lt, hipe_rtl:mk_imm(0),
+ TrueLbl, FalseLbl, Pred)];
+ '>=' ->
+ [Arg1, Arg2] = Args,
+ [hipe_tagscheme:test_two_fixnums(Arg1, Arg2,
+ hipe_rtl:label_name(GenLbl)),
+ hipe_tagscheme:fixnum_ge(Arg1, Arg2, TrueLbl, FalseLbl, Pred),
+ GenLbl,
+ hipe_rtl:mk_call([Tmp], cmp_2, Args, TestRetName, [], not_remote),
+ TestRetLbl,
+ hipe_rtl:mk_branch(Tmp, ge, hipe_rtl:mk_imm(0),
+ TrueLbl, FalseLbl, Pred)];
+ '=<' ->
+ [Arg1, Arg2] = Args,
+ [hipe_tagscheme:test_two_fixnums(Arg1, Arg2,
+ hipe_rtl:label_name(GenLbl)),
+ hipe_tagscheme:fixnum_le(Arg1, Arg2, TrueLbl, FalseLbl, Pred),
+ GenLbl,
+ hipe_rtl:mk_call([Tmp], cmp_2, Args, TestRetName, [], not_remote),
+ TestRetLbl,
+ hipe_rtl:mk_branch(Tmp, le, hipe_rtl:mk_imm(0),
+ TrueLbl, FalseLbl, Pred)];
+ _Other ->
+ [hipe_rtl:mk_call([Tmp], CondOp, Args, TestRetName, [], not_remote),
+ TestRetLbl,
+ hipe_rtl:mk_branch(Tmp, ne, hipe_rtl:mk_imm(0),
+ TrueLbl, FalseLbl, Pred)]
+ end.
+
+%% --------------------------------------------------------------------
+%%
+%% Translate a list argument list of icode vars to rtl vars. Also
+%% handles constants in arguments.
+%%
+
+args_to_vars([Arg|Args],VarMap, ConstTab) ->
+ {Vars, VarMap1, ConstTab1, Code} =
+ args_to_vars(Args, VarMap, ConstTab),
+ case hipe_icode:is_variable(Arg) of
+ true ->
+ {Var, VarMap2} = hipe_rtl_varmap:icode_var2rtl_var(Arg, VarMap1),
+ {[Var|Vars], VarMap2, ConstTab1, Code};
+ false ->
+ case type_of_const(Arg) of
+ big ->
+ ConstVal = hipe_icode:const_value(Arg),
+ {ConstTab2, Label} = hipe_consttab:insert_term(ConstTab1, ConstVal),
+ NewArg = hipe_rtl:mk_const_label(Label),
+ {[NewArg|Vars], VarMap1, ConstTab2, Code};
+ fixnum ->
+ ConstVal = hipe_icode:const_value(Arg),
+ NewArg = hipe_rtl:mk_imm(tagged_val_of(ConstVal)),
+ {[NewArg|Vars], VarMap1, ConstTab1, Code};
+ nil ->
+ NewArg = hipe_rtl:mk_imm(tagged_val_of([])),
+ {[NewArg|Vars], VarMap1, ConstTab1, Code};
+ _ ->
+ Var = hipe_rtl:mk_new_var(),
+ {Code2, ConstTab2} = gen_const_move(Var, Arg, ConstTab1),
+ {[Var|Vars], VarMap1, ConstTab2, [Code2,Code]}
+ end
+ end;
+args_to_vars([], VarMap, ConstTab) ->
+ {[], VarMap, ConstTab, []}.
+
+%% --------------------------------------------------------------------
+
+%%
+%% Translate a move where the source is a constant
+%%
+
+gen_const_move(Dst, Const, ConstTab) ->
+ ConstVal = hipe_icode:const_value(Const),
+ case type_of_const(Const) of
+ %% const_fun ->
+ %% gen_fun_move(Dst, ConstVal, ConstTab);
+ nil ->
+ Src = hipe_rtl:mk_imm(tagged_val_of([])),
+ {hipe_rtl:mk_move(Dst, Src), ConstTab};
+ fixnum ->
+ Src = hipe_rtl:mk_imm(tagged_val_of(ConstVal)),
+ {hipe_rtl:mk_move(Dst, Src), ConstTab};
+ atom ->
+ {hipe_rtl:mk_load_atom(Dst, ConstVal), ConstTab};
+ big ->
+ gen_big_move(Dst, ConstVal, ConstTab)
+ end.
+
+%% gen_fun_move(Dst, Fun, ConstTab) ->
+%% ?WARNING_MSG("Funmove ~w! -- NYI\n", [Fun]),
+%% {NewTab, Label} = hipe_consttab:insert_fun(ConstTab, Fun),
+%% {hipe_rtl:mk_load_address(Dst, Label, constant), NewTab}.
+
+gen_big_move(Dst, Big, ConstTab) ->
+ {NewTab, Label} = hipe_consttab:insert_term(ConstTab, Big),
+ {hipe_rtl:mk_move(Dst, hipe_rtl:mk_const_label(Label)),
+ NewTab}.
+
+type_of_const(Const) ->
+ case hipe_icode:const_value(Const) of
+ [] ->
+ nil;
+ X when is_integer(X) ->
+ case hipe_tagscheme:is_fixnum(X) of
+ true -> fixnum;
+ false -> big
+ end;
+ A when is_atom(A) ->
+ atom;
+ _ ->
+ big
+ end.
+
+tagged_val_of([]) -> hipe_tagscheme:mk_nil();
+tagged_val_of(X) when is_integer(X) -> hipe_tagscheme:mk_fixnum(X).