aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hipe/icode
diff options
context:
space:
mode:
Diffstat (limited to 'lib/hipe/icode')
-rw-r--r--lib/hipe/icode/hipe_icode_fp.erl354
1 files 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.