%% -*- erlang-indent-level: 2 -*- %% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2001-2016. All Rights Reserved. %% %% 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. %% %% %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}; 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}; map -> {hipe_tagscheme:test_map(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).