From c3af7910226cabddcdfa1561b56127e71e3a2ee9 Mon Sep 17 00:00:00 2001 From: Kostis Sagonas Date: Mon, 29 Feb 2016 20:23:05 +0100 Subject: A test that crashes the HiPE compiler when inlining FP ops --- lib/hipe/test/basic_SUITE_data/basic_floats.erl | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/lib/hipe/test/basic_SUITE_data/basic_floats.erl b/lib/hipe/test/basic_SUITE_data/basic_floats.erl index eec175075a..32bbb6c7fc 100644 --- a/lib/hipe/test/basic_SUITE_data/basic_floats.erl +++ b/lib/hipe/test/basic_SUITE_data/basic_floats.erl @@ -18,6 +18,7 @@ test() -> ok = test_catch_fp_conv(), ok = test_fp_with_fp_exceptions(), %% ok = test_fmt_double_fpe_leak(), % this requires printing + ok = test_icode_type_crash(), ok. %%-------------------------------------------------------------------- @@ -178,3 +179,32 @@ test_fmt_double_fpe_leak(X, Y) -> math:log10(Y). int_two() -> 2. + +%%-------------------------------------------------------------------- +%% Contains code which confuses the icode_type analysis and results +%% in a compiler crash. Stipped down from code sent by Paul Guyot. +%% Compiles alright with the option 'no_icode_type' but that defeats +%% the purpose of the test. + +test_icode_type_crash() -> + Fun = f(1, 2, 3), + 42.0 = Fun(), + ok. + +f(A, B, C) -> + fun () -> + X = case A of + 0 -> 1 / B; + _ -> A / C + end, + Y = case B of + a -> 1.0; + b -> 2.0; + _ -> 6.0 + end, + Z = case C of + c -> 0.1 * X; + _ -> 7.0 + end, + Y * Z + end. -- cgit v1.2.3 From c7cc7877e048eab4ee16169653d7cec51fe8a8df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20L=C3=A5ng?= Date: Wed, 2 Mar 2016 14:55:25 +0100 Subject: hipe: Fix crashing bugs when inlining FP ops It was assumed in hipe_icode_fp:filter_map/3 that either all predecessors would have an up-to-date ("assigned") tagged copy, or none of them. This is temporarily false during the fixpoint loop in basic_floats:test_icode_type_crash_2/0, which exercises the all_args_equal(Bindings) =:= true branch, that would previously erroneously end up in the 'false' branch, which is what caused the crash in that case. This is likewise only temporarily false during the fixpoint loop in basic_floats:test_icode_type_crash/0, but that case instead exercises the 'false' branch, justifying the inclusion of both tests. --- lib/hipe/icode/hipe_icode_fp.erl | 43 +++++++++++++------------ 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}. -- cgit v1.2.3 From ef0d2d77e7cc1837bbed9a5be745cbfd83c1ca06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20L=C3=A5ng?= Date: Thu, 3 Mar 2016 13:50:51 +0100 Subject: hipe_icode_fp: Add specs and switch trees to maps --- lib/hipe/icode/hipe_icode_fp.erl | 354 ++++++++++++++++++++++++++++----------- 1 file changed, 256 insertions(+), 98 deletions(-) diff --git a/lib/hipe/icode/hipe_icode_fp.erl b/lib/hipe/icode/hipe_icode_fp.erl index 3e4a2f039a..7bfb21e7db 100644 --- a/lib/hipe/icode/hipe_icode_fp.erl +++ b/lib/hipe/icode/hipe_icode_fp.erl @@ -34,9 +34,28 @@ -include("hipe_icode.hrl"). -include("../flow/cfg.hrl"). --record(state, {edge_map = gb_trees:empty() :: gb_trees:tree(), - fp_ebb_map = gb_trees:empty() :: gb_trees:tree(), - cfg :: #cfg{}}). +-type mapped_fvar() :: icode_fvar() | {assigned, icode_fvar()} . +-type incoming_fvars() :: [{icode_lbl(), mapped_fvar()}]. +-type initial_var_map() :: #{icode_var() => incoming_fvars()}. +-type bb_phi_list() :: [{icode_fvar(), [{icode_lbl(), icode_fvar()}]}]. +-type var_map_phi() :: #{phi => bb_phi_list(), + icode_var() => mapped_fvar()}. +-type var_map() :: #{icode_var() => mapped_fvar()}. + +-type edge() :: {icode_lbl(), icode_lbl()}. +-type edge_map() :: #{edge() => var_map()}. + +-type worklist(Item) :: {[Item], [Item], gb_sets:set(Item)}. +-type worklist() :: worklist(icode_lbl()). + +-type fail_lbl() :: [] | icode_lbl(). +-type in_block() :: {true, fail_lbl()} | false. +-type fp_ebb_map() :: #{{inblock_in | inblock_out, icode_lbl()} | edge() + => in_block()}. + +-record(state, {edge_map = #{} :: edge_map(), + fp_ebb_map = #{} :: fp_ebb_map(), + cfg :: #cfg{}}). %%-------------------------------------------------------------------- @@ -59,10 +78,14 @@ cfg(Cfg) -> %% corresponding fcheckerror. %%-------------------------------------------------------------------- +-spec annotate_fclearerror(#cfg{}) -> #cfg{}. + annotate_fclearerror(Cfg) -> Labels = hipe_icode_cfg:reverse_postorder(Cfg), annotate_fclearerror(Labels, Cfg). +-spec annotate_fclearerror([icode_lbl()], #cfg{}) -> #cfg{}. + annotate_fclearerror([Label|Left], Cfg) -> BB = hipe_icode_cfg:bb(Cfg, Label), Code = hipe_bb:code(BB), @@ -73,6 +96,9 @@ annotate_fclearerror([Label|Left], Cfg) -> annotate_fclearerror([], Cfg) -> Cfg. +-spec annotate_fclearerror1(icode_instrs(), icode_lbl(), #cfg{}, icode_instrs()) + -> icode_instrs(). + annotate_fclearerror1([I|Left], Label, Cfg, Acc) -> case I of #icode_call{} -> @@ -90,6 +116,9 @@ annotate_fclearerror1([I|Left], Label, Cfg, Acc) -> annotate_fclearerror1([], _Label, _Cfg, Acc) -> lists:reverse(Acc). +-spec lookahead_for_fcheckerror(icode_instrs(), icode_lbl(), #cfg{}) -> + fail_lbl(). + lookahead_for_fcheckerror([I|Left], Label, Cfg) -> case I of #icode_call{} -> @@ -111,10 +140,14 @@ lookahead_for_fcheckerror([], Label, Cfg) -> lookahead_for_fcheckerror(Code, Succ, Cfg) end. +-spec unannotate_fclearerror(#cfg{}) -> #cfg{}. + unannotate_fclearerror(Cfg) -> Labels = hipe_icode_cfg:reverse_postorder(Cfg), unannotate_fclearerror(Labels, Cfg). +-spec unannotate_fclearerror([icode_lbl()], #cfg{}) -> #cfg{}. + unannotate_fclearerror([Label|Left], Cfg) -> BB = hipe_icode_cfg:bb(Cfg, Label), Code = hipe_bb:code(BB), @@ -125,6 +158,9 @@ unannotate_fclearerror([Label|Left], Cfg) -> unannotate_fclearerror([], Cfg) -> Cfg. +-spec unannotate_fclearerror1(icode_instrs(), icode_instrs()) -> + icode_instrs(). + unannotate_fclearerror1([I|Left], Acc) -> case I of #icode_call{} -> @@ -145,10 +181,14 @@ unannotate_fclearerror1([], Acc) -> %% Make float EBBs %%-------------------------------------------------------------------- +-spec place_fp_blocks(#state{}) -> #state{}. + place_fp_blocks(State) -> WorkList = new_worklist(State), transform_block(WorkList, State). +-spec transform_block(worklist(), #state{}) -> #state{}. + transform_block(WorkList, State) -> case get_work(WorkList) of none -> @@ -182,6 +222,10 @@ transform_block(WorkList, State) -> end end. +-spec update_maps(#state{}, icode_lbl(), ordsets:ordset(icode_lbl()), + var_map(), ordsets:ordset(icode_lbl()), var_map()) + -> fixpoint | {#state{}, [icode_lbl()]}. + update_maps(State, Label, SuccSet, SuccMap, FailSet, FailMap) -> {NewState, Add1} = update_maps(State, Label, SuccSet, SuccMap, []), case update_maps(NewState, Label, FailSet, FailMap, Add1) of @@ -189,6 +233,10 @@ update_maps(State, Label, SuccSet, SuccMap, FailSet, FailMap) -> {_NewState1, _Add} = Ret -> Ret end. +-spec update_maps(#state{}, icode_lbl(), ordsets:ordset(icode_lbl()), + var_map(), [icode_lbl()]) + -> {#state{}, [icode_lbl()]}. + update_maps(State, From, [To|Left], Map, Acc) -> case state__map_update(State, From, To, Map) of fixpoint -> @@ -199,10 +247,13 @@ update_maps(State, From, [To|Left], Map, Acc) -> update_maps(State, _From, [], _Map, Acc) -> {State, Acc}. +-spec transform_instrs(icode_instrs(), edge_map(), var_map(), icode_instrs()) + -> {var_map(), icode_instrs()}. + transform_instrs([I|Left], PhiMap, Map, Acc) -> Defines = hipe_icode:defines(I), - NewMap = delete_all(Defines, Map), - NewPhiMap = delete_all(Defines, PhiMap), + NewMap = maps:without(Defines, Map), + NewPhiMap = maps:without(Defines, PhiMap), case I of #icode_phi{} -> Uses = hipe_icode:uses(I), @@ -214,7 +265,7 @@ transform_instrs([I|Left], PhiMap, Map, Acc) -> %% All arguments are untagged. Let's untag the destination. Dst = hipe_icode:phi_dst(I), NewDst = hipe_icode:mk_new_fvar(), - NewMap1 = gb_trees:enter(Dst, NewDst, NewMap), + NewMap1 = NewMap#{Dst => NewDst}, NewI = subst_phi_uncond(I, NewDst, PhiMap), transform_instrs(Left, NewPhiMap, NewMap1, [NewI|Acc]); _ -> @@ -233,7 +284,7 @@ transform_instrs([I|Left], PhiMap, Map, Acc) -> [Src] -> case lookup(Src, Map) of none -> - NewMap1 = gb_trees:enter(Src, {assigned, Dst}, NewMap), + NewMap1 = NewMap#{Src => {assigned, Dst}}, transform_instrs(Left, NewPhiMap, NewMap1, [I|Acc]); Dst -> %% This is the instruction that untagged the variable. @@ -256,7 +307,7 @@ transform_instrs([I|Left], PhiMap, Map, Acc) -> unsafe_tag_float -> [Dst] = hipe_icode:defines(I), [Src] = hipe_icode:uses(I), - NewMap1 = gb_trees:enter(Dst, {assigned, Src}, NewMap), + NewMap1 = NewMap#{Dst => {assigned, Src}}, transform_instrs(Left, NewPhiMap, NewMap1,[I|Acc]); _ -> {NewMap1, NewAcc} = check_for_fop_candidates(I, NewMap, Acc), @@ -269,6 +320,9 @@ transform_instrs([I|Left], PhiMap, Map, Acc) -> transform_instrs([], _PhiMap, Map, Acc) -> {Map, lists:reverse(Acc)}. +-spec check_for_fop_candidates(icode_instr(), var_map(), icode_instrs()) + -> {var_map(), icode_instrs()}. + check_for_fop_candidates(I, Map, Acc) -> case is_fop_cand(I) of false -> @@ -311,6 +365,8 @@ check_for_fop_candidates(I, Map, Acc) -> end. +-spec handle_untagged_arguments(icode_instr(), var_map()) -> icode_instrs(). + %% If this is an instruction that needs to operate on tagged values, %% which currently are untagged, we must tag the values and perhaps %% end the fp ebb. @@ -322,23 +378,24 @@ handle_untagged_arguments(I, Map) -> Tag -> TagIntrs = [hipe_icode:mk_primop([Dst], unsafe_tag_float, - [gb_trees:get(Dst, Map)]) || Dst <- Tag], + [maps:get(Dst, Map)]) || Dst <- Tag], [I|TagIntrs] end. +-spec do_prelude(var_map_phi()) -> {[#icode_phi{}], var_map()}. + %% Add phi nodes for untagged fp values. -do_prelude(Map) -> - case gb_trees:lookup(phi, Map) of - none -> - {[], Map}; - {value, List} -> - %%io:format("Adding phi: ~w\n", [List]), - Fun = fun ({FVar, Bindings}, Acc) -> - [hipe_icode:mk_phi(FVar, Bindings)|Acc] - end, - {lists:foldl(Fun, [], List), gb_trees:delete(phi, Map)} - end. +do_prelude(Map = #{phi := List}) -> + %%io:format("Adding phi: ~w\n", [List]), + Fun = fun ({FVar, Bindings}, Acc) -> + [hipe_icode:mk_phi(FVar, Bindings)|Acc] + end, + {lists:foldl(Fun, [], List), maps:remove(phi, Map)}; +do_prelude(Map) -> {[], Map}. + +-spec split_code([I]) -> {[I], I} when + I :: icode_instr(). split_code(Code) -> split_code(Code, []). @@ -349,6 +406,8 @@ split_code([I|Left], Acc) -> split_code(Left, [I|Acc]). +-spec finalize(#state{}) -> #state{}. + %% When all code is mapped to fp instructions we must make sure that %% the fp ebb information going into each block is the same as the %% information coming out of each predecessor. Otherwise, we must add @@ -360,17 +419,25 @@ finalize(State) -> Edges = needs_fcheckerror(NewState), finalize(Edges, NewState). +-spec finalize([edge()], #state{}) -> #state{}. + finalize([{From, To}|Left], State) -> NewState = add_fp_ebb_fixup(From, To, State), finalize(Left, NewState); finalize([], State) -> State. +-spec needs_fcheckerror(#state{}) -> [{none | icode_lbl(), icode_lbl()}]. + needs_fcheckerror(State) -> Cfg = state__cfg(State), Labels = hipe_icode_cfg:labels(Cfg), needs_fcheckerror(Labels, State, []). +-spec needs_fcheckerror([icode_lbl()], #state{}, + [{none | icode_lbl(), icode_lbl()}]) + -> [{none | icode_lbl(), icode_lbl()}]. + needs_fcheckerror([Label|Left], State, Acc) -> case state__get_in_block_in(State, Label) of {true, _} -> @@ -395,6 +462,8 @@ needs_fcheckerror([Label|Left], State, Acc) -> needs_fcheckerror([], _State, Acc) -> Acc. +-spec add_fp_ebb_fixup(none | icode_lbl(), icode_lbl(), #state{}) -> #state{}. + add_fp_ebb_fixup('none', To, State) -> %% Add the fcheckerror to the start of the block. BB = state__bb(State, To), @@ -416,9 +485,15 @@ add_fp_ebb_fixup(From, To, State) -> NewToBB = hipe_bb:code_update(ToBB, NewToCode), state__bb_add(NewState1, To, NewToBB). +-spec redirect_phis(icode_instrs(), icode_lbl(), icode_lbl()) + -> icode_instrs(). + redirect_phis(Code, OldFrom, NewFrom) -> redirect_phis(Code, OldFrom, NewFrom, []). +-spec redirect_phis(icode_instrs(), icode_lbl(), icode_lbl(), icode_instrs()) + -> icode_instrs(). + redirect_phis([I|Is] = Code, OldFrom, NewFrom, Acc) -> case I of #icode_phi{} -> @@ -430,13 +505,20 @@ redirect_phis([I|Is] = Code, OldFrom, NewFrom, Acc) -> redirect_phis([], _OldFrom, _NewFrom, Acc) -> lists:reverse(Acc). +-spec subst_phi(#icode_phi{}, #icode_variable{}, edge_map()) + -> #icode_phi{}. + subst_phi(I, Dst, Map) -> ArgList = subst_phi_uses0(hipe_icode:phi_arglist(I), Map, []), hipe_icode:mk_phi(Dst, ArgList). +-spec subst_phi_uses0([{icode_lbl(), #icode_variable{}}], edge_map(), + [{icode_lbl(), #icode_variable{}}]) + -> [{icode_lbl(), #icode_variable{}}]. + subst_phi_uses0([{Pred, Var}|Left], Map, Acc) -> - case gb_trees:lookup(Var, Map) of - {value, List} -> + case Map of + #{Var := List} -> case lists:keyfind(Pred, 1, List) of {Pred, {assigned, _NewVar}} -> %% The variable is untagged, but it has been assigned. Keep it! @@ -448,20 +530,27 @@ subst_phi_uses0([{Pred, Var}|Left], Map, Acc) -> %% The variable is not untagged. subst_phi_uses0(Left, Map, [{Pred, Var} | Acc]) end; - none -> + #{} -> %% The variable is not untagged. subst_phi_uses0(Left, Map, [{Pred, Var} | Acc]) end; subst_phi_uses0([], _Map, Acc) -> Acc. +-spec subst_phi_uncond(#icode_phi{}, #icode_variable{}, edge_map()) + -> #icode_phi{}. + subst_phi_uncond(I, Dst, Map) -> ArgList = subst_phi_uses_uncond0(hipe_icode:phi_arglist(I), Map, []), hipe_icode:mk_phi(Dst, ArgList). +-spec subst_phi_uses_uncond0([{icode_lbl(), #icode_variable{}}], edge_map(), + [{icode_lbl(), #icode_variable{}}]) + -> [{icode_lbl(), #icode_variable{}}]. + subst_phi_uses_uncond0([{Pred, Var}|Left], Map, Acc) -> - case gb_trees:lookup(Var, Map) of - {value, List} -> + case Map of + #{Var := List} -> case lists:keyfind(Pred, 1, List) of {Pred, {assigned, NewVar}} -> %% The variable is untagged! @@ -473,13 +562,15 @@ subst_phi_uses_uncond0([{Pred, Var}|Left], Map, Acc) -> %% The variable is not untagged. subst_phi_uses_uncond0(Left, Map, [{Pred, Var} | Acc]) end; - none -> + #{} -> %% The variable is not untagged. subst_phi_uses_uncond0(Left, Map, [{Pred, Var} | Acc]) end; subst_phi_uses_uncond0([], _Map, Acc) -> Acc. +-spec place_error_handling(worklist(), #state{}) -> #state{}. + place_error_handling(WorkList, State) -> case get_work(WorkList) of none -> @@ -502,6 +593,9 @@ place_error_handling(WorkList, State) -> end end. +-spec place_error(icode_instrs(), in_block(), icode_instrs()) + -> {icode_instrs(), in_block()}. + place_error([I|Left], InBlock, Acc) -> case I of #icode_call{} -> @@ -638,12 +732,10 @@ instr_allowed_in_fp_ebb(Instr) -> %%============================================================= %% ------------------------------------------------------------ -%% Handling the gb_tree +%% Handling the variable map -delete_all([Key|Left], Tree) -> - delete_all(Left, gb_trees:delete_any(Key, Tree)); -delete_all([], Tree) -> - Tree. +-spec lookup_list([icode_var() | #icode_const{}], var_map()) + -> [none | icode_fvar()]. lookup_list(List, Info) -> lookup_list(List, fun lookup/2, Info, []). @@ -653,33 +745,43 @@ lookup_list([H|T], Fun, Info, Acc) -> lookup_list([], _, _, Acc) -> lists:reverse(Acc). +-spec lookup(icode_var() | #icode_const{}, var_map()) -> none | icode_fvar(). + lookup(Key, Tree) -> case hipe_icode:is_const(Key) of %% This can be true if the same constant has been %% untagged more than once true -> none; false -> - case gb_trees:lookup(Key, Tree) of - none -> none; - {value, {assigned, Val}} -> Val; - {value, Val} -> Val + case Tree of + #{Key := {assigned, Val}} -> Val; + #{Key := Val} -> Val; + #{} -> none end end. +-spec lookup_list_keep_consts([icode_var() | #icode_const{}], var_map()) + -> [none | icode_fvar() | #icode_const{}]. + lookup_list_keep_consts(List, Info) -> lookup_list(List, fun lookup_keep_consts/2, Info, []). +-spec lookup_keep_consts(icode_var() | #icode_const{}, var_map()) + -> none | icode_fvar() | #icode_const{}. + lookup_keep_consts(Key, Tree) -> case hipe_icode:is_const(Key) of true -> Key; false -> - case gb_trees:lookup(Key, Tree) of - none -> none; - {value, {assigned, Val}} -> Val; - {value, Val} -> Val + case Tree of + #{Key := {assigned, Val}} -> Val; + #{Key := Val} -> Val; + #{} -> none end end. +-spec get_type(icode_argument()) -> erl_types:erl_type(). + get_type(Var) -> case hipe_icode:is_const(Var) of true -> erl_types:t_from_term(hipe_icode:const_value(Var)); @@ -695,43 +797,50 @@ get_type(Var) -> %% ------------------------------------------------------------ %% Handling the map from variables to fp-variables +-spec join_maps([edge()], edge_map()) -> initial_var_map(). + join_maps(Edges, EdgeMap) -> - join_maps(Edges, EdgeMap, gb_trees:empty()). + join_maps(Edges, EdgeMap, #{}). join_maps([Edge = {Pred, _}|Left], EdgeMap, Map) -> - case gb_trees:lookup(Edge, EdgeMap) of - none -> + case EdgeMap of + #{Edge := OldMap} -> + NewMap = join_maps0(maps:to_list(OldMap), Pred, Map), + join_maps(Left, EdgeMap, NewMap); + #{} -> %% All predecessors have not been handled. Use empty map. - gb_trees:empty(); - {value, OldMap} -> - NewMap = join_maps0(gb_trees:to_list(OldMap), Pred, Map), - join_maps(Left, EdgeMap, NewMap) + #{} end; join_maps([], _, Map) -> Map. -join_maps0([{phi, _}|Tail], Pred, Map) -> - join_maps0(Tail, Pred, Map); -join_maps0([{Var, FVar}|Tail], Pred, Map) -> - case gb_trees:lookup(Var, Map) of - none -> - join_maps0(Tail, Pred, gb_trees:enter(Var, [{Pred, FVar}], Map)); - {value, List} -> +-spec join_maps0(list(), icode_lbl(), initial_var_map()) -> initial_var_map(). + +join_maps0([{Var=#icode_variable{kind=var}, FVar}|Tail], Pred, Map) -> + case Map of + #{Var := List} -> case lists:keyfind(Pred, 1, List) of false -> - join_maps0(Tail, Pred, gb_trees:update(Var, [{Pred, FVar}|List], Map)); + join_maps0(Tail, Pred, Map#{Var := [{Pred, FVar}|List]}); {Pred, FVar} -> %% No problem. join_maps0(Tail, Pred, Map); _ -> exit('New binding to same variable') - end + end; + #{} -> + join_maps0(Tail, Pred, Map#{Var => [{Pred, FVar}]}) end; join_maps0([], _, Map) -> Map. +-spec filter_map(initial_var_map(), pos_integer()) -> var_map_phi(). + filter_map(Map, NofPreds) -> - filter_map(gb_trees:to_list(Map), NofPreds, Map). + filter_map(maps:to_list(Map), NofPreds, Map). + +-spec filter_map([{icode_var(), incoming_fvars()}], pos_integer(), + var_map_phi()) -> var_map_phi(). filter_map([{Var, Bindings}|Left], NofPreds, Map) -> case length(Bindings) =:= NofPreds of @@ -747,35 +856,39 @@ filter_map([{Var, Bindings}|Left], NofPreds, Map) -> end; {Pred, FVar0} when is_integer(Pred) -> FVar0 end, - filter_map(Left, NofPreds, gb_trees:update(Var, NewBinding, Map)); + filter_map(Left, NofPreds, Map#{Var := NewBinding}); false -> PhiDst = hipe_icode:mk_new_fvar(), PhiArgs = strip_of_assigned(Bindings), NewMap = - case gb_trees:lookup(phi, Map) of - none -> - gb_trees:insert(phi, [{PhiDst, PhiArgs}], Map); - {value, Val} -> - gb_trees:update(phi, [{PhiDst, PhiArgs}|Val], Map) + case Map of + #{phi := Val} -> + Map#{phi := [{PhiDst, PhiArgs}|Val]}; + #{} -> + Map#{phi => [{PhiDst, PhiArgs}]} end, NewBinding = case bindings_all_assigned(Bindings) of true -> {assigned, PhiDst}; false -> PhiDst end, - filter_map(Left, NofPreds, gb_trees:update(Var, NewBinding, NewMap)) + filter_map(Left, NofPreds, NewMap#{Var := NewBinding}) end; false -> - filter_map(Left, NofPreds, gb_trees:delete(Var, Map)) + filter_map(Left, NofPreds, maps:remove(Var, Map)) end; filter_map([], _NofPreds, Map) -> Map. +-spec bindings_all_assigned(incoming_fvars()) -> boolean(). + bindings_all_assigned([]) -> true; bindings_all_assigned([{_, {assigned, _}}|Left]) -> bindings_all_assigned(Left); bindings_all_assigned(_) -> false. +-spec all_args_equal(incoming_fvars()) -> boolean(). + %% 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. @@ -798,20 +911,24 @@ all_args_equal(_, _) -> false. +-spec add_new_bindings_unassigned([icode_var()], var_map()) -> var_map(). + %% We differentiate between values that have been assigned as %% tagged variables and those that got a 'virtual' binding. add_new_bindings_unassigned([Var|Left], Map) -> FVar = hipe_icode:mk_new_fvar(), - add_new_bindings_unassigned(Left, gb_trees:insert(Var, FVar, Map)); + add_new_bindings_unassigned(Left, Map#{Var => FVar}); add_new_bindings_unassigned([], Map) -> Map. +-spec add_new_bindings_assigned([icode_var()], var_map()) -> var_map(). + add_new_bindings_assigned([Var|Left], Map) -> case lookup(Var, Map) of none -> FVar = hipe_icode:mk_new_fvar(), - NewMap = gb_trees:insert(Var, {assigned, FVar}, Map), + NewMap = Map#{Var => {assigned, FVar}}, add_new_bindings_assigned(Left, NewMap); _ -> add_new_bindings_assigned(Left, Map) @@ -819,6 +936,8 @@ add_new_bindings_assigned([Var|Left], Map) -> add_new_bindings_assigned([], Map) -> Map. +-spec strip_of_assigned(incoming_fvars()) -> [{icode_lbl(), icode_fvar()}]. + strip_of_assigned(List) -> strip_of_assigned(List, []). @@ -833,6 +952,8 @@ strip_of_assigned([], Acc) -> %% Help functions for the transformation from ordinary instruction to %% fp-instruction +-spec is_fop_cand(icode_instr()) -> boolean(). + is_fop_cand(I) -> case hipe_icode:call_fun(I) of '/' -> true; @@ -843,6 +964,8 @@ is_fop_cand(I) -> end end. +-spec any_is_float([icode_argument()]) -> boolean(). + any_is_float(Vars) -> lists:any(fun (V) -> erl_types:t_is_float(get_type(V)) end, Vars). @@ -869,25 +992,32 @@ fun_to_fop(Fun) -> end. +-spec must_be_tagged(icode_var(), var_map()) -> boolean(). + %% If there is a tagged version of this variable available we don't %% have to tag the untagged version. must_be_tagged(Var, Map) -> - case gb_trees:lookup(Var, Map) of - none -> false; - {value, {assigned, _}} -> false; - {value, Val} -> hipe_icode:is_fvar(Val) + case Map of + #{Var := {assigned, _}} -> false; + #{Var := Val} -> hipe_icode:is_fvar(Val); + #{} -> false end. +-spec get_conv_instrs([icode_argument()], var_map()) -> icode_instrs(). + %% Converting to floating point variables get_conv_instrs(Vars, Map) -> get_conv_instrs(Vars, Map, []). +-spec get_conv_instrs([icode_argument()], var_map(), icode_instrs()) + -> icode_instrs(). + get_conv_instrs([Var|Left], Map, Acc) -> - {_, Dst} = gb_trees:get(Var, Map), - NewI = + #{Var := {_, Dst}} = Map, + NewI = case erl_types:t_is_float(get_type(Var)) of true -> [hipe_icode:mk_primop([Dst], unsafe_untag_float, [Var])]; @@ -899,6 +1029,8 @@ get_conv_instrs([], _, Acc) -> Acc. +-spec conv_consts([#icode_const{}], icode_instr()) -> icode_instr(). + conv_consts(ConstArgs, I) -> conv_consts(ConstArgs, I, []). @@ -937,63 +1069,79 @@ state__bb_add(S = #state{cfg = Cfg}, Label, BB) -> NewCfg = hipe_icode_cfg:bb_add(Cfg, Label, BB), S#state{cfg = NewCfg}. +-spec state__map(#state{}, icode_lbl()) -> initial_var_map(). + state__map(S = #state{edge_map = EM}, To) -> join_maps([{From, To} || From <- state__pred(S, To)], EM). +-spec state__map_update(#state{}, icode_lbl(), icode_lbl(), var_map()) -> + fixpoint | #state{}. + state__map_update(S = #state{edge_map = EM}, From, To, Map) -> FromTo = {From, To}, MapChanged = - case gb_trees:lookup(FromTo, EM) of - {value, Map1} -> not match(Map1, Map); - none -> true + case EM of + #{FromTo := Map1} -> not match(Map1, Map); + #{} -> true end, case MapChanged of true -> - NewEM = gb_trees:enter(FromTo, Map, EM), + NewEM = EM#{FromTo => Map}, S#state{edge_map = NewEM}; false -> fixpoint end. +-spec state__join_in_block(#state{}, icode_lbl()) + -> fixpoint | {#state{}, in_block()}. + state__join_in_block(S = #state{fp_ebb_map = Map}, Label) -> Pred = state__pred(S, Label), Edges = [{X, Label} || X <- Pred], - NewInBlock = join_in_block([gb_trees:lookup(X, Map) || X <- Edges]), + NewInBlock = join_in_block([maps:find(X, Map) || X <- Edges]), InBlockLabel = {inblock_in, Label}, - case gb_trees:lookup(InBlockLabel, Map) of - none -> - NewMap = gb_trees:insert(InBlockLabel, NewInBlock, Map), - {S#state{fp_ebb_map = NewMap}, NewInBlock}; - {value, NewInBlock} -> + case Map of + #{InBlockLabel := NewInBlock} -> fixpoint; - _Other -> - NewMap = gb_trees:update(InBlockLabel, NewInBlock, Map), + _ -> + NewMap = Map#{InBlockLabel => NewInBlock}, {S#state{fp_ebb_map = NewMap}, NewInBlock} end. +-spec state__in_block_out_update(#state{}, icode_lbl(), in_block()) + -> #state{}. + state__in_block_out_update(S = #state{fp_ebb_map = Map}, Label, NewInBlock) -> Succ = state__succ(S, Label), Edges = [{Label, X} || X <- Succ], NewMap = update_edges(Edges, NewInBlock, Map), - NewMap1 = gb_trees:enter({inblock_out, Label}, NewInBlock, NewMap), + NewMap1 = NewMap#{{inblock_out, Label} => NewInBlock}, S#state{fp_ebb_map = NewMap1}. +-spec update_edges([edge()], in_block(), fp_ebb_map()) -> fp_ebb_map(). + update_edges([Edge|Left], NewInBlock, Map) -> - NewMap = gb_trees:enter(Edge, NewInBlock, Map), + NewMap = Map#{Edge => NewInBlock}, update_edges(Left, NewInBlock, NewMap); update_edges([], _NewInBlock, NewMap) -> NewMap. +-spec join_in_block([error | {ok, in_block()}]) -> in_block(). + join_in_block([]) -> false; -join_in_block([none|_]) -> +join_in_block([error|_]) -> false; -join_in_block([{value, InBlock}|Left]) -> +join_in_block([{ok, InBlock}|Left]) -> join_in_block(Left, InBlock). -join_in_block([none|_], _Current) -> +-spec join_in_block([error | {ok, in_block()}], Current) + -> false | Current when + Current :: in_block(). + +join_in_block([error|_], _Current) -> false; -join_in_block([{value, InBlock}|Left], Current) -> +join_in_block([{ok, InBlock}|Left], Current) -> if Current =:= InBlock -> join_in_block(Left, Current); Current =:= false -> false; InBlock =:= false -> false; @@ -1001,19 +1149,25 @@ join_in_block([{value, InBlock}|Left], Current) -> end; join_in_block([], Current) -> Current. - + + +-spec state__get_in_block_in(#state{}, icode_lbl()) -> in_block(). state__get_in_block_in(#state{fp_ebb_map = Map}, Label) -> - gb_trees:get({inblock_in, Label}, Map). + maps:get({inblock_in, Label}, Map). state__get_in_block_out(#state{fp_ebb_map = Map}, Label) -> - gb_trees:get({inblock_out, Label}, Map). + maps:get({inblock_out, Label}, Map). + +-spec new_worklist(#state{}) -> worklist(). new_worklist(#state{cfg = Cfg}) -> Start = hipe_icode_cfg:start_label(Cfg), {[Start], [], gb_sets:insert(Start, gb_sets:empty())}. +-spec get_work(worklist()) -> none | {icode_lbl(), worklist()}. + get_work({[Label|Left], List, Set}) -> {Label, {Left, List, gb_sets:delete(Label, Set)}}; get_work({[], [], _Set}) -> @@ -1021,6 +1175,8 @@ get_work({[], [], _Set}) -> get_work({[], List, Set}) -> get_work({lists:reverse(List), [], Set}). +-spec add_work(worklist(), [icode_lbl()]) -> worklist(). + add_work({List1, List2, Set} = Work, [Label|Left]) -> case gb_sets:is_member(Label, Set) of true -> @@ -1033,15 +1189,17 @@ add_work({List1, List2, Set} = Work, [Label|Left]) -> add_work(WorkList, []) -> WorkList. +-spec match(var_map(), var_map()) -> boolean(). + match(Tree1, Tree2) -> - match_1(gb_trees:to_list(Tree1), Tree2) andalso - match_1(gb_trees:to_list(Tree2), Tree1). + match_1(maps:to_list(Tree1), Tree2) andalso + match_1(maps:to_list(Tree2), Tree1). match_1([{Key, Val}|Left], Tree2) -> - case gb_trees:lookup(Key, Tree2) of - {value, Val} -> + case Tree2 of + #{Key := Val} -> match_1(Left, Tree2); - _ -> false + #{} -> false end; match_1([], _) -> true. -- cgit v1.2.3 From 19374264924eb00d9475f6e694335e81a3f31c45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20L=C3=A5ng?= Date: Thu, 3 Mar 2016 16:12:24 +0100 Subject: hipe_icode_fp: Define types for all records used --- lib/hipe/icode/hipe_icode_fp.erl | 99 +++++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 47 deletions(-) diff --git a/lib/hipe/icode/hipe_icode_fp.erl b/lib/hipe/icode/hipe_icode_fp.erl index 7bfb21e7db..3098e629ca 100644 --- a/lib/hipe/icode/hipe_icode_fp.erl +++ b/lib/hipe/icode/hipe_icode_fp.erl @@ -55,11 +55,16 @@ -record(state, {edge_map = #{} :: edge_map(), fp_ebb_map = #{} :: fp_ebb_map(), - cfg :: #cfg{}}). + cfg :: cfg()}). +-type state() :: #state{}. + +-type icode_phi() :: #icode_phi{}. +-type icode_variable() :: #icode_variable{}. +-type icode_const() :: #icode_const{}. %%-------------------------------------------------------------------- --spec cfg(#cfg{}) -> #cfg{}. +-spec cfg(cfg()) -> cfg(). cfg(Cfg) -> %%hipe_icode_cfg:pp(Cfg), @@ -78,13 +83,13 @@ cfg(Cfg) -> %% corresponding fcheckerror. %%-------------------------------------------------------------------- --spec annotate_fclearerror(#cfg{}) -> #cfg{}. +-spec annotate_fclearerror(cfg()) -> cfg(). annotate_fclearerror(Cfg) -> Labels = hipe_icode_cfg:reverse_postorder(Cfg), annotate_fclearerror(Labels, Cfg). --spec annotate_fclearerror([icode_lbl()], #cfg{}) -> #cfg{}. +-spec annotate_fclearerror([icode_lbl()], cfg()) -> cfg(). annotate_fclearerror([Label|Left], Cfg) -> BB = hipe_icode_cfg:bb(Cfg, Label), @@ -96,7 +101,7 @@ annotate_fclearerror([Label|Left], Cfg) -> annotate_fclearerror([], Cfg) -> Cfg. --spec annotate_fclearerror1(icode_instrs(), icode_lbl(), #cfg{}, icode_instrs()) +-spec annotate_fclearerror1(icode_instrs(), icode_lbl(), cfg(), icode_instrs()) -> icode_instrs(). annotate_fclearerror1([I|Left], Label, Cfg, Acc) -> @@ -116,7 +121,7 @@ annotate_fclearerror1([I|Left], Label, Cfg, Acc) -> annotate_fclearerror1([], _Label, _Cfg, Acc) -> lists:reverse(Acc). --spec lookahead_for_fcheckerror(icode_instrs(), icode_lbl(), #cfg{}) -> +-spec lookahead_for_fcheckerror(icode_instrs(), icode_lbl(), cfg()) -> fail_lbl(). lookahead_for_fcheckerror([I|Left], Label, Cfg) -> @@ -140,13 +145,13 @@ lookahead_for_fcheckerror([], Label, Cfg) -> lookahead_for_fcheckerror(Code, Succ, Cfg) end. --spec unannotate_fclearerror(#cfg{}) -> #cfg{}. +-spec unannotate_fclearerror(cfg()) -> cfg(). unannotate_fclearerror(Cfg) -> Labels = hipe_icode_cfg:reverse_postorder(Cfg), unannotate_fclearerror(Labels, Cfg). --spec unannotate_fclearerror([icode_lbl()], #cfg{}) -> #cfg{}. +-spec unannotate_fclearerror([icode_lbl()], cfg()) -> cfg(). unannotate_fclearerror([Label|Left], Cfg) -> BB = hipe_icode_cfg:bb(Cfg, Label), @@ -181,13 +186,13 @@ unannotate_fclearerror1([], Acc) -> %% Make float EBBs %%-------------------------------------------------------------------- --spec place_fp_blocks(#state{}) -> #state{}. +-spec place_fp_blocks(state()) -> state(). place_fp_blocks(State) -> WorkList = new_worklist(State), transform_block(WorkList, State). --spec transform_block(worklist(), #state{}) -> #state{}. +-spec transform_block(worklist(), state()) -> state(). transform_block(WorkList, State) -> case get_work(WorkList) of @@ -222,9 +227,9 @@ transform_block(WorkList, State) -> end end. --spec update_maps(#state{}, icode_lbl(), ordsets:ordset(icode_lbl()), +-spec update_maps(state(), icode_lbl(), ordsets:ordset(icode_lbl()), var_map(), ordsets:ordset(icode_lbl()), var_map()) - -> fixpoint | {#state{}, [icode_lbl()]}. + -> fixpoint | {state(), [icode_lbl()]}. update_maps(State, Label, SuccSet, SuccMap, FailSet, FailMap) -> {NewState, Add1} = update_maps(State, Label, SuccSet, SuccMap, []), @@ -233,9 +238,9 @@ update_maps(State, Label, SuccSet, SuccMap, FailSet, FailMap) -> {_NewState1, _Add} = Ret -> Ret end. --spec update_maps(#state{}, icode_lbl(), ordsets:ordset(icode_lbl()), +-spec update_maps(state(), icode_lbl(), ordsets:ordset(icode_lbl()), var_map(), [icode_lbl()]) - -> {#state{}, [icode_lbl()]}. + -> {state(), [icode_lbl()]}. update_maps(State, From, [To|Left], Map, Acc) -> case state__map_update(State, From, To, Map) of @@ -382,7 +387,7 @@ handle_untagged_arguments(I, Map) -> [I|TagIntrs] end. --spec do_prelude(var_map_phi()) -> {[#icode_phi{}], var_map()}. +-spec do_prelude(var_map_phi()) -> {[icode_phi()], var_map()}. %% Add phi nodes for untagged fp values. @@ -406,7 +411,7 @@ split_code([I|Left], Acc) -> split_code(Left, [I|Acc]). --spec finalize(#state{}) -> #state{}. +-spec finalize(state()) -> state(). %% When all code is mapped to fp instructions we must make sure that %% the fp ebb information going into each block is the same as the @@ -419,7 +424,7 @@ finalize(State) -> Edges = needs_fcheckerror(NewState), finalize(Edges, NewState). --spec finalize([edge()], #state{}) -> #state{}. +-spec finalize([edge()], state()) -> state(). finalize([{From, To}|Left], State) -> NewState = add_fp_ebb_fixup(From, To, State), @@ -427,14 +432,14 @@ finalize([{From, To}|Left], State) -> finalize([], State) -> State. --spec needs_fcheckerror(#state{}) -> [{none | icode_lbl(), icode_lbl()}]. +-spec needs_fcheckerror(state()) -> [{none | icode_lbl(), icode_lbl()}]. needs_fcheckerror(State) -> Cfg = state__cfg(State), Labels = hipe_icode_cfg:labels(Cfg), needs_fcheckerror(Labels, State, []). --spec needs_fcheckerror([icode_lbl()], #state{}, +-spec needs_fcheckerror([icode_lbl()], state(), [{none | icode_lbl(), icode_lbl()}]) -> [{none | icode_lbl(), icode_lbl()}]. @@ -462,7 +467,7 @@ needs_fcheckerror([Label|Left], State, Acc) -> needs_fcheckerror([], _State, Acc) -> Acc. --spec add_fp_ebb_fixup(none | icode_lbl(), icode_lbl(), #state{}) -> #state{}. +-spec add_fp_ebb_fixup(none | icode_lbl(), icode_lbl(), state()) -> state(). add_fp_ebb_fixup('none', To, State) -> %% Add the fcheckerror to the start of the block. @@ -505,16 +510,16 @@ redirect_phis([I|Is] = Code, OldFrom, NewFrom, Acc) -> redirect_phis([], _OldFrom, _NewFrom, Acc) -> lists:reverse(Acc). --spec subst_phi(#icode_phi{}, #icode_variable{}, edge_map()) - -> #icode_phi{}. +-spec subst_phi(icode_phi(), icode_variable(), edge_map()) + -> icode_phi(). subst_phi(I, Dst, Map) -> ArgList = subst_phi_uses0(hipe_icode:phi_arglist(I), Map, []), hipe_icode:mk_phi(Dst, ArgList). --spec subst_phi_uses0([{icode_lbl(), #icode_variable{}}], edge_map(), - [{icode_lbl(), #icode_variable{}}]) - -> [{icode_lbl(), #icode_variable{}}]. +-spec subst_phi_uses0([{icode_lbl(), icode_variable()}], edge_map(), + [{icode_lbl(), icode_variable()}]) + -> [{icode_lbl(), icode_variable()}]. subst_phi_uses0([{Pred, Var}|Left], Map, Acc) -> case Map of @@ -537,16 +542,16 @@ subst_phi_uses0([{Pred, Var}|Left], Map, Acc) -> subst_phi_uses0([], _Map, Acc) -> Acc. --spec subst_phi_uncond(#icode_phi{}, #icode_variable{}, edge_map()) - -> #icode_phi{}. +-spec subst_phi_uncond(icode_phi(), icode_variable(), edge_map()) + -> icode_phi(). subst_phi_uncond(I, Dst, Map) -> ArgList = subst_phi_uses_uncond0(hipe_icode:phi_arglist(I), Map, []), hipe_icode:mk_phi(Dst, ArgList). --spec subst_phi_uses_uncond0([{icode_lbl(), #icode_variable{}}], edge_map(), - [{icode_lbl(), #icode_variable{}}]) - -> [{icode_lbl(), #icode_variable{}}]. +-spec subst_phi_uses_uncond0([{icode_lbl(), icode_variable()}], edge_map(), + [{icode_lbl(), icode_variable()}]) + -> [{icode_lbl(), icode_variable()}]. subst_phi_uses_uncond0([{Pred, Var}|Left], Map, Acc) -> case Map of @@ -569,7 +574,7 @@ subst_phi_uses_uncond0([{Pred, Var}|Left], Map, Acc) -> subst_phi_uses_uncond0([], _Map, Acc) -> Acc. --spec place_error_handling(worklist(), #state{}) -> #state{}. +-spec place_error_handling(worklist(), state()) -> state(). place_error_handling(WorkList, State) -> case get_work(WorkList) of @@ -734,7 +739,7 @@ instr_allowed_in_fp_ebb(Instr) -> %% ------------------------------------------------------------ %% Handling the variable map --spec lookup_list([icode_var() | #icode_const{}], var_map()) +-spec lookup_list([icode_var() | icode_const()], var_map()) -> [none | icode_fvar()]. lookup_list(List, Info) -> @@ -745,7 +750,7 @@ lookup_list([H|T], Fun, Info, Acc) -> lookup_list([], _, _, Acc) -> lists:reverse(Acc). --spec lookup(icode_var() | #icode_const{}, var_map()) -> none | icode_fvar(). +-spec lookup(icode_var() | icode_const(), var_map()) -> none | icode_fvar(). lookup(Key, Tree) -> case hipe_icode:is_const(Key) of @@ -760,14 +765,14 @@ lookup(Key, Tree) -> end end. --spec lookup_list_keep_consts([icode_var() | #icode_const{}], var_map()) - -> [none | icode_fvar() | #icode_const{}]. +-spec lookup_list_keep_consts([icode_var() | icode_const()], var_map()) + -> [none | icode_fvar() | icode_const()]. lookup_list_keep_consts(List, Info) -> lookup_list(List, fun lookup_keep_consts/2, Info, []). --spec lookup_keep_consts(icode_var() | #icode_const{}, var_map()) - -> none | icode_fvar() | #icode_const{}. +-spec lookup_keep_consts(icode_var() | icode_const(), var_map()) + -> none | icode_fvar() | icode_const(). lookup_keep_consts(Key, Tree) -> case hipe_icode:is_const(Key) of @@ -1029,7 +1034,7 @@ get_conv_instrs([], _, Acc) -> Acc. --spec conv_consts([#icode_const{}], icode_instr()) -> icode_instr(). +-spec conv_consts([icode_const()], icode_instr()) -> icode_instr(). conv_consts(ConstArgs, I) -> conv_consts(ConstArgs, I, []). @@ -1069,13 +1074,13 @@ state__bb_add(S = #state{cfg = Cfg}, Label, BB) -> NewCfg = hipe_icode_cfg:bb_add(Cfg, Label, BB), S#state{cfg = NewCfg}. --spec state__map(#state{}, icode_lbl()) -> initial_var_map(). +-spec state__map(state(), icode_lbl()) -> initial_var_map(). state__map(S = #state{edge_map = EM}, To) -> join_maps([{From, To} || From <- state__pred(S, To)], EM). --spec state__map_update(#state{}, icode_lbl(), icode_lbl(), var_map()) -> - fixpoint | #state{}. +-spec state__map_update(state(), icode_lbl(), icode_lbl(), var_map()) -> + fixpoint | state(). state__map_update(S = #state{edge_map = EM}, From, To, Map) -> FromTo = {From, To}, @@ -1092,8 +1097,8 @@ state__map_update(S = #state{edge_map = EM}, From, To, Map) -> fixpoint end. --spec state__join_in_block(#state{}, icode_lbl()) - -> fixpoint | {#state{}, in_block()}. +-spec state__join_in_block(state(), icode_lbl()) + -> fixpoint | {state(), in_block()}. state__join_in_block(S = #state{fp_ebb_map = Map}, Label) -> Pred = state__pred(S, Label), @@ -1108,8 +1113,8 @@ state__join_in_block(S = #state{fp_ebb_map = Map}, Label) -> {S#state{fp_ebb_map = NewMap}, NewInBlock} end. --spec state__in_block_out_update(#state{}, icode_lbl(), in_block()) - -> #state{}. +-spec state__in_block_out_update(state(), icode_lbl(), in_block()) + -> state(). state__in_block_out_update(S = #state{fp_ebb_map = Map}, Label, NewInBlock) -> Succ = state__succ(S, Label), @@ -1151,7 +1156,7 @@ join_in_block([], Current) -> Current. --spec state__get_in_block_in(#state{}, icode_lbl()) -> in_block(). +-spec state__get_in_block_in(state(), icode_lbl()) -> in_block(). state__get_in_block_in(#state{fp_ebb_map = Map}, Label) -> maps:get({inblock_in, Label}, Map). @@ -1160,7 +1165,7 @@ state__get_in_block_out(#state{fp_ebb_map = Map}, Label) -> maps:get({inblock_out, Label}, Map). --spec new_worklist(#state{}) -> worklist(). +-spec new_worklist(state()) -> worklist(). new_worklist(#state{cfg = Cfg}) -> Start = hipe_icode_cfg:start_label(Cfg), -- cgit v1.2.3 From e6c42f382429b0f8e2edc8d5676f656f37a9a408 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20L=C3=A5ng?= Date: Mon, 7 Mar 2016 13:14:07 +0100 Subject: hipe_icode_fp: Replace helper with lists:all --- lib/hipe/icode/hipe_icode_fp.erl | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/lib/hipe/icode/hipe_icode_fp.erl b/lib/hipe/icode/hipe_icode_fp.erl index 3098e629ca..4f404d458c 100644 --- a/lib/hipe/icode/hipe_icode_fp.erl +++ b/lib/hipe/icode/hipe_icode_fp.erl @@ -850,12 +850,15 @@ filter_map(Map, NofPreds) -> filter_map([{Var, Bindings}|Left], NofPreds, Map) -> case length(Bindings) =:= NofPreds of true -> + BindingsAllAssigned = lists:all(fun({_, {assigned, _}}) -> true; + ({_, _}) -> false + end, Bindings), case all_args_equal(Bindings) of true -> NewBinding = case hd(Bindings) of {Pred, {assigned, FVar0}} when is_integer(Pred) -> - case bindings_all_assigned(Bindings) of + case BindingsAllAssigned of true -> {assigned, FVar0}; false -> FVar0 end; @@ -873,7 +876,7 @@ filter_map([{Var, Bindings}|Left], NofPreds, Map) -> Map#{phi => [{PhiDst, PhiArgs}]} end, NewBinding = - case bindings_all_assigned(Bindings) of + case BindingsAllAssigned of true -> {assigned, PhiDst}; false -> PhiDst end, @@ -885,13 +888,6 @@ filter_map([{Var, Bindings}|Left], NofPreds, Map) -> filter_map([], _NofPreds, Map) -> Map. --spec bindings_all_assigned(incoming_fvars()) -> boolean(). - -bindings_all_assigned([]) -> true; -bindings_all_assigned([{_, {assigned, _}}|Left]) -> - bindings_all_assigned(Left); -bindings_all_assigned(_) -> false. - -spec all_args_equal(incoming_fvars()) -> boolean(). %% all_args_equal returns true if the mapping for a variable is the -- cgit v1.2.3 From e86a36d19b8e7e84b66588c37714e6e57a8309a7 Mon Sep 17 00:00:00 2001 From: Kostis Sagonas Date: Mon, 7 Mar 2016 20:45:49 +0100 Subject: Comment and clean up a test --- lib/hipe/test/basic_SUITE_data/basic_floats.erl | 65 ++++++++++++------------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/lib/hipe/test/basic_SUITE_data/basic_floats.erl b/lib/hipe/test/basic_SUITE_data/basic_floats.erl index ebd3852002..ce28f6e156 100644 --- a/lib/hipe/test/basic_SUITE_data/basic_floats.erl +++ b/lib/hipe/test/basic_SUITE_data/basic_floats.erl @@ -210,42 +210,41 @@ f(A, B, C) -> 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. +%%-------------------------------------------------------------------- +%% Contains another case that crashed hipe_icode_fp. This sample was +%% sent by Mattias Jansson (25 Nov 2015). It compiled alright with the +%% option 'no_icode_type' but that defeats the purpose of the test. +%% Unfortunately, the execution of this code goes into an infinite +%% loop, even if the map in the second argument of eat_what/2 gets the +%% appropriate key-value pairs. Still, it is retained as a test +%% because it exposed a different crash than test_icode_type_crash/0. test_icode_type_crash_2() -> - {'EXIT', {function_clause, _}} = (catch eat()), - ok. + {'EXIT', {function_clause, _}} = (catch eat()), + ok. eat() -> - eat_what(1.0, #{}). + 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}. + #{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}. -- cgit v1.2.3 From a6fa6f54bb508da8c92b597a56acbb866abf2f0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20L=C3=A5ng?= Date: Thu, 10 Mar 2016 15:48:57 +0100 Subject: hipe_icode_fp: simplify match/2 --- lib/hipe/icode/hipe_icode_fp.erl | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/lib/hipe/icode/hipe_icode_fp.erl b/lib/hipe/icode/hipe_icode_fp.erl index 4f404d458c..ae12f20cc2 100644 --- a/lib/hipe/icode/hipe_icode_fp.erl +++ b/lib/hipe/icode/hipe_icode_fp.erl @@ -1192,15 +1192,5 @@ add_work(WorkList, []) -> -spec match(var_map(), var_map()) -> boolean(). -match(Tree1, Tree2) -> - match_1(maps:to_list(Tree1), Tree2) andalso - match_1(maps:to_list(Tree2), Tree1). - -match_1([{Key, Val}|Left], Tree2) -> - case Tree2 of - #{Key := Val} -> - match_1(Left, Tree2); - #{} -> false - end; -match_1([], _) -> - true. +match(Tree1, Tree2) when is_map(Tree1), is_map(Tree2) -> + Tree1 =:= Tree2. -- cgit v1.2.3