diff options
-rw-r--r-- | lib/hipe/icode/hipe_icode_fp.erl | 43 | ||||
-rw-r--r-- | lib/hipe/test/basic_SUITE_data/basic_floats.erl | 41 |
2 files changed, 64 insertions, 20 deletions
diff --git a/lib/hipe/icode/hipe_icode_fp.erl b/lib/hipe/icode/hipe_icode_fp.erl index 5ae0395b72..3e4a2f039a 100644 --- a/lib/hipe/icode/hipe_icode_fp.erl +++ b/lib/hipe/icode/hipe_icode_fp.erl @@ -738,8 +738,16 @@ filter_map([{Var, Bindings}|Left], NofPreds, Map) -> true -> case all_args_equal(Bindings) of true -> - {_, FVar} = hd(Bindings), - filter_map(Left, NofPreds, gb_trees:update(Var, FVar, Map)); + NewBinding = + case hd(Bindings) of + {Pred, {assigned, FVar0}} when is_integer(Pred) -> + case bindings_all_assigned(Bindings) of + true -> {assigned, FVar0}; + false -> FVar0 + end; + {Pred, FVar0} when is_integer(Pred) -> FVar0 + end, + filter_map(Left, NofPreds, gb_trees:update(Var, NewBinding, Map)); false -> PhiDst = hipe_icode:mk_new_fvar(), PhiArgs = strip_of_assigned(Bindings), @@ -751,7 +759,7 @@ filter_map([{Var, Bindings}|Left], NofPreds, Map) -> gb_trees:update(phi, [{PhiDst, PhiArgs}|Val], Map) end, NewBinding = - case bindings_are_assigned(Bindings) of + case bindings_all_assigned(Bindings) of true -> {assigned, PhiDst}; false -> PhiDst end, @@ -763,30 +771,25 @@ filter_map([{Var, Bindings}|Left], NofPreds, Map) -> filter_map([], _NofPreds, Map) -> Map. -bindings_are_assigned([{_, {assigned, _}}|Left]) -> - assert_assigned(Left), - true; -bindings_are_assigned(Bindings) -> - assert_not_assigned(Bindings), - false. - -assert_assigned([{_, {assigned, _}}|Left]) -> - assert_assigned(Left); -assert_assigned([]) -> - ok. - -assert_not_assigned([{_, FVar}|Left]) -> - true = hipe_icode:is_fvar(FVar), - assert_not_assigned(Left); -assert_not_assigned([]) -> - ok. +bindings_all_assigned([]) -> true; +bindings_all_assigned([{_, {assigned, _}}|Left]) -> + bindings_all_assigned(Left); +bindings_all_assigned(_) -> false. %% all_args_equal returns true if the mapping for a variable is the %% same from all predecessors, i.e., we do not need a phi-node. +%% During the fixpoint loop, a mapping might become assigned, without that +%% information having propagated into all predecessors. We take care to answer +%% true even if FVar is only assigned in some predecessors. + +all_args_equal([{_, {assigned, FVar}}|Left]) -> + all_args_equal(Left, FVar); all_args_equal([{_, FVar}|Left]) -> all_args_equal(Left, FVar). +all_args_equal([{_, {assigned, FVar1}}|Left], FVar1) -> + all_args_equal(Left, FVar1); all_args_equal([{_, FVar1}|Left], FVar1) -> all_args_equal(Left, FVar1); all_args_equal([], _) -> diff --git a/lib/hipe/test/basic_SUITE_data/basic_floats.erl b/lib/hipe/test/basic_SUITE_data/basic_floats.erl index 32bbb6c7fc..ebd3852002 100644 --- a/lib/hipe/test/basic_SUITE_data/basic_floats.erl +++ b/lib/hipe/test/basic_SUITE_data/basic_floats.erl @@ -19,6 +19,7 @@ test() -> ok = test_fp_with_fp_exceptions(), %% ok = test_fmt_double_fpe_leak(), % this requires printing ok = test_icode_type_crash(), + ok = test_icode_type_crash_2(), ok. %%-------------------------------------------------------------------- @@ -208,3 +209,43 @@ f(A, B, C) -> end, Y * Z end. + +%%%------------------------------------------------------------------- +%%% Contains another case that crashes hipe_icode_fp. This sample was +%%% sent by Mattias Jansson. Compiles alright with the option +%%% 'no_icode_type' but that defeats the purpose of the test. + +test_icode_type_crash_2() -> + {'EXIT', {function_clause, _}} = (catch eat()), + ok. + +eat() -> + eat_what(1.0, #{}). + +eat_what(Factor, #{rat_type := LT} = Rat) -> + #{ cheese := Cheese } = Rat, + UnitCheese = Cheese / 2, + RetA = case eat() of + {full, RetA1} -> + CheeseB2 = min(RetA1, UnitCheese) * Factor, + case eat() of + full -> + {win, RetA1}; + hungry -> + {partial, RetA1 - CheeseB2} + end; + AOther -> + AOther + end, + RetB = case eat() of + {full, RetB1} -> + CheeseA2 = min(RetB1, UnitCheese) * Factor, + rat:init(single, LT, CheeseA2), + case eat() of + full -> + {full, RetB1}; + hungry -> + {hungry, RetB1 - CheeseA2} + end + end, + {RetA, RetB}. |