aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hipe
diff options
context:
space:
mode:
Diffstat (limited to 'lib/hipe')
-rw-r--r--lib/hipe/arm/hipe_arm_assemble.erl2
-rw-r--r--lib/hipe/cerl/cerl_prettypr.erl18
-rw-r--r--lib/hipe/cerl/cerl_to_icode.erl8
-rw-r--r--lib/hipe/cerl/erl_bif_types.erl51
-rw-r--r--lib/hipe/cerl/erl_types.erl590
-rw-r--r--lib/hipe/doc/src/hipe_app.xml17
-rw-r--r--lib/hipe/doc/src/notes.xml121
-rw-r--r--lib/hipe/icode/hipe_beam_to_icode.erl51
-rw-r--r--lib/hipe/icode/hipe_icode_primops.erl37
-rw-r--r--lib/hipe/icode/hipe_icode_range.erl6
-rw-r--r--lib/hipe/llvm/hipe_llvm_merge.erl2
-rw-r--r--lib/hipe/main/hipe.app.src2
-rw-r--r--lib/hipe/main/hipe.erl12
-rw-r--r--lib/hipe/ppc/hipe_ppc_assemble.erl2
-rw-r--r--lib/hipe/rtl/Makefile2
-rw-r--r--lib/hipe/rtl/hipe_rtl_arith.inc15
-rw-r--r--lib/hipe/rtl/hipe_rtl_arith_32.erl3
-rw-r--r--lib/hipe/rtl/hipe_rtl_binary.erl144
-rw-r--r--lib/hipe/rtl/hipe_rtl_binary_construct.erl205
-rw-r--r--lib/hipe/rtl/hipe_rtl_binary_match.erl175
-rw-r--r--lib/hipe/rtl/hipe_tagscheme.erl39
-rw-r--r--lib/hipe/sparc/hipe_sparc_assemble.erl2
-rw-r--r--lib/hipe/test/Makefile4
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_arith.erl72
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_beam_instrs.erl102
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_bifs.erl257
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_bignums.erl143
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_boolean.erl47
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_bugs_beam.erl138
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_bugs_hipe.erl463
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_comparisons.erl157
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_exceptions.erl465
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_floats.erl180
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_fun.erl124
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_guards.erl164
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_inline_function.erl73
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_inline_module.erl31
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_issues_beam.erl326
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_issues_hipe.erl153
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_lists.erl61
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_module_info.erl32
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_pattern_match.erl46
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_random.erl238
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_receive.erl56
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_records.erl28
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_strength_reduce.erl65
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_switches.erl52
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_tail_rec.erl39
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_tuples.erl177
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_add.erl10
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_construct.erl177
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_match.erl108
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_split.erl10
-rw-r--r--lib/hipe/test/bs_SUITE_data/bs_utf.erl344
-rw-r--r--lib/hipe/test/hipe_testsuite_driver.erl16
-rw-r--r--lib/hipe/test/sanity_SUITE_data/sanity_comp_timeout.erl28
-rw-r--r--lib/hipe/test/sanity_SUITE_data/sanity_no_zombies.erl21
-rw-r--r--lib/hipe/vsn.mk2
-rw-r--r--lib/hipe/x86/hipe_x86_assemble.erl2
59 files changed, 5306 insertions, 609 deletions
diff --git a/lib/hipe/arm/hipe_arm_assemble.erl b/lib/hipe/arm/hipe_arm_assemble.erl
index 7859e2d4a8..5f98c6593e 100644
--- a/lib/hipe/arm/hipe_arm_assemble.erl
+++ b/lib/hipe/arm/hipe_arm_assemble.erl
@@ -48,7 +48,7 @@ assemble(CompiledCode, Closures, Exports, Options) ->
DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap),
SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap,Closures,Exports),
SlimRefs = hipe_pack_constants:slim_refs(AccRefs),
- Bin = term_to_binary([{?VERSION_STRING(),?HIPE_SYSTEM_CRC},
+ Bin = term_to_binary([{?VERSION_STRING(),?HIPE_ERTS_CHECKSUM},
ConstAlign, ConstSize,
SC,
DataRelocs, % nee LM, LabelMap
diff --git a/lib/hipe/cerl/cerl_prettypr.erl b/lib/hipe/cerl/cerl_prettypr.erl
index 7e8b7f60bd..1a6e6999fe 100644
--- a/lib/hipe/cerl/cerl_prettypr.erl
+++ b/lib/hipe/cerl/cerl_prettypr.erl
@@ -64,8 +64,8 @@
seq_arg/1, seq_body/1, string_lit/1, try_arg/1,
try_body/1, try_vars/1, try_evars/1, try_handler/1,
tuple_es/1, type/1, values_es/1, var_name/1,
- c_map/1, map_arg/1, map_es/1, is_c_map_empty/1,
- c_map_pair/2, map_pair_key/1, map_pair_val/1, map_pair_op/1
+ map_arg/1, map_es/1, is_c_map_empty/1,
+ map_pair_key/1, map_pair_val/1, map_pair_op/1
]).
-define(PAPER, 76).
@@ -499,12 +499,8 @@ lay_literal(Node, Ctxt) ->
lay_cons(Node, Ctxt);
V when is_tuple(V) ->
lay_tuple(Node, Ctxt);
- M when is_map(M), map_size(M) =:= 0 ->
- text("~{}~");
M when is_map(M) ->
- lay_map(c_map([c_map_pair(abstract(K),abstract(V))
- || {K,V} <- maps:to_list(M)]),
- Ctxt)
+ lay_map(Node, Ctxt)
end.
lay_var(Node, Ctxt) ->
@@ -627,12 +623,10 @@ lay_map_pair(Node, Ctxt) ->
K = map_pair_key(Node),
V = map_pair_val(Node),
OpTxt = case concrete(map_pair_op(Node)) of
- assoc -> "::<";
- exact -> "~<"
+ assoc -> "=>";
+ exact -> ":="
end,
- beside(floating(text(OpTxt)),
- beside(lay(K,Ctxt),beside(floating(text(",")), beside(lay(V,Ctxt),
- floating(text(">")))))).
+ beside(lay(K,Ctxt),beside(floating(text(OpTxt)),lay(V,Ctxt))).
lay_let(Node, Ctxt) ->
V = lay_value_list(let_vars(Node), Ctxt),
diff --git a/lib/hipe/cerl/cerl_to_icode.erl b/lib/hipe/cerl/cerl_to_icode.erl
index 97b95f2e7c..ab131c2d01 100644
--- a/lib/hipe/cerl/cerl_to_icode.erl
+++ b/lib/hipe/cerl/cerl_to_icode.erl
@@ -794,9 +794,9 @@ bitstr_gen_op([V], #ctxt{fail=FL, class=guard}, SizeInfo, ConstInfo,
Type, Flags, Base, Offset) ->
SL = new_label(),
case SizeInfo of
- {all,_NewUnit, NewAlign, S1} ->
+ {all, NewUnit, NewAlign, S1} ->
Type = binary,
- Name = {bs_put_binary_all, Flags},
+ Name = {bs_put_binary_all, NewUnit, Flags},
Primop = {hipe_bs_primop, Name},
{add_code([icode_guardop([Offset], Primop,
[V, Base, Offset], SL, FL),
@@ -819,9 +819,9 @@ bitstr_gen_op([V], #ctxt{fail=FL, class=guard}, SizeInfo, ConstInfo,
bitstr_gen_op([V], _Ctxt, SizeInfo, ConstInfo, Type, Flags, Base,
Offset) ->
case SizeInfo of
- {all, _NewUnit, NewAlign, S} ->
+ {all, NewUnit, NewAlign, S} ->
Type = binary,
- Name = {bs_put_binary_all, Flags},
+ Name = {bs_put_binary_all, NewUnit, Flags},
Primop = {hipe_bs_primop, Name},
{add_code([icode_call_primop([Offset], Primop,
[V, Base, Offset])], S),
diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl
index 41a6c731c9..c2fb79c089 100644
--- a/lib/hipe/cerl/erl_bif_types.erl
+++ b/lib/hipe/cerl/erl_bif_types.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2015. 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.
@@ -93,7 +93,7 @@
t_list/0,
t_list/1,
t_list_elements/2,
- t_list_termination/1,
+ t_list_termination/2,
t_mfa/0,
t_module/0,
t_nil/0,
@@ -514,14 +514,15 @@ type(erlang, 'bsl', 2, Xs, Opaques) ->
type(erlang, 'bnot', 1, Xs, Opaques) ->
strict(erlang, 'bnot', 1, Xs,
fun ([X1]) ->
- case arith('bnot', X1, Opaques) of
+ case arith_bnot(X1, Opaques) of
error -> t_integer();
{ok, T} -> T
end
end, Opaques);
%% Guard bif, needs to be here.
type(erlang, abs, 1, Xs, Opaques) ->
- strict(erlang, abs, 1, Xs, fun ([X]) -> X end, Opaques);
+ strict(erlang, abs, 1, Xs,
+ fun ([X1]) -> arith_abs(X1, Opaques) end, Opaques);
%% This returns (-X)-1, so it often gives a negative result.
%% strict(erlang, 'bnot', 1, Xs, fun (_) -> t_integer() end, Opaques);
type(erlang, append, 2, Xs, _Opaques) -> type(erlang, '++', 2, Xs); % alias
@@ -767,6 +768,18 @@ type(erlang, length, 1, Xs, Opaques) ->
%% Guard bif, needs to be here.
type(erlang, map_size, 1, Xs, Opaques) ->
strict(erlang, map_size, 1, Xs, fun (_) -> t_non_neg_integer() end, Opaques);
+type(erlang, make_fun, 3, Xs, Opaques) ->
+ strict(erlang, make_fun, 3, Xs,
+ fun ([_, _, Arity]) ->
+ case t_number_vals(Arity, Opaques) of
+ [N] ->
+ case is_integer(N) andalso 0 =< N andalso N =< 255 of
+ true -> t_fun(N, t_any());
+ false -> t_none()
+ end;
+ _Other -> t_fun()
+ end
+ end, Opaques);
type(erlang, make_tuple, 2, Xs, Opaques) ->
strict(erlang, make_tuple, 2, Xs,
fun ([Int, _]) ->
@@ -1336,8 +1349,8 @@ type(lists, foldr, 3, Xs, _Opaques) -> type(lists, foldl, 3, Xs); % same
type(lists, keydelete, 3, Xs, Opaques) ->
strict(lists, keydelete, 3, Xs,
fun ([_, _, L]) ->
- Term = t_list_termination(L),
- t_sup(Term, erl_types:lift_list_to_pos_empty(L))
+ Term = t_list_termination(L, Opaques),
+ t_sup(Term, erl_types:lift_list_to_pos_empty(L, Opaques))
end, Opaques);
type(lists, keyfind, 3, Xs, Opaques) ->
strict(lists, keyfind, 3, Xs,
@@ -1927,7 +1940,7 @@ negwidth(X, N) ->
false -> negwidth(X, N+1)
end.
-arith('bnot', X1, Opaques) ->
+arith_bnot(X1, Opaques) ->
case t_is_integer(X1, Opaques) of
false -> error;
true ->
@@ -1937,6 +1950,28 @@ arith('bnot', X1, Opaques) ->
infinity_add(infinity_inv(Min1), -1))}
end.
+arith_abs(X1, Opaques) ->
+ case t_is_integer(X1, Opaques) of
+ false ->
+ case t_is_float(X1, Opaques) of
+ true -> t_float();
+ false -> t_number()
+ end;
+ true ->
+ Min1 = number_min(X1, Opaques),
+ Max1 = number_max(X1, Opaques),
+ {NewMin, NewMax} =
+ case infinity_geq(Min1, 0) of
+ true -> {Min1, Max1};
+ false ->
+ case infinity_geq(Max1, 0) of
+ true -> {0, infinity_inv(Min1)};
+ false -> {infinity_inv(Max1), infinity_inv(Min1)}
+ end
+ end,
+ t_from_range(NewMin, NewMax)
+ end.
+
arith_mult(Min1, Max1, Min2, Max2) ->
Tmp_list = [infinity_mult(Min1, Min2), infinity_mult(Min1, Max2),
infinity_mult(Max1, Min2), infinity_mult(Max1, Max2)],
@@ -2338,6 +2373,8 @@ arg_types(erlang, length, 1) ->
%% Guard bif, needs to be here.
arg_types(erlang, map_size, 1) ->
[t_map()];
+arg_types(erlang, make_fun, 3) ->
+ [t_atom(), t_atom(), t_arity()];
arg_types(erlang, make_tuple, 2) ->
[t_non_neg_fixnum(), t_any()]; % the value 0 is OK as first argument
arg_types(erlang, make_tuple, 3) ->
diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl
index 25cf1a7ae1..7a2abc226f 100644
--- a/lib/hipe/cerl/erl_types.erl
+++ b/lib/hipe/cerl/erl_types.erl
@@ -82,7 +82,7 @@
t_form_to_string/1,
t_from_form/4,
t_from_form/5,
- t_from_form_without_remote/2,
+ t_from_form_without_remote/3,
t_check_record_fields/4,
t_check_record_fields/5,
t_from_range/2,
@@ -150,7 +150,7 @@
t_list/0,
t_list/1,
t_list_elements/1, t_list_elements/2,
- t_list_termination/1,
+ t_list_termination/1, t_list_termination/2,
t_map/0,
t_map/1,
t_matchstate/0,
@@ -209,7 +209,7 @@
record_field_diffs_to_string/2,
subst_all_vars_to_any/1,
subst_all_remote/2,
- lift_list_to_pos_empty/1,
+ lift_list_to_pos_empty/1, lift_list_to_pos_empty/2,
is_opaque_type/2,
is_erl_type/1,
atom_to_string/1
@@ -1510,6 +1510,11 @@ t_list_elements(Type, Opaques) ->
list_elements(?list(Contents, _, _)) -> Contents;
list_elements(?nil) -> ?none.
+-spec t_list_termination(erl_type(), opaques()) -> erl_type().
+
+t_list_termination(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun t_list_termination/1).
+
-spec t_list_termination(erl_type()) -> erl_type().
t_list_termination(?nil) -> ?nil;
@@ -1585,6 +1590,11 @@ is_maybe_improper_list(_) -> false.
%% %% false = t_is_subtype(t_nil(), Termination),
%% ?list(Content, Termination, ?any).
+-spec lift_list_to_pos_empty(erl_type(), opaques()) -> erl_type().
+
+lift_list_to_pos_empty(Type, Opaques) ->
+ do_opaque(Type, Opaques, fun lift_list_to_pos_empty/1).
+
-spec lift_list_to_pos_empty(erl_type()) -> erl_type().
lift_list_to_pos_empty(?nil) -> ?nil;
@@ -2701,8 +2711,94 @@ is_compat_args([A1|Args1], [A2|Args2]) ->
is_compat_args([], []) -> true;
is_compat_args(_, _) -> false.
-is_compat_arg(A, A) -> true;
-is_compat_arg(A1, A2) -> t_is_any(A1) orelse t_is_any(A2).
+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)) ->
+ (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)) ->
+ try
+ specialization_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)
+ end;
+is_specialization(?union(List), T2) ->
+ case unify_union(List) of
+ {yes, Type} -> is_specialization(Type, T2);
+ no -> false
+ end;
+is_specialization(T1, ?union(List)) ->
+ case unify_union(List) of
+ {yes, Type} -> is_specialization(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) ->
+ case {unify_union(List1), unify_union(List2)} of
+ {{yes, Type1}, {yes, Type2}} -> {yes, Type1, Type2};
+ {{yes, Type1}, no} -> {yes, Type1, T2};
+ {no, {yes, Type2}} -> {yes, T1, Type2};
+ {no, no} -> no
+ end.
-spec t_inf_lists([erl_type()], [erl_type()]) -> [erl_type()].
@@ -3961,27 +4057,32 @@ mod_name(Mod, Name) ->
-type type_names() :: [type_key() | record_key()].
+-type mta() :: {module(), atom(), arity()}.
+-type mra() :: {module(), atom(), arity()}.
+-type site() :: {'type', mta()} | {'spec', mfa()} | {'record', mra()}.
+
-spec t_from_form(parse_form(), sets:set(mfa()),
- module(), mod_records()) -> erl_type().
+ site(), mod_records()) -> erl_type().
-t_from_form(Form, ExpTypes, Module, RecDict) ->
- t_from_form(Form, ExpTypes, Module, RecDict, dict:new()).
+t_from_form(Form, ExpTypes, Site, RecDict) ->
+ t_from_form(Form, ExpTypes, Site, RecDict, dict:new()).
-spec t_from_form(parse_form(), sets:set(mfa()),
- module(), mod_records(), var_table()) -> erl_type().
+ site(), mod_records(), var_table()) -> erl_type().
-t_from_form(Form, ExpTypes, Module, RecDict, VarDict) ->
- {T, _} = t_from_form1(Form, [], ExpTypes, Module, RecDict, VarDict),
+t_from_form(Form, ExpTypes, Site, RecDict, VarDict) ->
+ {T, _} = t_from_form1(Form, ExpTypes, Site, RecDict, VarDict),
T.
%% Replace external types with with none().
--spec t_from_form_without_remote(parse_form(), type_table()) -> erl_type().
+-spec t_from_form_without_remote(parse_form(), site(), type_table()) ->
+ erl_type().
-t_from_form_without_remote(Form, TypeTable) ->
- Module = mod,
+t_from_form_without_remote(Form, Site, TypeTable) ->
+ Module = site_module(Site),
RecDict = dict:from_list([{Module, TypeTable}]),
ExpTypes = replace_by_none,
- {T, _} = t_from_form1(Form, [], ExpTypes, Module, RecDict, dict:new()),
+ {T, _} = t_from_form1(Form, ExpTypes, Site, RecDict, dict:new()),
T.
%% REC_TYPE_LIMIT is used for limiting the depth of recursive types.
@@ -3995,23 +4096,32 @@ t_from_form_without_remote(Form, TypeTable) ->
-type expand_depth() :: integer().
-t_from_form1(Form, TypeNames, ET, M, MR, V) ->
- t_from_form1(Form, TypeNames, ET, M, MR, V, ?EXPAND_DEPTH).
+-spec t_from_form1(parse_form(), sets:set(mfa()) | 'replace_by_none',
+ site(), mod_records(), var_table()) ->
+ {erl_type(), expand_limit()}.
+
+t_from_form1(Form, ET, Site, MR, V) ->
+ TypeNames = initial_typenames(Site),
+ t_from_form1(Form, TypeNames, ET, Site, MR, V, ?EXPAND_DEPTH).
-t_from_form1(Form, TypeNames, ET, M, MR, V, D) ->
+initial_typenames({type, _MTA}=Site) -> [Site];
+initial_typenames({spec, _MFA}) -> [];
+initial_typenames({record, _MRA}) -> [].
+
+t_from_form1(Form, TypeNames, ET, Site, MR, V, D) ->
L = ?EXPAND_LIMIT,
- {T, L1} = t_from_form(Form, TypeNames, ET, M, MR, V, D, L),
+ {T, L1} = t_from_form(Form, TypeNames, ET, Site, MR, V, D, L),
if
L1 =< 0, D > 1 ->
D1 = D div 2,
- t_from_form1(Form, TypeNames, ET, M, MR, V, D1);
+ t_from_form1(Form, TypeNames, ET, Site, MR, V, D1);
true ->
{T, L1}
end.
-spec t_from_form(parse_form(), type_names(),
sets:set(mfa()) | 'replace_by_none',
- module(), mod_records(), var_table(),
+ site(), mod_records(), var_table(),
expand_depth(), expand_limit())
-> {erl_type(), expand_limit()}.
@@ -4021,193 +4131,194 @@ t_from_form1(Form, TypeNames, ET, M, MR, V, D) ->
%% self() ! {self(), ext_types, {RemMod, Name, ArgsLen}}
%% is called, unless 'replace_by_none' is given.
%%
-%% It is assumed that M can be found in MR.
+%% It is assumed that site_module(S) can be found in MR.
-t_from_form(_, _TypeNames, _ET, _M, _MR, _V, D, L) when D =< 0 ; L =< 0 ->
+t_from_form(_, _TypeNames, _ET, _S, _MR, _V, D, L) when D =< 0 ; L =< 0 ->
{t_any(), L};
-t_from_form({var, _L, '_'}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({var, _L, '_'}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_any(), L};
-t_from_form({var, _L, Name}, _TypeNames, _ET, _M, _MR, V, _D, L) ->
+t_from_form({var, _L, Name}, _TypeNames, _ET, _S, _MR, V, _D, L) ->
case dict:find(Name, V) of
error -> {t_var(Name), L};
{ok, Val} -> {Val, L}
end;
-t_from_form({ann_type, _L, [_Var, Type]}, TypeNames, ET, M, MR, V, D, L) ->
- t_from_form(Type, TypeNames, ET, M, MR, V, D, L);
-t_from_form({paren_type, _L, [Type]}, TypeNames, ET, M, MR, V, D, L) ->
- t_from_form(Type, TypeNames, ET, M, MR, V, D, L);
+t_from_form({ann_type, _L, [_Var, Type]}, TypeNames, ET, S, MR, V, D, L) ->
+ t_from_form(Type, TypeNames, ET, S, MR, V, D, L);
+t_from_form({paren_type, _L, [Type]}, TypeNames, ET, S, MR, V, D, L) ->
+ t_from_form(Type, TypeNames, ET, S, MR, V, D, L);
t_from_form({remote_type, _L, [{atom, _, Module}, {atom, _, Type}, Args]},
- TypeNames, ET, M, MR, V, D, L) ->
- remote_from_form(Module, Type, Args, TypeNames, ET, M, MR, V, D, L);
-t_from_form({atom, _L, Atom}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+ TypeNames, ET, S, MR, V, D, L) ->
+ remote_from_form(Module, Type, Args, TypeNames, ET, S, MR, V, D, L);
+t_from_form({atom, _L, Atom}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_atom(Atom), L};
-t_from_form({integer, _L, Int}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({integer, _L, Int}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_integer(Int), L};
-t_from_form({op, _L, _Op, _Arg} = Op, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({op, _L, _Op, _Arg} = Op, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
case erl_eval:partial_eval(Op) of
{integer, _, Val} ->
{t_integer(Val), L};
_ -> throw({error, io_lib:format("Unable to evaluate type ~w\n", [Op])})
end;
t_from_form({op, _L, _Op, _Arg1, _Arg2} = Op, _TypeNames,
- _ET, _M, _MR, _V, _D, L) ->
+ _ET, _S, _MR, _V, _D, L) ->
case erl_eval:partial_eval(Op) of
{integer, _, Val} ->
{t_integer(Val), L};
_ -> throw({error, io_lib:format("Unable to evaluate type ~w\n", [Op])})
end;
-t_from_form({type, _L, any, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, any, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_any(), L};
-t_from_form({type, _L, arity, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, arity, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_arity(), L};
-t_from_form({type, _L, atom, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, atom, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_atom(), L};
-t_from_form({type, _L, binary, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, binary, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_binary(), L};
t_from_form({type, _L, binary, [Base, Unit]} = Type,
- _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+ _TypeNames, _ET, _S, _MR, _V, _D, L) ->
case {erl_eval:partial_eval(Base), erl_eval:partial_eval(Unit)} of
{{integer, _, B}, {integer, _, U}} when B >= 0, U >= 0 ->
{t_bitstr(U, B), L};
_ -> throw({error, io_lib:format("Unable to evaluate type ~w\n", [Type])})
end;
-t_from_form({type, _L, bitstring, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, bitstring, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_bitstr(), L};
-t_from_form({type, _L, bool, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, bool, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_boolean(), L}; % XXX: Temporarily
-t_from_form({type, _L, boolean, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, boolean, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_boolean(), L};
-t_from_form({type, _L, byte, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, byte, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_byte(), L};
-t_from_form({type, _L, char, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, char, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_char(), L};
-t_from_form({type, _L, float, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, float, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_float(), L};
-t_from_form({type, _L, function, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, function, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_fun(), L};
-t_from_form({type, _L, 'fun', []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, 'fun', []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_fun(), L};
t_from_form({type, _L, 'fun', [{type, _, any}, Range]}, TypeNames,
- ET, M, MR, V, D, L) ->
- {T, L1} = t_from_form(Range, TypeNames, ET, M, MR, V, D - 1, L - 1),
+ ET, S, MR, V, D, L) ->
+ {T, L1} = t_from_form(Range, TypeNames, ET, S, MR, V, D - 1, L - 1),
{t_fun(T), L1};
t_from_form({type, _L, 'fun', [{type, _, product, Domain}, Range]},
- TypeNames, ET, M, MR, V, D, L) ->
- {Dom1, L1} = list_from_form(Domain, TypeNames, ET, M, MR, V, D, L),
- {Ran1, L2} = t_from_form(Range, TypeNames, ET, M, MR, V, D - 1, L1),
+ TypeNames, ET, S, MR, V, D, L) ->
+ {Dom1, L1} = list_from_form(Domain, TypeNames, ET, S, MR, V, D, L),
+ {Ran1, L2} = t_from_form(Range, TypeNames, ET, S, MR, V, D - 1, L1),
{t_fun(Dom1, Ran1), L2};
-t_from_form({type, _L, identifier, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, identifier, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_identifier(), L};
-t_from_form({type, _L, integer, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, integer, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_integer(), L};
-t_from_form({type, _L, iodata, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, iodata, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_iodata(), L};
-t_from_form({type, _L, iolist, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, iolist, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_iolist(), L};
-t_from_form({type, _L, list, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, list, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_list(), L};
-t_from_form({type, _L, list, [Type]}, TypeNames, ET, M, MR, V, D, L) ->
- {T, L1} = t_from_form(Type, TypeNames, ET, M, MR, V, D - 1, L - 1),
+t_from_form({type, _L, list, [Type]}, TypeNames, ET, S, MR, V, D, L) ->
+ {T, L1} = t_from_form(Type, TypeNames, ET, S, MR, V, D - 1, L - 1),
{t_list(T), L1};
-t_from_form({type, _L, map, _}, TypeNames, ET, M, MR, V, D, L) ->
- builtin_type(map, t_map([]), TypeNames, ET, M, MR, V, D, L);
-t_from_form({type, _L, mfa, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, map, _}, TypeNames, ET, S, MR, V, D, L) ->
+ builtin_type(map, t_map([]), TypeNames, ET, S, MR, V, D, L);
+t_from_form({type, _L, mfa, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_mfa(), L};
-t_from_form({type, _L, module, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, module, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_module(), L};
-t_from_form({type, _L, nil, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, nil, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_nil(), L};
-t_from_form({type, _L, neg_integer, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, neg_integer, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_neg_integer(), L};
-t_from_form({type, _L, non_neg_integer, []}, _TypeNames, _ET, _M, _MR,
+t_from_form({type, _L, non_neg_integer, []}, _TypeNames, _ET, _S, _MR,
_V, _D, L) ->
{t_non_neg_integer(), L};
-t_from_form({type, _L, no_return, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, no_return, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_unit(), L};
-t_from_form({type, _L, node, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, node, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_node(), L};
-t_from_form({type, _L, none, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, none, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_none(), L};
-t_from_form({type, _L, nonempty_list, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, nonempty_list, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_nonempty_list(), L};
-t_from_form({type, _L, nonempty_list, [Type]}, TypeNames, ET, M, MR, V, D, L) ->
- {T, L1} = t_from_form(Type, TypeNames, ET, M, MR, V, D, L - 1),
+t_from_form({type, _L, nonempty_list, [Type]}, TypeNames, ET, S, MR, V, D, L) ->
+ {T, L1} = t_from_form(Type, TypeNames, ET, S, MR, V, D, L - 1),
{t_nonempty_list(T), L1};
t_from_form({type, _L, nonempty_improper_list, [Cont, Term]}, TypeNames,
- ET, M, MR, V, D, L) ->
- {T1, L1} = t_from_form(Cont, TypeNames, ET, M, MR, V, D, L - 1),
- {T2, L2} = t_from_form(Term, TypeNames, ET, M, MR, V, D, L1),
+ ET, S, MR, V, D, L) ->
+ {T1, L1} = t_from_form(Cont, TypeNames, ET, S, MR, V, D, L - 1),
+ {T2, L2} = t_from_form(Term, TypeNames, ET, S, MR, V, D, L1),
{t_cons(T1, T2), L2};
t_from_form({type, _L, nonempty_maybe_improper_list, []}, _TypeNames,
- _ET, _M, _MR, _V, _D, L) ->
+ _ET, _S, _MR, _V, _D, L) ->
{t_cons(?any, ?any), L};
t_from_form({type, _L, nonempty_maybe_improper_list, [Cont, Term]},
- TypeNames, ET, M, MR, V, D, L) ->
- {T1, L1} = t_from_form(Cont, TypeNames, ET, M, MR, V, D, L - 1),
- {T2, L2} = t_from_form(Term, TypeNames, ET, M, MR, V, D, L1),
+ TypeNames, ET, S, MR, V, D, L) ->
+ {T1, L1} = t_from_form(Cont, TypeNames, ET, S, MR, V, D, L - 1),
+ {T2, L2} = t_from_form(Term, TypeNames, ET, S, MR, V, D, L1),
{t_cons(T1, T2), L2};
-t_from_form({type, _L, nonempty_string, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, nonempty_string, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_nonempty_string(), L};
-t_from_form({type, _L, number, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, number, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_number(), L};
-t_from_form({type, _L, pid, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, pid, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_pid(), L};
-t_from_form({type, _L, port, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, port, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_port(), L};
-t_from_form({type, _L, pos_integer, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, pos_integer, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_pos_integer(), L};
t_from_form({type, _L, maybe_improper_list, []}, _TypeNames,
- _ET, _M, _MR, _V, _D, L) ->
+ _ET, _S, _MR, _V, _D, L) ->
{t_maybe_improper_list(), L};
t_from_form({type, _L, maybe_improper_list, [Content, Termination]},
- TypeNames, ET, M, MR, V, D, L) ->
- {T1, L1} = t_from_form(Content, TypeNames, ET, M, MR, V, D, L - 1),
- {T2, L2} = t_from_form(Termination, TypeNames, ET, M, MR, V, D, L1),
+ TypeNames, ET, S, MR, V, D, L) ->
+ {T1, L1} = t_from_form(Content, TypeNames, ET, S, MR, V, D, L - 1),
+ {T2, L2} = t_from_form(Termination, TypeNames, ET, S, MR, V, D, L1),
{t_maybe_improper_list(T1, T2), L2};
-t_from_form({type, _L, product, Elements}, TypeNames, ET, M, MR, V, D, L) ->
- {Lst, L1} = list_from_form(Elements, TypeNames, ET, M, MR, V, D - 1, L),
+t_from_form({type, _L, product, Elements}, TypeNames, ET, S, MR, V, D, L) ->
+ {Lst, L1} = list_from_form(Elements, TypeNames, ET, S, MR, V, D - 1, L),
{t_product(Lst), L1};
t_from_form({type, _L, range, [From, To]} = Type,
- _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+ _TypeNames, _ET, _S, _MR, _V, _D, L) ->
case {erl_eval:partial_eval(From), erl_eval:partial_eval(To)} of
{{integer, _, FromVal}, {integer, _, ToVal}} ->
{t_from_range(FromVal, ToVal), L};
_ -> throw({error, io_lib:format("Unable to evaluate type ~w\n", [Type])})
end;
-t_from_form({type, _L, record, [Name|Fields]}, TypeNames, ET, M, MR, V, D, L) ->
- record_from_form(Name, Fields, TypeNames, ET, M, MR, V, D, L);
-t_from_form({type, _L, reference, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, record, [Name|Fields]}, TypeNames, ET, S, MR, V, D, L) ->
+ record_from_form(Name, Fields, TypeNames, ET, S, MR, V, D, L);
+t_from_form({type, _L, reference, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_reference(), L};
-t_from_form({type, _L, string, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, string, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_string(), L};
-t_from_form({type, _L, term, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, term, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_any(), L};
-t_from_form({type, _L, timeout, []}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, timeout, []}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_timeout(), L};
-t_from_form({type, _L, tuple, any}, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+t_from_form({type, _L, tuple, any}, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{t_tuple(), L};
-t_from_form({type, _L, tuple, Args}, TypeNames, ET, M, MR, V, D, L) ->
- {Lst, L1} = list_from_form(Args, TypeNames, ET, M, MR, V, D - 1, L),
+t_from_form({type, _L, tuple, Args}, TypeNames, ET, S, MR, V, D, L) ->
+ {Lst, L1} = list_from_form(Args, TypeNames, ET, S, MR, V, D - 1, L),
{t_tuple(Lst), L1};
-t_from_form({type, _L, union, Args}, TypeNames, ET, M, MR, V, D, L) ->
- {Lst, L1} = list_from_form(Args, TypeNames, ET, M, MR, V, D, L),
+t_from_form({type, _L, union, Args}, TypeNames, ET, S, MR, V, D, L) ->
+ {Lst, L1} = list_from_form(Args, TypeNames, ET, S, MR, V, D, L),
{t_sup(Lst), L1};
-t_from_form({user_type, _L, Name, Args}, TypeNames, ET, M, MR, V, D, L) ->
- type_from_form(Name, Args, TypeNames, ET, M, MR, V, D, L);
-t_from_form({type, _L, Name, Args}, TypeNames, ET, M, MR, V, D, L) ->
+t_from_form({user_type, _L, Name, Args}, TypeNames, ET, S, MR, V, D, L) ->
+ type_from_form(Name, Args, TypeNames, ET, S, MR, V, D, L);
+t_from_form({type, _L, Name, Args}, TypeNames, ET, S, MR, V, D, L) ->
%% Compatibility: modules compiled before Erlang/OTP 18.0.
- type_from_form(Name, Args, TypeNames, ET, M, MR, V, D, L);
+ type_from_form(Name, Args, TypeNames, ET, S, MR, V, D, L);
t_from_form({opaque, _L, Name, {Mod, Args, Rep}}, _TypeNames,
- _ET, _M, _MR, _V, _D, L) ->
+ _ET, _S, _MR, _V, _D, L) ->
%% XXX. To be removed.
{t_opaque(Mod, Name, Args, Rep), L}.
-builtin_type(Name, Type, TypeNames, ET, M, MR, V, D, L) ->
+builtin_type(Name, Type, TypeNames, ET, Site, MR, V, D, L) ->
+ M = site_module(Site),
case dict:find(M, MR) of
{ok, R} ->
case lookup_type(Name, 0, R) of
{_, {{_M, _FL, _F, _A}, _T}} ->
- type_from_form(Name, [], TypeNames, ET, M, MR, V, D, L);
+ type_from_form(Name, [], TypeNames, ET, Site, MR, V, D, L);
error ->
{Type, L}
end;
@@ -4215,92 +4326,107 @@ builtin_type(Name, Type, TypeNames, ET, M, MR, V, D, L) ->
{Type, L}
end.
-type_from_form(Name, Args, TypeNames, ET, M, MR, V, D, L) ->
+type_from_form(Name, Args, TypeNames, ET, Site0, MR, V, D, L) ->
ArgsLen = length(Args),
- {ArgTypes, L1} = list_from_form(Args, TypeNames, ET, M, MR, V, D, L),
- {ok, R} = dict:find(M, MR),
+ Module = site_module(Site0),
+ {ok, R} = dict:find(Module, MR),
+ TypeName = {type, {Module, Name, ArgsLen}},
case lookup_type(Name, ArgsLen, R) of
{type, {{Module, _FileName, Form, ArgNames}, _Type}} ->
- TypeName = {type, Module, Name, ArgsLen},
case can_unfold_more(TypeName, TypeNames) of
true ->
+ NewTypeNames = [TypeName|TypeNames],
+ {ArgTypes, L1} =
+ list_from_form(Args, TypeNames, ET, Site0, MR, V, D, L),
List = lists:zip(ArgNames, ArgTypes),
TmpV = dict:from_list(List),
- t_from_form(Form, [TypeName|TypeNames], ET, M, MR, TmpV, D, L1);
+ Site = TypeName,
+ t_from_form(Form, NewTypeNames, ET, Site, MR, TmpV, D, L1);
false ->
- {t_any(), L1}
+ {t_any(), L}
end;
{opaque, {{Module, _FileName, Form, ArgNames}, Type}} ->
- TypeName = {opaque, Module, Name, ArgsLen},
- {Rep, L2} =
- case can_unfold_more(TypeName, TypeNames) of
- true ->
- List = lists:zip(ArgNames, ArgTypes),
- TmpV = dict:from_list(List),
- t_from_form(Form, [TypeName|TypeNames], ET, M, MR, TmpV, D, L1);
- false -> {t_any(), L1}
- end,
- Rep1 = choose_opaque_type(Rep, Type),
- Rep2 = case t_is_none(Rep1) of
- true -> Rep1;
- false ->
- Args2 = [subst_all_vars_to_any(ArgType) ||
- ArgType <- ArgTypes],
- t_opaque(Module, Name, Args2, Rep1)
- end,
- {Rep2, L2};
+ case can_unfold_more(TypeName, TypeNames) of
+ true ->
+ NewTypeNames = [TypeName|TypeNames],
+ {ArgTypes, L1} =
+ list_from_form(Args, NewTypeNames, ET, Site0, MR, V, D, L),
+ List = lists:zip(ArgNames, ArgTypes),
+ TmpV = dict:from_list(List),
+ Site = TypeName,
+ {Rep, L2} =
+ t_from_form(Form, NewTypeNames, ET, Site, MR, TmpV, D, L1),
+ Rep1 = choose_opaque_type(Rep, Type),
+ Rep2 = case cannot_have_opaque(Rep1, TypeName, TypeNames) of
+ true -> Rep1;
+ false ->
+ ArgTypes2 = subst_all_vars_to_any_list(ArgTypes),
+ t_opaque(Module, Name, ArgTypes2, Rep1)
+ end,
+ {Rep2, L2};
+ false -> {t_any(), L}
+ end;
error ->
Msg = io_lib:format("Unable to find type ~w/~w\n", [Name, ArgsLen]),
throw({error, Msg})
end.
-remote_from_form(RemMod, Name, Args, TypeNames, ET, M, MR, V, D, L) ->
- {ArgTypes, L1} = list_from_form(Args, TypeNames, ET, M, MR, V, D, L),
+remote_from_form(RemMod, Name, Args, TypeNames, ET, S, MR, V, D, L) ->
if
ET =:= replace_by_none ->
- {t_none(), L1};
+ {t_none(), L};
true ->
ArgsLen = length(Args),
+ MFA = {RemMod, Name, ArgsLen},
case dict:find(RemMod, MR) of
error ->
- self() ! {self(), ext_types, {RemMod, Name, ArgsLen}},
- {t_any(), L1};
+ self() ! {self(), ext_types, MFA},
+ {t_any(), L};
{ok, RemDict} ->
- MFA = {RemMod, Name, ArgsLen},
+ RemType = {type, MFA},
case sets:is_element(MFA, ET) of
true ->
case lookup_type(Name, ArgsLen, RemDict) of
{type, {{_Mod, _FileLine, Form, ArgNames}, _Type}} ->
- RemType = {type, RemMod, Name, ArgsLen},
case can_unfold_more(RemType, TypeNames) of
true ->
+ NewTypeNames = [RemType|TypeNames],
+ {ArgTypes, L1} = list_from_form(Args, TypeNames,
+ ET, S, MR, V, D, L),
List = lists:zip(ArgNames, ArgTypes),
TmpVarDict = dict:from_list(List),
- NewTypeNames = [RemType|TypeNames],
+ Site = RemType,
t_from_form(Form, NewTypeNames, ET,
- RemMod, MR, TmpVarDict, D, L1);
+ Site, MR, TmpVarDict, D, L1);
false ->
- {t_any(), L1}
+ {t_any(), L}
end;
{opaque, {{Mod, _FileLine, Form, ArgNames}, Type}} ->
- RemType = {opaque, RemMod, Name, ArgsLen},
- List = lists:zip(ArgNames, ArgTypes),
- TmpVarDict = dict:from_list(List),
- {NewRep, L2} =
- case can_unfold_more(RemType, TypeNames) of
- true ->
- NewTypeNames = [RemType|TypeNames],
- t_from_form(Form, NewTypeNames, ET, RemMod, MR,
- TmpVarDict, D, L1);
- false ->
- {t_any(), L1}
- end,
- NewRep1 = choose_opaque_type(NewRep, Type),
- NewRep2 = case t_is_none(NewRep1) of
- true -> NewRep1;
- false -> t_opaque(Mod, Name, ArgTypes, NewRep1)
- end,
- {NewRep2, L2};
+ case can_unfold_more(RemType, TypeNames) of
+ true ->
+ NewTypeNames = [RemType|TypeNames],
+ {ArgTypes, L1} = list_from_form(Args, NewTypeNames,
+ ET, S, MR, V, D, L),
+ List = lists:zip(ArgNames, ArgTypes),
+ TmpVarDict = dict:from_list(List),
+ Site = RemType,
+ {NewRep, L2} =
+ t_from_form(Form, NewTypeNames, ET, Site, MR,
+ TmpVarDict, D, L1),
+ NewRep1 = choose_opaque_type(NewRep, Type),
+ NewRep2 =
+ case
+ cannot_have_opaque(NewRep1, RemType, TypeNames)
+ of
+ true -> NewRep1;
+ false ->
+ ArgTypes2 = subst_all_vars_to_any_list(ArgTypes),
+ t_opaque(Mod, Name, ArgTypes2, NewRep1)
+ end,
+ {NewRep2, L2};
+ false ->
+ {t_any(), L}
+ end;
error ->
Msg = io_lib:format("Unable to find remote type ~w:~w()\n",
[RemMod, Name]),
@@ -4308,11 +4434,14 @@ remote_from_form(RemMod, Name, Args, TypeNames, ET, M, MR, V, D, L) ->
end;
false ->
self() ! {self(), ext_types, {RemMod, Name, ArgsLen}},
- {t_any(), L1}
+ {t_any(), L}
end
end
end.
+subst_all_vars_to_any_list(Types) ->
+ [subst_all_vars_to_any(Type) || Type <- Types].
+
%% Opaque types (both local and remote) are problematic when it comes
%% to the limits (TypeNames, D, and L). The reason is that if any() is
%% substituted for a more specialized subtype of an opaque type, the
@@ -4332,22 +4461,24 @@ choose_opaque_type(Type, DeclType) ->
false -> DeclType
end.
-record_from_form({atom, _, Name}, ModFields, TypeNames, ET, M, MR, V, D, L) ->
+record_from_form({atom, _, Name}, ModFields, TypeNames, ET, S, MR, V, D, L) ->
case can_unfold_more({record, Name}, TypeNames) of
true ->
+ M = site_module(S),
{ok, R} = dict:find(M, MR),
case lookup_record(Name, R) of
{ok, DeclFields} ->
NewTypeNames = [{record, Name}|TypeNames],
+ S1 = {record, {M, Name, length(DeclFields)}},
{GetModRec, L1} = get_mod_record(ModFields, DeclFields,
- NewTypeNames, ET, M, MR, V, D, L),
+ NewTypeNames, ET, S1, MR, V, D, L),
case GetModRec of
{error, FieldName} ->
throw({error, io_lib:format("Illegal declaration of #~w{~w}\n",
[Name, FieldName])});
{ok, NewFields} ->
{NewFields1, L2} =
- fields_from_form(NewFields, NewTypeNames, ET, M, MR,
+ fields_from_form(NewFields, NewTypeNames, ET, S1, MR,
dict:new(), D, L1),
Rec = t_tuple(
[t_atom(Name)|[Type
@@ -4361,12 +4492,12 @@ record_from_form({atom, _, Name}, ModFields, TypeNames, ET, M, MR, V, D, L) ->
{t_any(), L}
end.
-get_mod_record([], DeclFields, _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+get_mod_record([], DeclFields, _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{{ok, DeclFields}, L};
-get_mod_record(ModFields, DeclFields, TypeNames, ET, M, MR, V, D, L) ->
+get_mod_record(ModFields, DeclFields, TypeNames, ET, S, MR, V, D, L) ->
DeclFieldsDict = lists:keysort(1, DeclFields),
{ModFieldsDict, L1} =
- build_field_dict(ModFields, TypeNames, ET, M, MR, V, D, L),
+ build_field_dict(ModFields, TypeNames, ET, S, MR, V, D, L),
case get_mod_record_types(DeclFieldsDict, ModFieldsDict, []) of
{error, _FieldName} = Error -> {Error, L1};
{ok, FinalKeyDict} ->
@@ -4375,17 +4506,17 @@ get_mod_record(ModFields, DeclFields, TypeNames, ET, M, MR, V, D, L) ->
{{ok, Fields}, L1}
end.
-build_field_dict(FieldTypes, TypeNames, ET, M, MR, V, D, L) ->
- build_field_dict(FieldTypes, TypeNames, ET, M, MR, V, D, L, []).
+build_field_dict(FieldTypes, TypeNames, ET, S, MR, V, D, L) ->
+ build_field_dict(FieldTypes, TypeNames, ET, S, MR, V, D, L, []).
build_field_dict([{type, _, field_type, [{atom, _, Name}, Type]}|Left],
- TypeNames, ET, M, MR, V, D, L, Acc) ->
- {T, L1} = t_from_form(Type, TypeNames, ET, M, MR, V, D, L - 1),
+ TypeNames, ET, S, MR, V, D, L, Acc) ->
+ {T, L1} = t_from_form(Type, TypeNames, ET, S, MR, V, D, L - 1),
NewAcc = [{Name, Type, T}|Acc],
{Dict, L2} =
- build_field_dict(Left, TypeNames, ET, M, MR, V, D, L1, NewAcc),
+ build_field_dict(Left, TypeNames, ET, S, MR, V, D, L1, NewAcc),
{Dict, L2};
-build_field_dict([], _TypeNames, _ET, _M, _MR, _V, _D, L, Acc) ->
+build_field_dict([], _TypeNames, _ET, _S, _MR, _V, _D, L, Acc) ->
{lists:keysort(1, Acc), L}.
get_mod_record_types([{FieldName, _Abstr, _DeclType}|Left1],
@@ -4404,88 +4535,94 @@ get_mod_record_types(_, [{FieldName2, _FormType, _ModType}|_], _Acc) ->
%% It is important to create a limited version of the record type
%% since nested record types can otherwise easily result in huge
%% terms.
-fields_from_form([], _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+fields_from_form([], _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{[], L};
-fields_from_form([{Name, Abstr, _Type}|Tail], TypeNames, ET, M, MR,
+fields_from_form([{Name, Abstr, _Type}|Tail], TypeNames, ET, S, MR,
V, D, L) ->
- {T, L1} = t_from_form(Abstr, TypeNames, ET, M, MR, V, D, L),
- {F, L2} = fields_from_form(Tail, TypeNames, ET, M, MR, V, D, L1),
+ {T, L1} = t_from_form(Abstr, TypeNames, ET, S, MR, V, D, L),
+ {F, L2} = fields_from_form(Tail, TypeNames, ET, S, MR, V, D, L1),
{[{Name, T}|F], L2}.
-list_from_form([], _TypeNames, _ET, _M, _MR, _V, _D, L) ->
+list_from_form([], _TypeNames, _ET, _S, _MR, _V, _D, L) ->
{[], L};
-list_from_form([H|Tail], TypeNames, ET, M, MR, V, D, L) ->
- {H1, L1} = t_from_form(H, TypeNames, ET, M, MR, V, D, L - 1),
- {T1, L2} = list_from_form(Tail, TypeNames, ET, M, MR, V, D, L1),
+list_from_form([H|Tail], TypeNames, ET, S, MR, V, D, L) ->
+ {H1, L1} = t_from_form(H, TypeNames, ET, S, MR, V, D, L - 1),
+ {T1, L2} = list_from_form(Tail, TypeNames, ET, S, MR, V, D, L1),
{[H1|T1], L2}.
--spec t_check_record_fields(parse_form(), sets:set(mfa()), module(),
+-spec t_check_record_fields(parse_form(), sets:set(mfa()), site(),
mod_records()) -> ok.
-t_check_record_fields(Form, ExpTypes, Module, RecDict) ->
- t_check_record_fields(Form, ExpTypes, Module, RecDict, dict:new()).
+t_check_record_fields(Form, ExpTypes, Site, RecDict) ->
+ t_check_record_fields(Form, ExpTypes, Site, RecDict, dict:new()).
--spec t_check_record_fields(parse_form(), sets:set(mfa()), module(),
+-spec t_check_record_fields(parse_form(), sets:set(mfa()), site(),
mod_records(), var_table()) -> ok.
%% If there is something wrong with parse_form()
%% throw({error, io_lib:chars()} is called.
-t_check_record_fields({var, _L, _}, _ET, _M, _MR, _V) -> ok;
-t_check_record_fields({ann_type, _L, [_Var, Type]}, ET, M, MR, V) ->
- t_check_record_fields(Type, ET, M, MR, V);
-t_check_record_fields({paren_type, _L, [Type]}, ET, M, MR, V) ->
- t_check_record_fields(Type, ET, M, MR, V);
+t_check_record_fields({var, _L, _}, _ET, _S, _MR, _V) -> ok;
+t_check_record_fields({ann_type, _L, [_Var, Type]}, ET, S, MR, V) ->
+ t_check_record_fields(Type, ET, S, MR, V);
+t_check_record_fields({paren_type, _L, [Type]}, ET, S, MR, V) ->
+ t_check_record_fields(Type, ET, S, MR, V);
t_check_record_fields({remote_type, _L, [{atom, _, _}, {atom, _, _}, Args]},
- ET, M, MR, V) ->
- list_check_record_fields(Args, ET, M, MR, V);
-t_check_record_fields({atom, _L, _}, _ET, _M, _MR, _V) -> ok;
-t_check_record_fields({integer, _L, _}, _ET, _M, _MR, _V) -> ok;
-t_check_record_fields({op, _L, _Op, _Arg}, _ET, _M, _MR, _V) -> ok;
-t_check_record_fields({op, _L, _Op, _Arg1, _Arg2}, _ET, _M, _MR, _V) -> ok;
-t_check_record_fields({type, _L, tuple, any}, _ET, _M, _MR, _V) -> ok;
-t_check_record_fields({type, _L, map, any}, _ET, _M, _MR, _V) -> ok;
-t_check_record_fields({type, _L, binary, [_Base, _Unit]}, _ET, _M, _MR, _V) ->
+ ET, S, MR, V) ->
+ list_check_record_fields(Args, ET, S, MR, V);
+t_check_record_fields({atom, _L, _}, _ET, _S, _MR, _V) -> ok;
+t_check_record_fields({integer, _L, _}, _ET, _S, _MR, _V) -> ok;
+t_check_record_fields({op, _L, _Op, _Arg}, _ET, _S, _MR, _V) -> ok;
+t_check_record_fields({op, _L, _Op, _Arg1, _Arg2}, _ET, _S, _MR, _V) -> ok;
+t_check_record_fields({type, _L, tuple, any}, _ET, _S, _MR, _V) -> ok;
+t_check_record_fields({type, _L, map, any}, _ET, _S, _MR, _V) -> ok;
+t_check_record_fields({type, _L, binary, [_Base, _Unit]}, _ET, _S, _MR, _V) ->
ok;
t_check_record_fields({type, _L, 'fun', [{type, _, any}, Range]},
- ET, M, MR, V) ->
- t_check_record_fields(Range, ET, M, MR, V);
-t_check_record_fields({type, _L, range, [_From, _To]}, _ET, _M, _MR, _V) ->
+ ET, S, MR, V) ->
+ t_check_record_fields(Range, ET, S, MR, V);
+t_check_record_fields({type, _L, range, [_From, _To]}, _ET, _S, _MR, _V) ->
ok;
-t_check_record_fields({type, _L, record, [Name|Fields]}, ET, M, MR, V) ->
- check_record(Name, Fields, ET, M, MR, V);
-t_check_record_fields({type, _L, _, Args}, ET, M, MR, V) ->
- list_check_record_fields(Args, ET, M, MR, V);
-t_check_record_fields({user_type, _L, _Name, Args}, ET, M, MR, V) ->
- list_check_record_fields(Args, ET, M, MR, V).
-
-check_record({atom, _, Name}, ModFields, ET, M, MR, V) ->
+t_check_record_fields({type, _L, record, [Name|Fields]}, ET, S, MR, V) ->
+ check_record(Name, Fields, ET, S, MR, V);
+t_check_record_fields({type, _L, _, Args}, ET, S, MR, V) ->
+ list_check_record_fields(Args, ET, S, MR, V);
+t_check_record_fields({user_type, _L, _Name, Args}, ET, S, MR, V) ->
+ list_check_record_fields(Args, ET, S, MR, V).
+
+check_record({atom, _, Name}, ModFields, ET, Site, MR, V) ->
+ M = site_module(Site),
{ok, R} = dict:find(M, MR),
{ok, DeclFields} = lookup_record(Name, R),
- case check_fields(ModFields, DeclFields, ET, M, MR, V) of
+ case check_fields(Name, ModFields, DeclFields, ET, Site, MR, V) of
{error, FieldName} ->
throw({error, io_lib:format("Illegal declaration of #~w{~w}\n",
[Name, FieldName])});
ok -> ok
end.
-check_fields([{type, _, field_type, [{atom, _, Name}, Abstr]}|Left],
- DeclFields, ET, M, MR, V) ->
- Type = t_from_form(Abstr, ET, M, MR, V),
+check_fields(RecName, [{type, _, field_type, [{atom, _, Name}, Abstr]}|Left],
+ DeclFields, ET, Site0, MR, V) ->
+ M = site_module(Site0),
+ Site = {record, {M, RecName, length(DeclFields)}},
+ Type = t_from_form(Abstr, ET, Site, MR, V),
{Name, _, DeclType} = lists:keyfind(Name, 1, DeclFields),
TypeNoVars = subst_all_vars_to_any(Type),
case t_is_subtype(TypeNoVars, DeclType) of
false -> {error, Name};
- true -> check_fields(Left, DeclFields, ET, M, MR, V)
+ true -> check_fields(RecName, Left, DeclFields, ET, Site0, MR, V)
end;
-check_fields([], _Decl, _ET, _M, _MR, _V) ->
+check_fields(_RecName, [], _Decl, _ET, _Site, _MR, _V) ->
ok.
-list_check_record_fields([], _ET, _M, _MR, _V) ->
+list_check_record_fields([], _ET, _S, _MR, _V) ->
ok;
-list_check_record_fields([H|Tail], ET, M, MR, V) ->
- ok = t_check_record_fields(H, ET, M, MR, V),
- list_check_record_fields(Tail, ET, M, MR, V).
+list_check_record_fields([H|Tail], ET, S, MR, V) ->
+ ok = t_check_record_fields(H, ET, S, MR, V),
+ list_check_record_fields(Tail, ET, S, MR, V).
+
+site_module({_, {Module, _, _}}) ->
+ Module.
-spec t_var_names([erl_type()]) -> [atom()].
@@ -4580,8 +4717,9 @@ t_form_to_string({type, _L, Name, []} = T) ->
M = mod,
D0 = dict:new(),
MR = dict:from_list([{M, D0}]),
+ S = {type, {M,Name,0}},
{T1, _} =
- t_from_form(T, [], sets:new(), M, MR, D0, _Deep=1000, _ALot=100000),
+ t_from_form(T, [], sets:new(), S, MR, D0, _Deep=1000, _ALot=100000),
t_to_string(T1)
catch throw:{error, _} -> atom_to_string(Name) ++ "()"
end;
@@ -4673,6 +4811,12 @@ lookup_type(Name, Arity, RecDict) ->
type_is_defined(TypeOrOpaque, Name, Arity, RecDict) ->
dict:is_key({TypeOrOpaque, Name, Arity}, RecDict).
+cannot_have_opaque(Type, TypeName, TypeNames) ->
+ t_is_none(Type) orelse is_recursive(TypeName, TypeNames).
+
+is_recursive(TypeName, TypeNames) ->
+ lists:member(TypeName, TypeNames).
+
can_unfold_more(TypeName, TypeNames) ->
Fun = fun(E, Acc) -> case E of TypeName -> Acc + 1; _ -> Acc end end,
lists:foldl(Fun, 0, TypeNames) < ?REC_TYPE_LIMIT.
diff --git a/lib/hipe/doc/src/hipe_app.xml b/lib/hipe/doc/src/hipe_app.xml
index 98fec900af..bf4bdbb3b3 100644
--- a/lib/hipe/doc/src/hipe_app.xml
+++ b/lib/hipe/doc/src/hipe_app.xml
@@ -37,15 +37,14 @@
<description>
<p>
The normal way to native-compile an Erlang module using HiPE is to include the atom native
- in the Erlang compiler options, as in:
- <code>
- 1> <input>c(my_module, [native]).</input></code>
- Options to the HiPE compiler are then passed as follows:
- <code>
- 1> <input>c(my_module, [native,{hipe,Options}]).</input></code>
- For on-line help in the Erlang shell, call <c>hipe:help()</c>.
- Details on HiPE compiler options are given by <c>hipe:help_options()</c>.
- </p>
+ in the Erlang compiler options, as in:</p>
+ <pre>
+ 1> <input>c(my_module, [native]).</input></pre>
+ <p>Options to the HiPE compiler are then passed as follows:</p>
+ <pre>
+ 1> <input>c(my_module, [native,{hipe,Options}]).</input></pre>
+ <p>For on-line help in the Erlang shell, call <c>hipe:help()</c>.
+ Details on HiPE compiler options are given by <c>hipe:help_options()</c>.</p>
</description>
<section>
<title>SEE ALSO</title>
diff --git a/lib/hipe/doc/src/notes.xml b/lib/hipe/doc/src/notes.xml
index 33a18ff7ef..b5b13948e9 100644
--- a/lib/hipe/doc/src/notes.xml
+++ b/lib/hipe/doc/src/notes.xml
@@ -31,6 +31,95 @@
</header>
<p>This document describes the changes made to HiPE.</p>
+<section><title>Hipe 3.14</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix hipe bug causing segfaults when native code
+ constructs binaries starting with a zero-length integer
+ field.</p>
+ <p>
+ Own Id: OTP-13048</p>
+ </item>
+ <item>
+ <p>
+ Reintroduce the <c>erlang:make_fun/3</c> BIF in
+ erl_bif_types.</p>
+ <p>
+ Own Id: OTP-13068</p>
+ </item>
+ <item>
+ <p>
+ In certain cases of matching with very big binaries, the
+ HiPE compiler generated code that would fail the match,
+ even in cases that the matching was successful. The
+ problem was more quite noticeable on 32-bit platforms.</p>
+ <p>
+ Own Id: OTP-13092</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ mikpe/hipe_x86_signal-musl-support</p>
+ <p>
+ Own Id: OTP-13159</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Hipe 3.13</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix bugs concerning <c>erlang:abs/1</c>. </p>
+ <p>
+ Own Id: OTP-12948</p>
+ </item>
+ <item>
+ <p> Fix a bug concerning <c>lists:keydelete/3</c> with
+ union and opaque types. </p>
+ <p>
+ Own Id: OTP-12949</p>
+ </item>
+ <item>
+ <p>
+ A beam file compiled by hipe for an incompatible runtime
+ system was sometimes not rejected by the loader, which
+ could lead to vm crash. This fix will also allow the same
+ hipe compiler to be used by both normal and debug-built
+ vm.</p>
+ <p>
+ Own Id: OTP-12962</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ New function <c>hipe:erts_checksum/0</c> which returns a
+ value identifying the target runtime system for the
+ compiler. Used by dialyzer for its beam cache directory.</p>
+ <p>
+ Own Id: OTP-12963 Aux Id: OTP-12962, OTP-12964 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Hipe 3.12</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -275,22 +364,28 @@
<p>
EEP43: New data type - Maps</p>
<p>
- With Maps you may for instance: <taglist> <item><c>M0 =
- #{ a =&gt; 1, b =&gt; 2}, % create
- associations</c></item> <item><c>M1 = M0#{ a := 10 }, %
- update values</c></item> <item><c>M2 = M1#{ "hi" =&gt;
- "hello"}, % add new associations</c></item> <item><c>#{
- "hi" := V1, a := V2, b := V3} = M2. % match keys with
- values</c></item> </taglist></p>
+ With Maps you may for instance:</p>
+ <taglist>
+ <tag/> <item><c>M0 = #{ a =&gt; 1, b =&gt; 2}, % create
+ associations</c></item>
+ <tag/><item><c>M1 = M0#{ a := 10 }, % update values</c></item>
+ <tag/><item><c>M2 = M1#{ "hi" =&gt;
+ "hello"}, % add new associations</c></item>
+ <tag/><item><c>#{ "hi" := V1, a := V2, b := V3} = M2.
+ % match keys with values</c></item>
+ </taglist>
<p>
For information on how to use Maps please see Map Expressions in the
<seealso marker="doc/reference_manual:expressions#map_expressions">
Reference Manual</seealso>.</p>
<p>
The current implementation is without the following
- features: <taglist> <item>No variable keys</item>
- <item>No single value access</item> <item>No map
- comprehensions</item> </taglist></p>
+ features:</p>
+ <taglist>
+ <tag/><item>No variable keys</item>
+ <tag/><item>No single value access</item>
+ <tag/><item>No map comprehensions</item>
+ </taglist>
<p>
Note that Maps is <em>experimental</em> during OTP 17.0.</p>
<p>
@@ -558,19 +653,17 @@
<section><title>Fixed Bugs and Malfunctions</title>
<list>
<item>
- <p>
<list> <item><p>No warnings for underspecs with remote
types</p></item> <item><p> Fix crash in Typer</p></item>
<item><p>Fix Dialyzer's warning for its own
code</p></item> <item><p>Fix Dialyzer's warnings in
HiPE</p></item> <item><p>Add file/line info in a
particular Dialyzer crash</p></item> <item><p>Update
- inets test results</p></item> </list></p>
+ inets test results</p></item> </list>
<p>
Own Id: OTP-9758</p>
</item>
<item>
- <p>
<list> <item><p>Correct callback spec in application
module</p></item> <item><p>Refine warning about callback
specs with extra ranges</p></item> <item><p>Cleanup
@@ -581,7 +674,7 @@
analysis</p></item> <item><p>Fix crash in
Dialyzer</p></item> <item><p>Variable substitution was
not generalizing any unknown variables.</p></item>
- </list></p>
+ </list>
<p>
Own Id: OTP-9776</p>
</item>
diff --git a/lib/hipe/icode/hipe_beam_to_icode.erl b/lib/hipe/icode/hipe_beam_to_icode.erl
index 0c7bdb788a..37c6ba9c60 100644
--- a/lib/hipe/icode/hipe_beam_to_icode.erl
+++ b/lib/hipe/icode/hipe_beam_to_icode.erl
@@ -881,6 +881,15 @@ trans_fun([{bs_init_bits,{f,Lbl},Size,_Words,_LiveRegs,{field_flags,Flags0},X}|
trans_fun([{bs_add, {f,Lbl}, [Old,New,Unit], Res}|Instructions], Env) ->
Dst = mk_var(Res),
Temp = mk_var(new),
+ {FailLblName, FailCode} =
+ if Lbl =:= 0 ->
+ FailLbl = mk_label(new),
+ {hipe_icode:label_name(FailLbl),
+ [FailLbl,
+ hipe_icode:mk_fail([hipe_icode:mk_const(badarg)], error)]};
+ true ->
+ {map_label(Lbl), []}
+ end,
MultIs =
case {New,Unit} of
{{integer, NewInt}, _} ->
@@ -890,40 +899,26 @@ trans_fun([{bs_add, {f,Lbl}, [Old,New,Unit], Res}|Instructions], Env) ->
[hipe_icode:mk_move(Temp, NewVar)];
_ ->
NewVar = mk_var(New),
- if Lbl =:= 0 ->
- [hipe_icode:mk_primop([Temp], '*',
- [NewVar, hipe_icode:mk_const(Unit)])];
- true ->
- Succ = mk_label(new),
- [hipe_icode:mk_primop([Temp], '*',
- [NewVar, hipe_icode:mk_const(Unit)],
- hipe_icode:label_name(Succ), map_label(Lbl)),
- Succ]
- end
+ Succ = mk_label(new),
+ [hipe_icode:mk_primop([Temp], '*',
+ [NewVar, hipe_icode:mk_const(Unit)],
+ hipe_icode:label_name(Succ), FailLblName),
+ Succ]
end,
Succ2 = mk_label(new),
- {FailLblName, FailCode} =
- if Lbl =:= 0 ->
- FailLbl = mk_label(new),
- {hipe_icode:label_name(FailLbl),
- [FailLbl,
- hipe_icode:mk_fail([hipe_icode:mk_const(badarg)], error)]};
- true ->
- {map_label(Lbl), []}
- end,
IsPos =
[hipe_icode:mk_if('>=', [Temp, hipe_icode:mk_const(0)],
hipe_icode:label_name(Succ2), FailLblName)] ++
- FailCode ++ [Succ2],
- AddI =
+ FailCode ++ [Succ2],
+ AddRhs =
case Old of
- {integer,OldInt} ->
- hipe_icode:mk_primop([Dst], '+', [Temp, hipe_icode:mk_const(OldInt)]);
- _ ->
- OldVar = mk_var(Old),
- hipe_icode:mk_primop([Dst], '+', [Temp, OldVar])
+ {integer,OldInt} -> hipe_icode:mk_const(OldInt);
+ _ -> mk_var(Old)
end,
- MultIs ++ IsPos ++ [AddI|trans_fun(Instructions, Env)];
+ Succ3 = mk_label(new),
+ AddI = hipe_icode:mk_primop([Dst], '+', [Temp, AddRhs],
+ hipe_icode:label_name(Succ3), FailLblName),
+ MultIs ++ IsPos ++ [AddI,Succ3|trans_fun(Instructions, Env)];
%%--------------------------------------------------------------------
%% Bit syntax instructions added in R12B-5 (Fall 2008)
%%--------------------------------------------------------------------
@@ -1306,7 +1301,7 @@ trans_bin([{bs_put_binary,{f,Lbl},Size,Unit,{field_flags,Flags},Source}|
{Name, Args, Env2} =
case Size of
{atom,all} -> %% put all bits
- {{bs_put_binary_all, Flags}, [Src,Base,Offset], Env};
+ {{bs_put_binary_all, Unit, Flags}, [Src,Base,Offset], Env};
{integer,NoBits} when is_integer(NoBits), NoBits >= 0 ->
%% Create a N*Unit bits subbinary
{{bs_put_binary, NoBits*Unit, Flags}, [Src,Base,Offset], Env};
diff --git a/lib/hipe/icode/hipe_icode_primops.erl b/lib/hipe/icode/hipe_icode_primops.erl
index ffb51b2ea4..84aae30291 100644
--- a/lib/hipe/icode/hipe_icode_primops.erl
+++ b/lib/hipe/icode/hipe_icode_primops.erl
@@ -116,7 +116,7 @@ is_safe({hipe_bs_primop, {bs_init, _, _}}) -> false;
is_safe({hipe_bs_primop, {bs_init_bits, _}}) -> false;
is_safe({hipe_bs_primop, {bs_init_bits, _, _}}) -> false;
is_safe({hipe_bs_primop, {bs_put_binary, _, _}}) -> false;
-is_safe({hipe_bs_primop, {bs_put_binary_all, _}}) -> false;
+is_safe({hipe_bs_primop, {bs_put_binary_all, _, _}}) -> false;
is_safe({hipe_bs_primop, {bs_put_float, _, _, _}}) -> false;
is_safe({hipe_bs_primop, {bs_put_integer, _, _, _}}) -> false;
is_safe({hipe_bs_primop, {bs_put_string, _, _}}) -> false;
@@ -219,7 +219,7 @@ fails({hipe_bs_primop, {bs_init, _, _}}) -> true;
fails({hipe_bs_primop, {bs_init_bits, _}}) -> true;
fails({hipe_bs_primop, {bs_init_bits, _, _}}) -> true;
fails({hipe_bs_primop, {bs_put_binary, _, _}}) -> true;
-fails({hipe_bs_primop, {bs_put_binary_all, _}}) -> true;
+fails({hipe_bs_primop, {bs_put_binary_all, _, _}}) -> true;
fails({hipe_bs_primop, {bs_put_float, _, _, _}}) -> true;
fails({hipe_bs_primop, {bs_put_integer, _, _, _}}) -> true;
fails({hipe_bs_primop, {bs_put_string, _, _}}) -> true;
@@ -265,8 +265,8 @@ pp(Dev, Op) ->
io:format(Dev, "gc_test<~w>", [N]);
{hipe_bs_primop, BsOp} ->
case BsOp of
- {bs_put_binary_all, Flags} ->
- io:format(Dev, "bs_put_binary_all<~w>", [Flags]);
+ {bs_put_binary_all, Unit, Flags} ->
+ io:format(Dev, "bs_put_binary_all<~w, ~w>", [Unit,Flags]);
{bs_put_binary, Size} ->
io:format(Dev, "bs_put_binary<~w>", [Size]);
{bs_put_binary, Flags, Size} ->
@@ -505,11 +505,13 @@ type(Primop, Args) ->
NewMatchState =
erl_types:t_matchstate_update_present(NewBinType, MatchState),
if Signed =:= 0 ->
- erl_types:t_product([erl_types:t_from_range(0, 1 bsl Size - 1),
+ UpperBound = inf_add(safe_bsl(1, Size), -1),
+ erl_types:t_product([erl_types:t_from_range(0, UpperBound),
NewMatchState]);
Signed =:= 4 ->
- erl_types:t_product([erl_types:t_from_range(- (1 bsl (Size-1)),
- (1 bsl (Size-1)) - 1),
+ erl_types:t_product([erl_types:t_from_range(
+ inf_inv(safe_bsl(1, Size-1)),
+ inf_add(safe_bsl(1, Size-1), -1)),
NewMatchState])
end;
[_Arg] ->
@@ -628,8 +630,9 @@ type(Primop, Args) ->
[_SrcType, _BitsType, _Base, Type] ->
erl_types:t_bitstr_concat(Type, erl_types:t_bitstr(Size, 0))
end;
- {hipe_bs_primop, {bs_put_binary_all, _Flags}} ->
- [SrcType, _Base, Type] = Args,
+ {hipe_bs_primop, {bs_put_binary_all, Unit, _Flags}} ->
+ [SrcType0, _Base, Type] = Args,
+ SrcType = erl_types:t_inf(erl_types:t_bitstr(Unit, 0), SrcType0),
erl_types:t_bitstr_concat(SrcType,Type);
{hipe_bs_primop, {bs_put_string, _, Size}} ->
[_Base, Type] = Args,
@@ -965,3 +968,19 @@ check_fun_args(_, _) ->
match_bin(Pattern, Match) ->
erl_types:t_bitstr_match(Pattern, Match).
+
+safe_bsl(0, _) -> 0;
+safe_bsl(Base, Shift) when Shift =< 128 -> Base bsl Shift;
+safe_bsl(Base, _Shift) when Base > 0 -> pos_inf;
+safe_bsl(Base, _Shift) when Base < 0 -> neg_inf.
+
+inf_inv(pos_inf) -> neg_inf;
+inf_inv(neg_inf) -> pos_inf;
+inf_inv(Number) -> -Number.
+
+inf_add(pos_inf, _Number) -> pos_inf;
+inf_add(neg_inf, _Number) -> neg_inf;
+inf_add(_Number, pos_inf) -> pos_inf;
+inf_add(_Number, neg_inf) -> neg_inf;
+inf_add(Number1, Number2) when is_integer(Number1), is_integer(Number2) ->
+ Number1 + Number2.
diff --git a/lib/hipe/icode/hipe_icode_range.erl b/lib/hipe/icode/hipe_icode_range.erl
index ba5fa1bfd7..9a20527a83 100644
--- a/lib/hipe/icode/hipe_icode_range.erl
+++ b/lib/hipe/icode/hipe_icode_range.erl
@@ -1202,11 +1202,11 @@ basic_type(#unsafe_update_element{}) -> not_analysed.
analyse_bs_get_integer(Size, Flags, true) ->
Signed = Flags band 4,
if Signed =:= 0 ->
- Max = 1 bsl Size - 1,
+ Max = inf_add(inf_bsl(1, Size), -1),
Min = 0;
true ->
- Max = 1 bsl (Size-1) - 1,
- Min = -(1 bsl (Size-1))
+ Max = inf_add(inf_bsl(1, Size-1), -1),
+ Min = inf_inv(inf_bsl(1, Size-1))
end,
{Min, Max};
analyse_bs_get_integer(Size, Flags, false) when is_integer(Size),
diff --git a/lib/hipe/llvm/hipe_llvm_merge.erl b/lib/hipe/llvm/hipe_llvm_merge.erl
index 3ababfc21a..6e891ac3b0 100644
--- a/lib/hipe/llvm/hipe_llvm_merge.erl
+++ b/lib/hipe/llvm/hipe_llvm_merge.erl
@@ -27,7 +27,7 @@ finalize(CompiledCode, Closures, Exports) ->
DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap),
SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap, Closures, Exports),
SlimRefs = hipe_pack_constants:slim_refs(AccRefs),
- term_to_binary([{?VERSION_STRING(),?HIPE_SYSTEM_CRC},
+ term_to_binary([{?VERSION_STRING(),?HIPE_ERTS_CHECKSUM},
ConstAlign, ConstSize,
SC, % ConstMap
DataRelocs, % LabelMap
diff --git a/lib/hipe/main/hipe.app.src b/lib/hipe/main/hipe.app.src
index 008393e63c..aa86b6dc5b 100644
--- a/lib/hipe/main/hipe.app.src
+++ b/lib/hipe/main/hipe.app.src
@@ -225,4 +225,4 @@
{applications, [kernel,stdlib]},
{env, []},
{runtime_dependencies, ["syntax_tools-1.6.14","stdlib-2.5","kernel-3.0",
- "erts-7.0","compiler-5.0"]}]}.
+ "erts-7.1","compiler-5.0"]}]}.
diff --git a/lib/hipe/main/hipe.erl b/lib/hipe/main/hipe.erl
index ce4f49ffa7..1a4bbf179f 100644
--- a/lib/hipe/main/hipe.erl
+++ b/lib/hipe/main/hipe.erl
@@ -208,7 +208,8 @@
help_options/0,
help_option/1,
help_debug_options/0,
- version/0]).
+ version/0,
+ erts_checksum/0]).
-ifndef(DEBUG).
-define(DEBUG,true).
@@ -216,6 +217,7 @@
-include("hipe.hrl").
-include("../../compiler/src/beam_disasm.hrl").
+-include("../rtl/hipe_literals.hrl").
%%-------------------------------------------------------------------
%% Basic type declaration for exported functions of the 'hipe' module
@@ -1032,6 +1034,12 @@ post(Res, Icode, Options) ->
version() ->
?VERSION_STRING().
+%% @doc Returns checksum identifying the target runtime system.
+-spec erts_checksum() -> integer().
+
+erts_checksum() ->
+ ?HIPE_ERTS_CHECKSUM.
+
%% --------------------------------------------------------------------
%% D O C U M E N T A T I O N - H E L P
%% --------------------------------------------------------------------
@@ -1062,6 +1070,8 @@ help() ->
" Prints a description of debug options.\n" ++
" version() ->\n" ++
" Returns the HiPE version as a string'.\n" ++
+ " erts_checksum() ->\n" ++
+ " Returns a checksum identifying the target runtime system.\n" ++
"\n" ++
" For HiPE developers only:\n" ++
" Use `help_hiper()' for information about HiPE's low-level interface\n",
diff --git a/lib/hipe/ppc/hipe_ppc_assemble.erl b/lib/hipe/ppc/hipe_ppc_assemble.erl
index 4d419978ef..00f28d60e4 100644
--- a/lib/hipe/ppc/hipe_ppc_assemble.erl
+++ b/lib/hipe/ppc/hipe_ppc_assemble.erl
@@ -50,7 +50,7 @@ assemble(CompiledCode, Closures, Exports, Options) ->
DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap),
SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap,Closures,Exports),
SlimRefs = hipe_pack_constants:slim_refs(AccRefs),
- Bin = term_to_binary([{?VERSION_STRING(),?HIPE_SYSTEM_CRC},
+ Bin = term_to_binary([{?VERSION_STRING(),?HIPE_ERTS_CHECKSUM},
ConstAlign, ConstSize,
SC,
DataRelocs, % nee LM, LabelMap
diff --git a/lib/hipe/rtl/Makefile b/lib/hipe/rtl/Makefile
index d2517b13fc..1bf52fe312 100644
--- a/lib/hipe/rtl/Makefile
+++ b/lib/hipe/rtl/Makefile
@@ -75,7 +75,7 @@ TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
include ../native.mk
-ERL_COMPILE_FLAGS += +inline +warn_unused_import +warn_exported_vars
+ERL_COMPILE_FLAGS += -Werror +inline +warn_unused_import +warn_exported_vars
# ----------------------------------------------------
# Targets
diff --git a/lib/hipe/rtl/hipe_rtl_arith.inc b/lib/hipe/rtl/hipe_rtl_arith.inc
index 1f455f47ed..1dff56b074 100644
--- a/lib/hipe/rtl/hipe_rtl_arith.inc
+++ b/lib/hipe/rtl/hipe_rtl_arith.inc
@@ -30,13 +30,13 @@
%% Returns a tuple
%% {Res, Sign, Zero, Overflow, Carry}
%% Res will be a number in the range
-%% MAX_SIGNED_INT >= Res >= MIN_SIGNED_INT
+%% MAX_UNSIGNED_INT >= Res >= 0
%% The other four values are flags that are either true or false
%%
eval_alu(Op, Arg1, Arg2)
- when Arg1 =< ?MAX_SIGNED_INT,
+ when Arg1 =< ?MAX_UNSIGNED_INT,
Arg1 >= ?MIN_SIGNED_INT,
- Arg2 =< ?MAX_SIGNED_INT,
+ Arg2 =< ?MAX_UNSIGNED_INT,
Arg2 >= ?MIN_SIGNED_INT ->
Sign1 = sign_bit(Arg1),
@@ -111,7 +111,7 @@ eval_alu(Op, Arg1, Arg2)
Res = N = Z = V = C = 0,
?EXIT({"unknown alu op", Op})
end,
- {two_comp_to_erl(Res), N, Z, V, C};
+ {Res, N, Z, V, C};
eval_alu(Op, Arg1, Arg2) ->
?EXIT({argument_overflow,Op,Arg1,Arg2}).
@@ -162,16 +162,9 @@ eval_cond(Cond, Arg1, Arg2) ->
sign_bit(Val) ->
((Val bsr ?SIGN_BIT) band 1) =:= 1.
-two_comp_to_erl(V) ->
- if V > ?MAX_SIGNED_INT ->
- - ((?MAX_UNSIGNED_INT + 1) - V);
- true -> V
- end.
-
shiftmask(Arg) ->
Setbits = ?BITS - Arg,
(1 bsl Setbits) - 1.
zero(Val) ->
Val =:= 0.
-
diff --git a/lib/hipe/rtl/hipe_rtl_arith_32.erl b/lib/hipe/rtl/hipe_rtl_arith_32.erl
index 572556be1c..d790a8b981 100644
--- a/lib/hipe/rtl/hipe_rtl_arith_32.erl
+++ b/lib/hipe/rtl/hipe_rtl_arith_32.erl
@@ -24,7 +24,8 @@
%% Filename : hipe_rtl_arith_32.erl
%% Module : hipe_rtl_arith_32
%% Purpose : To implement 32-bit RTL-arithmetic
-%% Notes : The arithmetic works on 32-bit signed integers.
+%% Notes : The arithmetic works on 32-bit signed and unsigned
+%% integers.
%% The implementation is taken from the implementation
%% of arithmetic on SPARC.
%% XXX: This code is seldom used, and hence also
diff --git a/lib/hipe/rtl/hipe_rtl_binary.erl b/lib/hipe/rtl/hipe_rtl_binary.erl
index b549073050..9cbab08ee2 100644
--- a/lib/hipe/rtl/hipe_rtl_binary.erl
+++ b/lib/hipe/rtl/hipe_rtl_binary.erl
@@ -1,3 +1,4 @@
+%% -*- erlang-indent-level: 2 -*-
%%%
%%% %CopyrightBegin%
%%%
@@ -28,11 +29,20 @@
-export([gen_rtl/7]).
+-export([floorlog2/1, get_word_integer/4, make_size/3, make_size/4]).
+
+%%--------------------------------------------------------------------
+
+-define(BYTE_SHIFT, 3). %% Turn bits into bytes or vice versa
+-define(BYTE_SIZE, 8).
+
+%%--------------------------------------------------------------------
+
gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SysLimName, ConstTab) ->
case type_of_operation(BsOP) of
match ->
{hipe_rtl_binary_match:gen_rtl(
- BsOP, Dst, Args, TrueLblName, FalseLblName),ConstTab};
+ BsOP, Dst, Args, TrueLblName, FalseLblName),ConstTab};
construct ->
hipe_rtl_binary_construct:gen_rtl(
BsOP, Dst, Args, TrueLblName, FalseLblName, SysLimName, ConstTab)
@@ -62,7 +72,7 @@ type_of_operation({bs_init,_,_}) -> construct;
type_of_operation({bs_init_bits,_}) -> construct;
type_of_operation({bs_init_bits,_,_}) -> construct;
type_of_operation({bs_put_binary,_,_}) -> construct;
-type_of_operation({bs_put_binary_all,_}) -> construct;
+type_of_operation({bs_put_binary_all,_,_}) -> construct;
type_of_operation({bs_put_float,_,_,_}) -> construct;
type_of_operation({bs_put_integer,_,_,_}) -> construct;
type_of_operation({bs_put_string,_,_}) -> construct;
@@ -79,3 +89,133 @@ type_of_operation(bs_final) -> construct;
type_of_operation({bs_append,_,_,_,_}) -> construct;
type_of_operation({bs_private_append,_,_}) -> construct;
type_of_operation(bs_init_writable) -> construct.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% Small utility functions:
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+create_lbls(X) when X > 0 ->
+ [hipe_rtl:mk_new_label()|create_lbls(X-1)];
+create_lbls(0) ->
+ [].
+
+%%------------------------------------------------------------------------------
+%% Utilities used by both hipe_rtl_binary_construct and hipe_rtl_binary_match
+%%------------------------------------------------------------------------------
+
+get_word_integer(Var, Register, SystemLimitLblName, FalseLblName) ->
+ [EndLbl] = create_lbls(1),
+ EndName = hipe_rtl:label_name(EndLbl),
+ get_word_integer(Var, Register,SystemLimitLblName, FalseLblName, EndName, EndName,
+ [EndLbl]).
+
+get_word_integer(Var, Register, SystemLimitLblName, FalseLblName, TrueLblName,
+ BigLblName, Tail) ->
+ [FixnumLbl, NotFixnumLbl, BignumLbl, SuccessLbl] = create_lbls(4),
+ [hipe_tagscheme:test_fixnum(Var, hipe_rtl:label_name(FixnumLbl),
+ hipe_rtl:label_name(NotFixnumLbl), 0.99),
+ FixnumLbl,
+ hipe_tagscheme:fixnum_ge(Var, hipe_rtl:mk_imm(hipe_tagscheme:mk_fixnum(0)),
+ hipe_rtl:label_name(SuccessLbl), FalseLblName,
+ 0.99),
+ SuccessLbl,
+ hipe_tagscheme:untag_fixnum(Register, Var),
+ hipe_rtl:mk_goto(TrueLblName),
+ NotFixnumLbl,
+ hipe_tagscheme:test_pos_bignum_arity(Var, 1, hipe_rtl:label_name(BignumLbl),
+ FalseLblName, SystemLimitLblName, 0.99),
+ BignumLbl,
+ hipe_tagscheme:unsafe_get_one_word_pos_bignum(Register, Var),
+ hipe_rtl:mk_goto(BigLblName) | Tail].
+
+make_size(UnitImm, BitsVar, FailLblName) ->
+ make_size(UnitImm, BitsVar, FailLblName, FailLblName).
+
+make_size(1, BitsVar, OverflowLblName, FalseLblName) ->
+ DstReg = hipe_rtl:mk_new_reg_gcsafe(),
+ {get_word_integer(BitsVar, DstReg, OverflowLblName, FalseLblName), DstReg};
+make_size(?BYTE_SIZE, BitsVar, OverflowLblName, FalseLblName) ->
+ DstReg = hipe_rtl:mk_new_reg_gcsafe(),
+ [FixnumLbl, BignumLbl] = create_lbls(2),
+ WordBits = hipe_rtl_arch:word_size() * ?BYTE_SIZE,
+ FixnumLblName = hipe_rtl:label_name(FixnumLbl),
+ Tail = [BignumLbl,
+ hipe_rtl:mk_branch(DstReg, 'ltu',
+ hipe_rtl:mk_imm(1 bsl (WordBits - ?BYTE_SHIFT)),
+ FixnumLblName, OverflowLblName, 0.99),
+ FixnumLbl,
+ hipe_rtl:mk_alu(DstReg, DstReg, sll, hipe_rtl:mk_imm(?BYTE_SHIFT))],
+ Code = get_word_integer(BitsVar, DstReg, OverflowLblName, FalseLblName,
+ FixnumLblName, hipe_rtl:label_name(BignumLbl), Tail),
+ {Code, DstReg};
+make_size(UnitImm, BitsVar, OverflowLblName, FalseLblName) ->
+ DstReg = hipe_rtl:mk_new_reg_gcsafe(),
+ UnitList = number2list(UnitImm),
+ Code = multiply_code(UnitList, BitsVar, DstReg, OverflowLblName, FalseLblName),
+ {Code, DstReg}.
+
+multiply_code(List=[Head|_Tail], Variable, Result, OverflowLblName,
+ FalseLblName) ->
+ Test = set_high(Head),
+ Tmp1 = hipe_rtl:mk_new_reg(),
+ SuccessLbl = hipe_rtl:mk_new_label(),
+ Register = hipe_rtl:mk_new_reg(),
+ Code = [hipe_rtl:mk_move(Result, hipe_rtl:mk_imm(0))|
+ get_word_integer(Variable, Register, OverflowLblName, FalseLblName)]
+ ++
+ [hipe_rtl:mk_alub(Tmp1, Register, 'and', hipe_rtl:mk_imm(Test),
+ eq, hipe_rtl:label_name(SuccessLbl),
+ OverflowLblName, 0.99),
+ SuccessLbl],
+ multiply_code(List, Register, Result, OverflowLblName, Tmp1, Code).
+
+multiply_code([ShiftSize|Rest], Register, Result, OverflowLblName, Tmp1,
+ OldCode) ->
+ SuccessLbl = hipe_rtl:mk_new_label(),
+ Code =
+ OldCode ++
+ [hipe_rtl:mk_alu(Tmp1, Register, sll, hipe_rtl:mk_imm(ShiftSize)),
+ hipe_rtl:mk_alub(Result, Tmp1, 'add', Result, not_overflow,
+ hipe_rtl:label_name(SuccessLbl), OverflowLblName, 0.99),
+ SuccessLbl],
+ multiply_code(Rest, Register, Result, OverflowLblName, Tmp1, Code);
+multiply_code([], _Register, _Result, _OverflowLblName, _Tmp1, Code) ->
+ Code.
+
+set_high(X) ->
+ WordBits = hipe_rtl_arch:word_size() * ?BYTE_SIZE,
+ set_high(min(X, WordBits), WordBits, 0).
+
+set_high(0, _, Y) ->
+ Y;
+set_high(X, WordBits, Y) ->
+ set_high(X-1, WordBits, Y+(1 bsl (WordBits-X))).
+
+
+number2list(X) when is_integer(X), X >= 0 ->
+ number2list(X, []).
+
+number2list(1, Acc) ->
+ lists:reverse([0|Acc]);
+number2list(0, Acc) ->
+ lists:reverse(Acc);
+number2list(X, Acc) ->
+ F = floorlog2(X),
+ number2list(X-(1 bsl F), [F|Acc]).
+
+floorlog2(X) ->
+ %% Double-precision floats do not have enough precision to make floorlog2
+ %% exact for integers larger than 2^47.
+ Approx = round(math:log(X)/math:log(2)-0.5),
+ floorlog2_refine(X, Approx).
+
+floorlog2_refine(X, Approx) ->
+ if (1 bsl Approx) > X ->
+ floorlog2_refine(X, Approx - 1);
+ (1 bsl (Approx+1)) > X ->
+ Approx;
+ true ->
+ floorlog2_refine(X, Approx + 1)
+ end.
diff --git a/lib/hipe/rtl/hipe_rtl_binary_construct.erl b/lib/hipe/rtl/hipe_rtl_binary_construct.erl
index 40bd22aa8e..4403aa552f 100644
--- a/lib/hipe/rtl/hipe_rtl_binary_construct.erl
+++ b/lib/hipe/rtl/hipe_rtl_binary_construct.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2015. 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.
@@ -34,6 +34,10 @@
get_field_from_term/3,
set_field_from_pointer/3,
get_field_from_pointer/3]).
+
+-import(hipe_rtl_binary, [floorlog2/1,
+ get_word_integer/4,
+ make_size/4]).
%%-------------------------------------------------------------------------
-include("../main/hipe.hrl").
@@ -94,10 +98,11 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab
var_init_bits(Size, Dst0, Base, Offset, TrueLblName,
SystemLimitLblName, FalseLblName);
- {bs_put_binary_all, _Flags} ->
+ {bs_put_binary_all, Unit, _Flags} ->
[Src, Base, Offset] = Args,
[NewOffset] = get_real(Dst),
- put_binary_all(NewOffset, Src, Base, Offset, TrueLblName, FalseLblName);
+ put_binary_all(NewOffset, Src, Base, Offset, Unit,
+ TrueLblName, FalseLblName);
{bs_put_binary, Size, _Flags} ->
case is_illegal_const(Size) of
@@ -110,7 +115,9 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab
put_static_binary(NewOffset, Src, Size, Base, Offset,
TrueLblName, FalseLblName);
[Src, Bits, Base, Offset] ->
- {SizeCode, SizeReg} = make_size(Size, Bits, FalseLblName),
+ {SizeCode, SizeReg} = make_size(Size, Bits,
+ SystemLimitLblName,
+ FalseLblName),
InCode = put_dynamic_binary(NewOffset, Src, SizeReg, Base,
Offset, TrueLblName, FalseLblName),
SizeCode ++ InCode
@@ -132,7 +139,9 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab
put_float(NewOffset, Src, Base, Offset, Size, CCode, Aligned,
LittleEndian, ConstInfo, TrueLblName);
[Src, Bits, Base, Offset] ->
- {SizeCode, SizeReg} = make_size(Size, Bits, FalseLblName),
+ {SizeCode, SizeReg} = make_size(Size, Bits,
+ SystemLimitLblName,
+ FalseLblName),
InCode = float_c_code(NewOffset, Src, Base, Offset, SizeReg,
Flags, TrueLblName, FalseLblName),
SizeCode ++ InCode
@@ -161,6 +170,7 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab
CCode, Aligned, LittleEndian, TrueLblName);
[Src, Bits, Base, Offset] ->
{SizeCode, SizeReg} = make_size(Size, Bits,
+ SystemLimitLblName,
FalseLblName),
CCode = int_c_code(NewOffset, Src, Base,
Offset, SizeReg, Flags,
@@ -209,6 +219,7 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab
TrueLblName);
[Src, Bits, Base, Offset] ->
{SizeCode, SizeReg} = make_size(Size, Bits,
+ SystemLimitLblName,
FalseLblName),
CCode = int_c_code(NewOffset, Src, Base,
Offset, SizeReg, Flags,
@@ -293,7 +304,7 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab
[SizeReg] = create_regs(1),
[Base] = create_unsafe_regs(1),
[hipe_rtl:mk_gctest(?PROC_BIN_WORDSIZE + ?SUB_BIN_WORDSIZE),
- check_and_untag_fixnum(Size, SizeReg, FalseLblName),
+ get_word_integer(Size, SizeReg, SystemLimitLblName, FalseLblName),
allocate_writable(DstVar, Base, SizeReg, Zero, Zero),
hipe_rtl:mk_goto(TrueLblName)];
@@ -305,7 +316,7 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab
SubBinSize = {sub_binary, binsize},
[get_field_from_term({sub_binary, orig}, Bin, ProcBin),
get_field_from_term(SubBinSize, Bin, SubSize),
- check_and_untag_fixnum(Size, SizeReg, FalseLblName),
+ get_word_integer(Size, SizeReg, SystemLimitLblName, FalseLblName),
realloc_binary(SizeReg, ProcBin, Base),
calculate_sizes(Bin, SizeReg, Offset, EndSubSize, EndSubBitSize),
set_field_from_term(SubBinSize, Bin, EndSubSize),
@@ -313,20 +324,21 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab
hipe_rtl:mk_move(DstVar, Bin),
hipe_rtl:mk_goto(TrueLblName)];
- {bs_append, _U, _F, _B, _Bla} ->
+ {bs_append, _U, _F, Unit, _Bla} ->
[Size, Bin] = Args,
[DstVar, Base, Offset] = Dst,
[ProcBin] = create_vars(1),
[Flags, SizeReg, IsWritable, EndSubSize, EndSubBitSize] =
create_regs(5),
- [ContLbl,ContLbl2,ContLbl3,WritableLbl,NotWritableLbl] = Lbls =
- create_lbls(5),
- [ContLblName, ContLbl2Name, ContLbl3Name, Writable, NotWritable] =
+ [ContLbl,ContLbl2,ContLbl3,ContLbl4,WritableLbl,NotWritableLbl] =
+ Lbls = create_lbls(6),
+ [ContLblName, ContLbl2Name, ContLbl3Name, ContLbl4Name,
+ Writable, NotWritable] =
[hipe_rtl:label_name(Lbl) || Lbl <- Lbls],
Zero = hipe_rtl:mk_imm(0),
SubIsWritable = {sub_binary, is_writable},
[hipe_rtl:mk_gctest(?SUB_BIN_WORDSIZE + ?PROC_BIN_WORDSIZE),
- check_and_untag_fixnum(Size, SizeReg, FalseLblName),
+ get_word_integer(Size, SizeReg, SystemLimitLblName, FalseLblName),
hipe_tagscheme:test_bitstr(Bin, ContLblName, FalseLblName, 0.99),
ContLbl,
hipe_tagscheme:test_subbinary(Bin,ContLbl2Name, NotWritable),
@@ -339,17 +351,19 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab
get_field_from_term({proc_bin, flags}, ProcBin, Flags),
hipe_rtl:mk_alub(Flags, Flags, 'and',
hipe_rtl:mk_imm(?PB_IS_WRITABLE),
- eq, NotWritable, Writable, 0.01),
+ eq, NotWritable, ContLbl4Name, 0.01),
+ ContLbl4,
+ calculate_sizes(Bin, SizeReg, Offset, EndSubSize, EndSubBitSize),
+ is_divisible(Offset, Unit, Writable, FalseLblName),
WritableLbl,
set_field_from_term(SubIsWritable, Bin, Zero),
realloc_binary(SizeReg, ProcBin, Base),
- calculate_sizes(Bin, SizeReg, Offset, EndSubSize, EndSubBitSize),
hipe_tagscheme:mk_sub_binary(DstVar, EndSubSize, Zero,
EndSubBitSize, Zero,
hipe_rtl:mk_imm(1), ProcBin),
hipe_rtl:mk_goto(TrueLblName),
NotWritableLbl,
- not_writable_code(Bin, SizeReg, DstVar, Base, Offset,
+ not_writable_code(Bin, SizeReg, DstVar, Base, Offset, Unit,
TrueLblName, FalseLblName)]
end,
{Code, ConstTab}
@@ -361,7 +375,7 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-not_writable_code(Bin, SizeReg, Dst, Base, Offset,
+not_writable_code(Bin, SizeReg, Dst, Base, Offset, Unit,
TrueLblName, FalseLblName) ->
[SrcBase] = create_unsafe_regs(1),
[SrcOffset, SrcSize, TotSize, TotBytes, UsedBytes] = create_regs(5),
@@ -372,13 +386,13 @@ not_writable_code(Bin, SizeReg, Dst, Base, Offset,
hipe_rtl:mk_alu(TotBytes, TotSize, add, ?LOW_BITS),
hipe_rtl:mk_alu(TotBytes, TotBytes, srl, ?BYTE_SHIFT),
hipe_rtl:mk_alu(UsedBytes, TotBytes, sll, hipe_rtl:mk_imm(1)),
- hipe_rtl:mk_branch(UsedBytes, ge, hipe_rtl:mk_imm(256),
+ hipe_rtl:mk_branch(UsedBytes, geu, hipe_rtl:mk_imm(256),
AllLblName, IncLblName),
IncLbl,
hipe_rtl:mk_move(UsedBytes, hipe_rtl:mk_imm(256)),
AllLbl,
allocate_writable(Dst, Base, UsedBytes, TotBytes, TotSize),
- put_binary_all(Offset, Bin, Base, hipe_rtl:mk_imm(0),
+ put_binary_all(Offset, Bin, Base, hipe_rtl:mk_imm(0), Unit,
TrueLblName, FalseLblName)].
allocate_writable(Dst, Base, UsedBytes, TotBytes, TotSize) ->
@@ -397,16 +411,6 @@ allocate_writable(Dst, Base, UsedBytes, TotBytes, TotSize) ->
hipe_tagscheme:mk_sub_binary(Dst, EndSubSize, Zero, EndSubBitSize,
Zero, hipe_rtl:mk_imm(1), ProcBin)].
-check_and_untag_fixnum(Size, SizeReg, FalseLblName) ->
- [ContLbl,NextLbl] = Lbls = create_lbls(2),
- [ContLblName,NextLblName] = get_label_names(Lbls),
- [hipe_tagscheme:test_fixnum(Size, ContLblName, FalseLblName, 0.99),
- ContLbl,
- hipe_tagscheme:untag_fixnum(SizeReg,Size),
- hipe_rtl:mk_branch(SizeReg, ge, hipe_rtl:mk_imm(0), NextLblName,
- FalseLblName),
- NextLbl].
-
realloc_binary(SizeReg, ProcBin, Base) ->
[NoReallocLbl, ReallocLbl, NextLbl, ContLbl] = Lbls = create_lbls(4),
[NoReallocLblName, ReallocLblName, NextLblName, ContLblName] =
@@ -428,7 +432,7 @@ realloc_binary(SizeReg, ProcBin, Base) ->
set_field_from_term(ProcBinFlagsTag, ProcBin, Flags),
get_field_from_term(ProcBinValTag, ProcBin, BinPointer),
get_field_from_pointer(BinOrigSizeTag, BinPointer, OrigSize),
- hipe_rtl:mk_branch(OrigSize, 'lt', ResultingSize,
+ hipe_rtl:mk_branch(OrigSize, 'ltu', ResultingSize,
ReallocLblName, NoReallocLblName),
NoReallocLbl,
get_field_from_term(ProcBinBytesTag, ProcBin, Base),
@@ -669,14 +673,14 @@ var_init2(Size, Dst, Base, Offset, TrueLblName, SystemLimitLblName, FalseLblName
WordSize = hipe_rtl_arch:word_size(),
[ContLbl,HeapLbl,REFCLbl,NextLbl] = create_lbls(4),
[USize,Tmp] = create_unsafe_regs(2),
- [get_32_bit_value(Size, USize, SystemLimitLblName, FalseLblName),
- hipe_rtl:mk_branch(USize, le, hipe_rtl:mk_imm(?MAX_BINSIZE),
- hipe_rtl:label_name(ContLbl),
- SystemLimitLblName),
+ [get_word_integer(Size, USize, SystemLimitLblName, FalseLblName),
+ hipe_rtl:mk_branch(USize, leu, hipe_rtl:mk_imm(?MAX_BINSIZE),
+ hipe_rtl:label_name(ContLbl),
+ SystemLimitLblName),
ContLbl,
hipe_rtl:mk_move(Offset, hipe_rtl:mk_imm(0)),
- hipe_rtl:mk_branch(USize, le, hipe_rtl:mk_imm(?MAX_HEAP_BIN_SIZE),
- hipe_rtl:label_name(HeapLbl),
+ hipe_rtl:mk_branch(USize, leu, hipe_rtl:mk_imm(?MAX_HEAP_BIN_SIZE),
+ hipe_rtl:label_name(HeapLbl),
hipe_rtl:label_name(REFCLbl)),
HeapLbl,
hipe_rtl:mk_alu(Tmp, USize, add, hipe_rtl:mk_imm(3*WordSize-1)),
@@ -694,8 +698,8 @@ var_init2(Size, Dst, Base, Offset, TrueLblName, SystemLimitLblName, FalseLblName
hipe_rtl:mk_goto(TrueLblName)].
var_init_bits(Size, Dst, Base, Offset, TrueLblName, SystemLimitLblName, FalseLblName) ->
- [HeapLbl,REFCLbl,NextLbl,NoSubLbl,SubLbl,ContLbl,
- NoCreateSubBin, CreateSubBin, JoinLbl, JoinLbl2] = create_lbls(10),
+ [HeapLbl,REFCLbl,NextLbl,NoSubLbl,SubLbl,
+ NoCreateSubBin, CreateSubBin, JoinLbl, JoinLbl2] = create_lbls(9),
[USize,ByteSize,TotByteSize,OffsetBits] = create_regs(4),
[TmpDst] = create_unsafe_regs(1),
Log2WordSize = hipe_rtl_arch:log2_word_size(),
@@ -705,7 +709,7 @@ var_init_bits(Size, Dst, Base, Offset, TrueLblName, SystemLimitLblName, FalseLbl
?PROC_BIN_WORDSIZE) + ?SUB_BIN_WORDSIZE,
Zero = hipe_rtl:mk_imm(0),
[hipe_rtl:mk_gctest(MaximumWords),
- get_32_bit_value(Size, USize, SystemLimitLblName, FalseLblName),
+ get_word_integer(Size, USize, SystemLimitLblName, FalseLblName),
hipe_rtl:mk_alu(ByteSize, USize, srl, ?BYTE_SHIFT),
hipe_rtl:mk_alub(OffsetBits, USize, 'and', ?LOW_BITS, eq,
hipe_rtl:label_name(NoSubLbl),
@@ -716,11 +720,7 @@ var_init_bits(Size, Dst, Base, Offset, TrueLblName, SystemLimitLblName, FalseLbl
SubLbl,
hipe_rtl:mk_alu(TotByteSize, ByteSize, 'add', hipe_rtl:mk_imm(1)),
JoinLbl,
- hipe_rtl:mk_branch(USize, le, hipe_rtl:mk_imm(?MAX_BINSIZE),
- hipe_rtl:label_name(ContLbl),
- SystemLimitLblName),
- ContLbl,
- hipe_rtl:mk_branch(TotByteSize, 'le', hipe_rtl:mk_imm(?MAX_HEAP_BIN_SIZE),
+ hipe_rtl:mk_branch(TotByteSize, 'leu', hipe_rtl:mk_imm(?MAX_HEAP_BIN_SIZE),
hipe_rtl:label_name(HeapLbl),
hipe_rtl:label_name(REFCLbl)),
HeapLbl,
@@ -743,13 +743,16 @@ var_init_bits(Size, Dst, Base, Offset, TrueLblName, SystemLimitLblName, FalseLbl
hipe_rtl:mk_move(Dst, TmpDst),
hipe_rtl:mk_goto(TrueLblName)].
-put_binary_all(NewOffset, Src, Base, Offset, TLName, FLName) ->
+put_binary_all(NewOffset, Src, Base, Offset, Unit, TLName, FLName) ->
[SrcBase,SrcOffset,NumBits] = create_regs(3),
+ [ContLbl] = create_lbls(1),
CCode = binary_c_code(NewOffset, Src, Base, Offset, NumBits, TLName),
AlignedCode = copy_aligned_bytes(SrcBase, SrcOffset, NumBits, Base, Offset,
NewOffset, TLName),
- get_base_offset_size(Src, SrcBase, SrcOffset, NumBits,FLName) ++
- test_alignment(SrcOffset, NumBits, Offset, AlignedCode, CCode).
+ [get_base_offset_size(Src, SrcBase, SrcOffset, NumBits,FLName),
+ is_divisible(NumBits, Unit, hipe_rtl:label_name(ContLbl), FLName),
+ ContLbl
+ |test_alignment(SrcOffset, NumBits, Offset, AlignedCode, CCode)].
test_alignment(SrcOffset, NumBits, Offset, AlignedCode, CCode) ->
[Tmp] = create_regs(1),
@@ -976,7 +979,7 @@ copy_string(StringBase, StringSize, BinBase, BinOffset, NewOffset, TrueLblName)
small_check(SizeVar, CopySize, FalseLblName) ->
SuccessLbl = hipe_rtl:mk_new_label(),
- [hipe_rtl:mk_branch(SizeVar, le, CopySize,
+ [hipe_rtl:mk_branch(SizeVar, leu, CopySize,
hipe_rtl:label_name(SuccessLbl), FalseLblName),
SuccessLbl].
@@ -1192,7 +1195,10 @@ copy_little_word(Base, Offset, NewOffset, Word) ->
hipe_rtl:mk_store(Base, TmpOffset, Word, byte),
hipe_rtl:mk_alu(NewOffset, Offset, 'add', hipe_rtl:mk_imm(32))].
-copy_offset_int_big(Base, Offset, NewOffset, Size, Tmp1) when is_integer(Size) ->
+copy_offset_int_big(_Base, Offset, NewOffset, 0, _Tmp1) ->
+ [hipe_rtl:mk_move(NewOffset, Offset)];
+copy_offset_int_big(Base, Offset, NewOffset, Size, Tmp1)
+ when is_integer(Size), Size > 0 ->
Tmp2 = hipe_rtl:mk_new_reg(),
Tmp3 = hipe_rtl:mk_new_reg(),
Tmp4 = hipe_rtl:mk_new_reg(),
@@ -1203,7 +1209,7 @@ copy_offset_int_big(Base, Offset, NewOffset, Size, Tmp1) when is_integer(Size) -
Tmp9 = hipe_rtl:mk_new_reg(),
OldByte = hipe_rtl:mk_new_reg(),
TmpOffset = hipe_rtl:mk_new_reg(),
- BranchLbl = hipe_rtl:mk_new_label(),
+ BranchLbl = hipe_rtl:mk_new_label(),
BodyLbl = hipe_rtl:mk_new_label(),
EndLbl = hipe_rtl:mk_new_label(),
NextLbl = hipe_rtl:mk_new_label(),
@@ -1276,89 +1282,18 @@ copy_float_big(Base, Offset, NewOffset, Src, FalseLblName, TrueLblName, var) ->
hipe_tagscheme:test_flonum(Src, hipe_rtl:label_name(SuccessLbl), FalseLblName, 0.99) ++
[SuccessLbl|copy_float_big(Base, Offset, NewOffset, Src, FalseLblName, TrueLblName, pass)].
-make_size(1, BitsVar, FalseLblName) ->
- [DstReg] = create_regs(1),
- {first_part(BitsVar, DstReg, FalseLblName), DstReg};
-make_size(?BYTE_SIZE, BitsVar, FalseLblName) ->
- [DstReg] = create_regs(1),
- Code =
- first_part(BitsVar, DstReg, FalseLblName) ++
- [hipe_rtl:mk_alu(DstReg, DstReg, 'sll', ?BYTE_SHIFT)],
- {Code, DstReg};
-make_size(UnitImm, BitsVar, FalseLblName) ->
- [DstReg] = create_regs(1),
- UnitList = number2list(UnitImm),
- Code = multiply_code(UnitList, BitsVar, DstReg, FalseLblName),
- {Code, DstReg}.
-
-multiply_code(List=[Head|_Tail], Variable, Result, FalseLblName) ->
- Test = set_high(Head),
- Tmp1 = hipe_rtl:mk_new_reg(),
- SuccessLbl = hipe_rtl:mk_new_label(),
- Register = hipe_rtl:mk_new_reg(),
- Code = [hipe_rtl:mk_move(Result, hipe_rtl:mk_imm(0))|
- first_part(Variable, Register, FalseLblName)]
- ++
- [hipe_rtl:mk_alub(Tmp1, Register, 'and', hipe_rtl:mk_imm(Test),
- 'eq', hipe_rtl:label_name(SuccessLbl),
- FalseLblName, 0.99),
- SuccessLbl],
- multiply_code(List, Register, Result, FalseLblName, Tmp1, Code).
-
-multiply_code([ShiftSize|Rest], Register, Result, FalseLblName, Tmp1, OldCode) ->
- SuccessLbl = hipe_rtl:mk_new_label(),
- Code = OldCode ++ [hipe_rtl:mk_alu(Tmp1, Register, 'sll',
- hipe_rtl:mk_imm(ShiftSize)),
- hipe_rtl:mk_alub(Result, Tmp1, 'add', Result, not_overflow, hipe_rtl:label_name(SuccessLbl), FalseLblName, 0.99),
- SuccessLbl],
- multiply_code(Rest, Register, Result, FalseLblName, Tmp1, Code);
-multiply_code([], _Register, _Result, _FalseLblName, _Tmp1, Code) ->
- Code.
-
-number2list(X) when is_integer(X), X >= 0 ->
- number2list(X, []).
-
-number2list(1, Acc) ->
- lists:reverse([0|Acc]);
-number2list(0, Acc) ->
- lists:reverse(Acc);
-number2list(X, Acc) ->
- F = floorlog2(X),
- number2list(X-(1 bsl F), [F|Acc]).
-
-floorlog2(X) ->
- round(math:log(X)/math:log(2)-0.5).
-
-set_high(X) ->
- set_high(X, 0).
-
-set_high(0, Y) ->
- Y;
-set_high(X, Y) ->
- set_high(X-1, Y+(1 bsl (27-X))).
-
-get_32_bit_value(Size, USize, SystemLimitLblName, NegLblName) ->
- Lbls = [FixLbl, BigLbl, OkLbl, PosBigLbl] = create_lbls(4),
- [FixLblName, BigLblName, OkLblName, PosBigLblName] = [hipe_rtl:label_name(Lbl) || Lbl <- Lbls],
- [hipe_tagscheme:test_fixnum(Size, FixLblName, BigLblName, 0.99),
- FixLbl,
- hipe_tagscheme:untag_fixnum(USize, Size),
- hipe_rtl:mk_branch(USize, ge, hipe_rtl:mk_imm(0), OkLblName, NegLblName),
- BigLbl,
- hipe_tagscheme:test_pos_bignum(Size, PosBigLblName, NegLblName, 0.99),
- PosBigLbl,
- hipe_tagscheme:get_one_word_pos_bignum(USize, Size, SystemLimitLblName),
- OkLbl].
-
-
-first_part(Var, Register, FalseLblName) ->
- [SuccessLbl1, SuccessLbl2] = create_lbls(2),
- [hipe_tagscheme:test_fixnum(Var, hipe_rtl:label_name(SuccessLbl1),
- FalseLblName, 0.99),
- SuccessLbl1,
- hipe_tagscheme:fixnum_ge(Var, hipe_rtl:mk_imm(hipe_tagscheme:mk_fixnum(0)),
- hipe_rtl:label_name(SuccessLbl2), FalseLblName, 0.99),
- SuccessLbl2,
- hipe_tagscheme:untag_fixnum(Register, Var)].
-
-
+is_divisible(_Dividend, 1, SuccLbl, _FailLbl) ->
+ [hipe_rtl:mk_goto(SuccLbl)];
+is_divisible(Dividend, Divisor, SuccLbl, FailLbl) ->
+ Log2 = floorlog2(Divisor),
+ case Divisor =:= 1 bsl Log2 of
+ true -> %% Divisor is a power of 2
+ %% Test that the Log2-1 lowest bits are clear
+ Mask = hipe_rtl:mk_imm(Divisor - 1),
+ [Tmp] = create_regs(1),
+ [hipe_rtl:mk_alub(Tmp, Dividend, 'and', Mask, eq, SuccLbl, FailLbl, 0.99)];
+ false ->
+ %% We need division, fall back to a primop
+ [hipe_rtl:mk_call([], is_divisible, [Dividend, hipe_rtl:mk_imm(Divisor)],
+ SuccLbl, FailLbl, not_remote)]
+ end.
diff --git a/lib/hipe/rtl/hipe_rtl_binary_match.erl b/lib/hipe/rtl/hipe_rtl_binary_match.erl
index 364aab1b6f..be4c35dae0 100644
--- a/lib/hipe/rtl/hipe_rtl_binary_match.erl
+++ b/lib/hipe/rtl/hipe_rtl_binary_match.erl
@@ -2,7 +2,7 @@
%%%
%%% %CopyrightBegin%
%%%
-%%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%%% Copyright Ericsson AB 2007-2015. 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.
@@ -31,11 +31,12 @@
-import(hipe_tagscheme, [set_field_from_term/3, get_field_from_term/3]).
+-import(hipe_rtl_binary, [make_size/3]).
+
-include("hipe_literals.hrl").
%%--------------------------------------------------------------------
--define(MAX_BINSIZE, trunc(?MAX_HEAP_BIN_SIZE / hipe_rtl_arch:word_size()) + 2).
-define(BYTE_SHIFT, 3). %% Turn bits into bytes or vice versa
-define(LOW_BITS, 7). %% Three lowest bits set
-define(BYTE_SIZE, 8).
@@ -181,17 +182,20 @@ gen_rtl({bs_get_binary, Size, Flags}, [Dst, NewMs], Args,
[hipe_rtl:mk_goto(FalseLblName)];
false ->
Unsafe = unsafe(Flags),
- case Args of
- [Ms] ->
- SizeReg = hipe_rtl:mk_new_reg(),
- SizeCode = [hipe_rtl:mk_move(SizeReg, hipe_rtl:mk_imm(Size))];
- [Ms, BitsVar] ->
- {SizeCode, SizeReg} = make_size(Size, BitsVar, FalseLblName)
- end,
- InCode = get_binary(Dst, Ms, SizeReg, Unsafe,
+ {OldMs, SizeReg, SizeCode} =
+ case Args of
+ [Ms] ->
+ SzReg = hipe_rtl:mk_new_reg(),
+ SzCode = [hipe_rtl:mk_move(SzReg, hipe_rtl:mk_imm(Size))],
+ {Ms, SzReg, SzCode};
+ [Ms, BitsVar] ->
+ {SzCode, SzReg} = make_size(Size, BitsVar, FalseLblName),
+ {Ms, SzReg, SzCode}
+ end,
+ InCode = get_binary(Dst, OldMs, SizeReg, Unsafe,
TrueLblName, FalseLblName),
[hipe_rtl:mk_gctest(?SUB_BIN_WORDSIZE)] ++
- update_ms(NewMs, Ms) ++ SizeCode ++ InCode
+ update_ms(NewMs, OldMs) ++ SizeCode ++ InCode
end;
%% ----- bs_get_utf8 -----
gen_rtl(bs_get_utf8, [Dst, NewMs], [Ms], TrueLblName, FalseLblName) ->
@@ -230,14 +234,26 @@ gen_rtl({bs_skip_bits_all, Unit, _Flags}, Dst, [Ms],
skip_bits_all(Unit, Ms, TrueLblName, FalseLblName);
%% ----- bs_skip_bits -----
gen_rtl({bs_skip_bits, Bits}, Dst, [Ms|Args], TrueLblName, FalseLblName) ->
+ MaxValue = (1 bsl (hipe_rtl_arch:word_size() * ?BYTE_SIZE)),
opt_update_ms(Dst, Ms) ++
- case Args of
- [] ->
- skip_bits2(Ms, hipe_rtl:mk_imm(Bits), TrueLblName, FalseLblName);
- [Arg] ->
- {SizeCode, SizeReg} = make_size(Bits, Arg, FalseLblName),
- InCode = skip_bits2(Ms, SizeReg, TrueLblName, FalseLblName),
- SizeCode ++ InCode
+ case Bits < MaxValue of
+ true ->
+ case Args of
+ [] ->
+ skip_bits2(Ms, hipe_rtl:mk_imm(Bits), TrueLblName, FalseLblName);
+ [Arg] ->
+ {SizeCode, SizeReg} = make_size(Bits, Arg, FalseLblName),
+ InCode = skip_bits2(Ms, SizeReg, TrueLblName, FalseLblName),
+ SizeCode ++ InCode
+ end;
+ false -> % handle overflow case
+ case Args of
+ [] ->
+ [hipe_rtl:mk_goto(FalseLblName)];
+ [Arg] ->
+ [hipe_rtl:mk_branch(Arg, 'eq', hipe_tagscheme:mk_fixnum(0),
+ TrueLblName, FalseLblName, 0.5)]
+ end
end;
%% ----- bs_restore -----
gen_rtl({bs_restore, Slot}, [NewMs], [Ms], TrueLblName, _FalseLblName) ->
@@ -318,32 +334,50 @@ float_get_c_code(Dst1, Ms, Size, Flags, TrueLblName, FalseLblName) ->
get_c_code(Func, Dst1, Ms, Size, Flags, TrueLblName, FalseLblName) ->
SizeReg = hipe_rtl:mk_new_reg_gcsafe(),
FlagsReg = hipe_rtl:mk_new_reg_gcsafe(),
+ RetReg = hipe_rtl:mk_new_reg_gcsafe(),
MatchBuf = hipe_rtl:mk_new_reg(),
RetLabel = hipe_rtl:mk_new_label(),
+ OkLabel = hipe_rtl:mk_new_label(),
NonVal = hipe_rtl:mk_imm(hipe_tagscheme:mk_non_value()),
[hipe_rtl:mk_move(SizeReg, Size),
hipe_rtl:mk_move(FlagsReg, hipe_rtl:mk_imm(Flags)),
hipe_tagscheme:extract_matchbuffer(MatchBuf, Ms),
- hipe_rtl_arch:call_bif([Dst1], Func, [SizeReg, FlagsReg, MatchBuf],
+ hipe_rtl_arch:call_bif([RetReg], Func, [SizeReg, FlagsReg, MatchBuf],
hipe_rtl:label_name(RetLabel), FalseLblName),
RetLabel,
- hipe_rtl:mk_branch(Dst1, eq, NonVal, FalseLblName, TrueLblName, 0.01)].
+ hipe_rtl:mk_branch(RetReg, eq, NonVal, FalseLblName,
+ hipe_rtl:label_name(OkLabel), 0.01),
+ OkLabel,
+ hipe_rtl:mk_move(Dst1, RetReg),
+ hipe_rtl:mk_goto(TrueLblName)].
utf8_get_c_code(Dst, Ms, TrueLblName, FalseLblName) ->
+ RetReg = hipe_rtl:mk_new_reg_gcsafe(),
+ OkLabel = hipe_rtl:mk_new_label(),
MatchBuf = hipe_rtl:mk_new_reg(),
NonVal = hipe_rtl:mk_imm(hipe_tagscheme:mk_non_value()),
[hipe_tagscheme:extract_matchbuffer(MatchBuf, Ms),
- hipe_rtl_arch:call_bif([Dst], bs_get_utf8, [MatchBuf], [], []),
- hipe_rtl:mk_branch(Dst, eq, NonVal, FalseLblName, TrueLblName, 0.01)].
+ hipe_rtl_arch:call_bif([RetReg], bs_get_utf8, [MatchBuf], [], []),
+ hipe_rtl:mk_branch(RetReg, eq, NonVal, FalseLblName,
+ hipe_rtl:label_name(OkLabel), 0.01),
+ OkLabel,
+ hipe_rtl:mk_move(Dst, RetReg),
+ hipe_rtl:mk_goto(TrueLblName)].
utf16_get_c_code(Flags, Dst, Ms, TrueLblName, FalseLblName) ->
+ RetReg = hipe_rtl:mk_new_reg_gcsafe(),
+ OkLabel = hipe_rtl:mk_new_label(),
MatchBuf = hipe_rtl:mk_new_reg(),
NonVal = hipe_rtl:mk_imm(hipe_tagscheme:mk_non_value()),
FlagsReg = hipe_rtl:mk_new_reg_gcsafe(),
[hipe_tagscheme:extract_matchbuffer(MatchBuf, Ms),
hipe_rtl:mk_move(FlagsReg, hipe_rtl:mk_imm(Flags)),
- hipe_rtl_arch:call_bif([Dst], bs_get_utf16, [MatchBuf, FlagsReg], [], []),
- hipe_rtl:mk_branch(Dst, eq, NonVal, FalseLblName, TrueLblName, 0.01)].
+ hipe_rtl_arch:call_bif([RetReg], bs_get_utf16, [MatchBuf, FlagsReg], [], []),
+ hipe_rtl:mk_branch(RetReg, eq, NonVal, FalseLblName,
+ hipe_rtl:label_name(OkLabel), 0.01),
+ OkLabel,
+ hipe_rtl:mk_move(Dst, RetReg),
+ hipe_rtl:mk_goto(TrueLblName)].
validate_unicode_retract_c_code(Src, Ms, TrueLblName, FalseLblName) ->
MatchBuf = hipe_rtl:mk_new_reg(),
@@ -802,10 +836,10 @@ create_lbls(0) ->
create_lbls(X) when X > 0 ->
[hipe_rtl:mk_new_label()|create_lbls(X-1)].
-make_dyn_prep(SizeReg, CCode) ->
+make_dyn_prep(SizeReg, CCode) ->
[CLbl, SuccessLbl] = create_lbls(2),
- Init = [hipe_rtl:mk_branch(SizeReg, le, hipe_rtl:mk_imm(?MAX_SMALL_BITS),
- hipe_rtl:label_name(SuccessLbl),
+ Init = [hipe_rtl:mk_branch(SizeReg, leu, hipe_rtl:mk_imm(?MAX_SMALL_BITS),
+ hipe_rtl:label_name(SuccessLbl),
hipe_rtl:label_name(CLbl)),
SuccessLbl],
End = [CLbl|CCode],
@@ -850,8 +884,8 @@ get_unaligned_int_to_reg(Reg, Size, Base, Offset, LowBits, Shiftr, Type) ->
hipe_rtl:mk_imm((WordSize-MinLoad)*?BYTE_SIZE))];
{_, WordSize} ->
UnsignedBig = {unsigned, big},
- [hipe_rtl:mk_branch(TotBits, le, hipe_rtl:mk_imm(MinLoad*?BYTE_SIZE),
- hipe_rtl:label_name(LessLbl),
+ [hipe_rtl:mk_branch(TotBits, leu, hipe_rtl:mk_imm(MinLoad*?BYTE_SIZE),
+ hipe_rtl:label_name(LessLbl),
hipe_rtl:label_name(MoreLbl)),
LessLbl,
load_bytes(LoadDst, Base, ByteOffset, Type, MinLoad),
@@ -911,7 +945,7 @@ get_big_unknown_int(Dst1, Base, Offset, NewOffset,
hipe_rtl:mk_alu(ByteOffset, Offset, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)),
load_bytes(LoadDst, Base, ByteOffset, Type, 1),
BackLbl,
- hipe_rtl:mk_branch(ByteOffset, le, Limit, hipe_rtl:label_name(LoopLbl),
+ hipe_rtl:mk_branch(ByteOffset, leu, Limit, hipe_rtl:label_name(LoopLbl),
hipe_rtl:label_name(EndLbl)),
LoopLbl,
load_bytes(Tmp, Base, ByteOffset, {unsigned, big}, 1),
@@ -940,8 +974,8 @@ get_little_unknown_int(Dst1, Base, Offset, NewOffset,
hipe_rtl:mk_alu(Limit, Tmp, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)),
hipe_rtl:mk_move(ShiftReg, hipe_rtl:mk_imm(0)),
BackLbl,
- hipe_rtl:mk_branch(ByteOffset, lt, Limit,
- hipe_rtl:label_name(LoopLbl),
+ hipe_rtl:mk_branch(ByteOffset, ltu, Limit,
+ hipe_rtl:label_name(LoopLbl),
hipe_rtl:label_name(DoneLbl)),
LoopLbl,
load_bytes(Tmp, Base, ByteOffset, {unsigned, big}, 1),
@@ -1057,7 +1091,7 @@ load_bytes(Dst, Base, Offset, {Signedness, Endianness}, X) when X > 1 ->
hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(1)),
hipe_rtl:mk_alu(Dst, Dst, sll, hipe_rtl:mk_imm(8)),
hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
- hipe_rtl:mk_branch(Offset, lt, Limit, hipe_rtl:label_name(LoopLbl),
+ hipe_rtl:mk_branch(Offset, ltu, Limit, hipe_rtl:label_name(LoopLbl),
hipe_rtl:label_name(EndLbl)),
EndLbl];
little ->
@@ -1069,7 +1103,7 @@ load_bytes(Dst, Base, Offset, {Signedness, Endianness}, X) when X > 1 ->
hipe_rtl:mk_load(Tmp1, Base, TmpOffset, byte, Signedness),
hipe_rtl:mk_alu(Dst, Dst, sll, hipe_rtl:mk_imm(8)),
hipe_rtl:mk_alu(Dst, Dst, 'or', Tmp1),
- hipe_rtl:mk_branch(Offset, lt, TmpOffset, hipe_rtl:label_name(LoopLbl),
+ hipe_rtl:mk_branch(Offset, ltu, TmpOffset, hipe_rtl:label_name(LoopLbl),
hipe_rtl:label_name(EndLbl)),
EndLbl,
hipe_rtl:mk_move(Offset, Limit)]
@@ -1085,78 +1119,5 @@ create_gcsafe_regs(X) when X > 0 ->
create_gcsafe_regs(0) ->
[].
-first_part(Var, Register, FalseLblName) ->
- [SuccessLbl1, SuccessLbl2] = create_lbls(2),
- [hipe_tagscheme:test_fixnum(Var, hipe_rtl:label_name(SuccessLbl1),
- FalseLblName, 0.99),
- SuccessLbl1,
- hipe_tagscheme:fixnum_ge(Var, hipe_rtl:mk_imm(hipe_tagscheme:mk_fixnum(0)),
- hipe_rtl:label_name(SuccessLbl2), FalseLblName, 0.99),
- SuccessLbl2,
- hipe_tagscheme:untag_fixnum(Register, Var)].
-
-make_size(1, BitsVar, FalseLblName) ->
- [DstReg] = create_regs(1),
- {first_part(BitsVar, DstReg, FalseLblName), DstReg};
-make_size(?BYTE_SIZE, BitsVar, FalseLblName) ->
- [DstReg] = create_regs(1),
- Code =
- first_part(BitsVar, DstReg, FalseLblName) ++
- [hipe_rtl:mk_alu(DstReg, DstReg, sll, hipe_rtl:mk_imm(?BYTE_SHIFT))],
- {Code, DstReg};
-make_size(UnitImm, BitsVar, FalseLblName) ->
- [DstReg] = create_regs(1),
- UnitList = number2list(UnitImm),
- Code = multiply_code(UnitList, BitsVar, DstReg, FalseLblName),
- {Code, DstReg}.
-
-multiply_code(List=[Head|_Tail], Variable, Result, FalseLblName) ->
- Test = set_high(Head),
- Tmp1 = hipe_rtl:mk_new_reg(),
- SuccessLbl = hipe_rtl:mk_new_label(),
- Register = hipe_rtl:mk_new_reg(),
- Code = [hipe_rtl:mk_move(Result, hipe_rtl:mk_imm(0))|
- first_part(Variable, Register, FalseLblName)]
- ++
- [hipe_rtl:mk_alub(Tmp1, Register, 'and', hipe_rtl:mk_imm(Test),
- eq, hipe_rtl:label_name(SuccessLbl),
- FalseLblName, 0.99),
- SuccessLbl],
- multiply_code(List, Register, Result, FalseLblName, Tmp1, Code).
-
-multiply_code([ShiftSize|Rest], Register, Result, FalseLblName, Tmp1, OldCode) ->
- SuccessLbl = hipe_rtl:mk_new_label(),
- Code =
- OldCode ++
- [hipe_rtl:mk_alu(Tmp1, Register, sll, hipe_rtl:mk_imm(ShiftSize)),
- hipe_rtl:mk_alub(Result, Tmp1, 'add', Result, not_overflow,
- hipe_rtl:label_name(SuccessLbl), FalseLblName, 0.99),
- SuccessLbl],
- multiply_code(Rest, Register, Result, FalseLblName, Tmp1, Code);
-multiply_code([], _Register, _Result, _FalseLblName, _Tmp1, Code) ->
- Code.
-
-number2list(X) when is_integer(X), X >= 0 ->
- number2list(X, []).
-
-number2list(1, Acc) ->
- lists:reverse([0|Acc]);
-number2list(0, Acc) ->
- lists:reverse(Acc);
-number2list(X, Acc) ->
- F = floorlog2(X),
- number2list(X-(1 bsl F), [F|Acc]).
-
-floorlog2(X) ->
- round(math:log(X)/math:log(2)-0.5).
-
-set_high(X) ->
- set_high(X, 0).
-
-set_high(0, Y) ->
- Y;
-set_high(X, Y) ->
- set_high(X-1, Y+(1 bsl (27-X))).
-
is_illegal_const(Const) ->
Const >= 1 bsl (hipe_rtl_arch:word_size() * ?BYTE_SIZE) orelse Const < 0.
diff --git a/lib/hipe/rtl/hipe_tagscheme.erl b/lib/hipe/rtl/hipe_tagscheme.erl
index 1bb4c3cc5f..8825a3ade3 100644
--- a/lib/hipe/rtl/hipe_tagscheme.erl
+++ b/lib/hipe/rtl/hipe_tagscheme.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2015. 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.
@@ -41,7 +41,8 @@
test_any_pid/4, test_any_port/4,
test_ref/4, test_fun/4, test_fun2/5, test_matchstate/4,
test_binary/4, test_bitstr/4, test_list/4, test_map/4,
- test_integer/4, test_number/4, test_tuple_N/5]).
+ test_integer/4, test_number/4, test_tuple_N/5,
+ test_pos_bignum_arity/6]).
-export([realtag_fixnum/2, tag_fixnum/2, realuntag_fixnum/2, untag_fixnum/2]).
-export([test_two_fixnums/3, test_fixnums/4, unsafe_fixnum_add/3,
unsafe_fixnum_sub/3,
@@ -53,9 +54,10 @@
-export([unsafe_closure_element/3]).
-export([mk_fun_header/0, tag_fun/2]).
-export([unsafe_untag_float/2, unsafe_tag_float/2]).
--export([mk_sub_binary/6,mk_sub_binary/7]).
+-export([mk_sub_binary/6, mk_sub_binary/7]).
-export([unsafe_mk_big/3, unsafe_load_float/3]).
--export([bignum_sizeneed/1,bignum_sizeneed_code/2, get_one_word_pos_bignum/3]).
+-export([bignum_sizeneed/1, bignum_sizeneed_code/2, get_one_word_pos_bignum/3,
+ unsafe_get_one_word_pos_bignum/2]).
-export([test_subbinary/3, test_heap_binary/3]).
-export([create_heap_binary/3, create_refc_binary/3, create_refc_binary/4]).
-export([create_matchstate/6, convert_matchstate/1, compare_matchstate/4]).
@@ -349,6 +351,24 @@ test_pos_bignum(X, TrueLab, FalseLab, Pred) ->
mask_and_compare(Tmp, BigMask, ?TAG_HEADER_POS_BIG,
TrueLab, FalseLab, Pred)].
+test_pos_bignum_arity(X, Arity, TrueLab, NotPosBignumLab, FalseLab, Pred) ->
+ Tmp = hipe_rtl:mk_new_reg_gcsafe(),
+ BoxedLab = hipe_rtl:mk_new_label(),
+ HeaderImm = hipe_rtl:mk_imm(mk_header(Arity, ?TAG_HEADER_POS_BIG)),
+ [test_is_boxed(X, hipe_rtl:label_name(BoxedLab), NotPosBignumLab, Pred),
+ BoxedLab,
+ get_header(Tmp, X)] ++
+ case NotPosBignumLab =:= FalseLab of
+ true -> [];
+ false ->
+ BignumLab = hipe_rtl:mk_new_label(),
+ BigMask = ?TAG_HEADER_MASK,
+ [mask_and_compare(Tmp, BigMask, ?TAG_HEADER_POS_BIG,
+ hipe_rtl:label_name(BignumLab), NotPosBignumLab, Pred),
+ BignumLab]
+ end ++
+ [hipe_rtl:mk_branch(Tmp, 'eq', HeaderImm, TrueLab, FalseLab, Pred)].
+
test_matchstate(X, TrueLab, FalseLab, Pred) ->
Tmp = hipe_rtl:mk_new_reg_gcsafe(),
HalfTrueLab = hipe_rtl:mk_new_label(),
@@ -963,13 +983,16 @@ get_one_word_pos_bignum(USize, Size, Fail) ->
Header = hipe_rtl:mk_new_reg(),
HalfLbl = hipe_rtl:mk_new_label(),
HalfLblName = hipe_rtl:label_name(HalfLbl),
- WordSize = hipe_rtl_arch:word_size(),
PosHead = hipe_rtl:mk_imm(mk_header(1, ?TAG_HEADER_POS_BIG)),
[get_header(Header, Size),
hipe_rtl:mk_branch(Header, eq, PosHead, HalfLblName, Fail),
- HalfLbl,
- hipe_rtl:mk_load(USize, Size, hipe_rtl:mk_imm(1*WordSize
- -?TAG_PRIMARY_BOXED))].
+ HalfLbl |
+ unsafe_get_one_word_pos_bignum(USize, Size)].
+
+unsafe_get_one_word_pos_bignum(USize, Size) ->
+ WordSize = hipe_rtl_arch:word_size(),
+ Imm = hipe_rtl:mk_imm(1*WordSize-?TAG_PRIMARY_BOXED),
+ [hipe_rtl:mk_load(USize, Size, Imm)].
-spec bignum_sizeneed(non_neg_integer()) -> non_neg_integer().
diff --git a/lib/hipe/sparc/hipe_sparc_assemble.erl b/lib/hipe/sparc/hipe_sparc_assemble.erl
index 5424a6c965..0e27c78416 100644
--- a/lib/hipe/sparc/hipe_sparc_assemble.erl
+++ b/lib/hipe/sparc/hipe_sparc_assemble.erl
@@ -49,7 +49,7 @@ assemble(CompiledCode, Closures, Exports, Options) ->
DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap),
SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap,Closures,Exports),
SlimRefs = hipe_pack_constants:slim_refs(AccRefs),
- Bin = term_to_binary([{?VERSION_STRING(),?HIPE_SYSTEM_CRC},
+ Bin = term_to_binary([{?VERSION_STRING(),?HIPE_ERTS_CHECKSUM},
ConstAlign, ConstSize,
SC,
DataRelocs, % nee LM, LabelMap
diff --git a/lib/hipe/test/Makefile b/lib/hipe/test/Makefile
index 009f503abb..d781e4f9be 100644
--- a/lib/hipe/test/Makefile
+++ b/lib/hipe/test/Makefile
@@ -10,8 +10,10 @@ MODULES= \
# .erl files for these modules are automatically generated
GEN_MODULES= \
+ basic_SUITE \
bs_SUITE \
- maps_SUITE
+ maps_SUITE \
+ sanity_SUITE
ERL_FILES= $(MODULES:%=%.erl)
diff --git a/lib/hipe/test/basic_SUITE_data/basic_arith.erl b/lib/hipe/test/basic_SUITE_data/basic_arith.erl
new file mode 100644
index 0000000000..28e99be053
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_arith.erl
@@ -0,0 +1,72 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%---------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%%
+%%% Contains tests cases for compilation of arithmetic.
+%%%---------------------------------------------------------------------
+-module(basic_arith).
+
+-export([test/0]).
+
+test() ->
+ ok = test_rem(),
+ ok = test_bit_ops(),
+ ok = test_uplus(),
+ ok = test_bsl_errors(),
+ ok.
+
+%%----------------------------------------------------------------------
+%% Tests the remainder operator.
+
+test_rem() ->
+ 2 = ret_rem(42, 20),
+ -2 = ret_rem(-42, 20),
+ -2 = ret_rem(-42, -20),
+ {'EXIT', {badarith, _}} = ret_rem(3.14, 2),
+ {'EXIT', {badarith, _}} = ret_rem(42, 3.14),
+ ok.
+
+ret_rem(X, Y) ->
+ catch X rem Y.
+
+%%----------------------------------------------------------------------
+%%
+
+test_bit_ops() ->
+ 2 = bbb(11, 2, 16#3ff),
+ ok.
+
+bbb(X, Y, Z) ->
+ ((1 bsl X) bor Y) band Z.
+
+%%----------------------------------------------------------------------
+%% Tests unary plus: it used to be the identity function but not anymore
+
+test_uplus() ->
+ badarith = try uplus(gazonk) catch error:Err -> Err end,
+ 42 = uplus(42),
+ ok.
+
+uplus(X) -> +(X).
+
+%%----------------------------------------------------------------------
+%% The first part of this test triggered a bug in the emulator as one
+%% of the arguments to bsl is not an integer.
+%%
+%% The second part triggered a compilation crash since an arithmetic
+%% expression resulting in a 'system_limit' exception was statically
+%% evaluated and an arithmetic result was expected.
+
+test_bsl_errors() ->
+ {'EXIT', {'badarith', _}} = (catch (t1(0, pad, 0))),
+ badarith = try t2(0, pad, 0) catch error:Err1 -> Err1 end,
+ system_limit = try (id(1) bsl 100000000) catch error:Err2 -> Err2 end,
+ ok.
+
+t1(_, X, _) ->
+ (1 bsl X) + 1.
+
+t2(_, X, _) ->
+ (X bsl 1) + 1.
+
+id(I) -> I.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_beam_instrs.erl b/lib/hipe/test/basic_SUITE_data/basic_beam_instrs.erl
new file mode 100644
index 0000000000..6fafea3b09
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_beam_instrs.erl
@@ -0,0 +1,102 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%%
+%%% Tests for correct translation of various BEAM instructions.
+%%%-------------------------------------------------------------------
+-module(basic_beam_instrs).
+
+-export([test/0]).
+
+test() ->
+ ok = test_make_fun(),
+ ok = test_switch_val(),
+ ok = test_put_literal(),
+ ok = test_set_tuple_element(),
+ ok = test_unguarded_unsafe_element(),
+ ok.
+
+%%--------------------------------------------------------------------
+%% Tests whether the translation of make_fun works.
+
+test_make_fun() ->
+ {F, G} = double_the_fun(),
+ ok = F(),
+ {ok, 42} = G(42),
+ FV1 = {ok, free_var1},
+ FV2 = {also, {free, var2}},
+ {FV1, {ok, [bv]}, FV2} = contains_fun(FV1, ignored, FV2),
+ ok.
+
+double_the_fun() ->
+ {fun () -> ok end, fun (V) -> {ok, V} end}.
+
+contains_fun(X, _IGNORED_ARG, Y) ->
+ calls_fun(fun(Term) -> {X, Term, Y} end).
+
+calls_fun(F) ->
+ F({ok, [bv]}).
+
+%%--------------------------------------------------------------------
+%% Tests whether the translation of switch_val works.
+
+test_switch_val() ->
+ 'A' = sv(a),
+ 'B' = sv(b),
+ 'C' = sv(c),
+ foo = sv(d),
+ ok.
+
+sv(a) -> 'A';
+sv(b) -> 'B';
+sv(c) -> 'C';
+sv(_) -> foo.
+
+%%--------------------------------------------------------------------
+%% Tests correct handling of literals (statically constant terms)
+
+-define(QUADRUPLE, {a,b,c,42}).
+-define(DEEP_LIST, [42,[42,[42]]]).
+
+test_put_literal() ->
+ ?QUADRUPLE = mk_literal_quadruple(),
+ ?DEEP_LIST = mk_literal_deep_list(),
+ ok.
+
+mk_literal_quadruple() ->
+ ?QUADRUPLE.
+
+mk_literal_deep_list() ->
+ ?DEEP_LIST.
+
+%%--------------------------------------------------------------------
+%% Tests whether the translation of set_tuple_element works.
+
+-record(rec, {f1, f2, f3, f4, f5}).
+
+test_set_tuple_element() ->
+ F2 = [a,b,c], F4 = {a,b},
+ State0 = init_rec(F2, F4),
+ State1 = simple_set(State0, 42),
+ #rec{f1 = foo, f2 = F2, f3 = 42, f4 = F4, f5 = 42.0} = odd_set(State1, 21),
+ ok.
+
+init_rec(F2, F4) ->
+ #rec{f1 = bar, f2 = F2, f3 = 10, f4 = F4, f5 = 3.14}.
+
+simple_set(State, Val) -> %% f3 = Val is the one used in set_element;
+ State#rec{f3 = Val, f5 = Val*2}. %% this checks the case of variable
+
+odd_set(State, Val) -> %% f3 = foo is the one used in set_element;
+ State#rec{f1 = foo, f5 = Val*2.0}. %% this checks the case of constant
+
+%%--------------------------------------------------------------------
+%% Tests the handling of unguarded unsafe_element operations that BEAM
+%% can sometimes construct on records (when it has enough context).
+
+test_unguarded_unsafe_element() ->
+ {badrecord, rec} = try unguarded_unsafe_element(42) catch error:E -> E end,
+ ok.
+
+unguarded_unsafe_element(X) ->
+ X#rec{f1 = X#rec.f3}.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_bifs.erl b/lib/hipe/test/basic_SUITE_data/basic_bifs.erl
new file mode 100644
index 0000000000..e7ee2f3678
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_bifs.erl
@@ -0,0 +1,257 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%%
+%%% Contains tests for handling of BIFs in guards and body calls.
+%%%-------------------------------------------------------------------
+-module(basic_bifs).
+
+-export([test/0]).
+
+-define(BIG, 1398479237498374913984792374983749).
+
+test() ->
+ ok = test_abs(),
+ ok = test_binary_part(),
+ ok = test_element(),
+ ok = test_float(),
+ ok = test_float_to_list(),
+ ok = test_integer_to_list(),
+ ok = test_list_to_float(),
+ ok = test_list_to_integer(),
+ ok = test_round(),
+ ok = test_trunc(),
+ ok.
+
+%%--------------------------------------------------------------------
+
+test_abs() ->
+ t_abs(5.5, 0.0, -100.0, 5, 0, -100, ?BIG).
+
+t_abs(F1, F2, F3, I1, I2, I3, BigNum) ->
+ %% Floats.
+ 5.5 = abs(F1),
+ 0.0 = abs(F2),
+ 100.0 = abs(F3),
+ %% Integers.
+ 5 = abs(I1),
+ 0 = abs(I2),
+ 100 = abs(I3),
+ %% Bignums.
+ BigNum = abs(BigNum),
+ BigNum = abs(-BigNum),
+ ok.
+
+%%--------------------------------------------------------------------
+%% Checks that 2-ary and 3-ary BIFs can be compiled to native code.
+
+test_binary_part() ->
+ Bin = <<1,2,3,4,5,6,7,8,9,10>>,
+ BinPart = bp3(Bin),
+ <<7,8>> = bp2(BinPart),
+ ok.
+
+bp2(Bin) ->
+ binary_part(Bin, {1, 2}).
+
+bp3(Bin) ->
+ binary_part(Bin, byte_size(Bin), -5).
+
+%%--------------------------------------------------------------------
+
+test_element() ->
+ true = elem({a, b}),
+ false = elem({a, c}),
+ other = elem(gazonk),
+ ok.
+
+elem(T) when element(1, T) == a -> element(2, T) == b;
+elem(_) -> other.
+
+%%--------------------------------------------------------------------
+
+test_float() ->
+ t_float(0, 42, -100, 2.5, 0.0, -100.42, ?BIG, -?BIG).
+
+t_float(I1, I2, I3, F1, F2, F3, B1, B2) ->
+ 0.0 = float(I1),
+ 2.5 = float(F1),
+ 0.0 = float(F2),
+ -100.42 = float(F3),
+ 42.0 = float(I2),
+ -100.0 = float(I3),
+ %% Bignums.
+ 1398479237498374913984792374983749.0 = float(B1),
+ -1398479237498374913984792374983749.0 = float(B2),
+ %% Extremly big bignums.
+ Big = list_to_integer(duplicate(2000, $1)),
+ {'EXIT', _} = (catch float(Big)),
+ %% Invalid types and lists.
+ {'EXIT', _} = (catch my_list_to_integer(atom)),
+ {'EXIT', _} = (catch my_list_to_integer(123)),
+ {'EXIT', _} = (catch my_list_to_integer([$1, [$2]])),
+ {'EXIT', _} = (catch my_list_to_integer("1.2")),
+ {'EXIT', _} = (catch my_list_to_integer("a")),
+ {'EXIT', _} = (catch my_list_to_integer("")),
+ ok.
+
+my_list_to_integer(X) ->
+ list_to_integer(X).
+
+%%--------------------------------------------------------------------
+
+test_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 \n 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.
+
+%%--------------------------------------------------------------------
+
+test_integer_to_list() ->
+ t_integer_to_list(0, 42, 32768, 268435455, 123456932798748738738).
+
+t_integer_to_list(I1, I2, I3, I4, BIG) ->
+ "0" = integer_to_list(I1),
+ "42" = integer_to_list(I2),
+ "-42" = integer_to_list(-I2),
+ "-42" = integer_to_list(-I2),
+ "32768" = integer_to_list(I3),
+ "268435455" = integer_to_list(I4),
+ "-268435455" = integer_to_list(-I4),
+ "123456932798748738738" = integer_to_list(BIG),
+ BigList = duplicate(2000, $1),
+ Big = list_to_integer(BigList),
+ BigList = integer_to_list(Big),
+ ok.
+
+%%--------------------------------------------------------------------
+
+test_list_to_float() ->
+ ok = t_list_to_float_safe(),
+ ok = t_list_to_float_risky().
+
+t_list_to_float_safe() ->
+ 0.0 = my_list_to_float("0.0"),
+ 0.0 = my_list_to_float("-0.0"),
+ 0.5 = my_list_to_float("0.5"),
+ -0.5 = my_list_to_float("-0.5"),
+ 100.0 = my_list_to_float("1.0e2"),
+ 127.5 = my_list_to_float("127.5"),
+ -199.5 = my_list_to_float("-199.5"),
+ {'EXIT', _} = (catch my_list_to_float("0")),
+ {'EXIT', _} = (catch my_list_to_float("0..0")),
+ {'EXIT', _} = (catch my_list_to_float("0e12")),
+ {'EXIT', _} = (catch my_list_to_float("--0.0")),
+ ok.
+
+my_list_to_float(X) ->
+ list_to_float(X).
+
+%% This might crash the emulator. (Used to crash Erlang 4.4.1 on Unix.)
+
+t_list_to_float_risky() ->
+ Many_Ones = duplicate(25000, $1),
+ ok = case list_to_float("2." ++ Many_Ones) of
+ F when is_float(F), 0.0 < F, F =< 3.14 -> ok
+ end,
+ {'EXIT', _} = (catch list_to_float("2" ++ Many_Ones)),
+ ok.
+
+%%--------------------------------------------------------------------
+
+test_list_to_integer() ->
+ ok = t_list_to_integer_small("0", "00", "-0", "1", "-1", "42", "-12",
+ "32768", "268435455", "-268435455"),
+ ok = t_list_to_integer_bignum("123456932798748738738666"),
+ ok.
+
+t_list_to_integer_small(S1, S2, S3, S4, S5, S6, S7, S8, S9, S10) ->
+ 0 = list_to_integer(S1),
+ 0 = list_to_integer(S2),
+ 0 = list_to_integer(S3),
+ 1 = list_to_integer(S4),
+ -1 = list_to_integer(S5),
+ 42 = list_to_integer(S6),
+ -12 = list_to_integer(S7),
+ 32768 = list_to_integer(S8),
+ 268435455 = list_to_integer(S9),
+ -268435455 = list_to_integer(S10),
+ ok.
+
+t_list_to_integer_bignum(S) ->
+ 123456932798748738738666 = list_to_integer(S),
+ case list_to_integer(duplicate(2000, $1)) of
+ I when is_integer(I), I > 123456932798748738738666 -> ok
+ end.
+
+%%--------------------------------------------------------------------
+
+test_round() ->
+ ok = t_round_small(0.0, 0.4, 0.5, -0.4, -0.5, 255.3, 255.6, -1033.3, -1033.6),
+ ok = t_round_big(4294967296.1, 4294967296.9),
+ ok.
+
+t_round_small(F1, F2, F3, F4, F5, F6, F7, F8, F9) ->
+ 0 = round(F1),
+ 0 = round(F2),
+ 1 = round(F3),
+ 0 = round(F4),
+ -1 = round(F5),
+ 255 = round(F6),
+ 256 = round(F7),
+ -1033 = round(F8),
+ -1034 = round(F9),
+ ok.
+
+t_round_big(B1, B2) ->
+ 4294967296 = round(B1),
+ 4294967297 = round(B2),
+ -4294967296 = round(-B1),
+ -4294967297 = round(-B2),
+ ok.
+
+%%--------------------------------------------------------------------
+
+test_trunc() ->
+ t_trunc(0.0, 5.3333, -10.978987, 4294967305.7).
+
+t_trunc(F1, F2, F3, B) ->
+ 0 = trunc(F1),
+ 5 = trunc(F2),
+ -10 = trunc(F3),
+ %% Bignums.
+ 4294967305 = trunc(B),
+ -4294967305 = trunc(-B),
+ ok.
+
+%%--------------------------------------------------------------------
+%% Auxiliary functions below
+
+duplicate(N, X) when is_integer(N), N >= 0 ->
+ duplicate(N, X, []).
+
+duplicate(0, _, L) -> L;
+duplicate(N, X, L) -> duplicate(N-1, X, [X|L]).
diff --git a/lib/hipe/test/basic_SUITE_data/basic_bignums.erl b/lib/hipe/test/basic_SUITE_data/basic_bignums.erl
new file mode 100644
index 0000000000..e3b523b3f5
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_bignums.erl
@@ -0,0 +1,143 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%%
+%%% Contains code examples that test bignum arithmetic and matching.
+%%%-------------------------------------------------------------------
+-module(basic_bignums).
+
+-export([test/0, test_bsl/0]).
+
+test() ->
+ ok = test_ops(),
+ ok = test_big_fac(),
+ ok = test_int_overfl_32(),
+ ok = test_int_overfl_64(),
+ ok = test_int_overfl_32_guard(),
+ ok = test_int_overfl_64_guard(),
+ ok.
+
+%%--------------------------------------------------------------------
+%% Define some constants for the tests of arithmetic operators
+
+-define(X, 68719476736).
+-define(Y, 98765432101234).
+-define(Z, 4722366482869645213696).
+-define(W, 339254531512339254531512).
+
+-define(B1, 4398046511104).
+-define(B5, 1645504557321206042154969182557350504982735865633579863348609024).
+-define(B17, 86182066610968551542636378241108028056376767329454880514019834315878107616003372189510312530372009184902888961739623919010110377987011442493486117202360415845666384627768436296772219009176743399772868636439042064384).
+
+%%--------------------------------------------------------------------
+
+test_ops() ->
+ ok = test_mult(),
+ ok = test_div(),
+ ok = test_round(),
+ ok = test_trunc(),
+ ok = test_bsl(),
+ ok.
+
+test_mult() ->
+ ?Z = mult(?X, ?X),
+ ok.
+
+mult(X, Y) -> X * Y.
+
+test_div() ->
+ 4 = div_f(339254531512, ?X),
+ 0 = div_f(?Y, ?Y+1),
+ 64 = div_f(?B1, ?X),
+ ?X = div_f(?Z, ?X),
+ 1073741824 = div_f(?Z, ?B1),
+ ok.
+
+div_f(X, Y) -> X div Y.
+
+test_round() ->
+ 0 = round_f(?Z, ?W),
+ 1 = round_f(?Y, ?Y),
+ 71 = round_f(?W, ?Z),
+ 1437 = round_f(?Y, ?X),
+ 47813960 = round_f(?Z, ?Y),
+ 4936803183406 = round_f(?W, ?X),
+ ok.
+
+trunc_f(X, Y) -> round(X/Y).
+
+test_trunc() ->
+ 0 = trunc_f(?Z, ?W),
+ 1 = trunc_f(?Y, ?Y),
+ 72 = trunc_f(?W, ?Z),
+ 1437 = trunc_f(?Y, ?X),
+ 47813961 = trunc_f(?Z, ?Y),
+ 4936803183407 = trunc_f(?W, ?X),
+ ok.
+
+round_f(X, Y) -> trunc(X/Y).
+
+test_bsl() ->
+ ?B1 = bsl_f(1, 42),
+ ?B5 = n(5, fun erlang:'bsl'/2, 1, 42), % use the operator
+ ?B17 = n(17, fun bsl_f/2, 1, 42), % use the local function
+ ok.
+
+bsl_f(X, Y) -> X bsl Y.
+
+%% applies a binary function N times
+n(1, F, X, Y) -> F(X, Y);
+n(N, F, X, Y) when N > 1 -> n(N-1, F, F(X, Y), Y).
+
+%%--------------------------------------------------------------------
+
+-define(FAC42, 1405006117752879898543142606244511569936384000000000).
+
+test_big_fac() ->
+ ?FAC42 = fac(42),
+ ok.
+
+fac(0) -> 1;
+fac(N) -> N * fac(N-1).
+
+%%--------------------------------------------------------------------
+%% Tests for correct handling of integer overflow
+
+test_int_overfl_32() ->
+ 16#7FFFFFF = add(16#7FFFFFF, 0),
+ 16#8000000 = add(16#8000000, 0),
+ 16#8000001 = add(16#8000000, 1),
+ case add(16#7FFFFFF, 1) of
+ 16#8000000 -> ok;
+ -16#7FFFFFF -> error
+ end.
+
+test_int_overfl_64() ->
+ 16#7FFFFFFFFFFFFFF = add(16#7FFFFFFFFFFFFFF, 0),
+ 16#800000000000000 = add(16#800000000000000, 0),
+ 16#800000000000001 = add(16#800000000000000, 1),
+ case add(16#7FFFFFFFFFFFFFF, 1) of
+ 16#800000000000000 -> ok;
+ -16#7FFFFFFFFFFFFFF -> error
+ end.
+
+add(X, Y) -> X + Y.
+
+%%--------------------------------------------------------------------
+%% Tests for correct handling of integer overflow in guards
+
+test_int_overfl_32_guard() ->
+ ok = overfl_in_guard(16#7ffffff, 0),
+ ok = overfl_in_guard(16#7ffffff, 16#7ffffff),
+ ok.
+
+test_int_overfl_64_guard() ->
+ ok = overfl_in_guard(16#7ffffffffffffff, 0),
+ ok = overfl_in_guard(16#7ffffffffffffff, 16#7ffffffffffffff),
+ ok.
+
+overfl_in_guard(X, Y) ->
+ case ok of
+ V when X+Y > 12 -> V;
+ _ -> bad
+ end.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_boolean.erl b/lib/hipe/test/basic_SUITE_data/basic_boolean.erl
new file mode 100644
index 0000000000..e4a91ef5af
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_boolean.erl
@@ -0,0 +1,47 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%%
+%%% Tests for correct translation of booleans and their primitives.
+%%%-------------------------------------------------------------------
+-module(basic_boolean).
+
+-export([test/0]).
+
+test() ->
+ ok = test_boolean_ops(false, true),
+ ok = test_orelse_redundant(),
+ ok.
+
+%%--------------------------------------------------------------------
+
+test_boolean_ops(F, T) ->
+ true = T and T,
+ false = T and F,
+ false = F and T,
+ false = F and F,
+ true = T or T,
+ true = T or F,
+ true = F or T,
+ false = F or F,
+ true = T andalso T,
+ false = T andalso F,
+ false = F andalso T,
+ false = F andalso F,
+ true = T orelse T,
+ true = T orelse F,
+ true = F orelse T,
+ false = F orelse F,
+ ok.
+
+%%--------------------------------------------------------------------
+%% Redundant test in BEAM code will generate type warning.
+
+test_orelse_redundant() ->
+ true = test_orelse(true, true, true),
+ ok.
+
+test_orelse(A, B, C) ->
+ A andalso B orelse C.
+
+%%--------------------------------------------------------------------
diff --git a/lib/hipe/test/basic_SUITE_data/basic_bugs_beam.erl b/lib/hipe/test/basic_SUITE_data/basic_bugs_beam.erl
new file mode 100644
index 0000000000..964b0f423a
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_bugs_beam.erl
@@ -0,0 +1,138 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%%
+%%% Contains code examples that exhibited bugs in the BEAM compiler.
+%%%-------------------------------------------------------------------
+-module(basic_bugs_beam).
+
+-export([test/0]).
+
+%% the following is needed for the test_weird_message
+-export([loop/1]).
+%% the following are needed for the test_catch_bug
+-behaviour(gen_server).
+-export([start_link/1]).
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+test() ->
+ ok = test_fp_basic_blocks(),
+ ok = test_weird_message(),
+ ok = test_catch_bug(),
+ ok.
+
+%%--------------------------------------------------------------------
+%% Test which shows that BEAM's splitting of basic blocks should take
+%% into account that arithmetic operations implemented as BIFs can
+%% also cause exceptions and thus calls to BIFs should end basic blocks.
+%%
+%% Investigated and fixed in the beginning of April 2004.
+%%--------------------------------------------------------------------
+
+test_fp_basic_blocks() ->
+ ok = t1(),
+ ok = t2().
+
+t1() ->
+ X = (catch bad_arith1(2.0, 1.7)),
+ case X of
+ {'EXIT', {badarith, _}} ->
+ ok;
+ _ ->
+ error
+ end.
+
+bad_arith1(X, Y) when is_float(X) ->
+ X1 = X * 1.7e+308,
+ X2 = X1 + 1.0,
+ Y1 = Y * 2,
+ {X2, Y1}.
+
+%% Similarly, it is not kosher to have anything that can fail inside
+%% the fp block since it will throw the exception before the fp
+%% exception and we will get the same problems.
+
+t2() ->
+ case catch bad_arith2(2.0, []) of
+ {'EXIT', {badarith, _}} ->
+ ok;
+ _ ->
+ error
+ end.
+
+bad_arith2(X, Y) when is_float(X) ->
+ X1 = X * 1.7e+308,
+ Y1 = element(1, Y),
+ {X1 + 1.0, Y1}.
+
+%%--------------------------------------------------------------------
+%% Sending 'test' to this process should return 'ok'. But:
+%%
+%% 1> MOD:test().
+%% Weird: received true
+%% timeout
+%%
+%% Surprisingly, the message has been bound to the value of 'ena'
+%% in the record! The problem was visible in the .S file.
+%%--------------------------------------------------------------------
+
+-record(state, {ena = true}).
+
+test_weird_message() ->
+ P = spawn_link(?MODULE, loop, [#state{}]),
+ P ! {msg, self()},
+ receive
+ What -> What
+ after 42 -> timeout
+ end.
+
+loop(S) ->
+ receive
+ _ when S#state.ena == false ->
+ io:format("Weird: ena is false\n");
+ % loop(S);
+ {msg, Pid} ->
+ Pid ! ok;
+ % loop(S);
+ Other ->
+ io:format("Weird: received ~p\n", [Other])
+ % loop(S)
+ end.
+
+%%--------------------------------------------------------------------
+%% This was posted on the Erlang mailing list as a question:
+%%
+%% Given the module below and the function call
+%% "catch_bug:start_link(foo)."
+%% from the Erlang shell, why does Erlang crash with "Catch not found"?
+%%
+%% The BEAM compiler was generating wrong code for this case;
+%% this was fixed in R9C-0. Native code generation was OK.
+%%--------------------------------------------------------------------
+
+test_catch_bug() ->
+ ignore = start_link(foo),
+ ok.
+
+start_link(Param) ->
+ gen_server:start_link(?MODULE, Param, []).
+
+init(Param) ->
+ process_flag(trap_exit, true),
+ (catch begin
+ dummy(Param),
+ (catch exit(bar))
+ end
+ ),
+ ignore.
+
+dummy(_) -> ok.
+
+%% gen_server callbacks below
+handle_call(_Call, _From, State) -> {noreply, State}.
+handle_cast(_Msg, State) -> {noreply, State}.
+handle_info(_Msg, State) -> {noreply, State}.
+terminate(_Reason, _State) -> ok.
+code_change(_OldVsn, State, _Extra) -> {ok, State}.
+
diff --git a/lib/hipe/test/basic_SUITE_data/basic_bugs_hipe.erl b/lib/hipe/test/basic_SUITE_data/basic_bugs_hipe.erl
new file mode 100644
index 0000000000..caa0e71d0b
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_bugs_hipe.erl
@@ -0,0 +1,463 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%----------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%%
+%%% Contains code examples that exhibited bugs in the HiPE compiler.
+%%%----------------------------------------------------------------------
+-module(basic_bugs_hipe).
+
+-export([test/0]).
+
+test() ->
+ ok = test_ets_bifs(),
+ ok = test_szar_bug(),
+ ok = test_bit_shift(),
+ ok = test_match_big_list(),
+ ok = test_unsafe_bsl(),
+ ok = test_unsafe_bsr(),
+ ok = test_R12B5_seg_fault(),
+ ok = test_switch_neg_int(),
+ ok = test_icode_range_anal(),
+ ok.
+
+%%-----------------------------------------------------------------------
+%% From: Bjorn Gustavsson
+%%
+%% This code, if HiPE compiled, crashed like this (on SPARC)
+%%
+%% (gdb) where
+%% #0 fullsweep_heap (p=0x2c60dc, new_sz=610, objv=0xffbee8b4, nobj=3)
+%% at beam/ggc.c:1060
+%% #1 0x7ff24 in erts_garbage_collect (p=0x2c60dc, need=2, objv=0x1128fc, ...)
+%% at beam/ggc.c:1648
+%% #2 0xab6fc in hipe_mode_switch (p=0x2c60dc, cmd=704512, reg=0x1128fc)
+%% at hipe/hipe_mode_switch.c:180
+%% #3 0x8e27c in process_main () at beam/beam_emu.c:3314
+%% #4 0x31338 in erl_start (argc=9, argv=0xffbeed5c) at beam/erl_init.c:936
+%% #5 0x2d9f4 in main (argc=9, argv=0xffbeed5c) at sys/unix/erl_main.c:28
+%%
+%% A guess at what could be the problem: From R8, many ets BIFs trap
+%% to other ets BIFs with a *different* arity (i.e. they have more or
+%% less arguments). I have probably forgotten to mention that subtle
+%% change.
+%%-----------------------------------------------------------------------
+
+test_ets_bifs() ->
+ Seed = {1032, 15890, 22716},
+ put(random_seed, Seed),
+ do_random_test().
+
+do_random_test() ->
+ OrdSet = ets:new(xxx, [ordered_set]),
+ Set = ets:new(xxx, []),
+ do_n_times(fun() ->
+ Key = create_random_string(25),
+ Value = create_random_tuple(25),
+ ets:insert(OrdSet, {Key, Value}),
+ ets:insert(Set, {Key, Value})
+ end, 5000),
+ %% io:format("~nData inserted~n"),
+ do_n_times(fun() ->
+ I = random:uniform(25),
+ Key = create_random_string(I) ++ '_',
+ L1 = ets_match_object(OrdSet, {Key, '_'}),
+ L2 = lists:sort(ets_match_object(Set, {Key, '_'})),
+ case L1 == L2 of
+ false ->
+ %% io:format("~p != ~p~n", [L1, L2]),
+ exit({not_eq, L1, L2});
+ true ->
+ ok
+ end
+ end, 2000),
+ %% io:format("~nData matched~n"),
+ ets:match_delete(OrdSet, '_'),
+ ets:match_delete(Set, '_'),
+ ok.
+
+create_random_string(0) ->
+ [];
+create_random_string(OfLength) ->
+ C = case random:uniform(2) of
+ 1 -> (random:uniform($Z - $A + 1) - 1) + $A;
+ _ -> (random:uniform($z - $a + 1) - 1) + $a
+ end,
+ [C | create_random_string(OfLength - 1)].
+
+create_random_tuple(OfLength) ->
+ list_to_tuple([list_to_atom([X]) || X <- create_random_string(OfLength)]).
+
+ets_match_object(Tab,Expr) ->
+ case random:uniform(2) of
+ 1 -> ets:match_object(Tab,Expr);
+ _ -> match_object_chunked(Tab,Expr)
+ end.
+
+match_object_chunked(Tab,Expr) ->
+ match_object_chunked_collect(ets:match_object(Tab, Expr,
+ random:uniform(1999) + 1)).
+
+match_object_chunked_collect('$end_of_table') ->
+ [];
+match_object_chunked_collect({Results, Continuation}) ->
+ Results ++ match_object_chunked_collect(ets:match_object(Continuation)).
+
+do_n_times(_, 0) ->
+ ok;
+do_n_times(Fun, N) ->
+ Fun(),
+ case N rem 1000 of
+ 0 -> ok; %% WAS: io:format(".");
+ _ -> ok
+ end,
+ do_n_times(Fun, N - 1).
+
+%%-----------------------------------------------------------------------
+%% From: Jozsef Berces (PR/ECZ)
+%% Date: Feb 19, 2004
+%%
+%% Program which was added to the testsuite as a result of another bug
+%% report involving tuples as funs. Thanks God, these are no longer
+%% supported, but the following is a good test for testing calling
+%% native code funs from BEAM code (lists:map, lists:filter, ...).
+%%-----------------------------------------------------------------------
+
+test_szar_bug() ->
+ ["A","B","C"] = smartconcat([], "H'A, H'B, H'C"),
+ ok.
+
+smartconcat(B, L) ->
+ LL = tokenize(L, $,),
+ NewlineDel = fun (X) -> killcontrol(X) end,
+ StripFun = fun (X) -> string:strip(X) end,
+ LL2 = lists:map(NewlineDel, lists:map(StripFun, LL)),
+ EmptyDel = fun(X) ->
+ case string:len(X) of
+ 0 -> false;
+ _ -> true
+ end
+ end,
+ LL3 = lists:filter(EmptyDel, LL2),
+ HexFormat = fun(X, Acc) ->
+ case string:str(X, "H'") of
+ 1 ->
+ case checkhex(string:substr(X, 3)) of
+ {ok, Y} ->
+ {Y, Acc};
+ _ ->
+ {X, Acc + 1}
+ end;
+ _ ->
+ {X, Acc + 1}
+ end
+ end,
+ {LL4,_Ret} = lists:mapfoldl(HexFormat, 0, LL3),
+ lists:append(B, lists:sublist(LL4, lists:max([0, 25 - length(B)]))).
+
+checkhex(L) ->
+ checkhex(L, "").
+
+checkhex([H | T], N) when H >= $0, H =< $9 ->
+ checkhex(T, [H | N]);
+checkhex([H | T], N) when H >= $A, H =< $F ->
+ checkhex(T, [H | N]);
+checkhex([H | T], N) when H =< 32 ->
+ checkhex(T, N);
+checkhex([_ | _], _) ->
+ {error, ""};
+checkhex([], N) ->
+ {ok, lists:reverse(N)}.
+
+killcontrol([C | S]) when C < 32 ->
+ killcontrol(S);
+killcontrol([C | S]) ->
+ [C | killcontrol(S)];
+killcontrol([]) ->
+ [].
+
+tokenize(L, C) ->
+ tokenize(L, C, [], []).
+
+tokenize([C | T], C, A, B) ->
+ case A of
+ [] ->
+ tokenize(T, C, [], B);
+ _ ->
+ tokenize(T, C, [], [lists:reverse(A) | B])
+ end;
+tokenize([H | T], C, A, B) ->
+ tokenize(T, C, [H | A], B);
+tokenize(_, _, [], B) ->
+ lists:reverse(B);
+tokenize(_, _, A, B) ->
+ lists:reverse([lists:reverse(A) | B]).
+
+%%-----------------------------------------------------------------------
+%% From: Niclas Pehrsson
+%% Date: Apr 20, 2006
+%%
+%% We found something weird with the bit shifting in HiPE. It seems
+%% that bsr in some cases shifts the bits in the wrong way...
+%%
+%% Fixed about 10 mins afterwards; was a bug in constant propagation.
+%%-----------------------------------------------------------------------
+
+test_bit_shift() ->
+ 1 = plain_shift(), % 1
+ 6 = length_list_plus(), % 6
+ 0 = shift_length_list(), % 0
+ 1 = shift_length_list_plus(), % 1
+ 1 = shift_length_list_plus2(), % 1
+ 24 = shift_length_list_plus_bsl(), % 24
+ 1 = shift_fun(), % 1
+ %% {1, 6, 0, 1, 1, 24, 1} = {A, B, C, D, E, F, G},
+ ok.
+
+plain_shift() ->
+ 6 bsr 2.
+
+length_list() ->
+ length([0,0]).
+
+length_list_plus() ->
+ length([0,0]) + 4.
+
+shift_length_list() ->
+ length([0,0]) bsr 2.
+
+shift_length_list_plus() ->
+ (length([0,0]) + 4) bsr 2.
+
+shift_length_list_plus_bsl() ->
+ (length([0,0]) + 4) bsl 2.
+
+shift_length_list_plus2() ->
+ N = length([0,0]) + 4,
+ N bsr 2.
+
+shift_fun() ->
+ (length_list() + 4) bsr 2.
+
+%%-----------------------------------------------------------------------
+%% From: Igor Goryachev
+%% Date: June 15, 2006
+%%
+%% I have experienced a different behaviour and possibly a weird result
+%% while playing with matching a big list on x86 and x86_64 machines.
+%%-----------------------------------------------------------------------
+
+-define(BIG_LIST,
+ ["uid", "nickname", "n_family", "n_given", "email_pref",
+ "tel_home_number", "tel_cellular_number", "adr_home_country",
+ "adr_home_locality", "adr_home_region", "url", "gender", "bday",
+ "constitution", "height", "weight", "hair", "routine", "smoke",
+ "maritalstatus", "children", "independence", "school_number",
+ "school_locality", "school_title", "school_period", "org_orgname",
+ "title", "adr_work_locality", "photo_type", "photo_binval"]).
+
+test_match_big_list() ->
+ case create_tuple_with_big_const_list() of
+ {selected, ?BIG_LIST, _} -> ok;
+ _ -> weird
+ end.
+
+create_tuple_with_big_const_list() ->
+ {selected, ?BIG_LIST, [{"test"}]}.
+
+%%-----------------------------------------------------------------------
+%% In October 2006 the HiPE compiler acquired more type-driven
+%% optimisations of arithmetic operations. One of these, the
+%% transformation of bsl to a pure fixnum bsl fixnum -> fixnum version
+%% (unsafe_bsl), was incorrectly performed even when the result
+%% wouldn't be a fixnum. The error occurred for all backends, but the
+%% only place known to break was hipe_arm:imm_to_am1/2. Some
+%% immediates got broken on ARM, causing segmentation faults in
+%% compiler_tests when HiPE recompiled itself.
+%%-----------------------------------------------------------------------
+
+test_unsafe_bsl() ->
+ ok = bsl_check(bsl_test_cases()).
+
+bsl_test_cases() ->
+ [{16#FF, {16#FF, 0}},
+ {16#F000000F, {16#FF, 2}}].
+
+bsl_check([]) -> ok;
+bsl_check([{X, Y}|Rest]) ->
+ case imm_to_am1(X) of
+ Y -> bsl_check(Rest);
+ _ -> 'hipe_broke_bsl'
+ end.
+
+imm_to_am1(Imm) ->
+ imm_to_am1(Imm band 16#FFFFFFFF, 16).
+imm_to_am1(Imm, RotCnt) ->
+ if Imm >= 0, Imm =< 255 -> {Imm, RotCnt band 15};
+ true ->
+ NewRotCnt = RotCnt - 1,
+ if NewRotCnt =:= 0 -> []; % full circle, no joy
+ true ->
+ NewImm = (Imm bsr 2) bor ((Imm band 3) bsl 30),
+ imm_to_am1(NewImm, NewRotCnt)
+ end
+ end.
+
+%%-----------------------------------------------------------------------
+%% Another transformation, namely that of bsr to a pure fixnum bsr
+%% fixnum -> fixnum version (unsafe_bsr), failed to check for shifts
+%% larger than the number of bits in fixnums. Such shifts should
+%% return zero, but instead they became plain machine-level shift
+%% instructions. Machines often only consider the low-order bits of
+%% the shift count, so machine-level shifts larger than the word size
+%% do not match the Erlang semantics.
+%%-----------------------------------------------------------------------
+
+test_unsafe_bsr() ->
+ ok = bsr_check(bsr_test_cases()).
+
+bsr_test_cases() ->
+ [{16#FF, 4, 16#0F},
+ {16#FF, 64, 0}].
+
+bsr_check([]) -> ok;
+bsr_check([{X, Y, Z}|Rest]) ->
+ case do_bsr(X, Y) of
+ Z -> bsr_check(Rest);
+ _ -> 'hipe_broke_bsr'
+ end.
+
+do_bsr(X, Y) ->
+ (X band 16#FFFF) bsr (Y band 16#FFFF).
+
+%%-----------------------------------------------------------------------
+%% From: Sergey S, mid January 2009.
+%%
+%% While I was playing with +native option, I run into a bug in HiPE
+%% which leads to segmentation fault using +native and Erlang R12B-5.
+%%
+%% Eshell V5.6.5
+%% 1> crash:test().
+%% # Some message to be printed here each loop iteration
+%% Segmentation fault
+%%
+%% Diagnosed and fixed by Mikael Pettersson (22 Jan 2009):
+%%
+%% I've analysed the recently posted HiPE bug report on erlang-bugs
+%% <http://www.erlang.org/pipermail/erlang-bugs/2009-January/001162.html>.
+%% The segfault is caused by memory corruption, which in turn is caused
+%% by RTL removing an update of the HP (heap pointer) register due to
+%% what looks like broken liveness information.
+%%-----------------------------------------------------------------------
+
+test_R12B5_seg_fault() ->
+ _ = spawn(fun() -> init() end),
+ ok.
+
+init() ->
+ repeat(5, fun() -> void end),
+ receive after infinity -> ok end.
+
+repeat(0, _) ->
+ ok;
+repeat(N, Fun) ->
+ %% io:format("# Some message to be printed here each loop iteration\n"),
+ Fun(),
+ repeat(N - 1, Fun).
+
+%%-----------------------------------------------------------------------
+%% From: Jon Meredith
+%% Date: July 9, 2009
+%%
+%% Binary search key tables are sorted by the loader based on the
+%% runtime representations of the keys as unsigned words. However,
+%% the code generated for the binary search used signed comparisons.
+%% That worked for atoms and non-negative fixnums, but not for
+%% negative fixnums. Fixed by Mikael Pettersson July 10, 2009.
+%%-----------------------------------------------------------------------
+
+test_switch_neg_int() ->
+ ok = f(-80, 8).
+
+f(10, -1) -> ok;
+f(X, Y) ->
+ Y = g(X),
+ f(X + 10, Y - 1).
+
+g(X) -> % g(0) should be 0 but became -1
+ case X of
+ 0 -> 0;
+ -10 -> 1;
+ -20 -> 2;
+ -30 -> 3;
+ -40 -> 4;
+ -50 -> 5;
+ -60 -> 6;
+ -70 -> 7;
+ -80 -> 8;
+ _ -> -1
+ end.
+
+%%-----------------------------------------------------------------------
+%% From: Paul Guyot
+%% Date: Jan 31, 2011
+%%
+%% There is a bug in HiPE compilation with the comparison of floats
+%% with integers. This bug happens in functions f/1 and g/2 below.
+%% BEAM will evaluate f_eq(42) and f_eq(42.0) to true, while HiPE
+%% will evaluate them to false.
+%%
+%% The culprit was the Icode range analysis which was buggy. (On the
+%% other hand, HiPE properly evaluated these calls to true if passed
+%% the option 'no_icode_range'.) Fixed by Kostis Sagonas.
+%% --------------------------------------------------------------------
+
+test_icode_range_anal() ->
+ true = f_eq(42),
+ true = f_eq(42.0),
+ false = f_ne(42),
+ false = f_ne(42.0),
+ false = f_eq_ex(42),
+ false = f_eq_ex(42.0),
+ true = f_ne_ex(42),
+ true = f_ne_ex(42.0),
+ false = f_gt(42),
+ false = f_gt(42.0),
+ true = f_le(42),
+ true = f_le(42.0),
+ zero_test = g(0, test),
+ zero_test = g(0.0, test),
+ non_zero_test = g(42, test),
+ other = g(42, other),
+ ok.
+
+f_eq(X) ->
+ Y = X / 2,
+ Y == 21.
+
+f_ne(X) ->
+ Y = X / 2,
+ Y /= 21.
+
+f_eq_ex(X) ->
+ Y = X / 2,
+ Y =:= 21.
+
+f_ne_ex(X) ->
+ Y = X / 2,
+ Y =/= 21.
+
+f_gt(X) ->
+ Y = X / 2,
+ Y > 21.
+
+f_le(X) ->
+ Y = X / 2,
+ Y =< 21.
+
+g(X, Z) ->
+ Y = X / 2,
+ case Z of
+ test when Y == 0 -> zero_test;
+ test -> non_zero_test;
+ other -> other
+ end.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_comparisons.erl b/lib/hipe/test/basic_SUITE_data/basic_comparisons.erl
new file mode 100644
index 0000000000..8dab2cab1f
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_comparisons.erl
@@ -0,0 +1,157 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%%
+%%% Contains tests for correct execution of comparison operators.
+%%%-------------------------------------------------------------------
+-module(basic_comparisons).
+
+-export([test/0]).
+
+test() ->
+ Ns = [0, 0.0, 42, 42.0, gazonk],
+ T1F4 = [true, false, false, false, false],
+ T2F3 = [true, true, false, false, false],
+ F1T4 = [false, true, true, true, true],
+ F2T3 = [false, false, true, true, true],
+ %% tests for calls
+ T1F4 = [eq_exact_call(0, N) || N <- Ns],
+ F1T4 = [ne_exact_call(0, N) || N <- Ns],
+ T2F3 = [eq_call(0, N) || N <- Ns],
+ F2T3 = [ne_call(0, N) || N <- Ns],
+ %% tests for guards
+ T1F4 = [eq_exact_guard(0, N) || N <- Ns],
+ F1T4 = [ne_exact_guard(0, N) || N <- Ns],
+ T2F3 = [eq_guard(0, N) || N <- Ns],
+ F2T3 = [ne_guard(0, N) || N <- Ns],
+ %% some more tests
+ ok = test_against_zero(),
+ ok = test_against_other_terms(),
+ ok = test_sofs_func(),
+ ok.
+
+test_against_zero() ->
+ Xs = [0, 1, 0.0],
+ [true, false, false] = [is_zero_int(X) || X <- Xs],
+ [true, false, true] = [is_zero_num(X) || X <- Xs],
+ [false, true, true] = [is_nonzero_int(X) || X <- Xs],
+ [false, true, false] = [is_nonzero_num(X) || X <- Xs],
+ ok.
+
+test_against_other_terms() ->
+ TTT = {true, true, true},
+ FFF = {false, false, false},
+ TTT = {is_foo_exact(foo), is_foo_term1(foo), is_foo_term2(foo)},
+ FFF = {is_foo_exact(bar), is_foo_term1(bar), is_foo_term2(bar)},
+ FFF = {is_nonfoo_exact(foo), is_nonfoo_term1(foo), is_nonfoo_term2(foo)},
+ TTT = {is_nonfoo_exact(bar), is_nonfoo_term1(bar), is_nonfoo_term2(bar)},
+ Tup = {a, {42}, [c]},
+ TTT = {is_tuple_skel(Tup), is_tuple_exact(Tup), is_tuple_term(Tup)},
+ BNi = <<42>>,
+ TTT = {is_bin_exact(BNi), is_bin_term1(BNi), is_bin_term2(BNi)},
+ BNf = <<42/float>>,
+ FFF = {is_bin_exact(BNf), is_bin_term1(BNf), is_bin_term2(BNf)},
+ ok.
+
+test_sofs_func() ->
+ L = [0, 0.0],
+ ok = sofs_func(L, L, L).
+
+%%--------------------------------------------------------------------
+%% Test for comparison operators used in body calls
+
+eq_exact_call(X, Y) -> X =:= Y.
+
+ne_exact_call(X, Y) -> X =/= Y.
+
+eq_call(X, Y) -> X == Y.
+
+ne_call(X, Y) -> X /= Y.
+
+%%--------------------------------------------------------------------
+%% Tests for comparison operators used as guards
+
+eq_exact_guard(X, Y) when X =:= Y -> true;
+eq_exact_guard(_, _) -> false.
+
+ne_exact_guard(X, Y) when X =/= Y -> true;
+ne_exact_guard(_, _) -> false.
+
+eq_guard(X, Y) when X == Y -> true;
+eq_guard(_, _) -> false.
+
+ne_guard(X, Y) when X /= Y -> true;
+ne_guard(_, _) -> false.
+
+%%--------------------------------------------------------------------
+
+is_zero_int(N) when N =:= 0 -> true;
+is_zero_int(_) -> false.
+
+is_nonzero_int(N) when N =/= 0 -> true;
+is_nonzero_int(_) -> false.
+
+is_zero_num(N) when N == 0 -> true;
+is_zero_num(_) -> false.
+
+is_nonzero_num(N) when N /= 0 -> true;
+is_nonzero_num(_) -> false.
+
+%%--------------------------------------------------------------------
+%% There should not really be any difference in the generated code
+%% for the following three functions.
+
+is_foo_exact(A) when A =:= foo -> true;
+is_foo_exact(_) -> false.
+
+is_foo_term1(A) when A == foo -> true;
+is_foo_term1(_) -> false.
+
+is_foo_term2(A) when foo == A -> true;
+is_foo_term2(_) -> false.
+
+%%--------------------------------------------------------------------
+%% Same for these cases
+
+is_nonfoo_exact(A) when A =/= foo -> true;
+is_nonfoo_exact(_) -> false.
+
+is_nonfoo_term1(A) when A /= foo -> true;
+is_nonfoo_term1(_) -> false.
+
+is_nonfoo_term2(A) when foo /= A -> true;
+is_nonfoo_term2(_) -> false.
+
+%%--------------------------------------------------------------------
+
+is_tuple_skel({A,{B},[C]}) when is_atom(A), is_integer(B), is_atom(C) -> true;
+is_tuple_skel(T) when is_tuple(T) -> false.
+
+is_tuple_exact(T) when T =:= {a,{42},[c]} -> true;
+is_tuple_exact(T) when is_tuple(T) -> false.
+
+is_tuple_term(T) when T == {a,{42.0},[c]} -> true;
+is_tuple_term(T) when is_tuple(T) -> false.
+
+%%--------------------------------------------------------------------
+%% But for binaries the treatment has to be different, due to the need
+%% for construction of the binary in the guard.
+
+is_bin_exact(B) when B =:= <<42>> -> true;
+is_bin_exact(_) -> false.
+
+is_bin_term1(B) when B == <<42>> -> true;
+is_bin_term1(_) -> false.
+
+is_bin_term2(B) when <<42>> == B -> true;
+is_bin_term2(_) -> false.
+
+%%--------------------------------------------------------------------
+%% a test from sofs.erl which failed at some point
+
+sofs_func([X | Ts], X0, L) when X /= X0 ->
+ sofs_func(Ts, X, L);
+sofs_func([X | _Ts], X0, _L) when X == X0 ->
+ ok;
+sofs_func([], _X0, L) ->
+ L.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_exceptions.erl b/lib/hipe/test/basic_SUITE_data/basic_exceptions.erl
new file mode 100644
index 0000000000..229a0516dc
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_exceptions.erl
@@ -0,0 +1,465 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%%
+%%% Contains tests that raise exceptions and catch them.
+%%%-------------------------------------------------------------------
+-module(basic_exceptions).
+
+-export([test/0, test_catches/0]).
+
+%% functions used as arguments to spawn/3
+-export([bad_guy/2]).
+
+test() ->
+ ok = test_catch_exit(42),
+ ok = test_catch_throw(42),
+ ok = test_catch_element(),
+ ok = test_catch_crash(),
+ ok = test_catch_empty(),
+ ok = test_catch_merge(),
+ ok = test_catches_merged(),
+ ok = test_pending_errors(),
+ ok = test_bad_fun_call(),
+ ok = test_guard_bif(),
+ ok.
+
+%%--------------------------------------------------------------------
+%% Written in 2001 by Erik Johansson.
+
+test_catches() ->
+ ExitBar = {'EXIT', bar},
+ L1 = [ExitBar, ok, ExitBar, {ok, ExitBar}],
+ L1 = [t1(), t2(), t3(), t4()],
+ badarith = (catch element(1, element(2, t5(a, b)))),
+ L2 = [42, ExitBar, ExitBar, {no_exception, ok}],
+ L2 = [t5(21, 21), t6(), t7(), t8()],
+ ok.
+
+t1() ->
+ catch foo().
+
+t2() ->
+ V = (catch ok()),
+ s(),
+ V.
+
+t3() ->
+ V = (catch foo()),
+ V.
+
+t4() ->
+ V1 = ok(),
+ V2 = (catch foo()),
+ {V1, V2}.
+
+t5(A, B) ->
+ catch A + B.
+
+t6() ->
+ catch {no_exception, ok(), foo()}.
+
+t7() ->
+ catch {no_exception, foo(), ok()}.
+
+t8() ->
+ catch {no_exception, ok()}.
+
+foo() ->
+ s(),
+ exit(bar).
+
+ok() -> s(), ok.
+
+s() -> nada.
+
+%%--------------------------------------------------------------------
+
+test_catch_exit(N) ->
+ {'EXIT', N} = (catch exit(N)),
+ {'EXIT', 42} = (catch exit(42)),
+ 42 = try exit(N) catch exit:R1 -> R1 end,
+ 42 = try exit(42) catch exit:R2 -> R2 end,
+ ok.
+
+%%--------------------------------------------------------------------
+
+test_catch_throw(N) ->
+ N = (catch throw(N)),
+ 42 = (catch throw(42)),
+ 42 = try throw(N) catch throw:R1 -> R1 end,
+ 42 = try throw(42) catch throw:R2 -> R2 end,
+ ok.
+
+%%--------------------------------------------------------------------
+
+test_catch_element() ->
+ 'EXIT' = test_catch_element([]),
+ 'EXIT' = test_catch_element(42),
+ ok.
+
+test_catch_element(N) ->
+ element(1, catch element(N, {1,2,3,4,5,6,7,8,9,10,11})).
+
+%%--------------------------------------------------------------------
+
+-define(try_match(E),
+ catch ?MODULE:non_existing(),
+ {'EXIT', {{badmatch, nomatch}, _}} = (catch E = no_match())).
+
+test_catch_crash() ->
+ ?try_match(a),
+ ?try_match(42),
+ ?try_match({a, b, c}),
+ ?try_match([]),
+ ?try_match(1.0),
+ ok.
+
+no_match() -> nomatch.
+
+%% small_test() ->
+%% catch ?MODULE:non_existing(),
+%% io:format("Before\n",[]),
+%% hipe_bifs:show_nstack(self()),
+%% io:format("After\n",[]),
+%% garbage_collect().
+
+%%--------------------------------------------------------------------
+%% Tests whether the HiPE compiler optimizes catches in a way that
+%% does not result in an infinite loop.
+%%--------------------------------------------------------------------
+
+test_catch_empty() ->
+ badmatch().
+
+badmatch() ->
+ Big = ret_big(),
+ Float = ret_float(),
+ catch a = Big,
+ catch b = Float,
+ ok = case Big of Big -> ok end,
+ ok = case Float of Float -> ok end,
+ ok.
+
+ret_big() ->
+ 329847987298478924982978248748729829487298292982972978239874.
+
+ret_float() ->
+ 3.1415927.
+
+%%--------------------------------------------------------------------
+%% Test that shows how BEAM can merge catch-end blocks that belong to
+%% different catch-start instructions. Written by Richard Carlsson.
+%%--------------------------------------------------------------------
+
+test_catch_merge() ->
+ merge(get(whatever)).
+
+merge(foo=X) ->
+ catch f(X),
+ catch g(X);
+merge(X) ->
+ catch f(X),
+ catch g(X).
+
+f(_) -> ok.
+
+g(_) -> ok.
+
+%%--------------------------------------------------------------------
+%% Written by Tobias Lindahl.
+
+test_catches_merged() ->
+ {'EXIT', _} = merged_catches(foo),
+ {'EXIT', {badarith, _}} = merged_catches(bar),
+ {'EXIT', _} = merged_catches(baz),
+ ok.
+
+merged_catches(X) ->
+ case X of
+ foo -> catch fail1(0);
+ bar -> catch {catch(1 = X), fail2(0)};
+ baz -> catch fail3(0)
+ end.
+
+fail1(X) -> 1/X.
+
+fail2(X) -> 1/X.
+
+fail3(X) -> 1/X.
+
+%%--------------------------------------------------------------------
+%% Taken from exception_SUITE.erl
+%%--------------------------------------------------------------------
+
+test_pending_errors() ->
+ error_logger:tty(false), % disable printouts of error reports
+ pending_errors().
+
+%% Test various exceptions, in the presence of a previous error
+%% suppressed in a guard.
+pending_errors() ->
+ pending(e_badmatch, {badmatch, b}),
+ pending(x, function_clause),
+ pending(e_case, {case_clause, xxx}),
+ pending(e_if, if_clause),
+ %% pending(e_badarith, badarith),
+ %% pending(e_undef, undef),
+ pending(e_timeoutval, timeout_value),
+ %% pending(e_badarg, badarg),
+ %% pending(e_badarg_spawn, badarg),
+ ok.
+
+bad_guy(pe_badarith, Other) when Other+1 =:= 0 -> % badarith (suppressed)
+ ok;
+bad_guy(pe_badarg, Other) when length(Other) > 0 -> % badarg (suppressed)
+ ok;
+bad_guy(_, e_case) ->
+ case xxx() of
+ ok -> ok
+ end; % case_clause
+bad_guy(_, e_if) ->
+ B = b(),
+ if
+ a == B -> ok
+ end; % if_clause
+%% bad_guy(_, e_badarith) ->
+%% 1+b; % badarith
+bad_guy(_, e_undef) ->
+ non_existing_module:foo(); % undef
+bad_guy(_, e_timeoutval) ->
+ receive
+ after gazonk -> ok % timeout_value
+ end;
+bad_guy(_, e_badarg) ->
+ node(xxx); % badarg
+bad_guy(_, e_badarg_spawn) ->
+ spawn({}, {}, {}); % badarg
+bad_guy(_, e_badmatch) ->
+ a = b(). % badmatch
+
+xxx() -> xxx.
+
+b() -> b.
+
+pending(Arg, Expected) ->
+ pending(pe_badarith, Arg, Expected),
+ pending(pe_badarg, Arg, Expected).
+
+pending(First, Second, Expected) ->
+ pending_catched(First, Second, Expected),
+ pending_exit_message([First, Second], Expected).
+
+pending_catched(First, Second, Expected) ->
+ %% ok = io:format("Catching bad_guy(~p, ~p)\n", [First, Second]),
+ case catch bad_guy(First, Second) of
+ {'EXIT', Reason} ->
+ pending(Reason, bad_guy, [First, Second], Expected);
+ Other ->
+ exit({not_exit, Other})
+ end.
+
+pending_exit_message(Args, Expected) ->
+ %% ok = io:format("Trapping exits from spawn_link(~p, ~p, ~p)\n",
+ %% [?MODULE, bad_guy, Args]),
+ process_flag(trap_exit, true),
+ Pid = spawn_link(?MODULE, bad_guy, Args),
+ receive
+ {'EXIT', Pid, Reason} ->
+ pending(Reason, bad_guy, Args, Expected);
+ Other ->
+ exit({unexpected_message, Other})
+ after 10000 ->
+ exit(timeout)
+ end,
+ process_flag(trap_exit, false).
+
+%% pending({badarg, [{erlang,Bif,BifArgs},{?MODULE,Func,Arity}|_]},
+%% Func, Args, _Code)
+%% when atom(Bif), list(BifArgs), length(Args) =:= Arity ->
+%% ok;
+pending({badarg,Trace}, _, _, _) when is_list(Trace) ->
+ ok;
+%% pending({undef,[{non_existing_module,foo,[]}|_]}, _, _, _) ->
+%% ok;
+pending({undef,Trace}, _, _, _) when is_list(Trace) ->
+ ok;
+%% pending({function_clause,[{?MODULE,Func,Args}|_]}, Func, Args, _Code) ->
+%% ok;
+pending({function_clause,Trace}, _, _, _) when is_list(Trace) ->
+ ok;
+%% pending({Code,[{?MODULE,Func,Arity}|_]}, Func, Args, Code)
+%% when length(Args) =:= Arity ->
+%% ok;
+pending({Code,Trace}, _, _, Code) when is_list(Trace) ->
+ ok;
+pending(Reason, _Function, _Args, _Code) ->
+ exit({bad_exit_reason, Reason}).
+
+%%--------------------------------------------------------------------
+%% Taken from fun_SUITE.erl
+%%
+%% Checks correct exception throwing when calling a bad fun.
+%%--------------------------------------------------------------------
+
+test_bad_fun_call() ->
+ ok = bad_call_fc(42),
+ ok = bad_call_fc(xx),
+ ok = bad_call_fc({}),
+ ok = bad_call_fc({1}),
+ ok = bad_call_fc({1,2,3}),
+ ok = bad_call_fc({1,2,3}),
+ ok = bad_call_fc({1,2,3,4}),
+ ok = bad_call_fc({1,2,3,4,5,6}),
+ ok = bad_call_fc({1,2,3,4,5}),
+ ok = bad_call_fc({1,2}),
+ ok.
+
+bad_call_fc(Fun) ->
+ Args = [some, stupid, args],
+ Res = (catch Fun(Fun(Args))),
+ case Res of
+ {'EXIT', {{badfun, Fun} ,_Where}} ->
+ ok; %% = io:format("~p(~p) -> ~p\n", [Fun, Args, Res]);
+ Other ->
+ io:format("~p(~p) -> ~p\n", [Fun, Args, Res]),
+ exit({bad_result, Other})
+ end.
+
+%%--------------------------------------------------------------------
+%% Taken from guard_SUITE.erl
+%%
+%% Tests correct handling of exceptions by calling guard BIFs with
+%% nasty (but legal arguments).
+%%--------------------------------------------------------------------
+
+test_guard_bif() ->
+ Big = -237849247829874297658726487367328971246284736473821617265433,
+ Float = 387924.874,
+
+ %% Succeding use of guard bifs.
+
+ try_gbif('abs/1', Big, -Big),
+ try_gbif('float/1', Big, float(Big)),
+ try_gbif('trunc/1', Float, 387924.0),
+ try_gbif('round/1', Float, 387925.0),
+ try_gbif('length/1', [], 0),
+
+ try_gbif('length/1', [a], 1),
+ try_gbif('length/1', [a, b], 2),
+ try_gbif('length/1', lists:seq(0, 31), 32),
+
+ try_gbif('hd/1', [a], a),
+ try_gbif('hd/1', [a, b], a),
+
+ try_gbif('tl/1', [a], []),
+ try_gbif('tl/1', [a, b], [b]),
+ try_gbif('tl/1', [a, b, c], [b, c]),
+
+ try_gbif('size/1', {}, 0),
+ try_gbif('size/1', {a}, 1),
+ try_gbif('size/1', {a, b}, 2),
+ try_gbif('size/1', {a, b, c}, 3),
+ try_gbif('size/1', list_to_binary([]), 0),
+ try_gbif('size/1', list_to_binary([1]), 1),
+ try_gbif('size/1', list_to_binary([1, 2]), 2),
+ try_gbif('size/1', list_to_binary([1, 2, 3]), 3),
+
+ try_gbif('element/2', {x}, {1, x}),
+ try_gbif('element/2', {x, y}, {1, x}),
+ try_gbif('element/2', {x, y}, {2, y}),
+
+ try_gbif('self/0', 0, self()),
+ try_gbif('node/0', 0, node()),
+ try_gbif('node/1', self(), node()),
+
+ %% Failing use of guard bifs.
+
+ try_fail_gbif('abs/1', Big, 1),
+ try_fail_gbif('abs/1', [], 1),
+
+ try_fail_gbif('float/1', Big, 42),
+ try_fail_gbif('float/1', [], 42),
+
+ try_fail_gbif('trunc/1', Float, 0.0),
+ try_fail_gbif('trunc/1', [], 0.0),
+
+ try_fail_gbif('round/1', Float, 1.0),
+ try_fail_gbif('round/1', [], a),
+
+ try_fail_gbif('length/1', [], 1),
+ try_fail_gbif('length/1', [a], 0),
+ try_fail_gbif('length/1', a, 0),
+ try_fail_gbif('length/1', {a}, 0),
+
+ try_fail_gbif('hd/1', [], 0),
+ try_fail_gbif('hd/1', [a], x),
+ try_fail_gbif('hd/1', x, x),
+
+ try_fail_gbif('tl/1', [], 0),
+ try_fail_gbif('tl/1', [a], x),
+ try_fail_gbif('tl/1', x, x),
+
+ try_fail_gbif('size/1', {}, 1),
+ try_fail_gbif('size/1', [], 0),
+ try_fail_gbif('size/1', [a], 1),
+ try_fail_gbif('size/1', fun() -> 1 end, 0),
+ try_fail_gbif('size/1', fun() -> 1 end, 1),
+
+ try_fail_gbif('element/2', {}, {1, x}),
+ try_fail_gbif('element/2', {x}, {1, y}),
+ try_fail_gbif('element/2', [], {1, z}),
+
+ try_fail_gbif('self/0', 0, list_to_pid("<0.0.0>")),
+ try_fail_gbif('node/0', 0, xxxx),
+ try_fail_gbif('node/1', self(), xxx),
+ try_fail_gbif('node/1', yyy, xxx),
+ ok.
+
+try_gbif(Id, X, Y) ->
+ case guard_bif(Id, X, Y) of
+ {Id, X, Y} ->
+ %% io:format("guard_bif(~p, ~p, ~p) -- ok\n", [Id, X, Y]);
+ ok;
+ Other ->
+ ok = io:format("guard_bif(~p, ~p, ~p) -- bad result: ~p\n",
+ [Id, X, Y, Other]),
+ exit({bad_result,try_gbif})
+ end.
+
+try_fail_gbif(Id, X, Y) ->
+ case catch guard_bif(Id, X, Y) of
+ %% {'EXIT', {function_clause,[{?MODULE,guard_bif,[Id,X,Y]}|_]}} ->
+ {'EXIT', {function_clause,_}} -> % in HiPE, a trace is not generated
+ %% io:format("guard_bif(~p, ~p, ~p) -- ok\n", [Id,X,Y]);
+ ok;
+ Other ->
+ ok = io:format("guard_bif(~p, ~p, ~p) -- bad result: ~p\n",
+ [Id, X, Y, Other]),
+ exit({bad_result,try_fail_gbif})
+ end.
+
+guard_bif('abs/1', X, Y) when abs(X) == Y ->
+ {'abs/1', X, Y};
+guard_bif('float/1', X, Y) when float(X) == Y ->
+ {'float/1', X, Y};
+guard_bif('trunc/1', X, Y) when trunc(X) == Y ->
+ {'trunc/1', X, Y};
+guard_bif('round/1', X, Y) when round(X) == Y ->
+ {'round/1', X, Y};
+guard_bif('length/1', X, Y) when length(X) == Y ->
+ {'length/1', X, Y};
+guard_bif('hd/1', X, Y) when hd(X) == Y ->
+ {'hd/1', X, Y};
+guard_bif('tl/1', X, Y) when tl(X) == Y ->
+ {'tl/1', X, Y};
+guard_bif('size/1', X, Y) when size(X) == Y ->
+ {'size/1', X, Y};
+guard_bif('element/2', X, {Pos, Expected}) when element(Pos, X) == Expected ->
+ {'element/2', X, {Pos, Expected}};
+guard_bif('self/0', X, Y) when self() == Y ->
+ {'self/0', X, Y};
+guard_bif('node/0', X, Y) when node() == Y ->
+ {'node/0', X, Y};
+guard_bif('node/1', X, Y) when node(X) == Y ->
+ {'node/1', X, Y}.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_floats.erl b/lib/hipe/test/basic_SUITE_data/basic_floats.erl
new file mode 100644
index 0000000000..eec175075a
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_floats.erl
@@ -0,0 +1,180 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%%
+%%% Contains tests that manipulate floating point numbers.
+%%%-------------------------------------------------------------------
+-module(basic_floats).
+
+-export([test/0]).
+-export([test_fmt_double_fpe_leak/0]). % suppress the unused warning
+
+test() ->
+ ok = test_arith_ops(),
+ ok = test_fp_ebb(),
+ ok = test_fp_phi(),
+ ok = test_big_bad_float(),
+ ok = test_catch_bad_fp_arith(),
+ ok = test_catch_fp_conv(),
+ ok = test_fp_with_fp_exceptions(),
+ %% ok = test_fmt_double_fpe_leak(), % this requires printing
+ ok.
+
+%%--------------------------------------------------------------------
+
+test_arith_ops() ->
+ E = 2.5617,
+ 5.703200000000001 = add(E),
+ 0.5798000000000001 = sub(E),
+ 8.047580550000001 = mult(E),
+ -6.023e23 = negate(6.023e23),
+ ok.
+
+add(X) ->
+ 3.1415 + X.
+
+sub(X) ->
+ 3.1415 - X.
+
+mult(X) ->
+ 3.1415 * X.
+
+%% tests the translation of the fnegate BEAM instruction.
+negate(X) ->
+ - (X + 0.0).
+
+%%--------------------------------------------------------------------
+%% Test the construction of overlapping extended basic blocks where
+%% BEAM has constructed one and hipe_icode_fp constructs the other.
+%%--------------------------------------------------------------------
+
+test_fp_ebb() ->
+ 1.0 = foo(2 * math:pi()),
+ 1.0 = bar(2 * math:pi()),
+ ok.
+
+foo(X) ->
+ X / (2 * math:pi()).
+
+bar(X) ->
+ F = float_two(),
+ case F < 3.0 of
+ true -> (X * F) / ((2 * F) * math:pi());
+ false -> weird
+ end.
+
+float_two() ->
+ 2.0.
+
+%%--------------------------------------------------------------------
+
+test_fp_phi() ->
+ 10 = fp_phi(10, 100),
+ undefined = fp_phi(1.1e302, 0.000000001),
+ ok.
+
+fp_phi(A, B) ->
+ case catch A / B of
+ {'EXIT', _Reason} -> undefined;
+ _ -> round(100 * (A / B))
+ end.
+
+%%--------------------------------------------------------------------
+
+-define(BS, "93904329458954829589425849258998492384932849328493284932849328493284932389248329432932483294832949245827588578423578435783475834758375837580745807304258924584295924588459834958349589348589345934859384958349583945893458934859438593485995348594385943859438593458934589345938594385934859483958348934589435894859485943859438594594385938459438595034950439504395043950495043593485943758.0").
+
+test_big_bad_float() ->
+ ok = try f2l(?BS) catch error:badarg -> ok end,
+ ok = case catch f2l(?BS) of {'EXIT', {badarg, _}} -> ok end,
+ ok.
+
+f2l(F) ->
+ float_to_list(list_to_float(F)).
+
+%%--------------------------------------------------------------------
+%% Tests catching of floating point bad arithmetic.
+
+test_catch_bad_fp_arith() ->
+ 5.7 = f(2.56),
+ {'EXIT', {badarith, _}} = bad_arith(9.9),
+ ok.
+
+f(F) when is_float(F) -> F + 3.14.
+
+bad_arith(F) when is_float(F) ->
+ catch F * 1.70000e+308.
+
+%%--------------------------------------------------------------------
+%% Tests proper catching of exceptions due to illegal convertion of
+%% bignums to floating point numbers.
+
+test_catch_fp_conv() ->
+ F = 1.7e308, %% F is a number very close to a maximum float.
+ ok = big_arith(F),
+ ok = big_const_float(F),
+ ok.
+
+big_arith(F) ->
+ I = trunc(F),
+ {'EXIT', {badarith, _}} = big_int_arith(I),
+ ok.
+
+big_int_arith(I) when is_integer(I) ->
+ catch(3.0 + 2*I).
+
+big_const_float(F) ->
+ I = trunc(F),
+ badarith = try (1/(2*I)) catch error:Err -> Err end,
+ _ = 2/I,
+ {'EXIT', _} = (catch 4/(2*I)),
+ ok.
+
+%%--------------------------------------------------------------------
+%% Forces floating point exceptions and tests that subsequent, legal,
+%% operations are calculated correctly.
+
+test_fp_with_fp_exceptions() ->
+ 0.0 = math:log(1.0),
+ badarith = try math:log(float_minus_one()) catch error:E1 -> E1 end,
+ 0.0 = math:log(1.0),
+ badarith = try math:log(float_zero()) catch error:E2 -> E2 end,
+ 0.0 = math:log(1.0),
+ %% An old-fashioned exception here just so as to test this case also
+ {'EXIT', _} = (catch fp_mult(3.23e133, 3.57e257)),
+ 0.0 = math:log(1.0),
+ badarith = try fp_div(5.0, 0.0) catch error:E3 -> E3 end,
+ 0.0 = math:log(1.0),
+ ok.
+
+fp_mult(X, Y) -> X * Y.
+
+fp_div(X, Y) -> X / Y.
+
+%% The following two function definitions appear here just to shut
+%% off 'expression will fail with a badarg' warnings from the compiler
+
+float_zero() -> 0.0.
+
+float_minus_one() -> -1.0.
+
+%%--------------------------------------------------------------------
+%% Test that erl_printf_format.c:fmt_double() does not leak pending FP
+%% exceptions to subsequent code. This used to break x87 FP code on
+%% 32-bit x86. Based on a problem report from Richard Carlsson.
+
+test_fmt_double_fpe_leak() ->
+ test_fmt_double_fpe_leak(float_zero(), int_two()),
+ ok.
+
+%% We need the specific sequence of erlang:display/1 on a float that
+%% triggers faulting ops in fmt_double() followed by a simple FP BIF.
+%% We also need to repeat this at least three times.
+test_fmt_double_fpe_leak(X, Y) ->
+ erlang:display(X), _ = math:log10(Y),
+ erlang:display(X), _ = math:log10(Y),
+ erlang:display(X), _ = math:log10(Y),
+ erlang:display(X), _ = math:log10(Y),
+ erlang:display(X),
+ math:log10(Y).
+
+int_two() -> 2.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_fun.erl b/lib/hipe/test/basic_SUITE_data/basic_fun.erl
new file mode 100644
index 0000000000..18ba7fdb3f
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_fun.erl
@@ -0,0 +1,124 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%%
+%%% Tests for correct handling of funs.
+%%%-------------------------------------------------------------------
+-module(basic_fun).
+
+-export([test/0]).
+
+-export([dummy_foo/4, add1/1, test_fun03/0]).
+
+test() ->
+ ok = test_calls(),
+ ok = test_is_function(),
+ ok = test_is_function2(),
+ ok.
+
+%%--------------------------------------------------------------------
+%% Tests function and fun calls.
+
+test_calls() ->
+ ok = test_apply_call(?MODULE, dummy_foo),
+ ok = test_fun_call(fun dummy_foo/4),
+ ok = test_fun_call(fun ?MODULE:dummy_foo/4),
+ ok.
+
+test_apply_call(M, F) ->
+ M:F(bar, 42, foo, 17).
+
+test_fun_call(Fun) ->
+ Fun(bar, 42, foo, 17).
+
+dummy_foo(_, _, foo, _) -> ok.
+
+%%--------------------------------------------------------------------
+%% Tests handling of funs out of exported functions and 2-tuple funs.
+
+test_fun03() ->
+ MFPair = add1_as_2tuple(),
+ 4712 = do_call(add1_as_export(), 4711),
+ {badfun, MFPair} = try do_call(MFPair, 88) catch error:Err -> Err end,
+ true = do_guard(add1_as_export()),
+ false = do_guard(MFPair), % 2-tuples do not satisfy is_function/1
+ ok.
+
+do_call(F, X) -> F(X).
+
+do_guard(F) when is_function(F) -> true;
+do_guard(_) -> false.
+
+add1_as_export() -> fun ?MODULE:add1/1.
+
+add1_as_2tuple() -> {?MODULE, add1}.
+
+add1(X) -> X+1.
+
+%%--------------------------------------------------------------------
+%% Tests the is_function guard and BIF.
+
+test_is_function() ->
+ Fun = fun (X, foo) -> dummy_foo(X, mnesia_lib, foo, [X]) end,
+ ok = test_when_guard(Fun),
+ ok = test_if_guard(Fun),
+ ok.
+
+test_when_guard(X) when is_function(X) -> ok.
+
+test_if_guard(X) ->
+ if is_function(X) -> ok;
+ true -> weird
+ end.
+
+%%--------------------------------------------------------------------
+%% Tests the is_function2 guard and BIF.
+
+test_is_function2() ->
+ ok = test_guard(),
+ ok = test_guard2(),
+ ok = test_call(),
+ ok.
+
+test_guard() ->
+ zero_fun = test_f2(fun () -> ok end),
+ unary_fun = test_f2(fun(X) -> X end),
+ binary_fun = test_f2(fun (X, Y) -> {X, Y} end),
+ no_fun = test_f2(gazonk),
+ ok.
+
+test_f2(Fun) when is_function(Fun, 0) ->
+ zero_fun;
+test_f2(Fun) when is_function(Fun, 1) ->
+ unary_fun;
+test_f2(Fun) when is_function(Fun, 2) ->
+ binary_fun;
+test_f2(_) ->
+ no_fun.
+
+test_guard2() ->
+ zero_fun = test_f2_n(fun () -> ok end, 0),
+ unary_fun = test_f2_n(fun (X) -> X end, 1),
+ binary_fun = test_f2_n(fun (X, Y) -> {X, Y} end, 2),
+ no_fun = test_f2_n(gazonk, 0),
+ ok.
+
+test_f2_n(F, N) when is_function(F, N) ->
+ case N of
+ 0 -> zero_fun;
+ 1 -> unary_fun;
+ 2 -> binary_fun
+ end;
+test_f2_n(_, _) ->
+ no_fun.
+
+test_call() ->
+ true = test_fn2(fun (X, Y) -> {X,Y} end, 2),
+ false = test_fn2(fun (X, Y) -> {X,Y} end, 3),
+ false = test_fn2(gazonk, 2),
+ {'EXIT', {badarg, _TR1}} = (catch test_fn2(gazonk, gazonk)),
+ {'EXIT', {badarg, _TR2}} = (catch test_fn2(fun (X, Y) -> {X, Y} end, gazonk)),
+ ok.
+
+test_fn2(F, N) ->
+ is_function(F, N).
diff --git a/lib/hipe/test/basic_SUITE_data/basic_guards.erl b/lib/hipe/test/basic_SUITE_data/basic_guards.erl
new file mode 100644
index 0000000000..81eeed7c3b
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_guards.erl
@@ -0,0 +1,164 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%%
+%%% Contains tests for correct handling of guards and guard BIFs.
+%%%-------------------------------------------------------------------
+-module(basic_guards).
+
+-export([test/0]).
+%% Prevent the inlining of the following functions
+-export([bad_arith/0, bad_tuple/0, is_strange_guard/0]).
+
+test() ->
+ ok = guard0(4.2),
+ ok = guard1([foo]),
+ ok = test_guard2(),
+ ok = test_guard3(),
+ ok = test_guard4(),
+ ok = test_is_boolean(),
+ ok = test_bad_guards(),
+ ok.
+
+%%--------------------------------------------------------------------
+
+guard0(X) when X /= 0, is_float(X) ->
+ ok.
+
+guard1(X) when is_atom(X) orelse is_float(X) ->
+ error1;
+guard1(X) when is_reference(hd(X)) ->
+ error2;
+guard1(X) when is_integer(hd(X)) ->
+ error3;
+guard1(X) when hd(X) == foo ->
+ ok.
+
+%%--------------------------------------------------------------------
+
+test_guard2() ->
+ ok1 = guard2(true),
+ not_boolean = guard2(42),
+ ok2 = guard2(false),
+ ok.
+
+guard2(X) when X -> % gets transformed to: is_boolean(X), X =:= true
+ ok1;
+guard2(X) when X =:= false ->
+ ok2;
+guard2(_) ->
+ not_boolean.
+
+%%--------------------------------------------------------------------
+
+-define(is_foo(X), (is_atom(X) or (is_tuple(X) and (element(1, X) =:= 'foo')))).
+
+test_guard3() ->
+ no = f('foo'),
+ yes = f({'foo', 42}),
+ no = f(42),
+ ok.
+
+f(X) when ?is_foo(X) -> yes;
+f(_) -> no.
+
+%%--------------------------------------------------------------------
+
+-define(EXT_REF, <<131,114,0,3,100,0,19,114,101,102,95,116,101,115,116,95,98,117,103,64,103,111,114,98,97,103,2,0,0,0,125,0,0,0,0,0,0,0,0>>).
+
+test_guard4() ->
+ yes = is_ref(make_ref()),
+ no = is_ref(gazonk),
+ yes = is_ref(an_external_ref(?EXT_REF)),
+ ok.
+
+is_ref(Ref) when is_reference(Ref) -> yes;
+is_ref(_Ref) -> no.
+
+an_external_ref(Bin) ->
+ binary_to_term(Bin).
+
+%%--------------------------------------------------------------------
+
+test_is_boolean() ->
+ ok = is_boolean_in_if(),
+ ok = is_boolean_in_guard().
+
+is_boolean_in_if() ->
+ ok1 = tif(true),
+ ok2 = tif(false),
+ not_bool = tif(other),
+ ok.
+
+is_boolean_in_guard() ->
+ ok = tg(true),
+ ok = tg(false),
+ not_bool = tg(other),
+ ok.
+
+tif(V) ->
+ Yes = yes(), %% just to prevent the optimizer removing this
+ if
+ %% the following line generates an is_boolean instruction
+ V, Yes == yes ->
+ %% while the following one does not (?!)
+ %% Yes == yes, V ->
+ ok1;
+ not(not(not(V))) ->
+ ok2;
+ V ->
+ ok3;
+ true ->
+ not_bool
+ end.
+
+tg(V) when is_boolean(V) ->
+ ok;
+tg(_) ->
+ not_bool.
+
+yes() -> yes.
+
+%%--------------------------------------------------------------------
+%% original test by Bjorn G
+
+test_bad_guards() ->
+ ok = bad_arith(),
+ ok = bad_tuple(),
+ ok = is_strange_guard(),
+ ok.
+
+bad_arith() ->
+ 13 = bad_arith1(1, 12),
+ 42 = bad_arith1(1, infinity),
+ 42 = bad_arith1(infinity, 1),
+ 42 = bad_arith2(infinity, 1),
+ 42 = bad_arith3(inf),
+ 42 = bad_arith4(infinity, 1),
+ ok.
+
+bad_arith1(T1, T2) when (T1 + T2) < 17 -> T1 + T2;
+bad_arith1(_, _) -> 42.
+
+bad_arith2(T1, T2) when (T1 * T2) < 17 -> T1 * T2;
+bad_arith2(_, _) -> 42.
+
+bad_arith3(T) when (bnot T) < 17 -> T;
+bad_arith3(_) -> 42.
+
+bad_arith4(T1, T2) when (T1 bsr T2) < 10 -> T1 bsr T2;
+bad_arith4(_, _) -> 42.
+
+bad_tuple() ->
+ error = bad_tuple1(a),
+ error = bad_tuple1({a, b}),
+ x = bad_tuple1({x, b}),
+ y = bad_tuple1({a, b, y}),
+ ok.
+
+bad_tuple1(T) when element(1, T) =:= x -> x;
+bad_tuple1(T) when element(3, T) =:= y -> y;
+bad_tuple1(_) -> error.
+
+is_strange_guard() when is_tuple({1, bar, length([1, 2, 3, 4]), self()}) -> ok;
+is_strange_guard() -> error.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_inline_function.erl b/lib/hipe/test/basic_SUITE_data/basic_inline_function.erl
new file mode 100644
index 0000000000..4c08064670
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_inline_function.erl
@@ -0,0 +1,73 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%%
+%%% Contains tests that depend on the compiler inliner being turned on.
+%%%-------------------------------------------------------------------
+-module(basic_inline_function).
+
+-export([test/0]).
+
+-compile({inline, [{to_objects, 3}]}).
+
+test() ->
+ ok = test_inline_match(),
+ ok.
+
+%%--------------------------------------------------------------------
+
+test_inline_match() ->
+ bad_object = test1(a, {binary, foo, set}, c),
+ bad_object = test2(a, {binary, foo, set}, c),
+ bad_object = test3(a, {binary, foo, set}, c),
+ ok.
+
+%% Inlined
+test1(KeysObjs, C, Ts) ->
+ case catch to_objects(KeysObjs, C, Ts) of
+ {'EXIT', _} ->
+ bad_object;
+ ok ->
+ ok
+ end.
+
+%% "Inlined" by hand
+test2(KeysObjs, C, _Ts) ->
+ case catch (case C of
+ {binary, _, set} ->
+ <<_ObjSz0:32, _T/binary>> = KeysObjs;
+ _ -> ok
+ end) of
+ {'EXIT', _} ->
+ bad_object;
+ ok ->
+ ok
+ end.
+
+%% Not inlined
+test3(KeysObjs, C, Ts) ->
+ case catch fto_objects(KeysObjs, C, Ts) of
+ {'EXIT', _} ->
+ bad_object;
+ ok ->
+ ok
+ end.
+
+%% Inlined.
+to_objects(Bin, {binary, _, set}, _Ts) ->
+ <<_ObjSz0:32, _T/binary>> = Bin,
+ ok;
+to_objects(<<_ObjSz0:32, _T/binary>> ,_, _) ->
+ ok;
+to_objects(_Bin, _, _Ts) ->
+ ok.
+
+%% Not Inlined.
+fto_objects(Bin, {binary, _, set}, _Ts) ->
+ <<_ObjSz0:32, _T/binary>> = Bin,
+ ok;
+fto_objects(<<_ObjSz0:32, _T/binary>> ,_,_) ->
+ ok;
+fto_objects(_Bin, _, _Ts) ->
+ ok.
+
diff --git a/lib/hipe/test/basic_SUITE_data/basic_inline_module.erl b/lib/hipe/test/basic_SUITE_data/basic_inline_module.erl
new file mode 100644
index 0000000000..306c6a39ce
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_inline_module.erl
@@ -0,0 +1,31 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%%
+%%% Contains tests that depend on the compiler inliner being turned on.
+%%%-------------------------------------------------------------------
+-module(basic_inline_module).
+
+-export([test/0]).
+
+-compile([inline]). %% necessary for these tests
+
+test() ->
+ ok = test_case_end_atom(),
+ ok.
+
+%%--------------------------------------------------------------------
+%% Tests whether the translation of a case_end instruction works even
+%% when an exception (no matching case pattern) is to be raised.
+
+test_case_end_atom() ->
+ {'EXIT',{{case_clause,some_atom},_Trace}} = (catch test_case_stm_inlining()),
+ ok.
+
+test_case_stm_inlining() ->
+ case some_atom() of
+ another_atom -> strange_result
+ end.
+
+some_atom() ->
+ some_atom.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_issues_beam.erl b/lib/hipe/test/basic_SUITE_data/basic_issues_beam.erl
new file mode 100644
index 0000000000..73367c5c45
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_issues_beam.erl
@@ -0,0 +1,326 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%%
+%%% Contains code examples, mostly taken from the mailing list, that
+%%% crashed the BEAM compiler or gave an internal error at some point.
+%%%-------------------------------------------------------------------
+-module(basic_issues_beam).
+
+-export([test/0]).
+
+test() ->
+ ok = test_crash_R10_hinde(),
+ ok = test_error_R10_mander(),
+ ok = test_error_R11_bjorklund(),
+ ok = test_error_R11_rath(),
+ ok = test_error_R12_empty_bin_rec(),
+ ok = test_bug_R12_cornish(),
+ ok = test_crash_R12_morris(),
+ ok = test_error_R13_almeida(),
+ ok = test_error_R13B01_fisher(),
+ ok = test_error_R13B01_sawatari(),
+ ok = test_error_R13B01_whongo(),
+ ok = test_error_R16B03_norell(),
+ ok = test_error_try_wings(),
+ ok.
+
+%%--------------------------------------------------------------------
+%% Fisher R10 compiler crash
+%%--------------------------------------------------------------------
+
+-record(r, {a, b, c}).
+
+test_crash_R10_hinde() ->
+ rec_R10_hinde(#r{}).
+
+rec_R10_hinde(As) ->
+ case As of
+ A when A#r.b == ""; A#r.b == undefined -> ok;
+ _ -> error
+ end.
+
+%%--------------------------------------------------------------------
+%% From: Peter-Henry Mander
+%% Date: 27 Jan, 2005
+%%
+%% I managed to isolate a non-critical BEAM compilation error
+%% (internal error in v3_codegen) when compiling the following code:
+%%--------------------------------------------------------------------
+
+test_error_R10_mander() ->
+ try just_compile_me_R10() catch _:_ -> ok end.
+
+just_compile_me_R10() ->
+ URI_Before =
+ {absoluteURI,
+ {scheme, fun() -> nil end},
+ {hier_part,
+ {net_path,
+ {srvr,
+ {userinfo, nil},
+ fun() -> nil end},
+ nil},
+ {port, nil}}},
+ {absoluteURI,
+ {scheme, _},
+ {hier_part,
+ {net_path,
+ {srvr,
+ {userinfo, nil},
+ _HostportBefore},
+ nil},
+ {port, nil}}} = URI_Before,
+ %% ... some funky code ommitted, not relevant ...
+ {absoluteURI,
+ {scheme, _},
+ {hier_part,
+ {net_path,
+ {srvr,
+ {userinfo, nil},
+ HostportAfter},
+ nil},
+ {port, nil}}} = URI_Before,
+ %% NOTE: I intended to write URI_After instead of URI_Before
+ %% but the accident revealed that when you add the line below,
+ %% it causes internal error in v3_codegen on compilation
+ {hostport, {hostname, "HostName"}, {port, nil}} = HostportAfter,
+ ok.
+
+%%--------------------------------------------------------------------
+%% From: Martin Bjorklund
+%% Date: Aug 16, 2006
+%%
+%% I found this compiler bug in R10B-10 and R11B-0.
+%%
+%% Function -just_compile_me/0-fun-2-/1 refers to undefined label 18
+%% ./bjorklund_R11compiler_bug.erl:none: internal error in beam_clean;
+%% crash reason: {{case_clause,{'EXIT',{undefined_label,18}}},
+%% [{compile,'-select_passes/2-anonymous-2-',2},
+%% {compile,'-internal_comp/4-anonymous-1-',2},
+%% {compile,fold_comp,3},
+%% {compile,internal_comp,4},
+%% {compile,internal,3}]}
+%%--------------------------------------------------------------------
+
+test_error_R11_bjorklund() ->
+ just_compile_me_R11_bjorklund().
+
+just_compile_me_R11_bjorklund() ->
+ G = fun() -> ok end,
+ try
+ G() %% fun() -> ok end
+ after
+ fun({A, B}) -> A + B end
+ end.
+
+%%--------------------------------------------------------------------
+%% From: Tim Rath
+%% Date: Sep 13, 2006
+%% Subject: Compiler bug not quite fixed
+%%
+%%
+%% I saw a compiler bug posted to the list by Martin Bjorklund that
+%% appeared to be exactly the problem I'm seeing, and then noticed
+%% that this was fixed in R11B-1. Unfortunately, though R11B-1 appears
+%% to fix the code submitted by Martin, it does not fix my case.
+%%
+%% Function -just_compile_me/0-fun-2-/1 refers to undefined label 13
+%% ./rath_R11compiler_bug.erl:none: internal error in beam_clean;
+%% crash reason: {{case_clause,{'EXIT',{undefined_label,13}}},
+%% [{compile,'-select_passes/2-anonymous-2-',2},
+%% {compile,'-internal_comp/4-anonymous-1-',2},
+%% {compile,fold_comp,3},
+%% {compile,internal_comp,4},
+%% {compile,internal,3}]}
+%%--------------------------------------------------------------------
+
+test_error_R11_rath() ->
+ just_compile_me_R11_rath().
+
+just_compile_me_R11_rath() ->
+ A = {6},
+ try
+ io:fwrite("")
+ after
+ fun () ->
+ fun () -> {_} = A end
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Program that crashed the R12B-0 compiler: internal error in v3_codegen
+%%----------------------------------------------------------------------
+
+-record(rec, {a = <<>> :: binary(), b = 42 :: integer()}).
+
+test_error_R12_empty_bin_rec() ->
+ 42 = test_empty_bin_rec(#rec{}),
+ ok.
+
+test_empty_bin_rec(R) ->
+ #rec{a = <<>>} = R,
+ R#rec.b.
+
+%%----------------------------------------------------------------------
+%% From: Simon Cornish
+%% Date: Jan 13, 2008
+%%
+%% The attached Erlang code demonstrates an R12B-0 bug with funs.
+%% Compile and evaluate the two die/1 calls for two different failure modes.
+%% It seems to me that the live register check for call_fun is off by one.
+%%----------------------------------------------------------------------
+
+-record(b, {c}).
+
+test_bug_R12_cornish() ->
+ {a2, a} = die(a),
+ {a2, {b, c}} = die({b, c}),
+ ok.
+
+die(A) ->
+ F = fun() -> {ok, A} end,
+ if A#b.c =:= [] -> one;
+ true ->
+ case F() of
+ {ok, A2} -> {a2, A2};
+ _ -> three
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% From: Hunter Morris
+%% Date: Nov 20, 2008
+%%
+%% The following code (tested with R12B-4 or R12B-5, vanilla compiler
+%% options) produces a compiler crash. It's nonsensical, and I realise
+%% that andalso can be quite evil, but it's a crash nonetheless.
+%%----------------------------------------------------------------------
+
+test_crash_R12_morris() ->
+ foo(42).
+
+foo(Bar) when (is_integer(Bar) andalso Bar =:= 0) ; Bar =:= 42 ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% From: Paulo Sergio Almeida
+%% Date: May 20, 2009
+%%
+%% The following code when compiled under R13B gives a compiler error.
+%% Function loop/1 refers to undefined label 6
+%% ./almeida_R13compiler_bug.erl:none: internal error in beam_peep;
+%% crash reason: {{case_clause,{'EXIT',{undefined_label,6}}},
+%% [{compile,'-select_passes/2-anonymous-2-',2},
+%% {compile,'-internal_comp/4-anonymous-1-',2},
+%%--------------------------------------------------------------------
+
+test_error_R13_almeida() ->
+ self() ! {backup, 42, false},
+ loop([]).
+
+loop(Tids) ->
+ receive
+ {backup, Tid, Dumping} ->
+ case Dumping of
+ false -> ok;
+ _ -> receive {logged, Tab, Tid} -> put({log, Tab}, Tid) end
+ end,
+ collect(Tid, Tids, [])
+ end.
+
+collect(_, _, _) -> ok.
+
+%%--------------------------------------------------------------------
+%% Fisher R13B01 compiler error
+%%--------------------------------------------------------------------
+
+test_error_R13B01_fisher() ->
+ perform_select({foo, "42"}).
+
+perform_select({Type, Keyval}) ->
+ try
+ if is_atom(Type) andalso length(Keyval) > 0 -> ok;
+ true -> ok
+ end
+ catch
+ _:_ -> fail
+ end.
+
+%%--------------------------------------------------------------------
+%% From: Mikage Sawatari
+%% Date: Jun 12, 2009
+%%
+%% I have the following compilation problem on Erlang R13B01.
+%% Compiler reports "Internal consistency check failed".
+%%--------------------------------------------------------------------
+
+test_error_R13B01_sawatari() ->
+ test_sawatari([1, null, 3], <<1, 2, 3>>).
+
+test_sawatari([], _Bin) -> ok;
+test_sawatari([H|T], Bin) ->
+ _ = case H of
+ null -> <<Bin/binary>>;
+ _ -> ok
+ end,
+ test_sawatari(T, Bin).
+
+%%--------------------------------------------------------------------
+
+test_error_R13B01_whongo() ->
+ S = "gazonk",
+ S = orgno_alphanum(S),
+ ok.
+
+orgno_alphanum(Cs) ->
+ [C || C <- Cs, ((C >= $0) andalso (C =< $9))
+ orelse ((C >= $a) andalso (C =< $z))
+ orelse ((C >= $A) andalso (C =< $Z))].
+
+%%--------------------------------------------------------------------
+%% I'm getting an Internal Consistency Check error when attempting to
+%% build Wings3D on Mac OS X 10.4.2 (Erlang OTP R10B-6):
+%%
+%% erlc -pa /ebin +warn_unused_vars -I/include -I ../e3d -W +debug_info
+%% '-Dwings_version="0.98.31"' -pa ../ebin -o../ebin wings_color.erl
+%% wings_color: function internal_rgb_to_hsv/3+97:
+%% Internal consistency check failed - please report this bug.
+%% Instruction: {test,is_eq_exact,{f,80},[{x,0},{atom,error}]}
+%% Error: {unsafe_instruction,{float_error_state,cleared}}:
+%%
+%% The problem is the interaction of the 'try' construct with the
+%% handling of FP exceptions.
+%%--------------------------------------------------------------------
+
+test_error_try_wings() ->
+ %% a call with a possible FP exception
+ {199.99999999999997, 0.045454545454545456, 44} = rgb_to_hsv(42, 43, 44),
+ ok.
+
+rgb_to_hsv(R, G, B) ->
+ Max = lists:max([R, G, B]),
+ Min = lists:min([R, G, B]),
+ V = Max,
+ {Hue, Sat} = try
+ {if Min == B -> (G-Min)/(R+G-2.0*Min);
+ Min == R -> (1.0+(B-Min)/(B+G-2.0*Min));
+ Min == G -> (2.0+(R-Min)/(B+R-2.0*Min))
+ end * 120, (Max-Min)/Max}
+ catch
+ error:badarith -> {undefined, 0.0}
+ end,
+ {Hue, Sat, V}.
+
+%%--------------------------------------------------------------------
+%% From: Ulf Norell
+%% Date: Feb 28, 2014
+%%
+%% This caused an internal error in v3_codegen
+%%--------------------------------------------------------------------
+
+test_error_R16B03_norell() ->
+ test_error_R16B03_norell(#r{}, gazonk).
+
+test_error_R16B03_norell(Rec, Tag) ->
+ is_record(Rec, Tag, 3) orelse ok.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_issues_hipe.erl b/lib/hipe/test/basic_SUITE_data/basic_issues_hipe.erl
new file mode 100644
index 0000000000..e71045bfe2
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_issues_hipe.erl
@@ -0,0 +1,153 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%%
+%%% Contains code examples that exhibited crashes in the HiPE compiler.
+%%%-------------------------------------------------------------------
+-module(basic_issues_hipe).
+
+-export([test/0]).
+
+%% functions that need to be exported so that they are retained.
+-export([auth/4]).
+
+test() ->
+ ok = test_dominance_trees(),
+ ok = test_merged_const(),
+ ok = test_var_pair(),
+ ok = test_bif_fails(),
+ ok = test_find_catches(),
+ ok = test_heap_allocate_trim(),
+ ok.
+
+%%--------------------------------------------------------------------
+%% This is taken from a file sent to us by Martin Bjorklund @ Nortel
+%% on 14th November 2004. The problem was in the SSA unconvert pass.
+%%
+%% No tests here; we simply check that the HiPE compiler does not go
+%% into an infinite loop when compiling strange functions like this.
+%%--------------------------------------------------------------------
+
+auth(_, A, B, C) ->
+ auth(A, B, C, []).
+
+%%--------------------------------------------------------------------
+%% Exposed a crash in the generation of dominance trees used in SSA.
+%%--------------------------------------------------------------------
+
+-record(state, {f}).
+
+test_dominance_trees() ->
+ {ok, true} = doit(true, #state{f = true}),
+ ok.
+
+doit(Foo, S) ->
+ Fee = case Foo of
+ Bar when Bar == S#state.f; Bar == [] -> true;
+ _ -> false
+ end,
+ {ok, Fee}.
+
+%%--------------------------------------------------------------------
+%% Checks that the merging of constants in the constant table uses the
+%% appropriate comparison function for this.
+%%--------------------------------------------------------------------
+
+test_merged_const() ->
+ Const1 = {'', 1.0000},
+ Const2 = {'', 1},
+ match(Const1, Const2).
+
+match(A, A) ->
+ error;
+match(_A, _B) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% Checks that the HiPE compiler does not get confused by constant
+%% data structures similar to the internal compiler data structures.
+%%--------------------------------------------------------------------
+
+test_var_pair() ->
+ ok = var_pair([gazonk]).
+
+var_pair([_|_]) ->
+ var_pair({var, some_atom});
+var_pair(_) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% This module was causing the HiPE compiler to crash in January 2007.
+%% The culprit was an "optimization" of the BEAM compiler: postponing
+%% the save of x variables when BIFs cannot fail. This was fixed on
+%% February 1st, by making the HiPE compiler use the same functions
+%% as the BEAM compiler for deciding whether a BIF fails.
+%%--------------------------------------------------------------------
+
+test_bif_fails() ->
+ [42] = bif_fails_in_catch([42]),
+ true = bif_fails_in_try([42]),
+ ok.
+
+bif_fails_in_catch(X) ->
+ case catch get(gazonk) of
+ _ -> X
+ end.
+
+bif_fails_in_try(X) ->
+ try
+ true = X =/= []
+ catch
+ _ -> nil(X)
+ end.
+
+nil(_) -> [].
+
+%%--------------------------------------------------------------------
+%% Test that resulted in a native code compiler crash in the code of
+%% hipe_icode_exceptions:find_catches/1 when compiling find_catches/2.
+%%--------------------------------------------------------------------
+
+test_find_catches() ->
+ 42 = find_catches(a, false),
+ ok.
+
+find_catches(X, Y) ->
+ case X of
+ a when Y =:= true ->
+ catch id(X),
+ X;
+ b when Y =:= true ->
+ catch id(X),
+ X;
+ a ->
+ catch id(X),
+ 42;
+ b ->
+ catch id(X),
+ 42
+ end.
+
+id(X) -> X.
+
+%%--------------------------------------------------------------------
+%% Date: Dec 28, 2007
+%%
+%% This is a test adapted from the file sent to the Erlang mailing
+%% list by Eranga Udesh. The file did not compile because of problems
+%% with the heap_allocate instruction and stack trimming.
+%%--------------------------------------------------------------------
+
+test_heap_allocate_trim() ->
+ {abandon, 42} = get_next_retry(a, 42),
+ ok.
+
+get_next_retry(Error, Count) ->
+ case catch pair(retry_scheme, {Error, Count}) of
+ _ ->
+ case pair(Error, Count) of
+ _ -> {abandon, Count}
+ end
+ end.
+
+pair(A, B) -> {A, B}.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_lists.erl b/lib/hipe/test/basic_SUITE_data/basic_lists.erl
new file mode 100644
index 0000000000..264a7f86f6
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_lists.erl
@@ -0,0 +1,61 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%%
+%%% Contains tests that manipulate and pattern match against lists
+%%% (perhaps by calling functions from the 'lists' module).
+%%%-------------------------------------------------------------------
+-module(basic_lists).
+
+-export([test/0]).
+
+test() ->
+ ok = test_length(),
+ ok = test_lists_key(),
+ ok = test_lists_and_strings(),
+ ok.
+
+%%--------------------------------------------------------------------
+
+test_length() ->
+ Len = 42,
+ Lst = mklist(Len, []),
+ Len = iterate(100, Lst),
+ ok.
+
+mklist(0, L) -> L;
+mklist(X, L) -> mklist(X-1, [X|L]).
+
+iterate(0, L) -> len(L, 0);
+iterate(X, L) -> len(L, 0), iterate(X-1, L).
+
+len([_|X], L) -> len(X, L+1);
+len([], L) -> L.
+
+%%--------------------------------------------------------------------
+
+test_lists_key() ->
+ First = {x, 42.0},
+ Second = {y, -77},
+ Third = {z, [a, b, c], {5.0}},
+ List = [First, Second, Third],
+ {value, First} = key_search_find(42, 2, List),
+ ok.
+
+key_search_find(Key, Pos, List) ->
+ case lists:keyfind(Key, Pos, List) of
+ false ->
+ false = lists:keysearch(Key, Pos, List);
+ Tuple when is_tuple(Tuple) ->
+ {value, Tuple} = lists:keysearch(Key, Pos, List)
+ end.
+
+%%--------------------------------------------------------------------
+
+test_lists_and_strings() ->
+ LL = ["H'A", " H'B", " H'C"],
+ LL2 = lists:map(fun string:strip/1, LL),
+ HexFormat = fun(X, Acc) -> {string:substr(X, 3), Acc} end,
+ {LL3,_Ret} = lists:mapfoldl(HexFormat, 0, LL2),
+ ["A", "B", "C"] = lists:sublist(LL3, 42),
+ ok.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_module_info.erl b/lib/hipe/test/basic_SUITE_data/basic_module_info.erl
new file mode 100644
index 0000000000..cab48b10ba
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_module_info.erl
@@ -0,0 +1,32 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%% Date: Oct 25, 2003
+%%%
+%%% Tests whether calling module_info from the same module works.
+%%% This seems trivial, but the problem is that the module_info/[0,1]
+%%% functions that the BEAM file contains used to be dummy functions
+%%% containing crap. So, these functions could not be used for
+%%% compilation to native code and the functions that the BEAM loader
+%%% generates should have been used instead. This was a HiPE bug
+%%% reported by Dan Wallin.
+%%%-------------------------------------------------------------------
+-module(basic_module_info).
+
+-export([test/0]).
+
+test() ->
+ L = test_local_mi0_call(),
+ E = test_remote_mi1_call(),
+ {3, 3} = {L, E},
+ ok.
+
+test_local_mi0_call() ->
+ ModInfo = module_info(),
+ %% io:format("ok, ModInfo=~w\n", [ModInfo]),
+ {exports, FunList} = lists:keyfind(exports, 1, ModInfo),
+ length(FunList).
+
+test_remote_mi1_call() ->
+ FunList = ?MODULE:module_info(exports),
+ length(FunList).
diff --git a/lib/hipe/test/basic_SUITE_data/basic_pattern_match.erl b/lib/hipe/test/basic_SUITE_data/basic_pattern_match.erl
new file mode 100644
index 0000000000..93240354a7
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_pattern_match.erl
@@ -0,0 +1,46 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%%
+%%% Contains code examples that test pattern matching against terms of
+%%% various types.
+%%%-------------------------------------------------------------------
+-module(basic_pattern_match).
+
+-export([test/0]).
+
+test() ->
+ ok = test_hello_world(),
+ ok = test_list_plus_plus_match(),
+ ok.
+
+%%--------------------------------------------------------------------
+%% Trivial test to test pattern matching compilation with atoms, the
+%% correct handling of all sorts of alphanumeric types in Erlang, and
+%% conversions between them.
+
+test_hello_world() ->
+ String = gimme(string),
+ String = atom_to_list(gimme(atom)),
+ String = binary_to_list(gimme(binary)),
+ true = (list_to_atom(String) =:= gimme(atom)),
+ true = (list_to_binary(String) =:= gimme(binary)),
+ ok.
+
+gimme(string) ->
+ "hello world";
+gimme(atom) ->
+ 'hello world';
+gimme(binary) ->
+ <<"hello world">>.
+
+%%--------------------------------------------------------------------
+%% Makes sure that pattern matching expressions involving ++ work OK.
+%% The third expression caused a problem in the Erlang shell of R11B-5.
+%% It worked OK in both interpreted and compiled code.
+
+test_list_plus_plus_match() ->
+ ok = (fun("X" ++ _) -> ok end)("X"),
+ ok = (fun([$X | _]) -> ok end)("X"),
+ ok = (fun([$X] ++ _) -> ok end)("X"),
+ ok.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_random.erl b/lib/hipe/test/basic_SUITE_data/basic_random.erl
new file mode 100644
index 0000000000..783947bd31
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_random.erl
@@ -0,0 +1,238 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%%
+%%% A test for list handling created using the 'random' module.
+%%%-------------------------------------------------------------------
+-module(basic_random).
+
+-export([test/0]).
+
+%% It can be used as a benchmark by playing with the following defines
+-define(N, 1000).
+-define(Iter, 500).
+
+test() ->
+ ok = random(?N).
+
+random(N) ->
+ random(N, ?Iter).
+
+random(N, Iter) ->
+ random:seed(1, 2, 3),
+ t(ranlist(N, [], N*100), Iter).
+
+ranlist(0, L, _N) -> L;
+ranlist(N, L, N0) -> ranlist(N-1, [random:uniform(N0)+300 | L], N0).
+
+t(_, 0) -> ok;
+t(L, Iter) ->
+ %% io:format("Sort starting~n"),
+ sort(L),
+ t(L, Iter-1).
+
+sort([X, Y | L]) when X =< Y ->
+ split_1(X, Y, L, [], []);
+sort([X, Y | L]) ->
+ split_2(X, Y, L, [], []);
+sort(L) ->
+ L.
+
+%% Ascending.
+split_1(X, Y, [Z | L], R, Rs) when Z >= Y ->
+ split_1(Y, Z, L, [X | R], Rs);
+split_1(X, Y, [Z | L], R, Rs) when Z >= X ->
+ split_1(Z, Y, L, [X | R], Rs);
+split_1(X, Y, [Z | L], [], Rs) ->
+ split_1(X, Y, L, [Z], Rs);
+split_1(X, Y, [Z | L], R, Rs) ->
+ split_1_1(X, Y, L, R, Rs, Z);
+split_1(X, Y, [], R, Rs) ->
+ rmergel([[Y, X | R] | Rs], []).
+
+%% One out-of-order element, S.
+split_1_1(X, Y, [Z | L], R, Rs, S) when Z >= Y ->
+ split_1_1(Y, Z, L, [X | R], Rs, S);
+split_1_1(X, Y, [Z | L], R, Rs, S) when Z >= X ->
+ split_1_1(Z, Y, L, [X | R], Rs, S);
+split_1_1(X, Y, [Z | L], R, Rs, S) when S =< Z ->
+ split_1(S, Z, L, [], [[Y, X | R] | Rs]);
+split_1_1(X, Y, [Z | L], R, Rs, S) ->
+ split_1(Z, S, L, [], [[Y, X | R] | Rs]);
+split_1_1(X, Y, [], R, Rs, S) ->
+ rmergel([[S], [Y, X | R] | Rs], []).
+
+%% Descending.
+split_2(X, Y, [Z | L], R, Rs) when Z =< Y ->
+ split_2(Y, Z, L, [X | R], Rs);
+split_2(X, Y, [Z | L], R, Rs) when Z =< X ->
+ split_2(Z, Y, L, [X | R], Rs);
+split_2(X, Y, [Z | L], [], Rs) ->
+ split_2(X, Y, L, [Z], Rs);
+split_2(X, Y, [Z | L], R, Rs) ->
+ split_2_1(X, Y, L, R, Rs, Z);
+split_2(X, Y, [], R, Rs) ->
+ mergel([[Y, X | R] | Rs], []).
+
+split_2_1(X, Y, [Z | L], R, Rs, S) when Z =< Y ->
+ split_2_1(Y, Z, L, [X | R], Rs, S);
+split_2_1(X, Y, [Z | L], R, Rs, S) when Z =< X ->
+ split_2_1(Z, Y, L, [X | R], Rs, S);
+split_2_1(X, Y, [Z | L], R, Rs, S) when S > Z ->
+ split_2(S, Z, L, [], [[Y, X | R] | Rs]);
+split_2_1(X, Y, [Z | L], R, Rs, S) ->
+ split_2(Z, S, L, [], [[Y, X | R] | Rs]);
+split_2_1(X, Y, [], R, Rs, S) ->
+ mergel([[S], [Y, X | R] | Rs], []).
+
+mergel([[] | L], Acc) ->
+ mergel(L, Acc);
+mergel([A, [H2 | T2], [H3 | T3] | L], Acc) ->
+ mergel(L, [merge3_1(A, [], H2, T2, H3, T3) | Acc]);
+mergel([A, [H | T]], Acc) ->
+ rmergel([merge2_1(A, H, T, []) | Acc], []);
+mergel([L], []) ->
+ L;
+mergel([L], Acc) ->
+ rmergel([lists:reverse(L, []) | Acc], []);
+mergel([], []) ->
+ [];
+mergel([], Acc) ->
+ rmergel(Acc, []);
+mergel([A, [] | L], Acc) ->
+ mergel([A | L], Acc);
+mergel([A, B, [] | L], Acc) ->
+ mergel([A, B | L], Acc).
+
+rmergel([A, [H2 | T2], [H3 | T3] | L], Acc) ->
+ rmergel(L, [rmerge3_1(A, [], H2, T2, H3, T3) | Acc]);
+rmergel([A, [H | T]], Acc) ->
+ mergel([rmerge2_1(A, H, T, []) | Acc], []);
+rmergel([L], Acc) ->
+ mergel([lists:reverse(L, []) | Acc], []);
+rmergel([], Acc) ->
+ mergel(Acc, []).
+
+%% Take L1 apart.
+merge3_1([H1 | T1], M, H2, T2, H3, T3) when H1 =< H2 ->
+ merge3_12(T1, H1, H2, T2, H3, T3, M);
+merge3_1([H1 | T1], M, H2, T2, H3, T3) ->
+ merge3_21(T1, H1, H2, T2, H3, T3, M);
+merge3_1(_nil, M, H2, T2, H3, T3) when H2 =< H3 ->
+ merge2_1(T2, H3, T3, [H2 | M]);
+merge3_1(_nil, M, H2, T2, H3, T3) ->
+ merge2_1(T3, H2, T2, [H3 | M]).
+
+%% Take L2 apart.
+merge3_2(T1, H1, M, [H2 | T2], H3, T3) when H1 =< H2 ->
+ merge3_12(T1, H1, H2, T2, H3, T3, M);
+merge3_2(T1, H1, M, [H2 | T2], H3, T3) ->
+ merge3_21(T1, H1, H2, T2, H3, T3, M);
+merge3_2(T1, H1, M, _nil, H3, T3) when H1 =< H3 ->
+ merge2_1(T1, H3, T3, [H1 | M]);
+merge3_2(T1, H1, M, _nil, H3, T3) ->
+ merge2_1(T3, H1, T1, [H3 | M]).
+
+%% H1 <= H2. Inlined.
+merge3_12(T1, H1, H2, T2, H3, T3, M) when H3 < H1 ->
+ merge3_12_3(T1, H1, H2, T2, [H3 | M], T3);
+merge3_12(T1, H1, H2, T2, H3, T3, M) ->
+ merge3_1(T1, [H1 | M], H2, T2, H3, T3).
+
+%% H1 <= H2, take L3 apart.
+merge3_12_3(T1, H1, H2, T2, M, [H3 | T3]) when H3 < H1 ->
+ merge3_12_3(T1, H1, H2, T2, [H3 | M], T3);
+merge3_12_3(T1, H1, H2, T2, M, [H3 | T3]) ->
+ merge3_1(T1, [H1 | M], H2, T2, H3, T3);
+merge3_12_3(T1, H1, H2, T2, M, _nil) ->
+ merge2_1(T1, H2, T2, [H1 | M]).
+
+%% H1 > H2. Inlined.
+merge3_21(T1, H1, H2, T2, H3, T3, M) when H3 < H2 ->
+ merge3_21_3(T1, H1, H2, T2, [H3 | M], T3);
+merge3_21(T1, H1, H2, T2, H3, T3, M) ->
+ merge3_2(T1, H1, [H2 | M], T2, H3, T3).
+
+%% H1 > H2, take L3 apart.
+merge3_21_3(T1, H1, H2, T2, M, [H3 | T3]) when H3 < H2 ->
+ merge3_21_3(T1, H1, H2, T2, [H3 | M], T3);
+merge3_21_3(T1, H1, H2, T2, M, [H3 | T3]) ->
+ merge3_2(T1, H1, [H2 | M], T2, H3, T3);
+merge3_21_3(T1, H1, H2, T2, M, _nil) ->
+ merge2_1(T2, H1, T1, [H2 | M]).
+
+%% Take L1 apart.
+rmerge3_1([H1 | T1], M, H2, T2, H3, T3) when H1 > H2 ->
+ rmerge3_12(T1, H1, H2, T2, H3, T3, M);
+rmerge3_1([H1 | T1], M, H2, T2, H3, T3) ->
+ rmerge3_21(T1, H1, H2, T2, H3, T3, M);
+rmerge3_1(_nil, M, H2, T2, H3, T3) when H2 > H3 ->
+ rmerge2_1(T2, H3, T3, [H2 | M]);
+rmerge3_1(_nil, M, H2, T2, H3, T3) ->
+ rmerge2_1(T3, H2, T2, [H3 | M]).
+
+%% Take L2 apart.
+rmerge3_2(T1, H1, M, [H2 | T2], H3, T3) when H1 > H2 ->
+ rmerge3_12(T1, H1, H2, T2, H3, T3, M);
+rmerge3_2(T1, H1, M, [H2 | T2], H3, T3) ->
+ rmerge3_21(T1, H1, H2, T2, H3, T3, M);
+rmerge3_2(T1, H1, M, _nil, H3, T3) when H1 > H3 ->
+ rmerge2_1(T1, H3, T3, [H1 | M]);
+rmerge3_2(T1, H1, M, _nil, H3, T3) ->
+ rmerge2_1(T3, H1, T1, [H3 | M]).
+
+%% H1 > H2. Inlined.
+rmerge3_12(T1, H1, H2, T2, H3, T3, M) when H3 >= H1 ->
+ rmerge3_12_3(T1, H1, H2, T2, [H3 | M], T3);
+rmerge3_12(T1, H1, H2, T2, H3, T3, M) ->
+ rmerge3_1(T1, [H1 | M], H2, T2, H3, T3).
+
+%% H1 > H2, take L3 apart.
+rmerge3_12_3(T1, H1, H2, T2, M, [H3 | T3]) when H3 >= H1 ->
+ rmerge3_12_3(T1, H1, H2, T2, [H3 | M], T3);
+rmerge3_12_3(T1, H1, H2, T2, M, [H3 | T3]) ->
+ rmerge3_1(T1, [H1 | M], H2, T2, H3, T3);
+rmerge3_12_3(T1, H1, H2, T2, M, _nil) ->
+ rmerge2_1(T1, H2, T2, [H1 | M]).
+
+%% H1 =< H2. Inlined.
+rmerge3_21(T1, H1, H2, T2, H3, T3, M) when H3 >= H2 ->
+ rmerge3_21_3(T1, H1, H2, T2, [H3 | M], T3);
+rmerge3_21(T1, H1, H2, T2, H3, T3, M) ->
+ rmerge3_2(T1, H1, [H2 | M], T2, H3, T3).
+
+%% H1 =< H2, take L3 apart.
+rmerge3_21_3(T1, H1, H2, T2, M, [H3 | T3]) when H3 >= H2 ->
+ rmerge3_21_3(T1, H1, H2, T2, [H3 | M], T3);
+rmerge3_21_3(T1, H1, H2, T2, M, [H3 | T3]) ->
+ rmerge3_2(T1, H1, [H2 | M], T2, H3, T3);
+rmerge3_21_3(T1, H1, H2, T2, M, _nil) ->
+ rmerge2_1(T2, H1, T1, [H2 | M]).
+
+merge2_1([H1 | T1], H2, T2, M) when H2 < H1 ->
+ merge2_2(T1, H1, T2, [H2 | M]);
+merge2_1([H1 | T1], H2, T2, M) ->
+ merge2_1(T1, H2, T2, [H1 | M]);
+merge2_1(_nil, H2, T2, M) ->
+ lists:reverse(T2, [H2 | M]).
+
+merge2_2(T1, H1, [H2 | T2], M) when H1 < H2 ->
+ merge2_1(T1, H2, T2, [H1 | M]);
+merge2_2(T1, H1, [H2 | T2], M) ->
+ merge2_2(T1, H1, T2, [H2 | M]);
+merge2_2(T1, H1, _nil, M) ->
+ lists:reverse(T1, [H1 | M]).
+
+rmerge2_1([H1 | T1], H2, T2, M) when H2 >= H1 ->
+ rmerge2_2(T1, H1, T2, [H2 | M]);
+rmerge2_1([H1 | T1], H2, T2, M) ->
+ rmerge2_1(T1, H2, T2, [H1 | M]);
+rmerge2_1(_nil, H2, T2, M) ->
+ lists:reverse(T2, [H2 | M]).
+
+rmerge2_2(T1, H1, [H2 | T2], M) when H1 >= H2 ->
+ rmerge2_1(T1, H2, T2, [H1 | M]);
+rmerge2_2(T1, H1, [H2 | T2], M) ->
+ rmerge2_2(T1, H1, T2, [H2 | M]);
+rmerge2_2(T1, H1, _nil, M) ->
+ lists:reverse(T1, [H1 | M]).
diff --git a/lib/hipe/test/basic_SUITE_data/basic_receive.erl b/lib/hipe/test/basic_SUITE_data/basic_receive.erl
new file mode 100644
index 0000000000..5f865d7b7a
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_receive.erl
@@ -0,0 +1,56 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%%
+%%% Contains code examples that test correct handling of receives.
+%%%-------------------------------------------------------------------
+-module(basic_receive).
+
+-export([test/0]).
+
+test() ->
+ ok = test_wait_timeout(),
+ ok = test_double_timeout(),
+ ok = test_reschedule(),
+ ok.
+
+%%--------------------------------------------------------------------
+
+test_wait_timeout() ->
+ receive after 42 -> ok end.
+
+%%--------------------------------------------------------------------
+
+test_double_timeout() ->
+ self() ! foo,
+ self() ! another_foo,
+ receive
+ non_existent -> weird
+ after 0 -> timeout
+ end,
+ receive
+ foo -> ok
+ after 1000 -> timeout
+ end.
+
+%%--------------------------------------------------------------------
+%% Check that RESCHEDULE returns from BIFs work.
+
+test_reschedule() ->
+ erts_debug:set_internal_state(available_internal_state, true),
+ First = self(),
+ Second = spawn(fun() -> doit(First) end),
+ receive
+ Second -> ok
+ end,
+ receive
+ after 42 -> ok
+ end,
+ erts_debug:set_internal_state(hipe_test_reschedule_resume, Second),
+ ok.
+
+doit(First) ->
+ First ! self(),
+ erts_debug:set_internal_state(hipe_test_reschedule_suspend, 1).
+
+%%--------------------------------------------------------------------
diff --git a/lib/hipe/test/basic_SUITE_data/basic_records.erl b/lib/hipe/test/basic_SUITE_data/basic_records.erl
new file mode 100644
index 0000000000..cbb451196c
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_records.erl
@@ -0,0 +1,28 @@
+%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%%
+%%% Contains tests that manipulate and pattern match against records.
+%%%-------------------------------------------------------------------
+-module(basic_records).
+
+-export([test/0]).
+
+test() ->
+ ok = test_rec1(),
+ ok.
+
+%%--------------------------------------------------------------------
+
+-record(r, {ra}).
+-record(s, {sa, sb, sc, sd}).
+
+test_rec1() ->
+ R = #r{},
+ S = #s{},
+ S1 = S#s{sc=R, sd=1},
+ R1 = S1#s.sc,
+ undefined = R1#r.ra,
+ ok.
+
+%%--------------------------------------------------------------------
diff --git a/lib/hipe/test/basic_SUITE_data/basic_strength_reduce.erl b/lib/hipe/test/basic_SUITE_data/basic_strength_reduce.erl
new file mode 100644
index 0000000000..0f94320a33
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_strength_reduce.erl
@@ -0,0 +1,65 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%%
+%%% Tests the strength reduction component of the HiPE compiler.
+%%%-------------------------------------------------------------------
+-module(basic_strength_reduce).
+
+-export([test/0]).
+%% These functions are exported so as to not remove them by inlining
+-export([crash_0/1, crash_1/1, crash_2/1, crash_3/1, bug_div_2N/1]).
+
+test() ->
+ ok = test_strength_reduce1(),
+ ok.
+
+%%--------------------------------------------------------------------
+
+test_strength_reduce1() ->
+ ok = crash_0(0),
+ ok = crash_1(42),
+ ok = crash_2(42),
+ ok = crash_3(42),
+ 5 = 42 bsr 3 = bug_div_2N(42),
+ -6 = -42 bsr 3 = bug_div_2N(-42) - 1,
+ ok.
+
+%% This is a crash report by Peter Wang (10 July 2007) triggering an
+%% R11B-5 crash: strength reduction could not handle calls with no
+%% destination
+crash_0(A) ->
+ case A of
+ 0 ->
+ A div 8,
+ ok
+ end.
+
+%% The above was simplified to the following which showed another
+%% crash, this time on RTL
+crash_1(A) when is_integer(A), A >= 0 ->
+ A div 8,
+ ok.
+
+%% A similar crash like the first one, but in a different place in the
+%% code, was triggered by the following code
+crash_2(A) when is_integer(A), A >= 0 ->
+ A div 1,
+ ok.
+
+%% A crash similar to the first one happened in the following code
+crash_3(A) ->
+ case A of
+ 42 ->
+ A * 0,
+ ok
+ end.
+
+%% Strength reduction for div/2 and rem/2 with a power of 2
+%% should be performed only for non-negative integers
+bug_div_2N(X) when is_integer(X), X >= 0 ->
+ X div 8;
+bug_div_2N(X) when is_integer(X), X < 0 ->
+ X div 8.
+
+%%--------------------------------------------------------------------
diff --git a/lib/hipe/test/basic_SUITE_data/basic_switches.erl b/lib/hipe/test/basic_SUITE_data/basic_switches.erl
new file mode 100644
index 0000000000..0a7ae5b8b7
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_switches.erl
@@ -0,0 +1,52 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%%
+%%% Contains tests for pattern matching switches.
+%%%-------------------------------------------------------------------
+-module(basic_switches).
+
+-export([test/0]).
+
+test() ->
+ ok = test_switch_mix(),
+ ok.
+
+%%---------------------------------------------------------------------
+
+-define(BIG1, 21323233222132323322).
+-define(BIG2, 4242424242424242424242424242424242).
+
+test_switch_mix() ->
+ small1 = t(42),
+ small2 = t(17),
+ big1 = t(?BIG1),
+ big2 = t(?BIG2),
+ atom = t(foo),
+ pid = t(self()),
+ float = t(4.2),
+ ok.
+
+t(V) ->
+ S = self(),
+ case V of
+ 42 -> small1;
+ 17 -> small2;
+ ?BIG1 -> big1;
+ ?BIG2 -> big2;
+ 1 -> no;
+ 2 -> no;
+ 3 -> no;
+ 4 -> no;
+ 5 -> no;
+ 6 -> no;
+ 7 -> no;
+ 8 -> no;
+ foo -> atom;
+ 9 -> no;
+ 4.2 -> float;
+ S -> pid;
+ _ -> no
+ end.
+
+%%---------------------------------------------------------------------
diff --git a/lib/hipe/test/basic_SUITE_data/basic_tail_rec.erl b/lib/hipe/test/basic_SUITE_data/basic_tail_rec.erl
new file mode 100644
index 0000000000..0124f13df6
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_tail_rec.erl
@@ -0,0 +1,39 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%%
+%%% Contains tests that check that tail recursion optimization occurs.
+%%%-------------------------------------------------------------------
+-module(basic_tail_rec).
+
+-export([test/0]).
+-export([app0/2]). %% used in an apply/3 call
+
+test() ->
+ ok = test_app_tail(),
+ ok.
+
+%%--------------------------------------------------------------------
+%% Written by Mikael Pettersson: check that apply is tail recursive.
+
+%% Increased the following quantity from 20 to 30 so that the test
+%% remains valid even with the naive register allocator. - Kostis
+-define(SIZE_INCREASE, 30).
+
+test_app_tail() ->
+ Inc = start(400),
+ %% io:format("Inc ~w\n", [Inc]),
+ case Inc > ?SIZE_INCREASE of
+ true ->
+ {error, "apply/3 is not tail recursive in native code"};
+ false ->
+ ok
+ end.
+
+start(N) ->
+ app0(N, hipe_bifs:nstack_used_size()).
+
+app0(0, Size0) ->
+ hipe_bifs:nstack_used_size() - Size0;
+app0(N, Size) ->
+ apply(?MODULE, app0, [N-1, Size]).
diff --git a/lib/hipe/test/basic_SUITE_data/basic_tuples.erl b/lib/hipe/test/basic_SUITE_data/basic_tuples.erl
new file mode 100644
index 0000000000..94c187e364
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_tuples.erl
@@ -0,0 +1,177 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%%
+%%% Contains tests that manipulate and pattern match against tuples.
+%%%-------------------------------------------------------------------
+-module(basic_tuples).
+
+-export([test/0]).
+
+test() ->
+ Num = 4711,
+ ok = test_match({}, {1}, {1,2}, {1,2,3}, {1,2,3,4}, {1,2,3,4,5},
+ {1,2,3,4,5,6}, {1,2,3,4,5,6,7}, {1,2,3,4,5,6,7,8}),
+ ok = test_size({}, {a}, {{a},{b}}, {a,{b},c}),
+ ok = test_element({}, {a}, {a,b}, Num),
+ ok = test_setelement({}, {1}, {1,2}, 3, [1,2]),
+ ok = test_tuple_to_list({}, {a}, {a,b}, {a,b,c}, {a,b,c,d}, Num),
+ ok = test_list_to_tuple([], [a], [a,b], [a,b,c], [a,b,c,d], Num),
+ ok = test_tuple_with_case(),
+ ok = test_tuple_in_guard({a, b}, {a, b, c}),
+ ok.
+
+%%--------------------------------------------------------------------
+%% Tests matching of tuples
+
+test_match(T0, T1, T2, T3, T4, T5, T6, T7, T8) ->
+ {} = T0,
+ {1} = T1,
+ {1, 2} = T2,
+ {1, 2, 3} = T3,
+ {1, 2, 3, 4} = T4,
+ {1, 2, 3, 4, 5} = T5,
+ {1, 2, 3, 4, 5, 6} = T6,
+ T6 = {1, 2, 3, 4, 5, 6},
+ T7 = {1, 2, 3, 4, 5, 6, 7},
+ {1, 2, 3, 4, 5, 6, 7, 8} = T8,
+ ok.
+
+%%--------------------------------------------------------------------
+%% Tests the size/1 and tuple_size/1 BIFs.
+
+test_size(T0, T1, T2, T3) ->
+ [0, 1, 2, 3] = [size(T) || T <- [T0, T1, T2, T3]],
+ [0, 1, 2, 3] = [tuple_size(T) || T <- [T0, T1, T2, T3]],
+ ok.
+
+%%--------------------------------------------------------------------
+%% Tests element/2.
+
+test_element(T0, T1, T2, N) ->
+ a = element(1, T1),
+ a = element(1, T2),
+ %% indirect calls to element/2
+ List = lists:seq(1, N),
+ Tuple = list_to_tuple(List),
+ ok = get_elements(List, Tuple, 1),
+ %% some cases that throw exceptions
+ {'EXIT', _} = (catch my_element(0, T2)),
+ {'EXIT', _} = (catch my_element(3, T2)),
+ {'EXIT', _} = (catch my_element(1, T0)),
+ {'EXIT', _} = (catch my_element(1, List)),
+ {'EXIT', _} = (catch my_element(1, N)),
+ {'EXIT', _} = (catch my_element(1.5, T2)),
+ ok.
+
+my_element(Pos, Term) ->
+ element(Pos, Term).
+
+get_elements([Element|Rest], Tuple, Pos) ->
+ Element = element(Pos, Tuple),
+ get_elements(Rest, Tuple, Pos + 1);
+get_elements([], _Tuple, _Pos) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% Tests set_element/3.
+
+test_setelement(T0, T1, Pair, Three, L) ->
+ {x} = setelement(1, T1, x),
+ {x, 2} = setelement(1, Pair, x),
+ {1, x} = setelement(2, Pair, x),
+ %% indirect calls to setelement/3
+ Tuple = list_to_tuple(lists:duplicate(2048, x)),
+ NewTuple = set_all_elements(Tuple, 1),
+ NewTuple = list_to_tuple(lists:seq(1+7, 2048+7)),
+ %% the following cases were rewritten to use the Three
+ %% variable in this weird way so as to silence the compiler
+ {'EXIT', _} = (catch setelement(Three - Three, Pair, x)),
+ {'EXIT', _} = (catch setelement(Three, Pair, x)),
+ {'EXIT', _} = (catch setelement(Three div Three, T0, x)),
+ {'EXIT', _} = (catch setelement(Three div Three, L, x)),
+ {'EXIT', _} = (catch setelement(Three / 2, Pair, x)),
+ ok.
+
+set_all_elements(Tuple, Pos) when Pos =< tuple_size(Tuple) ->
+ set_all_elements(setelement(Pos, Tuple, Pos+7), Pos+1);
+set_all_elements(Tuple, Pos) when Pos > tuple_size(Tuple) ->
+ Tuple.
+
+%%--------------------------------------------------------------------
+%% Tests tuple_to_list/1.
+
+test_tuple_to_list(T0, T1, T2, T3, T4, Size) ->
+ [] = tuple_to_list(T0),
+ [a] = tuple_to_list(T1),
+ [a, b] = tuple_to_list(T2),
+ [a, b, c] = tuple_to_list(T3),
+ [a, b, c, d] = tuple_to_list(T4),
+ [a, b, c, d] = tuple_to_list(T4),
+ %% test a big tuple
+ List = lists:seq(1, Size),
+ Tuple = list_to_tuple(List),
+ Size = tuple_size(Tuple),
+ List = tuple_to_list(Tuple),
+ %% some cases that should result in errors
+ {'EXIT', _} = (catch my_tuple_to_list(element(2, T3))),
+ {'EXIT', _} = (catch my_tuple_to_list(Size)),
+ ok.
+
+my_tuple_to_list(X) ->
+ tuple_to_list(X).
+
+%%--------------------------------------------------------------------
+%% Tests list_to_tuple/1.
+
+test_list_to_tuple(L0, L1, L2, L3, L4, Size) ->
+ {} = list_to_tuple(L0),
+ {a} = list_to_tuple(L1),
+ {a, b} = list_to_tuple(L2),
+ {a, b, c} = list_to_tuple(L3),
+ {a, b, c, d} = list_to_tuple(L4),
+ {a, b, c, d, e} = list_to_tuple(L4++[e]),
+ %% test list_to_tuple with a big list
+ Tuple = list_to_tuple(lists:seq(1, Size)),
+ Size = tuple_size(Tuple),
+ %% some cases that should result in errors
+ {'EXIT', _} = (catch my_list_to_tuple({a,b})),
+ {'EXIT', _} = (catch my_list_to_tuple([hd(L1)|hd(L2)])),
+ ok.
+
+my_list_to_tuple(X) ->
+ list_to_tuple(X).
+
+%%--------------------------------------------------------------------
+%% Tests that a case nested inside a tuple is ok.
+%% (This was known to crash earlier versions of BEAM.)
+
+test_tuple_with_case() ->
+ {reply, true} = tuple_with_case(),
+ ok.
+
+tuple_with_case() ->
+ %% The following comments apply to the BEAM compiler.
+ void(), % Reset var count.
+ {reply, % Compiler will choose {x,1} for tuple.
+ case void() of % Call will reset var count.
+ {'EXIT', Reason} -> % Case will return in {x,1} (first free),
+ {error, Reason}; % but the tuple will be build in {x,1},
+ _ -> % so case value is lost and a circular
+ true % data element is built.
+ end}.
+
+void() -> ok.
+
+%%--------------------------------------------------------------------
+%% Test to build a tuple in a guard.
+
+test_tuple_in_guard(T2, T3) ->
+ %% T2 = {a, b}; T3 = {a, b, c}
+ ok = if T2 == {element(1, T3), element(2, T3)} -> ok;
+ true -> other
+ end,
+ ok = if T3 == {element(1, T3), element(2, T3), element(3, T3)} -> ok;
+ true -> other
+ end,
+ ok.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_add.erl b/lib/hipe/test/bs_SUITE_data/bs_add.erl
index af5a3b2f23..4b92e6b413 100644
--- a/lib/hipe/test/bs_SUITE_data/bs_add.erl
+++ b/lib/hipe/test/bs_SUITE_data/bs_add.erl
@@ -2,7 +2,7 @@
%%-------------------------------------------------------------------------
%% The guard in f/3 revealed a problem in the translation of the 'bs_add'
%% BEAM instruction to Icode. The fail label was not properly translated.
-%% Fixed 3/2/2011.
+%% Fixed 3/2/2011. Then in 2015 we found another issue: g/2. Also fixed.
%%-------------------------------------------------------------------------
-module(bs_add).
@@ -10,9 +10,17 @@
test() ->
42 = f(<<12345:16>>, 4711, <<42>>),
+ true = g(<<1:13>>, 3), %% was handled OK, but
+ false = g(<<>>, gurka), %% this one leaked badarith
ok.
f(Bin, A, B) when <<A:9, B:7/binary>> == Bin ->
gazonk;
f(Bin, _, _) when is_binary(Bin) ->
42.
+
+%% Complex way of testing (bit_size(Bin) + Len) rem 8 =:= 0
+g(Bin, Len) when is_binary(<<Bin/binary-unit:1, 123:Len>>) ->
+ true;
+g(_, _) ->
+ false.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_construct.erl b/lib/hipe/test/bs_SUITE_data/bs_construct.erl
index 9cc9ac848c..b9e7d93570 100644
--- a/lib/hipe/test/bs_SUITE_data/bs_construct.erl
+++ b/lib/hipe/test/bs_SUITE_data/bs_construct.erl
@@ -13,6 +13,12 @@ test() ->
ok = bs5(),
16#10000008 = bit_size(large_bin(1, 2, 3, 4)),
ok = bad_ones(),
+ ok = zero_width(),
+ ok = not_used(),
+ ok = bad_append(),
+ ok = system_limit(),
+ ok = bad_floats(),
+ ok = huge_binaries(),
ok.
%%--------------------------------------------------------------------
@@ -126,3 +132,174 @@ bad_ones() ->
Bin123 = <<1,2,3>>,
?FAIL(<<Bin123/float>>),
ok.
+
+%%--------------------------------------------------------------------
+%% Taken from the emulator bs_construct_SUITE - seg faulted till 18.1
+
+zero_width() ->
+ Z = id(0),
+ Small = id(42),
+ Big = id(1 bsl 128), % puts stuff on the heap
+ <<>> = <<Small:Z>>,
+ <<>> = <<Small:0>>,
+ <<>> = <<Big:Z>>,
+ <<>> = <<Big:0>>,
+ ok.
+
+id(X) -> X.
+
+%%--------------------------------------------------------------------
+%% Taken from bs_construct_SUITE. The test checks that constructed
+%% binaries that are not used would still give a `badarg' exception.
+%% Problem was that in native code one of them gave `badarith'.
+
+not_used() ->
+ ok = not_used1(3, <<"dum">>),
+ {'EXIT',{badarg,_}} = (catch not_used1(42, "dum_string")),
+ {'EXIT',{badarg,_}} = (catch not_used2(666, -2)),
+ {'EXIT',{badarg,_}} = (catch not_used2(666, "bad_size")), % this one
+ {'EXIT',{badarg,_}} = (catch not_used3(666)),
+ ok.
+
+not_used1(I, BinString) ->
+ <<I:32,BinString/binary>>,
+ ok.
+
+not_used2(I, Sz) ->
+ <<I:Sz>>,
+ ok.
+
+not_used3(I) ->
+ <<I:(-8)>>,
+ ok.
+
+%%--------------------------------------------------------------------
+%% Taken from bs_construct_SUITE.
+
+bad_append() ->
+ do_bad_append(<<127:1>>, fun append_unit_3/1),
+ do_bad_append(<<127:2>>, fun append_unit_3/1),
+ do_bad_append(<<127:17>>, fun append_unit_3/1),
+
+ do_bad_append(<<127:3>>, fun append_unit_4/1),
+ do_bad_append(<<127:5>>, fun append_unit_4/1),
+ do_bad_append(<<127:7>>, fun append_unit_4/1),
+ do_bad_append(<<127:199>>, fun append_unit_4/1),
+
+ do_bad_append(<<127:7>>, fun append_unit_8/1),
+ do_bad_append(<<127:9>>, fun append_unit_8/1),
+
+ do_bad_append(<<0:8>>, fun append_unit_16/1),
+ do_bad_append(<<0:15>>, fun append_unit_16/1),
+ do_bad_append(<<0:17>>, fun append_unit_16/1),
+ ok.
+
+do_bad_append(Bin0, Appender) ->
+ {'EXIT',{badarg,_}} = (catch Appender(Bin0)),
+
+ Bin1 = id(<<0:3,Bin0/bitstring>>),
+ <<_:3,Bin2/bitstring>> = Bin1,
+ {'EXIT',{badarg,_}} = (catch Appender(Bin2)),
+
+ %% Create a writable binary.
+ Empty = id(<<>>),
+ Bin3 = <<Empty/bitstring,Bin0/bitstring>>,
+ {'EXIT',{badarg,_}} = (catch Appender(Bin3)),
+ ok.
+
+append_unit_3(Bin) ->
+ <<Bin/binary-unit:3,0:1>>.
+
+append_unit_4(Bin) ->
+ <<Bin/binary-unit:4,0:1>>.
+
+append_unit_8(Bin) ->
+ <<Bin/binary,0:1>>.
+
+append_unit_16(Bin) ->
+ <<Bin/binary-unit:16,0:1>>.
+
+%%--------------------------------------------------------------------
+%% Taken from bs_construct_SUITE.
+
+system_limit() ->
+ WordSize = erlang:system_info(wordsize),
+ BitsPerWord = WordSize * 8,
+ {'EXIT',{system_limit,_}} =
+ (catch <<0:(id(0)),42:(id(1 bsl BitsPerWord))>>),
+ {'EXIT',{system_limit,_}} =
+ (catch <<42:(id(1 bsl BitsPerWord)),0:(id(0))>>),
+ {'EXIT',{system_limit,_}} =
+ (catch <<(id(<<>>))/binary,0:(id(1 bsl 100))>>),
+
+ %% Would fail to load.
+ {'EXIT',{system_limit,_}} = (catch <<0:(1 bsl 67)>>),
+ {'EXIT',{system_limit,_}} = (catch <<0:((1 bsl 64)+1)>>),
+ case WordSize of
+ 4 ->
+ system_limit_32();
+ 8 ->
+ ok
+ end.
+
+system_limit_32() ->
+ {'EXIT',{badarg,_}} = (catch <<42:(-1)>>),
+ {'EXIT',{badarg,_}} = (catch <<42:(id(-1))>>),
+ {'EXIT',{badarg,_}} = (catch <<42:(id(-389739873536870912))/unit:8>>),
+ {'EXIT',{system_limit,_}} = (catch <<42:536870912/unit:8>>),
+ {'EXIT',{system_limit,_}} = (catch <<42:(id(536870912))/unit:8>>),
+ {'EXIT',{system_limit,_}} = (catch <<0:(id(8)),42:536870912/unit:8>>),
+ {'EXIT',{system_limit,_}} = (catch <<0:(id(8)),42:(id(536870912))/unit:8>>),
+
+ %% The size would be silently truncated, resulting in a crash.
+ {'EXIT',{system_limit,_}} = (catch <<0:(1 bsl 35)>>),
+ {'EXIT',{system_limit,_}} = (catch <<0:((1 bsl 32)+1)>>),
+
+ %% Would fail to load.
+ {'EXIT',{system_limit,_}} = (catch <<0:(1 bsl 43)>>),
+ {'EXIT',{system_limit,_}} = (catch <<0:((1 bsl 40)+1)>>),
+ ok.
+
+%%--------------------------------------------------------------------
+
+bad_floats() ->
+ WordSize = erlang:system_info(wordsize),
+ BitsPerWord = WordSize * 8,
+ {'EXIT',{badarg,_}} = (catch <<3.14:(id(33))/float>>),
+ {'EXIT',{badarg,_}} = (catch <<3.14:(id(64 bor 32))/float>>),
+ {'EXIT',{badarg,_}} = (catch <<3.14:(id((1 bsl 28) bor 32))/float>>),
+ {'EXIT',{system_limit,_}} = (catch <<3.14:(id(1 bsl BitsPerWord))/float>>),
+ ok.
+
+%%--------------------------------------------------------------------
+%% A bug in the implementation of binaries compared sizes in bits with sizes in
+%% bytes, causing <<0:(id((1 bsl 31)-1))>> to fail to construct with
+%% 'system_limit'.
+%% <<0:(id((1 bsl 32)-1))>> was succeeding because the comparison was
+%% (incorrectly) signed.
+
+huge_binaries() ->
+ AlmostIllegal = id(<<0:(id((1 bsl 32)-8))>>),
+ case erlang:system_info(wordsize) of
+ 4 -> huge_binaries_32(AlmostIllegal);
+ 8 -> ok
+ end,
+ garbage_collect(),
+ id(<<0:(id((1 bsl 31)-1))>>),
+ id(<<0:(id((1 bsl 30)-1))>>),
+ garbage_collect(),
+ ok.
+
+huge_binaries_32(AlmostIllegal) ->
+ %% Attempt construction of too large binary using bs_init/1 (which takes the
+ %% number of bytes as an argument, which should be compared to the maximum
+ %% size in bytes).
+ {'EXIT',{system_limit,_}} = (catch <<0:32,AlmostIllegal/binary>>),
+ %% Attempt construction of too large binary using bs_init/1 with a size in
+ %% bytes that has the msb set (and would be negative if it was signed).
+ {'EXIT',{system_limit,_}} =
+ (catch <<0:8, AlmostIllegal/binary, AlmostIllegal/binary,
+ AlmostIllegal/binary, AlmostIllegal/binary,
+ AlmostIllegal/binary, AlmostIllegal/binary,
+ AlmostIllegal/binary, AlmostIllegal/binary>>),
+ ok.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_match.erl b/lib/hipe/test/bs_SUITE_data/bs_match.erl
index 7bc93a316b..b241ea8d35 100644
--- a/lib/hipe/test/bs_SUITE_data/bs_match.erl
+++ b/lib/hipe/test/bs_SUITE_data/bs_match.erl
@@ -1,8 +1,8 @@
%%% -*- erlang-indent-level: 2 -*-
%%%-------------------------------------------------------------------
%%% File : bs_match.erl
-%%% Author : Per Gustafsson <[email protected]>
-%%% Purpose : Performs simple matching and construction of binaries
+%%% Authors : Per Gustafsson <[email protected]>, Kostis Sagonas <[email protected]>
+%%% Purpose : Tests matching and construction of binaries
%%% TODO : Add binary and float tests
%%% Created : 20 Feb 2004
%%%-------------------------------------------------------------------
@@ -13,7 +13,7 @@
test() ->
Funs = [fun test_aligned/0, fun test_unaligned/0,
fun test_zero_tail/0, fun test_integer_matching/0,
- fun test_writable_bin/0],
+ fun test_writable_bin/0, fun test_match_huge_bin/0],
lists:foreach(fun (F) -> ok = F() end, Funs).
%%-------------------------------------------------------------------
@@ -175,6 +175,9 @@ test_dynamic_integer_matching(N) ->
<<12:N/integer-little, 0:S>> = <<12:N/integer-little, 0:S>>,
ok.
+%%-------------------------------------------------------------------
+%% Test writable bin -- added by Sverker Eriksson
+
test_writable_bin() ->
test_writable_bin(<<>>, 0),
ok.
@@ -185,3 +188,102 @@ test_writable_bin(Bin0, N) when N < 128 ->
Bin1 = <<Bin0/binary, N>>,
<<_/utf8, _/binary>> = Bin1,
test_writable_bin(Bin1, N+1).
+
+%%-------------------------------------------------------------------
+%% Test matching with a huge bin -- taken from bs_match_bin_SUITE
+
+test_match_huge_bin() ->
+ Bin = <<0:(1 bsl 27),13:8>>,
+ skip_huge_bin_1(1 bsl 27, Bin),
+ 16777216 = match_huge_bin_1(1 bsl 27, Bin),
+ %% Test overflowing the size of a binary field.
+ nomatch = overflow_huge_bin_skip_32(Bin),
+ nomatch = overflow_huge_bin_32(Bin),
+ nomatch = overflow_huge_bin_skip_64(Bin),
+ nomatch = overflow_huge_bin_64(Bin),
+ %% Size in variable
+ ok = overflow_huge_bin(Bin, lists:seq(25, 32)++lists:seq(50, 64)),
+ ok = overflow_huge_bin_unit128(Bin, lists:seq(25, 32)++lists:seq(50, 64)),
+ ok.
+
+overflow_huge_bin(Bin, [Sz0|Sizes]) ->
+ Sz = id(1 bsl Sz0),
+ case Bin of
+ <<_:Sz/binary-unit:8,0,_/binary>> ->
+ {error,Sz};
+ _ ->
+ case Bin of
+ <<NewBin:Sz/binary-unit:8,0,_/binary>> ->
+ {error,Sz,size(NewBin)};
+ _ ->
+ overflow_huge_bin(Bin, Sizes)
+ end
+ end;
+overflow_huge_bin(_, []) -> ok.
+
+overflow_huge_bin_unit128(Bin, [Sz0|Sizes]) ->
+ Sz = id(1 bsl Sz0),
+ case Bin of
+ <<_:Sz/binary-unit:128,0,_/binary>> ->
+ {error,Sz};
+ _ ->
+ case Bin of
+ <<NewBin:Sz/binary-unit:128,0,_/binary>> ->
+ {error,Sz,size(NewBin)};
+ _ ->
+ overflow_huge_bin_unit128(Bin, Sizes)
+ end
+ end;
+overflow_huge_bin_unit128(_, []) -> ok.
+
+skip_huge_bin_1(I, Bin) ->
+ <<_:I/binary-unit:1,13>> = Bin,
+ ok.
+
+match_huge_bin_1(I, Bin) ->
+ case Bin of
+ <<Val:I/binary-unit:1,13>> -> size(Val);
+ _ -> nomatch
+ end.
+
+overflow_huge_bin_skip_32(<<_:4294967296/binary,0,_/binary>>) -> 1; % 1 bsl 32
+overflow_huge_bin_skip_32(<<_:33554432/binary-unit:128,0,_/binary>>) -> 2; % 1 bsl 25
+overflow_huge_bin_skip_32(<<_:67108864/binary-unit:64,0,_/binary>>) -> 3; % 1 bsl 26
+overflow_huge_bin_skip_32(<<_:134217728/binary-unit:32,0,_/binary>>) -> 4; % 1 bsl 27
+overflow_huge_bin_skip_32(<<_:268435456/binary-unit:16,0,_/binary>>) -> 5; % 1 bsl 28
+overflow_huge_bin_skip_32(<<_:536870912/binary-unit:8,0,_/binary>>) -> 6; % 1 bsl 29
+overflow_huge_bin_skip_32(<<_:1073741824/binary-unit:8,0,_/binary>>) -> 7; % 1 bsl 30
+overflow_huge_bin_skip_32(<<_:2147483648/binary-unit:8,0,_/binary>>) -> 8; % 1 bsl 31
+overflow_huge_bin_skip_32(_) -> nomatch.
+
+overflow_huge_bin_32(<<Bin:4294967296/binary,_/binary>>) -> {1,Bin}; % 1 bsl 32
+overflow_huge_bin_32(<<Bin:33554432/binary-unit:128,0,_/binary>>) -> {2,Bin}; % 1 bsl 25
+overflow_huge_bin_32(<<Bin:67108864/binary-unit:128,0,_/binary>>) -> {3,Bin}; % 1 bsl 26
+overflow_huge_bin_32(<<Bin:134217728/binary-unit:128,0,_/binary>>) -> {4,Bin}; % 1 bsl 27
+overflow_huge_bin_32(<<Bin:268435456/binary-unit:128,0,_/binary>>) -> {5,Bin}; % 1 bsl 28
+overflow_huge_bin_32(<<Bin:536870912/binary-unit:128,0,_/binary>>) -> {6,Bin}; % 1 bsl 29
+overflow_huge_bin_32(<<Bin:1073741824/binary-unit:128,0,_/binary>>) -> {7,Bin}; % 1 bsl 30
+overflow_huge_bin_32(<<Bin:2147483648/binary-unit:128,0,_/binary>>) -> {8,Bin}; % 1 bsl 31
+overflow_huge_bin_32(_) -> nomatch.
+
+overflow_huge_bin_skip_64(<<_:18446744073709551616/binary,0,_/binary>>) -> 1; % 1 bsl 64
+overflow_huge_bin_skip_64(<<_:144115188075855872/binary-unit:128,0,_/binary>>) -> 2; % 1 bsl 57
+overflow_huge_bin_skip_64(<<_:288230376151711744/binary-unit:64,0,_/binary>>) -> 3; % 1 bsl 58
+overflow_huge_bin_skip_64(<<_:576460752303423488/binary-unit:32,0,_/binary>>) -> 4; % 1 bsl 59
+overflow_huge_bin_skip_64(<<_:1152921504606846976/binary-unit:16,0,_/binary>>) -> 5; % 1 bsl 60
+overflow_huge_bin_skip_64(<<_:2305843009213693952/binary-unit:8,0,_/binary>>) -> 6; % 1 bsl 61
+overflow_huge_bin_skip_64(<<_:4611686018427387904/binary-unit:8,0,_/binary>>) -> 7; % 1 bsl 62
+overflow_huge_bin_skip_64(<<_:9223372036854775808/binary-unit:8,_/binary>>) -> 8; % 1 bsl 63
+overflow_huge_bin_skip_64(_) -> nomatch.
+
+overflow_huge_bin_64(<<Bin:18446744073709551616/binary,_/binary>>) -> {1,Bin}; % 1 bsl 64
+overflow_huge_bin_64(<<Bin:144115188075855872/binary-unit:128,0,_/binary>>) -> {2,Bin}; % 1 bsl 57
+overflow_huge_bin_64(<<Bin:288230376151711744/binary-unit:128,0,_/binary>>) -> {3,Bin}; % 1 bsl 58
+overflow_huge_bin_64(<<Bin:576460752303423488/binary-unit:128,0,_/binary>>) -> {4,Bin}; % 1 bsl 59
+overflow_huge_bin_64(<<Bin:1152921504606846976/binary-unit:128,0,_/binary>>) -> {5,Bin}; % 1 bsl 60
+overflow_huge_bin_64(<<Bin:2305843009213693952/binary-unit:128,0,_/binary>>) -> {6,Bin}; % 1 bsl 61
+overflow_huge_bin_64(<<Bin:4611686018427387904/binary-unit:128,0,_/binary>>) -> {7,Bin}; % 1 bsl 62
+overflow_huge_bin_64(<<Bin:9223372036854775808/binary-unit:128,0,_/binary>>) -> {8,Bin}; % 1 bsl 63
+overflow_huge_bin_64(_) -> nomatch.
+
+id(I) -> I.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_split.erl b/lib/hipe/test/bs_SUITE_data/bs_split.erl
index 2e52308a77..617543f789 100644
--- a/lib/hipe/test/bs_SUITE_data/bs_split.erl
+++ b/lib/hipe/test/bs_SUITE_data/bs_split.erl
@@ -26,13 +26,13 @@ bs1(L, B, Pos, Sz1, Sz2) ->
<<B1:Sz1/binary, B2:Sz2/binary>> = B,
bs2(L, B, Pos, B1, B2).
-bs2(L, B, Pos, B1, B2)->
+bs2(L, B, Pos, B1, B2) ->
B1 = list_to_binary(lists:sublist(L, 1, Pos)),
bs3(L, B, Pos, B2).
bs3(L, B, Pos, B2) ->
B2 = list_to_binary(lists:nthtail(Pos, L)),
- byte_split(L, B, Pos-1).
+ byte_split(L, B, Pos - 1).
%%--------------------------------------------------------------------
@@ -56,14 +56,14 @@ bit_split_binary2(_Action, _Bin, [], _Bef) -> ok.
bit_split_binary3(Action, Bin, List, Bef, Aft) when Bef =< Aft ->
Action(Bin, List, Bef, (Aft-Bef) div 8 * 8),
- bit_split_binary3(Action, Bin, List, Bef, Aft-8);
+ bit_split_binary3(Action, Bin, List, Bef, Aft - 8);
bit_split_binary3(_, _, _, _, _) -> ok.
make_bin_from_list(_List, 0) ->
mkbin([]);
make_bin_from_list(List, N) ->
list_to_binary([make_int(List, 8, 0),
- make_bin_from_list(lists:nthtail(8, List), N-8)]).
+ make_bin_from_list(lists:nthtail(8, List), N - 8)]).
make_int(_List, 0, Acc) -> Acc;
make_int([H|T], N, Acc) -> make_int(T, N-1, Acc bsl 1 bor H).
@@ -101,5 +101,5 @@ z_split(B, N) ->
<<_:N/binary>> ->
[B];
_ ->
- z_split(B, N+1)
+ z_split(B, N + 1)
end.
diff --git a/lib/hipe/test/bs_SUITE_data/bs_utf.erl b/lib/hipe/test/bs_SUITE_data/bs_utf.erl
index f50ae08964..24526f574d 100644
--- a/lib/hipe/test/bs_SUITE_data/bs_utf.erl
+++ b/lib/hipe/test/bs_SUITE_data/bs_utf.erl
@@ -1,18 +1,356 @@
%% -*- erlang-indent-level: 2 -*-
%%-------------------------------------------------------------------
-%% Purpose: test support for UTF datatypes in binaries - INCOMPLETE
+%% Purpose: test support for UTF datatypes in binaries
+%%
+%% Most of it taken from emulator/test/bs_utf_SUITE.erl
%%-------------------------------------------------------------------
-module(bs_utf).
-export([test/0]).
+-include_lib("test_server/include/test_server.hrl").
+
test() ->
+ ok = utf8_cm65(),
+ ok = utf8_roundtrip(),
+ ok = utf16_roundtrip(),
+ ok = utf32_roundtrip(),
+ %% The following were problematic for the LLVM backend
+ ok = utf8_illegal_sequences(),
+ ok = utf16_illegal_sequences(),
+ ok = utf32_illegal_sequences(),
+ ok.
+
+%%-------------------------------------------------------------------
+%% A test with construction and matching
+
+utf8_cm65() ->
<<65>> = b65utf8(),
ok = m(<<65>>).
+b65utf8() ->
+ <<65/utf8>>.
+
m(<<65/utf8>>) ->
ok.
-b65utf8() ->
- <<65/utf8>>.
+%%-------------------------------------------------------------------
+
+utf8_roundtrip() ->
+ ok = utf8_roundtrip(0, 16#D7FF),
+ ok = utf8_roundtrip(16#E000, 16#10FFFF),
+ ok.
+
+utf8_roundtrip(First, Last) when First =< Last ->
+ Bin = int_to_utf8(First),
+ Bin = id(<<First/utf8>>),
+ Bin = id(<<(id(<<>>))/binary,First/utf8>>),
+ Unaligned = id(<<3:2,First/utf8>>),
+ <<_:2,Bin/binary>> = Unaligned,
+ <<First/utf8>> = Bin,
+ <<First/utf8>> = make_unaligned(Bin),
+ utf8_roundtrip(First+1, Last);
+utf8_roundtrip(_, _) ->
+ ok.
+
+%%-------------------------------------------------------------------
+
+utf16_roundtrip() ->
+ Big = fun utf16_big_roundtrip/1,
+ Little = fun utf16_little_roundtrip/1,
+ PidRefs = [spawn_monitor(fun() -> do_utf16_roundtrip(Fun) end) ||
+ Fun <- [Big,Little]],
+ [receive {'DOWN', Ref, process, Pid, Reason} -> normal=Reason end ||
+ {Pid, Ref} <- PidRefs],
+ ok.
+
+do_utf16_roundtrip(Fun) ->
+ do_utf16_roundtrip(0, 16#D7FF, Fun),
+ do_utf16_roundtrip(16#E000, 16#10FFFF, Fun).
+
+do_utf16_roundtrip(First, Last, Fun) when First =< Last ->
+ Fun(First),
+ do_utf16_roundtrip(First+1, Last, Fun);
+do_utf16_roundtrip(_, _, _) -> ok.
+
+utf16_big_roundtrip(Char) ->
+ Bin = id(<<Char/utf16>>),
+ Bin = id(<<(id(<<>>))/binary,Char/utf16>>),
+ Unaligned = id(<<3:2,Char/utf16>>),
+ <<_:2,Bin/binary>> = Unaligned,
+ <<Char/utf16>> = Bin,
+ <<Char/utf16>> = make_unaligned(Bin),
+ ok.
+
+utf16_little_roundtrip(Char) ->
+ Bin = id(<<Char/little-utf16>>),
+ Bin = id(<<(id(<<>>))/binary,Char/little-utf16>>),
+ Unaligned = id(<<3:2,Char/little-utf16>>),
+ <<_:2,Bin/binary>> = Unaligned,
+ <<Char/little-utf16>> = Bin,
+ <<Char/little-utf16>> = make_unaligned(Bin),
+ ok.
+
+%%-------------------------------------------------------------------
+
+utf32_roundtrip() ->
+ Big = fun utf32_big_roundtrip/1,
+ Little = fun utf32_little_roundtrip/1,
+ PidRefs = [spawn_monitor(fun() -> do_utf32_roundtrip(Fun) end) ||
+ Fun <- [Big,Little]],
+ [receive {'DOWN', Ref, process, Pid, Reason} -> normal=Reason end ||
+ {Pid, Ref} <- PidRefs],
+ ok.
+
+do_utf32_roundtrip(Fun) ->
+ do_utf32_roundtrip(0, 16#D7FF, Fun),
+ do_utf32_roundtrip(16#E000, 16#10FFFF, Fun).
+
+do_utf32_roundtrip(First, Last, Fun) when First =< Last ->
+ Fun(First),
+ do_utf32_roundtrip(First+1, Last, Fun);
+do_utf32_roundtrip(_, _, _) -> ok.
+
+utf32_big_roundtrip(Char) ->
+ Bin = id(<<Char/utf32>>),
+ Bin = id(<<(id(<<>>))/binary,Char/utf32>>),
+ Unaligned = id(<<3:2,Char/utf32>>),
+ <<_:2,Bin/binary>> = Unaligned,
+ <<Char/utf32>> = Bin,
+ <<Char/utf32>> = make_unaligned(Bin),
+ ok.
+
+utf32_little_roundtrip(Char) ->
+ Bin = id(<<Char/little-utf32>>),
+ Bin = id(<<(id(<<>>))/binary,Char/little-utf32>>),
+ Unaligned = id(<<3:2,Char/little-utf32>>),
+ <<_:2,Bin/binary>> = Unaligned,
+ <<Char/little-utf32>> = Bin,
+ <<Char/little-utf32>> = make_unaligned(Bin),
+ ok.
+
+%%-------------------------------------------------------------------
+
+utf8_illegal_sequences() ->
+ fail_range(16#10FFFF+1, 16#10FFFF+512), % Too large.
+ fail_range(16#D800, 16#DFFF), % Reserved for UTF-16.
+
+ %% Illegal first character.
+ [fail(<<I,16#8F,16#8F,16#8F>>) || I <- lists:seq(16#80, 16#BF)],
+
+ %% Short sequences.
+ short_sequences(16#80, 16#10FFFF),
+
+ %% Overlong sequences. (Using more bytes than necessary
+ %% is not allowed.)
+ overlong(0, 127, 2),
+ overlong(128, 16#7FF, 3),
+ overlong(16#800, 16#FFFF, 4),
+ ok.
+
+fail_range(Char, End) when Char =< End ->
+ {'EXIT', _} = (catch <<Char/utf8>>),
+ Bin = int_to_utf8(Char),
+ fail(Bin),
+ fail_range(Char+1, End);
+fail_range(_, _) -> ok.
+
+short_sequences(Char, End) ->
+ Step = (End - Char) div erlang:system_info(schedulers) + 1,
+ PidRefs = short_sequences_1(Char, Step, End),
+ [receive {'DOWN', Ref, process, Pid, Reason} -> normal=Reason end ||
+ {Pid, Ref} <- PidRefs],
+ ok.
+
+short_sequences_1(Char, Step, End) when Char =< End ->
+ CharEnd = lists:min([Char+Step-1,End]),
+ [spawn_monitor(fun() ->
+ %% io:format("~p - ~p\n", [Char, CharEnd]),
+ do_short_sequences(Char, CharEnd)
+ end)|short_sequences_1(Char+Step, Step, End)];
+short_sequences_1(_, _, _) -> [].
+
+do_short_sequences(Char, End) when Char =< End ->
+ short_sequence(Char),
+ do_short_sequences(Char+1, End);
+do_short_sequences(_, _) -> ok.
+
+short_sequence(I) ->
+ case int_to_utf8(I) of
+ <<S0:3/binary,_:8>> ->
+ <<S1:2/binary,R1:8>> = S0,
+ <<S2:1/binary,_:8>> = S1,
+ fail(S0),
+ fail(S1),
+ fail(S2),
+ fail(<<S2/binary,16#7F,R1,R1>>),
+ fail(<<S1/binary,16#7F,R1>>),
+ fail(<<S0/binary,16#7F>>);
+ <<S0:2/binary,_:8>> ->
+ <<S1:1/binary,R1:8>> = S0,
+ fail(S0),
+ fail(S1),
+ fail(<<S0/binary,16#7F>>),
+ fail(<<S1/binary,16#7F>>),
+ fail(<<S1/binary,16#7F,R1>>);
+ <<S:1/binary,_:8>> ->
+ fail(S),
+ fail(<<S/binary,16#7F>>)
+ end.
+
+overlong(Char, Last, NumBytes) when Char =< Last ->
+ overlong(Char, NumBytes),
+ overlong(Char+1, Last, NumBytes);
+overlong(_, _, _) -> ok.
+
+overlong(Char, NumBytes) when NumBytes < 5 ->
+ case int_to_utf8(Char, NumBytes) of
+ <<Char/utf8>>=Bin ->
+ ?t:fail({illegal_encoding_accepted,Bin,Char});
+ <<OtherChar/utf8>>=Bin ->
+ ?t:fail({illegal_encoding_accepted,Bin,Char,OtherChar});
+ _ -> ok
+ end,
+ overlong(Char, NumBytes+1);
+overlong(_, _) -> ok.
+
+fail(Bin) ->
+ fail_1(Bin),
+ fail_1(make_unaligned(Bin)).
+
+fail_1(<<Char/utf8>> = Bin) ->
+ ?t:fail({illegal_encoding_accepted, Bin, Char});
+fail_1(_) -> ok.
+
+%%-------------------------------------------------------------------
+
+utf16_illegal_sequences() ->
+ utf16_fail_range(16#10FFFF+1, 16#10FFFF+512), % Too large.
+ utf16_fail_range(16#D800, 16#DFFF), % Reserved for UTF-16.
+ lonely_hi_surrogate(16#D800, 16#DFFF),
+ leading_lo_surrogate(16#DC00, 16#DFFF),
+ ok.
+
+utf16_fail_range(Char, End) when Char =< End ->
+ {'EXIT', _} = (catch <<Char/big-utf16>>),
+ {'EXIT', _} = (catch <<Char/little-utf16>>),
+ utf16_fail_range(Char+1, End);
+utf16_fail_range(_, _) -> ok.
+
+lonely_hi_surrogate(Char, End) when Char =< End ->
+ BinBig = <<Char:16/big>>,
+ BinLittle = <<Char:16/little>>,
+ case {BinBig,BinLittle} of
+ {<<Bad/big-utf16>>,_} ->
+ ?t:fail({lonely_hi_surrogate_accepted,Bad});
+ {_,<<Bad/little-utf16>>} ->
+ ?t:fail({lonely_hi_surrogate_accepted,Bad});
+ {_,_} ->
+ ok
+ end,
+ lonely_hi_surrogate(Char+1, End);
+lonely_hi_surrogate(_, _) -> ok.
+
+leading_lo_surrogate(Char, End) when Char =< End ->
+ leading_lo_surrogate(Char, 16#D800, 16#DFFF),
+ leading_lo_surrogate(Char+1, End);
+leading_lo_surrogate(_, _) -> ok.
+
+leading_lo_surrogate(HiSurr, LoSurr, End) when LoSurr =< End ->
+ BinBig = <<HiSurr:16/big,LoSurr:16/big>>,
+ BinLittle = <<HiSurr:16/little,LoSurr:16/little>>,
+ case {BinBig,BinLittle} of
+ {<<Bad/big-utf16,_/bits>>,_} ->
+ ?t:fail({leading_lo_surrogate_accepted,Bad});
+ {_,<<Bad/little-utf16,_/bits>>} ->
+ ?t:fail({leading_lo_surrogate_accepted,Bad});
+ {_,_} ->
+ ok
+ end,
+ leading_lo_surrogate(HiSurr, LoSurr+1, End);
+leading_lo_surrogate(_, _, _) -> ok.
+
+%%-------------------------------------------------------------------
+
+utf32_illegal_sequences() ->
+ utf32_fail_range(16#10FFFF+1, 16#10FFFF+512), % Too large.
+ utf32_fail_range(16#D800, 16#DFFF), % Reserved for UTF-16.
+ utf32_fail_range(-100, -1),
+ ok.
+
+utf32_fail_range(Char, End) when Char =< End ->
+ {'EXIT', _} = (catch <<Char/big-utf32>>),
+ {'EXIT', _} = (catch <<Char/little-utf32>>),
+ case {<<Char:32>>,<<Char:32/little>>} of
+ {<<Unexpected/utf32>>,_} ->
+ ?t:fail(Unexpected);
+ {_,<<Unexpected/little-utf32>>} ->
+ ?t:fail(Unexpected);
+ {_,_} -> ok
+ end,
+ utf32_fail_range(Char+1, End);
+utf32_fail_range(_, _) -> ok.
+
+%%-------------------------------------------------------------------
+%% This function intentionally allows construction of UTF-8 sequence
+%% in illegal ranges.
+
+int_to_utf8(I) when I =< 16#7F ->
+ <<I>>;
+int_to_utf8(I) when I =< 16#7FF ->
+ B2 = I,
+ B1 = (I bsr 6),
+ <<1:1,1:1,0:1,B1:5,1:1,0:1,B2:6>>;
+int_to_utf8(I) when I =< 16#FFFF ->
+ B3 = I,
+ B2 = (I bsr 6),
+ B1 = (I bsr 12),
+ <<1:1,1:1,1:1,0:1,B1:4,1:1,0:1,B2:6,1:1,0:1,B3:6>>;
+int_to_utf8(I) when I =< 16#3FFFFF ->
+ B4 = I,
+ B3 = (I bsr 6),
+ B2 = (I bsr 12),
+ B1 = (I bsr 18),
+ <<1:1,1:1,1:1,1:1,0:1,B1:3,1:1,0:1,B2:6,1:1,0:1,B3:6,1:1,0:1,B4:6>>;
+int_to_utf8(I) when I =< 16#3FFFFFF ->
+ B5 = I,
+ B4 = (I bsr 6),
+ B3 = (I bsr 12),
+ B2 = (I bsr 18),
+ B1 = (I bsr 24),
+ <<1:1,1:1,1:1,1:1,1:1,0:1,B1:2,1:1,0:1,B2:6,1:1,0:1,B3:6,1:1,0:1,B4:6,
+ 1:1,0:1,B5:6>>.
+
+%% int_to_utf8(I, NumberOfBytes) -> Binary.
+%% This function can be used to construct overlong sequences.
+int_to_utf8(I, 1) ->
+ <<I>>;
+int_to_utf8(I, 2) ->
+ B2 = I,
+ B1 = (I bsr 6),
+ <<1:1,1:1,0:1,B1:5,1:1,0:1,B2:6>>;
+int_to_utf8(I, 3) ->
+ B3 = I,
+ B2 = (I bsr 6),
+ B1 = (I bsr 12),
+ <<1:1,1:1,1:1,0:1,B1:4,1:1,0:1,B2:6,1:1,0:1,B3:6>>;
+int_to_utf8(I, 4) ->
+ B4 = I,
+ B3 = (I bsr 6),
+ B2 = (I bsr 12),
+ B1 = (I bsr 18),
+ <<1:1,1:1,1:1,1:1,0:1,B1:3,1:1,0:1,B2:6,1:1,0:1,B3:6,1:1,0:1,B4:6>>.
+
+%%-------------------------------------------------------------------
+
+make_unaligned(Bin0) when is_binary(Bin0) ->
+ Bin1 = <<0:3,Bin0/binary,31:5>>,
+ Sz = byte_size(Bin0),
+ <<0:3,Bin:Sz/binary,31:5>> = id(Bin1),
+ Bin.
+
+%%-------------------------------------------------------------------
+%% Just to prevent compiler optimizations
+
+id(X) -> X.
diff --git a/lib/hipe/test/hipe_testsuite_driver.erl b/lib/hipe/test/hipe_testsuite_driver.erl
index 5f05a716bc..9f5d7421b4 100644
--- a/lib/hipe/test/hipe_testsuite_driver.erl
+++ b/lib/hipe/test/hipe_testsuite_driver.erl
@@ -176,7 +176,8 @@ run(TestCase, Dir, _OutDir) ->
HiPEOpts = try TestCase:hipe_options() catch error:undef -> [] end,
{ok, TestCase} = hipe:c(TestCase, HiPEOpts),
ok = TestCase:test(),
- case is_llvm_opt_available() of
+ ToLLVM = try TestCase:to_llvm() catch error:undef -> true end,
+ case ToLLVM andalso hipe:llvm_support_available() of
true ->
{ok, TestCase} = hipe:c(TestCase, [to_llvm|HiPEOpts]),
ok = TestCase:test();
@@ -186,16 +187,3 @@ run(TestCase, Dir, _OutDir) ->
%% lists:foreach(fun (DF) -> ok end, % = file:delete(DF) end,
%% [filename:join(OutDir, D) || D <- DataFiles])
%% end.
-
-
-%% This function, which is supposed to check whether the right LLVM
-%% infrastructure is available, should be probably written in a better
-%% and more portable way and moved to the hipe application.
-
-is_llvm_opt_available() ->
- OptStr = os:cmd("opt -version"),
- SubStr = "LLVM version ", N = length(SubStr),
- case string:str(OptStr, SubStr) of
- 0 -> false;
- S -> P = S + N, string:sub_string(OptStr, P, P + 2) >= "3.4"
- end.
diff --git a/lib/hipe/test/sanity_SUITE_data/sanity_comp_timeout.erl b/lib/hipe/test/sanity_SUITE_data/sanity_comp_timeout.erl
new file mode 100644
index 0000000000..9f0830574f
--- /dev/null
+++ b/lib/hipe/test/sanity_SUITE_data/sanity_comp_timeout.erl
@@ -0,0 +1,28 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%----------------------------------------------------------------------
+%%% Author: Kostis Sagonas
+%%%
+%%% Tests that when the native code compilation times out or gets killed
+%%% for some other reason, the parent process does not also get killed.
+%%%
+%%% Problem discovered by Bjorn G. on 1/12/2003 and fixed by Kostis.
+%%%----------------------------------------------------------------------
+
+-module(sanity_comp_timeout).
+
+-export([test/0, to_llvm/0]).
+
+test() ->
+ ok = write_dummy_mod(),
+ error_logger:tty(false), % disable printouts of error reports
+ Self = self(), % get the parent process
+ c:c(dummy_mod, [native, {hipe, [{timeout, 1}]}]), % This will kill the process
+ Self = self(), % make sure the parent process stays the same
+ ok.
+
+to_llvm() -> false.
+
+write_dummy_mod() ->
+ Prog = <<"-module(dummy_mod).\n-export([test/0]).\ntest() -> ok.\n">>,
+ ok = file:write_file("dummy_mod.erl", Prog).
+
diff --git a/lib/hipe/test/sanity_SUITE_data/sanity_no_zombies.erl b/lib/hipe/test/sanity_SUITE_data/sanity_no_zombies.erl
new file mode 100644
index 0000000000..87e746042e
--- /dev/null
+++ b/lib/hipe/test/sanity_SUITE_data/sanity_no_zombies.erl
@@ -0,0 +1,21 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%----------------------------------------------------------------------
+%%% Author: Per Gustafsson
+%%%
+%%% Checks that HiPE's concurrent compilation does not leave any zombie
+%%% processes around after compilation has finished.
+%%%
+%%% This was a bug reported on erlang-bugs (Oct 25, 2007).
+%%%----------------------------------------------------------------------
+
+-module(sanity_no_zombies).
+
+-export([test/0, to_llvm/0]).
+
+test() ->
+ L = length(processes()),
+ hipe:c(?MODULE, [concurrent_comp]), % force concurrent compilation
+ L = length(processes()),
+ ok.
+
+to_llvm() -> false.
diff --git a/lib/hipe/vsn.mk b/lib/hipe/vsn.mk
index e507ae933f..123792e708 100644
--- a/lib/hipe/vsn.mk
+++ b/lib/hipe/vsn.mk
@@ -1 +1 @@
-HIPE_VSN = 3.12
+HIPE_VSN = 3.14
diff --git a/lib/hipe/x86/hipe_x86_assemble.erl b/lib/hipe/x86/hipe_x86_assemble.erl
index 4ffa3d35ba..695ce16887 100644
--- a/lib/hipe/x86/hipe_x86_assemble.erl
+++ b/lib/hipe/x86/hipe_x86_assemble.erl
@@ -83,7 +83,7 @@ assemble(CompiledCode, Closures, Exports, Options) ->
DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap),
SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap,Closures,Exports),
SlimRefs = hipe_pack_constants:slim_refs(AccRefs),
- Bin = term_to_binary([{?VERSION_STRING(),?HIPE_SYSTEM_CRC},
+ Bin = term_to_binary([{?VERSION_STRING(),?HIPE_ERTS_CHECKSUM},
ConstAlign, ConstSize,
SC,
DataRelocs, % nee LM, LabelMap