From 84adefa331c4159d432d22840663c38f155cd4c1 Mon Sep 17 00:00:00 2001 From: Erlang/OTP Date: Fri, 20 Nov 2009 14:54:40 +0000 Subject: The R13B03 release. --- lib/hipe/icode/hipe_icode_ssa_const_prop.erl | 728 +++++++++++++++++++++++++++ 1 file changed, 728 insertions(+) create mode 100644 lib/hipe/icode/hipe_icode_ssa_const_prop.erl (limited to 'lib/hipe/icode/hipe_icode_ssa_const_prop.erl') diff --git a/lib/hipe/icode/hipe_icode_ssa_const_prop.erl b/lib/hipe/icode/hipe_icode_ssa_const_prop.erl new file mode 100644 index 0000000000..f1640b1cee --- /dev/null +++ b/lib/hipe/icode/hipe_icode_ssa_const_prop.erl @@ -0,0 +1,728 @@ +%% -*- erlang-indent-level: 2 -*- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2003-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% +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% ============================================================================ +%% Filename : hipe_icode_ssa_const_prop.erl +%% Authors : Daniel Luna, Erik Andersson +%% Purpose : Perform sparse conditional constant propagation on Icode. +%% Notes : Works on the control-flow graph. +%% +%% History : * 2003-03-05: Created. +%% * 2003-08-11: Passed simple testsuite. +%% * 2003-10-01: Passed compiler testsuite. +%% ============================================================================ +%% +%% Exports: propagate/1. +%% +%% ============================================================================ +%% +%% TODO: +%% +%% Take care of failures in call and replace operation with appropriate +%% failure. +%% +%% Handle ifs with non-binary operators +%% +%% We want multisets for easier (and faster) creation of env->ssa_edges +%% +%% Maybe do things with begin_handler, begin_try if possible +%% +%% Propagation of constant arguments when some of the arguments are bottom +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +-module(hipe_icode_ssa_const_prop). +-export([propagate/1]). + +-include("../main/hipe.hrl"). +-include("hipe_icode.hrl"). +-include("../flow/cfg.hrl"). +-include("hipe_icode_primops.hrl"). + +-define(CONST_PROP_MSG(Str,L), ok). +%%-define(CONST_PROP_MSG(Str,L), io:format(Str,L)). + +%%-define(DEBUG, 1). + +%%----------------------------------------------------------------------------- +%% Include stuff shared between SCCP on Icode and RTL. +%% NOTE: Needs to appear after DEBUG is possibly defined. +%%----------------------------------------------------------------------------- + +-define(CODE, hipe_icode). +-define(CFG, hipe_icode_cfg). + +-include("../ssa/hipe_ssa_const_prop.inc"). + +%%----------------------------------------------------------------------------- + +visit_expression(Instruction, Environment) -> + EvaluatedArguments = [lookup_lattice_value(Argument, Environment) + || Argument <- hipe_icode:args(Instruction)], + case Instruction of + #icode_move{} -> + visit_move (Instruction, EvaluatedArguments, Environment); + #icode_if{} -> + visit_if (Instruction, EvaluatedArguments, Environment); + #icode_goto{} -> + visit_goto (Instruction, EvaluatedArguments, Environment); + #icode_type{} -> + visit_type (Instruction, EvaluatedArguments, Environment); + #icode_call{} -> + visit_call (Instruction, EvaluatedArguments, Environment); + #icode_switch_val{} -> + visit_switch_val (Instruction, EvaluatedArguments, Environment); + #icode_switch_tuple_arity{} -> + visit_switch_tuple_arity(Instruction, EvaluatedArguments, Environment); + #icode_begin_handler{} -> + visit_begin_handler (Instruction, EvaluatedArguments, Environment); + #icode_begin_try{} -> + visit_begin_try (Instruction, EvaluatedArguments, Environment); + #icode_fail{} -> + visit_fail (Instruction, EvaluatedArguments, Environment); + _ -> + %% label, end_try, comment, return, + {[], [], Environment} + end. + +%%----------------------------------------------------------------------------- + +visit_begin_try(Instruction, [], Environment) -> + Label = hipe_icode:begin_try_label(Instruction), + Successor = hipe_icode:begin_try_successor(Instruction), + {[Label, Successor], [], Environment}. + +%%----------------------------------------------------------------------------- + +visit_begin_handler(Instruction, _Arguments, Environment) -> + Destinations = hipe_icode:begin_handler_dstlist(Instruction), + {Environment1, SSAWork} = + lists:foldl(fun (Dst, {Env0,Work0}) -> + {Env, Work} = update_lattice_value({Dst, bottom}, Env0), + {Env, Work ++ Work0} + end, + {Environment, []}, + Destinations), + {[], SSAWork, Environment1}. + +%%----------------------------------------------------------------------------- + +visit_switch_val(Instruction, [Argument], Environment) -> + Cases = hipe_icode:switch_val_cases(Instruction), + FailLabel = hipe_icode:switch_val_fail_label(Instruction), + case Argument of + bottom -> + FlowWork = [Label || {_Value, Label} <- Cases], + FlowWork1 = [FailLabel | FlowWork], + {FlowWork1, [], Environment}; + _ -> + Target = get_switch_target(Cases, Argument, FailLabel), + {[Target], [], Environment} + end. + +%%----------------------------------------------------------------------------- + +visit_switch_tuple_arity(Instruction, [Argument], Environment) -> + Cases = hipe_icode:switch_tuple_arity_cases(Instruction), + FailLabel = hipe_icode:switch_tuple_arity_fail_label(Instruction), + case Argument of + bottom -> + FlowWork = [Label || {_Value, Label} <- Cases], + FlowWork1 = [FailLabel | FlowWork], + {FlowWork1, [], Environment}; + Constant -> + UnTagged = hipe_icode:const_value(Constant), + case is_tuple(UnTagged) of + true -> + Target = get_switch_target(Cases, tuple_size(UnTagged), FailLabel), + {[Target], [], Environment}; + false -> + {[FailLabel], [], Environment} + end + end. + +%%----------------------------------------------------------------------------- + +get_switch_target([], _Argument, FailLabel) -> + FailLabel; +get_switch_target([{CaseValue, Target} | CaseList], Argument, FailLabel) -> + case CaseValue =:= Argument of + true -> + Target; + false -> + get_switch_target(CaseList, Argument, FailLabel) + end. + +%%----------------------------------------------------------------------------- + +visit_move(Instruction, [SourceValue], Environment) -> + Destination = hipe_icode:move_dst(Instruction), + {Environment1, SSAWork} = update_lattice_value({Destination, SourceValue}, + Environment), + {[], SSAWork, Environment1}. + +%%----------------------------------------------------------------------------- + +visit_if(Instruction, Arguments, Environment) -> + FlowWork = + case evaluate_if(hipe_icode:if_op(Instruction), Arguments) of + true -> + TrueLabel = hipe_icode:if_true_label(Instruction), + [TrueLabel]; + false -> + FalseLabel = hipe_icode:if_false_label(Instruction), + [FalseLabel]; + bottom -> + TrueLabel = hipe_icode:if_true_label(Instruction), + FalseLabel = hipe_icode:if_false_label(Instruction), + [TrueLabel, FalseLabel] + end, + {FlowWork, [], Environment}. + +%%----------------------------------------------------------------------------- + +visit_goto(Instruction, _Arguments, Environment) -> + GotoLabel = hipe_icode:goto_label(Instruction), + FlowWork = [GotoLabel], + {FlowWork, [], Environment}. + +%%----------------------------------------------------------------------------- + +visit_fail(Instruction, _Arguments, Environment) -> + FlowWork = hipe_icode:successors(Instruction), + {FlowWork, [], Environment}. + +%%----------------------------------------------------------------------------- + +visit_type(Instruction, Values, Environment) -> + FlowWork = + case evaluate_type(hipe_icode:type_test(Instruction), Values) of + true -> + TrueLabel = hipe_icode:type_true_label(Instruction), + [TrueLabel]; + false -> + FalseLabel = hipe_icode:type_false_label(Instruction), + [FalseLabel]; + bottom -> + TrueLabel = hipe_icode:type_true_label(Instruction), + FalseLabel = hipe_icode:type_false_label(Instruction), + [TrueLabel, FalseLabel] + end, + {FlowWork, [], Environment}. + +%%----------------------------------------------------------------------------- + +visit_call(Ins, Args, Environment) -> + Dsts = hipe_icode:call_dstlist(Ins), + Fun = hipe_icode:call_fun(Ins), + Fail = call_fail_labels(Ins), + Cont = call_continuation_labels(Ins), + visit_call(Dsts, Args, Fun, Cont, Fail, Environment). + +visit_call(Dst, Args, Fun, Cont, Fail, Environment) -> + {FlowWork, {Environment1, SSAWork}} = + case lists:any(fun(X) -> (X =:= bottom) end, Args) of + true -> + {Fail ++ Cont, update_lattice_value({Dst, bottom}, Environment)}; + false -> + ConstArgs = [hipe_icode:const_value(Argument) || Argument <- Args], + try evaluate_call_or_enter(ConstArgs, Fun) of + bottom -> + {Fail ++ Cont, update_lattice_value({Dst, bottom}, Environment)}; + Constant -> + {Cont, update_lattice_value({Dst, Constant}, Environment)} + catch + _:_ -> + {Fail, update_lattice_value({Dst, bottom}, Environment)} + end + end, + {FlowWork, SSAWork, Environment1}. + +%%----------------------------------------------------------------------------- + +call_fail_labels(I) -> + case hipe_icode:call_fail_label(I) of + [] -> []; + Label -> [Label] + end. + +call_continuation_labels(I) -> + case hipe_icode:call_continuation(I) of + [] -> []; + Label -> [Label] + end. + +%%----------------------------------------------------------------------------- + +%% Unary calls +evaluate_call_or_enter([Argument], Fun) -> + case Fun of + mktuple -> + hipe_icode:mk_const(list_to_tuple([Argument])); + unsafe_untag_float -> + hipe_icode:mk_const(float(Argument)); + conv_to_float -> + hipe_icode:mk_const(float(Argument)); + fnegate -> + hipe_icode:mk_const(0.0 - Argument); + 'bnot' -> + hipe_icode:mk_const(Argument); + #unsafe_element{index=N} -> + hipe_icode:mk_const(element(N, Argument)); + {erlang, hd, 1} -> + hipe_icode:mk_const(hd(Argument)); + {erlang, tl, 1} -> + hipe_icode:mk_const(tl(Argument)); + {erlang, atom_to_list, 1} -> + hipe_icode:mk_const(atom_to_list(Argument)); + {erlang, list_to_atom, 1} -> + hipe_icode:mk_const(list_to_atom(Argument)); + {erlang, tuple_to_list, 1} -> + hipe_icode:mk_const(tuple_to_list(Argument)); + {erlang, list_to_tuple, 1} -> + hipe_icode:mk_const(list_to_tuple(Argument)); + {erlang, length, 1} -> + hipe_icode:mk_const(length(Argument)); + {erlang, size, 1} -> + hipe_icode:mk_const(size(Argument)); + {erlang, bit_size, 1} -> + hipe_icode:mk_const(bit_size(Argument)); + {erlang, byte_size, 1} -> + hipe_icode:mk_const(byte_size(Argument)); + {erlang, tuple_size, 1} -> + hipe_icode:mk_const(tuple_size(Argument)); + {erlang, abs, 1} -> + hipe_icode:mk_const(abs(Argument)); + {erlang, round, 1} -> + hipe_icode:mk_const(round(Argument)); + {erlang, trunc, 1} -> + hipe_icode:mk_const(trunc(Argument)); + _ -> + bottom + end; +%% Binary calls +evaluate_call_or_enter([Argument1,Argument2], Fun) -> + case Fun of + '+' -> + hipe_icode:mk_const(Argument1 + Argument2); + '-' -> + hipe_icode:mk_const(Argument1 - Argument2); + '*' -> + hipe_icode:mk_const(Argument1 * Argument2); + '/' -> + hipe_icode:mk_const(Argument1 / Argument2); + 'band' -> + hipe_icode:mk_const(Argument1 band Argument2); + 'bor' -> + hipe_icode:mk_const(Argument1 bor Argument2); + 'bsl' -> + hipe_icode:mk_const(Argument1 bsl Argument2); + 'bsr' -> + hipe_icode:mk_const(Argument1 bsr Argument2); + 'bxor' -> + hipe_icode:mk_const(Argument1 bxor Argument2); + fp_add -> + hipe_icode:mk_const(float(Argument1 + Argument2)); + fp_sub -> + hipe_icode:mk_const(float(Argument1 - Argument2)); + fp_mul -> + hipe_icode:mk_const(float(Argument1 * Argument2)); + fp_div -> + hipe_icode:mk_const(Argument1 / Argument2); + cons -> + hipe_icode:mk_const([Argument1 | Argument2]); + mktuple -> + hipe_icode:mk_const(list_to_tuple([Argument1,Argument2])); + #unsafe_update_element{index=N} -> + hipe_icode:mk_const(setelement(N, Argument1, Argument2)); + {erlang, '++', 2} -> + hipe_icode:mk_const(Argument1 ++ Argument2); + {erlang, '--', 2} -> + hipe_icode:mk_const(Argument1 -- Argument2); + {erlang, 'div', 2} -> + hipe_icode:mk_const(Argument1 div Argument2); + {erlang, 'rem', 2} -> + hipe_icode:mk_const(Argument1 rem Argument2); + {erlang, append_element, 2} -> + hipe_icode:mk_const(erlang:append_element(Argument1, Argument2)); + {erlang, element, 2} -> + hipe_icode:mk_const(element(Argument1, Argument2)); + _Other -> + %% io:format("In ~w(~w,~w)~n", [_Other,Argument1,Argument2]), + bottom + end; + +%% The rest of the calls +evaluate_call_or_enter(Arguments, Fun) -> + case Fun of + mktuple -> + hipe_icode:mk_const(list_to_tuple(Arguments)); + {erlang, setelement, 3} -> + [Argument1, Argument2, Argument3] = Arguments, + hipe_icode:mk_const(setelement(Argument1, Argument2, Argument3)); + _ -> + bottom + end. + +%%----------------------------------------------------------------------------- + +evaluate_if(Conditional, [Argument1, Argument2]) -> + case ((Argument1 =:= bottom) or (Argument2 =:= bottom)) of + true -> bottom; + false -> evaluate_if_const(Conditional, Argument1, Argument2) + end; +evaluate_if(_Conditional, _Arguments) -> + bottom. + +%%----------------------------------------------------------------------------- + +evaluate_if_const(Conditional, Argument1, Argument2) -> + case Conditional of + '=:=' -> Argument1 =:= Argument2; + '==' -> Argument1 == Argument2; + '=/=' -> Argument1 =/= Argument2; + '/=' -> Argument1 /= Argument2; + '<' -> Argument1 < Argument2; + '>=' -> Argument1 >= Argument2; + '=<' -> Argument1 =< Argument2; + '>' -> Argument1 > Argument2; + _ -> bottom + end. + +%%----------------------------------------------------------------------------- + +evaluate_type(Type, Vals) -> + case [X || X <- Vals, X =:= bottom] of + [] -> evaluate_type_const(Type, Vals); + _ -> bottom + end. + +%%----------------------------------------------------------------------------- + +evaluate_type_const(Type, [Arg|Left]) -> + Test = + case {Type, hipe_icode:const_value(Arg)} of + {nil, [] } -> true; + {nil, _ } -> false; + {cons, [_|_]} -> true; + {cons, _ } -> false; + {{tuple, N}, T} when tuple_size(T) =:= N -> true; + {atom, A} when is_atom(A) -> true; + {{atom, A}, A} when is_atom(A) -> true; + {{record, A, S}, R} when tuple_size(R) =:= S, + element(1, R) =:= A -> true; + {{record, _, _}, _} -> false; + _ -> bottom + end, + case Test of + bottom -> bottom; + false -> false; + true -> evaluate_type_const(Type, Left) + end; +evaluate_type_const(_Type, []) -> + true. + +%%----------------------------------------------------------------------------- +%% Icode-specific code below +%%----------------------------------------------------------------------------- + +update_instruction(Instruction, Environment) -> + case Instruction of + #icode_call{} -> + update_call(Instruction, Environment); + #icode_enter{} -> + update_enter(Instruction, Environment); + #icode_if{} -> + update_if(Instruction, Environment); + #icode_move{} -> + update_move(Instruction, Environment); + #icode_phi{} -> + update_phi(Instruction, Environment); + #icode_switch_val{} -> + update_switch_val(Instruction, Environment); + #icode_type{} -> + update_type(Instruction, Environment); + #icode_switch_tuple_arity{} -> + update_switch_tuple_arity(Instruction, Environment); + _ -> + %% goto, comment, label, return, begin_handler, end_try, + %% begin_try, fail + %% We could but don't handle: catch?, fail? + [Instruction] + end. + +%%----------------------------------------------------------------------------- + +update_call(Instruction, Environment) -> + DestList = hipe_icode:call_dstlist(Instruction), + case DestList of + [Destination] -> + case lookup_lattice_value(Destination, Environment) of + bottom -> + NewArguments = update_arguments( + hipe_icode:call_args(Instruction), + Environment), + [hipe_icode:call_args_update(Instruction, NewArguments)]; + X -> + NewInstructions = + case is_call_to_fp_op(Instruction) of + true -> + TmpIns = + hipe_icode:call_fun_update(Instruction, unsafe_untag_float), + [hipe_icode:call_args_update(TmpIns, [X])]; + false -> + case hipe_icode:call_continuation(Instruction) of + [] -> + [hipe_icode:mk_move(Destination, X)]; + ContinuationLabel -> + [hipe_icode:mk_move(Destination, X), + hipe_icode:mk_goto(ContinuationLabel)] + end + end, + ?CONST_PROP_MSG("call: ~w ---> ~w\n", + [Instruction, NewInstructions]), + NewInstructions + end; +%% %% [] -> %% No destination; we don't touch this +%% [] -> +%% NewArguments = update_arguments(hipe_icode:call_args(Instruction), +%% Environment), +%% [hipe_icode:call_args_update(Instruction, NewArguments)]; + %% List-> %% Means register allocation; not implemented at this point + _ -> + [Instruction] + end. + +%%----------------------------------------------------------------------------- + +is_call_to_fp_op(Instruction) -> + case hipe_icode:call_fun(Instruction) of + fp_add -> true; + fp_sub -> true; + fp_mul -> true; + fp_div -> true; + fnegate -> true; + conv_to_float -> true; + unsafe_untag_float -> true; + _ -> false + end. + +%%----------------------------------------------------------------------------- + +update_enter(Instruction, Environment) -> + Args = hipe_icode:enter_args(Instruction), + EvalArgs = [lookup_lattice_value(X, Environment) || X <- Args], + Fun = hipe_icode:enter_fun(Instruction), + case lists:any(fun(X) -> (X =:= bottom) end, EvalArgs) of + true -> + update_enter_arguments(Instruction, Environment); + false -> + ConstVals = [hipe_icode:const_value(X) || X <- EvalArgs], + try evaluate_call_or_enter(ConstVals, Fun) of + bottom -> + update_enter_arguments(Instruction, Environment); + Const -> + Dst = hipe_icode:mk_new_var(), + [hipe_icode:mk_move(Dst, Const), + hipe_icode:mk_return([Dst])] + catch + _:_ -> + update_enter_arguments(Instruction, Environment) + end + end. + +update_enter_arguments(Instruction, Env) -> + NewArguments = update_arguments(hipe_icode:enter_args(Instruction), Env), + [hipe_icode:enter_args_update(Instruction, NewArguments)]. + +%%----------------------------------------------------------------------------- + +update_if(Instruction, Environment) -> + Args = hipe_icode:if_args(Instruction), + EvaluatedArguments = [lookup_lattice_value(Argument, Environment) + || Argument <- Args], + Op = hipe_icode:if_op(Instruction), + case evaluate_if(Op, EvaluatedArguments) of + true -> + TrueLabel = hipe_icode:if_true_label(Instruction), + ?CONST_PROP_MSG("ifT: ~w ---> goto ~w\n", [Instruction, TrueLabel]), + [hipe_icode:mk_goto(TrueLabel)]; + false -> + FalseLabel = hipe_icode:if_false_label(Instruction), + ?CONST_PROP_MSG("ifF: ~w ---> goto ~w\n", [Instruction, FalseLabel]), + [hipe_icode:mk_goto(FalseLabel)]; + bottom -> + %% Convert the if-test to a type test if possible. + Op = hipe_icode:if_op(Instruction), + case Op =:= '=:=' orelse Op =:= '=/=' of + false -> [Instruction]; + true -> + [Arg1, Arg2] = Args, + case EvaluatedArguments of + [bottom, bottom] -> + [Instruction]; + [bottom, X] -> + conv_if_to_type(Instruction, hipe_icode:const_value(X), Arg1); + [X, bottom] -> + conv_if_to_type(Instruction, hipe_icode:const_value(X), Arg2) + end + end + end. + +conv_if_to_type(I, Const, Arg) when is_atom(Const); + is_integer(Const); + Const =:= [] -> + Test = + if is_atom(Const) -> {atom, Const}; + is_integer(Const) -> {integer, Const}; + true -> nil + end, + {T, F} = + case hipe_icode:if_op(I) of + '=:=' -> {hipe_icode:if_true_label(I),hipe_icode:if_false_label(I)}; + '=/=' -> {hipe_icode:if_false_label(I),hipe_icode:if_true_label(I)} + end, + NewI = hipe_icode:mk_type([Arg], Test, T, F), + ?CONST_PROP_MSG("if: ~w ---> type ~w\n", [I, NewI]), + [NewI]; +conv_if_to_type(I, _, _) -> + [I]. + +%%----------------------------------------------------------------------------- + +update_move(Instruction, Environment) -> + Destination = hipe_icode:move_dst(Instruction), + case lookup_lattice_value(Destination, Environment) of + bottom -> + [Instruction]; + X -> + case hipe_icode:move_src(Instruction) of + X -> + [Instruction]; + _ -> + ?CONST_PROP_MSG("move: ~w ---> ~w\n", [Instruction, X]), + [hipe_icode:move_src_update(Instruction, X)] + end + %% == [hipe_icode:mk_move(Destination, X)] + end. + +%%----------------------------------------------------------------------------- + +update_phi(Instruction, Environment) -> + Destination = hipe_icode:phi_dst(Instruction), + case lookup_lattice_value(Destination, Environment) of + bottom -> + [Instruction]; + X -> + ?CONST_PROP_MSG("phi: ~w ---> ~w\n", [Instruction, X]), + [hipe_icode:mk_move(Destination, X)] + end. + +%%----------------------------------------------------------------------------- + +update_type(Instruction, Environment) -> + EvaluatedArguments = [lookup_lattice_value(Argument, Environment) || + Argument <- hipe_icode:type_args(Instruction)], + case evaluate_type(hipe_icode:type_test(Instruction), EvaluatedArguments) of + true -> + TrueLabel = hipe_icode:type_true_label(Instruction), + ?CONST_PROP_MSG("typeT: ~w ---> goto ~w\n", [Instruction, TrueLabel]), + [hipe_icode:mk_goto(TrueLabel)]; + false -> + FalseLabel = hipe_icode:type_false_label(Instruction), + ?CONST_PROP_MSG("typeF: ~w ---> goto ~w\n", [Instruction, FalseLabel]), + [hipe_icode:mk_goto(FalseLabel)]; + bottom -> + [Instruction] + end. + +%%----------------------------------------------------------------------------- + +update_switch_val(Instruction, Environment) -> + Argument = hipe_icode:switch_val_term(Instruction), + Value = lookup_lattice_value(Argument, Environment), + case Value of + bottom -> + [Instruction]; + _ -> + Cases = hipe_icode:switch_val_cases(Instruction), + FailLabel = hipe_icode:switch_val_fail_label(Instruction), + Target = get_switch_target(Cases, Value, FailLabel), + ?CONST_PROP_MSG("sv: ~w ---> goto ~w\n", [Instruction, Target]), + [hipe_icode:mk_goto(Target)] + end. + +%%----------------------------------------------------------------------------- + +update_switch_tuple_arity(Instruction, Environment) -> + Argument = hipe_icode:switch_tuple_arity_term(Instruction), + Value = lookup_lattice_value(Argument, Environment), + case Value of + bottom -> + [Instruction]; + Constant -> + UnTagged = hipe_icode:const_value(Constant), + case is_tuple(UnTagged) of + true -> + Cases = hipe_icode:switch_tuple_arity_cases(Instruction), + FailLabel = hipe_icode:switch_tuple_arity_fail_label(Instruction), + Target = get_switch_target(Cases, tuple_size(UnTagged), FailLabel), + ?CONST_PROP_MSG("sta: ~w ---> goto ~w\n", [Instruction, Target]), + [hipe_icode:mk_goto(Target)]; + false -> + [Instruction] + %% TODO: Can the above be replaced with below??? Perhaps + %% together with some sort of "generate failure". + %% [hipe_icode:mk_goto(FailLabel)] + end + end. + +%%----------------------------------------------------------------------------- + +lookup_lattice_value(X, Environment) -> + LatticeValues = env__lattice_values(Environment), + case hipe_icode:is_const(X) of + true -> + X; + false -> + case gb_trees:lookup(X, LatticeValues) of + none -> + ?WARNING_MSG("Earlier compiler steps generated erroneous " + "code for X = ~w. We are ignoring this.\n",[X]), + bottom; + {value, top} -> + ?EXIT({"lookup_lattice_value, top", X}); + {value, Y} -> + Y + end + end. + +%%----------------------------------------------------------------------------- + +update_arguments(ArgumentList, Environment) -> + [case lookup_lattice_value(X, Environment) of + bottom -> + X; + Constant -> + Constant + end || X <- ArgumentList]. + +%%----------------------------- End of file ----------------------------------- -- cgit v1.2.3