diff options
Diffstat (limited to 'lib/hipe/rtl/hipe_icode2rtl.erl')
-rw-r--r-- | lib/hipe/rtl/hipe_icode2rtl.erl | 727 |
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). |