aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler/test
diff options
context:
space:
mode:
Diffstat (limited to 'lib/compiler/test')
-rw-r--r--lib/compiler/test/Makefile37
-rw-r--r--lib/compiler/test/andor_SUITE.erl2
-rw-r--r--lib/compiler/test/apply_SUITE.erl10
-rw-r--r--lib/compiler/test/beam_except_SUITE.erl38
-rw-r--r--lib/compiler/test/beam_jump_SUITE.erl142
-rw-r--r--lib/compiler/test/beam_reorder_SUITE.erl2
-rw-r--r--lib/compiler/test/beam_ssa_SUITE.erl213
-rw-r--r--lib/compiler/test/beam_type_SUITE.erl116
-rw-r--r--lib/compiler/test/beam_utils_SUITE.erl27
-rw-r--r--lib/compiler/test/beam_validator_SUITE.erl137
-rw-r--r--lib/compiler/test/beam_validator_SUITE_data/bad_bin_match.S2
-rw-r--r--lib/compiler/test/beam_validator_SUITE_data/merge_undefined.S4
-rw-r--r--lib/compiler/test/beam_validator_SUITE_data/receive_stacked.S10
-rw-r--r--lib/compiler/test/bif_SUITE.erl9
-rw-r--r--lib/compiler/test/bs_bincomp_SUITE.erl2
-rw-r--r--lib/compiler/test/bs_bit_binaries_SUITE.erl2
-rw-r--r--lib/compiler/test/bs_construct_SUITE.erl5
-rw-r--r--lib/compiler/test/bs_match_SUITE.erl216
-rw-r--r--lib/compiler/test/bs_utf_SUITE.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE.erl2
-rw-r--r--lib/compiler/test/compile_SUITE.erl311
-rw-r--r--lib/compiler/test/compiler.cover5
-rw-r--r--lib/compiler/test/core_alias_SUITE.erl2
-rw-r--r--lib/compiler/test/core_fold_SUITE.erl13
-rw-r--r--lib/compiler/test/error_SUITE.erl2
-rw-r--r--lib/compiler/test/float_SUITE.erl17
-rw-r--r--lib/compiler/test/fun_SUITE.erl7
-rw-r--r--lib/compiler/test/guard_SUITE.erl96
-rw-r--r--lib/compiler/test/guard_SUITE_data/guard_SUITE_tuple_size.S30
-rw-r--r--lib/compiler/test/inline_SUITE.erl32
-rw-r--r--lib/compiler/test/inline_SUITE_data/barnes2.erl2
-rw-r--r--lib/compiler/test/map_SUITE.erl95
-rw-r--r--lib/compiler/test/match_SUITE.erl183
-rw-r--r--lib/compiler/test/misc_SUITE.erl47
-rw-r--r--lib/compiler/test/overridden_bif_SUITE.erl2
-rw-r--r--lib/compiler/test/receive_SUITE.erl53
-rw-r--r--lib/compiler/test/record_SUITE.erl2
-rw-r--r--lib/compiler/test/regressions_SUITE.erl4
-rw-r--r--lib/compiler/test/test_lib.erl63
-rw-r--r--lib/compiler/test/trycatch_SUITE.erl26
-rw-r--r--lib/compiler/test/warnings_SUITE.erl86
41 files changed, 1554 insertions, 502 deletions
diff --git a/lib/compiler/test/Makefile b/lib/compiler/test/Makefile
index 2a5004aa4c..db8eb7e2e1 100644
--- a/lib/compiler/test/Makefile
+++ b/lib/compiler/test/Makefile
@@ -97,16 +97,30 @@ INLINE= \
receive \
record
+R21= \
+ bs_construct \
+ bs_match
+
CORE_MODULES = \
lfe_andor_SUITE \
lfe_guard_SUITE
+NO_MOD_OPT = $(NO_OPT)
+
+NO_SSA_OPT = $(NO_OPT)
+
NO_OPT_MODULES= $(NO_OPT:%=%_no_opt_SUITE)
NO_OPT_ERL_FILES= $(NO_OPT_MODULES:%=%.erl)
POST_OPT_MODULES= $(NO_OPT:%=%_post_opt_SUITE)
POST_OPT_ERL_FILES= $(POST_OPT_MODULES:%=%.erl)
INLINE_MODULES= $(INLINE:%=%_inline_SUITE)
INLINE_ERL_FILES= $(INLINE_MODULES:%=%.erl)
+R21_MODULES= $(R21:%=%_r21_SUITE)
+R21_ERL_FILES= $(R21_MODULES:%=%.erl)
+NO_MOD_OPT_MODULES= $(NO_MOD_OPT:%=%_no_module_opt_SUITE)
+NO_MOD_OPT_ERL_FILES= $(NO_MOD_OPT_MODULES:%=%.erl)
+NO_SSA_OPT_MODULES= $(NO_SSA_OPT:%=%_no_ssa_opt_SUITE)
+NO_SSA_OPT_ERL_FILES= $(NO_SSA_OPT_MODULES:%=%.erl)
ERL_FILES= $(MODULES:%=%.erl)
CORE_FILES= $(CORE_MODULES:%=%.core)
@@ -135,16 +149,24 @@ EBIN = .
# Targets
# ----------------------------------------------------
-make_emakefile: $(NO_OPT_ERL_FILES) $(POST_OPT_ERL_FILES) $(INLINE_ERL_FILES)
+make_emakefile: $(NO_OPT_ERL_FILES) $(POST_OPT_ERL_FILES) $(NO_SSA_OPT_ERL_FILES) \
+ $(INLINE_ERL_FILES) $(R21_ERL_FILES) $(NO_MOD_OPT_ERL_FILES)
$(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES) \
> $(EMAKEFILE)
$(ERL_TOP)/make/make_emakefile +no_copt +no_postopt \
+no_ssa_opt +no_recv_opt $(ERL_COMPILE_FLAGS) \
-o$(EBIN) $(NO_OPT_MODULES) >> $(EMAKEFILE)
+ $(ERL_TOP)/make/make_emakefile +no_share_opt +no_bsm_opt +no_fun_opt \
+ +no_ssa_opt +no_recv_opt $(ERL_COMPILE_FLAGS) \
+ -o$(EBIN) $(NO_SSA_OPT_MODULES) >> $(EMAKEFILE)
$(ERL_TOP)/make/make_emakefile +no_copt $(ERL_COMPILE_FLAGS) \
-o$(EBIN) $(POST_OPT_MODULES) >> $(EMAKEFILE)
$(ERL_TOP)/make/make_emakefile +inline $(ERL_COMPILE_FLAGS) \
-o$(EBIN) $(INLINE_MODULES) >> $(EMAKEFILE)
+ $(ERL_TOP)/make/make_emakefile +r21 $(ERL_COMPILE_FLAGS) \
+ -o$(EBIN) $(R21_MODULES) >> $(EMAKEFILE)
+ $(ERL_TOP)/make/make_emakefile +no_module_opt $(ERL_COMPILE_FLAGS) \
+ -o$(EBIN) $(NO_MOD_OPT_MODULES) >> $(EMAKEFILE)
$(ERL_TOP)/make/make_emakefile +from_core $(ERL_COMPILE_FLAGS) \
-o$(EBIN) $(CORE_MODULES) >> $(EMAKEFILE)
@@ -165,12 +187,21 @@ docs:
%_no_opt_SUITE.erl: %_SUITE.erl
sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@
+%_no_ssa_opt_SUITE.erl: %_SUITE.erl
+ sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@
+
%_post_opt_SUITE.erl: %_SUITE.erl
sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@
%_inline_SUITE.erl: %_SUITE.erl
sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@
+%_r21_SUITE.erl: %_SUITE.erl
+ sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@
+
+%_no_module_opt_SUITE.erl: %_SUITE.erl
+ sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@
+
# ----------------------------------------------------
# Release Target
# ----------------------------------------------------
@@ -183,7 +214,9 @@ release_tests_spec: make_emakefile
$(INSTALL_DATA) compiler.spec compiler.cover \
$(EMAKEFILE) $(ERL_FILES) "$(RELSYSDIR)"
$(INSTALL_DATA) $(NO_OPT_ERL_FILES) $(POST_OPT_ERL_FILES) \
- $(INLINE_ERL_FILES) "$(RELSYSDIR)"
+ $(INLINE_ERL_FILES) $(R21_ERL_FILES) \
+ $(NO_MOD_OPT_ERL_FILES) \
+ $(NO_SSA_OPT_ERL_FILES) "$(RELSYSDIR)"
$(INSTALL_DATA) $(CORE_FILES) "$(RELSYSDIR)"
for file in $(ERL_DUMMY_FILES); do \
module=`basename $$file .erl`; \
diff --git a/lib/compiler/test/andor_SUITE.erl b/lib/compiler/test/andor_SUITE.erl
index 721f77f0f6..5c463063c1 100644
--- a/lib/compiler/test/andor_SUITE.erl
+++ b/lib/compiler/test/andor_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/apply_SUITE.erl b/lib/compiler/test/apply_SUITE.erl
index be49cff9b9..2ee518b1a0 100644
--- a/lib/compiler/test/apply_SUITE.erl
+++ b/lib/compiler/test/apply_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. 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.
@@ -73,6 +73,7 @@ mfa(Config) when is_list(Config) ->
{'EXIT',_} = (catch ?APPLY2(Mod, (id(bazzzzzz)), a, b)),
{'EXIT',_} = (catch ?APPLY2({}, baz, a, b)),
{'EXIT',_} = (catch ?APPLY2(?MODULE, [], a, b)),
+ {'EXIT',_} = (catch bad_literal_call(1)),
ok = apply(Mod, foo, id([])),
{[a,b|c]} = apply(Mod, bar, id([[a,b|c]])),
@@ -92,6 +93,13 @@ mfa(Config) when is_list(Config) ->
apply(Mod, foo, []).
+%% The single call to this function with a literal argument caused type
+%% optimization to swap out the 'mod' field of a #b_remote{}, which was
+%% mishandled during code generation as it assumed that the module would always
+%% be an atom.
+bad_literal_call(I) ->
+ I:foo().
+
foo() ->
ok.
diff --git a/lib/compiler/test/beam_except_SUITE.erl b/lib/compiler/test/beam_except_SUITE.erl
index 1eb07c8c85..9380fe06c8 100644
--- a/lib/compiler/test/beam_except_SUITE.erl
+++ b/lib/compiler/test/beam_except_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. 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.
@@ -21,7 +21,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
- multiple_allocs/1,coverage/1]).
+ multiple_allocs/1,bs_get_tail/1,coverage/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -31,6 +31,7 @@ all() ->
groups() ->
[{p,[parallel],
[multiple_allocs,
+ bs_get_tail,
coverage]}].
init_per_suite(Config) ->
@@ -63,6 +64,17 @@ place(lee) ->
conditions() ->
(talking = going) = storage + [large = wanted].
+bs_get_tail(Config) ->
+ {<<"abc">>,0,0,Config} = bs_get_tail_1(id(<<0:32, "abc">>), 0, 0, Config),
+ {'EXIT',
+ {function_clause,
+ [{?MODULE,bs_get_tail_1,[<<>>,0,0,Config],_}|_]}} =
+ (catch bs_get_tail_1(id(<<>>), 0, 0, Config)),
+ ok.
+
+bs_get_tail_1(<<_:32, Rest/binary>>, Z1, Z2, F1) ->
+ {Rest,Z1,Z2,F1}.
+
coverage(_) ->
File = {file,"fake.erl"},
ok = fc(a),
@@ -83,8 +95,24 @@ coverage(_) ->
(catch bar(x)),
{'EXIT',{{case_clause,{1}},[{?MODULE,bar,1,[File,{line,9}]}|_]}} =
(catch bar(0)),
+
+ Self = self(),
+ {'EXIT',{{strange,Self},[{?MODULE,foo,[any],[File,{line,14}]}|_]}} =
+ (catch foo(any)),
+
+ {ok,succeed,1,2} = foobar(succeed, 1, 2),
+ {'EXIT',{function_clause,[{?MODULE,foobar,[[fail],1,2],
+ [{file,"fake.erl"},{line,16}]}|_]}} =
+ (catch foobar([fail], 1, 2)),
+ {'EXIT',{function_clause,[{?MODULE,fake_function_clause,[{a,b},42.0],_}|_]}} =
+ (catch fake_function_clause({a,b})),
+
ok.
+fake_function_clause(A) -> error(function_clause, [A,42.0]).
+
+id(I) -> I.
+
-file("fake.erl", 1).
fc(a) -> %Line 2
ok; %Line 3
@@ -96,3 +124,9 @@ bar(X) -> %Line 8
case {X+1} of %Line 9
1 -> ok %Line 10
end. %Line 11
+%% Cover collection code for function_clause exceptions.
+foo(A) -> %Line 13
+ error({strange,self()}, [A]). %Line 14
+%% Cover beam_except:tag_literal/1.
+foobar(A, B, C) when is_atom(A) -> %Line 16
+ {ok,A,B,C}. %Line 17
diff --git a/lib/compiler/test/beam_jump_SUITE.erl b/lib/compiler/test/beam_jump_SUITE.erl
index 488c30919b..a456f31d79 100644
--- a/lib/compiler/test/beam_jump_SUITE.erl
+++ b/lib/compiler/test/beam_jump_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2016. All Rights Reserved.
+%% Copyright Ericsson AB 2016-2018. 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.
@@ -21,7 +21,9 @@
-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
init_per_group/2,end_per_group/2,
- undefined_label/1,ambiguous_catch_try_state/1]).
+ undefined_label/1,ambiguous_catch_try_state/1,
+ unsafe_move_elimination/1,build_tuple/1,
+ coverage/1]).
suite() ->
[{ct_hooks,[ts_install_cth]}].
@@ -32,7 +34,10 @@ all() ->
groups() ->
[{p,[parallel],
[undefined_label,
- ambiguous_catch_try_state
+ ambiguous_catch_try_state,
+ unsafe_move_elimination,
+ build_tuple,
+ coverage
]}].
init_per_suite(Config) ->
@@ -72,3 +77,134 @@ river() -> song.
checks(Wanted) ->
%% Must be one line to cause the unsafe optimization.
{catch case river() of sheet -> begin +Wanted, if "da" -> Wanted end end end, catch case river() of sheet -> begin + Wanted, if "da" -> Wanted end end end}.
+
+unsafe_move_elimination(_Config) ->
+ {{left,right,false},false} = unsafe_move_elimination_1(left, right, false),
+ {{false,right,false},false} = unsafe_move_elimination_1(false, right, true),
+ {{true,right,right},right} = unsafe_move_elimination_1(true, right, true),
+ [ok = unsafe_move_elimination_2(I) || I <- lists:seq(0,16)],
+ ok.
+
+unsafe_move_elimination_1(Left, Right, Simple0) ->
+ id(1),
+
+ %% The move at label 29 would be removed by beam_jump, which is unsafe because
+ %% the two select_val instructions have different source registers.
+ %%
+ %% {select_val,{y,0},{f,25},{list,[{atom,true},{f,27},{atom,false},{f,29}]}}.
+ %% ^^^^^ ^^^^^^^^^^^^^^^^^^^
+ %% {label,27}.
+ %% {kill,{y,0}}.
+ %% {move,{y,2},{x,0}}.
+ %% {line,...}.
+ %% {call,1,{f,31}}.
+ %% {select_val,{x,0},{f,33},{list,[{atom,true},{f,35},{atom,false},{f,29}]}}.
+ %% ^^^^^ ^^^^^^^^^^^^^^^^^^^
+ %% {label,29}.
+ %% {move,{atom,false},{y,0}}. <=== REMOVED (unsafely).
+ %% {jump,{f,37}}.
+
+ Simple = case case Simple0 of
+ false -> false;
+ true -> id(Left)
+ end
+ of
+ false ->
+ false;
+ true ->
+ id(Right)
+ end,
+ {id({Left,Right,Simple}),Simple}.
+
+unsafe_move_elimination_2(Int) ->
+ %% The type optimization pass would recognize that TagInt can only be
+ %% [0 .. 7], so the first 'case' would select_val over [0 .. 6] and swap
+ %% out the fail label with the block for 7.
+ %%
+ %% A later optimization would merge this block with 'expects_h' in the
+ %% second case, as the latter is only reachable from the former.
+ %%
+ %% ... but this broke down when the move elimination optimization didn't
+ %% take the fail label of the first select_val into account. This caused it
+ %% to believe that the only way to reach 'expects_h' was through the second
+ %% case when 'Tag' =:= 'h', which made it remove the move instruction
+ %% added in the first case, passing garbage to expects_h/2.
+ TagInt = Int band 2#111,
+ Tag = case TagInt of
+ 0 -> a;
+ 1 -> b;
+ 2 -> c;
+ 3 -> d;
+ 4 -> e;
+ 5 -> f;
+ 6 -> g;
+ 7 -> h
+ end,
+ case Tag of
+ g -> expects_g(TagInt, Tag);
+ h -> expects_h(TagInt, Tag);
+ _ -> Tag = id(Tag), ok
+ end.
+
+expects_g(6, Atom) ->
+ Atom = id(g),
+ ok.
+
+expects_h(7, Atom) ->
+ Atom = id(h),
+ ok.
+
+-record(message2, {id, p1}).
+-record(message3, {id, p1, p2}).
+
+build_tuple(_Config) ->
+ {'EXIT',{{badrecord,message3},_}} = (catch do_build_tuple(#message2{})),
+ ok.
+
+do_build_tuple(Message) ->
+ if is_record(Message, message2) ->
+ Res = {res, rand:uniform(100)},
+ {Message#message3.id, Res}
+ end.
+
+coverage(_Config) ->
+ ok = coverage_1(ok),
+ {error,badarg} = coverage_1({error,badarg}),
+
+ gt = coverage_2(100, 42),
+ le = coverage_2(100, 999),
+ le = coverage_2([], []),
+ gt = coverage_2([], xxx),
+
+ ok.
+
+coverage_1(Var) ->
+ case id(Var) of
+ ok -> ok;
+ Error -> Error
+ end.
+
+%% Cover beam_jump:invert_test(is_ne_exact).
+coverage_2(Pre1, Pre2) ->
+ case
+ case Pre1 == [] of
+ false ->
+ false;
+ true ->
+ Pre2 /= []
+ end
+ of
+ true ->
+ gt;
+ false ->
+ case Pre1 > Pre2 of
+ true ->
+ gt;
+ false ->
+ le
+ end
+ end.
+
+
+id(I) ->
+ I.
diff --git a/lib/compiler/test/beam_reorder_SUITE.erl b/lib/compiler/test/beam_reorder_SUITE.erl
index 33b27b9f9f..c8a4f9a75f 100644
--- a/lib/compiler/test/beam_reorder_SUITE.erl
+++ b/lib/compiler/test/beam_reorder_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/beam_ssa_SUITE.erl b/lib/compiler/test/beam_ssa_SUITE.erl
index 0356c99c5a..15cf9bcbf3 100644
--- a/lib/compiler/test/beam_ssa_SUITE.erl
+++ b/lib/compiler/test/beam_ssa_SUITE.erl
@@ -21,7 +21,8 @@
-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
init_per_group/2,end_per_group/2,
- calls/1,tuple_matching/1,recv/1,maps/1]).
+ calls/1,tuple_matching/1,recv/1,maps/1,
+ cover_ssa_dead/1,combine_sw/1,share_opt/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -33,7 +34,10 @@ groups() ->
[tuple_matching,
calls,
recv,
- maps
+ maps,
+ cover_ssa_dead,
+ combine_sw,
+ share_opt
]}].
init_per_suite(Config) ->
@@ -88,7 +92,13 @@ start_it([_|_]=MFA) ->
end.
tuple_matching(_Config) ->
- do_tuple_matching({tag,42}).
+ do_tuple_matching({tag,42}),
+
+ true = is_two_tuple({a,b}),
+ false = is_two_tuple({a,b,c}),
+ false = is_two_tuple(atom),
+
+ ok.
do_tuple_matching(Arg) ->
Res = do_tuple_matching_1(Arg),
@@ -114,6 +124,12 @@ do_tuple_matching_3(Tuple) when is_tuple(Tuple) ->
{ok,element(2, Tuple)}
end.
+is_two_tuple(Arg) ->
+ case is_tuple(Arg) of
+ false -> false;
+ true -> tuple_size(Arg) == 2
+ end.
+
-record(reporter_state, {res,run_config}).
-record(run_config, {report_interval=0}).
@@ -286,5 +302,196 @@ maps_1(K) ->
#{K:=V} = #{},
V.
+-record(wx_ref, {type=any_type,ref=any_ref}).
+
+cover_ssa_dead(_Config) ->
+ str = format_str(str, escapable, [], true),
+ [iolist,str] = format_str(str, escapable, iolist, true),
+ bad = format_str(str, not_escapable, [], true),
+ bad = format_str(str, not_escapable, iolist, true),
+ bad = format_str(str, escapable, [], false),
+ bad = format_str(str, escapable, [], bad),
+
+ DefWxRef = #wx_ref{},
+ {DefWxRef,77,9999,[]} = contains(#wx_ref{}, 77, 9999),
+ {DefWxRef,77.0,9999,[]} = contains(#wx_ref{}, 77.0, 9999),
+ {DefWxRef,77,9999.0,[]} = contains(#wx_ref{}, 77, 9999.0),
+ {DefWxRef,77.0,9999.0,[]} = contains(#wx_ref{}, 77.0, 9999.0),
+ {any_type,any_ref,42,43,[option]} = contains(#wx_ref{}, {42,43}, [option]),
+ {any_type,any_ref,42,43,[]} = contains(#wx_ref{}, {42,43}, []),
+ {any_type,any_ref,42.0,43,[]} = contains(#wx_ref{}, {42.0,43}, []),
+ {any_type,any_ref,42,43.0,[]} = contains(#wx_ref{}, {42,43.0}, []),
+ {any_type,any_ref,42.0,43.0,[]} = contains(#wx_ref{}, {42.0,43.0}, []),
+
+ nope = conv_alub(false, '=:='),
+ ok = conv_alub(true, '=:='),
+ ok = conv_alub(true, none),
+ error = conv_alub(false, none),
+
+ {false,false} = eval_alu(false, false, false),
+ {true,false} = eval_alu(false, false, true),
+ {false,true} = eval_alu(false, true, false),
+ {false,false} = eval_alu(false, true, true),
+ {false,true} = eval_alu(true, false, false),
+ {false,false} = eval_alu(true, false, true),
+ {true,true} = eval_alu(true, true, false),
+ {false,true} = eval_alu(true, true, true),
+
+ 100.0 = percentage(1.0, 0.0),
+ 100.0 = percentage(1, 0),
+ 0.0 = percentage(0, 0),
+ 0.0 = percentage(0.0, 0.0),
+ 40.0 = percentage(4.0, 10.0),
+ 60.0 = percentage(6, 10),
+
+ %% Cover '=:=', followed by '=/='.
+ false = 'cover__=:=__=/='(41),
+ true = 'cover__=:=__=/='(42),
+ false = 'cover__=:=__=/='(43),
+
+ %% Cover '<', followed by '=/='.
+ true = 'cover__<__=/='(41),
+ false = 'cover__<__=/='(42),
+ false = 'cover__<__=/='(43),
+
+ %% Cover '=<', followed by '=/='.
+ true = 'cover__=<__=/='(41),
+ true = 'cover__=<__=/='(42),
+ false = 'cover__=<__=/='(43),
+
+ %% Cover '>=', followed by '=/='.
+ false = 'cover__>=__=/='(41),
+ true = 'cover__>=__=/='(42),
+ true = 'cover__>=__=/='(43),
+
+ %% Cover '>', followed by '=/='.
+ false = 'cover__>__=/='(41),
+ false = 'cover__>__=/='(42),
+ true = 'cover__>__=/='(43),
+
+ ok.
+
+'cover__=:=__=/='(X) when X =:= 42 -> X =/= 43;
+'cover__=:=__=/='(_) -> false.
+
+'cover__<__=/='(X) when X < 42 -> X =/= 42;
+'cover__<__=/='(_) -> false.
+
+'cover__=<__=/='(X) when X =< 42 -> X =/= 43;
+'cover__=<__=/='(_) -> false.
+
+'cover__>=__=/='(X) when X >= 42 -> X =/= 41;
+'cover__>=__=/='(_) -> false.
+
+'cover__>__=/='(X) when X > 42 -> X =/= 42;
+'cover__>__=/='(_) -> false.
+
+format_str(Str, FormatData, IoList, EscChars) ->
+ Escapable = FormatData =:= escapable,
+ case id(Str) of
+ IoStr when Escapable, EscChars, IoList == [] ->
+ id(IoStr);
+ IoStr when Escapable, EscChars ->
+ [IoList,id(IoStr)];
+ _ ->
+ bad
+ end.
+
+contains(This, X, Y) when is_record(This, wx_ref), is_number(X), is_number(Y) ->
+ {This,X,Y,[]};
+contains(#wx_ref{type=ThisT,ref=ThisRef}, {CX,CY}, Options)
+ when is_number(CX), is_number(CY), is_list(Options) ->
+ {ThisT,ThisRef,CX,CY,Options}.
+
+conv_alub(HasDst, CmpOp) ->
+ case (not HasDst) andalso CmpOp =/= none of
+ true -> nope;
+ false ->
+ case HasDst of
+ false -> error;
+ true -> ok
+ end
+ end.
+
+eval_alu(Sign1, Sign2, N) ->
+ V = (Sign1 andalso Sign2 andalso (not N))
+ or ((not Sign1) andalso (not Sign2) andalso N),
+ C = (Sign1 andalso Sign2)
+ or ((not N) andalso (Sign1 orelse Sign2)),
+ {V,C}.
+
+percentage(Divident, Divisor) ->
+ if Divisor == 0 andalso Divident /= 0 ->
+ 100.0;
+ Divisor == 0 ->
+ 0.0;
+ true ->
+ Divident / Divisor * 100
+ end.
+
+combine_sw(_Config) ->
+ [a] = do_comb_sw_1(a),
+ [b,b] = do_comb_sw_1(b),
+ [c] = do_comb_sw_1(c),
+ [c] = do_comb_sw_1(c),
+ [] = do_comb_sw_1(z),
+
+ [a] = do_comb_sw_2(a),
+ [b2,b1] = do_comb_sw_2(b),
+ [c] = do_comb_sw_2(c),
+ [c] = do_comb_sw_2(c),
+ [] = do_comb_sw_2(z),
+
+ ok.
+
+do_comb_sw_1(X) ->
+ put(?MODULE, []),
+ if
+ X == a; X == b ->
+ put(?MODULE, [X|get(?MODULE)]);
+ true ->
+ ok
+ end,
+ if
+ X == b; X == c ->
+ put(?MODULE, [X|get(?MODULE)]);
+ true ->
+ ok
+ end,
+ erase(?MODULE).
+
+do_comb_sw_2(X) ->
+ put(?MODULE, []),
+ case X of
+ a ->
+ put(?MODULE, [a|get(?MODULE)]);
+ b ->
+ put(?MODULE, [b1|get(?MODULE)]);
+ _ ->
+ ok
+ end,
+ case X of
+ b ->
+ put(?MODULE, [b2|get(?MODULE)]);
+ c ->
+ put(?MODULE, [c|get(?MODULE)]);
+ _ ->
+ ok
+ end,
+ erase(?MODULE).
+
+share_opt(_Config) ->
+ ok = do_share_opt(0).
+
+do_share_opt(A) ->
+ %% The compiler would be stuck in an infinite loop in beam_ssa_share.
+ case A of
+ 0 -> a;
+ 1 -> b;
+ 2 -> c
+ end,
+ receive after 1 -> ok end.
+
+
%% The identity function.
id(I) -> I.
diff --git a/lib/compiler/test/beam_type_SUITE.erl b/lib/compiler/test/beam_type_SUITE.erl
index caf43dad40..a7ffc3f60a 100644
--- a/lib/compiler/test/beam_type_SUITE.erl
+++ b/lib/compiler/test/beam_type_SUITE.erl
@@ -21,8 +21,8 @@
-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
init_per_group/2,end_per_group/2,
- integers/1,coverage/1,booleans/1,setelement/1,cons/1,
- tuple/1,record_float/1,binary_float/1,float_compare/1,
+ integers/1,numbers/1,coverage/1,booleans/1,setelement/1,
+ cons/1,tuple/1,record_float/1,binary_float/1,float_compare/1,
arity_checks/1,elixir_binaries/1,find_best/1,
test_size/1]).
@@ -34,6 +34,7 @@ all() ->
groups() ->
[{p,[parallel],
[integers,
+ numbers,
coverage,
booleans,
setelement,
@@ -115,8 +116,8 @@ do_integers_4(_, _, Res) ->
Res.
do_integers_5(X0, Y0) ->
- %% X and Y will use the same register.
- X = X0 band 1,
+ %% _X and Y will use the same register.
+ _X = X0 band 1,
Y = Y0 band 3,
case Y of
0 -> zero;
@@ -125,6 +126,59 @@ do_integers_5(X0, Y0) ->
3 -> three
end.
+numbers(_Config) ->
+ Int = id(42),
+ true = is_integer(Int),
+ true = is_number(Int),
+ false = is_float(Int),
+
+ Float = id(42.0),
+ true = is_float(Float),
+ true = is_number(Float),
+ false = is_integer(Float),
+
+ Number = id(1) + id(2),
+ true = is_number(Number),
+ true = is_integer(Number),
+ false = is_float(Number),
+
+ AnotherNumber = id(99.0) + id(1),
+ true = is_float(AnotherNumber),
+ true = is_number(AnotherNumber),
+ false = is_integer(AnotherNumber),
+
+ NotNumber = id(atom),
+ true = is_atom(NotNumber),
+ false = is_number(NotNumber),
+ false = is_integer(NotNumber),
+ false = is_float(NotNumber),
+
+ true = is_number(Int),
+ true = is_number(Float),
+ true = is_number(Number),
+ true = is_number(AnotherNumber),
+
+ %% Cover beam_ssa_type:join/2.
+
+ Join1 = case id(a) of
+ a -> 3 + id(7); %Number.
+ b -> id(5) / id(2) %Float.
+ end,
+ true = is_integer(Join1),
+
+ Join2 = case id(a) of
+ a -> id(5) / 2; %Float.
+ b -> 3 + id(7) %Number.
+ end,
+ true = is_float(Join2),
+
+ %% Cover beam_ssa_type:meet/2.
+
+ Meet1 = id(0) + -10.0, %Float.
+ 10.0 = abs(Meet1), %Number.
+
+ ok.
+
coverage(Config) ->
{'EXIT',{badarith,_}} = (catch id(1) bsl 0.5),
{'EXIT',{badarith,_}} = (catch id(2.0) bsl 2),
@@ -159,18 +213,59 @@ coverage(Config) ->
[_|_] ->
ok
end,
+
+ %% Cover beam_type:verified_type(none).
+ {'EXIT',{badarith,_}} = (catch (id(2) / id(1)) band 16#ff),
+
ok.
booleans(_Config) ->
- {'EXIT',{{case_clause,_},_}} = (catch do_booleans(42)),
+ {'EXIT',{{case_clause,_},_}} = (catch do_booleans_1(42)),
+
+ ok = do_booleans_2(42, 41),
+ error = do_booleans_2(42, 42),
+
+ AnyAtom = id(atom),
+ true = is_atom(AnyAtom),
+ false = is_boolean(AnyAtom),
+
+ MaybeBool = id(maybe),
+ case MaybeBool of
+ true -> ok;
+ maybe -> ok;
+ false -> ok
+ end,
+ false = is_boolean(MaybeBool),
+
+ NotBool = id(a),
+ case NotBool of
+ a -> ok;
+ b -> ok;
+ c -> ok
+ end,
+ false = is_boolean(NotBool),
+
ok.
-do_booleans(B) ->
+do_booleans_1(B) ->
case is_integer(B) of
yes -> yes;
no -> no
end.
+do_booleans_2(A, B) ->
+ Not = not do_booleans_cmp(A, B),
+ case Not of
+ true ->
+ case Not of
+ true -> error;
+ false -> ok
+ end;
+ false -> ok
+ end.
+
+do_booleans_cmp(A, B) -> A > B.
+
setelement(_Config) ->
T0 = id({a,42}),
{a,_} = T0,
@@ -223,8 +318,15 @@ cons_hdtl(B) ->
id(1),
{id(hd(Cons)),id(tl(Cons))}.
+-record(bird, {a=a,b=id(42)}).
+
tuple(_Config) ->
{'EXIT',{{badmatch,{necessary}},_}} = (catch do_tuple()),
+
+ [] = [X || X <- [], #bird{a = a} == {r,X,foo}],
+ [] = [X || X <- [], #bird{b = b} == {bird,X}],
+ [] = [X || X <- [], 3 == X#bird.a],
+
ok.
do_tuple() ->
@@ -361,7 +463,7 @@ find_best([], <<"a">>) ->
find_best([], nil) ->
{error,<<"should not get here">>}.
-test_size(Config) ->
+test_size(_Config) ->
2 = do_test_size({a,b}),
4 = do_test_size(<<42:32>>),
ok.
diff --git a/lib/compiler/test/beam_utils_SUITE.erl b/lib/compiler/test/beam_utils_SUITE.erl
index ac19305d69..eb0af59f9d 100644
--- a/lib/compiler/test/beam_utils_SUITE.erl
+++ b/lib/compiler/test/beam_utils_SUITE.erl
@@ -26,7 +26,7 @@
select/1,y_catch/1,otp_8949_b/1,liveopt/1,coverage/1,
y_registers/1,user_predef/1,scan_f/1,cafu/1,
receive_label/1,read_size_file_version/1,not_used/1,
- is_used_fr/1]).
+ is_used_fr/1,unsafe_is_function/1]).
-export([id/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -53,7 +53,8 @@ groups() ->
cafu,
read_size_file_version,
not_used,
- is_used_fr
+ is_used_fr,
+ unsafe_is_function
]}].
init_per_suite(Config) ->
@@ -196,7 +197,7 @@ do_bs_init_4(Arg1, Arg2) ->
id(Rewrite)
end/binary,
"/shared">>);
- Other ->
+ _Other ->
error
end.
@@ -552,7 +553,7 @@ not_used_p(_C, S, K, L) when is_record(K, k) ->
id(K)
end.
-is_used_fr(Config) ->
+is_used_fr(_Config) ->
1 = is_used_fr(self(), self()),
1 = is_used_fr(self(), other),
receive 1 -> ok end,
@@ -570,6 +571,24 @@ is_used_fr(X, Y) ->
end,
X ! 1.
+%% ERL-778.
+unsafe_is_function(_Config) ->
+ {undefined,any} = unsafe_is_function(undefined, any),
+ {ok,any} = unsafe_is_function(fun() -> ok end, any),
+ {'EXIT',{{case_clause,_},_}} = (catch unsafe_is_function(fun(_) -> ok end, any)),
+ ok.
+
+unsafe_is_function(F, M) ->
+ %% There would be an internal consistency failure:
+ %% Instruction: {bif,is_function,{f,0},[{x,0},{integer,0}],{x,2}}
+ %% Error: {uninitialized_reg,{y,0}}:
+
+ NewValue = case is_function(F, 0) of
+ true -> F();
+ false when F =:= undefined -> undefined
+ end,
+ {NewValue,M}.
+
%% The identity function.
id(I) -> I.
diff --git a/lib/compiler/test/beam_validator_SUITE.erl b/lib/compiler/test/beam_validator_SUITE.erl
index d3e544a9cc..8b39fce479 100644
--- a/lib/compiler/test/beam_validator_SUITE.erl
+++ b/lib/compiler/test/beam_validator_SUITE.erl
@@ -34,7 +34,7 @@
undef_label/1,illegal_instruction/1,failing_gc_guard_bif/1,
map_field_lists/1,cover_bin_opt/1,
val_dsetel/1,bad_tuples/1,bad_try_catch_nesting/1,
- receive_stacked/1]).
+ receive_stacked/1,aliased_types/1,type_conflict/1]).
-include_lib("common_test/include/ct.hrl").
@@ -63,7 +63,7 @@ groups() ->
undef_label,illegal_instruction,failing_gc_guard_bif,
map_field_lists,cover_bin_opt,val_dsetel,
bad_tuples,bad_try_catch_nesting,
- receive_stacked]}].
+ receive_stacked,aliased_types,type_conflict]}].
init_per_suite(Config) ->
test_lib:recompile(?MODULE),
@@ -107,13 +107,12 @@ xrange(Config) when is_list(Config) ->
Errors = do_val(xrange, Config),
[{{t,sum_1,2},
{{bif,'+',{f,0},[{x,-1},{x,1}],{x,0}},4,
- {uninitialized_reg,{x,-1}}}},
+ {bad_register,{x,-1}}}},
{{t,sum_2,2},
- {{bif,'+',{f,0},[{x,0},{x,1023}],{x,0}},4,
- {uninitialized_reg,{x,1023}}}},
+ {{bif,'+',{f,0},[{x,0},{x,1023}],{x,0}},4,limit}},
{{t,sum_3,2},
{{bif,'+',{f,0},[{x,0},{x,1}],{x,-1}},4,
- {invalid_store,{x,-1},number}}},
+ {bad_register,{x,-1}}}},
{{t,sum_4,2},
{{bif,'+',{f,0},[{x,0},{x,1}],{x,1023}},4,limit}}] = Errors,
ok.
@@ -122,15 +121,15 @@ yrange(Config) when is_list(Config) ->
Errors = do_val(yrange, Config),
[{{t,sum_1,2},
{{move,{x,1},{y,-1}},5,
- {invalid_store,{y,-1},term}}},
+ {bad_register,{y,-1}}}},
{{t,sum_2,2},
{{bif,'+',{f,0},[{x,0},{y,1024}],{x,0}},7,
- {uninitialized_reg,{y,1024}}}},
+ limit}},
{{t,sum_3,2},
{{move,{x,1},{y,1024}},5,limit}},
{{t,sum_4,2},
{{move,{x,1},{y,-1}},5,
- {invalid_store,{y,-1},term}}}] = Errors,
+ {bad_register,{y,-1}}}}] = Errors,
ok.
stack(Config) when is_list(Config) ->
@@ -157,9 +156,9 @@ call_last(Config) when is_list(Config) ->
merge_undefined(Config) when is_list(Config) ->
Errors = do_val(merge_undefined, Config),
[{{t,handle_call,2},
- {{call_ext,1,{extfunc,erlang,exit,1}},
- 10,
- {uninitialized_reg,{y,0}}}}] = Errors,
+ {{call_ext,2,{extfunc,debug,filter,2}},
+ 22,
+ {uninitialized_reg,{y,_}}}}] = Errors,
ok.
uninit(Config) when is_list(Config) ->
@@ -178,7 +177,7 @@ unsafe_catch(Config) when is_list(Config) ->
Errors = do_val(unsafe_catch, Config),
[{{t,small,2},
{{bs_put_integer,{f,0},{integer,16},1,
- {field_flags,[unsigned,big]},{y,0}},
+ {field_flags,[unsigned,big]},{y,0}},
20,
{unassigned,{y,0}}}}] = Errors,
ok.
@@ -211,19 +210,19 @@ bad_catch_try(Config) when is_list(Config) ->
Errors = do_val(bad_catch_try, Config),
[{{bad_catch_try,bad_1,1},
{{'catch',{x,0},{f,3}},
- 5,{invalid_store,{x,0},{catchtag,[3]}}}},
+ 5,{invalid_tag_register,{x,0}}}},
{{bad_catch_try,bad_2,1},
{{catch_end,{x,9}},
- 8,{source_not_y_reg,{x,9}}}},
+ 8,{invalid_tag_register,{x,9}}}},
{{bad_catch_try,bad_3,1},
- {{catch_end,{y,1}},9,{bad_type,{atom,kalle}}}},
+ {{catch_end,{y,1}},9,{invalid_tag,{y,1},{atom,kalle}}}},
{{bad_catch_try,bad_4,1},
- {{'try',{x,0},{f,15}},5,{invalid_store,{x,0},{trytag,[15]}}}},
+ {{'try',{x,0},{f,15}},5,{invalid_tag_register,{x,0}}}},
{{bad_catch_try,bad_5,1},
- {{try_case,{y,1}},12,{bad_type,term}}},
+ {{try_case,{y,1}},12,{invalid_tag,{y,1},term}}},
{{bad_catch_try,bad_6,1},
{{move,{integer,1},{y,1}},7,
- {invalid_store,{y,1},{integer,1}}}}] = Errors,
+ {invalid_store,{y,1}}}}] = Errors,
ok.
cons_guard(Config) when is_list(Config) ->
@@ -247,7 +246,7 @@ freg_range(Config) when is_list(Config) ->
{{t,sum_3,2},
{{bif,fadd,{f,0},[{fr,0},{fr,1}],{fr,-1}},
7,
- {bad_target,{fr,-1}}}},
+ {bad_register,{fr,-1}}}},
{{t,sum_4,2},
{{bif,fadd,{f,0},[{fr,0},{fr,1}],{fr,1024}},
7,
@@ -539,37 +538,37 @@ receive_stacked(Config) ->
[{{receive_stacked,f1,0},
{{loop_rec_end,{f,3}},
17,
- {fragile_message_reference,{y,0}}}},
+ {fragile_message_reference,{y,_}}}},
{{receive_stacked,f2,0},
- {{test_heap,3,0},10,{fragile_message_reference,{y,1}}}},
+ {{test_heap,3,0},10,{fragile_message_reference,{y,_}}}},
{{receive_stacked,f3,0},
- {{test_heap,3,0},10,{fragile_message_reference,{y,1}}}},
+ {{test_heap,3,0},10,{fragile_message_reference,{y,_}}}},
{{receive_stacked,f4,0},
- {{test_heap,3,0},10,{fragile_message_reference,{y,1}}}},
+ {{test_heap,3,0},10,{fragile_message_reference,{y,_}}}},
{{receive_stacked,f5,0},
{{loop_rec_end,{f,23}},
23,
- {fragile_message_reference,{y,1}}}},
+ {fragile_message_reference,{y,_}}}},
{{receive_stacked,f6,0},
- {{gc_bif,byte_size,{f,29},0,[{y,0}],{x,0}},
+ {{gc_bif,byte_size,{f,29},0,[{y,_}],{x,0}},
12,
- {fragile_message_reference,{y,0}}}},
+ {fragile_message_reference,{y,_}}}},
{{receive_stacked,f7,0},
{{loop_rec_end,{f,33}},
20,
- {fragile_message_reference,{y,0}}}},
+ {fragile_message_reference,{y,_}}}},
{{receive_stacked,f8,0},
{{loop_rec_end,{f,38}},
20,
- {fragile_message_reference,{y,0}}}},
+ {fragile_message_reference,{y,_}}}},
{{receive_stacked,m1,0},
{{loop_rec_end,{f,43}},
19,
- {fragile_message_reference,{y,0}}}},
+ {fragile_message_reference,{y,_}}}},
{{receive_stacked,m2,0},
{{loop_rec_end,{f,48}},
33,
- {fragile_message_reference,{y,0}}}}] = Errors,
+ {fragile_message_reference,{y,_}}}}] = Errors,
%% Compile the original source code as a smoke test.
Data = proplists:get_value(data_dir, Config),
@@ -579,6 +578,79 @@ receive_stacked(Config) ->
ok.
+aliased_types(Config) ->
+ Seq = lists:seq(1, 5),
+ 1 = aliased_types_1(Seq, Config),
+
+ {1,1} = aliased_types_2(Seq),
+ {42,none} = aliased_types_2([]),
+
+ gurka = aliased_types_3([gurka]),
+ gaffel = aliased_types_3([gaffel]),
+
+ ok.
+
+%% ERL-735: validator failed to track types on aliased registers, rejecting
+%% legitimate optimizations.
+%%
+%% move x0 y0
+%% bif hd L1 x0
+%% get_hd y0 %% The validator failed to see that y0 was a list
+%%
+aliased_types_1(Bug, Config) ->
+ if
+ Config =/= [gurka, gaffel] -> %% Pointless branch.
+ _ = hd(Bug),
+ lists:seq(1, 5),
+ hd(Bug)
+ end.
+
+%% ERL-832: validator failed to realize that a Y register was a cons.
+aliased_types_2(Bug) ->
+ Res = case Bug of
+ [] -> id(42);
+ _ -> hd(Bug)
+ end,
+ {Res,case Bug of
+ [] -> none;
+ _ -> hd(Bug)
+ end}.
+
+%% ERL-832 part deux; validator failed to realize that an aliased register was
+%% a cons.
+aliased_types_3(Bug) ->
+ List = [Y || Y <- Bug],
+ case List of
+ [] -> Bug;
+ _ ->
+ if
+ hd(List) -> a:a();
+ true -> ok
+ end,
+ hd(List)
+ end.
+
+
+%% ERL-867; validation proceeded after a type conflict, causing incorrect types
+%% to be joined.
+
+-record(r, { e1 = e1, e2 = e2 }).
+
+type_conflict(Config) when is_list(Config) ->
+ {e1, e2} = type_conflict_1(#r{}),
+ ok.
+
+type_conflict_1(C) ->
+ Src = id(C#r.e2),
+ TRes = try id(Src) of
+ R -> R
+ catch
+ %% C:R can never match, yet it assumed that the type of 'C' was
+ %% an atom from here on.
+ C:R -> R
+ end,
+ {C#r.e1, TRes}.
+
%%%-------------------------------------------------------------------------
transform_remove(Remove, Module) ->
@@ -637,3 +709,6 @@ night(Turned) ->
ok.
participating(_, _, _, _) -> ok.
+
+id(I) ->
+ I.
diff --git a/lib/compiler/test/beam_validator_SUITE_data/bad_bin_match.S b/lib/compiler/test/beam_validator_SUITE_data/bad_bin_match.S
index a60ca1e89a..c7610971f1 100644
--- a/lib/compiler/test/beam_validator_SUITE_data/bad_bin_match.S
+++ b/lib/compiler/test/beam_validator_SUITE_data/bad_bin_match.S
@@ -11,5 +11,5 @@
{label,1}.
{func_info,{atom,t},{atom,t},1}.
{label,2}.
- {test,bs_start_match2,{f,1},1,[{x,0},0],{x,0}}.
+ {test,bs_start_match3,{f,1},1,[{x,0}],{x,0}}.
return.
diff --git a/lib/compiler/test/beam_validator_SUITE_data/merge_undefined.S b/lib/compiler/test/beam_validator_SUITE_data/merge_undefined.S
index 481d55045d..aa344807e4 100644
--- a/lib/compiler/test/beam_validator_SUITE_data/merge_undefined.S
+++ b/lib/compiler/test/beam_validator_SUITE_data/merge_undefined.S
@@ -15,8 +15,9 @@
{select_val,{x,0},{f,1},{list,[{atom,gurka},{f,3},{atom,delete},{f,4}]}}.
{label,3}.
{allocate_heap,2,6,2}.
- %% The Y registers are not initialized here.
{test,is_eq_exact,{f,5},[{x,0},{atom,ok}]}.
+ %% This is unreachable since {x,0} is known not to be 'ok'. We should not
+ %% fail with "uninitialized y registers" on erlang:exit/1
{move,{atom,nisse},{x,0}}.
{call_ext,1,{extfunc,erlang,exit,1}}.
{label,4}.
@@ -29,6 +30,7 @@
{call_ext,2,{extfunc,io,format,2}}.
{test,is_ne_exact,{f,6},[{x,0},{atom,ok}]}.
{label,5}.
+ %% The Y registers are not initialized here.
{move,{atom,logReader},{x,1}}.
{move,{atom,console},{x,0}}.
{call_ext,2,{extfunc,debug,filter,2}}.
diff --git a/lib/compiler/test/beam_validator_SUITE_data/receive_stacked.S b/lib/compiler/test/beam_validator_SUITE_data/receive_stacked.S
index cca052a9c4..a878204d16 100644
--- a/lib/compiler/test/beam_validator_SUITE_data/receive_stacked.S
+++ b/lib/compiler/test/beam_validator_SUITE_data/receive_stacked.S
@@ -172,7 +172,7 @@
{allocate_zero,1,0}.
{label,28}.
{loop_rec,{f,30},{x,0}}.
- {test,bs_start_match2,{f,29},1,[{x,0},0],{x,0}}.
+ {test,bs_start_match3,{f,29},1,[{x,0}],{x,0}}.
{test,bs_get_integer2,
{f,29},
1,
@@ -219,7 +219,7 @@
{allocate_zero,1,0}.
{label,33}.
{loop_rec,{f,35},{x,0}}.
- {test,bs_start_match2,{f,34},1,[{x,0},0],{x,0}}.
+ {test,bs_start_match3,{f,34},1,[{x,0}],{x,0}}.
{test,bs_get_integer2,
{f,34},
1,
@@ -240,7 +240,7 @@
{y,0}}.
{'%',{no_bin_opt,{binary_used_in,{test,is_binary,{f,34},[{y,0}]}},
[63,{file,"receive_stacked.erl"}]}}.
- {test,is_binary,{f,34},[{y,0}]}.
+ {test,is_eq_exact,{f,34},[{y,0},{literal,<<0,1,2,3>>}]}.
remove_message.
{move,{integer,42},{x,0}}.
{line,[{location,"receive_stacked.erl",64}]}.
@@ -262,7 +262,7 @@
{allocate_zero,1,0}.
{label,38}.
{loop_rec,{f,40},{x,0}}.
- {test,bs_start_match2,{f,39},1,[{x,0},0],{x,1}}.
+ {test,bs_start_match3,{f,39},1,[{x,0}],{x,1}}.
{test,bs_get_integer2,
{f,39},
2,
@@ -283,7 +283,7 @@
{y,0}}.
{'%',{no_bin_opt,{[{x,1},{y,0}],{loop_rec_end,{f,38}},not_handled},
[70,{file,"receive_stacked.erl"}]}}.
- {test,is_binary,{f,39},[{x,0}]}.
+ {test,is_eq_exact,{f,39},[{x,0},{literal,<<0,1,2,3>>}]}.
remove_message.
{move,{integer,42},{x,0}}.
{line,[{location,"receive_stacked.erl",71}]}.
diff --git a/lib/compiler/test/bif_SUITE.erl b/lib/compiler/test/bif_SUITE.erl
index c4c709eb3a..423a7666af 100644
--- a/lib/compiler/test/bif_SUITE.erl
+++ b/lib/compiler/test/bif_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2016. All Rights Reserved.
+%% Copyright Ericsson AB 2016-2018. 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.
@@ -23,7 +23,7 @@
-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
init_per_group/2,end_per_group/2,
- beam_validator/1,trunc_and_friends/1,cover_safe_bifs/1]).
+ beam_validator/1,trunc_and_friends/1,cover_safe_and_pure_bifs/1]).
suite() ->
[{ct_hooks,[ts_install_cth]}].
@@ -35,7 +35,7 @@ groups() ->
[{p,[parallel],
[beam_validator,
trunc_and_friends,
- cover_safe_bifs
+ cover_safe_and_pure_bifs
]}].
init_per_suite(Config) ->
@@ -106,7 +106,7 @@ trunc_template(Func, Bif) ->
catch error:badarg -> ok end,
ok.").
-cover_safe_bifs(Config) ->
+cover_safe_and_pure_bifs(Config) ->
_ = get(),
_ = get_keys(a),
_ = group_leader(),
@@ -118,5 +118,6 @@ cover_safe_bifs(Config) ->
_ = processes(),
_ = registered(),
_ = term_to_binary(Config),
+ 42 = list_to_integer("2A", 16),
ok.
diff --git a/lib/compiler/test/bs_bincomp_SUITE.erl b/lib/compiler/test/bs_bincomp_SUITE.erl
index a5d49020a9..0419b16eea 100644
--- a/lib/compiler/test/bs_bincomp_SUITE.erl
+++ b/lib/compiler/test/bs_bincomp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/bs_bit_binaries_SUITE.erl b/lib/compiler/test/bs_bit_binaries_SUITE.erl
index 17faa012bc..526769f3a6 100644
--- a/lib/compiler/test/bs_bit_binaries_SUITE.erl
+++ b/lib/compiler/test/bs_bit_binaries_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/bs_construct_SUITE.erl b/lib/compiler/test/bs_construct_SUITE.erl
index ccc49df005..69017d87e7 100644
--- a/lib/compiler/test/bs_construct_SUITE.erl
+++ b/lib/compiler/test/bs_construct_SUITE.erl
@@ -153,6 +153,8 @@ l(I_13, I_big1, I_16, Bin) ->
[0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
16#77,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,
16#FF,16#FF,16#FF,16#FF,16#FF,16#FF]),
+ ?T(<< (<<"abc",7:3>>):3/binary >>,
+ [$a,$b,$c]),
%% Mix different units.
?T(<<37558955:(I_16-12)/unit:8,1:1>>,
@@ -311,6 +313,9 @@ fail(Config) when is_list(Config) ->
{'EXIT',{badarg,_}} = (catch <<0:(-(1 bsl 100))>>),
{'EXIT',{badarg,_}} = (catch <<Bin/binary,0:(-(1 bsl 100))>>),
+ %% Unaligned sizes with literal binaries.
+ {'EXIT',{badarg,_}} = (catch <<0,(<<7777:17>>)/binary>>),
+
ok.
float_bin(Config) when is_list(Config) ->
diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl
index b4277f0705..2cfcb841a7 100644
--- a/lib/compiler/test/bs_match_SUITE.erl
+++ b/lib/compiler/test/bs_match_SUITE.erl
@@ -40,7 +40,10 @@
map_and_binary/1,unsafe_branch_caching/1,
bad_literals/1,good_literals/1,constant_propagation/1,
parse_xml/1,get_payload/1,escape/1,num_slots_different/1,
- beam_bsm/1,guard/1,is_ascii/1,non_opt_eq/1,erl_689/1]).
+ beam_bsm/1,guard/1,is_ascii/1,non_opt_eq/1,
+ expression_before_match/1,erl_689/1,restore_on_call/1,
+ restore_after_catch/1,matches_on_parameter/1,big_positions/1,
+ matching_meets_apply/1,bs_start_match2_defs/1]).
-export([coverage_id/1,coverage_external_ignore/2]).
@@ -56,7 +59,7 @@ all() ->
[{group,p}].
groups() ->
- [{p,[parallel],
+ [{p,[],
[size_shadow,int_float,otp_5269,null_fields,wiger,
bin_tail,save_restore,
partitioned_bs_match,function_clause,unit,
@@ -72,7 +75,10 @@ groups() ->
map_and_binary,unsafe_branch_caching,
bad_literals,good_literals,constant_propagation,parse_xml,
get_payload,escape,num_slots_different,
- beam_bsm,guard,is_ascii,non_opt_eq,erl_689]}].
+ beam_bsm,guard,is_ascii,non_opt_eq,
+ expression_before_match,erl_689,restore_on_call,
+ matches_on_parameter,big_positions,
+ matching_meets_apply,bs_start_match2_defs]}].
init_per_suite(Config) ->
@@ -736,6 +742,20 @@ coverage(Config) when is_list(Config) ->
binary = coverage_bitstring(<<7>>),
bitstring = coverage_bitstring(<<7:4>>),
other = coverage_bitstring([a]),
+
+ %% Cover code in beam_trim.
+
+ {done,<<17,53>>,[253,155,200]} =
+ coverage_trim(<<253,155,200,17,53>>, e0, e1, e2, e3, []),
+
+ <<"(right|linux)">> = coverage_trim_1(<<"">>, <<"right">>, <<"linux">>),
+ <<"/(right|linux)">> = coverage_trim_1(<<"/">>, <<"right">>, <<"linux">>),
+ <<"(left|linux)/(right|linux)">> =
+ coverage_trim_1(<<"left">>, <<"right">>, <<"linux">>),
+
+ {10,<<"-">>,""} = coverage_trim_2(<<"-">>, 10, []),
+ {8,<<"-">>,"aa"} = coverage_trim_2(<<"aa-">>, 10, []),
+
ok.
coverage_fold(Fun, Acc, <<H,T/binary>>) ->
@@ -830,6 +850,37 @@ coverage_bitstring(Bin) when is_binary(Bin) -> binary;
coverage_bitstring(<<_/bitstring>>) -> bitstring;
coverage_bitstring(_) -> other.
+coverage_trim(<<C:8,T/binary>> = Bin, E0, E1, E2, E3, Acc) ->
+ case id(C > 128) of
+ true ->
+ coverage_trim(T, E0, E1, E2, E3, [C|Acc]);
+ false ->
+ {done,Bin,lists:reverse(Acc)}
+ end.
+
+coverage_trim_1(<<>>, Right, OsType) ->
+ do_coverage_trim_1(Right, OsType);
+coverage_trim_1(<<"/">>, Right, OsType) ->
+ <<"/",(do_coverage_trim_1(Right, OsType))/binary>>;
+coverage_trim_1(Left, Right, OsType) ->
+ <<(do_coverage_trim_1(Left, OsType))/binary,
+ "/",
+ (do_coverage_trim_1(Right, OsType))/binary>>.
+
+do_coverage_trim_1(A, OsType) ->
+ <<"(",A/binary,"|",OsType/binary,")">>.
+
+coverage_trim_2(<<C/utf8,R/binary>> = Bin, I, L) ->
+ case printable_char(C) of
+ true ->
+ coverage_trim_2(R, I - 1, [C | L]);
+ false ->
+ {I,Bin,lists:reverse(L)}
+ end.
+
+printable_char($a) -> true;
+printable_char(_) -> false.
+
multiple_uses(Config) when is_list(Config) ->
{344,62879,345,<<245,159,1,89>>} = multiple_uses_1(<<1,88,245,159,1,89>>),
true = multiple_uses_2(<<0,0,197,18>>),
@@ -1734,14 +1785,22 @@ non_opt_eq([], <<>>) ->
%% ERL-689
-erl_689(Config) ->
+erl_689(_Config) ->
{{0, 0, 0}, <<>>} = do_erl_689_1(<<0>>, ?MODULE),
{{2018, 8, 7}, <<>>} = do_erl_689_1(<<4,2018:16/little,8,7>>, ?MODULE),
{{0, 0, 0}, <<>>} = do_erl_689_2(?MODULE, <<0>>),
{{2018, 8, 7}, <<>>} = do_erl_689_2(?MODULE, <<4,2018:16/little,8,7>>),
ok.
-do_erl_689_1(<<Length, Data/binary>>, _) ->
+do_erl_689_1(Arg1, Arg2) ->
+ Res = do_erl_689_1a(Arg1, Arg2),
+ Res = do_erl_689_1b(Arg1, Arg2).
+
+do_erl_689_2(Arg1, Arg2) ->
+ Res = do_erl_689_2a(Arg1, Arg2),
+ Res = do_erl_689_2b(Arg1, Arg2).
+
+do_erl_689_1a(<<Length, Data/binary>>, _) ->
case {Data, Length} of
{_, 0} ->
%% bs_context_to_binary would incorrectly set Data to the original
@@ -1751,7 +1810,19 @@ do_erl_689_1(<<Length, Data/binary>>, _) ->
{{Y, M, D}, Rest}
end.
-do_erl_689_2(_, <<Length, Data/binary>>) ->
+do_erl_689_1b(<<Length, Data/binary>>, _) ->
+ case {Data, Length} of
+ {_, 0} ->
+ %% bs_context_to_binary would incorrectly set Data to the original
+ %% binary (before matching in the function head).
+ id(0),
+ {{0, 0, 0}, Data};
+ {<<Y:16/little, M, D, Rest/binary>>, 4} ->
+ id(1),
+ {{Y, M, D}, Rest}
+ end.
+
+do_erl_689_2a(_, <<Length, Data/binary>>) ->
case {Length, Data} of
{0, _} ->
%% bs_context_to_binary would incorrectly set Data to the original
@@ -1761,7 +1832,140 @@ do_erl_689_2(_, <<Length, Data/binary>>) ->
{{Y, M, D}, Rest}
end.
+do_erl_689_2b(_, <<Length, Data/binary>>) ->
+ case {Length, Data} of
+ {0, _} ->
+ %% bs_context_to_binary would incorrectly set Data to the original
+ %% binary (before matching in the function head).
+ id(0),
+ {{0, 0, 0}, Data};
+ {4, <<Y:16/little, M, D, Rest/binary>>} ->
+ id(1),
+ {{Y, M, D}, Rest}
+ end.
+
+%% ERL-753
+
+bs_start_match2_defs(_Config) ->
+ {<<"http://127.0.0.1:1234/vsaas/hello">>} = api_url(<<"hello">>),
+ {"https://127.0.0.1:4321/vsaas/hello"} = api_url({https, "hello"}).
+
+api_url(URL) ->
+ case URL of
+ <<_/binary>> -> {<<"http://127.0.0.1:1234/vsaas/",URL/binary>>};
+ {https, [_|_] = URL1} -> {"https://127.0.0.1:4321/vsaas/"++URL1}
+ end.
+
check(F, R) ->
R = F().
+%% Make sure that an expression that comes between function start and a match
+%% expression passes validation.
+expression_before_match(Config) when is_list(Config) ->
+ <<_,R/binary>> = id(<<0,1,2,3>>),
+ {1, <<2,3>>} = expression_before_match_1(R),
+ ok.
+
+expression_before_match_1(R) ->
+ A = id(1),
+ case R of
+ <<1,Bar/binary>> -> {A, Bar};
+ <<>> -> {A, baz}
+ end.
+
+%% Make sure that context positions are updated on calls.
+restore_on_call(Config) when is_list(Config) ->
+ ok = restore_on_call_1(<<0, 1, 2>>).
+
+restore_on_call_1(<<0, Rest/binary>>) ->
+ <<2>> = restore_on_call_2(Rest),
+ <<2>> = restore_on_call_2(Rest), %% {badmatch, <<>>} on missing restore.
+ ok.
+
+restore_on_call_2(<<1, Rest/binary>>) -> Rest;
+restore_on_call_2(Other) -> Other.
+
+%% 'catch' must invalidate positions.
+restore_after_catch(Config) when is_list(Config) ->
+ <<0, 1>> = restore_after_catch_1(<<0, 1>>),
+ ok.
+
+restore_after_catch_1(<<A/binary>>) ->
+ try throw_after_byte(A) of
+ _ -> impossible
+ catch
+ throw:_Any ->
+ %% Will equal <<1>> if the bug is present.
+ A
+ end.
+
+throw_after_byte(<<_,_/binary>>) ->
+ throw(away).
+
+matches_on_parameter(Config) when is_list(Config) ->
+ %% This improves coverage for matching on "naked" parameters.
+ {<<"urka">>, <<"a">>} = matches_on_parameter_1(<<"gurka">>),
+ ok = (catch matches_on_parameter_2(<<"10001110101">>, 0)).
+
+matches_on_parameter_1(Bin) ->
+ <<"g", A/binary>> = Bin,
+ <<_,_,"rk", B/binary>> = Bin,
+ {A, B}.
+
+matches_on_parameter_2(Bin, Offset) ->
+ <<_:Offset, Bit:1, Rest/bits>> = Bin,
+ case bit_size(Rest) of
+ 0 -> throw(ok);
+ _ -> [Bit | matches_on_parameter_2(Bin, Offset + 1)]
+ end.
+
+big_positions(Config) when is_list(Config) ->
+ %% This provides coverage for when match context positions no longer fit
+ %% into an immediate on 32-bit platforms.
+
+ A = <<0:((1 bsl 27) - 8), $A, 1:1, "gurka", $A>>,
+ B = <<0:((1 bsl 27) - 8), $B, "hello", $B>>,
+
+ {a,$A} = bp_start_match(A),
+ {b,$B} = bp_start_match(B),
+ {a,$A} = bp_getpos(A),
+ {b,$B} = bp_getpos(B),
+
+ ok.
+
+%% After the first iteration the context's position will no longer fit into an
+%% immediate. To improve performance the bs_start_match3 instruction will
+%% return a new context with an updated base position so that we won't have to
+%% resort to using bigints.
+bp_start_match(<<_:(1 bsl 27),T/bits>>) -> bp_start_match(T);
+bp_start_match(<<1:1,"gurka",A>>) -> {a,A};
+bp_start_match(<<"hello",B>>) -> {b,B}.
+
+%% This is a corner case where the above didn't work perfectly; if the position
+%% was _just_ small enough to fit into an immediate when bs_start_match3 was
+%% hit, but too large at bs_get_position, then it must be saved as a bigint.
+bp_getpos(<<_:((1 bsl 27) - 8),T/bits>>) -> bp_getpos(T);
+bp_getpos(<<A,1:1,"gurka",A>>) -> {a,A};
+bp_getpos(<<B,"hello",B>>) -> {b,B}.
+
+matching_meets_apply(_Config) ->
+ <<"abc">> = do_matching_meets_apply(<<"/abc">>, []),
+ 42 = do_matching_meets_apply(<<"">>, {erlang,-42}),
+ 100 = do_matching_meets_apply(no_binary, {erlang,-100}),
+ ok.
+
+do_matching_meets_apply(<<$/, Rest/binary>>, _Handler) ->
+ id(Rest);
+do_matching_meets_apply(<<_/binary>>=Name, never_matches_a) ->
+ %% Used to crash the compiler because variables in a remote
+ %% were not handled properly by beam_ssa_bsm.
+ Name:foo(gurka);
+do_matching_meets_apply(<<_/binary>>=Name, never_matches_b) ->
+ %% Another case of the above.
+ foo:Name(gurka);
+do_matching_meets_apply(_Bin, {Handler, State}) ->
+ %% Another case of the above.
+ Handler:abs(State).
+
+
id(I) -> I.
diff --git a/lib/compiler/test/bs_utf_SUITE.erl b/lib/compiler/test/bs_utf_SUITE.erl
index 4330677260..8ea4a849ec 100644
--- a/lib/compiler/test/bs_utf_SUITE.erl
+++ b/lib/compiler/test/bs_utf_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compilation_SUITE.erl b/lib/compiler/test/compilation_SUITE.erl
index def7a60f45..74f9dbd9b4 100644
--- a/lib/compiler/test/compilation_SUITE.erl
+++ b/lib/compiler/test/compilation_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl
index 85f0b7dc46..408af80dd9 100644
--- a/lib/compiler/test/compile_SUITE.erl
+++ b/lib/compiler/test/compile_SUITE.erl
@@ -28,15 +28,15 @@
init_per_group/2,end_per_group/2,
app_test/1,appup_test/1,
debug_info/4, custom_debug_info/1, custom_compile_info/1,
- file_1/1, forms_2/1, module_mismatch/1, big_file/1, outdir/1,
+ file_1/1, forms_2/1, module_mismatch/1, outdir/1,
binary/1, makedep/1, cond_and_ifdef/1, listings/1, listings_big/1,
other_output/1, kernel_listing/1, encrypted_abstr/1,
strict_record/1, utf8_atoms/1, utf8_functions/1, extra_chunks/1,
cover/1, env/1, core_pp/1, tuple_calls/1,
- core_roundtrip/1, asm/1, optimized_guards/1,
+ core_roundtrip/1, asm/1,
sys_pre_attributes/1, dialyzer/1,
warnings/1, pre_load_check/1, env_compiler_options/1,
- bc_options/1, deterministic_include/1
+ bc_options/1, deterministic_include/1, deterministic_paths/1
]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -46,14 +46,14 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
-spec all() -> all_return_type().
all() ->
- [app_test, appup_test, file_1, forms_2, module_mismatch, big_file, outdir,
+ [app_test, appup_test, file_1, forms_2, module_mismatch, outdir,
binary, makedep, cond_and_ifdef, listings, listings_big,
other_output, kernel_listing, encrypted_abstr, tuple_calls,
strict_record, utf8_atoms, utf8_functions, extra_chunks,
- cover, env, core_pp, core_roundtrip, asm, optimized_guards,
+ cover, env, core_pp, core_roundtrip, asm,
sys_pre_attributes, dialyzer, warnings, pre_load_check,
env_compiler_options, custom_debug_info, bc_options,
- custom_compile_info, deterministic_include].
+ custom_compile_info, deterministic_include, deterministic_paths].
groups() ->
[].
@@ -104,6 +104,7 @@ file_1(Config) when is_list(Config) ->
compile_and_verify(Simple, Target, []),
compile_and_verify(Simple, Target, [native]),
compile_and_verify(Simple, Target, [debug_info]),
+ compile_and_verify(Simple, Target, [no_postopt]),
{ok,simple} = compile:file(Simple, [no_line_info]), %Coverage
{ok,simple} = compile:file(Simple, [{eprof,beam_z}]), %Coverage
@@ -231,17 +232,6 @@ module_mismatch(Config) when is_list(Config) ->
ok.
-big_file(Config) when is_list(Config) ->
- {Big,Target} = get_files(Config, big, "big_file"),
- ok = file:set_cwd(filename:dirname(Target)),
- compile_and_verify(Big, Target, []),
- compile_and_verify(Big, Target, [debug_info]),
- compile_and_verify(Big, Target, [no_postopt]),
-
- %% Cleanup.
- ok = file:delete(Target),
- ok.
-
%% Tests that the {outdir, Dir} option works.
outdir(Config) when is_list(Config) ->
@@ -370,43 +360,37 @@ do_file_listings(DataDir, PrivDir, [File|Files]) ->
TargetDir = filename:join(PrivDir, listings),
ok = file:make_dir(TargetDir),
- %% Test all dedicated listing options.
- do_listing(Simple, TargetDir, 'S'),
- do_listing(Simple, TargetDir, 'E'),
- do_listing(Simple, TargetDir, 'P'),
- do_listing(Simple, TargetDir, dpp, ".pp"),
- do_listing(Simple, TargetDir, dabstr, ".abstr"),
- do_listing(Simple, TargetDir, dexp, ".expand"),
- do_listing(Simple, TargetDir, dcore, ".core"),
- do_listing(Simple, TargetDir, doldinline, ".oldinline"),
- do_listing(Simple, TargetDir, dinline, ".inline"),
- do_listing(Simple, TargetDir, dcore, ".core"),
- do_listing(Simple, TargetDir, dcopt, ".copt"),
- do_listing(Simple, TargetDir, dcbsm, ".core_bsm"),
- do_listing(Simple, TargetDir, dsetel, ".dsetel"),
- do_listing(Simple, TargetDir, dkern, ".kernel"),
- do_listing(Simple, TargetDir, dssa, ".ssa"),
- do_listing(Simple, TargetDir, dssaopt, ".ssaopt"),
- do_listing(Simple, TargetDir, dprecg, ".precodegen"),
- do_listing(Simple, TargetDir, dcg, ".codegen"),
- do_listing(Simple, TargetDir, dblk, ".block"),
- do_listing(Simple, TargetDir, dexcept, ".except"),
- do_listing(Simple, TargetDir, dbs, ".bs"),
- do_listing(Simple, TargetDir, ddead, ".dead"),
- do_listing(Simple, TargetDir, djmp, ".jump"),
- do_listing(Simple, TargetDir, dclean, ".clean"),
- do_listing(Simple, TargetDir, dpeep, ".peep"),
- do_listing(Simple, TargetDir, dopt, ".optimize"),
-
- %% First clean up.
- Listings = filename:join(PrivDir, listings),
- lists:foreach(fun(F) -> ok = file:delete(F) end,
- filelib:wildcard(filename:join(Listings, "*"))),
+ List = [{'S',".S"},
+ {'E',".E"},
+ {'P',".P"},
+ {dpp, ".pp"},
+ {dabstr, ".abstr"},
+ {dexp, ".expand"},
+ {dcore, ".core"},
+ {doldinline, ".oldinline"},
+ {dinline, ".inline"},
+ {dcore, ".core"},
+ {dcopt, ".copt"},
+ {dcbsm, ".core_bsm"},
+ {dkern, ".kernel"},
+ {dssa, ".ssa"},
+ {dssaopt, ".ssaopt"},
+ {dprecg, ".precodegen"},
+ {dcg, ".codegen"},
+ {dblk, ".block"},
+ {dexcept, ".except"},
+ {djmp, ".jump"},
+ {dclean, ".clean"},
+ {dpeep, ".peep"},
+ {dopt, ".optimize"},
+ {diffable, ".S"}],
+ p_listings(List, Simple, TargetDir),
%% Test options that produce a listing file if 'binary' is not given.
do_listing(Simple, TargetDir, to_pp, ".P"),
do_listing(Simple, TargetDir, to_exp, ".E"),
do_listing(Simple, TargetDir, to_core0, ".core"),
+ Listings = filename:join(PrivDir, listings),
ok = file:delete(filename:join(Listings, File ++ ".core")),
do_listing(Simple, TargetDir, to_core, ".core"),
do_listing(Simple, TargetDir, to_kernel, ".kernel"),
@@ -422,24 +406,35 @@ do_file_listings(DataDir, PrivDir, [File|Files]) ->
listings_big(Config) when is_list(Config) ->
{Big,Target} = get_files(Config, big, listings_big),
TargetDir = filename:dirname(Target),
- do_listing(Big, TargetDir, 'S'),
- do_listing(Big, TargetDir, 'E'),
- do_listing(Big, TargetDir, 'P'),
- do_listing(Big, TargetDir, dkern, ".kernel"),
- do_listing(Big, TargetDir, dssa, ".ssa"),
- do_listing(Big, TargetDir, dssaopt, ".ssaopt"),
- do_listing(Big, TargetDir, dprecg, ".precodegen"),
- do_listing(Big, TargetDir, to_dis, ".dis"),
-
- TargetNoext = filename:rootname(Target, code:objfile_extension()),
- {ok,big} = compile:file(TargetNoext, [from_asm,{outdir,TargetDir}]),
-
- %% Cleanup.
- ok = file:delete(Target),
- lists:foreach(fun(F) -> ok = file:delete(F) end,
- filelib:wildcard(filename:join(TargetDir, "*"))),
- ok = file:del_dir(TargetDir),
- ok.
+ List = [{'S',".S"},
+ {'E',".E"},
+ {'P',".P"},
+ {dkern, ".kernel"},
+ {dssa, ".ssa"},
+ {dssaopt, ".ssaopt"},
+ {dprecg, ".precodegen"},
+ {to_dis, ".dis"}],
+ p_listings(List, Big, TargetDir).
+
+p_listings(List, File, BaseDir) ->
+ Run = fun({Option,Extension}) ->
+ Uniq = erlang:unique_integer([positive]),
+ Dir = filename:join(BaseDir, integer_to_list(Uniq)),
+ ok = file:make_dir(Dir),
+ try
+ do_listing(File, Dir, Option, Extension),
+ ok
+ catch
+ Class:Error:Stk ->
+ io:format("~p:~p\n~p\n", [Class,Error,Stk]),
+ error
+ after
+ _ = [ok = file:delete(F) ||
+ F <- filelib:wildcard(filename:join(Dir, "*"))],
+ ok = file:del_dir(Dir)
+ end
+ end,
+ test_lib:p_run(Run, List).
other_output(Config) when is_list(Config) ->
{Simple,_Target} = get_files(Config, simple, "other_output"),
@@ -686,9 +681,6 @@ cover(Config) when is_list(Config) ->
io:format("~p\n", [compile:options()]),
ok.
-do_listing(Source, TargetDir, Type) ->
- do_listing(Source, TargetDir, Type, "." ++ atom_to_list(Type)).
-
do_listing(Source, TargetDir, Type, Ext) ->
io:format("Source: ~p TargetDir: ~p\n Type: ~p Ext: ~p\n",
[Source, TargetDir, Type, Ext]),
@@ -1175,88 +1167,6 @@ do_asm(Beam, Outdir) ->
error
end.
-%% Make sure that guards are fully optimized. Guards should
-%% should use 'test' instructions, not 'bif' instructions.
-
-optimized_guards(_Config) ->
- TestBeams = get_unique_beam_files(),
- test_lib:p_run(fun(F) -> do_opt_guards(F) end, TestBeams).
-
-do_opt_guards(Beam) ->
- {ok,{M,[{abstract_code,{raw_abstract_v1,A}}]}} =
- beam_lib:chunks(Beam, [abstract_code]),
- try
- {ok,M,Asm} = compile:forms(A, ['S']),
- do_opt_guards_mod(Asm)
- catch Class:Error:Stk ->
- io:format("~p: ~p ~p\n~p\n", [M,Class,Error,Stk]),
- error
- end.
-
-do_opt_guards_mod({Mod,_Exp,_Attr,Asm,_NumLabels}) ->
- case do_opt_guards_fs(Mod, Asm) of
- [] ->
- ok;
- [_|_]=Bifs ->
- io:format("ERRORS FOR ~p:\n~p\n", [Mod,Bifs]),
- error
- end.
-
-do_opt_guards_fs(Mod, [{function,Name,Arity,_,Is}|Fs]) ->
- Bifs0 = do_opt_guards_fun(Is),
-
- %% The compiler does not attempt to optimize 'xor'.
- %% Therefore, ignore all functions that use 'xor' in
- %% a guard.
- Bifs = case lists:any(fun({bif,'xor',_,_,_}) -> true;
- (_) -> false
- end, Bifs0) of
- true -> [];
- false -> Bifs0
- end,
-
- %% Filter out the allowed exceptions.
- FA = {Name,Arity},
- case {Bifs,is_exception(Mod, FA)} of
- {[_|_],true} ->
- io:format("~p:~p/~p IGNORED:\n~p\n",
- [Mod,Name,Arity,Bifs]),
- do_opt_guards_fs(Mod, Fs);
- {[_|_],false} ->
- [{FA,Bifs}|do_opt_guards_fs(Mod, Fs)];
- {[],false} ->
- do_opt_guards_fs(Mod, Fs);
- {[],true} ->
- io:format("Redundant exception for ~p:~p/~p\n",
- [Mod,Name,Arity]),
- error(redundant)
- end;
-do_opt_guards_fs(_, []) -> [].
-
-do_opt_guards_fun([{bif,Name,{f,F},As,_}=I|Is]) when F =/= 0 ->
- Arity = length(As),
- case erl_internal:comp_op(Name, Arity) orelse
- erl_internal:bool_op(Name, Arity) orelse
- erl_internal:new_type_test(Name, Arity) of
- true ->
- [I|do_opt_guards_fun(Is)];
- false ->
- do_opt_guards_fun(Is)
- end;
-do_opt_guards_fun([_|Is]) ->
- do_opt_guards_fun(Is);
-do_opt_guards_fun([]) -> [].
-
-is_exception(guard_SUITE, {'-complex_not/1-fun-4-',1}) -> true;
-is_exception(guard_SUITE, {'-complex_not/1-fun-5-',1}) -> true;
-is_exception(guard_SUITE, {bad_guards,1}) -> true;
-is_exception(guard_SUITE, {bad_guards_2,2}) -> true;
-is_exception(guard_SUITE, {bad_guards_3,2}) -> true;
-is_exception(guard_SUITE, {csemi7,3}) -> true;
-is_exception(guard_SUITE, {nested_not_2b,4}) -> true;
-is_exception(guard_SUITE, {tricky_1,2}) -> true;
-is_exception(_, _) -> false.
-
sys_pre_attributes(Config) ->
DataDir = proplists:get_value(data_dir, Config),
File = filename:join(DataDir, "attributes.erl"),
@@ -1473,36 +1383,49 @@ env_compiler_options(_Config) ->
bc_options(Config) ->
DataDir = proplists:get_value(data_dir, Config),
- 101 = highest_opcode(DataDir, small_float, [no_get_hd_tl,no_line_info]),
-
- 103 = highest_opcode(DataDir, big,
- [no_get_hd_tl,no_ssa_opt_record,
- no_line_info,no_stack_trimming]),
-
- 125 = highest_opcode(DataDir, small_float,
- [no_get_hd_tl,no_line_info,no_ssa_opt_float]),
-
- 132 = highest_opcode(DataDir, small,
- [no_get_hd_tl,no_ssa_opt_record,no_ssa_opt_float,no_line_info]),
-
- 136 = highest_opcode(DataDir, big, [no_get_hd_tl,no_ssa_opt_record,no_line_info]),
-
- 153 = highest_opcode(DataDir, big, [no_get_hd_tl,no_ssa_opt_record]),
- 153 = highest_opcode(DataDir, big, [r16]),
- 153 = highest_opcode(DataDir, big, [r17]),
- 153 = highest_opcode(DataDir, big, [r18]),
- 153 = highest_opcode(DataDir, big, [r19]),
- 153 = highest_opcode(DataDir, small_float, [r16]),
- 153 = highest_opcode(DataDir, small_float, []),
-
- 158 = highest_opcode(DataDir, small_maps, [r17]),
- 158 = highest_opcode(DataDir, small_maps, [r18]),
- 158 = highest_opcode(DataDir, small_maps, [r19]),
- 158 = highest_opcode(DataDir, small_maps, [r20]),
- 158 = highest_opcode(DataDir, small_maps, []),
-
- 163 = highest_opcode(DataDir, big, []),
-
+ L = [{101, small_float, [no_get_hd_tl,no_line_info]},
+ {103, big, [no_put_tuple2,no_get_hd_tl,no_ssa_opt_record,
+ no_line_info,no_stack_trimming]},
+ {125, small_float, [no_get_hd_tl,no_line_info,no_ssa_opt_float]},
+
+ {132, small, [no_put_tuple2,no_get_hd_tl,no_ssa_opt_record,
+ no_ssa_opt_float,no_line_info,no_bsm3]},
+
+ {153, small, [r20]},
+ {153, small, [r21]},
+
+ {136, big, [no_put_tuple2,no_get_hd_tl,
+ no_ssa_opt_record,no_line_info]},
+
+ {153, big, [no_put_tuple2,no_get_hd_tl, no_ssa_opt_record]},
+ {153, big, [r16]},
+ {153, big, [r17]},
+ {153, big, [r18]},
+ {153, big, [r19]},
+ {153, small_float, [r16]},
+ {153, small_float, []},
+
+ {158, small_maps, [r17]},
+ {158, small_maps, [r18]},
+ {158, small_maps, [r19]},
+ {158, small_maps, [r20]},
+ {158, small_maps, [r21]},
+
+ {164, small_maps, []},
+ {164, big, []}
+ ],
+
+ Test = fun({Expected,Mod,Options}) ->
+ case highest_opcode(DataDir, Mod, Options) of
+ Expected ->
+ ok;
+ Got ->
+ io:format("*** module ~p, options ~p => got ~p; expected ~p\n",
+ [Mod,Options,Got,Expected]),
+ error
+ end
+ end,
+ test_lib:p_run(Test, L),
ok.
highest_opcode(DataDir, Mod, Opt) ->
@@ -1529,6 +1452,30 @@ deterministic_include(Config) when is_list(Config) ->
ok.
+deterministic_paths(Config) when is_list(Config) ->
+ DataDir = proplists:get_value(data_dir, Config),
+
+ %% Files without +deterministic should differ if they were compiled from a
+ %% different directory.
+ true = deterministic_paths_1(DataDir, "simple", []),
+
+ %% ... but files with +deterministic shouldn't.
+ false = deterministic_paths_1(DataDir, "simple", [deterministic]),
+
+ ok.
+
+deterministic_paths_1(DataDir, Name, Opts) ->
+ Simple = filename:join(DataDir, "simple"),
+ {ok, Cwd} = file:get_cwd(),
+ try
+ {ok,_,A} = compile:file(Simple, [binary | Opts]),
+ ok = file:set_cwd(DataDir),
+ {ok,_,B} = compile:file(Name, [binary | Opts]),
+ A =/= B
+ after
+ file:set_cwd(Cwd)
+ end.
+
%%%
%%% Utilities.
%%%
diff --git a/lib/compiler/test/compiler.cover b/lib/compiler/test/compiler.cover
index 3fd7fc1937..fac0f9947c 100644
--- a/lib/compiler/test/compiler.cover
+++ b/lib/compiler/test/compiler.cover
@@ -1,5 +1,4 @@
-{incl_app,compiler,details}.
-
%% -*- erlang -*-
+{local_only,compiler,true}.
+{incl_app,compiler,details}.
{excl_mods,compiler,[core_scan,core_parse]}.
-
diff --git a/lib/compiler/test/core_alias_SUITE.erl b/lib/compiler/test/core_alias_SUITE.erl
index 4f96576621..737b1567d4 100644
--- a/lib/compiler/test/core_alias_SUITE.erl
+++ b/lib/compiler/test/core_alias_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl
index 68bc5c6e2f..adfebd5158 100644
--- a/lib/compiler/test/core_fold_SUITE.erl
+++ b/lib/compiler/test/core_fold_SUITE.erl
@@ -212,9 +212,14 @@ bifs(Config) when is_list(Config) ->
{ok,#{K:=V}} = id(list_to_tuple([ok,#{K=>V}])),
ok.
--define(CMP_SAME(A0, B), (fun(A) -> true = A == B, false = A /= B end)(id(A0))).
--define(CMP_DIFF(A0, B), (fun(A) -> false = A == B, true = A /= B end)(id(A0))).
-
+-define(CMP_SAME0(A0, B), (fun(A) -> true = A == B, false = A /= B end)(id(A0))).
+-define(CMP_SAME1(A0, B), (fun(A) -> false = A /= B, true = A == B end)(id(A0))).
+-define(CMP_SAME(A0, B), (true = ?CMP_SAME0(A0, B) =:= not ?CMP_SAME1(A0, B))).
+
+-define(CMP_DIFF0(A0, B), (fun(A) -> false = A == B, true = A /= B end)(id(A0))).
+-define(CMP_DIFF1(A0, B), (fun(A) -> true = A /= B, false = A == B end)(id(A0))).
+-define(CMP_DIFF(A0, B), (true = ?CMP_DIFF0(A0, B) =:= not ?CMP_DIFF1(A0, B))).
+
eq(Config) when is_list(Config) ->
?CMP_SAME([a,b,c], [a,b,c]),
?CMP_SAME([42.0], [42.0]),
@@ -497,7 +502,7 @@ source(true, Activities) ->
Activities
end.
-tim(#{reduction := Emergency}) ->
+tim(#{reduction := _Emergency}) ->
try
fun() -> surgery end
catch
diff --git a/lib/compiler/test/error_SUITE.erl b/lib/compiler/test/error_SUITE.erl
index da291bdc8b..8b9dbe4aa0 100644
--- a/lib/compiler/test/error_SUITE.erl
+++ b/lib/compiler/test/error_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/float_SUITE.erl b/lib/compiler/test/float_SUITE.erl
index 39867021cb..831e8279aa 100644
--- a/lib/compiler/test/float_SUITE.erl
+++ b/lib/compiler/test/float_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. 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.
@@ -20,7 +20,8 @@
-module(float_SUITE).
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
- pending/1,bif_calls/1,math_functions/1,mixed_float_and_int/1]).
+ pending/1,bif_calls/1,math_functions/1,mixed_float_and_int/1,
+ subtract_number_type/1]).
-include_lib("common_test/include/ct.hrl").
@@ -28,7 +29,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[pending, bif_calls, math_functions,
- mixed_float_and_int].
+ mixed_float_and_int, subtract_number_type].
groups() ->
[].
@@ -176,5 +177,15 @@ mixed_float_and_int(Config) when is_list(Config) ->
pc(Cov, NotCov, X) ->
round(Cov/(Cov+NotCov)*100) + 42 + 2.0*X.
+subtract_number_type(Config) when is_list(Config) ->
+ 120 = fact(5).
+
+fact(N) ->
+ fact(N, 1).
+
+fact(0, P) -> P;
+fact(1, P) -> P;
+fact(N, P) -> fact(N-1, P*N).
+
id(I) -> I.
diff --git a/lib/compiler/test/fun_SUITE.erl b/lib/compiler/test/fun_SUITE.erl
index e00885fcd6..1df0a05275 100644
--- a/lib/compiler/test/fun_SUITE.erl
+++ b/lib/compiler/test/fun_SUITE.erl
@@ -249,6 +249,13 @@ badfun(_Config) ->
expect_badfun(X, catch X(put(?FUNCTION_NAME, of_course))),
of_course = erase(?FUNCTION_NAME),
+ %% A literal as a Fun used to crash the code generator. This only happened
+ %% when type optimization had reduced `Fun` to a literal, hence the match.
+ Literal = fun(literal = Fun) ->
+ Fun()
+ end,
+ expect_badfun(literal, catch Literal(literal)),
+
ok.
expect_badfun(Term, Exit) ->
diff --git a/lib/compiler/test/guard_SUITE.erl b/lib/compiler/test/guard_SUITE.erl
index 73a8dc0fda..ed0a56f064 100644
--- a/lib/compiler/test/guard_SUITE.erl
+++ b/lib/compiler/test/guard_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. 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.
@@ -35,8 +35,7 @@
basic_andalso_orelse/1,traverse_dcd/1,
check_qlc_hrl/1,andalso_semi/1,t_tuple_size/1,binary_part/1,
bad_constants/1,bad_guards/1,
- guard_in_catch/1,beam_bool_SUITE/1,
- cover_beam_dead/1]).
+ guard_in_catch/1,beam_bool_SUITE/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -54,8 +53,7 @@ groups() ->
rel_ops,rel_op_combinations,
literal_type_tests,basic_andalso_orelse,traverse_dcd,
check_qlc_hrl,andalso_semi,t_tuple_size,binary_part,
- bad_constants,bad_guards,guard_in_catch,beam_bool_SUITE,
- cover_beam_dead]}].
+ bad_constants,bad_guards,guard_in_catch,beam_bool_SUITE]}].
init_per_suite(Config) ->
test_lib:recompile(?MODULE),
@@ -1297,6 +1295,32 @@ rel_ops(Config) when is_list(Config) ->
Empty = id([]),
?T(==, [], Empty),
+ %% Cover beam_ssa_dead:turn_op('/=').
+ ok = (fun(A, B) when is_atom(A) ->
+ X = id(A /= B),
+ if
+ X -> ok;
+ true -> error
+ end
+ end)(a, b),
+ ok = (fun(A, B) when is_atom(A) ->
+ X = id(B /= A),
+ if
+ X -> ok;
+ true -> error
+ end
+ end)(a, b),
+
+ %% Cover beam_ssa_dead.
+ Arrow = fun([T1,T2]) when T1 == $>, T2 == $>;
+ T1 == $<, T2 == $| -> true;
+ (_) -> false
+ end,
+ true = Arrow(">>"),
+ true = Arrow("<|"),
+ false = Arrow("><"),
+ false = Arrow(""),
+
ok.
-undef(TestOp).
@@ -1330,6 +1354,9 @@ rel_op_combinations_1(N, Digits) ->
Bool = is_digit_6(N),
Bool = is_digit_7(N),
Bool = is_digit_8(N),
+ Bool = is_digit_9(42, N),
+ Bool = is_digit_10(N, 0),
+ Bool = is_digit_11(N, 0),
rel_op_combinations_1(N-1, Digits).
is_digit_1(X) when 16#0660 =< X, X =< 16#0669 -> true;
@@ -1373,6 +1400,24 @@ is_digit_8(X) when X =< 16#0669, X > (16#0660-1) -> true;
is_digit_8(16#0670) -> false;
is_digit_8(_) -> false.
+is_digit_9(A, 0) when A =:= 42 -> false;
+is_digit_9(_, X) when X > 16#065F, X < 16#066A -> true;
+is_digit_9(_, X) when 16#0030 =< X, X =< 16#0039 -> true;
+is_digit_9(_, X) when 16#06F0 =< X, X =< 16#06F9 -> true;
+is_digit_9(_, _) -> false.
+
+is_digit_10(0, 0) -> false;
+is_digit_10(X, _) when X < 16#066A, 16#0660 =< X -> true;
+is_digit_10(X, _) when 16#0030 =< X, X =< 16#0039 -> true;
+is_digit_10(X, _) when 16#06F0 =< X, X =< 16#06F9 -> true;
+is_digit_10(_, _) -> false.
+
+is_digit_11(0, 0) -> false;
+is_digit_11(X, _) when X =< 16#0669, 16#0660 =< X -> true;
+is_digit_11(X, _) when 16#0030 =< X, X =< 16#0039 -> true;
+is_digit_11(X, _) when 16#06F0 =< X, X =< 16#06F9 -> true;
+is_digit_11(_, _) -> false.
+
rel_op_combinations_2(0, _) ->
ok;
rel_op_combinations_2(N, Range) ->
@@ -1473,6 +1518,7 @@ rel_op_combinations_3(N, Red) ->
Val = redundant_9(N),
Val = redundant_10(N),
Val = redundant_11(N),
+ Val = redundant_11(N),
rel_op_combinations_3(N-1, Red).
redundant_1(X) when X >= 51, X =< 80 -> 5*X;
@@ -1527,6 +1573,10 @@ redundant_11(X) when X =:= 10 -> 2*X;
redundant_11(X) when X >= 51, X =< 80 -> 5*X;
redundant_11(_) -> none.
+redundant_12(X) when X >= 50, X =< 80 -> 2*X;
+redundant_12(X) when X < 51 -> 5*X;
+redundant_12(_) -> none.
+
%% Test type tests on literal values. (From emulator test suites.)
literal_type_tests(Config) when is_list(Config) ->
case ?MODULE of
@@ -1779,16 +1829,6 @@ t_tuple_size(Config) when is_list(Config) ->
error = ludicrous_tuple_size({a,b,c}),
error = ludicrous_tuple_size([a,b,c]),
- %% Test the "unsafe case" - the register assigned the tuple size is
- %% not killed.
- DataDir = test_lib:get_data_dir(Config),
- File = filename:join(DataDir, "guard_SUITE_tuple_size"),
- {ok,Mod,Code} = compile:file(File, [from_asm,binary]),
- code:load_binary(Mod, File, Code),
- 14 = Mod:t({1,2,3,4}),
- _ = code:delete(Mod),
- _ = code:purge(Mod),
-
good_ip({1,2,3,4}),
good_ip({1,2,3,4,5,6,7,8}),
error = validate_ip({42,11}),
@@ -2221,32 +2261,6 @@ maps() ->
evidence(#{0 := Charge}) when 0; #{[] => Charge} == #{[] => 42} ->
ok.
-cover_beam_dead(_Config) ->
- Mod = ?FUNCTION_NAME,
- Attr = [],
- Fs = [{function,test,1,2,
- [{label,1},
- {line,[]},
- {func_info,{atom,Mod},{atom,test},1},
- {label,2},
- %% Cover beam_dead:turn_op/1 using swapped operand order.
- {test,is_ne_exact,{f,3},[{integer,1},{x,0}]},
- {test,is_eq_exact,{f,1},[{atom,a},{x,0}]},
- {label,3},
- {move,{atom,ok},{x,0}},
- return]}],
- Exp = [{test,1}],
- Asm = {Mod,Exp,Attr,Fs,3},
- {ok,Mod,Beam} = compile:forms(Asm, [from_asm,binary,report]),
- {module,Mod} = code:load_binary(Mod, Mod, Beam),
- ok = Mod:test(1),
- ok = Mod:test(a),
- {'EXIT',_} = (catch Mod:test(other)),
- true = code:delete(Mod),
- _ = code:purge(Mod),
-
- ok.
-
%% Call this function to turn off constant propagation.
id(I) -> I.
diff --git a/lib/compiler/test/guard_SUITE_data/guard_SUITE_tuple_size.S b/lib/compiler/test/guard_SUITE_data/guard_SUITE_tuple_size.S
deleted file mode 100644
index cffb792920..0000000000
--- a/lib/compiler/test/guard_SUITE_data/guard_SUITE_tuple_size.S
+++ /dev/null
@@ -1,30 +0,0 @@
-{module, guard_SUITE_tuple_size}. %% version = 0
-
-{exports, [{t,1}]}.
-
-{attributes, []}.
-
-{labels, 5}.
-
-
-{function, t, 1, 2}.
- {label,1}.
- {func_info,{atom,guard_SUITE_tuple_size},{atom,t},1}.
- {label,2}.
- {bif,tuple_size,{f,4},[{x,0}],{x,1}}.
- {test,is_eq_exact,{f,4},[{x,1},{integer,4}]}.
- {test,is_tuple,{f,3},[{x,0}]}.
- {test,test_arity,{f,3},[{x,0},4]}.
- {get_tuple_element,{x,0},0,{x,5}}.
- {get_tuple_element,{x,0},1,{x,2}}.
- {get_tuple_element,{x,0},2,{x,3}}.
- {get_tuple_element,{x,0},3,{x,4}}.
- {gc_bif,'+',{f,0},6,[{x,1},{x,2}],{x,0}}.
- {gc_bif,'+',{f,0},6,[{x,0},{x,3}],{x,0}}.
- {gc_bif,'+',{f,0},6,[{x,0},{x,4}],{x,0}}.
- {gc_bif,'+',{f,0},6,[{x,0},{x,5}],{x,0}}.
- return.
- {label,3}.
- {badmatch,{x,0}}.
- {label,4}.
- {jump,{f,1}}.
diff --git a/lib/compiler/test/inline_SUITE.erl b/lib/compiler/test/inline_SUITE.erl
index e03769012b..aff1a56c47 100644
--- a/lib/compiler/test/inline_SUITE.erl
+++ b/lib/compiler/test/inline_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. 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.
@@ -42,13 +42,9 @@ groups() ->
init_per_suite(Config) ->
test_lib:recompile(?MODULE),
- Pa = "-pa " ++ filename:dirname(code:which(?MODULE)),
- {ok,Node} = start_node(compiler, Pa),
- [{testing_node,Node}|Config].
+ Config.
-end_per_suite(Config) ->
- Node = proplists:get_value(testing_node, Config),
- test_server:stop_node(Node),
+end_per_suite(_Config) ->
ok.
init_per_group(_GroupName, Config) ->
@@ -89,7 +85,6 @@ attribute(Config) when is_list(Config) ->
?comp(maps_inline_test).
try_inline(Mod, Config) ->
- Node = proplists:get_value(testing_node, Config),
Src = filename:join(proplists:get_value(data_dir, Config),
atom_to_list(Mod)),
Out = proplists:get_value(priv_dir,Config),
@@ -100,7 +95,7 @@ try_inline(Mod, Config) ->
bin_opt_info,clint,ssalint]),
ct:timetrap({minutes,10}),
- NormalResult = rpc:call(Node, ?MODULE, load_and_call, [Out,Mod]),
+ NormalResult = load_and_call(Out, Mod),
%% Inlining.
io:format("Compiling with old inliner: ~s\n", [Src]),
@@ -109,7 +104,7 @@ try_inline(Mod, Config) ->
%% Run inlined code.
ct:timetrap({minutes,10}),
- OldInlinedResult = rpc:call(Node, ?MODULE, load_and_call, [Out,Mod]),
+ OldInlinedResult = load_and_call(Out, Mod),
%% Compare results.
compare(NormalResult, OldInlinedResult),
@@ -122,7 +117,7 @@ try_inline(Mod, Config) ->
%% Run inlined code.
ct:timetrap({minutes,10}),
- InlinedResult = rpc:call(Node, ?MODULE, load_and_call, [Out,Mod]),
+ InlinedResult = load_and_call(Out, Mod),
%% Compare results.
compare(NormalResult, InlinedResult),
@@ -131,6 +126,11 @@ try_inline(Mod, Config) ->
%% Delete Beam file.
ok = file:delete(filename:join(Out, atom_to_list(Mod)++code:objfile_extension())),
+ %% Delete loaded module.
+ _ = code:purge(Mod),
+ _ = code:delete(Mod),
+ _ = code:purge(Mod),
+
ok.
compare(Same, Same) -> ok;
@@ -144,12 +144,6 @@ compare([H1|_], [H2|_]) ->
ct:fail(different);
compare([], []) -> ok.
-start_node(Name, Args) ->
- case test_server:start_node(Name, slave, [{args,Args}]) of
- {ok,Node} -> {ok, Node};
- Error -> ct:fail(Error)
- end.
-
load_and_call(Out, Module) ->
io:format("Loading...\n",[]),
code:purge(Module),
@@ -350,10 +344,8 @@ otp_7223_2({a}) ->
1.
coverage(Config) when is_list(Config) ->
- Mod = bsdecode,
+ Mod = attribute,
Src = filename:join(proplists:get_value(data_dir, Config), Mod),
{ok,Mod,_} = compile:file(Src, [binary,report,{inline,0},
clint,ssalint]),
- {ok,Mod,_} = compile:file(Src, [binary,report,{inline,20},
- verbose,clint,ssalint]),
ok.
diff --git a/lib/compiler/test/inline_SUITE_data/barnes2.erl b/lib/compiler/test/inline_SUITE_data/barnes2.erl
index a986331060..49e9bdfb6b 100644
--- a/lib/compiler/test/inline_SUITE_data/barnes2.erl
+++ b/lib/compiler/test/inline_SUITE_data/barnes2.erl
@@ -6,7 +6,7 @@
?MODULE() ->
Stars = create_scenario(1000, 1.0),
R = hd(loop(10,1000.0,Stars,0)),
- Str = lists:flatten(io:lib_format("~s", [R])),
+ Str = lists:flatten(io_lib:format("~p", [R])),
{R,Str =:= {1.00000,-1.92269e+4,-1.92269e+4,2.86459e-2,2.86459e-2}}.
create_scenario(N, M) ->
diff --git a/lib/compiler/test/map_SUITE.erl b/lib/compiler/test/map_SUITE.erl
index 3e0ab78390..440b632381 100644
--- a/lib/compiler/test/map_SUITE.erl
+++ b/lib/compiler/test/map_SUITE.erl
@@ -70,7 +70,10 @@
t_bad_update/1,
%% new in OTP 21
- t_reused_key_variable/1
+ t_reused_key_variable/1,
+
+ %% new in OTP 22
+ t_mixed_clause/1,cover_beam_trim/1
]).
suite() -> [].
@@ -124,7 +127,10 @@ all() ->
t_bad_update,
%% new in OTP 21
- t_reused_key_variable
+ t_reused_key_variable,
+
+ %% new in OTP 22
+ t_mixed_clause,cover_beam_trim
].
groups() -> [].
@@ -1373,22 +1379,22 @@ map_usage(Def, Used) ->
t_guard_sequence(Config) when is_list(Config) ->
- {1, "a"} = map_guard_sequence_1(#{seq=>1,val=>id("a")}),
- {2, "b"} = map_guard_sequence_1(#{seq=>2,val=>id("b")}),
- {3, "c"} = map_guard_sequence_1(#{seq=>3,val=>id("c")}),
- {4, "d"} = map_guard_sequence_1(#{seq=>4,val=>id("d")}),
- {5, "e"} = map_guard_sequence_1(#{seq=>5,val=>id("e")}),
-
- {1,M1} = map_guard_sequence_2(M1 = id(#{a=>3})),
- {2,M2} = map_guard_sequence_2(M2 = id(#{a=>4, b=>4})),
- {3,gg,M3} = map_guard_sequence_2(M3 = id(#{a=>gg, b=>4})),
- {4,sc,sc,M4} = map_guard_sequence_2(M4 = id(#{a=>sc, b=>3, c=>sc2})),
- {5,kk,kk,M5} = map_guard_sequence_2(M5 = id(#{a=>kk, b=>other, c=>sc2})),
-
- %% error case
- {'EXIT',{function_clause,_}} = (catch map_guard_sequence_1(#{seq=>6,val=>id("e")})),
- {'EXIT',{function_clause,_}} = (catch map_guard_sequence_2(#{b=>5})),
- ok.
+ {1, "a"} = map_guard_sequence_1(#{seq=>1,val=>id("a")}),
+ {2, "b"} = map_guard_sequence_1(#{seq=>2,val=>id("b")}),
+ {3, "c"} = map_guard_sequence_1(#{seq=>3,val=>id("c")}),
+ {4, "d"} = map_guard_sequence_1(#{seq=>4,val=>id("d")}),
+ {5, "e"} = map_guard_sequence_1(#{seq=>5,val=>id("e")}),
+
+ {1,M1} = map_guard_sequence_2(M1 = id(#{a=>3})),
+ {2,M2} = map_guard_sequence_2(M2 = id(#{a=>4, b=>4})),
+ {3,gg,M3} = map_guard_sequence_2(M3 = id(#{a=>gg, b=>4})),
+ {4,sc,sc,M4} = map_guard_sequence_2(M4 = id(#{a=>sc, b=>3, c=>sc2})),
+ {5,kk,kk,M5} = map_guard_sequence_2(M5 = id(#{a=>kk, b=>other, c=>sc2})),
+
+ %% error case
+ {'EXIT',{function_clause,_}} = (catch map_guard_sequence_1(#{seq=>6,val=>id("e")})),
+ {'EXIT',{function_clause,_}} = (catch map_guard_sequence_2(#{b=>5})),
+ ok.
t_guard_sequence_large(Config) when is_list(Config) ->
M0 = id(#{ 10=>a0,20=>b0,30=>"c0","40"=>"d0",<<"50">>=>"e0",{["00",03]}=>"10",
@@ -1443,21 +1449,21 @@ t_guard_sequence_large(Config) when is_list(Config) ->
18=>a8,28=>b8,38=>"c8","48"=>"d8",<<"58">>=>"e8",{["08"]}=>"18",
19=>a9,29=>b9,39=>"c9","49"=>"d9",<<"59">>=>"e9",{["09"]}=>"19" } => "large map key 2" }),
- {1, "a"} = map_guard_sequence_1(M0#{seq=>1,val=>id("a")}),
- {2, "b"} = map_guard_sequence_1(M0#{seq=>2,val=>id("b")}),
- {3, "c"} = map_guard_sequence_1(M0#{seq=>3,val=>id("c")}),
- {4, "d"} = map_guard_sequence_1(M0#{seq=>4,val=>id("d")}),
- {5, "e"} = map_guard_sequence_1(M0#{seq=>5,val=>id("e")}),
+ {1, "a"} = map_guard_sequence_1(M0#{seq=>1,val=>id("a")}),
+ {2, "b"} = map_guard_sequence_1(M0#{seq=>2,val=>id("b")}),
+ {3, "c"} = map_guard_sequence_1(M0#{seq=>3,val=>id("c")}),
+ {4, "d"} = map_guard_sequence_1(M0#{seq=>4,val=>id("d")}),
+ {5, "e"} = map_guard_sequence_1(M0#{seq=>5,val=>id("e")}),
- {1,M1} = map_guard_sequence_2(M1 = id(M0#{a=>3})),
- {2,M2} = map_guard_sequence_2(M2 = id(M0#{a=>4, b=>4})),
- {3,gg,M3} = map_guard_sequence_2(M3 = id(M0#{a=>gg, b=>4})),
- {4,sc,sc,M4} = map_guard_sequence_2(M4 = id(M0#{a=>sc, b=>3, c=>sc2})),
- {5,kk,kk,M5} = map_guard_sequence_2(M5 = id(M0#{a=>kk, b=>other, c=>sc2})),
+ {1,M1} = map_guard_sequence_2(M1 = id(M0#{a=>3})),
+ {2,M2} = map_guard_sequence_2(M2 = id(M0#{a=>4, b=>4})),
+ {3,gg,M3} = map_guard_sequence_2(M3 = id(M0#{a=>gg, b=>4})),
+ {4,sc,sc,M4} = map_guard_sequence_2(M4 = id(M0#{a=>sc, b=>3, c=>sc2})),
+ {5,kk,kk,M5} = map_guard_sequence_2(M5 = id(M0#{a=>kk, b=>other, c=>sc2})),
- {'EXIT',{function_clause,_}} = (catch map_guard_sequence_1(M0#{seq=>6,val=>id("e")})),
- {'EXIT',{function_clause,_}} = (catch map_guard_sequence_2(M0#{b=>5})),
- ok.
+ {'EXIT',{function_clause,_}} = (catch map_guard_sequence_1(M0#{seq=>6,val=>id("e")})),
+ {'EXIT',{function_clause,_}} = (catch map_guard_sequence_2(M0#{b=>5})),
+ ok.
map_guard_sequence_1(#{seq:=1=Seq, val:=Val}) -> {Seq,Val};
map_guard_sequence_1(#{seq:=2=Seq, val:=Val}) -> {Seq,Val};
@@ -2079,7 +2085,7 @@ t_register_corruption(Config) when is_list(Config) ->
{3,wanted,<<"value">>} = register_corruption_foo(wanted,M),
ok.
-register_corruption_foo(A,#{a := V1, b := V2}) ->
+register_corruption_foo(_,#{a := V1, b := V2}) ->
register_corruption_dummy_call(1,V1,V2);
register_corruption_foo(A,#{b := V}) ->
register_corruption_dummy_call(2,A,V);
@@ -2161,6 +2167,31 @@ t_reused_key_variable(Config) when is_list(Config) ->
ok
end.
+t_mixed_clause(_Config) ->
+ put(fool_inliner, x),
+ K = get(fool_inliner),
+ {42,100} = case #{K=>42,y=>100} of
+ #{x:=X,y:=Y} ->
+ {X,Y}
+ end,
+ nomatch = case #{K=>42,y=>100} of
+ #{x:=X,y:=0} ->
+ {X,Y};
+ #{} ->
+ nomatch
+ end,
+ ok.
+
+cover_beam_trim(_Config) ->
+ val = do_cover_beam_trim(id, max, max, id, #{id=>val}),
+ ok.
+
+do_cover_beam_trim(Id, OldMax, Max, Id, M) ->
+ OldMax = id(Max),
+ #{Id:=Val} = id(M),
+ Val.
+
+
%% aux
rand_terms(0) -> [];
diff --git a/lib/compiler/test/match_SUITE.erl b/lib/compiler/test/match_SUITE.erl
index e3f842b668..94bfbb0efe 100644
--- a/lib/compiler/test/match_SUITE.erl
+++ b/lib/compiler/test/match_SUITE.erl
@@ -25,7 +25,7 @@
match_in_call/1,untuplify/1,shortcut_boolean/1,letify_guard/1,
selectify/1,deselectify/1,underscore/1,match_map/1,map_vars_used/1,
coverage/1,grab_bag/1,literal_binary/1,
- unary_op/1]).
+ unary_op/1,eq_types/1,match_after_return/1]).
-include_lib("common_test/include/ct.hrl").
@@ -40,7 +40,8 @@ groups() ->
match_in_call,untuplify,
shortcut_boolean,letify_guard,selectify,deselectify,
underscore,match_map,map_vars_used,coverage,
- grab_bag,literal_binary,unary_op]}].
+ grab_bag,literal_binary,unary_op,eq_types,
+ match_after_return]}].
init_per_suite(Config) ->
@@ -254,6 +255,8 @@ non_matching_aliases(_Config) ->
none = mixed_aliases([d]),
none = mixed_aliases({a,42}),
none = mixed_aliases(42),
+ none = mixed_aliases(<<6789:16>>),
+ none = mixed_aliases(#{key=>value}),
{'EXIT',{{badmatch,42},_}} = (catch nomatch_alias(42)),
{'EXIT',{{badmatch,job},_}} = (catch entirely()),
@@ -279,6 +282,16 @@ mixed_aliases(<<X:8>> = x) -> {a,X};
mixed_aliases([b] = <<X:8>>) -> {b,X};
mixed_aliases(<<X:8>> = {a,X}) -> {c,X};
mixed_aliases([X] = <<X:8>>) -> {d,X};
+mixed_aliases(<<X:16>> = X) -> {e,X};
+mixed_aliases(X = <<X:16>>) -> {f,X};
+mixed_aliases(<<X:16,_/binary>> = X) -> {g,X};
+mixed_aliases(X = <<X:16,_/binary>>) -> {h,X};
+mixed_aliases(X = #{key:=X}) -> {i,X};
+mixed_aliases(#{key:=X} = X) -> {j,X};
+mixed_aliases([X] = #{key:=X}) -> {k,X};
+mixed_aliases(#{key:=X} = [X]) -> {l,X};
+mixed_aliases({a,X} = #{key:=X}) -> {m,X};
+mixed_aliases(#{key:=X} = {a,X}) -> {n,X};
mixed_aliases(_) -> none.
nomatch_alias(I) ->
@@ -378,6 +391,13 @@ untuplify(Config) when is_list(Config) ->
%% We do this to cover sys_core_fold:unalias_pat/1.
{1,2,3,4,alias,{[1,2],{3,4},alias}} = untuplify_1([1,2], {3,4}, alias),
error = untuplify_1([1,2], {3,4}, 42),
+
+ %% Test that a previous bug in v3_codegen is gone. (The sinking of
+ %% stack frames into only the case arms that needed them was not always
+ %% safe.)
+ [33, -1, -33, 1] = untuplify_2(32, 65),
+ {33, 1, -33, -1} = untuplify_2(65, 32),
+
ok.
untuplify_1(A, B, C) ->
@@ -390,6 +410,21 @@ untuplify_1(A, B, C) ->
error
end.
+untuplify_2(V1, V2) ->
+ {D1,D2,D3,D4} =
+ if V1 > V2 ->
+ %% The 1 value was overwritten by the value of V2-V1.
+ {V1-V2, 1, V2-V1, -1};
+ true ->
+ {V2-V1, -1, V1-V2, 1}
+ end,
+ if
+ D2 > D4 ->
+ {D1, D2, D3, D4};
+ true ->
+ [D1, D2, D3, D4]
+ end.
+
%% Coverage of beam_dead:shortcut_boolean_label/4.
shortcut_boolean(Config) when is_list(Config) ->
false = shortcut_boolean_1([0]),
@@ -434,6 +469,7 @@ letify_guard(A, B) ->
selectify(Config) when is_list(Config) ->
integer = sel_different_types({r,42}),
atom = sel_different_types({r,forty_two}),
+ float = sel_different_types({r,100.0}),
none = sel_different_types({r,18}),
{'EXIT',_} = (catch sel_different_types([a,b,c])),
@@ -444,12 +480,15 @@ selectify(Config) when is_list(Config) ->
integer42 = sel_same_value2(42),
integer43 = sel_same_value2(43),
error = sel_same_value2(44),
+
ok.
sel_different_types({r,_}=T) when element(2, T) =:= forty_two ->
atom;
sel_different_types({r,_}=T) when element(2, T) =:= 42 ->
integer;
+sel_different_types({r,_}=T) when element(2, T) =:= 100.0 ->
+ float;
sel_different_types({r,_}) ->
none.
@@ -467,9 +506,8 @@ sel_same_value2(V) when V =:= 42; V =:= 43 ->
sel_same_value2(_) ->
error.
-%% Test deconstruction of select_val instructions in beam_peep into
-%% regular tests with just one possible value left. Hitting proper cases
-%% in beam_peep relies on unification of labels by beam_jump.
+%% Test deconstruction of select_val instructions to regular tests
+%% with zero or one values left.
deselectify(Config) when is_list(Config) ->
one_or_other = desel_tuple_arity({1}),
@@ -490,7 +528,31 @@ deselectify(Config) when is_list(Config) ->
one_or_other = dsel_atom_typecheck(one),
two = dsel_atom_typecheck(two),
- one_or_other = dsel_atom_typecheck(three).
+ one_or_other = dsel_atom_typecheck(three),
+
+ %% Cover deconstruction of select_val instructions in
+ %% beam_peep.
+
+ stop = dsel_peek_0(stop),
+ ignore = dsel_peek_0(ignore),
+ Config = dsel_peek_0(Config),
+
+ stop = dsel_peek_1(stop, any),
+ Config = dsel_peek_1(ignore, Config),
+ other = dsel_peek_1(other, ignored),
+
+ 0 = dsel_peek_2(0, any),
+ Config = dsel_peek_2(1, Config),
+ 2 = dsel_peek_2(2, ignored),
+
+ true = dsel_peek_3(true),
+ false = dsel_peek_3(false),
+ {error,Config} = dsel_peek_3(Config),
+
+ ok.
+
+%% The following will be optimized by the sharing optimizations
+%% in beam_ssa_opt.
desel_tuple_arity(Tuple) when is_tuple(Tuple) ->
case Tuple of
@@ -527,6 +589,39 @@ dsel_atom_typecheck(Val) when is_atom(Val) ->
_ -> one_or_other
end.
+%% The following functions are carefully crafted so that the sharing
+%% optimizations in beam_ssa_opt can't be applied. After applying the
+%% beam_jump:eliminate_moves/1 optimization and beam_clean:clean_labels/1
+%% has unified labels, beam_peep is able to optimize these functions.
+
+dsel_peek_0(A0) ->
+ case id(A0) of
+ stop -> stop;
+ ignore -> ignore;
+ A -> A
+ end.
+
+dsel_peek_1(A0, B) ->
+ case id(A0) of
+ stop -> stop;
+ ignore -> B;
+ A -> A
+ end.
+
+dsel_peek_2(A0, B) ->
+ case id(A0) of
+ 0 -> 0;
+ 1 -> B;
+ A -> A
+ end.
+
+dsel_peek_3(A0) ->
+ case id(A0) of
+ true -> true;
+ false -> false;
+ Other -> {error,Other}
+ end.
+
underscore(Config) when is_list(Config) ->
case Config of
[] ->
@@ -569,13 +664,26 @@ do_map_vars_used(X, Y, Map) ->
Val
end.
+-record(coverage_id, {bool=false,id}).
coverage(Config) when is_list(Config) ->
%% Cover beam_dead.
ok = coverage_1(x, a),
ok = coverage_1(x, b),
%% Cover sys_pre_expand.
- ok = coverage_3("abc").
+ ok = coverage_3("abc"),
+
+ %% Cover beam_ssa_dead.
+ {expr,key} = coverage_4([literal,get], [[expr,key]]),
+ {expr,key} = coverage_4([expr,key], []),
+
+ a = coverage_5([8,8,8], #coverage_id{bool=true}),
+ b = coverage_5([], #coverage_id{bool=true}),
+
+ %% Cover beam_ssa_opt.
+ ok = coverage_6(),
+
+ ok.
coverage_1(B, Tag) ->
case Tag of
@@ -588,6 +696,37 @@ coverage_2(2, b, x) -> ok.
coverage_3([$a]++[]++"bc") -> ok.
+%% Cover beam_ssa_dead:eval_type_test_1(is_nonempty_list, Arg).
+coverage_4([literal,get], [Expr]) ->
+ coverage_4(Expr, []);
+coverage_4([Expr,Key], []) ->
+ {Expr,Key}.
+
+%% Cover beam_ssa_dead:eval_type_test_1(is_tagged_tuple, Arg).
+coverage_5(Config, TermId)
+ when TermId =:= #coverage_id{bool=true},
+ Config =:= [8,8,8] ->
+ a;
+coverage_5(_Config, #coverage_id{bool=true}) ->
+ b.
+
+coverage_6() ->
+ X = 17,
+ case
+ case id(1) > 0 of
+ true ->
+ 17;
+ false ->
+ 42
+ end
+ of
+ X ->
+ ok;
+ V ->
+ %% Cover beam_ssa_opt:make_literal/2.
+ error([error,X,V])
+ end.
+
grab_bag(_Config) ->
[_|T] = id([a,b,c]),
[b,c] = id(T),
@@ -732,5 +871,35 @@ unary_op_1(Vop@1) ->
end
end.
+eq_types(_Config) ->
+ Ref = make_ref(),
+ Ref = eq_types(Ref, any),
+ ok.
+
+eq_types(A, B) ->
+ %% {put_tuple2,{y,0},{list,[{x,0},{x,1}]}}.
+ Term0 = {A, B},
+ Term = id(Term0),
+
+ %% {test,is_eq_exact,{f,3},[{y,0},{x,0}]}.
+ %% Here beam_validator must infer that {x,0} has the
+ %% same type as {y,0}.
+ Term = Term0,
+
+ %% {get_tuple_element,{x,0},0,{x,0}}.
+ {Ref22,_} = Term,
+
+ Ref22.
+
+match_after_return(Config) when is_list(Config) ->
+ %% The return type of the following call will never match the 'wont_happen'
+ %% clauses below, and the beam_ssa_type was clever enough to see that but
+ %% didn't remove the blocks, so it crashed when trying to extract A.
+ ok = case mar_test_tuple(erlang:unique_integer()) of
+ {gurka, never_matches, A} -> {wont_happen, A};
+ _ -> ok
+ end.
+
+mar_test_tuple(I) -> {gurka, I}.
id(I) -> I.
diff --git a/lib/compiler/test/misc_SUITE.erl b/lib/compiler/test/misc_SUITE.erl
index beae5eb618..a0b415ceaa 100644
--- a/lib/compiler/test/misc_SUITE.erl
+++ b/lib/compiler/test/misc_SUITE.erl
@@ -161,14 +161,13 @@ md5_1(Beam) ->
%% Cover some code that handles internal errors.
silly_coverage(Config) when is_list(Config) ->
- %% sys_core_fold, sys_core_alias, sys_core_bsm, sys_core_setel, v3_kernel
+ %% sys_core_fold, sys_core_alias, sys_core_bsm, v3_kernel
BadCoreErlang = {c_module,[],
name,[],[],
[{{c_var,[],{foo,2}},seriously_bad_body}]},
expect_error(fun() -> sys_core_fold:module(BadCoreErlang, []) end),
expect_error(fun() -> sys_core_alias:module(BadCoreErlang, []) end),
expect_error(fun() -> sys_core_bsm:module(BadCoreErlang, []) end),
- expect_error(fun() -> sys_core_dsetel:module(BadCoreErlang, []) end),
expect_error(fun() -> v3_kernel:module(BadCoreErlang, []) end),
%% beam_kernel_to_ssa
@@ -183,17 +182,24 @@ silly_coverage(Config) when is_list(Config) ->
%% beam_ssa_lint
%% beam_ssa_recv
+ %% beam_ssa_share
%% beam_ssa_pre_codegen
- %% beam_ssa_opt
%% beam_ssa_codegen
BadSSA = {b_module,#{},a,b,c,
[{b_function,#{func_info=>{mod,foo,0}},args,bad_blocks,0}]},
expect_error(fun() -> beam_ssa_lint:module(BadSSA, []) end),
expect_error(fun() -> beam_ssa_recv:module(BadSSA, []) end),
+ expect_error(fun() -> beam_ssa_share:module(BadSSA, []) end),
expect_error(fun() -> beam_ssa_pre_codegen:module(BadSSA, []) end),
- expect_error(fun() -> beam_ssa_opt:module(BadSSA, []) end),
expect_error(fun() -> beam_ssa_codegen:module(BadSSA, []) end),
+ %% beam_ssa_opt
+ BadSSABlocks = #{0 => {b_blk,#{},[bad_code],{b_ret,#{},arg}}},
+ BadSSAOpt = {b_module,#{},a,[],c,
+ [{b_function,#{func_info=>{mod,foo,0}},[],
+ BadSSABlocks,0}]},
+ expect_error(fun() -> beam_ssa_opt:module(BadSSAOpt, []) end),
+
%% beam_ssa_lint, beam_ssa_pp
{error,[{_,Errors}]} = beam_ssa_lint:module(bad_ssa_lint_input(), []),
_ = [io:put_chars(Mod:format_error(Reason)) ||
@@ -221,10 +227,6 @@ silly_coverage(Config) when is_list(Config) ->
{label,2}|non_proper_list]}],99},
expect_error(fun() -> beam_block:module(BlockInput, []) end),
- %% beam_bs
- BsInput = BlockInput,
- expect_error(fun() -> beam_bs:module(BsInput, []) end),
-
%% beam_except
ExceptInput = {?MODULE,[{foo,0}],[],
[{function,foo,0,2,
@@ -234,15 +236,9 @@ silly_coverage(Config) when is_list(Config) ->
{label,2}|non_proper_list]}],99},
expect_error(fun() -> beam_except:module(ExceptInput, []) end),
- %% beam_dead. This is tricky. Our function must look OK to
- %% beam_utils:clean_labels/1, but must crash beam_dead.
- DeadInput = {?MODULE,[{foo,0}],[],
- [{function,foo,0,2,
- [{label,1},
- {func_info,{atom,?MODULE},{atom,foo},0},
- {label,2},
- {test,is_eq_exact,{f,1},[bad,operands]}]}],99},
- expect_error(fun() -> beam_dead:module(DeadInput, []) end),
+ %% beam_jump
+ JumpInput = BlockInput,
+ expect_error(fun() -> beam_jump:module(JumpInput, []) end),
%% beam_clean
CleanInput = {?MODULE,[{foo,0}],[],
@@ -253,6 +249,10 @@ silly_coverage(Config) when is_list(Config) ->
{jump,{f,42}}]}],99},
expect_error(fun() -> beam_clean:module(CleanInput, []) end),
+ %% beam_jump
+ TrimInput = BlockInput,
+ expect_error(fun() -> beam_trim:module(TrimInput, []) end),
+
%% beam_peep. This is tricky. Use a select instruction with
%% an odd number of elements in the list to crash
%% prune_redundant_values/2 but not beam_clean:clean_labels/1.
@@ -260,21 +260,10 @@ silly_coverage(Config) when is_list(Config) ->
[{function,foo,0,2,
[{label,1},
{func_info,{atom,?MODULE},{atom,foo},0},
- {label,2},{select,op,r,{f,2},[{f,2}]}]}],
+ {label,2},{select,select_val,r,{f,2},[{f,2}]}]}],
2},
expect_error(fun() -> beam_peep:module(PeepInput, []) end),
- %% beam_bsm. This is tricky. Our function must be sane enough to not crash
- %% btb_index/1, but must crash the main optimization pass.
- BsmInput = {?MODULE,[{foo,0}],[],
- [{function,foo,0,2,
- [{label,1},
- {func_info,{atom,?MODULE},{atom,foo},0},
- {label,2},
- {test,bs_get_binary2,{f,99},0,[{x,0},{atom,all},1,[]],{x,0}},
- {block,[a|b]}]}],0},
- expect_error(fun() -> beam_bsm:module(BsmInput, []) end),
-
BeamZInput = {?MODULE,[{foo,0}],[],
[{function,foo,0,2,
[{label,1},
diff --git a/lib/compiler/test/overridden_bif_SUITE.erl b/lib/compiler/test/overridden_bif_SUITE.erl
index a46abe8dcf..6b8a9591c9 100644
--- a/lib/compiler/test/overridden_bif_SUITE.erl
+++ b/lib/compiler/test/overridden_bif_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/receive_SUITE.erl b/lib/compiler/test/receive_SUITE.erl
index 4219768d6f..0038eb1a4b 100644
--- a/lib/compiler/test/receive_SUITE.erl
+++ b/lib/compiler/test/receive_SUITE.erl
@@ -25,7 +25,8 @@
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
export/1,recv/1,coverage/1,otp_7980/1,ref_opt/1,
- wait/1,recv_in_try/1,double_recv/1]).
+ wait/1,recv_in_try/1,double_recv/1,receive_var_zero/1,
+ match_built_terms/1]).
-include_lib("common_test/include/ct.hrl").
@@ -45,7 +46,8 @@ all() ->
groups() ->
[{p,test_lib:parallel(),
[recv,coverage,otp_7980,ref_opt,export,wait,
- recv_in_try,double_recv]}].
+ recv_in_try,double_recv,receive_var_zero,
+ match_built_terms]}].
init_per_suite(Config) ->
@@ -378,4 +380,51 @@ do_double_recv(_, Msg) ->
error
end.
+%% Test 'after Z', when Z =:= 0 been propagated as an immediate by the type
+%% optimization pass.
+receive_var_zero(Config) when is_list(Config) ->
+ self() ! x,
+ self() ! y,
+ Z = zero(),
+ timeout = receive
+ z -> ok
+ after Z -> timeout
+ end,
+ timeout = receive
+ after Z -> timeout
+ end,
+ self() ! w,
+ receive
+ x -> ok;
+ Other ->
+ ct:fail({bad_message,Other})
+ end.
+
+zero() -> 0.
+
+%% ERL-862; the validator would explode when a term was constructed in a
+%% receive guard.
+
+-define(MATCH_BUILT_TERM(Ref, Expr),
+ (fun() ->
+ Ref = make_ref(),
+ A = id($a),
+ B = id($b),
+ Built = id(Expr),
+ self() ! {Ref, A, B},
+ receive
+ {Ref, A, B} when Expr =:= Built ->
+ ok
+ after 5000 ->
+ ct:fail("Failed to match message with term built in "
+ "receive guard.")
+ end
+ end)()).
+
+match_built_terms(Config) when is_list(Config) ->
+ ?MATCH_BUILT_TERM(Ref, [A, B]),
+ ?MATCH_BUILT_TERM(Ref, {A, B}),
+ ?MATCH_BUILT_TERM(Ref, <<A, B>>),
+ ?MATCH_BUILT_TERM(Ref, #{ 1 => A, 2 => B}).
+
id(I) -> I.
diff --git a/lib/compiler/test/record_SUITE.erl b/lib/compiler/test/record_SUITE.erl
index 118e0a241c..4ed7f39780 100644
--- a/lib/compiler/test/record_SUITE.erl
+++ b/lib/compiler/test/record_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/regressions_SUITE.erl b/lib/compiler/test/regressions_SUITE.erl
index f448d54933..39febf060f 100644
--- a/lib/compiler/test/regressions_SUITE.erl
+++ b/lib/compiler/test/regressions_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. 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.
@@ -23,7 +23,7 @@
-export([all/0,groups/0,init_per_testcase/2,end_per_testcase/2,
init_per_group/2,end_per_group/2,
- init_per_testcase/2,end_per_testcase/2,
+ init_per_suite/1,end_per_suite/1,
suite/0]).
-export([maps/1]).
diff --git a/lib/compiler/test/test_lib.erl b/lib/compiler/test/test_lib.erl
index c6baa611ec..39c26c6142 100644
--- a/lib/compiler/test/test_lib.erl
+++ b/lib/compiler/test/test_lib.erl
@@ -50,12 +50,8 @@ smoke_disasm(File) when is_list(File) ->
Res = beam_disasm:file(File),
{beam_file,_Mod} = {element(1, Res),element(2, Res)}.
-%% If we are running cover, we don't want to run test cases that
-%% invokes the compiler in parallel, as doing so would probably
-%% be slower than running them sequentially.
-
parallel() ->
- case test_server:is_cover() orelse erlang:system_info(schedulers) =:= 1 of
+ case erlang:system_info(schedulers) =:= 1 of
true -> [];
false -> [parallel]
end.
@@ -70,16 +66,24 @@ uniq() ->
opt_opts(Mod) ->
Comp = Mod:module_info(compile),
{options,Opts} = lists:keyfind(options, 1, Comp),
- lists:filter(fun(no_copt) -> true;
- (no_postopt) -> true;
- (no_ssa_opt) -> true;
- (no_recv_opt) -> true;
- (no_ssa_float) -> true;
- (no_stack_trimming) -> true;
- (debug_info) -> true;
- (inline) -> true;
- (_) -> false
- end, Opts).
+ lists:filter(fun
+ (debug_info) -> true;
+ (inline) -> true;
+ (no_bsm3) -> true;
+ (no_bsm_opt) -> true;
+ (no_copt) -> true;
+ (no_fun_opt) -> true;
+ (no_module_opt) -> true;
+ (no_postopt) -> true;
+ (no_put_tuple2) -> true;
+ (no_recv_opt) -> true;
+ (no_share_opt) -> true;
+ (no_ssa_float) -> true;
+ (no_ssa_opt) -> true;
+ (no_stack_trimming) -> true;
+ (no_type_opt) -> true;
+ (_) -> false
+ end, Opts).
%% Some test suites gets cloned (e.g. to "record_SUITE" to
%% "record_no_opt_SUITE"), but the data directory is not cloned.
@@ -89,17 +93,23 @@ get_data_dir(Config) ->
Data0 = proplists:get_value(data_dir, Config),
Opts = [{return,list}],
Data1 = re:replace(Data0, "_no_opt_SUITE", "_SUITE", Opts),
- Data = re:replace(Data1, "_post_opt_SUITE", "_SUITE", Opts),
- re:replace(Data, "_inline_SUITE", "_SUITE", Opts).
+ Data2 = re:replace(Data1, "_post_opt_SUITE", "_SUITE", Opts),
+ Data3 = re:replace(Data2, "_inline_SUITE", "_SUITE", Opts),
+ Data4 = re:replace(Data3, "_r21_SUITE", "_SUITE", Opts),
+ Data = re:replace(Data4, "_no_module_opt_SUITE", "_SUITE", Opts),
+ re:replace(Data, "_no_ssa_opt_SUITE", "_SUITE", Opts).
is_cloned_mod(Mod) ->
is_cloned_mod_1(atom_to_list(Mod)).
%% Test whether Mod is a cloned module.
-is_cloned_mod_1("no_opt_SUITE") -> true;
-is_cloned_mod_1("post_opt_SUITE") -> true;
-is_cloned_mod_1("inline_SUITE") -> true;
+is_cloned_mod_1("_no_opt_SUITE") -> true;
+is_cloned_mod_1("_no_ssa_opt_SUITE") -> true;
+is_cloned_mod_1("_post_opt_SUITE") -> true;
+is_cloned_mod_1("_inline_SUITE") -> true;
+is_cloned_mod_1("_21_SUITE") -> true;
+is_cloned_mod_1("_no_module_opt_SUITE") -> true;
is_cloned_mod_1([_|T]) -> is_cloned_mod_1(T);
is_cloned_mod_1([]) -> false.
@@ -108,18 +118,7 @@ is_cloned_mod_1([]) -> false.
p_run(Test, List) ->
S = erlang:system_info(schedulers),
- N = case test_server:is_cover() of
- false ->
- S + 1;
- true ->
- %% Cover is running. Using too many processes
- %% could slow us down. Measurements on my computer
- %% showed that using 4 parallel processes was
- %% slightly faster than using 3. Using more than
- %% 4 would not buy us much and could actually be
- %% slower.
- min(S, 4)
- end,
+ N = S + 1,
io:format("p_run: ~p parallel processes\n", [N]),
p_run_loop(Test, List, N, [], 0, 0).
diff --git a/lib/compiler/test/trycatch_SUITE.erl b/lib/compiler/test/trycatch_SUITE.erl
index 1b7ef4ddb0..8f9cd9ab1e 100644
--- a/lib/compiler/test/trycatch_SUITE.erl
+++ b/lib/compiler/test/trycatch_SUITE.erl
@@ -1189,7 +1189,8 @@ bad_raise(Expr) ->
test_raise(Expr) ->
test_raise_1(Expr),
test_raise_2(Expr),
- test_raise_3(Expr).
+ test_raise_3(Expr),
+ test_raise_4(Expr).
test_raise_1(Expr) ->
erase(exception),
@@ -1263,5 +1264,28 @@ do_test_raise_3(Expr) ->
erlang:raise(exit, {exception,C,E}, Stk)
end.
+test_raise_4(Expr) ->
+ try
+ do_test_raise_4(Expr)
+ catch
+ exit:{exception,C,E,Stk}:Stk ->
+ try
+ Expr()
+ catch
+ C:E:S ->
+ [StkTop|_] = S,
+ [StkTop|_] = Stk
+ end
+ end.
+
+do_test_raise_4(Expr) ->
+ try
+ Expr()
+ catch
+ C:E:Stk ->
+ %% Here the stacktrace must be built.
+ erlang:raise(exit, {exception,C,E,Stk}, Stk)
+ end.
+
id(I) -> I.
diff --git a/lib/compiler/test/warnings_SUITE.erl b/lib/compiler/test/warnings_SUITE.erl
index 42ff4f6133..70b7100451 100644
--- a/lib/compiler/test/warnings_SUITE.erl
+++ b/lib/compiler/test/warnings_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. 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.
@@ -42,7 +42,7 @@
comprehensions/1,maps/1,maps_bin_opt_info/1,
redundant_boolean_clauses/1,
latin1_fallback/1,underscore/1,no_warnings/1,
- bit_syntax/1,inlining/1]).
+ bit_syntax/1,inlining/1,tuple_calls/1]).
init_per_testcase(_Case, Config) ->
Config.
@@ -64,7 +64,8 @@ groups() ->
bin_opt_info,bin_construction,comprehensions,maps,
maps_bin_opt_info,
redundant_boolean_clauses,latin1_fallback,
- underscore,no_warnings,bit_syntax,inlining]}].
+ underscore,no_warnings,bit_syntax,inlining,
+ tuple_calls]}].
init_per_suite(Config) ->
test_lib:recompile(?MODULE),
@@ -239,19 +240,7 @@ guard(Config) when is_list(Config) ->
{4,sys_core_fold,nomatch_guard},
{6,sys_core_fold,no_clause_match},
{6,sys_core_fold,nomatch_guard},
- {6,sys_core_fold,{eval_failure,badarg}},
- {8,sys_core_fold,no_clause_match},
- {8,sys_core_fold,nomatch_guard},
- {8,sys_core_fold,{eval_failure,badarg}},
- {9,sys_core_fold,no_clause_match},
- {9,sys_core_fold,nomatch_guard},
- {9,sys_core_fold,{eval_failure,badarg}},
- {10,sys_core_fold,no_clause_match},
- {10,sys_core_fold,nomatch_guard},
- {10,sys_core_fold,{eval_failure,badarg}},
- {11,sys_core_fold,no_clause_match},
- {11,sys_core_fold,nomatch_guard},
- {11,sys_core_fold,{eval_failure,badarg}}
+ {6,sys_core_fold,{eval_failure,badarg}}
]}}],
[] = run(Config, Ts),
@@ -522,25 +511,43 @@ bin_opt_info(Config) when is_list(Config) ->
<<>> -> ok
end.
+ %% We use a tail in a BIF instruction, remote call, function
+ %% return, and an optimizable tail call for better coverage.
+ t2(<<A,B,T/bytes>>) ->
+ if
+ A > B -> t2(T);
+ A =< B -> T
+ end;
+ t2(<<_,T/bytes>>) when byte_size(T) < 4 ->
+ foo;
t2(<<_,T/bytes>>) ->
- split_binary(T, 4).
+ split_binary(T, 4).
">>,
- Ts1 = [{bsm1,
- Code,
- [bin_opt_info],
- {warnings,
- [{4,sys_core_bsm,orig_bin_var_used_in_guard},
- {5,beam_bsm,{no_bin_opt,{{t1,1},no_suitable_bs_start_match}}},
- {9,beam_bsm,{no_bin_opt,
- {binary_used_in,{extfunc,erlang,split_binary,2}}}} ]}}],
- [] = run(Config, Ts1),
+
+ Ws = (catch run_test(Config, Code, [bin_opt_info])),
+
+ %% This is an inexact match since the pass reports exact instructions as
+ %% part of the warnings, which may include annotations that vary from run
+ %% to run.
+ {warnings,
+ [{5,beam_ssa_bsm,{unsuitable_call,
+ {{b_local,{b_literal,t1},1},
+ {used_before_match,
+ {b_set,_,_,{bif,byte_size},[_]}}}}},
+ {5,beam_ssa_bsm,{binary_created,_,_}},
+ {11,beam_ssa_bsm,{binary_created,_,_}}, %% A =< B -> T
+ {13,beam_ssa_bsm,context_reused}, %% A > B -> t2(T);
+ {16,beam_ssa_bsm,{binary_created,_,_}}, %% when byte_size(T) < 4 ->
+ {19,beam_ssa_bsm,{remote_call,
+ {b_remote,
+ {b_literal,erlang},
+ {b_literal,split_binary},2}}},
+ {19,beam_ssa_bsm,{binary_created,_,_}} %% split_binary(T, 4)
+ ]} = Ws,
%% For coverage: don't give the bin_opt_info option.
- Ts2 = [{bsm2,
- Code,
- [],
- []}],
- [] = run(Config, Ts2),
+ [] = (catch run_test(Config, Code, [])),
+
ok.
bin_construction(Config) when is_list(Config) ->
@@ -746,7 +753,7 @@ maps_bin_opt_info(Config) when is_list(Config) ->
M.
">>,
[bin_opt_info],
- {warnings,[{2,beam_bsm,bin_opt}]}}],
+ {warnings,[{3,beam_ssa_bsm,context_reused}]}}],
[] = run(Config, Ts),
ok.
@@ -952,6 +959,20 @@ inlining(Config) ->
run(Config, Ts),
ok.
+tuple_calls(Config) ->
+ %% Make sure that no spurious warnings are generated.
+ Ts = [{inlining_1,
+ <<"-compile(tuple_calls).
+ dispatch(X) ->
+ (list_to_atom(\"prefix_\" ++
+ atom_to_list(suffix))):doit(X).
+ ">>,
+ [],
+ []}
+ ],
+ run(Config, Ts),
+ ok.
+
%%%
%%% End of test cases.
%%%
@@ -969,7 +990,6 @@ run(Config, Tests) ->
end,
lists:foldl(F, [], Tests).
-
%% Compiles a test module and returns the list of errors and warnings.
run_test(Conf, Test0, Warnings) ->