aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hipe
diff options
context:
space:
mode:
Diffstat (limited to 'lib/hipe')
-rw-r--r--lib/hipe/amd64/hipe_amd64_ra_sse2_postconditions.erl16
-rw-r--r--lib/hipe/arm/hipe_arm_registers.erl8
-rw-r--r--lib/hipe/arm/hipe_rtl_to_arm.erl9
-rw-r--r--lib/hipe/cerl/erl_bif_types.erl6
-rw-r--r--lib/hipe/cerl/erl_types.erl403
-rw-r--r--lib/hipe/doc/src/notes.xml113
-rw-r--r--lib/hipe/icode/hipe_beam_to_icode.erl28
-rw-r--r--lib/hipe/icode/hipe_icode.erl2
-rw-r--r--lib/hipe/icode/hipe_icode_call_elim.erl3
-rw-r--r--lib/hipe/icode/hipe_icode_primops.erl8
-rw-r--r--lib/hipe/llvm/hipe_llvm_main.erl14
-rw-r--r--lib/hipe/llvm/hipe_rtl_to_llvm.erl103
-rw-r--r--lib/hipe/main/hipe.erl91
-rw-r--r--lib/hipe/main/hipe.hrl.src12
-rw-r--r--lib/hipe/main/hipe_main.erl2
-rw-r--r--lib/hipe/ppc/hipe_ppc.erl12
-rw-r--r--lib/hipe/ppc/hipe_ppc_assemble.erl7
-rw-r--r--lib/hipe/rtl/hipe_rtl_binary.erl2
-rw-r--r--lib/hipe/rtl/hipe_rtl_binary_match.erl37
-rw-r--r--lib/hipe/sparc/hipe_rtl_to_sparc.erl40
-rw-r--r--lib/hipe/sparc/hipe_sparc_registers.erl8
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_num_bif.erl217
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_pmatch_bugs.erl48
-rw-r--r--lib/hipe/test/hipe_SUITE.erl6
-rw-r--r--lib/hipe/test/hipe_testsuite_driver.erl2
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_redundant_branch_is_key.erl14
-rw-r--r--lib/hipe/test/opt_verify_SUITE.erl39
-rw-r--r--lib/hipe/vsn.mk2
-rw-r--r--lib/hipe/x86/hipe_x86_postpass.erl3
29 files changed, 878 insertions, 377 deletions
diff --git a/lib/hipe/amd64/hipe_amd64_ra_sse2_postconditions.erl b/lib/hipe/amd64/hipe_amd64_ra_sse2_postconditions.erl
index 5451f1fe7d..b1f7bd7572 100644
--- a/lib/hipe/amd64/hipe_amd64_ra_sse2_postconditions.erl
+++ b/lib/hipe/amd64/hipe_amd64_ra_sse2_postconditions.erl
@@ -87,22 +87,29 @@ do_fp_unop(I, TempMap) ->
%%% Fix an fmove op.
do_fmove(I, TempMap) ->
#fmove{src=Src,dst=Dst} = I,
- case is_mem_opnd(Dst, TempMap) and is_mem_opnd(Src, TempMap) of
+ case
+ (is_mem_opnd(Src, TempMap) andalso is_mem_opnd(Dst, TempMap))
+ orelse (is_mem_opnd(Src, TempMap) andalso (not is_float_temp(Dst)))
+ orelse ((not is_float_temp(Src)) andalso is_mem_opnd(Dst, TempMap))
+ of
true ->
- Tmp = clone(Src),
+ Tmp = spill_temp(double),
{[#fmove{src=Src, dst=Tmp},I#fmove{src=Tmp,dst=Dst}],
true};
false ->
{[I], false}
end.
+is_float_temp(#x86_temp{type=Type}) -> Type =:= double;
+is_float_temp(#x86_mem{}) -> false.
+
%%% Check if an operand denotes a memory cell (mem or pseudo).
is_mem_opnd(Opnd, TempMap) ->
R =
case Opnd of
#x86_mem{} -> true;
- #x86_temp{} ->
+ #x86_temp{type=double} ->
Reg = hipe_x86:temp_reg(Opnd),
case hipe_x86:temp_is_allocatable(Opnd) of
true ->
@@ -176,6 +183,9 @@ clone(Dst) ->
#x86_mem{} -> hipe_x86:mem_type(Dst);
#x86_temp{} -> hipe_x86:temp_type(Dst)
end,
+ spill_temp(Type).
+
+spill_temp(Type) ->
hipe_x86:mk_new_temp(Type).
%%% Make a certain reg into a clone of Dst
diff --git a/lib/hipe/arm/hipe_arm_registers.erl b/lib/hipe/arm/hipe_arm_registers.erl
index 24cd929d41..dcf039676b 100644
--- a/lib/hipe/arm/hipe_arm_registers.erl
+++ b/lib/hipe/arm/hipe_arm_registers.erl
@@ -67,6 +67,8 @@
-define(R15, 15).
-define(LAST_PRECOLOURED, 15). % must handle both GPR and FPR ranges
+-define(LR, ?R14).
+
-define(ARG0, ?R1).
-define(ARG1, ?R2).
-define(ARG2, ?R3).
@@ -114,7 +116,7 @@ stack_pointer() -> ?STACK_POINTER.
proc_pointer() -> ?PROC_POINTER.
-lr() -> ?R14.
+lr() -> ?LR.
pc() -> ?R15.
@@ -198,7 +200,9 @@ call_clobbered() -> % does the RA strip the type or not?
].
tailcall_clobbered() -> % tailcall crapola needs one temp
- [{?TEMP1,tagged},{?TEMP1,untagged}].
+ [{?TEMP1,tagged},{?TEMP1,untagged}
+ ,{?LR,tagged},{?LR,untagged}
+ ].
live_at_return() ->
[%%{?LR,untagged},
diff --git a/lib/hipe/arm/hipe_rtl_to_arm.erl b/lib/hipe/arm/hipe_rtl_to_arm.erl
index ad5a559995..93342aba33 100644
--- a/lib/hipe/arm/hipe_rtl_to_arm.erl
+++ b/lib/hipe/arm/hipe_rtl_to_arm.erl
@@ -148,10 +148,11 @@ mk_shift_ir(S, Dst, Src1, ShiftOp, Src2) ->
mk_li(Tmp, Src1,
mk_shift_rr(S, Dst, Tmp, ShiftOp, Src2)).
-mk_shift_ri(S, Dst, Src1, ShiftOp, Src2) when is_integer(Src2) ->
- if Src2 >= 0, Src2 < 32 -> ok;
- true -> io:format("~w: excessive immediate shift ~w\n", [?MODULE,Src2])
- end,
+mk_shift_ri(S, Dst, Src1, ShiftOp, 0)
+ when ShiftOp =:= lsl; ShiftOp =:= lsr; ShiftOp =:= asr ->
+ [hipe_arm:mk_move(S, Dst, Src1)];
+mk_shift_ri(S, Dst, Src1, ShiftOp, Src2)
+ when is_integer(Src2), Src2 > 0, Src2 < 32 ->
Am1 = {Src1,ShiftOp,Src2},
[hipe_arm:mk_move(S, Dst, Am1)].
diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl
index 9453ca6c6f..230fce2e68 100644
--- a/lib/hipe/cerl/erl_bif_types.erl
+++ b/lib/hipe/cerl/erl_bif_types.erl
@@ -124,7 +124,7 @@
t_map_entries/2,
t_map_put/3,
t_map_update/3,
- map_pairwise_merge/3
+ t_map_pairwise_merge/4
]).
-ifdef(DO_ERL_BIF_TYPES_TEST).
@@ -1689,10 +1689,10 @@ type(maps, merge, 2, Xs, Opaques) ->
BDefK = t_map_def_key(MapB, Opaques),
ADefV = t_map_def_val(MapA, Opaques),
BDefV = t_map_def_val(MapB, Opaques),
- t_map(map_pairwise_merge(
+ t_map(t_map_pairwise_merge(
fun(K, _, _, mandatory, V) -> {K, mandatory, V};
(K, MNess, VA, optional, VB) -> {K, MNess, t_sup(VA,VB)}
- end, MapA, MapB),
+ end, MapA, MapB, Opaques),
t_sup(ADefK, BDefK), t_sup(ADefV, BDefV))
end, Opaques);
type(maps, put, 3, Xs, Opaques) ->
diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl
index 7826dada9d..a5a3e8c136 100644
--- a/lib/hipe/cerl/erl_types.erl
+++ b/lib/hipe/cerl/erl_types.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -159,6 +159,7 @@
t_map_get/2, t_map_get/3,
t_map_is_key/2, t_map_is_key/3,
t_map_update/2, t_map_update/3,
+ t_map_pairwise_merge/4,
t_map_put/2, t_map_put/3,
t_matchstate/0,
t_matchstate/2,
@@ -219,8 +220,7 @@
is_erl_type/1,
atom_to_string/1,
var_table__new/0,
- cache__new/0,
- map_pairwise_merge/3
+ cache__new/0
]).
%%-define(DO_ERL_TYPES_TEST, true).
@@ -236,7 +236,8 @@
-export([t_is_identifier/1]).
-endif.
--export_type([erl_type/0, opaques/0, type_table/0, var_table/0, cache/0]).
+-export_type([erl_type/0, opaques/0, type_table/0, mod_records/0,
+ var_table/0, cache/0]).
%%-define(DEBUG, true).
@@ -379,8 +380,9 @@
-type type_value() :: {{module(), {file:name(), erl_anno:line()},
erl_parse:abstract_type(), ArgNames :: [atom()]},
erl_type()}.
--type type_table() :: dict:dict(record_key() | type_key(),
- record_value() | type_value()).
+-type type_table() :: #{record_key() | type_key() =>
+ record_value() | type_value()}.
+-type mod_records() :: dict:dict(module(), type_table()).
-opaque var_table() :: #{atom() => erl_type()}.
@@ -494,9 +496,9 @@ t_contains_opaque(?function(Domain, Range), Opaques) ->
t_contains_opaque(Domain, Opaques)
orelse t_contains_opaque(Range, Opaques);
t_contains_opaque(?identifier(_Types), _Opaques) -> false;
-t_contains_opaque(?integer(_Types), _Opaques) -> false;
t_contains_opaque(?int_range(_From, _To), _Opaques) -> false;
t_contains_opaque(?int_set(_Set), _Opaques) -> false;
+t_contains_opaque(?integer(_Types), _Opaques) -> false;
t_contains_opaque(?list(Type, Tail, _), Opaques) ->
t_contains_opaque(Type, Opaques) orelse t_contains_opaque(Tail, Opaques);
t_contains_opaque(?map(_, _, _) = Map, Opaques) ->
@@ -524,7 +526,8 @@ list_contains_opaque(List, Opaques) ->
lists:any(fun(E) -> t_contains_opaque(E, Opaques) end, List).
%% t_find_opaque_mismatch/2 of two types should only be used if their
-%% t_inf is t_none() due to some opaque type violation.
+%% t_inf is t_none() due to some opaque type violation. However,
+%% 'error' is returned if a structure mismatch is found.
%%
%% The first argument of the function is the pattern and its second
%% argument the type we are matching against the pattern.
@@ -533,22 +536,30 @@ list_contains_opaque(List, Opaques) ->
'error' | {'ok', erl_type(), erl_type()}.
t_find_opaque_mismatch(T1, T2, Opaques) ->
- t_find_opaque_mismatch(T1, T2, T2, Opaques).
+ catch t_find_opaque_mismatch(T1, T2, T2, Opaques).
t_find_opaque_mismatch(?any, _Type, _TopType, _Opaques) -> error;
-t_find_opaque_mismatch(?none, _Type, _TopType, _Opaques) -> error;
+t_find_opaque_mismatch(?none, _Type, _TopType, _Opaques) -> throw(error);
t_find_opaque_mismatch(?list(T1, Tl1, _), ?list(T2, Tl2, _), TopType, Opaques) ->
t_find_opaque_mismatch_ordlists([T1, Tl1], [T2, Tl2], TopType, Opaques);
t_find_opaque_mismatch(T1, ?opaque(_) = T2, TopType, Opaques) ->
case is_opaque_type(T2, Opaques) of
- false -> {ok, TopType, T2};
+ false ->
+ case t_is_opaque(T1) andalso compatible_opaque_types(T1, T2) =/= [] of
+ true -> error;
+ false -> {ok, TopType, T2}
+ end;
true ->
t_find_opaque_mismatch(T1, t_opaque_structure(T2), TopType, Opaques)
end;
t_find_opaque_mismatch(?opaque(_) = T1, T2, TopType, Opaques) ->
%% The generated message is somewhat misleading:
case is_opaque_type(T1, Opaques) of
- false -> {ok, TopType, T1};
+ false ->
+ case t_is_opaque(T2) andalso compatible_opaque_types(T1, T2) =/= [] of
+ true -> error;
+ false -> {ok, TopType, T1}
+ end;
true ->
t_find_opaque_mismatch(t_opaque_structure(T1), T2, TopType, Opaques)
end;
@@ -564,7 +575,11 @@ t_find_opaque_mismatch(?tuple(_, _, _) = T1, ?tuple_set(_) = T2,
t_find_opaque_mismatch_lists(Tuples1, Tuples2, TopType, Opaques);
t_find_opaque_mismatch(T1, ?union(U2), TopType, Opaques) ->
t_find_opaque_mismatch_lists([T1], U2, TopType, Opaques);
-t_find_opaque_mismatch(_T1, _T2, _TopType, _Opaques) -> error.
+t_find_opaque_mismatch(T1, T2, _TopType, Opaques) ->
+ case t_is_none(t_inf(T1, T2, Opaques)) of
+ false -> error;
+ true -> throw(error)
+ end.
t_find_opaque_mismatch_ordlists(L1, L2, TopType, Opaques) ->
List = lists:zipwith(fun(T1, T2) ->
@@ -573,10 +588,11 @@ t_find_opaque_mismatch_ordlists(L1, L2, TopType, Opaques) ->
t_find_opaque_mismatch_list(List).
t_find_opaque_mismatch_lists(L1, L2, _TopType, Opaques) ->
- List = [t_find_opaque_mismatch(T1, T2, T2, Opaques) || T1 <- L1, T2 <- L2],
+ List = [catch t_find_opaque_mismatch(T1, T2, T2, Opaques) ||
+ T1 <- L1, T2 <- L2],
t_find_opaque_mismatch_list(List).
-t_find_opaque_mismatch_list([]) -> error;
+t_find_opaque_mismatch_list([]) -> throw(error);
t_find_opaque_mismatch_list([H|T]) ->
case H of
{ok, _T1, _T2} -> H;
@@ -611,9 +627,13 @@ t_decorate_with_opaque(T1, T2, Opaques) ->
false -> T1;
true ->
R = decorate(T1, T, Opaques),
- ?debug(case catch t_is_equal(t_unopaque(R), t_unopaque(T1)) of
- true -> ok;
- false ->
+ ?debug(case catch
+ not t_is_equal(t_unopaque(R), t_unopaque(T1))
+ orelse
+ t_is_equal(T1, T) andalso not t_is_equal(T1, R)
+ of
+ false -> ok;
+ _ ->
io:format("T1 = ~p,\n", [T1]),
io:format("T2 = ~p,\n", [T2]),
io:format("O = ~p,\n", [Opaques]),
@@ -642,7 +662,6 @@ decorate(?tuple_set(List), ?tuple_set(L), Opaques) ->
decorate(?union(List), T, Opaques) when T =/= ?any ->
?union(L) = force_union(T),
union_decorate(List, L, Opaques);
-decorate(?opaque(_)=T, _, _Opaques) -> T;
decorate(T, ?union(L), Opaques) when T =/= ?any ->
?union(List) = force_union(T),
union_decorate(List, L, Opaques);
@@ -656,7 +675,7 @@ decorate_with_opaque(Type, ?opaque(Set2), Opaques) ->
case decoration(set_to_list(Set2), Type, Opaques, [], false) of
{[], false} -> Type;
{List, All} when List =/= [] ->
- NewType = ?opaque(ordsets:from_list(List)),
+ NewType = sup_opaque(List),
case All of
true -> NewType;
false -> t_sup(NewType, Type)
@@ -670,9 +689,10 @@ decoration([#opaque{struct = S} = Opaque|OpaqueTypes], Type, Opaques,
case not IsOpaque orelse t_is_none(I) of
true -> decoration(OpaqueTypes, Type, Opaques, NewOpaqueTypes0, All);
false ->
- NewOpaque = Opaque#opaque{struct = decorate(I, S, Opaques)},
+ NewI = decorate(I, S, Opaques),
+ NewOpaque = combine(NewI, [Opaque]),
NewAll = All orelse t_is_equal(I, Type),
- NewOpaqueTypes = [NewOpaque|NewOpaqueTypes0],
+ NewOpaqueTypes = NewOpaque ++ NewOpaqueTypes0,
decoration(OpaqueTypes, Type, Opaques, NewOpaqueTypes, NewAll)
end;
decoration([], _Type, _Opaques, NewOpaqueTypes, All) ->
@@ -745,16 +765,16 @@ decorate_tuples_in_sets([], _L, _Opaques, Acc) ->
-spec t_opaque_from_records(type_table()) -> [erl_type()].
-t_opaque_from_records(RecDict) ->
- OpaqueRecDict =
- dict:filter(fun(Key, _Value) ->
+t_opaque_from_records(RecMap) ->
+ OpaqueRecMap =
+ maps:filter(fun(Key, _Value) ->
case Key of
{opaque, _Name, _Arity} -> true;
_ -> false
end
- end, RecDict),
- OpaqueTypeDict =
- dict:map(fun({opaque, Name, _Arity},
+ end, RecMap),
+ OpaqueTypeMap =
+ maps:map(fun({opaque, Name, _Arity},
{{Module, _FileLine, _Form, ArgNames}, _Type}) ->
%% Args = args_to_types(ArgNames),
%% List = lists:zip(ArgNames, Args),
@@ -763,8 +783,8 @@ t_opaque_from_records(RecDict) ->
Rep = t_any(), % not used for anything right now
Args = [t_any() || _ <- ArgNames],
t_opaque(Module, Name, Args, Rep)
- end, OpaqueRecDict),
- [OpaqueType || {_Key, OpaqueType} <- dict:to_list(OpaqueTypeDict)].
+ end, OpaqueRecMap),
+ [OpaqueType || {_Key, OpaqueType} <- maps:to_list(OpaqueTypeMap)].
%% Decompose opaque instances of type arg2 to structured types, in arg1
%% XXX: Same as t_unopaque
@@ -798,10 +818,6 @@ list_struct_from_opaque(Types, Opaques) ->
[t_struct_from_opaque(Type, Opaques) || Type <- Types].
%%-----------------------------------------------------------------------------
-
--type mod_records() :: dict:dict(module(), type_table()).
-
-%%-----------------------------------------------------------------------------
%% Unit type. Signals non termination.
%%
@@ -1664,10 +1680,12 @@ t_map(Pairs0, DefK0, DefV0) ->
%% define(DEBUG, true).
try
validate_map_elements(Pairs)
- catch error:badarg -> error(badarg, [Pairs0,DefK0,DefV0]);
- error:{badarg, E} -> error({badarg, E}, [Pairs0,DefK0,DefV0])
+ catch error:badarg -> error(badarg, [Pairs0,DefK0,DefV0])
end,
- ?map(Pairs, DefK, DefV).
+ case map_pairs_are_none(Pairs) of
+ true -> ?none;
+ false -> ?map(Pairs, DefK, DefV)
+ end.
normalise_map_optionals([], _, _) -> [];
normalise_map_optionals([E={K,?opt,?none}|T], DefK, DefV) ->
@@ -1684,7 +1702,6 @@ normalise_map_optionals([E={K,?opt,V}|T], DefK, DefV) ->
normalise_map_optionals([E|T], DefK, DefV) ->
[E|normalise_map_optionals(T, DefK, DefV)].
-validate_map_elements([{_,?mand,?none}|_]) -> error({badarg, none_in_mand});
validate_map_elements([{K1,_,_}|Rest=[{K2,_,_}|_]]) ->
case is_singleton_type(K1) andalso K1 < K2 of
false -> error(badarg);
@@ -1697,6 +1714,10 @@ validate_map_elements([{K,_,_}]) ->
end;
validate_map_elements([]) -> true.
+map_pairs_are_none([]) -> false;
+map_pairs_are_none([{_,?mand,?none}|_]) -> true;
+map_pairs_are_none([_|Ps]) -> map_pairs_are_none(Ps).
+
-spec t_is_map(erl_type()) -> boolean().
t_is_map(Type) ->
@@ -1763,13 +1784,26 @@ mapdict_insert(E1={K1,_,_}, [E2={K2,_,_}|T]) when K1 > K2 ->
[E2|mapdict_insert(E1, T)];
mapdict_insert(E={_,_,_}, T) -> [E|T].
+-type map_pairwise_merge_fun() :: fun((erl_type(),
+ t_map_mandatoriness(), erl_type(),
+ t_map_mandatoriness(), erl_type())
+ -> t_map_pair() | false).
+
+-spec t_map_pairwise_merge(map_pairwise_merge_fun(), erl_type(), erl_type(),
+ opaques()) -> t_map_dict().
+t_map_pairwise_merge(F, MapA, MapB, Opaques) ->
+ do_opaque(MapA, Opaques,
+ fun(UMapA) ->
+ do_opaque(MapB, Opaques,
+ fun(UMapB) ->
+ map_pairwise_merge(F, UMapA, UMapB)
+ end)
+ end).
+
%% Merges the pairs of two maps together. Missing pairs become (?opt, DefV) or
%% (?opt, ?none), depending on whether K \in DefK.
--spec map_pairwise_merge(fun((erl_type(),
- t_map_mandatoriness(), erl_type(),
- t_map_mandatoriness(), erl_type())
- -> t_map_pair() | false),
- erl_type(), erl_type()) -> t_map_dict().
+-spec map_pairwise_merge(map_pairwise_merge_fun(), erl_type(), erl_type())
+ -> t_map_dict().
map_pairwise_merge(F, ?map(APairs, ADefK, ADefV),
?map(BPairs, BDefK, BDefV)) ->
map_pairwise_merge(F, APairs, ADefK, ADefV, BPairs, BDefK, BDefV).
@@ -2223,16 +2257,21 @@ t_has_var_list([]) -> false.
-spec t_collect_vars(erl_type()) -> [erl_type()].
t_collect_vars(T) ->
- t_collect_vars(T, []).
+ Vs = t_collect_vars(T, maps:new()),
+ [V || {V, _} <- maps:to_list(Vs)].
+
+-type ctab() :: #{erl_type() => 'any'}.
--spec t_collect_vars(erl_type(), [erl_type()]) -> [erl_type()].
+-spec t_collect_vars(erl_type(), ctab()) -> ctab().
t_collect_vars(?var(_) = Var, Acc) ->
- ordsets:add_element(Var, Acc);
+ maps:put(Var, any, Acc);
t_collect_vars(?function(Domain, Range), Acc) ->
- ordsets:union(t_collect_vars(Domain, Acc), t_collect_vars(Range, []));
+ Acc1 = t_collect_vars(Domain, Acc),
+ t_collect_vars(Range, Acc1);
t_collect_vars(?list(Contents, Termination, _), Acc) ->
- ordsets:union(t_collect_vars(Contents, Acc), t_collect_vars(Termination, []));
+ Acc1 = t_collect_vars(Contents, Acc),
+ t_collect_vars(Termination, Acc1);
t_collect_vars(?product(Types), Acc) ->
t_collect_vars_list(Types, Acc);
t_collect_vars(?tuple(?any, ?any, ?any), Acc) ->
@@ -2833,12 +2872,7 @@ t_inf(?map(_, ADefK, ADefV) = A, ?map(_, BDefK, BDefV) = B, _Opaques) ->
%% becomes mandatory in the infinumum
(K, _, V1, _, V2) -> {K, ?mand, t_inf(V1, V2)}
end, A, B),
- %% If the infinimum of any mandatory values is ?none, the entire map infinimum
- %% is ?none.
- case lists:any(fun({_,?mand,?none})->true; ({_,_,_}) -> false end, Pairs) of
- true -> t_none();
- false -> t_map(Pairs, t_inf(ADefK, BDefK), t_inf(ADefV, BDefV))
- end;
+ t_map(Pairs, t_inf(ADefK, BDefK), t_inf(ADefV, BDefV));
t_inf(?matchstate(Pres1, Slots1), ?matchstate(Pres2, Slots2), _Opaques) ->
?matchstate(t_inf(Pres1, Pres2), t_inf(Slots1, Slots2));
t_inf(?nil, ?nil, _Opaques) -> ?nil;
@@ -2978,27 +3012,21 @@ inf_collect(_T1, [], _Opaques, OpL) ->
OpL.
combine(S, T1, T2) ->
- #opaque{mod = Mod1, name = Name1, args = Args1} = T1,
- #opaque{mod = Mod2, name = Name2, args = Args2} = T2,
- Comb1 = comb(Mod1, Name1, Args1, S, T1),
- case is_compat_opaque_names({Mod1, Name1, Args1}, {Mod2, Name2, Args2}) of
- true -> Comb1;
- false -> Comb1 ++ comb(Mod2, Name2, Args2, S, T2)
+ case is_compat_opaque_names(T1, T2) of
+ true -> combine(S, [T1]);
+ false -> combine(S, [T1, T2])
end.
-comb(Mod, Name, Args, S, T) ->
- case can_combine_opaque_names(Mod, Name, Args, S) of
- true ->
- ?opaque(Set) = S,
- Set;
- false ->
- [T#opaque{struct = S}]
- end.
+combine(?opaque(Set), Ts) ->
+ [comb2(O, T) || O <- Set, T <- Ts];
+combine(S, Ts) ->
+ [T#opaque{struct = S} || T <- Ts].
-can_combine_opaque_names(Mod1, Name1, Args1,
- ?opaque([#opaque{mod = Mod2, name = Name2, args = Args2}])) ->
- is_compat_opaque_names({Mod1, Name1, Args1}, {Mod2, Name2, Args2});
-can_combine_opaque_names(_, _, _, _) -> false.
+comb2(O, T) ->
+ case is_compat_opaque_names(O, T) of
+ true -> O;
+ false -> T#opaque{struct = ?opaque(set_singleton(O))}
+ end.
%% Combining two lists this way can be very time consuming...
%% Note: two parameterized opaque types are not the same if their
@@ -3007,32 +3035,27 @@ inf_opaque(Set1, Set2, Opaques) ->
List1 = inf_look_up(Set1, Opaques),
List2 = inf_look_up(Set2, Opaques),
List0 = [combine(Inf, T1, T2) ||
- {Is1, ModNameArgs1, T1} <- List1,
- {Is2, ModNameArgs2, T2} <- List2,
- not t_is_none(Inf = inf_opaque_types(Is1, ModNameArgs1, T1,
- Is2, ModNameArgs2, T2,
- Opaques))],
- List = lists:sort(lists:append(List0)),
+ {Is1, T1} <- List1,
+ {Is2, T2} <- List2,
+ not t_is_none(Inf = inf_opaque_types(Is1, T1, Is2, T2, Opaques))],
+ List = lists:append(List0),
sup_opaque(List).
%% Optimization: do just one lookup.
inf_look_up(Set, Opaques) ->
- [{Opaques =:= 'universe' orelse inf_is_opaque_type2(T, Opaques),
- {M, N, Args}, T} ||
- #opaque{mod = M, name = N, args = Args} = T <- set_to_list(Set)].
+ [{Opaques =:= 'universe' orelse inf_is_opaque_type2(T, Opaques), T} ||
+ T <- set_to_list(Set)].
inf_is_opaque_type2(T, {match, Opaques}) ->
is_opaque_type2(T, Opaques);
inf_is_opaque_type2(T, Opaques) ->
is_opaque_type2(T, Opaques).
-inf_opaque_types(IsOpaque1, ModNameArgs1, T1,
- IsOpaque2, ModNameArgs2, T2, Opaques) ->
+inf_opaque_types(IsOpaque1, T1, IsOpaque2, T2, Opaques) ->
#opaque{struct = S1}=T1,
#opaque{struct = S2}=T2,
case
- Opaques =:= 'universe' orelse
- is_compat_opaque_names(ModNameArgs1, ModNameArgs2)
+ Opaques =:= 'universe' orelse is_compat_opaque_names(T1, T2)
of
true -> t_inf(S1, S2, Opaques);
false ->
@@ -3046,98 +3069,109 @@ inf_opaque_types(IsOpaque1, ModNameArgs1, T1,
end
end.
-is_compat_opaque_names(ModNameArgs, ModNameArgs) -> true;
-is_compat_opaque_names({Mod,Name,Args1}, {Mod,Name,Args2}) ->
- is_compat_args(Args1, Args2);
-is_compat_opaque_names(_, _) -> false.
+compatible_opaque_types(?opaque(Es1), ?opaque(Es2)) ->
+ [{O1, O2} || O1 <- Es1, O2 <- Es2, is_compat_opaque_names(O1, O2)].
+
+is_compat_opaque_names(Opaque1, Opaque2) ->
+ #opaque{mod = Mod1, name = Name1, args = Args1} = Opaque1,
+ #opaque{mod = Mod2, name = Name2, args = Args2} = Opaque2,
+ case {{Mod1, Name1, Args1}, {Mod2, Name2, Args2}} of
+ {ModNameArgs, ModNameArgs} -> true;
+ {{Mod, Name, Args1}, {Mod, Name, Args2}} ->
+ is_compat_args(Args1, Args2);
+ _ -> false
+ end.
is_compat_args([A1|Args1], [A2|Args2]) ->
is_compat_arg(A1, A2) andalso is_compat_args(Args1, Args2);
is_compat_args([], []) -> true;
is_compat_args(_, _) -> false.
-is_compat_arg(A1, A2) ->
- is_specialization(A1, A2) orelse is_specialization(A2, A1).
-
--spec is_specialization(erl_type(), erl_type()) -> boolean().
-
-%% Returns true if the first argument is a specialization of the
-%% second argument in the sense that every type is a specialization of
-%% any(). For example, {_,_} is a specialization of any(), but not of
-%% tuple(). Does not handle variables, but any() and unions (sort of).
-
-is_specialization(T, T) -> true;
-is_specialization(_, ?any) -> true;
-is_specialization(?any, _) -> false;
-is_specialization(?function(Domain1, Range1), ?function(Domain2, Range2)) ->
- (is_specialization(Domain1, Domain2) andalso
- is_specialization(Range1, Range2));
-is_specialization(?list(Contents1, Termination1, Size1),
- ?list(Contents2, Termination2, Size2)) ->
+-spec is_compat_arg(erl_type(), erl_type()) -> boolean().
+
+%% The intention is that 'true' is to be returned iff one of the
+%% arguments is a specialization of the other argument in the sense
+%% that every type is a specialization of any(). For example, {_,_} is
+%% a specialization of any(), but not of tuple(). Does not handle
+%% variables, but any() and unions (sort of). However, the
+%% implementation is more relaxed as any() is compatible to anything.
+
+is_compat_arg(T, T) -> true;
+is_compat_arg(_, ?any) -> true;
+is_compat_arg(?any, _) -> true;
+is_compat_arg(?function(Domain1, Range1), ?function(Domain2, Range2)) ->
+ (is_compat_arg(Domain1, Domain2) andalso
+ is_compat_arg(Range1, Range2));
+is_compat_arg(?list(Contents1, Termination1, Size1),
+ ?list(Contents2, Termination2, Size2)) ->
(Size1 =:= Size2 andalso
- is_specialization(Contents1, Contents2) andalso
- is_specialization(Termination1, Termination2));
-is_specialization(?product(Types1), ?product(Types2)) ->
- specialization_list(Types1, Types2);
-is_specialization(?tuple(?any, ?any, ?any), ?tuple(_, _, _)) -> false;
-is_specialization(?tuple(_, _, _), ?tuple(?any, ?any, ?any)) -> false;
-is_specialization(?tuple(Elements1, Arity, _),
- ?tuple(Elements2, Arity, _)) when Arity =/= ?any ->
- specialization_list(Elements1, Elements2);
-is_specialization(?tuple_set([{Arity, List}]),
- ?tuple(Elements2, Arity, _)) when Arity =/= ?any ->
- specialization_list(sup_tuple_elements(List), Elements2);
-is_specialization(?tuple(Elements1, Arity, _),
- ?tuple_set([{Arity, List}])) when Arity =/= ?any ->
- specialization_list(Elements1, sup_tuple_elements(List));
-is_specialization(?tuple_set(List1), ?tuple_set(List2)) ->
+ is_compat_arg(Contents1, Contents2) andalso
+ is_compat_arg(Termination1, Termination2));
+is_compat_arg(?product(Types1), ?product(Types2)) ->
+ is_compat_list(Types1, Types2);
+is_compat_arg(?map(Pairs1, DefK1, DefV1), ?map(Pairs2, DefK2, DefV2)) ->
+ (is_compat_list(Pairs1, Pairs2) andalso
+ is_compat_arg(DefK1, DefK2) andalso
+ is_compat_arg(DefV1, DefV2));
+is_compat_arg(?tuple(?any, ?any, ?any), ?tuple(_, _, _)) -> false;
+is_compat_arg(?tuple(_, _, _), ?tuple(?any, ?any, ?any)) -> false;
+is_compat_arg(?tuple(Elements1, Arity, _),
+ ?tuple(Elements2, Arity, _)) when Arity =/= ?any ->
+ is_compat_list(Elements1, Elements2);
+is_compat_arg(?tuple_set([{Arity, List}]),
+ ?tuple(Elements2, Arity, _)) when Arity =/= ?any ->
+ is_compat_list(sup_tuple_elements(List), Elements2);
+is_compat_arg(?tuple(Elements1, Arity, _),
+ ?tuple_set([{Arity, List}])) when Arity =/= ?any ->
+ is_compat_list(Elements1, sup_tuple_elements(List));
+is_compat_arg(?tuple_set(List1), ?tuple_set(List2)) ->
try
- specialization_list_list([sup_tuple_elements(T) || {_Arity, T} <- List1],
- [sup_tuple_elements(T) || {_Arity, T} <- List2])
+ is_compat_list_list([sup_tuple_elements(T) || {_Arity, T} <- List1],
+ [sup_tuple_elements(T) || {_Arity, T} <- List2])
catch _:_ -> false
end;
-is_specialization(?union(List1)=T1, ?union(List2)=T2) ->
- case specialization_union2(T1, T2) of
- {yes, Type1, Type2} -> is_specialization(Type1, Type2);
- no -> specialization_list(List1, List2)
+is_compat_arg(?opaque(_) = T1, T2) ->
+ is_compat_arg(t_opaque_structure(T1), T2);
+is_compat_arg(T1, ?opaque(_) = T2) ->
+ is_compat_arg(T1, t_opaque_structure(T2));
+is_compat_arg(?union(List1)=T1, ?union(List2)=T2) ->
+ case is_compat_union2(T1, T2) of
+ {yes, Type1, Type2} -> is_compat_arg(Type1, Type2);
+ no -> is_compat_list(List1, List2)
end;
-is_specialization(?union(List), T2) ->
+is_compat_arg(?union(List), T2) ->
case unify_union(List) of
- {yes, Type} -> is_specialization(Type, T2);
+ {yes, Type} -> is_compat_arg(Type, T2);
no -> false
end;
-is_specialization(T1, ?union(List)) ->
+is_compat_arg(T1, ?union(List)) ->
case unify_union(List) of
- {yes, Type} -> is_specialization(T1, Type);
+ {yes, Type} -> is_compat_arg(T1, Type);
no -> false
end;
-is_specialization(?opaque(_) = T1, T2) ->
- is_specialization(t_opaque_structure(T1), T2);
-is_specialization(T1, ?opaque(_) = T2) ->
- is_specialization(T1, t_opaque_structure(T2));
-is_specialization(?var(_), _) -> exit(error);
-is_specialization(_, ?var(_)) -> exit(error);
-is_specialization(?none, _) -> false;
-is_specialization(_, ?none) -> false;
-is_specialization(?unit, _) -> false;
-is_specialization(_, ?unit) -> false;
-is_specialization(#c{}, #c{}) -> false.
-
-specialization_list_list(LL1, LL2) ->
- length(LL1) =:= length(LL2) andalso specialization_list_list1(LL1, LL2).
-
-specialization_list_list1([], []) -> true;
-specialization_list_list1([L1|LL1], [L2|LL2]) ->
- specialization_list(L1, L2) andalso specialization_list_list1(LL1, LL2).
-
-specialization_list(L1, L2) ->
- length(L1) =:= length(L2) andalso specialization_list1(L1, L2).
-
-specialization_list1([], []) -> true;
-specialization_list1([T1|L1], [T2|L2]) ->
- is_specialization(T1, T2) andalso specialization_list1(L1, L2).
-
-specialization_union2(?union(List1)=T1, ?union(List2)=T2) ->
+is_compat_arg(?var(_), _) -> exit(error);
+is_compat_arg(_, ?var(_)) -> exit(error);
+is_compat_arg(?none, _) -> false;
+is_compat_arg(_, ?none) -> false;
+is_compat_arg(?unit, _) -> false;
+is_compat_arg(_, ?unit) -> false;
+is_compat_arg(#c{}, #c{}) -> false.
+
+is_compat_list_list(LL1, LL2) ->
+ length(LL1) =:= length(LL2) andalso is_compat_list_list1(LL1, LL2).
+
+is_compat_list_list1([], []) -> true;
+is_compat_list_list1([L1|LL1], [L2|LL2]) ->
+ is_compat_list(L1, L2) andalso is_compat_list_list1(LL1, LL2).
+
+is_compat_list(L1, L2) ->
+ length(L1) =:= length(L2) andalso is_compat_list1(L1, L2).
+
+is_compat_list1([], []) -> true;
+is_compat_list1([T1|L1], [T2|L2]) ->
+ is_compat_arg(T1, T2) andalso is_compat_list1(L1, L2).
+
+is_compat_union2(?union(List1)=T1, ?union(List2)=T2) ->
case {unify_union(List1), unify_union(List2)} of
{{yes, Type1}, {yes, Type2}} -> {yes, Type1, Type2};
{{yes, Type1}, no} -> {yes, Type1, T2};
@@ -4170,7 +4204,7 @@ t_map(Fun, T) ->
-spec t_to_string(erl_type()) -> string().
t_to_string(T) ->
- t_to_string(T, dict:new()).
+ t_to_string(T, maps:new()).
-spec t_to_string(erl_type(), type_table()) -> string().
@@ -4366,7 +4400,7 @@ record_field_diffs_to_string(?tuple([_|Fs], Arity, Tag), RecDict) ->
string:join(FieldDiffs, " and ").
field_diffs([F|Fs], [{FName, _Abstr, DefType}|FDefs], RecDict, Acc) ->
- %% Don't care about opaqueness for now.
+ %% Don't care about opacity for now.
NewAcc =
case not t_is_none(t_inf(F, DefType)) of
true -> Acc;
@@ -4469,28 +4503,31 @@ t_from_form1(Form, ET, Site, MR, V, C) ->
vtab = V,
tnames = TypeNames},
L = ?EXPAND_LIMIT,
- {T1, L1, C1} = from_form(Form, State, ?EXPAND_DEPTH, L, C),
+ {T0, L0, C0} = from_form(Form, State, ?EXPAND_DEPTH, L, C),
if
- L1 =< 0 ->
- from_form_loop(Form, State, 1, L, C1);
+ L0 =< 0 ->
+ {T1, _, C1} = from_form(Form, State, 1, L, C0),
+ from_form_loop(Form, State, 2, L, C1, T1);
true ->
- {T1, C1}
+ {T0, C0}
end.
initial_typenames({type, _MTA}=Site) -> [Site];
initial_typenames({spec, _MFA}) -> [];
initial_typenames({record, _MRA}) -> [].
-from_form_loop(Form, State, D, Limit, C) ->
+from_form_loop(Form, State, D, Limit, C, T0) ->
{T1, L1, C1} = from_form(Form, State, D, Limit, C),
Delta = Limit - L1,
if
- %% Save some time by assuming next depth will exceed the limit.
+ L1 =< 0 ->
+ {T0, C1};
Delta * 8 > Limit ->
+ %% Save some time by assuming next depth will exceed the limit.
{T1, C1};
true ->
D1 = D + 1,
- from_form_loop(Form, State, D1, Limit, C1)
+ from_form_loop(Form, State, D1, Limit, C1, T1)
end.
-spec from_form(parse_form(),
@@ -4528,6 +4565,8 @@ from_form({atom, _L, Atom}, _S, _D, L, C) ->
{t_atom(Atom), L, C};
from_form({integer, _L, Int}, _S, _D, L, C) ->
{t_integer(Int), L, C};
+from_form({char, _L, Char}, _S, _D, L, C) ->
+ {t_integer(Char), L, C};
from_form({op, _L, _Op, _Arg} = Op, _S, _D, L, C) ->
case erl_eval:partial_eval(Op) of
{integer, _, Val} ->
@@ -4749,7 +4788,7 @@ type_from_form1(Name, Args, ArgsLen, R, TypeName, TypeNames, S, D, L, C) ->
{Rep, L2, C2} = recur_limit(Fun, D, L1, TypeName, TypeNames),
Rep1 = choose_opaque_type(Rep, Type),
Rep2 = case cannot_have_opaque(Rep1, TypeName, TypeNames) of
- true -> Rep1;
+ true -> Rep;
false ->
ArgTypes2 = subst_all_vars_to_any_list(ArgTypes),
t_opaque(Module, Name, ArgTypes2, Rep1)
@@ -4821,7 +4860,7 @@ remote_from_form1(RemMod, Name, Args, ArgsLen, RemDict, RemType, TypeNames,
NewRep1 = choose_opaque_type(NewRep, Type),
NewRep2 =
case cannot_have_opaque(NewRep1, RemType, TypeNames) of
- true -> NewRep1;
+ true -> NewRep;
false ->
ArgTypes2 = subst_all_vars_to_any_list(ArgTypes),
t_opaque(Mod, Name, ArgTypes2, NewRep1)
@@ -5042,6 +5081,7 @@ check_record_fields({remote_type, _L, [{atom, _, _}, {atom, _, _}, Args]},
list_check_record_fields(Args, S, C);
check_record_fields({atom, _L, _}, _S, C) -> C;
check_record_fields({integer, _L, _}, _S, C) -> C;
+check_record_fields({char, _L, _}, _S, C) -> C;
check_record_fields({op, _L, _Op, _Arg}, _S, C) -> C;
check_record_fields({op, _L, _Op, _Arg1, _Arg2}, _S, C) -> C;
check_record_fields({type, _L, tuple, any}, _S, C) -> C;
@@ -5143,6 +5183,7 @@ t_form_to_string({var, _L, Name}) -> atom_to_list(Name);
t_form_to_string({atom, _L, Atom}) ->
io_lib:write_string(atom_to_list(Atom), $'); % To quote or not to quote... '
t_form_to_string({integer, _L, Int}) -> integer_to_list(Int);
+t_form_to_string({char, _L, Char}) -> integer_to_list(Char);
t_form_to_string({op, _L, _Op, _Arg} = Op) ->
case erl_eval:partial_eval(Op) of
{integer, _, _} = Int -> t_form_to_string(Int);
@@ -5225,7 +5266,7 @@ t_form_to_string({type, _L, union, Args}) ->
t_form_to_string({type, _L, Name, []} = T) ->
try
M = mod,
- D0 = dict:new(),
+ D0 = maps:new(),
MR = dict:from_list([{M, D0}]),
Site = {type, {M,Name,0}},
V = var_table__new(),
@@ -5289,8 +5330,8 @@ is_erl_type(_) -> false.
-spec lookup_record(atom(), type_table()) ->
'error' | {'ok', [{atom(), parse_form(), erl_type()}]}.
-lookup_record(Tag, RecDict) when is_atom(Tag) ->
- case dict:find({record, Tag}, RecDict) of
+lookup_record(Tag, Table) when is_atom(Tag) ->
+ case maps:find({record, Tag}, Table) of
{ok, {_FileLine, [{_Arity, Fields}]}} ->
{ok, Fields};
{ok, {_FileLine, List}} when is_list(List) ->
@@ -5304,18 +5345,18 @@ lookup_record(Tag, RecDict) when is_atom(Tag) ->
-spec lookup_record(atom(), arity(), type_table()) ->
'error' | {'ok', [{atom(), parse_form(), erl_type()}]}.
-lookup_record(Tag, Arity, RecDict) when is_atom(Tag) ->
- case dict:find({record, Tag}, RecDict) of
+lookup_record(Tag, Arity, Table) when is_atom(Tag) ->
+ case maps:find({record, Tag}, Table) of
{ok, {_FileLine, [{Arity, Fields}]}} -> {ok, Fields};
{ok, {_FileLine, OrdDict}} -> orddict:find(Arity, OrdDict);
error -> error
end.
-spec lookup_type(_, _, _) -> {'type' | 'opaque', type_value()} | 'error'.
-lookup_type(Name, Arity, RecDict) ->
- case dict:find({type, Name, Arity}, RecDict) of
+lookup_type(Name, Arity, Table) ->
+ case maps:find({type, Name, Arity}, Table) of
error ->
- case dict:find({opaque, Name, Arity}, RecDict) of
+ case maps:find({opaque, Name, Arity}, Table) of
error -> error;
{ok, Found} -> {opaque, Found}
end;
@@ -5325,8 +5366,8 @@ lookup_type(Name, Arity, RecDict) ->
-spec type_is_defined('type' | 'opaque', atom(), arity(), type_table()) ->
boolean().
-type_is_defined(TypeOrOpaque, Name, Arity, RecDict) ->
- dict:is_key({TypeOrOpaque, Name, Arity}, RecDict).
+type_is_defined(TypeOrOpaque, Name, Arity, Table) ->
+ maps:is_key({TypeOrOpaque, Name, Arity}, Table).
cannot_have_opaque(Type, TypeName, TypeNames) ->
t_is_none(Type) orelse is_recursive(TypeName, TypeNames).
diff --git a/lib/hipe/doc/src/notes.xml b/lib/hipe/doc/src/notes.xml
index e2a1524be6..627794aee8 100644
--- a/lib/hipe/doc/src/notes.xml
+++ b/lib/hipe/doc/src/notes.xml
@@ -31,6 +31,111 @@
</header>
<p>This document describes the changes made to HiPE.</p>
+<section><title>Hipe 3.15.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix a bug concerning parameterized opaque types. </p>
+ <p>
+ Own Id: OTP-14130</p>
+ </item>
+ <item>
+ <p>
+ Fixed xml issues in old release notes</p>
+ <p>
+ Own Id: OTP-14269</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Hipe 3.15.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix flow control bug in hipe compiler that may cause
+ compile time crash.</p>
+ <p>
+ Own Id: OTP-13965 Aux Id: PR-1253 </p>
+ </item>
+ <item>
+ <p>
+ Fix bug in native compilation of bitstring pattern
+ matching causing erroneous runtime matching result. The
+ bug only affects code containing constant-valued segments
+ whose size is expressed in bits; it is triggered when the
+ pattern matching against these segments fails (i.e., when
+ the next clause needs to be tried).</p>
+ <p>
+ Own Id: OTP-14005</p>
+ </item>
+ <item>
+ <p>
+ Workaround in HiPE LLVM backend for a bug in LLVM 3.9.
+ The bug could cause LLVM-compiled modules to be rejected
+ during loading with a badarg exception in
+ hipe_bifs:enter_sdecs/1, but also cause corruption or
+ segmentation faults i runtime.</p>
+ <p>
+ Own Id: OTP-14027 Aux Id: ERL-292, PR-1237 </p>
+ </item>
+ <item>
+ <p>
+ Fix a bug in HiPE LLVM backend involving incorrect type
+ tests of atoms sometimes causing incorrect behaviour or
+ even segfaults.</p>
+ <p>
+ Own Id: OTP-14028 Aux Id: PR-1237 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Hipe 3.15.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed various hipe compiler backend bugs affecting mostly
+ ARM and SPARC.</p>
+ <p>
+ Own Id: OTP-13846 Aux Id: PR-1146 </p>
+ </item>
+ <item>
+ <p>
+ Fixed some Dialyzer warnings and code cleanup for the
+ Sparc compiler backend.</p>
+ <p>
+ Own Id: OTP-13861 Aux Id: PR-1148 </p>
+ </item>
+ <item>
+ <p> Fix erl_bif_types opaque bug. </p>
+ <p>
+ Own Id: OTP-13878 Aux Id: PR-1161, ERL-249 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Fix erl_types opaque match order</p>
+ <p>
+ Own Id: OTP-13876</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Hipe 3.15.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -45,12 +150,12 @@
</item>
<item>
<p>
- Various fixes and improvements to the HiPE LLVM backend.
+ Various fixes and improvements to the HiPE LLVM backend.</p>
<list> <item>Add support for LLVM 3.7 and 3.8 in the
HiPE/LLVM x86_64 backend</item> <item>Reinstate support
for the LLVM backend on x86 (works OK for LLVM 3.5 to 3.7
-- LLVM 3.8 has a bug that prevents it from generating
- correct native code on x86)</item> </list></p>
+ correct native code on x86)</item> </list>
<p>
Own Id: OTP-13626</p>
</item>
@@ -106,7 +211,7 @@
<item>
<p>
Fix various binary construction inconsistencies for hipe
- compiled code. <list> <item>Passing bad field sizes to
+ compiled code.</p> <list> <item>Passing bad field sizes to
binary constructions would throw <c>badarith</c> rather
than <c>badarg</c>. Worse, in guards, when the unit size
of the field was 1, the exception would leak rather than
@@ -126,7 +231,7 @@
missing check for unit size match when inserting a
binary. For example, a faulty expression like
<c>&lt;&lt;&lt;&lt;1:7&gt;&gt;/binary&gt;&gt;</c> would
- succeed.</item> </list></p>
+ succeed.</item> </list>
<p>
Own Id: OTP-13272</p>
</item>
diff --git a/lib/hipe/icode/hipe_beam_to_icode.erl b/lib/hipe/icode/hipe_beam_to_icode.erl
index 224aacd8d7..3386523206 100644
--- a/lib/hipe/icode/hipe_beam_to_icode.erl
+++ b/lib/hipe/icode/hipe_beam_to_icode.erl
@@ -763,32 +763,10 @@ trans_fun([{test,bs_test_unit,{f,Lbl},[Ms,Unit]}|
[MsVar], [], Env, Instructions);
trans_fun([{test,bs_match_string,{f,Lbl},[Ms,BitSize,Bin]}|
Instructions], Env) ->
- True = mk_label(new),
- FalseLabName = map_label(Lbl),
- TrueLabName = hipe_icode:label_name(True),
+ %% the current match buffer
MsVar = mk_var(Ms),
- TmpVar = mk_var(new),
- ByteSize = BitSize div 8,
- ExtraBits = BitSize rem 8,
- WordSize = hipe_rtl_arch:word_size(),
- if ExtraBits =:= 0 ->
- trans_op_call({hipe_bs_primop,{bs_match_string,Bin,ByteSize}}, Lbl,
- [MsVar], [MsVar], Env, Instructions);
- BitSize =< ((WordSize * 8) - 5) ->
- <<Int:BitSize, _/bits>> = Bin,
- {I1,Env1} = trans_one_op_call({hipe_bs_primop,{bs_get_integer,BitSize,0}}, Lbl,
- [MsVar], [TmpVar, MsVar], Env),
- I2 = hipe_icode:mk_type([TmpVar], {integer,Int}, TrueLabName, FalseLabName),
- I1 ++ [I2,True] ++ trans_fun(Instructions, Env1);
- true ->
- <<RealBin:ByteSize/binary, Int:ExtraBits, _/bits>> = Bin,
- {I1,Env1} = trans_one_op_call({hipe_bs_primop,{bs_match_string,RealBin,ByteSize}}, Lbl,
- [MsVar], [MsVar], Env),
- {I2,Env2} = trans_one_op_call({hipe_bs_primop,{bs_get_integer,ExtraBits,0}}, Lbl,
- [MsVar], [TmpVar, MsVar], Env1),
- I3 = hipe_icode:mk_type([TmpVar], {integer,Int}, TrueLabName, FalseLabName),
- I1 ++ I2 ++ [I3,True] ++ trans_fun(Instructions, Env2)
- end;
+ Primop = {hipe_bs_primop, {bs_match_string, Bin, BitSize}},
+ trans_op_call(Primop, Lbl, [MsVar], [MsVar], Env, Instructions);
trans_fun([{bs_context_to_binary,Var}|Instructions], Env) ->
%% the current match buffer
IVars = [trans_arg(Var)],
diff --git a/lib/hipe/icode/hipe_icode.erl b/lib/hipe/icode/hipe_icode.erl
index 78508dff22..13a0bf6141 100644
--- a/lib/hipe/icode/hipe_icode.erl
+++ b/lib/hipe/icode/hipe_icode.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/hipe/icode/hipe_icode_call_elim.erl b/lib/hipe/icode/hipe_icode_call_elim.erl
index 6a22133962..71c709a7d1 100644
--- a/lib/hipe/icode/hipe_icode_call_elim.erl
+++ b/lib/hipe/icode/hipe_icode_call_elim.erl
@@ -46,7 +46,8 @@ cfg(IcodeSSA) ->
-spec elim_insn(icode_instr()) -> icode_instr().
elim_insn(Insn=#icode_call{'fun'={_,_,_}=MFA, args=Args, type=remote,
dstlist=[Dst=#icode_variable{
- annotation={type_anno, RetType, _}}]}) ->
+ annotation={type_anno, RetType, _}}],
+ continuation=[], fail_label=[]}) ->
Opaques = 'universe',
case erl_types:t_is_singleton(RetType, Opaques) of
true ->
diff --git a/lib/hipe/icode/hipe_icode_primops.erl b/lib/hipe/icode/hipe_icode_primops.erl
index cee37b6a57..2a141c514e 100644
--- a/lib/hipe/icode/hipe_icode_primops.erl
+++ b/lib/hipe/icode/hipe_icode_primops.erl
@@ -287,8 +287,8 @@ pp(Dev, Op) ->
io:format(Dev, "bs_start_match<~w>", [Max]);
{{bs_start_match, Type}, Max} ->
io:format(Dev, "bs_start_match<~w,~w>", [Type,Max]);
- {bs_match_string, String, SizeInBytes} ->
- io:format(Dev, "bs_match_string<~w, ~w>", [String, SizeInBytes]);
+ {bs_match_string, String, SizeInBits} ->
+ io:format(Dev, "bs_match_string<~w, ~w>", [String, SizeInBits]);
{bs_get_integer, Size, Flags} ->
io:format(Dev, "bs_get_integer<~w, ~w>", [Size, Flags]);
{bs_get_float, Size, Flags} ->
@@ -596,10 +596,10 @@ type(Primop, Args) ->
erl_types:t_subtract(Type, erl_types:t_matchstate()),
erl_types:t_matchstate_slot(
erl_types:t_inf(Type, erl_types:t_matchstate()), 0));
- {hipe_bs_primop, {bs_match_string,_,Bytes}} ->
+ {hipe_bs_primop, {bs_match_string,_,Bits}} ->
[MatchState] = Args,
BinType = erl_types:t_matchstate_present(MatchState),
- NewBinType = match_bin(erl_types:t_bitstr(0, Bytes*8), BinType),
+ NewBinType = match_bin(erl_types:t_bitstr(0, Bits), BinType),
erl_types:t_matchstate_update_present(NewBinType, MatchState);
{hipe_bs_primop, {bs_test_unit,Unit}} ->
[MatchState] = Args,
diff --git a/lib/hipe/llvm/hipe_llvm_main.erl b/lib/hipe/llvm/hipe_llvm_main.erl
index 476d6fb49c..7f70826046 100644
--- a/lib/hipe/llvm/hipe_llvm_main.erl
+++ b/lib/hipe/llvm/hipe_llvm_main.erl
@@ -84,7 +84,7 @@ compile_with_llvm(FunName, Arity, LLVMCode, Options, UseBuffer) ->
__ = file:close(File_llvm),
%% Invoke LLVM compiler tools to produce an object file
llvm_opt(Dir, Filename, Options),
- llvm_llc(Dir, Filename, Options),
+ llvm_llc(Dir, Filename, Ver, Options),
compile(Dir, Filename, "gcc"), %%FIXME: use llc -filetype=obj and skip this!
{ok, Dir, Dir ++ Filename ++ ".o"}.
@@ -103,12 +103,14 @@ llvm_opt(Dir, Filename, Options) ->
%% @doc Invoke llc tool to compile the bitcode to object file
%% (_name.bc -> _name.o).
-llvm_llc(Dir, Filename, Options) ->
+llvm_llc(Dir, Filename, Ver, Options) ->
Source = Dir ++ Filename ++ ".bc",
OptLevel = trans_optlev_flag(llc, Options),
+ VerFlags = llc_ver_flags(Ver),
Align = find_stack_alignment(),
LlcFlags = [OptLevel, "-code-model=medium", "-stack-alignment=" ++ Align
- , "-tailcallopt", "-filetype=asm"], %%FIXME
+ , "-tailcallopt", "-filetype=asm" %FIXME
+ | VerFlags],
Command = "llc " ++ fix_opts(LlcFlags) ++ " " ++ Source,
%% io:format("LLC: ~s~n", [Command]),
case os:cmd(Command) of
@@ -153,6 +155,12 @@ trans_optlev_flag(Tool, Options) ->
undefined -> "-O2"
end.
+llc_ver_flags(Ver = {_, _}) when Ver >= {3,9} ->
+ %% Works around a bug in the x86-call-frame-opt pass (as of LLVM 3.9) that
+ %% break the garbage collection stack descriptors.
+ ["-no-x86-call-frame-opt"];
+llc_ver_flags({_, _}) -> [].
+
%%------------------------------------------------------------------------------
%% Functions to manage Relocations
%%------------------------------------------------------------------------------
diff --git a/lib/hipe/llvm/hipe_rtl_to_llvm.erl b/lib/hipe/llvm/hipe_rtl_to_llvm.erl
index 66b2e10fb8..2179f7f765 100644
--- a/lib/hipe/llvm/hipe_rtl_to_llvm.erl
+++ b/lib/hipe/llvm/hipe_rtl_to_llvm.erl
@@ -10,7 +10,8 @@
-include("../rtl/hipe_literals.hrl").
-include("hipe_llvm_arch.hrl").
--define(WORD_WIDTH, (?bytes_to_bits(hipe_rtl_arch:word_size()))).
+-define(BITS_IN_WORD, (?bytes_to_bits(hipe_rtl_arch:word_size()))).
+-define(BITS_IN_BYTE, (?bytes_to_bits(1))).
-define(BRANCH_META_TAKEN, "0").
-define(BRANCH_META_NOT_TAKEN, "1").
-define(FIRST_FREE_META_NO, 2).
@@ -95,9 +96,9 @@ do_alloca_stack([], _, _, Acc) ->
Acc;
do_alloca_stack([D|Ds], Params, Roots, Acc) ->
{Name, _I} = trans_dst(D),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
WordTyPtr = hipe_llvm:mk_pointer(WordTy),
- ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(8)),
+ ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(?BITS_IN_BYTE)),
case hipe_rtl:is_var(D) of
true ->
Num = hipe_rtl:var_index(D),
@@ -233,7 +234,7 @@ trans_alu(I, Relocs) ->
{Src1, I1} = trans_src(hipe_rtl:alu_src1(I)),
{Src2, I2} = trans_src(hipe_rtl:alu_src2(I)),
Op = trans_op(hipe_rtl:alu_op(I)),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
I3 = hipe_llvm:mk_operation(TmpDst, Op, WordTy, Src1, Src2, []),
I4 = store_stack_dst(TmpDst, RtlDst),
{[I4, I3, I2, I1], Relocs}.
@@ -258,7 +259,7 @@ trans_alub_overflow(I, Sign, Relocs) ->
TmpDst = mk_temp(),
Name = trans_alub_op(I, Sign),
NewRelocs = relocs_store(Name, {call, {llvm, Name, 2}}, Relocs),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
ReturnType = hipe_llvm:mk_struct([WordTy, hipe_llvm:mk_int(1)]),
T1 = mk_temp(),
I3 = hipe_llvm:mk_call(T1, false, [], [], ReturnType, "@" ++ Name,
@@ -320,7 +321,7 @@ trans_alub_no_overflow(I, Relocs) ->
{Dst, I2} = trans_src(hipe_rtl:alub_dst(I)),
Cond = trans_rel_op(hipe_rtl:alub_cond(I)),
T3 = mk_temp(),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
I5 = hipe_llvm:mk_icmp(T3, Cond, WordTy, Dst, "0"),
%% br
Metadata = branch_metadata(hipe_rtl:alub_pred(I)),
@@ -338,7 +339,7 @@ trans_branch(I, Relocs) ->
Cond = trans_rel_op(hipe_rtl:branch_cond(I)),
%% icmp
T1 = mk_temp(),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
I3 = hipe_llvm:mk_icmp(T1, Cond, WordTy, Src1, Src2),
%% br
True_label = mk_jump_label(hipe_rtl:branch_true_label(I)),
@@ -366,7 +367,7 @@ trans_call(I, Relocs) ->
{Name, I3, Relocs2} =
trans_call_name(RtlCallName, Relocs1, CallArgs, FinalArgs),
T1 = mk_temp(),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)),
I4 =
case hipe_rtl:call_fail(I) of
@@ -450,7 +451,7 @@ trans_call_name(RtlCallName, Relocs, CallArgs, FinalArgs) ->
%% order to make the call
TT1 = mk_temp(),
{RegName, II1} = trans_src(Reg),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
WordTyPtr = hipe_llvm:mk_pointer(WordTy),
II2 =
hipe_llvm:mk_conversion(TT1, inttoptr, WordTy, RegName, WordTyPtr),
@@ -503,7 +504,7 @@ trans_enter(I, Relocs) ->
{Name, I2, NewRelocs} =
trans_call_name(hipe_rtl:enter_fun(I), Relocs, CallArgs, FinalArgs),
T1 = mk_temp(),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)),
I3 = hipe_llvm:mk_call(T1, true, "cc 11", [], FunRetTy, Name, FinalArgs, []),
I4 = hipe_llvm:mk_ret([{FunRetTy, T1}]),
@@ -518,7 +519,7 @@ trans_fconv(I, Relocs) ->
TmpDst = mk_temp(),
{Src, I1} = trans_float_src(hipe_rtl:fconv_src(I)),
FloatTy = hipe_llvm:mk_double(),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
I2 = hipe_llvm:mk_conversion(TmpDst, sitofp, WordTy, Src, FloatTy),
I3 = store_float_stack(TmpDst, RtlDst),
{[I3, I2, I1], Relocs}.
@@ -538,7 +539,7 @@ trans_fload(I, Relocs) ->
{Src, I1} = trans_float_src(RtlSrc),
{Offset, I2} = trans_float_src(_Offset),
T1 = mk_temp(),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
FloatTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_double()),
I3 = hipe_llvm:mk_operation(T1, add, WordTy, Src, Offset, []),
T2 = mk_temp(),
@@ -619,7 +620,7 @@ trans_fstore(I, Relocs) ->
trans_fstore_reg(I, Relocs) ->
{Base, I0} = trans_reg(hipe_rtl:fstore_base(I), dst),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
WordTyPtr = hipe_llvm:mk_pointer(WordTy),
FloatTy = hipe_llvm:mk_double(),
FloatTyPtr = hipe_llvm:mk_pointer(FloatTy),
@@ -659,7 +660,7 @@ trans_load(I, Relocs) ->
{Src, I1} = trans_src(hipe_rtl:load_src(I)),
{Offset, I2} = trans_src(hipe_rtl:load_offset(I)),
T1 = mk_temp(),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
WordTyPtr = hipe_llvm:mk_pointer(WordTy),
I3 = hipe_llvm:mk_operation(T1, add, WordTy, Src, Offset, []),
%%----------------------------------------------------------------
@@ -737,7 +738,7 @@ trans_move(I, Relocs) ->
%% return
%%
trans_return(I, Relocs) ->
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
{VarRet, I1} =
case hipe_rtl:return_varlist(I) of
[] ->
@@ -777,7 +778,7 @@ trans_store(I, Relocs) ->
{Offset, I2} = trans_src(hipe_rtl:store_offset(I)),
{Value, I3} = trans_src(hipe_rtl:store_src(I)),
T1 = mk_temp(),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
WordTyPtr = hipe_llvm:mk_pointer(WordTy),
I4 = hipe_llvm:mk_operation(T1, add, WordTy, Base, Offset, []),
I5 =
@@ -811,14 +812,14 @@ trans_switch(I, Relocs, Data) ->
JumpLabels = [mk_jump_label(L) || L <- Labels],
SortOrder = hipe_rtl:switch_sort_order(I),
NrLabels = length(Labels),
- ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(8)),
+ ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(?BITS_IN_BYTE)),
TableType = hipe_llvm:mk_array(NrLabels, ByteTyPtr),
TableTypeP = hipe_llvm:mk_pointer(TableType),
TypedJumpLabels = [{hipe_llvm:mk_label_type(), X} || X <- JumpLabels],
T1 = mk_temp(),
{Src2, []} = trans_dst(RtlSrc),
TableName = "table_" ++ tl(Src2),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
I2 = hipe_llvm:mk_getelementptr(T1, TableTypeP, "@"++TableName,
[{WordTy, "0"}, {WordTy, Src}], false),
T2 = mk_temp(),
@@ -933,7 +934,7 @@ create_fail_blocks(Label, FailLabels, Acc) ->
false ->
Acc;
{value, {Label, FailLabel, SpAdj}, RestFailLabels} ->
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
I1 = hipe_llvm:mk_label(FailLabel),
LP = hipe_llvm:mk_landingpad(),
I2 =
@@ -962,7 +963,7 @@ create_fail_blocks(Label, FailLabels, Acc) ->
%% @doc Convert RTL argument list to LLVM argument list.
trans_args(ArgList) ->
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
MakeArg =
fun(A) ->
{Name, I1} = trans_src(A),
@@ -972,13 +973,13 @@ trans_args(ArgList) ->
%% @doc Convert a list of Precoloured registers to LLVM argument list.
fix_reg_args(ArgList) ->
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
[{WordTy, A} || A <- ArgList].
%% @doc Load Precoloured registers.
load_fixed_regs(RegList) ->
Names = [mk_temp_reg(R) || R <- RegList],
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
WordTyPtr = hipe_llvm:mk_pointer(WordTy),
Fun1 =
fun (X, Y) ->
@@ -991,7 +992,7 @@ load_fixed_regs(RegList) ->
store_fixed_regs(RegList, Name) ->
Names = [mk_temp_reg(R) || R <- RegList],
Indexes = lists:seq(0, erlang:length(RegList) - 1),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
WordTyPtr = hipe_llvm:mk_pointer(WordTy),
FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)),
Fun1 =
@@ -1060,7 +1061,7 @@ mk_temp_reg(Name) ->
store_stack_dst(TempDst, Dst) ->
{Dst2, II1} = trans_dst(Dst),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
WordTyPtr = hipe_llvm:mk_pointer(WordTy),
II2 = hipe_llvm:mk_store(WordTy, TempDst, WordTyPtr, Dst2, [], [], false),
[II2, II1].
@@ -1078,7 +1079,7 @@ trans_float_src(Src) ->
Name = "@DL" ++ integer_to_list(hipe_rtl:const_label_label(Src)),
T1 = mk_temp(),
%% XXX: Hardcoded offset
- ByteTy = hipe_llvm:mk_int(8),
+ ByteTy = hipe_llvm:mk_int(?BITS_IN_BYTE),
ByteTyPtr = hipe_llvm:mk_pointer(ByteTy),
I1 = hipe_llvm:mk_getelementptr(T1, ByteTyPtr, Name,
[{ByteTy, integer_to_list(?FLOAT_OFFSET)}], true),
@@ -1094,7 +1095,7 @@ trans_float_src(Src) ->
end.
trans_src(A) ->
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
WordTyPtr = hipe_llvm:mk_pointer(WordTy),
case hipe_rtl:is_imm(A) of
true ->
@@ -1197,7 +1198,7 @@ map_precoloured_reg(Index) ->
fix_reg_dst(Register) ->
case Register of
{Name, Offset} -> %% Case of %fcalls, %hplim
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
pointer_from_reg(Name, WordTy, Offset);
Name -> %% Case of %p and %hp
{Name, []}
@@ -1205,7 +1206,7 @@ fix_reg_dst(Register) ->
%% @doc Load precoloured src register.
fix_reg_src(Register) ->
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
WordTyPtr = hipe_llvm:mk_pointer(WordTy),
case Register of
{Name, Offset} -> %% Case of %fcalls, %hplim
@@ -1327,10 +1328,10 @@ insn_dst(I) ->
llvm_type_from_size(Size) ->
case Size of
- byte -> hipe_llvm:mk_int(8);
+ byte -> hipe_llvm:mk_int(?BITS_IN_BYTE);
int16 -> hipe_llvm:mk_int(16);
int32 -> hipe_llvm:mk_int(32);
- word -> hipe_llvm:mk_int(64)
+ word -> hipe_llvm:mk_int(?BITS_IN_WORD)
end.
%% @doc Create definition for the compiled function. The parameters that are
@@ -1360,13 +1361,13 @@ create_function_definition(Fun, Params, Code, LocalVars) ->
lists:flatten([EntryLabel, ExceptionSync, I2, LocalVars, StoredParams, I3]),
Final_Code = EntryBlock ++ Code,
FunctionOptions = [nounwind, noredzone, list_to_atom("gc \"erlang\"")],
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)),
hipe_llvm:mk_fun_def([], [], "cc 11", [], FunRetTy, FunctionName, Args,
FunctionOptions, [], Final_Code).
header_params(Params) ->
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
[{WordTy, "%v" ++ integer_to_list(hipe_rtl:var_index(P))} || P <- Params].
store_params(Params) ->
@@ -1375,7 +1376,7 @@ store_params(Params) ->
Index = hipe_rtl:var_index(X),
{Name, _} = trans_dst(X),
ParamName = "%v" ++ integer_to_list(Index),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
WordTyPtr = hipe_llvm:mk_pointer(WordTy),
hipe_llvm:mk_store(WordTy, ParamName, WordTyPtr, Name, [], [], false)
end,
@@ -1392,11 +1393,11 @@ fixed_registers() ->
end.
header_regs(Registers) ->
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
[{WordTy, "%" ++ X ++ "_in"} || X <- Registers].
load_regs(Registers) ->
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
WordTyPtr = hipe_llvm:mk_pointer(WordTy),
Fun1 =
fun(X) ->
@@ -1496,28 +1497,30 @@ seperate_relocs([R|Rs], CallAcc, AtomAcc, ClosureAcc, LabelAcc, JmpTableAcc) ->
%% @doc External declaration of an atom.
declare_atom({AtomName, _}) ->
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
- hipe_llvm:mk_const_decl("@" ++ AtomName, "external constant", WordTy, "").
+ %% The type has to be byte, or a backend might assume the constant is aligned
+ %% and incorrectly optimise away type tests
+ ByteTy = hipe_llvm:mk_int(?BITS_IN_BYTE),
+ hipe_llvm:mk_const_decl("@" ++ AtomName, "external constant", ByteTy, "").
%% @doc Creation of local variable for an atom.
load_atom({AtomName, _}) ->
Dst = "%" ++ AtomName ++ "_var",
Name = "@" ++ AtomName,
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
- WordTyPtr = hipe_llvm:mk_pointer(WordTy),
- hipe_llvm:mk_conversion(Dst, ptrtoint, WordTyPtr, Name, WordTy).
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
+ ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(?BITS_IN_BYTE)),
+ hipe_llvm:mk_conversion(Dst, ptrtoint, ByteTyPtr, Name, WordTy).
%% @doc External declaration of a closure.
declare_closure({ClosureName, _})->
- ByteTy = hipe_llvm:mk_int(8),
+ ByteTy = hipe_llvm:mk_int(?BITS_IN_BYTE),
hipe_llvm:mk_const_decl("@" ++ ClosureName, "external constant", ByteTy, "").
%% @doc Creation of local variable for a closure.
load_closure({ClosureName, _})->
Dst = "%" ++ ClosureName ++ "_var",
Name = "@" ++ ClosureName,
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
- ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(8)),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
+ ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(?BITS_IN_BYTE)),
hipe_llvm:mk_conversion(Dst, ptrtoint, ByteTyPtr, Name, WordTy).
%% @doc Declaration of a local variable for a switch jump table.
@@ -1548,7 +1551,7 @@ declare_closure_labels(ClosureLabels, Relocs, Fun) ->
List3 = string:join(List2, ",\n"),
List4 = "[\n" ++ List3 ++ "\n]\n",
NrLabels = length(LabelList),
- ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(8)),
+ ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(?BITS_IN_BYTE)),
TableType = hipe_llvm:mk_array(NrLabels, ByteTyPtr),
ConstDecl =
hipe_llvm:mk_const_decl("@table_closures", "constant", TableType, List4),
@@ -1563,7 +1566,7 @@ is_external_call(_, _) -> true.
call_to_decl({Name, {call, MFA}}) ->
{M, _F, A} = MFA,
CConv = "cc 11",
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)),
{Type, Args} =
case M of
@@ -1578,14 +1581,14 @@ call_to_decl({Name, {call, MFA}}) ->
%% @doc These functions are always declared, even if not used.
fixed_fun_decl() ->
- ByteTy = hipe_llvm:mk_int(8),
+ ByteTy = hipe_llvm:mk_int(?BITS_IN_BYTE),
ByteTyPtr = hipe_llvm:mk_pointer(ByteTy),
LandPad = hipe_llvm:mk_fun_decl([], [], [], [], hipe_llvm:mk_int(32),
"@__gcc_personality_v0", [hipe_llvm:mk_int(32), hipe_llvm:mk_int(64),
ByteTyPtr, ByteTyPtr], []),
GCROOTDecl = hipe_llvm:mk_fun_decl([], [], [], [], hipe_llvm:mk_void(),
"@llvm.gcroot", [hipe_llvm:mk_pointer(ByteTyPtr), ByteTyPtr], []),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)),
FixPinnedRegs = hipe_llvm:mk_fun_decl([], [], [], [], FunRetTy,
"@hipe_bifs.llvm_fix_pinned_regs.0", [], []),
@@ -1599,7 +1602,7 @@ fixed_fun_decl() ->
%% values, add the offset and convert them again to pointers.
declare_constant(Label) ->
Name = "@DL" ++ integer_to_list(Label),
- ByteTy = hipe_llvm:mk_int(8),
+ ByteTy = hipe_llvm:mk_int(?BITS_IN_BYTE),
hipe_llvm:mk_const_decl(Name, "external constant", ByteTy, "").
%% @doc Load a constant is achieved by converting a pointer to an integer of
@@ -1607,8 +1610,8 @@ declare_constant(Label) ->
load_constant(Label) ->
Dst = "%DL" ++ integer_to_list(Label) ++ "_var",
Name = "@DL" ++ integer_to_list(Label),
- WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
- ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(8)),
+ WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
+ ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(?BITS_IN_BYTE)),
hipe_llvm:mk_conversion(Dst, ptrtoint, ByteTyPtr, Name, WordTy).
%% @doc Store external constants and calls to dictionary.
diff --git a/lib/hipe/main/hipe.erl b/lib/hipe/main/hipe.erl
index 6c525dd143..cc0148a80e 100644
--- a/lib/hipe/main/hipe.erl
+++ b/lib/hipe/main/hipe.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -635,44 +635,51 @@ run_compiler(Name, DisasmFun, IcodeFun, Opts0) ->
Opts = expand_basic_options(Opts0 ++ ?COMPILE_DEFAULTS),
?when_option(verbose, Opts, ?debug_msg("Compiling: ~p\n",[Name])),
?option_start_time("Compile", Opts),
- Res = run_compiler_1(DisasmFun, IcodeFun, Opts),
+ Res = run_compiler_1(Name, DisasmFun, IcodeFun, Opts),
?option_stop_time("Compile", Opts),
Res.
-run_compiler_1(DisasmFun, IcodeFun, Options) ->
+run_compiler_1(Name, DisasmFun, IcodeFun, Options) ->
Parent = self(),
{trap_exit,TrapExit} = process_info(Parent, trap_exit),
%% Spawn a compilation process CompProc. In case this process gets
%% killed, the trap_exit flag is restored to that of the Parent process.
process_flag(trap_exit, true),
- CompProc = spawn_link(fun () ->
- %% Compiler process
- set_architecture(Options),
- pre_init(Options),
- %% The full option expansion is not done
- %% until the DisasmFun returns.
- {Code, CompOpts} = DisasmFun(Options),
- Opts0 = expand_options(Options ++ CompOpts,
- get(hipe_target_arch)),
- Opts =
- case proplists:get_bool(to_llvm, Opts0) andalso
- not llvm_support_available() of
- true ->
- ?error_msg("No LLVM version 3.4 or greater "
- "found in $PATH; aborting "
- "native code compilation.\n", []),
- ?EXIT(cant_find_required_llvm_version);
- false ->
- Opts0
- end,
- check_options(Opts),
- ?when_option(verbose, Options,
- ?debug_msg("Options: ~p.\n",[Opts])),
- init(Opts),
- {Icode, WholeModule} = IcodeFun(Code, Opts),
- CompRes = compile_finish(Icode, WholeModule, Opts),
- compiler_return(CompRes, Parent)
- end),
+ CompProc =
+ spawn_link(
+ fun () ->
+ try
+ %% Compiler process
+ set_architecture(Options),
+ pre_init(Options),
+ %% The full option expansion is not done
+ %% until the DisasmFun returns.
+ {Code, CompOpts} = DisasmFun(Options),
+ Opts0 = expand_options(Options ++ CompOpts,
+ get(hipe_target_arch)),
+ Opts =
+ case proplists:get_bool(to_llvm, Opts0) andalso
+ not llvm_support_available() of
+ true ->
+ ?error_msg("No LLVM version 3.4 or greater "
+ "found in $PATH; aborting "
+ "native code compilation.\n", []),
+ ?EXIT(cant_find_required_llvm_version);
+ false ->
+ Opts0
+ end,
+ check_options(Opts),
+ ?when_option(verbose, Options,
+ ?debug_msg("Options: ~p.\n",[Opts])),
+ init(Opts),
+ {Icode, WholeModule} = IcodeFun(Code, Opts),
+ CompRes = compile_finish(Icode, WholeModule, Opts),
+ compiler_return(CompRes, Parent)
+ catch error:Error ->
+ print_crash_message(Name, Error),
+ exit(Error)
+ end
+ end),
Timeout = case proplists:get_value(timeout, Options) of
N when is_integer(N), N >= 0 -> N;
undefined -> ?DEFAULT_TIMEOUT;
@@ -691,7 +698,7 @@ run_compiler_1(DisasmFun, IcodeFun, Options) ->
exit(CompProc, kill),
receive {'EXIT', CompProc, _} -> ok end,
flush(),
- ?error_msg("ERROR: Compilation timed out.\n",[]),
+ ?error_msg("ERROR: Compilation of ~w timed out.\n",[Name]),
exit(timed_out)
end,
Result = receive {CompProc, Res} -> Res end,
@@ -844,11 +851,25 @@ finalize_fun_sequential({MFA, Icode}, Opts, Servers) ->
catch
error:Error ->
?when_option(verbose, Opts, ?debug_untagged_msg("\n", [])),
- ErrorInfo = {Error, erlang:get_stacktrace()},
- ?error_msg("ERROR: ~p~n", [ErrorInfo]),
- ?EXIT(ErrorInfo)
+ print_crash_message(MFA, Error),
+ exit(Error)
end.
+print_crash_message(What, Error) ->
+ StackFun = fun(_,_,_) -> false end,
+ FormatFun = fun (Term, _) -> io_lib:format("~p", [Term]) end,
+ StackTrace = lib:format_stacktrace(1, erlang:get_stacktrace(),
+ StackFun, FormatFun),
+ WhatS = case What of
+ {M,F,A} -> io_lib:format("~w:~w/~w", [M,F,A]);
+ Mod -> io_lib:format("~w", [Mod])
+ end,
+ ?error_msg("INTERNAL ERROR~n"
+ "while compiling ~s~n"
+ "crash reason: ~p~n"
+ "~s~n",
+ [WhatS, Error, StackTrace]).
+
pp_server_start(Opts) ->
set_architecture(Opts),
garbage_collect(),
diff --git a/lib/hipe/main/hipe.hrl.src b/lib/hipe/main/hipe.hrl.src
index 53b59f88f0..b001743038 100644
--- a/lib/hipe/main/hipe.hrl.src
+++ b/lib/hipe/main/hipe.hrl.src
@@ -1,8 +1,8 @@
-%% -*- erlang-indent-level: 2 -*-
+%% -*- mode: erlang; erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -70,20 +70,24 @@
code_server:info_msg(?MSGTAG ++ Msg, Args)).
-define(untagged_msg(Msg, Args),
code_server:info_msg(Msg, Args)).
+-define(untagged_error_msg(Msg, Args),
+ code_server:error_msg(Msg, Args)).
-else.
-define(msg(Msg, Args),
io:format(?MSGTAG ++ Msg, Args)).
-define(untagged_msg(Msg, Args),
io:format(Msg, Args)).
+-define(untagged_error_msg(Msg, Args),
+ io:format(Msg, Args)).
-endif.
%%
%% Define error and warning messages.
%%
-define(error_msg(Msg, Args),
- code_server:error_msg(?MSGTAG ++
+ ?untagged_error_msg(?MSGTAG ++
"Error: [~s:~w]: " ++ Msg,
- [?MODULE,?LINE|Args])).
+ [?MODULE,?LINE|Args])).
-define(WARNING_MSG(Msg, Args),
?msg("Warning: [~s:~w]: " ++ Msg, [?MODULE,?LINE|Args])).
diff --git a/lib/hipe/main/hipe_main.erl b/lib/hipe/main/hipe_main.erl
index 4b89feb48a..8737560ad5 100644
--- a/lib/hipe/main/hipe_main.erl
+++ b/lib/hipe/main/hipe_main.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/hipe/ppc/hipe_ppc.erl b/lib/hipe/ppc/hipe_ppc.erl
index 0fa96162f6..380e791bc1 100644
--- a/lib/hipe/ppc/hipe_ppc.erl
+++ b/lib/hipe/ppc/hipe_ppc.erl
@@ -167,8 +167,10 @@ temp_is_precoloured(#ppc_temp{reg=Reg,type=Type}) ->
_ -> hipe_ppc_registers:is_precoloured_gpr(Reg)
end.
-mk_simm16(Value) -> #ppc_simm16{value=Value}.
-mk_uimm16(Value) -> #ppc_uimm16{value=Value}.
+mk_simm16(Value) when Value >= -(1 bsl 15), Value < (1 bsl 15) ->
+ #ppc_simm16{value=Value}.
+mk_uimm16(Value) when Value >= 0, Value < (1 bsl 16) ->
+ #ppc_uimm16{value=Value}.
mk_mfa(M, F, A) -> #ppc_mfa{m=M, f=F, a=A}.
@@ -240,7 +242,11 @@ mk_li(Dst, Value, Tail) -> % Dst can be R0
Value =< 16#7FFFFFFF ->
mk_li32(Dst, R0, Value, Tail);
true ->
- Highest = (Value bsr 48), % Value@highest
+ Highest = case (Value bsr 48) of % Value@highest
+ TopBitSet when TopBitSet >= (1 bsl 15) ->
+ TopBitSet - (1 bsl 16); % encoder needs it to be negative
+ FitsSimm16 -> FitsSimm16
+ end,
Higher = (Value bsr 32) band 16#FFFF, % Value@higher
High = (Value bsr 16) band 16#FFFF, % Value@h
Low = Value band 16#FFFF, % Value@l
diff --git a/lib/hipe/ppc/hipe_ppc_assemble.erl b/lib/hipe/ppc/hipe_ppc_assemble.erl
index ff9da01b11..d89ff6235c 100644
--- a/lib/hipe/ppc/hipe_ppc_assemble.erl
+++ b/lib/hipe/ppc/hipe_ppc_assemble.erl
@@ -175,7 +175,8 @@ do_slwi_opnds(Dst, Src1, {uimm,N}) when is_integer(N), 0 =< N, N < 32 ->
{Dst, Src1, {sh,N}, {mb,0}, {me,31-N}}.
do_srwi_opnds(Dst, Src1, {uimm,N}) when is_integer(N), 0 =< N, N < 32 ->
- {Dst, Src1, {sh,32-N}, {mb,N}, {me,31}}.
+ %% SH should be 0 (not 32) when N is 0
+ {Dst, Src1, {sh,(32-N) band 31}, {mb,N}, {me,31}}.
do_srawi_src2({uimm,N}) when is_integer(N), 0 =< N, N < 32 -> {sh,N}.
@@ -184,7 +185,8 @@ do_sldi_opnds(Dst, Src1, {uimm,N}) when is_integer(N), 0 =< N, N < 64 ->
{Dst, Src1, {sh6,N}, {me6,63-N}}.
do_srdi_opnds(Dst, Src1, {uimm,N}) when is_integer(N), 0 =< N, N < 64 ->
- {Dst, Src1, {sh6,64-N}, {mb6,N}}.
+ %% SH should be 0 (not 64) when N is 0
+ {Dst, Src1, {sh6,(64-N) band 63}, {mb6,N}}.
do_sradi_src2({uimm,N}) when is_integer(N), 0 =< N, N < 64 -> {sh6,N}.
@@ -246,6 +248,7 @@ do_load(I) ->
case LdOp of
'ld' -> do_disp_ds(Disp);
'ldu' -> do_disp_ds(Disp);
+ 'lwa' -> do_disp_ds(Disp);
_ -> do_disp(Disp)
end,
NewBase = do_reg(Base),
diff --git a/lib/hipe/rtl/hipe_rtl_binary.erl b/lib/hipe/rtl/hipe_rtl_binary.erl
index fb9c0c196d..9b400f4c93 100644
--- a/lib/hipe/rtl/hipe_rtl_binary.erl
+++ b/lib/hipe/rtl/hipe_rtl_binary.erl
@@ -19,7 +19,7 @@
%%% %CopyrightEnd%
%%%
%%%-------------------------------------------------------------------
-%%% File : hipe_rtl_binary_2.erl
+%%% File : hipe_rtl_binary.erl
%%% Author : Per Gustafsson <[email protected]>
%%% Description :
%%%
diff --git a/lib/hipe/rtl/hipe_rtl_binary_match.erl b/lib/hipe/rtl/hipe_rtl_binary_match.erl
index 528672b893..d999cd2743 100644
--- a/lib/hipe/rtl/hipe_rtl_binary_match.erl
+++ b/lib/hipe/rtl/hipe_rtl_binary_match.erl
@@ -270,24 +270,23 @@ gen_rtl({bs_save, Slot}, [NewMs], [Ms], TrueLblName, _FalseLblName) ->
set_field_from_term({matchstate, {saveoffset, Slot}}, Ms, Offset),
hipe_rtl:mk_goto(TrueLblName)];
%% ----- bs_match_string -----
-gen_rtl({bs_match_string, String, ByteSize}, Dst, [Ms],
+gen_rtl({bs_match_string, String, BitSize}, Dst, [Ms],
TrueLblName, FalseLblName) ->
{[Offset, BinSize, Base], Instrs} =
extract_matchstate_vars([offset, binsize, base], Ms),
[SuccessLbl, ALbl, ULbl] = create_lbls(3),
[NewOffset, BitOffset] = create_gcsafe_regs(2),
- Unit = hipe_rtl_arch:word_size() - 1,
- Loops = ByteSize div Unit,
- Init =
+ Unit = (hipe_rtl_arch:word_size() - 1) * ?BYTE_SIZE,
+ Init =
[Instrs,
opt_update_ms(Dst, Ms),
- check_size(Offset, hipe_rtl:mk_imm(ByteSize*?BYTE_SIZE), BinSize,
+ check_size(Offset, hipe_rtl:mk_imm(BitSize), BinSize,
NewOffset, hipe_rtl:label_name(SuccessLbl), FalseLblName),
SuccessLbl],
SplitCode =
[hipe_rtl:mk_alub(BitOffset, Offset, 'and', hipe_rtl:mk_imm(?LOW_BITS), eq,
hipe_rtl:label_name(ALbl), hipe_rtl:label_name(ULbl))],
- Loops = ByteSize div Unit,
+ Loops = BitSize div Unit,
SkipSize = Loops * Unit,
{ACode1, UCode1} =
case Loops of
@@ -297,9 +296,9 @@ gen_rtl({bs_match_string, String, ByteSize}, Dst, [Ms],
create_loops(Loops, Unit, String, Base,
Offset, BitOffset, FalseLblName)
end,
- <<_:SkipSize/binary, RestString/binary>> = String,
+ <<_:SkipSize/bits, RestString/bits>> = String,
{ACode2, UCode2} =
- case ByteSize rem Unit of
+ case BitSize rem Unit of
0 ->
{[], []};
Rem ->
@@ -393,12 +392,12 @@ validate_unicode_retract_c_code(Src, Ms, TrueLblName, FalseLblName) ->
create_loops(Loops, Unit, String, Base, Offset, BitOffset, FalseLblName) ->
[Reg] = create_gcsafe_regs(1),
AlignedFun = fun(Value) ->
- [get_int_to_reg(Reg, Unit*?BYTE_SIZE, Base, Offset, 'srl',
+ [get_int_to_reg(Reg, Unit, Base, Offset, 'srl',
{unsigned, big}),
update_and_test(Reg, Unit, Offset, Value, FalseLblName)]
end,
UnAlignedFun = fun(Value) ->
- [get_unaligned_int_to_reg(Reg, Unit*?BYTE_SIZE,
+ [get_unaligned_int_to_reg(Reg, Unit,
Base, Offset, BitOffset,
'srl', {unsigned, big})|
update_and_test(Reg, Unit, Offset, Value, FalseLblName)]
@@ -406,31 +405,31 @@ create_loops(Loops, Unit, String, Base, Offset, BitOffset, FalseLblName) ->
{create_loops(Loops, Unit, String, AlignedFun),
create_loops(Loops, Unit, String, UnAlignedFun)}.
-create_rests(Rem, String, Base, Offset, BitOffset, FalseLblName) ->
+create_rests(RemBits, String, Base, Offset, BitOffset, FalseLblName) ->
[Reg] = create_gcsafe_regs(1),
AlignedFun = fun(Value) ->
- [get_int_to_reg(Reg, Rem*?BYTE_SIZE, Base, Offset, 'srl',
+ [get_int_to_reg(Reg, RemBits, Base, Offset, 'srl',
{unsigned, big})|
just_test(Reg, Value, FalseLblName)]
end,
UnAlignedFun = fun(Value) ->
- [get_unaligned_int_to_reg(Reg, Rem*?BYTE_SIZE,
+ [get_unaligned_int_to_reg(Reg, RemBits,
Base, Offset, BitOffset,
'srl', {unsigned, big})|
just_test(Reg, Value, FalseLblName)]
end,
- {create_loops(1, Rem, String, AlignedFun),
- create_loops(1, Rem, String, UnAlignedFun)}.
+ {create_loops(1, RemBits, String, AlignedFun),
+ create_loops(1, RemBits, String, UnAlignedFun)}.
create_loops(0, _Unit, _String, _IntFun) ->
[];
create_loops(N, Unit, String, IntFun) ->
- {Value, RestString} = get_value(Unit,String),
+ {Value, RestString} = get_value(Unit, String),
[IntFun(Value),
create_loops(N-1, Unit, RestString, IntFun)].
update_and_test(Reg, Unit, Offset, Value, FalseLblName) ->
- [add_to_offset(Offset, Offset, hipe_rtl:mk_imm(Unit*?BYTE_SIZE), FalseLblName),
+ [add_to_offset(Offset, Offset, hipe_rtl:mk_imm(Unit), FalseLblName),
just_test(Reg, Value, FalseLblName)].
just_test(Reg, Value, FalseLblName) ->
@@ -439,8 +438,8 @@ just_test(Reg, Value, FalseLblName) ->
hipe_rtl:label_name(ContLbl), FalseLblName),
ContLbl].
-get_value(N,String) ->
- <<I:N/integer-unit:8, Rest/binary>> = String,
+get_value(N, String) ->
+ <<I:N, Rest/bits>> = String,
{I, Rest}.
make_int_gc_code(I) when is_integer(I) ->
diff --git a/lib/hipe/sparc/hipe_rtl_to_sparc.erl b/lib/hipe/sparc/hipe_rtl_to_sparc.erl
index eef5ba8d96..f9c043eafe 100644
--- a/lib/hipe/sparc/hipe_rtl_to_sparc.erl
+++ b/lib/hipe/sparc/hipe_rtl_to_sparc.erl
@@ -750,13 +750,25 @@ xaluop_commutes(XAluOp) ->
xaluop_is_shift(XAluOp) ->
case XAluOp of
+ 'add' -> false;
+ 'addcc' -> false;
+ 'and' -> false;
+ 'andcc' -> false;
+ 'cmpcc' -> false;
+ 'ldsb' -> false;
+ 'ldub' -> false;
+ 'lduw' -> false;
+ 'or' -> false;
'sll' -> true;
- 'srl' -> true;
+ %% 'sllx' -> true;
+ 'smul' -> false;
'sra' -> true;
- 'sllx' -> true;
- 'srlx' -> true;
- 'srax' -> true;
- _ -> false
+ %% 'srax' -> true;
+ 'srl' -> true;
+ %% 'srlx' -> true;
+ 'sub' -> false;
+ 'subcc' -> false;
+ 'xor' -> false
end.
%%% Convert an extended SPARC AluOp back to a plain AluOp.
@@ -764,9 +776,23 @@ xaluop_is_shift(XAluOp) ->
xaluop_normalise(XAluOp) ->
case XAluOp of
- 'cmp' -> 'sub';
+ 'add' -> 'add';
+ 'addcc' -> 'addcc';
+ 'and' -> 'and';
+ 'andcc' -> 'andcc';
+ %% 'cmp' -> 'sub';
'cmpcc' -> 'subcc';
- _ -> XAluOp
+ 'ldsb' -> 'ldsb';
+ 'ldub' -> 'ldub';
+ 'lduw' -> 'lduw';
+ 'or' -> 'or';
+ 'sll' -> 'sll';
+ 'smul' -> 'smul';
+ 'sra' -> 'sra';
+ 'srl' -> 'srl';
+ 'sub' -> 'sub';
+ 'subcc' -> 'subcc';
+ 'xor' -> 'xor'
end.
%%% Convert an RTL condition code.
diff --git a/lib/hipe/sparc/hipe_sparc_registers.erl b/lib/hipe/sparc/hipe_sparc_registers.erl
index 884215702b..6681a10070 100644
--- a/lib/hipe/sparc/hipe_sparc_registers.erl
+++ b/lib/hipe/sparc/hipe_sparc_registers.erl
@@ -86,6 +86,8 @@
-define(I7, 31).
-define(LAST_PRECOLOURED,31). % must handle both GRP and FPR ranges
+-define(RA, ?O7).
+
-define(ARG0, ?O1).
-define(ARG1, ?O2).
-define(ARG2, ?O3).
@@ -174,7 +176,7 @@ stack_pointer() -> ?STACK_POINTER.
proc_pointer() -> ?PROC_POINTER.
-return_address() -> ?O7.
+return_address() -> ?RA.
g0() -> ?G0.
@@ -283,7 +285,9 @@ call_clobbered() -> % does the RA strip the type or not?
].
tailcall_clobbered() -> % tailcall crapola needs one temp
- [{?TEMP1,tagged},{?TEMP1,untagged}].
+ [{?TEMP1,tagged},{?TEMP1,untagged}
+ ,{?RA,tagged},{?RA,untagged}
+ ].
live_at_return() ->
[{?HEAP_POINTER,untagged},
diff --git a/lib/hipe/test/basic_SUITE_data/basic_num_bif.erl b/lib/hipe/test/basic_SUITE_data/basic_num_bif.erl
new file mode 100644
index 0000000000..807c4b0d0d
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_num_bif.erl
@@ -0,0 +1,217 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% File : basic_num_bif.erl
+%%% Description : Taken from the compiler test suite
+%%%-------------------------------------------------------------------
+-module(basic_num_bif).
+
+-export([test/0]).
+
+%% Tests optimization of the BIFs:
+%% abs/1
+%% float/1
+%% float_to_list/1
+%% integer_to_list/1
+%% list_to_float/1
+%% list_to_integer/1
+%% round/1
+%% trunc/1
+
+test() ->
+ Funs = [fun t_abs/0, fun t_float/0,
+ fun t_float_to_list/0, fun t_integer_to_list/0,
+ fun t_list_to_float_safe/0, fun t_list_to_float_risky/0,
+ fun t_list_to_integer/0, fun t_round/0, fun t_trunc/0],
+ lists:foreach(fun (F) -> ok = F() end, Funs).
+
+t_abs() ->
+ %% Floats.
+ 5.5 = abs(5.5),
+ 0.0 = abs(0.0),
+ 100.0 = abs(-100.0),
+ %% Integers.
+ 5 = abs(5),
+ 0 = abs(0),
+ 100 = abs(-100),
+ %% The largest smallnum. OTP-3190.
+ X = (1 bsl 27) - 1,
+ X = abs(X),
+ X = abs(X-1)+1,
+ X = abs(X+1)-1,
+ X = abs(-X),
+ X = abs(-X-1)-1,
+ X = abs(-X+1)+1,
+ %% Bignums.
+ BigNum = 13984792374983749,
+ BigNum = abs(BigNum),
+ BigNum = abs(-BigNum),
+ ok.
+
+t_float() ->
+ 0.0 = float(0),
+ 2.5 = float(2.5),
+ 0.0 = float(0.0),
+ -100.55 = float(-100.55),
+ 42.0 = float(42),
+ -100.0 = float(-100),
+ %% Bignums.
+ 4294967305.0 = float(4294967305),
+ -4294967305.0 = float(-4294967305),
+ %% Extremely big bignums.
+ Big = list_to_integer(lists:duplicate(2000, $1)),
+ {'EXIT', {badarg, _}} = (catch float(Big)),
+ ok.
+
+%% Tests float_to_list/1.
+
+t_float_to_list() ->
+ test_ftl("0.0e+0", 0.0),
+ test_ftl("2.5e+1", 25.0),
+ test_ftl("2.5e+0", 2.5),
+ test_ftl("2.5e-1", 0.25),
+ test_ftl("-3.5e+17", -350.0e15),
+ ok.
+
+test_ftl(Expect, Float) ->
+ %% No on the next line -- we want the line number from t_float_to_list.
+ Expect = remove_zeros(lists:reverse(float_to_list(Float)), []).
+
+%% Removes any non-significant zeros in a floating point number.
+%% Example: 2.500000e+01 -> 2.5e+1
+
+remove_zeros([$+, $e|Rest], [$0, X|Result]) ->
+ remove_zeros([$+, $e|Rest], [X|Result]);
+remove_zeros([$-, $e|Rest], [$0, X|Result]) ->
+ remove_zeros([$-, $e|Rest], [X|Result]);
+remove_zeros([$0, $.|Rest], [$e|Result]) ->
+ remove_zeros(Rest, [$., $0, $e|Result]);
+remove_zeros([$0|Rest], [$e|Result]) ->
+ remove_zeros(Rest, [$e|Result]);
+remove_zeros([Char|Rest], Result) ->
+ remove_zeros(Rest, [Char|Result]);
+remove_zeros([], Result) ->
+ Result.
+
+%% Tests integer_to_list/1.
+
+t_integer_to_list() ->
+ "0" = integer_to_list(0),
+ "42" = integer_to_list(42),
+ "-42" = integer_to_list(-42),
+ "-42" = integer_to_list(-42),
+ "32768" = integer_to_list(32768),
+ "268435455" = integer_to_list(268435455),
+ "-268435455" = integer_to_list(-268435455),
+ "123456932798748738738" = integer_to_list(123456932798748738738),
+ Big_List = lists:duplicate(2000, $1),
+ Big = list_to_integer(Big_List),
+ Big_List = integer_to_list(Big),
+ ok.
+
+%% Tests list_to_float/1.
+
+t_list_to_float_safe() ->
+ 0.0 = list_to_float("0.0"),
+ 0.0 = list_to_float("-0.0"),
+ 0.5 = list_to_float("0.5"),
+ -0.5 = list_to_float("-0.5"),
+ 100.0 = list_to_float("1.0e2"),
+ 127.5 = list_to_float("127.5"),
+ -199.5 = list_to_float("-199.5"),
+ ok.
+
+%% This might crash the emulator...
+%% (Known to crash the Unix version of Erlang 4.4.1)
+
+t_list_to_float_risky() ->
+ Many_Ones = lists:duplicate(25000, $1),
+ _ = list_to_float("2."++Many_Ones),
+ {'EXIT', {badarg, _}} = (catch list_to_float("2"++Many_Ones)),
+ ok.
+
+%% Tests list_to_integer/1.
+
+t_list_to_integer() ->
+ 0 = list_to_integer("0"),
+ 0 = list_to_integer("00"),
+ 0 = list_to_integer("-0"),
+ 1 = list_to_integer("1"),
+ -1 = list_to_integer("-1"),
+ 42 = list_to_integer("42"),
+ -12 = list_to_integer("-12"),
+ 32768 = list_to_integer("32768"),
+ 268435455 = list_to_integer("268435455"),
+ -268435455 = list_to_integer("-268435455"),
+ %% Bignums.
+ 123456932798748738738 = list_to_integer("123456932798748738738"),
+ _ = list_to_integer(lists:duplicate(2000, $1)),
+ ok.
+
+%% Tests round/1.
+
+t_round() ->
+ 0 = round(0.0),
+ 0 = round(0.4),
+ 1 = round(0.5),
+ 0 = round(-0.4),
+ -1 = round(-0.5),
+ 255 = round(255.3),
+ 256 = round(255.6),
+ -1033 = round(-1033.3),
+ -1034 = round(-1033.6),
+ %% OTP-3722:
+ X = (1 bsl 27) - 1,
+ MX = -X,
+ MXm1 = -X-1,
+ MXp1 = -X+1,
+ F = X + 0.0,
+ X = round(F),
+ X = round(F+1)-1,
+ X = round(F-1)+1,
+ MX = round(-F),
+ MXm1 = round(-F-1),
+ MXp1 = round(-F+1),
+ X = round(F+0.1),
+ X = round(F+1+0.1)-1,
+ X = round(F-1+0.1)+1,
+ MX = round(-F+0.1),
+ MXm1 = round(-F-1+0.1),
+ MXp1 = round(-F+1+0.1),
+ X = round(F-0.1),
+ X = round(F+1-0.1)-1,
+ X = round(F-1-0.1)+1,
+ MX = round(-F-0.1),
+ MXm1 = round(-F-1-0.1),
+ MXp1 = round(-F+1-0.1),
+ 0.5 = abs(round(F+0.5)-(F+0.5)),
+ 0.5 = abs(round(F-0.5)-(F-0.5)),
+ 0.5 = abs(round(-F-0.5)-(-F-0.5)),
+ 0.5 = abs(round(-F+0.5)-(-F+0.5)),
+ %% Bignums.
+ 4294967296 = round(4294967296.1),
+ 4294967297 = round(4294967296.9),
+ -4294967296 = -round(4294967296.1),
+ -4294967297 = -round(4294967296.9),
+ ok.
+
+t_trunc() ->
+ 0 = trunc(0.0),
+ 5 = trunc(5.3333),
+ -10 = trunc(-10.978987),
+ %% The largest smallnum, converted to float (OTP-3722):
+ X = (1 bsl 27) - 1,
+ F = X + 0.0,
+ %% io:format("X = ~p/~w/~w, F = ~p/~w/~w, trunc(F) = ~p/~w/~w~n",
+ %% [X, X, binary_to_list(term_to_binary(X)),
+ %% F, F, binary_to_list(term_to_binary(F)),
+ %% trunc(F), trunc(F), binary_to_list(term_to_binary(trunc(F)))]),
+ X = trunc(F),
+ X = trunc(F+1)-1,
+ X = trunc(F-1)+1,
+ X = -trunc(-F),
+ X = -trunc(-F-1)-1,
+ X = -trunc(-F+1)+1,
+ %% Bignums.
+ 4294967305 = trunc(4294967305.7),
+ -4294967305 = trunc(-4294967305.7),
+ ok.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_pmatch_bugs.erl b/lib/hipe/test/bs_SUITE_data/bs_pmatch_bugs.erl
index b280705a47..d9f3278b45 100644
--- a/lib/hipe/test/bs_SUITE_data/bs_pmatch_bugs.erl
+++ b/lib/hipe/test/bs_SUITE_data/bs_pmatch_bugs.erl
@@ -9,6 +9,7 @@ test() ->
<<49,50,51>> = lex_digits1(Bin, 1, []),
<<49,50,51>> = lex_digits2(Bin, 1, []),
ok = var_bind_bug(<<1, 2, 3, 4, 5, 6, 7, 8>>),
+ ok = bs_match_string_bug(),
ok.
%%--------------------------------------------------------------------
@@ -65,3 +66,50 @@ var_bind_bug(<<A:1/binary, B:8/integer, _C:B/binary, _Rest/binary>>) ->
B -> wrong;
_ -> ok
end.
+
+%%--------------------------------------------------------------------
+%% From: Andreas Schultz
+%% Date: 2/11/2016
+%%
+%% Either HiPE is messing up binary matches in some cases or I'm not
+%% seeing the problem. ... <SNIP PROGRAM - CLEANED UP VERSION BELOW>
+%% With Erlang 19.1.3 the HiPE compiled version behaves differently
+%% than the non-HiPE version: ... <SNIP TEST RUNS>
+%% So, do I do something wrong here or is this a legitimate HiPE bug?
+%%
+%% Yes, this was a legitimate HiPE bug: The BEAM to ICode tranaslation
+%% of the bs_match_string instruction, written long ago for binaries
+%% (i.e., with byte-sized strings), tried to do a `clever' translation
+%% of even bit-sized strings using a HiPE primop that took a `Size'
+%% argument expressed in *bytes*. ICode is not really the place to do
+%% such a thing, and moreover there is really no reason for the HiPE
+%% primop not to take a Size argument expressed in *bits* instead.
+%% The bug was fixed by changing the `Size' argument to be in bits,
+%% postponing the translation of the bs_match_string primop until RTL
+%% and doing a proper translation using bit-sized quantities there.
+%%--------------------------------------------------------------------
+
+bs_match_string_bug() ->
+ ok = test0(<<50>>),
+ Bin = data(),
+ ok = test1(Bin),
+ ok = test2(Bin),
+ ok.
+
+%% Minimal test case showing the problem matching with strings
+test0(<<6:5, 0:1, 0:2>>) -> weird;
+test0(<<6:5, _:1, _:2>>) -> ok;
+test0(_) -> default.
+
+data() -> <<50,16,0>>.
+
+%% This was the problematic test case in HiPE: 'default' was returned
+test1(<<1:3, 1:1, _:1, 0:1, 0:1, 0:1, _/binary>>) -> weird;
+test1(<<1:3, 1:1, _:1, _:1, _:1, _:1, _/binary>>) -> ok;
+test1(_) -> default.
+
+%% This variation of test1/1 above worked OK, even in HiPE
+test2(<<1:3, 1:1, _:1, A:1, B:1, C:1, _/binary>>)
+ when A =:= 1; B =:= 1; C =:= 1 -> ok;
+test2(<<1:3, 1:1, _:1, 0:1, 0:1, 0:1, _/binary>>) -> weird;
+test2(_) -> default.
diff --git a/lib/hipe/test/hipe_SUITE.erl b/lib/hipe/test/hipe_SUITE.erl
index a5b3924aa8..b9adb660f2 100644
--- a/lib/hipe/test/hipe_SUITE.erl
+++ b/lib/hipe/test/hipe_SUITE.erl
@@ -16,7 +16,11 @@
%%
-module(hipe_SUITE).
--compile([export_all]).
+-export([all/0, groups/0,
+ init_per_suite/1, end_per_suite/1,
+ init_per_group/2, end_per_group/2,
+ app/0, app/1, appup/0, appup/1]).
+
-include_lib("common_test/include/ct.hrl").
all() ->
diff --git a/lib/hipe/test/hipe_testsuite_driver.erl b/lib/hipe/test/hipe_testsuite_driver.erl
index 03ec7adfd0..a3048d907e 100644
--- a/lib/hipe/test/hipe_testsuite_driver.erl
+++ b/lib/hipe/test/hipe_testsuite_driver.erl
@@ -99,7 +99,7 @@ write_suite(Suite) ->
write_header(#suite{suitename = SuiteName, outputfile = OutputFile,
testcases = TestCases}) ->
Exports = format_export(TestCases),
- TimeLimit = 3, %% with 1 or 2 it fails on some slow machines...
+ TimeLimit = 5, %% with 1 or 2 it fails on some slow machines...
io:format(OutputFile,
"%% ATTENTION!\n"
"%% This is an automatically generated file. Do not edit.\n\n"
diff --git a/lib/hipe/test/maps_SUITE_data/maps_redundant_branch_is_key.erl b/lib/hipe/test/maps_SUITE_data/maps_redundant_branch_is_key.erl
new file mode 100644
index 0000000000..17c3acd6af
--- /dev/null
+++ b/lib/hipe/test/maps_SUITE_data/maps_redundant_branch_is_key.erl
@@ -0,0 +1,14 @@
+-module(maps_redundant_branch_is_key).
+-export([test/0]).
+
+test() ->
+ ok = thingy(#{a => 1}),
+ ok = thingy(#{a => 2}),
+ ok.
+
+thingy(Map) ->
+ try
+ #{a := _} = Map,
+ ok
+ catch _ -> error
+ end.
diff --git a/lib/hipe/test/opt_verify_SUITE.erl b/lib/hipe/test/opt_verify_SUITE.erl
index 61952e81d7..86083fa02b 100644
--- a/lib/hipe/test/opt_verify_SUITE.erl
+++ b/lib/hipe/test/opt_verify_SUITE.erl
@@ -1,6 +1,9 @@
-module(opt_verify_SUITE).
--compile([export_all]).
+-export([all/0, groups/0,
+ init_per_suite/1, end_per_suite/1,
+ init_per_group/2, end_per_group/2,
+ call_elim/0, call_elim/1]).
all() ->
[call_elim].
@@ -23,23 +26,6 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
-call_elim_test_file(Config, FileName, Option) ->
- PrivDir = test_server:lookup_config(priv_dir, Config),
- TempOut = test_server:temp_name(filename:join(PrivDir, "call_elim_out")),
- {ok, TestCase} = compile:file(FileName),
- {ok, TestCase} = hipe:c(TestCase, [Option, {pp_range_icode, {file, TempOut}}]),
- {ok, Icode} = file:read_file(TempOut),
- ok = file:delete(TempOut),
- Icode.
-
-substring_count(Icode, Substring) ->
- substring_count(Icode, Substring, 0).
-substring_count(Icode, Substring, N) ->
- case string:str(Icode, Substring) of
- 0 -> N;
- I -> substring_count(lists:nthtail(I, Icode), Substring, N+1)
- end.
-
call_elim() ->
[{doc, "Test that the call elimination optimization pass is ok"}].
call_elim(Config) ->
@@ -60,3 +46,20 @@ call_elim(Config) ->
Icode6 = call_elim_test_file(Config, F3, no_icode_call_elim),
3 = substring_count(binary:bin_to_list(Icode6), "is_key"),
ok.
+
+call_elim_test_file(Config, FileName, Option) ->
+ PrivDir = test_server:lookup_config(priv_dir, Config),
+ TempOut = test_server:temp_name(filename:join(PrivDir, "call_elim_out")),
+ {ok, TestCase} = compile:file(FileName),
+ {ok, TestCase} = hipe:c(TestCase, [Option, {pp_range_icode, {file, TempOut}}]),
+ {ok, Icode} = file:read_file(TempOut),
+ ok = file:delete(TempOut),
+ Icode.
+
+substring_count(Icode, Substring) ->
+ substring_count(Icode, Substring, 0).
+substring_count(Icode, Substring, N) ->
+ case string:str(Icode, Substring) of
+ 0 -> N;
+ I -> substring_count(lists:nthtail(I, Icode), Substring, N+1)
+ end.
diff --git a/lib/hipe/vsn.mk b/lib/hipe/vsn.mk
index e61c1a042c..172d976931 100644
--- a/lib/hipe/vsn.mk
+++ b/lib/hipe/vsn.mk
@@ -1 +1 @@
-HIPE_VSN = 3.15.1
+HIPE_VSN = 3.15.4
diff --git a/lib/hipe/x86/hipe_x86_postpass.erl b/lib/hipe/x86/hipe_x86_postpass.erl
index 939baeccec..4515822a34 100644
--- a/lib/hipe/x86/hipe_x86_postpass.erl
+++ b/lib/hipe/x86/hipe_x86_postpass.erl
@@ -95,7 +95,8 @@ peep([I=#move{src=#x86_temp{reg=Src}, dst=#x86_temp{reg=Dst}},
%% ElimBinALMDouble
%% ----------------
-peep([Move=#move{src=Src, dst=Dst}, Alu=#alu{src=Src, dst=Dst}|Insns], Res, Lst) ->
+peep([Move=#move{src=Src, dst=Dst}, Alu=#alu{src=Src, dst=Dst}|Insns], Res, Lst)
+ when not is_record(Dst, x86_mem) ->
peep([Alu#alu{src=Dst}|Insns], [Move|Res], [elimBinALMDouble|Lst]);