aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'lib/compiler')
-rw-r--r--lib/compiler/doc/src/compile.xml26
-rw-r--r--lib/compiler/doc/src/notes.xml100
-rw-r--r--lib/compiler/src/Makefile17
-rw-r--r--lib/compiler/src/beam_a.erl97
-rw-r--r--lib/compiler/src/beam_asm.erl4
-rw-r--r--lib/compiler/src/beam_block.erl79
-rw-r--r--lib/compiler/src/beam_bool.erl43
-rw-r--r--lib/compiler/src/beam_bsm.erl159
-rw-r--r--lib/compiler/src/beam_clean.erl47
-rw-r--r--lib/compiler/src/beam_dead.erl18
-rw-r--r--lib/compiler/src/beam_dict.erl2
-rw-r--r--lib/compiler/src/beam_disasm.erl9
-rw-r--r--lib/compiler/src/beam_except.erl28
-rw-r--r--lib/compiler/src/beam_flatten.erl55
-rw-r--r--lib/compiler/src/beam_jump.erl129
-rw-r--r--lib/compiler/src/beam_peep.erl10
-rw-r--r--lib/compiler/src/beam_receive.erl58
-rw-r--r--lib/compiler/src/beam_trim.erl70
-rw-r--r--lib/compiler/src/beam_type.erl25
-rw-r--r--lib/compiler/src/beam_utils.erl284
-rw-r--r--lib/compiler/src/beam_validator.erl18
-rw-r--r--lib/compiler/src/beam_z.erl79
-rw-r--r--lib/compiler/src/compile.erl107
-rw-r--r--lib/compiler/src/compiler.app.src5
-rw-r--r--lib/compiler/src/core_lint.erl7
-rw-r--r--lib/compiler/src/core_scan.erl27
-rw-r--r--lib/compiler/src/erl_bifs.erl6
-rw-r--r--lib/compiler/src/sys_core_fold.erl160
-rw-r--r--lib/compiler/src/sys_expand_pmod.erl433
-rw-r--r--lib/compiler/src/sys_pre_expand.erl150
-rw-r--r--lib/compiler/src/v3_codegen.erl100
-rw-r--r--lib/compiler/src/v3_kernel.erl55
-rw-r--r--lib/compiler/test/Makefile6
-rw-r--r--lib/compiler/test/andor_SUITE.erl9
-rw-r--r--lib/compiler/test/beam_except_SUITE.erl (renamed from lib/compiler/test/beam_expect_SUITE.erl)4
-rw-r--r--lib/compiler/test/beam_validator_SUITE.erl21
-rw-r--r--lib/compiler/test/bs_bit_binaries_SUITE.erl14
-rw-r--r--lib/compiler/test/bs_construct_SUITE.erl34
-rw-r--r--lib/compiler/test/bs_match_SUITE.erl125
-rw-r--r--lib/compiler/test/compilation_SUITE.erl62
-rw-r--r--lib/compiler/test/compilation_SUITE_data/bad_functional_value.erl28
-rw-r--r--lib/compiler/test/compile_SUITE.erl30
-rw-r--r--lib/compiler/test/core_SUITE.erl8
-rw-r--r--lib/compiler/test/core_fold_SUITE.erl58
-rw-r--r--lib/compiler/test/error_SUITE.erl43
-rw-r--r--lib/compiler/test/guard_SUITE.erl21
-rw-r--r--lib/compiler/test/inline_SUITE.erl76
-rw-r--r--lib/compiler/test/match_SUITE.erl10
-rw-r--r--lib/compiler/test/misc_SUITE.erl22
-rw-r--r--lib/compiler/test/pmod_SUITE.erl121
-rw-r--r--lib/compiler/test/pmod_SUITE_data/pmod_basic.erl83
-rw-r--r--lib/compiler/test/receive_SUITE.erl8
-rw-r--r--lib/compiler/test/receive_SUITE_data/ref_opt/no_4.erl12
-rw-r--r--lib/compiler/test/receive_SUITE_data/ref_opt/yes_10.erl13
-rw-r--r--lib/compiler/test/receive_SUITE_data/ref_opt/yes_11.erl21
-rw-r--r--lib/compiler/test/receive_SUITE_data/ref_opt/yes_12.erl12
-rw-r--r--lib/compiler/test/receive_SUITE_data/ref_opt/yes_13.erl12
-rw-r--r--lib/compiler/test/record_SUITE.erl12
-rw-r--r--lib/compiler/test/test_lib.erl17
-rw-r--r--lib/compiler/test/trycatch_SUITE.erl12
-rw-r--r--lib/compiler/test/unused_multiple_values_error.core11
-rw-r--r--lib/compiler/test/warnings_SUITE.erl16
-rw-r--r--lib/compiler/vsn.mk2
63 files changed, 1585 insertions, 1745 deletions
diff --git a/lib/compiler/doc/src/compile.xml b/lib/compiler/doc/src/compile.xml
index 27d750f929..ddaae2655d 100644
--- a/lib/compiler/doc/src/compile.xml
+++ b/lib/compiler/doc/src/compile.xml
@@ -816,6 +816,32 @@ pi() -> 3.1416.
</section>
<section>
+ <title>Inlining of list functions</title>
+ <p>The compiler can also inline a variety of list manipulation functions
+ from the stdlib's lists module.</p>
+
+ <p>This feature must be explicitly enabled with a compiler option or a
+ <c>-compile()</c> attribute in the source module.</p>
+
+ <p>To enable inlining of list functions, use the <c>inline_list_funcs</c>
+ option.</p>
+
+ <p>The following functions are inlined:</p>
+ <list type="bulleted">
+ <item><seealso marker="stdlib:lists#all/2">lists:all/2</seealso></item>
+ <item><seealso marker="stdlib:lists#any/2">lists:any/2</seealso></item>
+ <item><seealso marker="stdlib:lists#foreach/2">lists:foreach/2</seealso></item>
+ <item><seealso marker="stdlib:lists#map/2">lists:map/2</seealso></item>
+ <item><seealso marker="stdlib:lists#flatmap/2">lists:flatmap/2</seealso></item>
+ <item><seealso marker="stdlib:lists#filter/2">lists:filter/2</seealso></item>
+ <item><seealso marker="stdlib:lists#foldl/3">lists:foldl/3</seealso></item>
+ <item><seealso marker="stdlib:lists#foldr/3">lists:foldr/3</seealso></item>
+ <item><seealso marker="stdlib:lists#mapfoldl/3">lists:mapfoldl/3</seealso></item>
+ <item><seealso marker="stdlib:lists#mapfoldr/3">lists:mapfoldr/3</seealso></item>
+ </list>
+ </section>
+
+ <section>
<title>Parse Transformations</title>
<p>Parse transformations are used when a programmer wants to use
diff --git a/lib/compiler/doc/src/notes.xml b/lib/compiler/doc/src/notes.xml
index 6d51074d4a..94fea84557 100644
--- a/lib/compiler/doc/src/notes.xml
+++ b/lib/compiler/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2012</year>
+ <year>2004</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,104 @@
<p>This document describes the changes made to the Compiler
application.</p>
+<section><title>Compiler 4.9.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The compiler would crash attempting to compile
+ expressions such as "element(2, not_tuple)".</p>
+ <p>
+ Own Id: OTP-10794</p>
+ </item>
+ <item>
+ <p>
+ Forbid multiple values in Core Erlang sequence arguments.
+ Thanks to Jos� Valim and Anthony Ramine.</p>
+ <p>
+ Own Id: OTP-10818</p>
+ </item>
+ <item>
+ <p>
+ An unsafe optimization would cause the compiler to crash
+ with an internal error for certain complex code
+ sequences.</p>
+ <p>
+ Own Id: OTP-10825 Aux Id: seq12247 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>Integers in expression that will give a floating point
+ result (such as "<c>X / 2</c>" will now be converted to
+ floating point at compile-time. (Suggested by Richard
+ O'Keefe.)</p>
+ <p>Identical floating points constans in a module will
+ now be coalesced to one entry in the constant pool.</p>
+ <p>
+ Own Id: OTP-10788</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 4.9</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The compiler optimizations have been polished, so that
+ the code quality will be slightly better in some cases.</p>
+ <p>
+ Own Id: OTP-10193</p>
+ </item>
+ <item>
+ <p> Support for Unicode has been implemented. </p>
+ <p>
+ Own Id: OTP-10302</p>
+ </item>
+ <item>
+ <p>Where necessary a comment stating encoding has been
+ added to Erlang files. The comment is meant to be removed
+ in Erlang/OTP R17B when UTF-8 becomes the default
+ encoding. </p>
+ <p>
+ Own Id: OTP-10630</p>
+ </item>
+ <item>
+ <p>
+ Fix some wrong warnings triggered by the option
+ inline_list_funcs. Thanks to Anthony Ramine.</p>
+ <p>
+ Own Id: OTP-10690</p>
+ </item>
+ <item>
+ <p>
+ Forbid local fun variables in Core Erlang guards. Thanks
+ to Anthony Ramine.</p>
+ <p>
+ Own Id: OTP-10706</p>
+ </item>
+ <item>
+ <p>
+ Binary syntax matches could cause an internal consistency
+ error in in the compiler. (Thanks to Viktor Sovietov for
+ reporting this bug.)</p>
+ <p>
+ Own Id: OTP-10724</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Compiler 4.8.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/compiler/src/Makefile b/lib/compiler/src/Makefile
index 958d3501c7..c6d09d85eb 100644
--- a/lib/compiler/src/Makefile
+++ b/lib/compiler/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2012. All Rights Reserved.
+# Copyright Ericsson AB 1996-2013. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -45,6 +45,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/compiler-$(VSN)
# Target Specs
# ----------------------------------------------------
MODULES = \
+ beam_a \
beam_asm \
beam_block \
beam_bool \
@@ -65,6 +66,7 @@ MODULES = \
beam_type \
beam_utils \
beam_validator \
+ beam_z \
cerl \
cerl_clauses \
cerl_inline \
@@ -80,7 +82,6 @@ MODULES = \
sys_core_dsetel \
sys_core_fold \
sys_core_inline \
- sys_expand_pmod \
sys_pre_attributes \
sys_pre_expand \
v3_codegen \
@@ -121,7 +122,7 @@ ifeq ($(NATIVE_LIBS_ENABLED),yes)
ERL_COMPILE_FLAGS += +native
endif
ERL_COMPILE_FLAGS += +inline +warn_unused_import \
- +warnings_as_errors \
+ -Werror \
-I../../stdlib/include -I$(EGEN) -W
# ----------------------------------------------------
@@ -143,19 +144,19 @@ clean:
# ----------------------------------------------------
$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
+ $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
$(EGEN)/beam_opcodes.erl $(EGEN)/beam_opcodes.hrl: genop.tab
- $(PERL) $(ERL_TOP)/erts/emulator/utils/beam_makeops -compiler -outdir $(EGEN) $<
+ $(gen_verbose)$(PERL) $(ERL_TOP)/erts/emulator/utils/beam_makeops -compiler -outdir $(EGEN) $<
$(EBIN)/beam_asm.beam: $(ESRC)/beam_asm.erl $(EGEN)/beam_opcodes.hrl
- $(ERLC) $(ERL_COMPILE_FLAGS) -DCOMPILER_VSN='"$(VSN)"' -o$(EBIN) $<
+ $(V_ERLC) $(ERL_COMPILE_FLAGS) -DCOMPILER_VSN='"$(VSN)"' -o$(EBIN) $<
$(EBIN)/cerl_inline.beam: $(ESRC)/cerl_inline.erl
- $(ERLC) $(ERL_COMPILE_FLAGS) +nowarn_shadow_vars -o$(EBIN) $<
+ $(V_ERLC) $(ERL_COMPILE_FLAGS) +nowarn_shadow_vars -o$(EBIN) $<
# ----------------------------------------------------
# Release Target
diff --git a/lib/compiler/src/beam_a.erl b/lib/compiler/src/beam_a.erl
new file mode 100644
index 0000000000..1c51226314
--- /dev/null
+++ b/lib/compiler/src/beam_a.erl
@@ -0,0 +1,97 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% Purpose: Run directly after code generation to do any normalization
+%% or preparation to simplify the optimization passes.
+%% (Mandatory.)
+
+-module(beam_a).
+
+-export([module/2]).
+
+module({Mod,Exp,Attr,Fs0,Lc}, _Opt) ->
+ Fs = [function(F) || F <- Fs0],
+ {ok,{Mod,Exp,Attr,Fs,Lc}}.
+
+function({function,Name,Arity,CLabel,Is0}) ->
+ try
+ %% Rename certain operations to simplify the optimization passes.
+ Is1 = rename_instrs(Is0),
+
+ %% Remove unusued labels for cleanliness and to help
+ %% optimization passes and HiPE.
+ Is = beam_jump:remove_unused_labels(Is1),
+ {function,Name,Arity,CLabel,Is}
+ catch
+ Class:Error ->
+ Stack = erlang:get_stacktrace(),
+ io:fwrite("Function: ~w/~w\n", [Name,Arity]),
+ erlang:raise(Class, Error, Stack)
+ end.
+
+rename_instrs([{apply_last,A,N}|Is]) ->
+ [{apply,A},{deallocate,N},return|rename_instrs(Is)];
+rename_instrs([{call_last,A,F,N}|Is]) ->
+ [{call,A,F},{deallocate,N},return|rename_instrs(Is)];
+rename_instrs([{call_ext_last,A,F,N}|Is]) ->
+ [{call_ext,A,F},{deallocate,N},return|rename_instrs(Is)];
+rename_instrs([{call_only,A,F}|Is]) ->
+ [{call,A,F},return|rename_instrs(Is)];
+rename_instrs([{call_ext_only,A,F}|Is]) ->
+ [{call_ext,A,F},return|rename_instrs(Is)];
+rename_instrs([I|Is]) ->
+ [rename_instr(I)|rename_instrs(Is)];
+rename_instrs([]) -> [].
+
+rename_instr({bs_put_binary=I,F,Sz,U,Fl,Src}) ->
+ {bs_put,F,{I,U,Fl},[Sz,Src]};
+rename_instr({bs_put_float=I,F,Sz,U,Fl,Src}) ->
+ {bs_put,F,{I,U,Fl},[Sz,Src]};
+rename_instr({bs_put_integer=I,F,Sz,U,Fl,Src}) ->
+ {bs_put,F,{I,U,Fl},[Sz,Src]};
+rename_instr({bs_put_utf8=I,F,Fl,Src}) ->
+ {bs_put,F,{I,Fl},[Src]};
+rename_instr({bs_put_utf16=I,F,Fl,Src}) ->
+ {bs_put,F,{I,Fl},[Src]};
+rename_instr({bs_put_utf32=I,F,Fl,Src}) ->
+ {bs_put,F,{I,Fl},[Src]};
+%% rename_instr({bs_put_string,_,_}=I) ->
+%% {bs_put,{f,0},I,[]};
+rename_instr({bs_add=I,F,[Src1,Src2,U],Dst}) when is_integer(U) ->
+ {bif,I,F,[Src1,Src2,{integer,U}],Dst};
+rename_instr({bs_utf8_size=I,F,Src,Dst}) ->
+ {bif,I,F,[Src],Dst};
+rename_instr({bs_utf16_size=I,F,Src,Dst}) ->
+ {bif,I,F,[Src],Dst};
+rename_instr({bs_init2=I,F,Sz,Extra,Live,Flags,Dst}) ->
+ {bs_init,F,{I,Extra,Flags},Live,[Sz],Dst};
+rename_instr({bs_init_bits=I,F,Sz,Extra,Live,Flags,Dst}) ->
+ {bs_init,F,{I,Extra,Flags},Live,[Sz],Dst};
+rename_instr({bs_append=I,F,Sz,Extra,Live,U,Src,Flags,Dst}) ->
+ {bs_init,F,{I,Extra,U,Flags},Live,[Sz,Src],Dst};
+rename_instr({bs_private_append=I,F,Sz,U,Src,Flags,Dst}) ->
+ {bs_init,F,{I,U,Flags},none,[Sz,Src],Dst};
+rename_instr(bs_init_writable=I) ->
+ {bs_init,{f,0},I,1,[{x,0}],{x,0}};
+rename_instr({select_val=I,Reg,Fail,{list,List}}) ->
+ {select,I,Reg,Fail,List};
+rename_instr({select_tuple_arity=I,Reg,Fail,{list,List}}) ->
+ {select,I,Reg,Fail,List};
+rename_instr(send) ->
+ {call_ext,2,send};
+rename_instr(I) -> I.
diff --git a/lib/compiler/src/beam_asm.erl b/lib/compiler/src/beam_asm.erl
index a7c8508321..112b087f3c 100644
--- a/lib/compiler/src/beam_asm.erl
+++ b/lib/compiler/src/beam_asm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -387,7 +387,7 @@ encode_arg({list, List}, Dict0) ->
{L, Dict} = encode_list(List, Dict0, []),
{[encode(?tag_z, 1), encode(?tag_u, length(List))|L], Dict};
encode_arg({float, Float}, Dict) when is_float(Float) ->
- {[encode(?tag_z, 0),<<Float:64/float>>], Dict};
+ encode_arg({literal,Float}, Dict);
encode_arg({fr,Fr}, Dict) ->
{[encode(?tag_z, 2),encode(?tag_u, Fr)], Dict};
encode_arg({field_flags,Flags0}, Dict) ->
diff --git a/lib/compiler/src/beam_block.erl b/lib/compiler/src/beam_block.erl
index cd568097fa..cf5244e1ce 100644
--- a/lib/compiler/src/beam_block.erl
+++ b/lib/compiler/src/beam_block.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -31,19 +31,16 @@ module({Mod,Exp,Attr,Fs0,Lc0}, _Opt) ->
function({function,Name,Arity,CLabel,Is0}, Lc0) ->
try
- %% Extra labels may thwart optimizations.
- Is1 = beam_jump:remove_unused_labels(Is0),
-
%% Collect basic blocks and optimize them.
- Is2 = blockify(Is1),
- Is3 = embed_lines(Is2),
- Is4 = move_allocates(Is3),
- Is5 = beam_utils:live_opt(Is4),
- Is6 = opt_blocks(Is5),
- Is7 = beam_utils:delete_live_annos(Is6),
+ Is1 = blockify(Is0),
+ Is2 = embed_lines(Is1),
+ Is3 = move_allocates(Is2),
+ Is4 = beam_utils:live_opt(Is3),
+ Is5 = opt_blocks(Is4),
+ Is6 = beam_utils:delete_live_annos(Is5),
%% Optimize bit syntax.
- {Is,Lc} = bsm_opt(Is7, Lc0),
+ {Is,Lc} = bsm_opt(Is6, Lc0),
%% Done.
{{function,Name,Arity,CLabel,Is},Lc}
@@ -74,9 +71,9 @@ blockify([{bs_save2,R,Point}=I,{test,is_eq_exact,_,_}=Test,
%% Do other peep-hole optimizations.
blockify([{test,is_atom,{f,Fail},[Reg]}=I|
- [{select_val,Reg,{f,Fail},
- {list,[{atom,false},{f,_}=BrFalse,
- {atom,true}=AtomTrue,{f,_}=BrTrue]}}|Is]=Is0],
+ [{select,select_val,Reg,{f,Fail},
+ [{atom,false},{f,_}=BrFalse,
+ {atom,true}=AtomTrue,{f,_}=BrTrue]}|Is]=Is0],
[{block,Bl}|_]=Acc) ->
case is_last_bool(Bl, Reg) of
false ->
@@ -89,9 +86,9 @@ blockify([{test,is_atom,{f,Fail},[Reg]}=I|
{test,is_eq_exact,BrFalse,[Reg,AtomTrue]}|Acc])
end;
blockify([{test,is_atom,{f,Fail},[Reg]}=I|
- [{select_val,Reg,{f,Fail},
- {list,[{atom,true}=AtomTrue,{f,_}=BrTrue,
- {atom,false},{f,_}=BrFalse]}}|Is]=Is0],
+ [{select,select_val,Reg,{f,Fail},
+ [{atom,true}=AtomTrue,{f,_}=BrTrue,
+ {atom,false},{f,_}=BrFalse]}|Is]=Is0],
[{block,Bl}|_]=Acc) ->
case is_last_bool(Bl, Reg) of
false ->
@@ -423,8 +420,8 @@ inverse_comp_op(_) -> none.
%%% Evaluation of constant bit fields.
%%%
-is_bs_put({bs_put_integer,_,_,_,_,_}) -> true;
-is_bs_put({bs_put_float,_,_,_,_,_}) -> true;
+is_bs_put({bs_put,_,{bs_put_integer,_,_},_}) -> true;
+is_bs_put({bs_put,_,{bs_put_float,_,_},_}) -> true;
is_bs_put(_) -> false.
collect_bs_puts(Is) ->
@@ -439,20 +436,24 @@ collect_bs_puts_1([I|Is]=Is0, Acc) ->
opt_bs_puts(Is) ->
opt_bs_1(Is, []).
-opt_bs_1([{bs_put_float,Fail,{integer,Sz},1,Flags0,Src}=I0|Is], Acc) ->
+opt_bs_1([{bs_put,Fail,
+ {bs_put_float,1,Flags0},[{integer,Sz},Src]}=I0|Is], Acc) ->
try eval_put_float(Src, Sz, Flags0) of
<<Int:Sz>> ->
Flags = force_big(Flags0),
- I = {bs_put_integer,Fail,{integer,Sz},1,Flags,{integer,Int}},
+ I = {bs_put,Fail,{bs_put_integer,1,Flags},
+ [{integer,Sz},{integer,Int}]},
opt_bs_1([I|Is], Acc)
catch
error:_ ->
opt_bs_1(Is, [I0|Acc])
end;
-opt_bs_1([{bs_put_integer,_,{integer,8},1,_,{integer,_}}|_]=IsAll, Acc0) ->
+opt_bs_1([{bs_put,_,{bs_put_integer,1,_},[{integer,8},{integer,_}]}|_]=IsAll,
+ Acc0) ->
{Is,Acc} = bs_collect_string(IsAll, Acc0),
opt_bs_1(Is, Acc);
-opt_bs_1([{bs_put_integer,Fail,{integer,Sz},1,F,{integer,N}}=I|Is0], Acc) when Sz > 8 ->
+opt_bs_1([{bs_put,Fail,{bs_put_integer,1,F},[{integer,Sz},{integer,N}]}=I|Is0],
+ Acc) when Sz > 8 ->
case field_endian(F) of
big ->
%% We can do this optimization for any field size without risk
@@ -466,14 +467,14 @@ opt_bs_1([{bs_put_integer,Fail,{integer,Sz},1,F,{integer,N}}=I|Is0], Acc) when S
%% an explosion in code size.
<<Int:Sz>> = <<N:Sz/little>>,
Flags = force_big(F),
- Is = [{bs_put_integer,Fail,{integer,Sz},1,
- Flags,{integer,Int}}|Is0],
+ Is = [{bs_put,Fail,{bs_put_integer,1,Flags},
+ [{integer,Sz},{integer,Int}]}|Is0],
opt_bs_1(Is, Acc);
_ -> %native or too wide little field
opt_bs_1(Is0, [I|Acc])
end;
-opt_bs_1([{Op,Fail,{integer,Sz},U,F,Src}|Is], Acc) when U > 1 ->
- opt_bs_1([{Op,Fail,{integer,U*Sz},1,F,Src}|Is], Acc);
+opt_bs_1([{bs_put,Fail,{Op,U,F},[{integer,Sz},Src]}|Is], Acc) when U > 1 ->
+ opt_bs_1([{bs_put,Fail,{Op,1,F},[{integer,U*Sz},Src]}|Is], Acc);
opt_bs_1([I|Is], Acc) ->
opt_bs_1(Is, [I|Acc]);
opt_bs_1([], Acc) -> reverse(Acc).
@@ -489,17 +490,17 @@ eval_put_float(Src, Sz, Flags) when Sz =< 256 -> %Only evaluate if Sz is reasona
value({integer,I}) -> I;
value({float,F}) -> F.
-bs_collect_string(Is, [{bs_put_string,Len,{string,Str}}|Acc]) ->
+bs_collect_string(Is, [{bs_put,_,{bs_put_string,Len,{string,Str}},[]}|Acc]) ->
bs_coll_str_1(Is, Len, reverse(Str), Acc);
bs_collect_string(Is, Acc) ->
bs_coll_str_1(Is, 0, [], Acc).
-bs_coll_str_1([{bs_put_integer,_,{integer,Sz},U,_,{integer,V}}|Is],
+bs_coll_str_1([{bs_put,_,{bs_put_integer,U,_},[{integer,Sz},{integer,V}]}|Is],
Len, StrAcc, IsAcc) when U*Sz =:= 8 ->
Byte = V band 16#FF,
bs_coll_str_1(Is, Len+1, [Byte|StrAcc], IsAcc);
bs_coll_str_1(Is, Len, StrAcc, IsAcc) ->
- {Is,[{bs_put_string,Len,{string,reverse(StrAcc)}}|IsAcc]}.
+ {Is,[{bs_put,{f,0},{bs_put_string,Len,{string,reverse(StrAcc)}},[]}|IsAcc]}.
field_endian({field_flags,F}) -> field_endian_1(F).
@@ -531,15 +532,17 @@ bs_split_int(N, Sz, Fail, Acc) ->
bs_split_int_1(N, FirstByteSz, Sz, Fail, Acc).
bs_split_int_1(-1, _, Sz, Fail, Acc) when Sz > 64 ->
- I = {bs_put_integer,Fail,{integer,Sz},1,{field_flags,[big]},{integer,-1}},
+ I = {bs_put,Fail,{bs_put_integer,1,{field_flags,[big]}},
+ [{integer,Sz},{integer,-1}]},
[I|Acc];
bs_split_int_1(0, _, Sz, Fail, Acc) when Sz > 64 ->
- I = {bs_put_integer,Fail,{integer,Sz},1,{field_flags,[big]},{integer,0}},
+ I = {bs_put,Fail,{bs_put_integer,1,{field_flags,[big]}},
+ [{integer,Sz},{integer,0}]},
[I|Acc];
bs_split_int_1(N, ByteSz, Sz, Fail, Acc) when Sz > 0 ->
Mask = (1 bsl ByteSz) - 1,
- I = {bs_put_integer,Fail,{integer,ByteSz},1,
- {field_flags,[big]},{integer,N band Mask}},
+ I = {bs_put,Fail,{bs_put_integer,1,{field_flags,[big]}},
+ [{integer,ByteSz},{integer,N band Mask}]},
bs_split_int_1(N bsr ByteSz, 8, Sz-ByteSz, Fail, [I|Acc]);
bs_split_int_1(_, _, _, _, Acc) -> Acc.
@@ -577,9 +580,9 @@ bsm_reroute([{bs_restore2,Reg,Save}=I|Is], D, _, Acc) ->
bsm_reroute(Is, D, {Reg,Save}, [I|Acc]);
bsm_reroute([{label,_}=I|Is], D, S, Acc) ->
bsm_reroute(Is, D, S, [I|Acc]);
-bsm_reroute([{select_val,Reg,F0,{list,Lbls0}}|Is], D, {_,Save}=S, Acc0) ->
+bsm_reroute([{select,select_val,Reg,F0,Lbls0}|Is], D, {_,Save}=S, Acc0) ->
[F|Lbls] = bsm_subst_labels([F0|Lbls0], Save, D),
- Acc = [{select_val,Reg,F,{list,Lbls}}|Acc0],
+ Acc = [{select,select_val,Reg,F,Lbls}|Acc0],
bsm_reroute(Is, D, S, Acc);
bsm_reroute([{test,TestOp,F0,TestArgs}=I|Is], D, {_,Save}=S, Acc0) ->
F = bsm_subst_label(F0, Save, D),
@@ -615,10 +618,6 @@ bsm_opt_2([{test,bs_skip_bits2,F,[Ctx,{integer,I1},Unit1,_]}|Is],
[{test,bs_skip_bits2,F,[Ctx,{integer,I2},Unit2,Flags]}|Acc]) ->
bsm_opt_2(Is, [{test,bs_skip_bits2,F,
[Ctx,{integer,I1*Unit1+I2*Unit2},1,Flags]}|Acc]);
-bsm_opt_2([{test,bs_match_string,F,[Ctx,Bin1]},
- {test,bs_match_string,F,[Ctx,Bin2]}|Is], Acc) ->
- I = {test,bs_match_string,F,[Ctx,<<Bin1/bitstring,Bin2/bitstring>>]},
- bsm_opt_2([I|Is], Acc);
bsm_opt_2([I|Is], Acc) ->
bsm_opt_2(Is, [I|Acc]);
bsm_opt_2([], Acc) -> reverse(Acc).
diff --git a/lib/compiler/src/beam_bool.erl b/lib/compiler/src/beam_bool.erl
index d9ea6f5a70..cf5455dfde 100644
--- a/lib/compiler/src/beam_bool.erl
+++ b/lib/compiler/src/beam_bool.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -168,18 +168,18 @@ bopt_block(Reg, Fail, OldIs, [{block,Bl0}|Acc0], St0) ->
end.
%% ensure_opt_safe(OriginalCode, OptCode, FollowingCode, Fail,
-%% ReversedPreceedingCode, State) -> ok
+%% ReversedPrecedingCode, State) -> ok
%% Comparing the original code to the optimized code, determine
%% whether the optimized code is guaranteed to work in the same
%% way as the original code.
%%
%% Throw an exception if the optimization is not safe.
%%
-ensure_opt_safe(Bl, NewCode, OldIs, Fail, PreceedingCode, St) ->
+ensure_opt_safe(Bl, NewCode, OldIs, Fail, PrecedingCode, St) ->
%% Here are the conditions that must be true for the
%% optimization to be safe.
%%
- %% 1. If a register is INITIALIZED by PreceedingCode,
+ %% 1. If a register is INITIALIZED by PrecedingCode,
%% then if that register assigned a value in the original
%% code, but not in the optimized code, it must be UNUSED or KILLED
%% in the code that follows.
@@ -190,29 +190,50 @@ ensure_opt_safe(Bl, NewCode, OldIs, Fail, PreceedingCode, St) ->
%% by the code that follows.
%%
%% 3. Any register that is assigned a value in the optimized
- %% code must be UNUSED or KILLED in the following code
- %% (because the register might be assigned the wrong value,
- %% and even if the value is right it might no longer be
- %% assigned on *all* paths leading to its use).
+ %% code must be UNUSED or KILLED in the following code,
+ %% unless we can be sure that it is always assigned the same
+ %% value.
- InitInPreceeding = initialized_regs(PreceedingCode),
+ InitInPreceding = initialized_regs(PrecedingCode),
PrevDst = dst_regs(Bl),
NewDst = dst_regs(NewCode),
NotSet = ordsets:subtract(PrevDst, NewDst),
- MustBeKilled = ordsets:subtract(NotSet, InitInPreceeding),
- MustBeUnused = ordsets:subtract(ordsets:union(NotSet, NewDst), MustBeKilled),
+ MustBeKilled = ordsets:subtract(NotSet, InitInPreceding),
case all_killed(MustBeKilled, OldIs, Fail, St) of
false -> throw(all_registers_not_killed);
true -> ok
end,
+ Same = assigned_same_value(Bl, NewCode),
+ MustBeUnused = ordsets:subtract(ordsets:union(NotSet, NewDst),
+ ordsets:union(MustBeKilled, Same)),
case none_used(MustBeUnused, OldIs, Fail, St) of
false -> throw(registers_used);
true -> ok
end,
ok.
+%% assigned_same_value(OldCode, NewCodeReversed) -> [DestinationRegs]
+%% Return an ordset with a list of all y registers that are always
+%% assigned the same value in the old and new code. Currently, we
+%% are very conservative in that we only consider identical move
+%% instructions in the same order.
+%%
+assigned_same_value(Old, New) ->
+ case reverse(New) of
+ [{block,Bl}|_] ->
+ assigned_same_value(Old, Bl, []);
+ _ ->
+ ordsets:new()
+ end.
+
+assigned_same_value([{set,[{y,_}=D],[S],move}|T1],
+ [{set,[{y,_}=D],[S],move}|T2], Acc) ->
+ assigned_same_value(T1, T2, [D|Acc]);
+assigned_same_value(_, _, Acc) ->
+ ordsets:from_list(Acc).
+
update_fail_label([{set,_,_,move}=I|Is], Fail, Acc) ->
update_fail_label(Is, Fail, [I|Acc]);
update_fail_label([{set,Ds,As,{bif,N,{f,_}}}|Is], Fail, Acc) ->
diff --git a/lib/compiler/src/beam_bsm.erl b/lib/compiler/src/beam_bsm.erl
index 1217f7f777..fdfcb08125 100644
--- a/lib/compiler/src/beam_bsm.erl
+++ b/lib/compiler/src/beam_bsm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -204,16 +204,6 @@ btb_reaches_match_1(Is, Regs, D) ->
btb_reaches_match_2([{block,Bl}|Is], Regs0, D) ->
Regs = btb_reaches_match_block(Bl, Regs0),
btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{call_only,Arity,{f,Lbl}}|_], Regs0, D) ->
- Regs = btb_kill_not_live(Arity, Regs0),
- btb_tail_call(Lbl, Regs, D);
-btb_reaches_match_2([{call_ext_only,Arity,Func}|_], Regs0, D) ->
- Regs = btb_kill_not_live(Arity, Regs0),
- btb_tail_call(Func, Regs, D);
-btb_reaches_match_2([{call_last,Arity,{f,Lbl},_}|_], Regs0, D) ->
- Regs1 = btb_kill_not_live(Arity, Regs0),
- Regs = btb_kill_yregs(Regs1),
- btb_tail_call(Lbl, Regs, D);
btb_reaches_match_2([{call,Arity,{f,Lbl}}|Is], Regs, D) ->
btb_call(Arity, Lbl, Regs, Is, D);
btb_reaches_match_2([{apply,Arity}|Is], Regs, D) ->
@@ -222,19 +212,16 @@ btb_reaches_match_2([{call_fun,Live}=I|Is], Regs, D) ->
btb_call(Live, I, Regs, Is, D);
btb_reaches_match_2([{make_fun2,_,_,_,Live}|Is], Regs, D) ->
btb_call(Live, make_fun2, Regs, Is, D);
-btb_reaches_match_2([{call_ext,Arity,{extfunc,Mod,Name,Arity}=Func}|Is], Regs0, D) ->
+btb_reaches_match_2([{call_ext,Arity,Func}=I|Is], Regs0, D) ->
%% Allow us scanning beyond the call in case the match
%% context is saved on the stack.
- case erl_bifs:is_exit_bif(Mod, Name, Arity) of
+ case beam_jump:is_exit_instruction(I) of
false ->
btb_call(Arity, Func, Regs0, Is, D);
true ->
Regs = btb_kill_not_live(Arity, Regs0),
btb_tail_call(Func, Regs, D)
end;
-btb_reaches_match_2([{call_ext_last,Arity,_,_}=I|_], Regs, D) ->
- btb_ensure_not_used(btb_regs_from_arity(Arity), I, Regs),
- D;
btb_reaches_match_2([{kill,Y}|Is], Regs, D) ->
btb_reaches_match_1(Is, btb_kill([Y], Regs), D);
btb_reaches_match_2([{deallocate,_}|Is], Regs0, D) ->
@@ -254,21 +241,45 @@ btb_reaches_match_2([{bif,_,{f,F},Ss,Dst}=I|Is], Regs0, D0) ->
Regs = btb_kill([Dst], Regs0),
D = btb_follow_branch(F, Regs, D0),
btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{test,bs_start_match2,_,_,[Ctx,_],Ctx}|Is], Regs, D) ->
- case btb_context_regs(Regs) of
- [Ctx] ->
- D;
- CtxRegs ->
- case member(Ctx, CtxRegs) of
- false -> btb_reaches_match_2(Is, Regs, D);
- true -> btb_error(unsuitable_bs_start_match)
+btb_reaches_match_2([{test,bs_start_match2,{f,F},Live,[Ctx,_],Ctx}=I|Is],
+ Regs0, D0) ->
+ CtxRegs = btb_context_regs(Regs0),
+ case member(Ctx, CtxRegs) of
+ false ->
+ %% This bs_start_match2 instruction does not use "our"
+ %% match state. Therefore we can continue the search
+ %% for another bs_start_match2 instruction.
+ D = btb_follow_branch(F, Regs0, D0),
+ Regs = btb_kill_not_live(Live, Regs0),
+ btb_reaches_match_2(Is, Regs, D);
+ true ->
+ %% OK. This instruction will use "our" match state,
+ %% but we must make sure that all other copies of the
+ %% match state are killed in the code that follows
+ %% the instruction. (We know that the fail branch cannot
+ %% be taken in this case.)
+ OtherCtxRegs = CtxRegs -- [Ctx],
+ case btb_are_all_unused(OtherCtxRegs, Is, D0) of
+ false -> btb_error({OtherCtxRegs,not_all_unused_after,I});
+ true -> D0
end
end;
-btb_reaches_match_2([{test,bs_start_match2,_,_,[Bin,_],Ctx}|Is], Regs, D) ->
- CtxRegs = btb_context_regs(Regs),
+btb_reaches_match_2([{test,bs_start_match2,{f,F},Live,[Bin,_],Ctx}|Is],
+ Regs0, D0) ->
+ CtxRegs = btb_context_regs(Regs0),
case member(Bin, CtxRegs) orelse member(Ctx, CtxRegs) of
- false -> btb_reaches_match_2(Is, Regs, D);
- true -> btb_error(unsuitable_bs_start_match)
+ false ->
+ %% This bs_start_match2 does not reference any copy of the
+ %% match state. Therefore it can safely be passed on the
+ %% way to another (perhaps more suitable) bs_start_match2
+ %% instruction.
+ D = btb_follow_branch(F, Regs0, D0),
+ Regs = btb_kill_not_live(Live, Regs0),
+ btb_reaches_match_2(Is, Regs, D);
+ true ->
+ %% This variant of the bs_start_match2 instruction does
+ %% not accept a match state as source.
+ btb_error(unsuitable_bs_start_match)
end;
btb_reaches_match_2([{test,_,{f,F},Ss}=I|Is], Regs, D0) ->
btb_ensure_not_used(Ss, I, Regs),
@@ -278,12 +289,7 @@ btb_reaches_match_2([{test,_,{f,F},_,Ss,_}=I|Is], Regs, D0) ->
btb_ensure_not_used(Ss, I, Regs),
D = btb_follow_branch(F, Regs, D0),
btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{select_val,Src,{f,F},{list,Conds}}=I|Is], Regs, D0) ->
- btb_ensure_not_used([Src], I, Regs),
- D1 = btb_follow_branch(F, Regs, D0),
- D = btb_follow_branches(Conds, Regs, D1),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{select_tuple_arity,Src,{f,F},{list,Conds}}=I|Is], Regs, D0) ->
+btb_reaches_match_2([{select,_,Src,{f,F},Conds}=I|Is], Regs, D0) ->
btb_ensure_not_used([Src], I, Regs),
D1 = btb_follow_branch(F, Regs, D0),
D = btb_follow_branches(Conds, Regs, D1),
@@ -293,46 +299,11 @@ btb_reaches_match_2([{jump,{f,Lbl}}|_], Regs, #btb{index=Li}=D) ->
btb_reaches_match_2(Is, Regs, D);
btb_reaches_match_2([{label,_}|Is], Regs, D) ->
btb_reaches_match_2(Is, Regs, D);
-btb_reaches_match_2([{bs_add,{f,0},_,Dst}|Is], Regs, D) ->
- btb_reaches_match_1(Is, btb_kill([Dst], Regs), D);
-btb_reaches_match_2([bs_init_writable|Is], Regs0, D) ->
- Regs = btb_kill_not_live(0, Regs0),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{bs_init2,{f,0},_,_,_,_,Dst}|Is], Regs, D) ->
- btb_reaches_match_1(Is, btb_kill([Dst], Regs), D);
-btb_reaches_match_2([{bs_init_bits,{f,0},_,_,_,_,Dst}|Is], Regs, D) ->
- btb_reaches_match_1(Is, btb_kill([Dst], Regs), D);
-btb_reaches_match_2([{bs_append,{f,0},_,_,_,_,Src,_,Dst}=I|Is], Regs, D) ->
- btb_ensure_not_used([Src], I, Regs),
- btb_reaches_match_1(Is, btb_kill([Dst], Regs), D);
-btb_reaches_match_2([{bs_private_append,{f,0},_,_,Src,_,Dst}=I|Is], Regs, D) ->
- btb_ensure_not_used([Src], I, Regs),
- btb_reaches_match_1(Is, btb_kill([Dst], Regs), D);
-btb_reaches_match_2([{bs_put_integer,{f,0},_,_,_,Src}=I|Is], Regs, D) ->
- btb_ensure_not_used([Src], I, Regs),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{bs_put_float,{f,0},_,_,_,Src}=I|Is], Regs, D) ->
- btb_ensure_not_used([Src], I, Regs),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{bs_put_binary,{f,0},_,_,_,Src}=I|Is], Regs, D) ->
- btb_ensure_not_used([Src], I, Regs),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{bs_put_string,_,_}|Is], Regs, D) ->
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{bs_utf8_size,_,Src,Dst}=I|Is], Regs, D) ->
- btb_ensure_not_used([Src], I, Regs),
- btb_reaches_match_1(Is, btb_kill([Dst], Regs), D);
-btb_reaches_match_2([{bs_utf16_size,_,Src,Dst}=I|Is], Regs, D) ->
- btb_ensure_not_used([Src], I, Regs),
+btb_reaches_match_2([{bs_init,{f,0},_,_,Ss,Dst}=I|Is], Regs, D) ->
+ btb_ensure_not_used(Ss, I, Regs),
btb_reaches_match_1(Is, btb_kill([Dst], Regs), D);
-btb_reaches_match_2([{bs_put_utf8,_,_,Src}=I|Is], Regs, D) ->
- btb_ensure_not_used([Src], I, Regs),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{bs_put_utf16,_,_,Src}=I|Is], Regs, D) ->
- btb_ensure_not_used([Src], I, Regs),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{bs_put_utf32,_,_,Src}=I|Is], Regs, D) ->
- btb_ensure_not_used([Src], I, Regs),
+btb_reaches_match_2([{bs_put,{f,0},_,Ss}=I|Is], Regs, D) ->
+ btb_ensure_not_used(Ss, I, Regs),
btb_reaches_match_1(Is, Regs, D);
btb_reaches_match_2([{bs_restore2,Src,_}=I|Is], Regs0, D) ->
case btb_contains_context(Src, Regs0) of
@@ -340,11 +311,11 @@ btb_reaches_match_2([{bs_restore2,Src,_}=I|Is], Regs0, D) ->
btb_reaches_match_1(Is, Regs0, D);
true ->
%% Check that all other copies of the context registers
- %% are killed by the following instructions.
+ %% are unused by the following instructions.
Regs = btb_kill([Src], Regs0),
CtxRegs = btb_context_regs(Regs),
- case btb_are_all_killed(CtxRegs, Is, D) of
- false -> btb_error({CtxRegs,not_all_killed_after,I});
+ case btb_are_all_unused(CtxRegs, Is, D) of
+ false -> btb_error({CtxRegs,not_all_unused_after,I});
true -> D#btb{must_not_save=true}
end
end;
@@ -354,11 +325,11 @@ btb_reaches_match_2([{bs_context_to_binary,Src}=I|Is], Regs0, D) ->
btb_reaches_match_1(Is, Regs0, D);
true ->
%% Check that all other copies of the context registers
- %% are killed by the following instructions.
+ %% are unused by the following instructions.
Regs = btb_kill([Src], Regs0),
CtxRegs = btb_context_regs(Regs),
- case btb_are_all_killed(CtxRegs, Is, D) of
- false -> btb_error({CtxRegs,not_all_killed_after,I});
+ case btb_are_all_unused(CtxRegs, Is, D) of
+ false -> btb_error({CtxRegs,not_all_unused_after,I});
true -> D#btb{must_not_save=true}
end
end;
@@ -389,13 +360,16 @@ btb_call(Arity, Lbl, Regs0, Is, D0) ->
%% First handle the call as if it were a tail call.
D = btb_tail_call(Lbl, Regs, D0),
- %% No problem so far, but now we must make sure that
- %% we don't have any copies of the match context
- %% tucked away in an y register.
+ %% No problem so far (the called function can handle a
+ %% match context). Now we must make sure that the rest
+ %% of this function following the call does not attempt
+ %% to use the match context in case there is a copy
+ %% tucked away in a y register.
RegList = btb_context_regs(Regs),
- case [R || {y,_}=R <- RegList] of
- [] -> D;
- [_|_] -> btb_error({multiple_uses,RegList})
+ YRegs = [R || {y,_}=R <- RegList],
+ case btb_are_all_unused(YRegs, Is, D) of
+ true -> D;
+ false -> btb_error({multiple_uses,RegList})
end;
true ->
%% No match context in any x register. It could have been
@@ -475,21 +449,12 @@ btb_reaches_match_block([{set,Ds,Ss,_}=I|Is], Regs0) ->
btb_reaches_match_block([], Regs) ->
Regs.
-%% btb_regs_from_arity(Arity) -> [Register])
-%% Create a list of x registers from a function arity.
-
-btb_regs_from_arity(Arity) ->
- btb_regs_from_arity_1(Arity, []).
-
-btb_regs_from_arity_1(0, Acc) -> Acc;
-btb_regs_from_arity_1(N, Acc) -> btb_regs_from_arity_1(N-1, [{x,N-1}|Acc]).
-
%% btb_are_all_killed([Register], [Instruction], D) -> true|false
-%% Test whether all of the register are killed in the instruction stream.
+%% Test whether all of the register are unused in the instruction stream.
-btb_are_all_killed(RegList, Is, #btb{index=Li}) ->
+btb_are_all_unused(RegList, Is, #btb{index=Li}) ->
all(fun(R) ->
- beam_utils:is_killed(R, Is, Li)
+ beam_utils:is_not_used(R, Is, Li)
end, RegList).
%% btp_regs_from_list([Register]) -> RegisterSet.
diff --git a/lib/compiler/src/beam_clean.erl b/lib/compiler/src/beam_clean.erl
index a7994ab3b3..e208ffec1f 100644
--- a/lib/compiler/src/beam_clean.erl
+++ b/lib/compiler/src/beam_clean.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -74,10 +74,6 @@ find_all_used([], _All, Used) -> Used.
update_work_list([{call,_,{f,L}}|Is], Sets) ->
update_work_list(Is, add_to_work_list(L, Sets));
-update_work_list([{call_last,_,{f,L},_}|Is], Sets) ->
- update_work_list(Is, add_to_work_list(L, Sets));
-update_work_list([{call_only,_,{f,L}}|Is], Sets) ->
- update_work_list(Is, add_to_work_list(L, Sets));
update_work_list([{make_fun2,{f,L},_,_,_}|Is], Sets) ->
update_work_list(Is, add_to_work_list(L, Sets));
update_work_list([_|Is], Sets) ->
@@ -200,7 +196,7 @@ replace([{test,Test,{f,Lbl},Ops}|Is], Acc, D) ->
replace(Is, [{test,Test,{f,label(Lbl, D)},Ops}|Acc], D);
replace([{test,Test,{f,Lbl},Live,Ops,Dst}|Is], Acc, D) ->
replace(Is, [{test,Test,{f,label(Lbl, D)},Live,Ops,Dst}|Acc], D);
-replace([{select_val,R,{f,Fail0},{list,Vls0}}|Is], Acc, D) ->
+replace([{select,I,R,{f,Fail0},Vls0}|Is], Acc, D) ->
Vls1 = map(fun ({f,L}) -> {f,label(L, D)};
(Other) -> Other end, Vls0),
Fail = label(Fail0, D),
@@ -210,12 +206,8 @@ replace([{select_val,R,{f,Fail0},{list,Vls0}}|Is], Acc, D) ->
%% Convert to a plain jump.
replace(Is, [{jump,{f,Fail}}|Acc], D);
Vls ->
- replace(Is, [{select_val,R,{f,Fail},{list,Vls}}|Acc], D)
+ replace(Is, [{select,I,R,{f,Fail},Vls}|Acc], D)
end;
-replace([{select_tuple_arity,R,{f,Fail},{list,Vls0}}|Is], Acc, D) ->
- Vls = map(fun ({f,L}) -> {f,label(L, D)};
- (Other) -> Other end, Vls0),
- replace(Is, [{select_tuple_arity,R,{f,label(Fail, D)},{list,Vls}}|Acc], D);
replace([{'try',R,{f,Lbl}}|Is], Acc, D) ->
replace(Is, [{'try',R,{f,label(Lbl, D)}}|Acc], D);
replace([{'catch',R,{f,Lbl}}|Is], Acc, D) ->
@@ -236,37 +228,12 @@ replace([{gc_bif,Name,{f,Lbl},Live,As,R}|Is], Acc, D) when Lbl =/= 0 ->
replace(Is, [{gc_bif,Name,{f,label(Lbl, D)},Live,As,R}|Acc], D);
replace([{call,Ar,{f,Lbl}}|Is], Acc, D) ->
replace(Is, [{call,Ar,{f,label(Lbl,D)}}|Acc], D);
-replace([{call_last,Ar,{f,Lbl},N}|Is], Acc, D) ->
- replace(Is, [{call_last,Ar,{f,label(Lbl,D)},N}|Acc], D);
-replace([{call_only,Ar,{f,Lbl}}|Is], Acc, D) ->
- replace(Is, [{call_only,Ar,{f,label(Lbl, D)}}|Acc], D);
replace([{make_fun2,{f,Lbl},U1,U2,U3}|Is], Acc, D) ->
replace(Is, [{make_fun2,{f,label(Lbl, D)},U1,U2,U3}|Acc], D);
-replace([{bs_init2,{f,Lbl},Sz,Words,R,F,Dst}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{bs_init2,{f,label(Lbl, D)},Sz,Words,R,F,Dst}|Acc], D);
-replace([{bs_init_bits,{f,Lbl},Sz,Words,R,F,Dst}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{bs_init_bits,{f,label(Lbl, D)},Sz,Words,R,F,Dst}|Acc], D);
-replace([{bs_put_integer,{f,Lbl},Bits,Unit,Fl,Val}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{bs_put_integer,{f,label(Lbl, D)},Bits,Unit,Fl,Val}|Acc], D);
-replace([{bs_put_utf8=I,{f,Lbl},Fl,Val}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{I,{f,label(Lbl, D)},Fl,Val}|Acc], D);
-replace([{bs_put_utf16=I,{f,Lbl},Fl,Val}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{I,{f,label(Lbl, D)},Fl,Val}|Acc], D);
-replace([{bs_put_utf32=I,{f,Lbl},Fl,Val}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{I,{f,label(Lbl, D)},Fl,Val}|Acc], D);
-replace([{bs_put_binary,{f,Lbl},Bits,Unit,Fl,Val}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{bs_put_binary,{f,label(Lbl, D)},Bits,Unit,Fl,Val}|Acc], D);
-replace([{bs_put_float,{f,Lbl},Bits,Unit,Fl,Val}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{bs_put_float,{f,label(Lbl, D)},Bits,Unit,Fl,Val}|Acc], D);
-replace([{bs_add,{f,Lbl},Src,Dst}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{bs_add,{f,label(Lbl, D)},Src,Dst}|Acc], D);
-replace([{bs_append,{f,Lbl},_,_,_,_,_,_,_}=I0|Is], Acc, D) when Lbl =/= 0 ->
- I = setelement(2, I0, {f,label(Lbl, D)}),
- replace(Is, [I|Acc], D);
-replace([{bs_utf8_size=I,{f,Lbl},Src,Dst}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{I,{f,label(Lbl, D)},Src,Dst}|Acc], D);
-replace([{bs_utf16_size=I,{f,Lbl},Src,Dst}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{I,{f,label(Lbl, D)},Src,Dst}|Acc], D);
+replace([{bs_init,{f,Lbl},Info,Live,Ss,Dst}|Is], Acc, D) when Lbl =/= 0 ->
+ replace(Is, [{bs_init,{f,label(Lbl, D)},Info,Live,Ss,Dst}|Acc], D);
+replace([{bs_put,{f,Lbl},Info,Ss}|Is], Acc, D) when Lbl =/= 0 ->
+ replace(Is, [{bs_put,{f,label(Lbl, D)},Info,Ss}|Acc], D);
replace([I|Is], Acc, D) ->
replace(Is, [I|Acc], D);
replace([], Acc, _) -> Acc.
diff --git a/lib/compiler/src/beam_dead.erl b/lib/compiler/src/beam_dead.erl
index 5f12a98f09..b15adfa889 100644
--- a/lib/compiler/src/beam_dead.erl
+++ b/lib/compiler/src/beam_dead.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -182,7 +182,7 @@ forward(Is, Lc) ->
forward([{block,[]}|Is], D, Lc, Acc) ->
%% Empty blocks can prevent optimizations.
forward(Is, D, Lc, Acc);
-forward([{select_val,Reg,_,{list,List}}=I|Is], D0, Lc, Acc) ->
+forward([{select,select_val,Reg,_,List}=I|Is], D0, Lc, Acc) ->
D = update_value_dict(List, Reg, D0),
forward(Is, D, Lc, [I|Acc]);
forward([{label,Lbl}=LblI,{block,[{set,[Dst],[Lit],move}|BlkIs]}=Blk|Is], D, Lc, Acc) ->
@@ -271,11 +271,11 @@ backward([{test,is_eq_exact,Fail,[Dst,{integer,Arity}]}=I|
end;
backward([{label,Lbl}=L|Is], D, Acc) ->
backward(Is, beam_utils:index_label(Lbl, Acc, D), [L|Acc]);
-backward([{select_val,Reg,{f,Fail0},{list,List0}}|Is], D, Acc) ->
+backward([{select,select_val,Reg,{f,Fail0},List0}|Is], D, Acc) ->
List = shortcut_select_list(List0, Reg, D, []),
Fail1 = shortcut_label(Fail0, D),
Fail = shortcut_bs_test(Fail1, Is, D),
- Sel = {select_val,Reg,{f,Fail},{list,List}},
+ Sel = {select,select_val,Reg,{f,Fail},List},
backward(Is, D, [Sel|Acc]);
backward([{jump,{f,To0}},{move,Src,Reg}=Move0|Is], D, Acc) ->
{To,Move} = case Src of
@@ -382,7 +382,7 @@ shortcut_select_label(To0, Reg, Val, D) ->
case beam_utils:code_at(To0, D) of
[{jump,{f,To}}|_] ->
shortcut_select_label(To, Reg, Val, D);
- [{test,is_atom,_,[Reg]},{select_val,Reg,{f,Fail},{list,Map}}|_] ->
+ [{test,is_atom,_,[Reg]},{select,select_val,Reg,{f,Fail},Map}|_] ->
To = find_select_val(Map, Val, Fail),
shortcut_select_label(To, Reg, Val, D);
[{test,is_eq_exact,{f,_},[Reg,{atom,Val}]},{label,To}|_] when is_atom(Val) ->
@@ -472,10 +472,10 @@ combine_eqs(To, [Reg,{Type,_}=Lit1]=Ops, D, [{label,L1}|_])
case beam_utils:code_at(To, D) of
[{test,is_eq_exact,{f,F2},[Reg,{Type,_}=Lit2]},
{label,L2}|_] when Lit1 =/= Lit2 ->
- {select_val,Reg,{f,F2},{list,[Lit1,{f,L1},Lit2,{f,L2}]}};
- [{select_val,Reg,{f,F2},{list,[{Type,_}|_]=List0}}|_] ->
+ {select,select_val,Reg,{f,F2},[Lit1,{f,L1},Lit2,{f,L2}]};
+ [{select,select_val,Reg,{f,F2},[{Type,_}|_]=List0}|_] ->
List = remove_from_list(Lit1, List0),
- {select_val,Reg,{f,F2},{list,[Lit1,{f,L1}|List]}};
+ {select,select_val,Reg,{f,F2},[Lit1,{f,L1}|List]};
_Is ->
{test,is_eq_exact,{f,To},Ops}
end;
@@ -527,6 +527,8 @@ count_bits_matched([{test,_,_,_,[_,Sz,U,{field_flags,_}],_}|Is], SavePoint, Bits
{integer,N} -> count_bits_matched(Is, SavePoint, Bits+N*U);
_ -> count_bits_matched(Is, SavePoint, Bits)
end;
+count_bits_matched([{test,bs_match_string,_,[_,Bits,_]}|Is], SavePoint, Bits0) ->
+ count_bits_matched(Is, SavePoint, Bits0+Bits);
count_bits_matched([{test,_,_,_}|Is], SavePoint, Bits) ->
count_bits_matched(Is, SavePoint, Bits);
count_bits_matched([{bs_save2,Reg,SavePoint}|_], {Reg,SavePoint}, Bits) ->
diff --git a/lib/compiler/src/beam_dict.erl b/lib/compiler/src/beam_dict.erl
index 531968b3c8..212b9fb03a 100644
--- a/lib/compiler/src/beam_dict.erl
+++ b/lib/compiler/src/beam_dict.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
diff --git a/lib/compiler/src/beam_disasm.erl b/lib/compiler/src/beam_disasm.erl
index 62bdc74cc8..1a8bbcee22 100644
--- a/lib/compiler/src/beam_disasm.erl
+++ b/lib/compiler/src/beam_disasm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -512,7 +512,12 @@ decode_z_tagged(Tag,B,Bs,Literals) when (B band 16#08) =:= 0 ->
decode_alloc_list(Bs, Literals);
4 -> % literal
{{u,LitIndex},RestBs} = decode_arg(Bs),
- {{literal,gb_trees:get(LitIndex, Literals)},RestBs};
+ case gb_trees:get(LitIndex, Literals) of
+ Float when is_float(Float) ->
+ {{float,Float},RestBs};
+ Literal ->
+ {{literal,Literal},RestBs}
+ end;
_ ->
?exit({decode_z_tagged,{invalid_extended_tag,N}})
end;
diff --git a/lib/compiler/src/beam_except.erl b/lib/compiler/src/beam_except.erl
index fb1a43cd9e..e5ec1bd904 100644
--- a/lib/compiler/src/beam_except.erl
+++ b/lib/compiler/src/beam_except.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -49,13 +49,14 @@ function({function,Name,Arity,CLabel,Is0}) ->
-record(st,
{lbl, %func_info label
- loc %location for func_info
+ loc, %location for func_info
+ arity %arity for function
}).
function_1(Is0) ->
case Is0 of
- [{label,Lbl},{line,Loc}|_] ->
- St = #st{lbl=Lbl,loc=Loc},
+ [{label,Lbl},{line,Loc},{func_info,_,_,Arity}|_] ->
+ St = #st{lbl=Lbl,loc=Loc,arity=Arity},
translate(Is0, St, []);
[{label,_}|_] ->
%% No line numbers. The source must be a .S file.
@@ -65,10 +66,6 @@ function_1(Is0) ->
translate([{call_ext,Ar,{extfunc,erlang,error,Ar}}=I|Is], St, Acc) ->
translate_1(Ar, I, Is, St, Acc);
-translate([{call_ext_only,Ar,{extfunc,erlang,error,Ar}}=I|Is], St, Acc) ->
- translate_1(Ar, I, Is, St, Acc);
-translate([{call_ext_last,Ar,{extfunc,erlang,error,Ar},_}=I|Is], St, Acc) ->
- translate_1(Ar, I, Is, St, Acc);
translate([I|Is], St, Acc) ->
translate(Is, St, [I|Acc]);
translate([], _, Acc) ->
@@ -78,14 +75,14 @@ translate_1(Ar, I, Is, St, [{line,_}=Line|Acc1]=Acc0) ->
case dig_out(Ar, Acc1) of
no ->
translate(Is, St, [I|Acc0]);
- {yes,function_clause,Acc2} ->
+ {yes,{function_clause,Arity},Acc2} ->
case {Line,St} of
- {{line,Loc},#st{lbl=Fi,loc=Loc}} ->
+ {{line,Loc},#st{lbl=Fi,loc=Loc,arity=Arity}} ->
Instr = {jump,{f,Fi}},
translate(Is, St, [Instr|Acc2]);
{_,_} ->
%% This must be "error(function_clause, Args)" in
- %% the Erlang source code. Don't translate.
+ %% the Erlang source code or a fun. Don't translate.
translate(Is, St, [I|Acc0])
end;
{yes,Instr,Acc2} ->
@@ -139,11 +136,16 @@ fix_block(Is0, Words) ->
[{set,[],[],{alloc,Live,{F1,F2,Needed-Words,F3}}}|Is].
dig_out_block_fc([{set,[],[],{alloc,Live,_}}|Bl]) ->
- dig_out_fc(Bl, Live-1, nil);
+ case dig_out_fc(Bl, Live-1, nil) of
+ no ->
+ no;
+ yes ->
+ {yes,{function_clause,Live}}
+ end;
dig_out_block_fc(_) -> no.
dig_out_fc([{set,[Dst],[{x,Reg},Dst0],put_list}|Is], Reg, Dst0) ->
dig_out_fc(Is, Reg-1, Dst);
dig_out_fc([{set,[{x,0}],[{atom,function_clause}],move}], -1, {x,1}) ->
- {yes,function_clause};
+ yes;
dig_out_fc(_, _, _) -> no.
diff --git a/lib/compiler/src/beam_flatten.erl b/lib/compiler/src/beam_flatten.erl
index 6c7cb849aa..25428c0c10 100644
--- a/lib/compiler/src/beam_flatten.erl
+++ b/lib/compiler/src/beam_flatten.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -79,49 +79,28 @@ norm_allocate({nozero,Ns,Nh,Inits}, Regs) ->
%% insert_alloc_in_bs_init(ReverseInstructionStream, AllocationInfo) ->
%% impossible | ReverseInstructionStream'
-%% A bs_init2/6 instruction should not be followed by a test heap instruction.
+%% A bs_init/6 instruction should not be followed by a test heap instruction.
%% Given the AllocationInfo from a test heap instruction, merge the
-%% allocation amounts into the previous bs_init2/6 instruction (if any).
+%% allocation amounts into the previous bs_init/6 instruction (if any).
%%
-insert_alloc_in_bs_init([I|_]=Is, Alloc) ->
- case is_bs_constructor(I) of
- false -> impossible;
- true -> insert_alloc_1(Is, Alloc, [])
- end.
-
-insert_alloc_1([{bs_init2=Op,Fail,Bs,Ws1,Regs,F,Dst}|Is], {_,nostack,Ws2,[]}, Acc) ->
- Al = beam_utils:combine_heap_needs(Ws1, Ws2),
- I = {Op,Fail,Bs,Al,Regs,F,Dst},
- reverse(Acc, [I|Is]);
-insert_alloc_1([{bs_init_bits=Op,Fail,Bs,Ws1,Regs,F,Dst}|Is], {_,nostack,Ws2,[]}, Acc) ->
- Al = beam_utils:combine_heap_needs(Ws1, Ws2),
- I = {Op,Fail,Bs,Al,Regs,F,Dst},
- reverse(Acc, [I|Is]);
-insert_alloc_1([{bs_append,Fail,Sz,Ws1,Regs,U,Bin,Fl,Dst}|Is],
- {_,nostack,Ws2,[]}, Acc) ->
+insert_alloc_in_bs_init([{bs_put,_,_,_}=I|Is], Alloc) ->
+ %% The instruction sequence ends with an bs_put/4 instruction.
+ %% We'll need to search backwards for the bs_init/6 instruction.
+ insert_alloc_1(Is, Alloc, [I]);
+insert_alloc_in_bs_init(_, _) -> impossible.
+
+insert_alloc_1([{bs_init=Op,Fail,Info0,Live,Ss,Dst}|Is],
+ {_,nostack,Ws2,[]}, Acc) when is_integer(Live) ->
+ %% The number of extra heap words is always in the second position
+ %% in the Info tuple.
+ Ws1 = element(2, Info0),
Al = beam_utils:combine_heap_needs(Ws1, Ws2),
- I = {bs_append,Fail,Sz,Al,Regs,U,Bin,Fl,Dst},
+ Info = setelement(2, Info0, Al),
+ I = {Op,Fail,Info,Live,Ss,Dst},
reverse(Acc, [I|Is]);
-insert_alloc_1([I|Is], Alloc, Acc) ->
+insert_alloc_1([{bs_put,_,_,_}=I|Is], Alloc, Acc) ->
insert_alloc_1(Is, Alloc, [I|Acc]).
-
-%% is_bs_constructor(Instruction) -> true|false.
-%% Test whether the instruction is a bit syntax construction
-%% instruction that can occur at the end of a bit syntax
-%% construction. (Since an empty binary would be expressed
-%% as a literal, the bs_init2/6 instruction will not occur
-%% at the end and therefore it is no need to test for it here.)
-%%
-is_bs_constructor({bs_put_integer,_,_,_,_,_}) -> true;
-is_bs_constructor({bs_put_utf8,_,_,_}) -> true;
-is_bs_constructor({bs_put_utf16,_,_,_}) -> true;
-is_bs_constructor({bs_put_utf32,_,_,_}) -> true;
-is_bs_constructor({bs_put_float,_,_,_,_,_}) -> true;
-is_bs_constructor({bs_put_binary,_,_,_,_,_}) -> true;
-is_bs_constructor({bs_put_string,_,_}) -> true;
-is_bs_constructor(_) -> false.
-
%% opt(Is0) -> Is
%% Simple peep-hole optimization to move a {move,Any,{x,0}} past
%% any kill up to the next call instruction. (To give the loader
diff --git a/lib/compiler/src/beam_jump.erl b/lib/compiler/src/beam_jump.erl
index db67d24514..b29a3565e4 100644
--- a/lib/compiler/src/beam_jump.erl
+++ b/lib/compiler/src/beam_jump.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -20,7 +20,7 @@
-module(beam_jump).
--export([module/2,module_labels/1,
+-export([module/2,
is_unreachable_after/1,is_exit_instruction/1,
remove_unused_labels/1,is_label_used_in/2]).
@@ -46,10 +46,13 @@
%%% such as a jump that never transfers control to the instruction
%%% following it.
%%%
-%%% (2) case_end, if_end, and badmatch, and function calls that cause an
-%%% exit (such as calls to exit/1) are moved to the end of the function.
-%%% The purpose is to allow further optimizations at the place from
-%%% which the code was moved.
+%%% (2) Short sequences starting with a label and ending in case_end, if_end,
+%%% and badmatch, and function calls that cause an exit (such as calls
+%%% to exit/1) are moved to the end of the function, but only if the
+%%% the block is not entered via a fallthrough. The purpose of this move
+%%% is to allow further optimizations at the place from which the
+%%% code was moved (a jump around the block could be replaced with a
+%%% fallthrough).
%%%
%%% (3) Any unreachable code is removed. Unreachable code is code
%%% after jump, call_last and other instructions which never
@@ -130,13 +133,6 @@ module({Mod,Exp,Attr,Fs0,Lc}, _Opt) ->
Fs = [function(F) || F <- Fs0],
{ok,{Mod,Exp,Attr,Fs,Lc}}.
-module_labels({Mod,Exp,Attr,Fs,Lc}) ->
- {Mod,Exp,Attr,[function_labels(F) || F <- Fs],Lc}.
-
-function_labels({function,Name,Arity,CLabel,Asm0}) ->
- Asm = remove_unused_labels(Asm0),
- {function,Name,Arity,CLabel,Asm}.
-
%% function(Function) -> Function'
%% Optimize jumps and branches.
%%
@@ -224,6 +220,8 @@ extract_seq([{line,_}=Line|Is], Acc) ->
extract_seq(Is, [Line|Acc]);
extract_seq([{block,_}=Bl|Is], Acc) ->
extract_seq_1(Is, [Bl|Acc]);
+extract_seq([{bs_context_to_binary,_}=I|Is], Acc) ->
+ extract_seq_1(Is, [I|Acc]);
extract_seq([{label,_}|_]=Is, Acc) ->
extract_seq_1(Is, Acc);
extract_seq(_, _) -> no.
@@ -232,6 +230,9 @@ extract_seq_1([{line,_}=Line|Is], Acc) ->
extract_seq_1(Is, [Line|Acc]);
extract_seq_1([{label,_},{func_info,_,_,_}|_], _) ->
no;
+extract_seq_1([{label,Lbl},{jump,{f,Lbl}}|_], _) ->
+ %% Don't move a sequence which have a fallthrough entering it.
+ no;
extract_seq_1([{label,_}=Lbl|Is], Acc) ->
{yes,[Lbl|Acc],Is};
extract_seq_1(_, _) -> no.
@@ -260,43 +261,39 @@ find_fixpoint(OptFun, Is0) ->
Is -> find_fixpoint(OptFun, Is)
end.
-opt([{test,Test0,{f,Lnum}=Lbl,Ops}=I|Is0], Acc, St) ->
- case Is0 of
- [{jump,{f,Lnum}}|Is] ->
- %% We have
- %% Test Label Ops
- %% jump Label
- %% The test instruction is definitely not needed.
- %% The jump instruction is not needed if there is
- %% a definition of Label following the jump instruction.
- case is_label_defined(Is, Lnum) of
- false ->
- %% The jump instruction is still needed.
- opt(Is0, [I|Acc], label_used(Lbl, St));
- true ->
- %% Neither the test nor the jump are needed.
- opt(Is, Acc, St)
- end;
- [{jump,To}|Is] ->
- case is_label_defined(Is, Lnum) of
- false ->
+opt([{test,_,{f,L}=Lbl,_}=I|[{jump,{f,L}}|_]=Is], Acc, St) ->
+ %% We have
+ %% Test Label Ops
+ %% jump Label
+ %% The test instruction is not needed if the test is pure
+ %% (it modifies neither registers nor bit syntax state).
+ case beam_utils:is_pure_test(I) of
+ false ->
+ %% Test is not pure; we must keep it.
+ opt(Is, [I|Acc], label_used(Lbl, St));
+ true ->
+ %% The test is pure and its failure label is the same
+ %% as in the jump that follows -- thus it is not needed.
+ opt(Is, Acc, St)
+ end;
+opt([{test,Test0,{f,L}=Lbl,Ops}=I|[{jump,To}|Is]=Is0], Acc, St) ->
+ case is_label_defined(Is, L) of
+ false ->
+ opt(Is0, [I|Acc], label_used(Lbl, St));
+ true ->
+ case invert_test(Test0) of
+ not_possible ->
opt(Is0, [I|Acc], label_used(Lbl, St));
- true ->
- case invert_test(Test0) of
- not_possible ->
- opt(Is0, [I|Acc], label_used(Lbl, St));
- Test ->
- opt([{test,Test,To,Ops}|Is], Acc, St)
- end
- end;
- _Other ->
- opt(Is0, [I|Acc], label_used(Lbl, St))
+ Test ->
+ %% Invert the test and remove the jump.
+ opt([{test,Test,To,Ops}|Is], Acc, St)
+ end
end;
+opt([{test,_,{f,_}=Lbl,_}=I|Is], Acc, St) ->
+ opt(Is, [I|Acc], label_used(Lbl, St));
opt([{test,_,{f,_}=Lbl,_,_,_}=I|Is], Acc, St) ->
opt(Is, [I|Acc], label_used(Lbl, St));
-opt([{select_val,_R,Fail,{list,Vls}}=I|Is], Acc, St) ->
- skip_unreachable(Is, [I|Acc], label_used([Fail|Vls], St));
-opt([{select_tuple_arity,_R,Fail,{list,Vls}}=I|Is], Acc, St) ->
+opt([{select,_,_R,Fail,Vls}=I|Is], Acc, St) ->
skip_unreachable(Is, [I|Acc], label_used([Fail|Vls], St));
opt([{label,L}=I|Is], Acc, #st{entry=L}=St) ->
%% NEVER move the entry label.
@@ -412,14 +409,8 @@ is_label_used(L, St) ->
is_unreachable_after({func_info,_M,_F,_A}) -> true;
is_unreachable_after(return) -> true;
-is_unreachable_after({call_ext_last,_Ar,_ExtFunc,_D}) -> true;
-is_unreachable_after({call_ext_only,_Ar,_ExtFunc}) -> true;
-is_unreachable_after({call_last,_Ar,_Lbl,_D}) -> true;
-is_unreachable_after({call_only,_Ar,_Lbl}) -> true;
-is_unreachable_after({apply_last,_Ar,_N}) -> true;
is_unreachable_after({jump,_Lbl}) -> true;
-is_unreachable_after({select_val,_R,_Lbl,_Cases}) -> true;
-is_unreachable_after({select_tuple_arity,_R,_Lbl,_Cases}) -> true;
+is_unreachable_after({select,_What,_R,_Lbl,_Cases}) -> true;
is_unreachable_after({loop_rec_end,_}) -> true;
is_unreachable_after({wait,_}) -> true;
is_unreachable_after(I) -> is_exit_instruction(I).
@@ -430,10 +421,6 @@ is_unreachable_after(I) -> is_exit_instruction(I).
is_exit_instruction({call_ext,_,{extfunc,M,F,A}}) ->
erl_bifs:is_exit_bif(M, F, A);
-is_exit_instruction({call_ext_last,_,{extfunc,M,F,A},_}) ->
- erl_bifs:is_exit_bif(M, F, A);
-is_exit_instruction({call_ext_only,_,{extfunc,M,F,A}}) ->
- erl_bifs:is_exit_bif(M, F, A);
is_exit_instruction(if_end) -> true;
is_exit_instruction({case_end,_}) -> true;
is_exit_instruction({try_case_end,_}) -> true;
@@ -516,9 +503,7 @@ ulbl({test,_,Fail,_}, Used) ->
mark_used(Fail, Used);
ulbl({test,_,Fail,_,_,_}, Used) ->
mark_used(Fail, Used);
-ulbl({select_val,_,Fail,{list,Vls}}, Used) ->
- mark_used_list(Vls, mark_used(Fail, Used));
-ulbl({select_tuple_arity,_,Fail,{list,Vls}}, Used) ->
+ulbl({select,_,_,Fail,Vls}, Used) ->
mark_used_list(Vls, mark_used(Fail, Used));
ulbl({'try',_,Lbl}, Used) ->
mark_used(Lbl, Used);
@@ -538,29 +523,9 @@ ulbl({bif,_Name,Lbl,_As,_R}, Used) ->
mark_used(Lbl, Used);
ulbl({gc_bif,_Name,Lbl,_Live,_As,_R}, Used) ->
mark_used(Lbl, Used);
-ulbl({bs_init2,Lbl,_,_,_,_,_}, Used) ->
- mark_used(Lbl, Used);
-ulbl({bs_init_bits,Lbl,_,_,_,_,_}, Used) ->
- mark_used(Lbl, Used);
-ulbl({bs_put_integer,Lbl,_Bits,_Unit,_Fl,_Val}, Used) ->
- mark_used(Lbl, Used);
-ulbl({bs_put_float,Lbl,_Bits,_Unit,_Fl,_Val}, Used) ->
- mark_used(Lbl, Used);
-ulbl({bs_put_binary,Lbl,_Bits,_Unit,_Fl,_Val}, Used) ->
- mark_used(Lbl, Used);
-ulbl({bs_put_utf8,Lbl,_Fl,_Val}, Used) ->
- mark_used(Lbl, Used);
-ulbl({bs_put_utf16,Lbl,_Fl,_Val}, Used) ->
- mark_used(Lbl, Used);
-ulbl({bs_put_utf32,Lbl,_Fl,_Val}, Used) ->
- mark_used(Lbl, Used);
-ulbl({bs_add,Lbl,_,_}, Used) ->
- mark_used(Lbl, Used);
-ulbl({bs_append,Lbl,_,_,_,_,_,_,_}, Used) ->
- mark_used(Lbl, Used);
-ulbl({bs_utf8_size,Lbl,_,_}, Used) ->
+ulbl({bs_init,Lbl,_,_,_,_}, Used) ->
mark_used(Lbl, Used);
-ulbl({bs_utf16_size,Lbl,_,_}, Used) ->
+ulbl({bs_put,Lbl,_,_}, Used) ->
mark_used(Lbl, Used);
ulbl(_, Used) -> Used.
diff --git a/lib/compiler/src/beam_peep.erl b/lib/compiler/src/beam_peep.erl
index f39fc50b95..97a8c7ba70 100644
--- a/lib/compiler/src/beam_peep.erl
+++ b/lib/compiler/src/beam_peep.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -120,13 +120,13 @@ peep([{test,Op,_,Ops}=I|Is], SeenTests0, Acc) ->
peep(Is, SeenTests, [I|Acc])
end
end;
-peep([{select_val,Src,Fail,
- {list,[{atom,false},{f,L},{atom,true},{f,L}]}}|
+peep([{select,select_val,Src,Fail,
+ [{atom,false},{f,L},{atom,true},{f,L}]}|
[{label,L}|_]=Is], SeenTests, Acc) ->
I = {test,is_boolean,Fail,[Src]},
peep([I|Is], SeenTests, Acc);
-peep([{select_val,Src,Fail,
- {list,[{atom,true},{f,L},{atom,false},{f,L}]}}|
+peep([{select,select_val,Src,Fail,
+ [{atom,true},{f,L},{atom,false},{f,L}]}|
[{label,L}|_]=Is], SeenTests, Acc) ->
I = {test,is_boolean,Fail,[Src]},
peep([I|Is], SeenTests, Acc);
diff --git a/lib/compiler/src/beam_receive.erl b/lib/compiler/src/beam_receive.erl
index bd1f44f66b..3dd5ed182e 100644
--- a/lib/compiler/src/beam_receive.erl
+++ b/lib/compiler/src/beam_receive.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -84,13 +84,29 @@ function({function,Name,Arity,Entry,Is}) ->
erlang:raise(Class, Error, Stack)
end.
+opt([{call_ext,A,{extfunc,erlang,spawn_monitor,A}}=I0|Is0], D, Acc)
+ when A =:= 1; A =:= 3 ->
+ case ref_in_tuple(Is0) of
+ no ->
+ opt(Is0, D, [I0|Acc]);
+ {yes,Regs,Is1,MatchReversed} ->
+ %% The call creates a brand new reference. Now
+ %% search for a receive statement in the same
+ %% function that will match against the reference.
+ case opt_recv(Is1, Regs, D) of
+ no ->
+ opt(Is0, D, [I0|Acc]);
+ {yes,Is,Lbl} ->
+ opt(Is, D, MatchReversed++[I0,{recv_mark,{f,Lbl}}|Acc])
+ end
+ end;
opt([{call_ext,Arity,{extfunc,erlang,Name,Arity}}=I|Is0], D, Acc) ->
case creates_new_ref(Name, Arity) of
true ->
%% The call creates a brand new reference. Now
%% search for a receive statement in the same
%% function that will match against the reference.
- case opt_recv(Is0, D) of
+ case opt_recv(Is0, regs_init_x0(), D) of
no ->
opt(Is0, D, [I|Acc]);
{yes,Is,Lbl} ->
@@ -104,19 +120,34 @@ opt([I|Is], D, Acc) ->
opt([], _, Acc) ->
reverse(Acc).
+ref_in_tuple([{test,is_tuple,_,[{x,0}]}=I1,
+ {test,test_arity,_,[{x,0},2]}=I2,
+ {block,[{set,[_],[{x,0}],{get_tuple_element,0}},
+ {set,[Dst],[{x,0}],{get_tuple_element,1}}|Bl]}=I3|Is]) ->
+ ref_in_tuple_1(Bl, Dst, Is, [I3,I2,I1]);
+ref_in_tuple([{test,is_tuple,_,[{x,0}]}=I1,
+ {test,test_arity,_,[{x,0},2]}=I2,
+ {block,[{set,[Dst],[{x,0}],{get_tuple_element,1}}|Bl]}=I3|Is]) ->
+ ref_in_tuple_1(Bl, Dst, Is, [I3,I2,I1]);
+ref_in_tuple(_) -> no.
+
+ref_in_tuple_1(Bl, Dst, Is, MatchReversed) ->
+ Regs0 = regs_init_singleton(Dst),
+ Regs = opt_update_regs_bl(Bl, Regs0),
+ {yes,Regs,Is,MatchReversed}.
+
%% creates_new_ref(Name, Arity) -> true|false.
%% Return 'true' if the BIF Name/Arity will create a new reference.
creates_new_ref(monitor, 2) -> true;
creates_new_ref(make_ref, 0) -> true;
creates_new_ref(_, _) -> false.
-%% opt_recv([Instruction], LabelIndex) -> no|{yes,[Instruction]}
+%% opt_recv([Instruction], Regs, LabelIndex) -> no|{yes,[Instruction]}
%% Search for a receive statement that will only retrieve messages
%% that contain the newly created reference (which is currently in {x,0}).
-opt_recv(Is, D) ->
- R = regs_init_x0(),
+opt_recv(Is, Regs, D) ->
L = gb_sets:empty(),
- opt_recv(Is, D, R, L, []).
+ opt_recv(Is, D, Regs, L, []).
opt_recv([{label,L}=Lbl,{loop_rec,{f,Fail},_}=Loop|Is], D, R0, _, Acc) ->
R = regs_kill_not_live(0, R0),
@@ -157,8 +188,6 @@ opt_update_regs({call_fun,_}, R, L) ->
{regs_kill_not_live(0, R),L};
opt_update_regs({kill,Y}, R, L) ->
{regs_kill([Y], R),L};
-opt_update_regs(send, R, L) ->
- {regs_kill_not_live(0, R),L};
opt_update_regs({'catch',_,{f,Lbl}}, R, L) ->
{R,gb_sets:add(Lbl, L)};
opt_update_regs({catch_end,_}, R, L) ->
@@ -220,7 +249,7 @@ opt_ref_used(Is, RefReg, Fail, D) ->
Done = gb_sets:singleton(Fail),
Regs = regs_init_x0(),
try
- opt_ref_used_1(Is, RefReg, D, Done, Regs),
+ _ = opt_ref_used_1(Is, RefReg, D, Done, Regs),
true
catch
throw:not_used ->
@@ -253,10 +282,7 @@ opt_ref_used_1([{test,is_ne_exact,{f,Fail},Args}|Is], RefReg, D, Done0, Regs) ->
opt_ref_used_1([{test,_,{f,Fail},_}|Is], RefReg, D, Done0, Regs) ->
Done = opt_ref_used_at(Fail, RefReg, D, Done0, Regs),
opt_ref_used_1(Is, RefReg, D, Done, Regs);
-opt_ref_used_1([{select_tuple_arity,_,{f,Fail},{list,List}}|_], RefReg, D, Done, Regs) ->
- Lbls = [F || {f,F} <- List] ++ [Fail],
- opt_ref_used_in_all(Lbls, RefReg, D, Done, Regs);
-opt_ref_used_1([{select_val,_,{f,Fail},{list,List}}|_], RefReg, D, Done, Regs) ->
+opt_ref_used_1([{select,_,_,{f,Fail},List}|_], RefReg, D, Done, Regs) ->
Lbls = [F || {f,F} <- List] ++ [Fail],
opt_ref_used_in_all(Lbls, RefReg, D, Done, Regs);
opt_ref_used_1([{label,Lbl}|Is], RefReg, D, Done, Regs) ->
@@ -323,6 +349,12 @@ opt_ref_used_bl([], Regs) -> Regs.
regs_init() ->
{0,0}.
+%% regs_init_singleton(Register) -> RegisterSet
+%% Return a set that only contains one register.
+
+regs_init_singleton(Reg) ->
+ regs_add(Reg, regs_init()).
+
%% regs_init_x0() -> RegisterSet
%% Return a set that only contains the {x,0} register.
diff --git a/lib/compiler/src/beam_trim.erl b/lib/compiler/src/beam_trim.erl
index 5f4fa3b1f8..fad9c42584 100644
--- a/lib/compiler/src/beam_trim.erl
+++ b/lib/compiler/src/beam_trim.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -172,38 +172,16 @@ remap([{bif,Name,Fail,Ss,D}|Is], Map, Acc) ->
remap([{gc_bif,Name,Fail,Live,Ss,D}|Is], Map, Acc) ->
I = {gc_bif,Name,Fail,Live,[Map(S) || S <- Ss],Map(D)},
remap(Is, Map, [I|Acc]);
-remap([{bs_add,Fail,[SrcA,SrcB,U],D}|Is], Map, Acc) ->
- I = {bs_add,Fail,[Map(SrcA),Map(SrcB),U],Map(D)},
+remap([{bs_init,Fail,Info,Live,Ss0,Dst0}|Is], Map, Acc) ->
+ Ss = [Map(Src) || Src <- Ss0],
+ Dst = Map(Dst0),
+ I = {bs_init,Fail,Info,Live,Ss,Dst},
remap(Is, Map, [I|Acc]);
-remap([{bs_append=Op,Fail,Bits,Heap,Live,Unit,Bin,Flags,D}|Is], Map, Acc) ->
- I = {Op,Fail,Map(Bits),Heap,Live,Unit,Map(Bin),Flags,Map(D)},
- remap(Is, Map, [I|Acc]);
-remap([{bs_private_append=Op,Fail,Bits,Unit,Bin,Flags,D}|Is], Map, Acc) ->
- I = {Op,Fail,Map(Bits),Unit,Map(Bin),Flags,Map(D)},
- remap(Is, Map, [I|Acc]);
-remap([bs_init_writable=I|Is], Map, Acc) ->
- remap(Is, Map, [I|Acc]);
-remap([{bs_init2,Fail,Src,Live,U,Flags,D}|Is], Map, Acc) ->
- I = {bs_init2,Fail,Map(Src),Live,U,Flags,Map(D)},
- remap(Is, Map, [I|Acc]);
-remap([{bs_init_bits,Fail,Src,Live,U,Flags,D}|Is], Map, Acc) ->
- I = {bs_init_bits,Fail,Map(Src),Live,U,Flags,Map(D)},
- remap(Is, Map, [I|Acc]);
-remap([{bs_put_binary=Op,Fail,Src,U,Flags,D}|Is], Map, Acc) ->
- I = {Op,Fail,Map(Src),U,Flags,Map(D)},
- remap(Is, Map, [I|Acc]);
-remap([{bs_put_integer=Op,Fail,Src,U,Flags,D}|Is], Map, Acc) ->
- I = {Op,Fail,Map(Src),U,Flags,Map(D)},
- remap(Is, Map, [I|Acc]);
-remap([{bs_put_float=Op,Fail,Src,U,Flags,D}|Is], Map, Acc) ->
- I = {Op,Fail,Map(Src),U,Flags,Map(D)},
- remap(Is, Map, [I|Acc]);
-remap([{bs_put_string,_,_}=I|Is], Map, Acc) ->
+remap([{bs_put=Op,Fail,Info,Ss}|Is], Map, Acc) ->
+ I = {Op,Fail,Info,[Map(S) || S <- Ss]},
remap(Is, Map, [I|Acc]);
remap([{kill,Y}|T], Map, Acc) ->
remap(T, Map, [{kill,Map(Y)}|Acc]);
-remap([send=I|T], Map, Acc) ->
- remap(T, Map, [I|Acc]);
remap([{make_fun2,_,_,_,_}=I|T], Map, Acc) ->
remap(T, Map, [I|Acc]);
remap([{deallocate,N}|Is], Map, Acc) ->
@@ -217,12 +195,6 @@ remap([{test,Name,Fail,Live,Ss,Dst}|Is], Map, Acc) ->
remap(Is, Map, [I|Acc]);
remap([return|_]=Is, _, Acc) ->
reverse(Acc, Is);
-remap([{call_last,Ar,Name,N}|Is], Map, Acc) ->
- I = {call_last,Ar,Name,Map({frame_size,N})},
- reverse(Acc, [I|Is]);
-remap([{call_ext_last,Ar,Name,N}|Is], Map, Acc) ->
- I = {call_ext_last,Ar,Name,Map({frame_size,N})},
- reverse(Acc, [I|Is]);
remap([{line,_}=I|Is], Map, Acc) ->
remap(Is, Map, [I|Acc]).
@@ -280,8 +252,8 @@ frame_size([{call_fun,_}|Is], Safe) ->
frame_size(Is, Safe);
frame_size([{call,_,_}|Is], Safe) ->
frame_size(Is, Safe);
-frame_size([{call_ext,A,{extfunc,M,F,A}}|Is], Safe) ->
- case erl_bifs:is_exit_bif(M, F, A) of
+frame_size([{call_ext,_,_}=I|Is], Safe) ->
+ case beam_jump:is_exit_instruction(I) of
true -> throw(not_possible);
false -> frame_size(Is, Safe)
end;
@@ -295,35 +267,15 @@ frame_size([{test,_,{f,L},_}|Is], Safe) ->
frame_size_branch(L, Is, Safe);
frame_size([{test,_,{f,L},_,_,_}|Is], Safe) ->
frame_size_branch(L, Is, Safe);
-frame_size([{bs_add,{f,L},_,_}|Is], Safe) ->
+frame_size([{bs_init,{f,L},_,_,_,_}|Is], Safe) ->
frame_size_branch(L, Is, Safe);
-frame_size([{bs_append,{f,L},_,_,_,_,_,_,_}|Is], Safe) ->
+frame_size([{bs_put,{f,L},_,_}|Is], Safe) ->
frame_size_branch(L, Is, Safe);
-frame_size([{bs_private_append,{f,L},_,_,_,_,_}|Is], Safe) ->
- frame_size_branch(L, Is, Safe);
-frame_size([bs_init_writable|Is], Safe) ->
- frame_size(Is, Safe);
-frame_size([{bs_init2,{f,L},_,_,_,_,_}|Is], Safe) ->
- frame_size_branch(L, Is, Safe);
-frame_size([{bs_init_bits,{f,L},_,_,_,_,_}|Is], Safe) ->
- frame_size_branch(L, Is, Safe);
-frame_size([{bs_put_binary,{f,L},_,_,_,_}|Is], Safe) ->
- frame_size_branch(L, Is, Safe);
-frame_size([{bs_put_integer,{f,L},_,_,_,_}|Is], Safe) ->
- frame_size_branch(L, Is, Safe);
-frame_size([{bs_put_float,{f,L},_,_,_,_}|Is], Safe) ->
- frame_size_branch(L, Is, Safe);
-frame_size([{bs_put_string,_,_}|Is], Safe) ->
- frame_size(Is, Safe);
frame_size([{kill,_}|Is], Safe) ->
frame_size(Is, Safe);
-frame_size([send|Is], Safe) ->
- frame_size(Is, Safe);
frame_size([{make_fun2,_,_,_,_}|Is], Safe) ->
frame_size(Is, Safe);
frame_size([{deallocate,N}|_], _) -> N;
-frame_size([{call_last,_,_,N}|_], _) -> N;
-frame_size([{call_ext_last,_,_,N}|_], _) -> N;
frame_size([{line,_}|Is], Safe) ->
frame_size(Is, Safe);
frame_size([_|_], _) -> throw(not_possible).
diff --git a/lib/compiler/src/beam_type.erl b/lib/compiler/src/beam_type.erl
index 7392f99fb6..3b51216a6c 100644
--- a/lib/compiler/src/beam_type.erl
+++ b/lib/compiler/src/beam_type.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -142,9 +142,11 @@ simplify_float(Is0, Ts0) ->
throw:not_possible -> not_possible
end.
-simplify_float_1([{set,[D0],[A],{alloc,_,{gc_bif,'-',{f,0}}}}=I|Is]=Is0, Ts0, Rs0, Acc0) ->
- case tdb_find(A, Ts0) of
+simplify_float_1([{set,[D0],[A0],{alloc,_,{gc_bif,'-',{f,0}}}}=I|Is]=Is0,
+ Ts0, Rs0, Acc0) ->
+ case tdb_find(A0, Ts0) of
float ->
+ A = coerce_to_float(A0),
{Rs1,Acc1} = load_reg(A, Ts0, Rs0, Acc0),
{D,Rs} = find_dest(D0, Rs1),
Areg = fetch_reg(A, Rs),
@@ -156,13 +158,16 @@ simplify_float_1([{set,[D0],[A],{alloc,_,{gc_bif,'-',{f,0}}}}=I|Is]=Is0, Ts0, Rs
{Rs,Acc} = flush(Rs0, Is0, Acc0),
simplify_float_1(Is, Ts, Rs, [I|checkerror(Acc)])
end;
-simplify_float_1([{set,[D0],[A,B],{alloc,_,{gc_bif,Op0,{f,0}}}}=I|Is]=Is0, Ts0, Rs0, Acc0) ->
- case float_op(Op0, A, B, Ts0) of
+simplify_float_1([{set,[D0],[A0,B0],{alloc,_,{gc_bif,Op0,{f,0}}}}=I|Is]=Is0,
+ Ts0, Rs0, Acc0) ->
+ case float_op(Op0, A0, B0, Ts0) of
no ->
Ts = update(I, Ts0),
{Rs,Acc} = flush(Rs0, Is0, Acc0),
simplify_float_1(Is, Ts, Rs, [I|checkerror(Acc)]);
{yes,Op} ->
+ A = coerce_to_float(A0),
+ B = coerce_to_float(B0),
{Rs1,Acc1} = load_reg(A, Ts0, Rs0, Acc0),
{Rs2,Acc2} = load_reg(B, Ts0, Rs1, Acc1),
{D,Rs} = find_dest(D0, Rs2),
@@ -187,6 +192,16 @@ simplify_float_1([], Ts, Rs, Acc0) ->
Is = opt_fmoves(Is0, []),
{Is,Ts}.
+coerce_to_float({integer,I}=Int) ->
+ try float(I) of
+ F ->
+ {float,F}
+ catch _:_ ->
+ %% Let the overflow happen at run-time.
+ Int
+ end;
+coerce_to_float(Other) -> Other.
+
opt_fmoves([{set,[{x,_}=R],[{fr,_}]=Src,fmove}=I1,
{set,[_]=Dst,[{x,_}=R],move}=I2|Is], Acc) ->
case beam_utils:is_killed_block(R, Is) of
diff --git a/lib/compiler/src/beam_utils.erl b/lib/compiler/src/beam_utils.erl
index 194f089ba1..8af0447f63 100644
--- a/lib/compiler/src/beam_utils.erl
+++ b/lib/compiler/src/beam_utils.erl
@@ -87,7 +87,7 @@ is_killed_at(R, Lbl, D) when is_integer(Lbl) ->
%% across branches.
is_not_used(R, Is, D) ->
- St = #live{bl=fun check_used_block/2,lbl=D,res=gb_trees:empty()},
+ St = #live{bl=check_used_block_fun(D),lbl=D,res=gb_trees:empty()},
case check_liveness(R, Is, St) of
{killed,_} -> true;
{used,_} -> false;
@@ -102,7 +102,7 @@ is_not_used(R, Is, D) ->
%% across branches.
is_not_used_at(R, Lbl, D) ->
- St = #live{bl=fun check_used_block/2,lbl=D,res=gb_trees:empty()},
+ St = #live{bl=check_used_block_fun(D),lbl=D,res=gb_trees:empty()},
case check_liveness_at(R, Lbl, St) of
{killed,_} -> true;
{used,_} -> false;
@@ -263,26 +263,14 @@ check_liveness(R, [{test,_,{f,Fail},As}|Is], St0) ->
{_,_}=Other -> Other
end
end;
-check_liveness(R, [{test,_,{f,Fail},Live,Ss,_}|Is], St0) ->
- case R of
- {x,X} ->
- case X < Live orelse member(R, Ss) of
- true -> {used,St0};
- false -> check_liveness_at(R, Fail, St0)
- end;
- {y,_} ->
- case check_liveness_at(R, Fail, St0) of
- {killed,St} -> check_liveness(R, Is, St);
- {_,_}=Other -> Other
- end
- end;
-check_liveness(R, [{select_val,R,_,_}|_], St) ->
- {used,St};
-check_liveness(R, [{select_val,_,Fail,{list,Branches}}|_], St) ->
- check_liveness_everywhere(R, [Fail|Branches], St);
-check_liveness(R, [{select_tuple_arity,R,_,_}|_], St) ->
+check_liveness(R, [{test,Op,Fail,Live,Ss,Dst}|Is], St) ->
+ %% Check this instruction as a block to get a less conservative
+ %% result if the caller is is_not_used/3.
+ Block = [{set,[Dst],Ss,{alloc,Live,{bif,Op,Fail}}}],
+ check_liveness(R, [{block,Block}|Is], St);
+check_liveness(R, [{select,_,R,_,_}|_], St) ->
{used,St};
-check_liveness(R, [{select_tuple_arity,_,Fail,{list,Branches}}|_], St) ->
+check_liveness(R, [{select,_,_,Fail,Branches}|_], St) ->
check_liveness_everywhere(R, [Fail|Branches], St);
check_liveness(R, [{jump,{f,F}}|_], St) ->
check_liveness_at(R, F, St);
@@ -301,37 +289,33 @@ check_liveness(R, [{kill,R}|_], St) ->
{killed,St};
check_liveness(R, [{kill,_}|Is], St) ->
check_liveness(R, Is, St);
-check_liveness(R, [bs_init_writable|Is], St) ->
- if
- R =:= {x,0} -> {used,St};
- true -> check_liveness(R, Is, St)
- end;
-check_liveness(R, [{bs_private_append,_,Bits,_,Bin,_,Dst}|Is], St) ->
- case R of
- Bits -> {used,St};
- Bin -> {used,St};
- Dst -> {killed,St};
- _ -> check_liveness(R, Is, St)
+check_liveness(R, [{bs_init,_,_,none,Ss,Dst}|Is], St) ->
+ case member(R, Ss) of
+ true ->
+ {used,St};
+ false ->
+ if
+ R =:= Dst -> {killed,St};
+ true -> check_liveness(R, Is, St)
+ end
end;
-check_liveness(R, [{bs_append,_,Bits,_,_,_,Bin,_,Dst}|Is], St) ->
+check_liveness(R, [{bs_init,_,_,Live,Ss,Dst}|Is], St) ->
case R of
- Bits -> {used,St};
- Bin -> {used,St};
- Dst -> {killed,St};
- _ -> check_liveness(R, Is, St)
- end;
-check_liveness(R, [{bs_init2,_,_,_,_,_,Dst}|Is], St) ->
- if
- R =:= Dst -> {killed,St};
- true -> check_liveness(R, Is, St)
- end;
-check_liveness(R, [{bs_init_bits,_,_,_,_,_,Dst}|Is], St) ->
- if
- R =:= Dst -> {killed,St};
- true -> check_liveness(R, Is, St)
+ {x,X} ->
+ case X < Live orelse member(R, Ss) of
+ true -> {used,St};
+ false -> {killed,St}
+ end;
+ {y,_} ->
+ case member(R, Ss) of
+ true -> {used,St};
+ false ->
+ if
+ R =:= Dst -> {killed,St};
+ true -> check_liveness(R, Is, St)
+ end
+ end
end;
-check_liveness(R, [{bs_put_string,_,_}|Is], St) ->
- check_liveness(R, Is, St);
check_liveness(R, [{deallocate,_}|Is], St) ->
case R of
{y,_} -> {killed,St};
@@ -339,29 +323,20 @@ check_liveness(R, [{deallocate,_}|Is], St) ->
end;
check_liveness(R, [return|_], St) ->
check_liveness_live_ret(R, 1, St);
-check_liveness(R, [{call_last,Live,_,_}|_], St) ->
- check_liveness_live_ret(R, Live, St);
-check_liveness(R, [{call_only,Live,_}|_], St) ->
- check_liveness_live_ret(R, Live, St);
-check_liveness(R, [{call_ext_last,Live,_,_}|_], St) ->
- check_liveness_live_ret(R, Live, St);
-check_liveness(R, [{call_ext_only,Live,_}|_], St) ->
- check_liveness_live_ret(R, Live, St);
check_liveness(R, [{call,Live,_}|Is], St) ->
case R of
{x,X} when X < Live -> {used,St};
{x,_} -> {killed,St};
{y,_} -> check_liveness(R, Is, St)
end;
-check_liveness(R, [{call_ext,Live,Func}|Is], St) ->
+check_liveness(R, [{call_ext,Live,_}=I|Is], St) ->
case R of
{x,X} when X < Live ->
{used,St};
{x,_} ->
{killed,St};
{y,_} ->
- {extfunc,Mod,Name,Arity} = Func,
- case erl_bifs:is_exit_bif(Mod, Name, Arity) of
+ case beam_jump:is_exit_instruction(I) of
false ->
check_liveness(R, Is, St);
true ->
@@ -387,14 +362,6 @@ check_liveness(R, [{apply,Args}|Is], St) ->
{x,_} -> {killed,St};
{y,_} -> check_liveness(R, Is, St)
end;
-check_liveness(R, [{apply_last,Args,_}|_], St) ->
- check_liveness_live_ret(R, Args+2, St);
-check_liveness(R, [send|Is], St) ->
- case R of
- {x,X} when X < 2 -> {used,St};
- {x,_} -> {killed,St};
- {y,_} -> check_liveness(R, Is, St)
- end;
check_liveness({x,R}, [{'%live',Live}|Is], St) ->
if
R < Live -> check_liveness(R, Is, St);
@@ -429,25 +396,9 @@ check_liveness(R, [{gc_bif,Op,{f,Fail},Live,Ss,D}|Is], St0) ->
Other
end
end;
-check_liveness(R, [{bs_add,{f,0},Ss,D}|Is], St) ->
+check_liveness(R, [{bs_put,{f,0},_,Ss}|Is], St) ->
case member(R, Ss) of
true -> {used,St};
- false when R =:= D -> {killed,St};
- false -> check_liveness(R, Is, St)
- end;
-check_liveness(R, [{bs_put_binary,{f,0},Sz,_,_,Src}|Is], St) ->
- case member(R, [Sz,Src]) of
- true -> {used,St};
- false -> check_liveness(R, Is, St)
- end;
-check_liveness(R, [{bs_put_integer,{f,0},Sz,_,_,Src}|Is], St) ->
- case member(R, [Sz,Src]) of
- true -> {used,St};
- false -> check_liveness(R, Is, St)
- end;
-check_liveness(R, [{bs_put_float,{f,0},Sz,_,_,Src}|Is], St) ->
- case member(R, [Sz,Src]) of
- true -> {used,St};
false -> check_liveness(R, Is, St)
end;
check_liveness(R, [{bs_restore2,S,_}|Is], St) ->
@@ -472,6 +423,16 @@ check_liveness(R, [{make_fun2,_,_,_,NumFree}|Is], St) ->
{x,_} -> {killed,St};
_ -> check_liveness(R, Is, St)
end;
+check_liveness({x,_}=R, [{'catch',_,_}|Is], St) ->
+ %% All x registers will be killed if an exception occurs.
+ %% Therefore we only need to check the liveness for the
+ %% instructions following the catch instruction.
+ check_liveness(R, Is, St);
+check_liveness({x,_}=R, [{'try',_,_}|Is], St) ->
+ %% All x registers will be killed if an exception occurs.
+ %% Therefore we only need to check the liveness for the
+ %% instructions inside the 'try' block.
+ check_liveness(R, Is, St);
check_liveness(R, [{try_end,Y}|Is], St) ->
case R of
Y ->
@@ -602,26 +563,50 @@ check_killed_block(_, []) -> transparent.
%%
%% (Unknown instructions will cause an exception.)
-check_used_block({x,X}=R, [{set,_,_,{alloc,Live,_}}|Is]) ->
+check_used_block_fun(D) ->
+ fun(R, Is) -> check_used_block(R, Is, D) end.
+
+check_used_block({x,X}=R, [{set,Ds,Ss,{alloc,Live,Op}}|Is], D) ->
if
X >= Live -> killed;
- true -> check_used_block(R, Is)
+ true ->
+ case member(R, Ss) orelse
+ is_reg_used_at(R, Op, D) of
+ true -> used;
+ false ->
+ case member(R, Ds) of
+ true -> killed;
+ false -> check_used_block(R, Is, D)
+ end
+ end
end;
-check_used_block(R, [{set,Ds,Ss,_Op}|Is]) ->
- case member(R, Ss) of
+check_used_block(R, [{set,Ds,Ss,Op}|Is], D) ->
+ case member(R, Ss) orelse
+ is_reg_used_at(R, Op, D) of
true -> used;
false ->
case member(R, Ds) of
true -> killed;
- false -> check_used_block(R, Is)
+ false -> check_used_block(R, Is, D)
end
end;
-check_used_block(R, [{'%live',Live}|Is]) ->
+check_used_block(R, [{'%live',Live}|Is], D) ->
case R of
{x,X} when X >= Live -> killed;
- _ -> check_used_block(R, Is)
+ _ -> check_used_block(R, Is, D)
end;
-check_used_block(_, []) -> transparent.
+check_used_block(_, [], _) -> transparent.
+
+is_reg_used_at(R, {gc_bif,_,{f,Lbl}}, D) ->
+ is_reg_used_at_1(R, Lbl, D);
+is_reg_used_at(R, {bif,_,{f,Lbl}}, D) ->
+ is_reg_used_at_1(R, Lbl, D);
+is_reg_used_at(_, _, _) -> false.
+
+is_reg_used_at_1(_, 0, _) ->
+ false;
+is_reg_used_at_1(R, Lbl, D) ->
+ not is_not_used_at(R, Lbl, D).
index_labels_1([{label,Lbl}|Is0], Acc) ->
Is = lists:dropwhile(fun({label,_}) -> true;
@@ -654,49 +639,21 @@ combine_alloc_lists_1([]) -> [].
live_opt([{bs_context_to_binary,Src}=I|Is], Regs0, D, Acc) ->
Regs = x_live([Src], Regs0),
live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_add,Fail,[Src1,Src2,_],Dst}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live([Src1,Src2], x_dead([Dst], Regs0)),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_init2,Fail,_,_,Live,_,_}=I|Is], _, D, Acc) ->
- Regs1 = live_call(Live),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_init_bits,Fail,Src1,_,Live,_,Src2}=I|Is], _, D, Acc) ->
- Regs1 = live_call(Live),
- Regs2 = x_live([Src1,Src2], Regs1),
- Regs = live_join_label(Fail, D, Regs2),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_append,Fail,Src1,_,Live,_,Src2,_,Dst}=I|Is], _Regs0, D, Acc) ->
- Regs1 = x_dead([Dst], x_live([Src1,Src2], live_call(Live))),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_private_append,Fail,Src1,_,Src2,_,Dst}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live([Src1,Src2], x_dead([Dst], Regs0)),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_put_binary,Fail,Src1,_,_,Src2}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live([Src1,Src2], Regs0),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_put_float,Fail,Src1,_,_,Src2}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live([Src1,Src2], Regs0),
+live_opt([{bs_init,Fail,_,none,Ss,Dst}=I|Is], Regs0, D, Acc) ->
+ Regs1 = x_live(Ss, x_dead([Dst], Regs0)),
Regs = live_join_label(Fail, D, Regs1),
live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_put_integer,Fail,Src1,_,_,Src2}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live([Src1,Src2], Regs0),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_put_utf8,Fail,_,Src}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live([Src], Regs0),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_put_utf16,Fail,_,Src}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live([Src], Regs0),
- Regs = live_join_label(Fail, D, Regs1),
+live_opt([{bs_init,Fail,Info,Live0,Ss,Dst}|Is], Regs0, D, Acc) ->
+ Regs1 = x_dead([Dst], Regs0),
+ Live = live_regs(Regs1),
+ true = Live =< Live0, %Assertion.
+ Regs2 = live_call(Live),
+ Regs3 = x_live(Ss, Regs2),
+ Regs = live_join_label(Fail, D, Regs3),
+ I = {bs_init,Fail,Info,Live,Ss,Dst},
live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_put_utf32,Fail,_,Src}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live([Src], Regs0),
+live_opt([{bs_put,Fail,_,Ss}=I|Is], Regs0, D, Acc) ->
+ Regs1 = x_live(Ss, Regs0),
Regs = live_join_label(Fail, D, Regs1),
live_opt(Is, Regs, D, [I|Acc]);
live_opt([{bs_restore2,Src,_}=I|Is], Regs0, D, Acc) ->
@@ -705,14 +662,6 @@ live_opt([{bs_restore2,Src,_}=I|Is], Regs0, D, Acc) ->
live_opt([{bs_save2,Src,_}=I|Is], Regs0, D, Acc) ->
Regs = x_live([Src], Regs0),
live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_utf8_size,Fail,Src,Dst}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live([Src], x_dead([Dst], Regs0)),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_utf16_size,Fail,Src,Dst}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live([Src], x_dead([Dst], Regs0)),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
live_opt([{test,bs_start_match2,Fail,Live,[Src,_],_}=I|Is], _, D, Acc) ->
Regs0 = live_call(Live),
Regs1 = x_live([Src], Regs0),
@@ -747,30 +696,16 @@ live_opt([{try_case_end,Src}=I|Is], _, D, Acc) ->
live_opt([if_end=I|Is], _, D, Acc) ->
Regs = 0,
live_opt(Is, Regs, D, [I|Acc]);
-live_opt([bs_init_writable=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(1), D, [I|Acc]);
live_opt([{call,Arity,_}=I|Is], _, D, Acc) ->
live_opt(Is, live_call(Arity), D, [I|Acc]);
live_opt([{call_ext,Arity,_}=I|Is], _, D, Acc) ->
live_opt(Is, live_call(Arity), D, [I|Acc]);
live_opt([{call_fun,Arity}=I|Is], _, D, Acc) ->
live_opt(Is, live_call(Arity+1), D, [I|Acc]);
-live_opt([{call_last,Arity,_,_}=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(Arity), D, [I|Acc]);
-live_opt([{call_ext_last,Arity,_,_}=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(Arity), D, [I|Acc]);
live_opt([{apply,Arity}=I|Is], _, D, Acc) ->
live_opt(Is, live_call(Arity+2), D, [I|Acc]);
-live_opt([{apply_last,Arity,_}=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(Arity+2), D, [I|Acc]);
-live_opt([{call_only,Arity,_}=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(Arity), D, [I|Acc]);
-live_opt([{call_ext_only,Arity,_}=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(Arity), D, [I|Acc]);
live_opt([{make_fun2,_,_,_,Arity}=I|Is], _, D, Acc) ->
live_opt(Is, live_call(Arity), D, [I|Acc]);
-live_opt([send=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(2), D, [I|Acc]);
live_opt([{test,_,Fail,Ss}=I|Is], Regs0, D, Acc) ->
Regs1 = x_live(Ss, Regs0),
Regs = live_join_label(Fail, D, Regs1),
@@ -780,16 +715,14 @@ live_opt([{test,_,Fail,Live,Ss,_}=I|Is], _, D, Acc) ->
Regs1 = x_live(Ss, Regs0),
Regs = live_join_label(Fail, D, Regs1),
live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{select_val,Src,Fail,{list,List}}=I|Is], Regs0, D, Acc) ->
+live_opt([{select,_,Src,Fail,List}=I|Is], Regs0, D, Acc) ->
Regs1 = x_live([Src], Regs0),
Regs = live_join_labels([Fail|List], D, Regs1),
live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{select_tuple_arity,Src,Fail,{list,List}}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live([Src], Regs0),
- Regs = live_join_labels([Fail|List], D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{'try',_,Fail}=I|Is], Regs0, D, Acc) ->
- Regs = live_join_label(Fail, D, Regs0),
+live_opt([{'try',_,_}=I|Is], Regs, D, Acc) ->
+ %% If an exeption happens, all x registers will be killed.
+ %% Therefore, we should only base liveness of the code inside
+ %% the try.
live_opt(Is, Regs, D, [I|Acc]);
live_opt([{try_case,_}=I|Is], _, D, Acc) ->
live_opt(Is, live_call(1), D, [I|Acc]);
@@ -799,8 +732,6 @@ live_opt([timeout=I|Is], _, D, Acc) ->
live_opt(Is, 0, D, [I|Acc]);
%% Transparent instructions - they neither use nor modify x registers.
-live_opt([{bs_put_string,_,_}=I|Is], Regs, D, Acc) ->
- live_opt(Is, Regs, D, [I|Acc]);
live_opt([{deallocate,_}=I|Is], Regs, D, Acc) ->
live_opt(Is, Regs, D, [I|Acc]);
live_opt([{kill,_}=I|Is], Regs, D, Acc) ->
@@ -827,13 +758,24 @@ live_opt([{allocate_heap,_,_,Live}=I|Is], _, D, Acc) ->
live_opt([], _, _, Acc) -> Acc.
-live_opt_block([{set,[],[],{alloc,Live,_}}=I|Is], _, D, Acc) ->
- live_opt_block(Is, live_call(Live), D, [I|Acc]);
-live_opt_block([{set,Ds,Ss,Op}=I|Is], Regs0, D, Acc) ->
- Regs = case Op of
- {alloc,Live,_} -> live_call(Live);
- _ -> x_live(Ss, x_dead(Ds, Regs0))
- end,
+live_opt_block([{set,Ds,Ss,Op}=I0|Is], Regs0, D, Acc) ->
+ Regs1 = x_live(Ss, x_dead(Ds, Regs0)),
+ {I,Regs} = case Op of
+ {alloc,Live0,Alloc} ->
+ %% The life-time analysis used by the code generator
+ %% is sometimes too conservative, so it may be
+ %% possible to lower the number of live registers
+ %% based on the exact liveness information.
+ %% The main benefit is that more optimizations that
+ %% depend on liveness information (such as the
+ %% beam_bool and beam_dead passes) may be applied.
+ Live = live_regs(Regs1),
+ true = Live =< Live0, %Assertion.
+ I1 = {set,Ds,Ss,{alloc,Live,Alloc}},
+ {I1,live_call(Live)};
+ _ ->
+ {I0,Regs1}
+ end,
case Ds of
[{x,X}] ->
case (not is_live(X, Regs0)) andalso Op =:= move of
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index 29758b8fb4..eb72290306 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -62,7 +62,7 @@ files([F|Fs]) ->
case file(F) of
ok -> ok;
{error,Es} ->
- io:format("~p:~n~s~n", [F,format_error(Es)])
+ io:format("~tp:~n~ts~n", [F,format_error(Es)])
end,
files(Fs);
files([]) -> ok.
@@ -649,7 +649,8 @@ valfun_4(send, Vst) ->
call(send, 2, Vst);
valfun_4({set_tuple_element,Src,Tuple,I}, Vst) ->
assert_term(Src, Vst),
- assert_type({tuple_element,I+1}, Tuple, Vst);
+ assert_type({tuple_element,I+1}, Tuple, Vst),
+ Vst;
%% Match instructions.
valfun_4({select_val,Src,{f,Fail},{list,Choices}}, Vst) ->
assert_term(Src, Vst),
@@ -1044,7 +1045,7 @@ float_op(Src, Dst, Vst0) ->
assert_fls(Fls, Vst) ->
case get_fls(Vst) of
- Fls -> Vst;
+ Fls -> ok;
OtherFls -> error({bad_floating_point_state,OtherFls})
end.
@@ -1120,7 +1121,7 @@ bsm_match_state(Slots) ->
{match_context,0,Slots}.
bsm_validate_context(Reg, Vst) ->
- bsm_get_context(Reg, Vst),
+ _ = bsm_get_context(Reg, Vst),
ok.
bsm_get_context({x,X}=Reg, #vst{current=#st{x=Xs}}=_Vst) when is_integer(X) ->
@@ -1133,7 +1134,7 @@ bsm_get_context(Reg, _) -> error({bad_source,Reg}).
bsm_save(Reg, {atom,start}, Vst) ->
%% Save point refering to where the match started.
%% It is always valid. But don't forget to validate the context register.
- bsm_get_context(Reg, Vst),
+ bsm_validate_context(Reg, Vst),
Vst;
bsm_save(Reg, SavePoint, Vst) ->
case bsm_get_context(Reg, Vst) of
@@ -1146,7 +1147,7 @@ bsm_save(Reg, SavePoint, Vst) ->
bsm_restore(Reg, {atom,start}, Vst) ->
%% (Mostly) automatic save point refering to where the match started.
%% It is always valid. But don't forget to validate the context register.
- bsm_get_context(Reg, Vst),
+ bsm_validate_context(Reg, Vst),
Vst;
bsm_restore(Reg, SavePoint, Vst) ->
case bsm_get_context(Reg, Vst) of
@@ -1312,8 +1313,7 @@ assert_term(Src, Vst) ->
%%
assert_type(WantedType, Term, Vst) ->
- assert_type(WantedType, get_term_type(Term, Vst)),
- Vst.
+ assert_type(WantedType, get_term_type(Term, Vst)).
assert_type(Correct, Correct) -> ok;
assert_type(float, {float,_}) -> ok;
diff --git a/lib/compiler/src/beam_z.erl b/lib/compiler/src/beam_z.erl
new file mode 100644
index 0000000000..8c6b0c916d
--- /dev/null
+++ b/lib/compiler/src/beam_z.erl
@@ -0,0 +1,79 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% Purpose: Run right before beam_asm to do any final fix-ups or clean-ups.
+%% (Mandatory.)
+
+-module(beam_z).
+
+-export([module/2]).
+
+module({Mod,Exp,Attr,Fs0,Lc}, _Opt) ->
+ Fs = [function(F) || F <- Fs0],
+ {ok,{Mod,Exp,Attr,Fs,Lc}}.
+
+function({function,Name,Arity,CLabel,Is0}) ->
+ try
+ Is = undo_renames(Is0),
+ {function,Name,Arity,CLabel,Is}
+ catch
+ Class:Error ->
+ Stack = erlang:get_stacktrace(),
+ io:fwrite("Function: ~w/~w\n", [Name,Arity]),
+ erlang:raise(Class, Error, Stack)
+ end.
+
+undo_renames([{call_ext,2,send}|Is]) ->
+ [send|undo_renames(Is)];
+undo_renames([{apply,A},{deallocate,N},return|Is]) ->
+ [{apply_last,A,N}|undo_renames(Is)];
+undo_renames([{call,A,F},{deallocate,N},return|Is]) ->
+ [{call_last,A,F,N}|undo_renames(Is)];
+undo_renames([{call_ext,A,F},{deallocate,N},return|Is]) ->
+ [{call_ext_last,A,F,N}|undo_renames(Is)];
+undo_renames([{call,A,F},return|Is]) ->
+ [{call_only,A,F}|undo_renames(Is)];
+undo_renames([{call_ext,A,F},return|Is]) ->
+ [{call_ext_only,A,F}|undo_renames(Is)];
+undo_renames([I|Is]) ->
+ [undo_rename(I)|undo_renames(Is)];
+undo_renames([]) -> [].
+
+undo_rename({bs_put,F,{I,U,Fl},[Sz,Src]}) ->
+ {I,F,Sz,U,Fl,Src};
+undo_rename({bs_put,F,{I,Fl},[Src]}) ->
+ {I,F,Fl,Src};
+undo_rename({bs_put,{f,0},{bs_put_string,_,_}=I,[]}) ->
+ I;
+undo_rename({bif,bs_add=I,F,[Src1,Src2,{integer,U}],Dst}) ->
+ {I,F,[Src1,Src2,U],Dst};
+undo_rename({bif,bs_utf8_size=I,F,[Src],Dst}) ->
+ {I,F,Src,Dst};
+undo_rename({bif,bs_utf16_size=I,F,[Src],Dst}) ->
+ {I,F,Src,Dst};
+undo_rename({bs_init,F,{I,U,Flags},none,[Sz,Src],Dst}) ->
+ {I,F,Sz,U,Src,Flags,Dst};
+undo_rename({bs_init,F,{I,Extra,Flags},Live,[Sz],Dst}) ->
+ {I,F,Sz,Extra,Live,Flags,Dst};
+undo_rename({bs_init,F,{I,Extra,U,Flags},Live,[Sz,Src],Dst}) ->
+ {I,F,Sz,Extra,Live,U,Src,Flags,Dst};
+undo_rename({bs_init,_,bs_init_writable=I,_,_,_}) ->
+ I;
+undo_rename({select,I,Reg,Fail,List}) ->
+ {I,Reg,Fail,{list,List}};
+undo_rename(I) -> I.
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index 0a368df5d6..497af2b52c 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -202,36 +202,38 @@ format_error(bad_crypto_key) ->
format_error(no_crypto_key) ->
"no crypto key supplied.";
format_error({native, E}) ->
- io_lib:fwrite("native-code compilation failed with reason: ~P.",
+ io_lib:fwrite("native-code compilation failed with reason: ~tP.",
[E, 25]);
format_error({native_crash,E,Stk}) ->
- io_lib:fwrite("native-code compilation crashed with reason: ~P.\n~P\n",
+ io_lib:fwrite("native-code compilation crashed with reason: ~tP.\n~tP\n",
[E,25,Stk,25]);
format_error({open,E}) ->
- io_lib:format("open error '~s'", [file:format_error(E)]);
+ io_lib:format("open error '~ts'", [file:format_error(E)]);
format_error({epp,E}) ->
epp:format_error(E);
format_error(write_error) ->
"error writing file";
format_error({rename,From,To,Error}) ->
- io_lib:format("failed to rename ~s to ~s: ~s",
+ io_lib:format("failed to rename ~ts to ~ts: ~ts",
[From,To,file:format_error(Error)]);
format_error({delete,File,Error}) ->
- io_lib:format("failed to delete file ~s: ~s",
+ io_lib:format("failed to delete file ~ts: ~ts",
[File,file:format_error(Error)]);
format_error({delete_temp,File,Error}) ->
- io_lib:format("failed to delete temporary file ~s: ~s",
+ io_lib:format("failed to delete temporary file ~ts: ~ts",
[File,file:format_error(Error)]);
format_error({parse_transform,M,R}) ->
- io_lib:format("error in parse transform '~s': ~p", [M, R]);
+ io_lib:format("error in parse transform '~s': ~tp", [M, R]);
+format_error({undef_parse_transform,M}) ->
+ io_lib:format("undefined parse transform '~s'", [M]);
format_error({core_transform,M,R}) ->
- io_lib:format("error in core transform '~s': ~p", [M, R]);
+ io_lib:format("error in core transform '~s': ~tp", [M, R]);
format_error({crash,Pass,Reason}) ->
- io_lib:format("internal error in ~p;\ncrash reason: ~p", [Pass,Reason]);
+ io_lib:format("internal error in ~p;\ncrash reason: ~tp", [Pass,Reason]);
format_error({bad_return,Pass,Reason}) ->
- io_lib:format("internal error in ~p;\nbad return value: ~p", [Pass,Reason]);
+ io_lib:format("internal error in ~p;\nbad return value: ~tp", [Pass,Reason]);
format_error({module_name,Mod,Filename}) ->
- io_lib:format("Module name '~s' does not match file name '~s'",
+ io_lib:format("Module name '~s' does not match file name '~ts'",
[Mod,Filename]).
%% The compile state record.
@@ -246,6 +248,7 @@ format_error({module_name,Mod,Filename}) ->
abstract_code=[], %Abstract code for debugger.
options=[] :: [option()], %Options for compilation
mod_options=[] :: [option()], %Options for module_info
+ encoding=none :: none | epp:source_encoding(),
errors=[],
warnings=[]}).
@@ -268,7 +271,7 @@ internal_comp(Passes, File, Suffix, St0) ->
ofile=objfile(Base, St0)},
Run = case member(time, St1#compile.options) of
true ->
- io:format("Compiling ~p\n", [File]),
+ io:format("Compiling ~tp\n", [File]),
fun run_tc/2;
false -> fun({_Name,Fun}, St) -> catch Fun(St) end
end,
@@ -551,12 +554,12 @@ select_list_passes_1([{iff,Flag,{done,Ext}}|Ps], Opts, Acc) ->
end;
select_list_passes_1([{iff=Op,Flag,List0}|Ps], Opts, Acc) when is_list(List0) ->
case select_list_passes(List0, Opts) of
- {done,_}=Done -> Done;
+ {done,List} -> {done,reverse(Acc) ++ List};
{not_done,List} -> select_list_passes_1(Ps, Opts, [{Op,Flag,List}|Acc])
end;
select_list_passes_1([{unless=Op,Flag,List0}|Ps], Opts, Acc) when is_list(List0) ->
case select_list_passes(List0, Opts) of
- {done,_}=Done -> Done;
+ {done,List} -> {done,reverse(Acc) ++ List};
{not_done,List} -> select_list_passes_1(Ps, Opts, [{Op,Flag,List}|Acc])
end;
select_list_passes_1([P|Ps], Opts, Acc) ->
@@ -630,7 +633,8 @@ kernel_passes() ->
asm_passes() ->
%% Assembly level optimisations.
[{delay,
- [{unless,no_postopt,
+ [{pass,beam_a},
+ {unless,no_postopt,
[{pass,beam_block},
{iff,dblk,{listing,"block"}},
{unless,no_except,{pass,beam_except}},
@@ -657,13 +661,11 @@ asm_passes() ->
{iff,dtrim,{listing,"trim"}},
{pass,beam_flatten}]},
- %% If post optimizations are turned off, we still coalesce
- %% adjacent labels and remove unused labels to keep the
- %% HiPE compiler happy.
- {iff,no_postopt,
- [?pass(beam_unused_labels),
- {pass,beam_clean}]},
+ %% If post optimizations are turned off, we still
+ %% need to do a few clean-ups to code.
+ {iff,no_postopt,[{pass,beam_clean}]},
+ {pass,beam_z},
{iff,dopt,{listing,"optimize"}},
{iff,'S',{listing,"S"}},
{iff,'to_asm',{done,"S"}}]},
@@ -681,7 +683,7 @@ binary_passes() ->
%% Remove the target file so we don't have an old one if the compilation fail.
remove_file(St) ->
- file:delete(St#compile.ofile),
+ _ = file:delete(St#compile.ofile),
{ok,St}.
-record(asm_module, {module,
@@ -733,8 +735,9 @@ collect_asm([X | Rest], R) ->
beam_consult_asm(St) ->
case file:consult(St#compile.ifile) of
{ok, Forms0} ->
+ Encoding = epp:read_encoding(St#compile.ifile),
{Module, Forms} = preprocess_asm_forms(Forms0),
- {ok,St#compile{module=Module, code=Forms}};
+ {ok,St#compile{module=Module, code=Forms, encoding=Encoding}};
{error,E} ->
Es = [{St#compile.ifile,[{none,?MODULE,{open,E}}]}],
{error,St#compile{errors=St#compile.errors ++ Es}}
@@ -776,7 +779,8 @@ parse_module(St) ->
R = epp:parse_file(St#compile.ifile, IncludePath, pre_defs(Opts)),
case R of
{ok,Forms} ->
- {ok,St#compile{code=Forms}};
+ Encoding = epp:read_encoding(St#compile.ifile),
+ {ok,St#compile{code=Forms,encoding=Encoding}};
{error,E} ->
Es = [{St#compile.ifile,[{none,?MODULE,{epp,E}}]}],
{error,St#compile{errors=St#compile.errors ++ Es}}
@@ -850,6 +854,10 @@ foldl_transform(St, [T|Ts]) ->
{error,Es,Ws} ->
{error,St#compile{warnings=St#compile.warnings ++ Ws,
errors=St#compile.errors ++ Es}};
+ {'EXIT',{undef,_}} ->
+ Es = [{St#compile.ifile,[{none,compile,
+ {undef_parse_transform,T}}]}],
+ {error,St#compile{errors=St#compile.errors ++ Es}};
{'EXIT',R} ->
Es = [{St#compile.ifile,[{none,compile,{parse_transform,T,R}}]}],
{error,St#compile{errors=St#compile.errors ++ Es}};
@@ -887,7 +895,6 @@ foldl_core_transforms(St, []) -> {ok,St}.
%%% Fetches the module name from a list of forms. The module attribute must
%%% be present.
-get_module([{attribute,_,module,{M,_As}} | _]) -> M;
get_module([{attribute,_,module,M} | _]) -> M;
get_module([_ | Rest]) ->
get_module(Rest).
@@ -899,11 +906,8 @@ add_default_base(St, Forms) ->
F = St#compile.filename,
case F of
"" ->
- M = case get_module(Forms) of
- PackageModule when is_list(PackageModule) -> last(PackageModule);
- M0 -> M0
- end,
- St#compile{base = atom_to_list(M)};
+ M = get_module(Forms),
+ St#compile{base=atom_to_list(M)};
_ ->
St
end.
@@ -1085,10 +1089,10 @@ makedep_output(#compile{code=Code,options=Opts,ofile=Ofile}=St) ->
{ok,Output1,CloseOutput} ->
try
%% Write the Makefile.
- io:fwrite(Output1, "~s", [Code]),
+ io:fwrite(Output1, "~ts", [Code]),
%% Close the file if relevant.
if
- CloseOutput -> file:close(Output1);
+ CloseOutput -> ok = file:close(Output1);
true -> ok
end,
{ok,St}
@@ -1227,7 +1231,7 @@ encrypt(des3_cbc=Mode, {K1,K2,K3, IVec}, Bin0) ->
random_bytes(N) ->
{A,B,C} = now(),
- random:seed(A, B, C),
+ _ = random:seed(A, B, C),
random_bytes_1(N, []).
random_bytes_1(0, Acc) -> Acc;
@@ -1236,10 +1240,6 @@ random_bytes_1(N, Acc) -> random_bytes_1(N-1, [random:uniform(255)|Acc]).
save_core_code(St) ->
{ok,St#compile{core_code=cerl:from_records(St#compile.code)}}.
-beam_unused_labels(#compile{code=Code0}=St) ->
- Code = beam_jump:module_labels(Code0),
- {ok,St#compile{code=Code}}.
-
beam_asm(#compile{ifile=File,code=Code0,
abstract_code=Abst,mod_options=Opts0}=St) ->
Source = filename:absname(File),
@@ -1338,16 +1338,12 @@ save_binary(#compile{code=none}=St) -> {ok,St};
save_binary(#compile{module=Mod,ofile=Outfile,
options=Opts}=St) ->
%% Test that the module name and output file name match.
- %% We must take care to not completely break a packaged module
- %% (even though packages still is as an experimental, unsupported
- %% feature) - so we will extract the last part of a packaged
- %% module name and compare only that.
case member(no_error_module_mismatch, Opts) of
true ->
save_binary_1(St);
false ->
Base = filename:rootname(filename:basename(Outfile)),
- case lists:last(packages:split(Mod)) of
+ case atom_to_list(Mod) of
Base ->
save_binary_1(St);
_ ->
@@ -1423,28 +1419,28 @@ report_warnings(#compile{options=Opts,warnings=Ws0}) ->
end.
format_message(F, P, [{{Line,Column}=Loc,Mod,E}|Es]) ->
- M = {{F,Loc},io_lib:format("~s:~w:~w ~s~s\n",
+ M = {{F,Loc},io_lib:format("~ts:~w:~w ~s~ts\n",
[F,Line,Column,P,Mod:format_error(E)])},
[M|format_message(F, P, Es)];
format_message(F, P, [{Line,Mod,E}|Es]) ->
- M = {{F,{Line,0}},io_lib:format("~s:~w: ~s~s\n",
+ M = {{F,{Line,0}},io_lib:format("~ts:~w: ~s~ts\n",
[F,Line,P,Mod:format_error(E)])},
[M|format_message(F, P, Es)];
format_message(F, P, [{Mod,E}|Es]) ->
- M = {none,io_lib:format("~s: ~s~s\n", [F,P,Mod:format_error(E)])},
+ M = {none,io_lib:format("~ts: ~s~ts\n", [F,P,Mod:format_error(E)])},
[M|format_message(F, P, Es)];
format_message(_, _, []) -> [].
%% list_errors(File, ErrorDescriptors) -> ok
list_errors(F, [{{Line,Column},Mod,E}|Es]) ->
- io:fwrite("~s:~w:~w: ~s\n", [F,Line,Column,Mod:format_error(E)]),
+ io:fwrite("~ts:~w:~w: ~ts\n", [F,Line,Column,Mod:format_error(E)]),
list_errors(F, Es);
list_errors(F, [{Line,Mod,E}|Es]) ->
- io:fwrite("~s:~w: ~s\n", [F,Line,Mod:format_error(E)]),
+ io:fwrite("~ts:~w: ~ts\n", [F,Line,Mod:format_error(E)]),
list_errors(F, Es);
list_errors(F, [{Mod,E}|Es]) ->
- io:fwrite("~s: ~s\n", [F,Mod:format_error(E)]),
+ io:fwrite("~ts: ~ts\n", [F,Mod:format_error(E)]),
list_errors(F, Es);
list_errors(_F, []) -> ok.
@@ -1500,10 +1496,12 @@ src_listing(Ext, St) ->
Ext, St).
do_src_listing(Lf, Fs) ->
- foreach(fun (F) -> io:put_chars(Lf, [erl_pp:form(F),"\n"]) end,
+ Opts = [lists:keyfind(encoding, 1, io:getopts(Lf))],
+ foreach(fun (F) -> io:put_chars(Lf, [erl_pp:form(F, Opts),"\n"]) end,
Fs).
-listing(Ext, St) ->
+listing(Ext, St0) ->
+ St = St0#compile{encoding = none},
listing(fun(Lf, Fs) -> beam_listing:module(Lf, Fs) end, Ext, St).
listing(LFun, Ext, St) ->
@@ -1511,6 +1509,7 @@ listing(LFun, Ext, St) ->
case file:open(Lfile, [write,delayed_write]) of
{ok,Lf} ->
Code = restore_expanded_types(Ext, St#compile.code),
+ output_encoding(Lf, St),
LFun(Lf, Code),
ok = file:close(Lf),
{ok,St};
@@ -1519,6 +1518,12 @@ listing(LFun, Ext, St) ->
{error,St#compile{errors=St#compile.errors ++ Es}}
end.
+output_encoding(F, #compile{encoding = none}) ->
+ ok = io:setopts(F, [{encoding, epp:default_encoding()}]);
+output_encoding(F, #compile{encoding = Encoding}) ->
+ ok = io:setopts(F, [{encoding, Encoding}]),
+ ok = io:fwrite(F, <<"%% ~s\n">>, [epp:encoding_to_string(Encoding)]).
+
restore_expanded_types("P", Fs) ->
epp:restore_typed_record_fields(Fs);
restore_expanded_types("E", {M,I,Fs0}) ->
diff --git a/lib/compiler/src/compiler.app.src b/lib/compiler/src/compiler.app.src
index 1133882728..8775c84698 100644
--- a/lib/compiler/src/compiler.app.src
+++ b/lib/compiler/src/compiler.app.src
@@ -1,7 +1,7 @@
% This is an -*- erlang -*- file.
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -20,6 +20,7 @@
[{description, "ERTS CXC 138 10"},
{vsn, "%VSN%"},
{modules, [
+ beam_a,
beam_asm,
beam_block,
beam_bool,
@@ -40,6 +41,7 @@
beam_type,
beam_utils,
beam_validator,
+ beam_z,
cerl,
cerl_clauses,
cerl_inline,
@@ -55,7 +57,6 @@
sys_core_dsetel,
sys_core_fold,
sys_core_inline,
- sys_expand_pmod,
sys_pre_attributes,
sys_pre_expand,
v3_codegen,
diff --git a/lib/compiler/src/core_lint.erl b/lib/compiler/src/core_lint.erl
index b513a8965c..1e8983f594 100644
--- a/lib/compiler/src/core_lint.erl
+++ b/lib/compiler/src/core_lint.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -247,7 +247,8 @@ gbody(E, Def, Rt, St0) ->
false -> St1
end.
-gexpr(#c_var{name=N}, Def, _Rt, St) -> expr_var(N, Def, St);
+gexpr(#c_var{name=N}, Def, _Rt, St) when is_atom(N); is_integer(N) ->
+ expr_var(N, Def, St);
gexpr(#c_literal{}, _Def, _Rt, St) -> St;
gexpr(#c_cons{hd=H,tl=T}, Def, _Rt, St) ->
gexpr_list([H,T], Def, St);
@@ -308,7 +309,7 @@ expr(#c_fun{vars=Vs,body=B}, Def, Rt, St0) ->
{Vvs,St1} = variable_list(Vs, St0),
return_match(Rt, 1, body(B, union(Vvs, Def), any, St1));
expr(#c_seq{arg=Arg,body=B}, Def, Rt, St0) ->
- St1 = expr(Arg, Def, any, St0), %Ignore values
+ St1 = expr(Arg, Def, 1, St0),
body(B, Def, Rt, St1);
expr(#c_let{vars=Vs,arg=Arg,body=B}, Def, Rt, St0) ->
St1 = body(Arg, Def, let_varcount(Vs), St0), %This is a body
diff --git a/lib/compiler/src/core_scan.erl b/lib/compiler/src/core_scan.erl
index 5aab8ae855..0ca2f57dde 100644
--- a/lib/compiler/src/core_scan.erl
+++ b/lib/compiler/src/core_scan.erl
@@ -1,7 +1,8 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -31,16 +32,16 @@
%% 173 - 176 { - ~ punctuation
%% 177 DEL control
%% 200 - 237 control
-%% 240 - 277 NBSP - � punctuation
-%% 300 - 326 � - � uppercase
-%% 327 � punctuation
-%% 330 - 336 � - � uppercase
-%% 337 - 366 � - � lowercase
-%% 367 � punctuation
-%% 370 - 377 � - � lowercase
+%% 240 - 277 NBSP - ¿ punctuation
+%% 300 - 326 À - Ö uppercase
+%% 327 × punctuation
+%% 330 - 336 Ø - Þ uppercase
+%% 337 - 366 ß - ö lowercase
+%% 367 ÷ punctuation
+%% 370 - 377 ø - ÿ lowercase
%%
%% Many punctuation characters region have special meaning. Must
-%% watch using � \327, bvery close to x \170
+%% watch using × \327, bvery close to x \170
-module(core_scan).
@@ -239,11 +240,11 @@ scan1([C|Cs], Toks, Pos) when C >= $\200, C =< $\240 ->
scan1(Cs, Toks, Pos);
scan1([C|Cs], Toks, Pos) when C >= $a, C =< $z -> %Keywords
scan_key_word(C, Cs, Toks, Pos);
-scan1([C|Cs], Toks, Pos) when C >= $�, C =< $�, C /= $� ->
+scan1([C|Cs], Toks, Pos) when C >= $ß, C =< $ÿ, C /= $÷ ->
scan_key_word(C, Cs, Toks, Pos);
scan1([C|Cs], Toks, Pos) when C >= $A, C =< $Z -> %Variables
scan_variable(C, Cs, Toks, Pos);
-scan1([C|Cs], Toks, Pos) when C >= $�, C =< $�, C /= $� ->
+scan1([C|Cs], Toks, Pos) when C >= $À, C =< $Þ, C /= $× ->
scan_variable(C, Cs, Toks, Pos);
scan1([C|Cs], Toks, Pos) when C >= $0, C =< $9 -> %Numbers
scan_number(C, Cs, Toks, Pos);
@@ -308,9 +309,9 @@ scan_name([], Ncs) ->
{Ncs,[]}.
name_char(C) when C >= $a, C =< $z -> true;
-name_char(C) when C >= $�, C =< $�, C /= $� -> true;
+name_char(C) when C >= $ß, C =< $ÿ, C /= $÷ -> true;
name_char(C) when C >= $A, C =< $Z -> true;
-name_char(C) when C >= $�, C =< $�, C /= $� -> true;
+name_char(C) when C >= $À, C =< $Þ, C /= $× -> true;
name_char(C) when C >= $0, C =< $9 -> true;
name_char($_) -> true;
name_char($@) -> true;
diff --git a/lib/compiler/src/erl_bifs.erl b/lib/compiler/src/erl_bifs.erl
index 9ad2378d00..3ad3c8c690 100644
--- a/lib/compiler/src/erl_bifs.erl
+++ b/lib/compiler/src/erl_bifs.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -68,6 +68,8 @@ is_pure(erlang, atom_to_list, 1) -> true;
is_pure(erlang, binary_part, 2) -> true;
is_pure(erlang, binary_part, 3) -> true;
is_pure(erlang, binary_to_atom, 2) -> true;
+is_pure(erlang, binary_to_float, 1) -> true;
+is_pure(erlang, binary_to_integer, 1) -> true;
is_pure(erlang, binary_to_list, 1) -> true;
is_pure(erlang, binary_to_list, 3) -> true;
is_pure(erlang, bit_size, 1) -> true;
@@ -75,8 +77,10 @@ is_pure(erlang, byte_size, 1) -> true;
is_pure(erlang, element, 2) -> true;
is_pure(erlang, float, 1) -> true;
is_pure(erlang, float_to_list, 1) -> true;
+is_pure(erlang, float_to_binary, 1) -> true;
is_pure(erlang, hash, 2) -> false;
is_pure(erlang, hd, 1) -> true;
+is_pure(erlang, integer_to_binary, 1) -> true;
is_pure(erlang, integer_to_list, 1) -> true;
is_pure(erlang, is_atom, 1) -> true;
is_pure(erlang, is_boolean, 1) -> true;
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index 18fba7962b..cda3f7d81e 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -132,7 +132,12 @@ body(Body, Sub) ->
body(#c_values{anno=A,es=Es0}, Ctxt, Sub) ->
Es1 = expr_list(Es0, Ctxt, Sub),
- #c_values{anno=A,es=Es1};
+ case Ctxt of
+ value ->
+ #c_values{anno=A,es=Es1};
+ effect ->
+ make_effect_seq(Es1, Sub)
+ end;
body(E, Ctxt, Sub) ->
?ASSERT(verify_scope(E, Sub)),
expr(E, Ctxt, Sub).
@@ -686,11 +691,14 @@ call_1(#c_call{anno=Anno}, lists, all, [Arg1,Arg2], Sub) ->
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
body=#c_case{arg=#c_apply{anno=Anno, op=F, args=[X]},
clauses = [CC1, CC2, CC3]}},
- C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
+ C2 = #c_clause{pats=[#c_literal{val=[]}],
+ guard=#c_call{module=#c_literal{val=erlang},
+ name=#c_literal{val=is_function},
+ args=[F, #c_literal{val=1}]},
body=#c_literal{val=true}},
- Err2 = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
+ Err2 = #c_tuple{es=[#c_literal{val='function_clause'}, F, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=match_fail(Anno, Err2)},
+ body=match_fail([{function_name,{'lists^all',1}}|Anno], Err2)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
@@ -713,11 +721,14 @@ call_1(#c_call{anno=Anno}, lists, any, [Arg1,Arg2], Sub) ->
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
body=#c_case{arg=#c_apply{anno=Anno, op=F, args=[X]},
clauses = [CC1, CC2, CC3]}},
- C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
+ C2 = #c_clause{pats=[#c_literal{val=[]}],
+ guard=#c_call{module=#c_literal{val=erlang},
+ name=#c_literal{val=is_function},
+ args=[F, #c_literal{val=1}]},
body=#c_literal{val=false}},
- Err2 = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
+ Err2 = #c_tuple{es=[#c_literal{val='function_clause'}, F, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=match_fail(Anno, Err2)},
+ body=match_fail([{function_name,{'lists^any',1}}|Anno], Err2)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
@@ -733,11 +744,14 @@ call_1(#c_call{anno=Anno}, lists, foreach, [Arg1,Arg2], Sub) ->
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
body=#c_seq{arg=#c_apply{anno=Anno, op=F, args=[X]},
body=#c_apply{anno=Anno, op=Loop, args=[Xs]}}},
- C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
+ C2 = #c_clause{pats=[#c_literal{val=[]}],
+ guard=#c_call{module=#c_literal{val=erlang},
+ name=#c_literal{val=is_function},
+ args=[F, #c_literal{val=1}]},
body=#c_literal{val=ok}},
- Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
+ Err = #c_tuple{es=[#c_literal{val='function_clause'}, F, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=match_fail(Anno, Err)},
+ body=match_fail([{function_name,{'lists^foreach',1}}|Anno], Err)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
@@ -756,14 +770,18 @@ call_1(#c_call{anno=Anno}, lists, map, [Arg1,Arg2], Sub) ->
op=F,
args=[X]},
body=#c_cons{hd=H,
+ anno=[compiler_generated],
tl=#c_apply{anno=Anno,
op=Loop,
args=[Xs]}}}},
- C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
+ C2 = #c_clause{pats=[#c_literal{val=[]}],
+ guard=#c_call{module=#c_literal{val=erlang},
+ name=#c_literal{val=is_function},
+ args=[F, #c_literal{val=1}]},
body=#c_literal{val=[]}},
- Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
+ Err = #c_tuple{es=[#c_literal{val='function_clause'}, F, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=match_fail(Anno, Err)},
+ body=match_fail([{function_name,{'lists^map',1}}|Anno], Err)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
@@ -780,18 +798,21 @@ call_1(#c_call{anno=Anno}, lists, flatmap, [Arg1,Arg2], Sub) ->
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
body=#c_let{vars=[H],
arg=#c_apply{anno=Anno, op=F, args=[X]},
- body=#c_call{anno=Anno,
+ body=#c_call{anno=[compiler_generated|Anno],
module=#c_literal{val=erlang},
name=#c_literal{val='++'},
args=[H,
#c_apply{anno=Anno,
op=Loop,
args=[Xs]}]}}},
- C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
+ C2 = #c_clause{pats=[#c_literal{val=[]}],
+ guard=#c_call{module=#c_literal{val=erlang},
+ name=#c_literal{val=is_function},
+ args=[F, #c_literal{val=1}]},
body=#c_literal{val=[]}},
- Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
+ Err = #c_tuple{es=[#c_literal{val='function_clause'}, F, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=match_fail(Anno, Err)},
+ body=match_fail([{function_name,{'lists^flatmap',1}}|Anno], Err)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
@@ -807,7 +828,7 @@ call_1(#c_call{anno=Anno}, lists, filter, [Arg1,Arg2], Sub) ->
B = #c_var{name='B'},
Err1 = #c_tuple{es=[#c_literal{val='case_clause'}, X]},
CC1 = #c_clause{pats=[#c_literal{val=true}], guard=#c_literal{val=true},
- body=#c_cons{hd=X, tl=Xs}},
+ body=#c_cons{anno=[compiler_generated], hd=X, tl=Xs}},
CC2 = #c_clause{pats=[#c_literal{val=false}], guard=#c_literal{val=true},
body=Xs},
CC3 = #c_clause{pats=[X], guard=#c_literal{val=true},
@@ -821,11 +842,14 @@ call_1(#c_call{anno=Anno}, lists, filter, [Arg1,Arg2], Sub) ->
op=Loop,
args=[Xs]},
body=Case}}},
- C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
+ C2 = #c_clause{pats=[#c_literal{val=[]}],
+ guard=#c_call{module=#c_literal{val=erlang},
+ name=#c_literal{val=is_function},
+ args=[F, #c_literal{val=1}]},
body=#c_literal{val=[]}},
- Err2 = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
+ Err2 = #c_tuple{es=[#c_literal{val='function_clause'}, F, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=match_fail(Anno, Err2)},
+ body=match_fail([{function_name,{'lists^filter',1}}|Anno], Err2)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
@@ -845,10 +869,14 @@ call_1(#c_call{anno=Anno}, lists, foldl, [Arg1,Arg2,Arg3], Sub) ->
args=[Xs, #c_apply{anno=Anno,
op=F,
args=[X, A]}]}},
- C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true}, body=A},
- Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
+ C2 = #c_clause{pats=[#c_literal{val=[]}],
+ guard=#c_call{module=#c_literal{val=erlang},
+ name=#c_literal{val=is_function},
+ args=[F, #c_literal{val=2}]},
+ body=A},
+ Err = #c_tuple{es=[#c_literal{val='function_clause'}, F, A, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=match_fail(Anno, Err)},
+ body=match_fail([{function_name,{'lists^foldl',2}}|Anno], Err)},
Fun = #c_fun{vars=[Xs, A],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
@@ -868,10 +896,14 @@ call_1(#c_call{anno=Anno}, lists, foldr, [Arg1,Arg2,Arg3], Sub) ->
args=[X, #c_apply{anno=Anno,
op=Loop,
args=[Xs, A]}]}},
- C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true}, body=A},
- Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
+ C2 = #c_clause{pats=[#c_literal{val=[]}],
+ guard=#c_call{module=#c_literal{val=erlang},
+ name=#c_literal{val=is_function},
+ args=[F, #c_literal{val=2}]},
+ body=A},
+ Err = #c_tuple{es=[#c_literal{val='function_clause'}, F, A, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=match_fail(Anno, Err)},
+ body=match_fail([{function_name,{'lists^foldr',2}}|Anno], Err)},
Fun = #c_fun{vars=[Xs, A],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
@@ -901,7 +933,10 @@ call_1(#c_call{anno=Anno}, lists, mapfoldl, [Arg1,Arg2,Arg3], Sub) ->
op=Loop,
args=[Xs, Avar]},
#c_tuple{es=[Xs, Avar]},
- #c_tuple{es=[#c_cons{hd=X, tl=Xs}, Avar]})
+ #c_tuple{anno=[compiler_generated],
+ es=[#c_cons{anno=[compiler_generated],
+ hd=X, tl=Xs},
+ Avar]})
%%% Multiple-value version
%%% #c_let{vars=[Xs,A],
%%% %% The tuple here will be optimised
@@ -910,14 +945,18 @@ call_1(#c_call{anno=Anno}, lists, mapfoldl, [Arg1,Arg2,Arg3], Sub) ->
%%% body=#c_values{es=[#c_cons{hd=X, tl=Xs},
%%% A]}}
)},
- C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
+ C2 = #c_clause{pats=[#c_literal{val=[]}],
+ guard=#c_call{module=#c_literal{val=erlang},
+ name=#c_literal{val=is_function},
+ args=[F, #c_literal{val=2}]},
%%% Tuple passing version
- body=#c_tuple{es=[#c_literal{val=[]}, Avar]}},
+ body=#c_tuple{anno=[compiler_generated],
+ es=[#c_literal{val=[]}, Avar]}},
%%% Multiple-value version
%%% body=#c_values{es=[#c_literal{val=[]}, A]}},
- Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
+ Err = #c_tuple{es=[#c_literal{val='function_clause'}, F, Avar, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=match_fail(Anno, Err)},
+ body=match_fail([{function_name,{'lists^mapfoldl',2}}|Anno], Err)},
Fun = #c_fun{vars=[Xs, Avar],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
@@ -955,7 +994,9 @@ call_1(#c_call{anno=Anno}, lists, mapfoldr, [Arg1,Arg2,Arg3], Sub) ->
#c_tuple{es=[Xs, Avar]},
Match(#c_apply{anno=Anno, op=F, args=[X, Avar]},
#c_tuple{es=[X, Avar]},
- #c_tuple{es=[#c_cons{hd=X, tl=Xs}, Avar]}))
+ #c_tuple{anno=[compiler_generated],
+ es=[#c_cons{anno=[compiler_generated],
+ hd=X, tl=Xs}, Avar]}))
%%% Multiple-value version
%%% body=#c_let{vars=[Xs,A],
%%% %% The tuple will be optimised away
@@ -965,14 +1006,18 @@ call_1(#c_call{anno=Anno}, lists, mapfoldr, [Arg1,Arg2,Arg3], Sub) ->
%%% #c_values{es=[#c_cons{hd=X, tl=Xs},
%%% A]})}
},
- C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
+ C2 = #c_clause{pats=[#c_literal{val=[]}],
+ guard=#c_call{module=#c_literal{val=erlang},
+ name=#c_literal{val=is_function},
+ args=[F, #c_literal{val=2}]},
%%% Tuple passing version
- body=#c_tuple{es=[#c_literal{val=[]}, Avar]}},
+ body=#c_tuple{anno=[compiler_generated],
+ es=[#c_literal{val=[]}, Avar]}},
%%% Multiple-value version
%%% body=#c_values{es=[#c_literal{val=[]}, A]}},
- Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
+ Err = #c_tuple{es=[#c_literal{val='function_clause'}, F, Avar, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=match_fail(Anno, Err)},
+ body=match_fail([{function_name,{'lists^mapfoldr',2}}|Anno], Err)},
Fun = #c_fun{vars=[Xs, Avar],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
@@ -1232,6 +1277,8 @@ eval_element(Call, #c_literal{val=Pos}, #c_var{name=V}, Types)
true ->
eval_failure(Call, badarg)
end;
+ {ok,_} ->
+ eval_failure(Call, badarg);
error ->
Call
end;
@@ -2632,16 +2679,19 @@ bsm_nonempty([#c_clause{pats=Ps}|Cs], Pos) ->
bsm_nonempty([], _ ) -> false.
%% bsm_ensure_no_partition(Cs, Pos) -> ok (exception if problem)
-%% We must make sure that binary matching is not partitioned between
+%% We must make sure that matching is not partitioned between
%% variables like this:
%% foo(<<...>>) -> ...
-%% foo(Var) when ... -> ...
-%% foo(<<...>>) ->
+%% foo(<Variable>) when ... -> ...
+%% foo(<Any non-variable pattern>) ->
%% If there is such partition, we are not allowed to reuse the binary variable
-%% for the match context. Also, arguments to the left of the argument that
-%% is matched against a binary, are only allowed to be simple variables, not
-%% used in guards. The reason is that we must know that the binary is only
-%% matched in one place.
+%% for the match context.
+%%
+%% Also, arguments to the left of the argument that is matched
+%% against a binary, are only allowed to be simple variables, not
+%% used in guards. The reason is that we must know that the binary is
+%% only matched in one place (i.e. there must be only one bs_start_match2
+%% instruction emitted).
bsm_ensure_no_partition(Cs, Pos) ->
bsm_ensure_no_partition_1(Cs, Pos, before).
@@ -2649,6 +2699,12 @@ bsm_ensure_no_partition(Cs, Pos) ->
%% Loop through each clause.
bsm_ensure_no_partition_1([#c_clause{pats=Ps,guard=G}|Cs], Pos, State0) ->
State = bsm_ensure_no_partition_2(Ps, Pos, G, simple_vars, State0),
+ case State of
+ 'after' ->
+ bsm_ensure_no_partition_after(Cs, Pos);
+ _ ->
+ ok
+ end,
bsm_ensure_no_partition_1(Cs, Pos, State);
bsm_ensure_no_partition_1([], _, _) -> ok.
@@ -2658,8 +2714,7 @@ bsm_ensure_no_partition_2([#c_binary{}=Where|_], 1, _, Vstate, State) ->
before when Vstate =:= simple_vars -> within;
before -> bsm_problem(Where, Vstate);
within when Vstate =:= simple_vars -> within;
- within -> bsm_problem(Where, Vstate);
- 'after' -> bsm_problem(Where, bin_partition)
+ within -> bsm_problem(Where, Vstate)
end;
bsm_ensure_no_partition_2([#c_alias{}=Alias|_], 1, N, Vstate, State) ->
%% Retrieve the real pattern that the alias refers to and check that.
@@ -2708,6 +2763,15 @@ bsm_ensure_no_partition_2([#c_var{name=V}|Ps], N, G, Vstate, S) ->
bsm_ensure_no_partition_2([_|Ps], N, G, _, S) ->
bsm_ensure_no_partition_2(Ps, N-1, G, bin_argument_order, S).
+bsm_ensure_no_partition_after([#c_clause{pats=Ps}|Cs], Pos) ->
+ case nth(Pos, Ps) of
+ #c_var{} ->
+ bsm_ensure_no_partition_after(Cs, Pos);
+ P ->
+ bsm_problem(P, bin_partition)
+ end;
+bsm_ensure_no_partition_after([], _) -> ok.
+
bsm_could_match_binary(#c_alias{pat=P}) -> bsm_could_match_binary(P);
bsm_could_match_binary(#c_cons{}) -> false;
bsm_could_match_binary(#c_tuple{}) -> false;
@@ -2832,7 +2896,7 @@ format_error(useless_building) ->
format_error(bin_opt_alias) ->
"INFO: the '=' operator will prevent delayed sub binary optimization";
format_error(bin_partition) ->
- "INFO: non-consecutive clauses that match binaries "
+ "INFO: matching non-variables after a previous clause matching a variable "
"will prevent delayed sub binary optimization";
format_error(bin_left_var_used_in_guard) ->
"INFO: a variable to the left of the binary pattern is used in a guard; "
diff --git a/lib/compiler/src/sys_expand_pmod.erl b/lib/compiler/src/sys_expand_pmod.erl
deleted file mode 100644
index da644b4f0b..0000000000
--- a/lib/compiler/src/sys_expand_pmod.erl
+++ /dev/null
@@ -1,433 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(sys_expand_pmod).
-
-%% Expand function definition forms of parameterized module. We assume
-%% all record definitions, imports, queries, etc., have been expanded
-%% away. Any calls on the form 'foo(...)' must be calls to local
-%% functions. Auto-generated functions (module_info,...) have not yet
-%% been added to the function definitions, but are listed in 'defined'
-%% and 'exports'. The automatic 'new/N' function is neither added to the
-%% definitions nor to the 'exports'/'defines' lists yet.
-
--export([forms/4]).
-
--record(pmod, {parameters, exports, defined, predef}).
-
-%% TODO: more abstract handling of predefined/static functions.
-
-forms(Fs0, Ps, Es0, Ds0) ->
- PreDef = [{module_info,0},{module_info,1}],
- forms(Fs0, Ps, Es0, Ds0, PreDef).
-
-forms(Fs0, Ps, Es0, Ds0, PreDef) ->
- St0 = #pmod{parameters=Ps,exports=Es0,defined=Ds0, predef=PreDef},
- {Fs1, St1} = forms(Fs0, St0),
- Es1 = update_function_names(Es0, St1),
- Ds1 = update_function_names(Ds0, St1),
- Fs2 = update_forms(Fs1, St1),
- {Fs2,Es1,Ds1}.
-
-%% This is extremely simplistic for now; all functions get an extra
-%% parameter, whether they need it or not, except for static functions.
-
-update_function_names(Es, St) ->
- [update_function_name(E, St) || E <- Es].
-
-update_function_name(E={F,A}, St) when F =/= new ->
- case ordsets:is_element(E, St#pmod.predef) of
- true -> E;
- false -> {F, A + 1}
- end;
-update_function_name(E, _St) ->
- E.
-
-update_forms([{function,L,N,A,Cs}|Fs],St) when N =/= new ->
- [{function,L,N,A+1,Cs}|update_forms(Fs,St)];
-update_forms([F|Fs],St) ->
- [F|update_forms(Fs,St)];
-update_forms([],_St) ->
- [].
-
-%% Process the program forms.
-
-forms([F0|Fs0],St0) ->
- {F1,St1} = form(F0,St0),
- {Fs1,St2} = forms(Fs0,St1),
- {[F1|Fs1],St2};
-forms([], St0) ->
- {[], St0}.
-
-%% Only function definitions are of interest here. State is not updated.
-form({function,Line,Name0,Arity0,Clauses0},St) when Name0 =/= new ->
- {Name,Arity,Clauses} = function(Name0, Arity0, Clauses0, St),
- {{function,Line,Name,Arity,Clauses},St};
-%% Pass anything else through
-form(F,St) -> {F,St}.
-
-function(Name, Arity, Clauses0, St) ->
- Clauses1 = clauses(Clauses0,St),
- {Name,Arity,Clauses1}.
-
-clauses([C|Cs],St) ->
- {clause,L,H,G,B} = clause(C,St),
- T = {tuple,L,[{var,L,V} || V <- ['_'|St#pmod.parameters]]},
- [{clause,L,H++[{match,L,T,{var,L,'THIS'}}],G,B}|clauses(Cs,St)];
-clauses([],_St) -> [].
-
-clause({clause,Line,H0,G0,B0},St) ->
- H1 = head(H0,St),
- G1 = guard(G0,St),
- B1 = exprs(B0,St),
- {clause,Line,H1,G1,B1}.
-
-head(Ps,St) -> patterns(Ps,St).
-
-patterns([P0|Ps],St) ->
- P1 = pattern(P0,St),
- [P1|patterns(Ps,St)];
-patterns([],_St) -> [].
-
-string_to_conses([], _Line, Tail) ->
- Tail;
-string_to_conses([E|Rest], Line, Tail) ->
- {cons, Line, {integer, Line, E}, string_to_conses(Rest, Line, Tail)}.
-
-pattern({var,_Line,_V}=Var,_St) -> Var;
-pattern({match,Line,L0,R0},St) ->
- L1 = pattern(L0,St),
- R1 = pattern(R0,St),
- {match,Line,L1,R1};
-pattern({integer,_Line,_I}=Integer,_St) -> Integer;
-pattern({char,_Line,_C}=Char,_St) -> Char;
-pattern({float,_Line,_F}=Float,_St) -> Float;
-pattern({atom,_Line,_A}=Atom,_St) -> Atom;
-pattern({string,_Line,_S}=String,_St) -> String;
-pattern({nil,_Line}=Nil,_St) -> Nil;
-pattern({cons,Line,H0,T0},St) ->
- H1 = pattern(H0,St),
- T1 = pattern(T0,St),
- {cons,Line,H1,T1};
-pattern({tuple,Line,Ps0},St) ->
- Ps1 = pattern_list(Ps0,St),
- {tuple,Line,Ps1};
-pattern({bin,Line,Fs},St) ->
- Fs2 = pattern_grp(Fs,St),
- {bin,Line,Fs2};
-pattern({op,_Line,'++',{nil,_},R},St) ->
- pattern(R,St);
-pattern({op,_Line,'++',{cons,Li,{char,_C2,_I}=Char,T},R},St) ->
- pattern({cons,Li,Char,{op,Li,'++',T,R}},St);
-pattern({op,_Line,'++',{cons,Li,{integer,_L2,_I}=Integer,T},R},St) ->
- pattern({cons,Li,Integer,{op,Li,'++',T,R}},St);
-pattern({op,_Line,'++',{string,Li,L},R},St) ->
- pattern(string_to_conses(L, Li, R),St);
-pattern({op,_Line,_Op,_A}=Op4,_St) -> Op4;
-pattern({op,_Line,_Op,_L,_R}=Op5,_St) -> Op5.
-
-pattern_grp([{bin_element,L1,E1,S1,T1} | Fs],St) ->
- S2 = case S1 of
- default ->
- default;
- _ ->
- expr(S1,St)
- end,
- T2 = case T1 of
- default ->
- default;
- _ ->
- bit_types(T1)
- end,
- [{bin_element,L1,expr(E1,St),S2,T2} | pattern_grp(Fs,St)];
-pattern_grp([],_St) ->
- [].
-
-bit_types([]) ->
- [];
-bit_types([Atom | Rest]) when is_atom(Atom) ->
- [Atom | bit_types(Rest)];
-bit_types([{Atom, Integer} | Rest]) when is_atom(Atom), is_integer(Integer) ->
- [{Atom, Integer} | bit_types(Rest)].
-
-pattern_list([P0|Ps],St) ->
- P1 = pattern(P0,St),
- [P1|pattern_list(Ps,St)];
-pattern_list([],_St) -> [].
-
-guard([G0|Gs],St) when is_list(G0) ->
- [guard0(G0,St) | guard(Gs,St)];
-guard(L,St) ->
- guard0(L,St).
-
-guard0([G0|Gs],St) ->
- G1 = guard_test(G0,St),
- [G1|guard0(Gs,St)];
-guard0([],_St) -> [].
-
-guard_test(Expr={call,Line,{atom,La,F},As0},St) ->
- case erl_internal:type_test(F, length(As0)) of
- true ->
- As1 = gexpr_list(As0,St),
- {call,Line,{atom,La,F},As1};
- _ ->
- gexpr(Expr,St)
- end;
-guard_test(Any,St) ->
- gexpr(Any,St).
-
-gexpr({var,_L,_V}=Var,_St) -> Var;
-% %% alternative implementation of accessing module parameters
-% case index(V,St#pmod.parameters) of
-% N when N > 0 ->
-% {call,L,{remote,L,{atom,L,erlang},{atom,L,element}},
-% [{integer,L,N+1},{var,L,'THIS'}]};
-% _ ->
-% Var
-% end;
-gexpr({integer,_Line,_I}=Integer,_St) -> Integer;
-gexpr({char,_Line,_C}=Char,_St) -> Char;
-gexpr({float,_Line,_F}=Float,_St) -> Float;
-gexpr({atom,_Line,_A}=Atom,_St) -> Atom;
-gexpr({string,_Line,_S}=String,_St) -> String;
-gexpr({nil,_Line}=Nil,_St) -> Nil;
-gexpr({cons,Line,H0,T0},St) ->
- H1 = gexpr(H0,St),
- T1 = gexpr(T0,St),
- {cons,Line,H1,T1};
-gexpr({tuple,Line,Es0},St) ->
- Es1 = gexpr_list(Es0,St),
- {tuple,Line,Es1};
-gexpr({call,Line,{atom,_La,F}=Atom,As0},St) ->
- true = erl_internal:guard_bif(F, length(As0)),
- As1 = gexpr_list(As0,St),
- {call,Line,Atom,As1};
-%% Pre-expansion generated calls to erlang:is_record/3 must also be handled
-gexpr({call,Line,{remote,La,{atom,Lb,erlang},{atom,Lc,is_record}},[_,_,_]=As0},St) ->
- As1 = gexpr_list(As0,St),
- {call,Line,{remote,La,{atom,Lb,erlang},{atom,Lc,is_record}},As1};
-%% Guard BIFs can be remote, but only in the module erlang...
-gexpr({call,Line,{remote,La,{atom,Lb,erlang},{atom,Lc,F}},As0},St) ->
- A = length(As0),
- true =
- erl_internal:guard_bif(F, A) orelse erl_internal:arith_op(F, A) orelse
- erl_internal:comp_op(F, A) orelse erl_internal:bool_op(F, A),
- As1 = gexpr_list(As0,St),
- {call,Line,{remote,La,{atom,Lb,erlang},{atom,Lc,F}},As1};
-%% Unfortunately, writing calls as {M,F}(...) is also allowed.
-gexpr({call,Line,{tuple,La,[{atom,Lb,erlang},{atom,Lc,F}]},As0},St) ->
- A = length(As0),
- true =
- erl_internal:guard_bif(F, A) orelse erl_internal:arith_op(F, A) orelse
- erl_internal:comp_op(F, A) orelse erl_internal:bool_op(F, A),
- As1 = gexpr_list(As0,St),
- {call,Line,{tuple,La,[{atom,Lb,erlang},{atom,Lc,F}]},As1};
-gexpr({bin,Line,Fs},St) ->
- Fs2 = pattern_grp(Fs,St),
- {bin,Line,Fs2};
-gexpr({op,Line,Op,A0},St) ->
- true = erl_internal:arith_op(Op, 1) orelse erl_internal:bool_op(Op, 1),
- A1 = gexpr(A0,St),
- {op,Line,Op,A1};
-gexpr({op,Line,Op,L0,R0},St) ->
- true =
- Op =:= 'andalso' orelse Op =:= 'orelse' orelse
- erl_internal:arith_op(Op, 2) orelse
- erl_internal:bool_op(Op, 2) orelse erl_internal:comp_op(Op, 2),
- L1 = gexpr(L0,St),
- R1 = gexpr(R0,St),
- {op,Line,Op,L1,R1}.
-
-gexpr_list([E0|Es],St) ->
- E1 = gexpr(E0,St),
- [E1|gexpr_list(Es,St)];
-gexpr_list([],_St) -> [].
-
-exprs([E0|Es],St) ->
- E1 = expr(E0,St),
- [E1|exprs(Es,St)];
-exprs([],_St) -> [].
-
-expr({var,_L,_V}=Var,_St) ->
- Var;
-% case index(V,St#pmod.parameters) of
-% N when N > 0 ->
-% {call,L,{remote,L,{atom,L,erlang},{atom,L,element}},
-% [{integer,L,N+1},{var,L,'THIS'}]};
-% _ ->
-% Var
-% end;
-expr({integer,_Line,_I}=Integer,_St) -> Integer;
-expr({float,_Line,_F}=Float,_St) -> Float;
-expr({atom,_Line,_A}=Atom,_St) -> Atom;
-expr({string,_Line,_S}=String,_St) -> String;
-expr({char,_Line,_C}=Char,_St) -> Char;
-expr({nil,_Line}=Nil,_St) -> Nil;
-expr({cons,Line,H0,T0},St) ->
- H1 = expr(H0,St),
- T1 = expr(T0,St),
- {cons,Line,H1,T1};
-expr({lc,Line,E0,Qs0},St) ->
- Qs1 = lc_bc_quals(Qs0,St),
- E1 = expr(E0,St),
- {lc,Line,E1,Qs1};
-expr({bc,Line,E0,Qs0},St) ->
- Qs1 = lc_bc_quals(Qs0,St),
- E1 = expr(E0,St),
- {bc,Line,E1,Qs1};
-expr({tuple,Line,Es0},St) ->
- Es1 = expr_list(Es0,St),
- {tuple,Line,Es1};
-expr({block,Line,Es0},St) ->
- Es1 = exprs(Es0,St),
- {block,Line,Es1};
-expr({'if',Line,Cs0},St) ->
- Cs1 = icr_clauses(Cs0,St),
- {'if',Line,Cs1};
-expr({'case',Line,E0,Cs0},St) ->
- E1 = expr(E0,St),
- Cs1 = icr_clauses(Cs0,St),
- {'case',Line,E1,Cs1};
-expr({'receive',Line,Cs0},St) ->
- Cs1 = icr_clauses(Cs0,St),
- {'receive',Line,Cs1};
-expr({'receive',Line,Cs0,To0,ToEs0},St) ->
- To1 = expr(To0,St),
- ToEs1 = exprs(ToEs0,St),
- Cs1 = icr_clauses(Cs0,St),
- {'receive',Line,Cs1,To1,ToEs1};
-expr({'try',Line,Es0,Scs0,Ccs0,As0},St) ->
- Es1 = exprs(Es0,St),
- Scs1 = icr_clauses(Scs0,St),
- Ccs1 = icr_clauses(Ccs0,St),
- As1 = exprs(As0,St),
- {'try',Line,Es1,Scs1,Ccs1,As1};
-expr({'fun',_,{function,_,_,_}}=ExtFun,_St) ->
- ExtFun;
-expr({'fun',Line,Body,Info},St) ->
- case Body of
- {clauses,Cs0} ->
- Cs1 = fun_clauses(Cs0,St),
- {'fun',Line,{clauses,Cs1},Info};
- {function,F,A} = Function ->
- {F1,A1} = update_function_name({F,A},St),
- if A1 =:= A ->
- {'fun',Line,Function,Info};
- true ->
- %% Must rewrite local fun-name to a fun that does a
- %% call with the extra THIS parameter.
- As = make_vars(A, Line),
- As1 = As ++ [{var,Line,'THIS'}],
- Call = {call,Line,{atom,Line,F1},As1},
- Cs = [{clause,Line,As,[],[Call]}],
- {'fun',Line,{clauses,Cs},Info}
- end;
- {function,_M,_F,_A} = Fun4 -> %This is an error in lint!
- {'fun',Line,Fun4,Info}
- end;
-expr({call,Lc,{atom,_,instance}=Name,As0},St) ->
- %% All local functions 'instance(...)' are static by definition,
- %% so they do not take a 'THIS' argument when called
- As1 = expr_list(As0,St),
- {call,Lc,Name,As1};
-expr({call,Lc,{atom,_,new}=Name,As0},St) ->
- %% All local functions 'new(...)' are static by definition,
- %% so they do not take a 'THIS' argument when called
- As1 = expr_list(As0,St),
- {call,Lc,Name,As1};
-expr({call,Lc,{atom,_,module_info}=Name,As0},St)
- when length(As0) =:= 0; length(As0) =:= 1 ->
- %% The module_info/0 and module_info/1 functions are also static.
- As1 = expr_list(As0,St),
- {call,Lc,Name,As1};
-expr({call,Lc,{atom,_Lf,_F}=Atom,As0},St) ->
- %% Local function call - needs THIS parameter.
- As1 = expr_list(As0,St),
- {call,Lc,Atom,As1 ++ [{var,0,'THIS'}]};
-expr({call,Line,F0,As0},St) ->
- %% Other function call
- F1 = expr(F0,St),
- As1 = expr_list(As0,St),
- {call,Line,F1,As1};
-expr({'catch',Line,E0},St) ->
- E1 = expr(E0,St),
- {'catch',Line,E1};
-expr({match,Line,P0,E0},St) ->
- E1 = expr(E0,St),
- P1 = pattern(P0,St),
- {match,Line,P1,E1};
-expr({bin,Line,Fs},St) ->
- Fs2 = pattern_grp(Fs,St),
- {bin,Line,Fs2};
-expr({op,Line,Op,A0},St) ->
- A1 = expr(A0,St),
- {op,Line,Op,A1};
-expr({op,Line,Op,L0,R0},St) ->
- L1 = expr(L0,St),
- R1 = expr(R0,St),
- {op,Line,Op,L1,R1};
-%% The following are not allowed to occur anywhere!
-expr({remote,Line,M0,F0},St) ->
- M1 = expr(M0,St),
- F1 = expr(F0,St),
- {remote,Line,M1,F1}.
-
-expr_list([E0|Es],St) ->
- E1 = expr(E0,St),
- [E1|expr_list(Es,St)];
-expr_list([],_St) -> [].
-
-icr_clauses([C0|Cs],St) ->
- C1 = clause(C0,St),
- [C1|icr_clauses(Cs,St)];
-icr_clauses([],_St) -> [].
-
-lc_bc_quals([{generate,Line,P0,E0}|Qs],St) ->
- E1 = expr(E0,St),
- P1 = pattern(P0,St),
- [{generate,Line,P1,E1}|lc_bc_quals(Qs,St)];
-lc_bc_quals([{b_generate,Line,P0,E0}|Qs],St) ->
- E1 = expr(E0,St),
- P1 = pattern(P0,St),
- [{b_generate,Line,P1,E1}|lc_bc_quals(Qs,St)];
-lc_bc_quals([E0|Qs],St) ->
- E1 = expr(E0,St),
- [E1|lc_bc_quals(Qs,St)];
-lc_bc_quals([],_St) -> [].
-
-fun_clauses([C0|Cs],St) ->
- C1 = clause(C0,St),
- [C1|fun_clauses(Cs,St)];
-fun_clauses([],_St) -> [].
-
-%% %% Return index from 1 upwards, or 0 if not in the list.
-%%
-%% index(X,Ys) -> index(X,Ys,1).
-%%
-%% index(X,[X|Ys],A) -> A;
-%% index(X,[Y|Ys],A) -> index(X,Ys,A+1);
-%% index(X,[],A) -> 0.
-
-make_vars(N, L) ->
- make_vars(1, N, L).
-
-make_vars(N, M, L) when N =< M ->
- V = list_to_atom("X"++integer_to_list(N)),
- [{var,L,V} | make_vars(N + 1, M, L)];
-make_vars(_, _, _) ->
- [].
diff --git a/lib/compiler/src/sys_pre_expand.erl b/lib/compiler/src/sys_pre_expand.erl
index 97d3ff626c..7d918a55ed 100644
--- a/lib/compiler/src/sys_pre_expand.erl
+++ b/lib/compiler/src/sys_pre_expand.erl
@@ -28,17 +28,14 @@
%% Main entry point.
-export([module/2]).
--import(ordsets, [from_list/1,add_element/2,union/2]).
+-import(ordsets, [from_list/1,union/2]).
-import(lists, [member/2,foldl/3,foldr/3]).
-include("../include/erl_bits.hrl").
-record(expand, {module=[], %Module name
- parameters=undefined, %Module parameters
- package="", %Module package
exports=[], %Exports
imports=[], %Imports
- mod_imports, %Module Imports
compile=[], %Compile flags
attributes=[], %Attributes
callbacks=[], %Callbacks
@@ -67,12 +64,8 @@ module(Fs0, Opts0) ->
%% Set pre-defined exported functions.
PreExp = [{module_info,0},{module_info,1}],
- %% Set pre-defined module imports.
- PreModImp = [{erlang,erlang},{packages,packages}],
-
%% Build initial expand record.
St0 = #expand{exports=PreExp,
- mod_imports=dict:from_list(PreModImp),
compile=Opts,
defined=PreExp,
bitdefault = erl_bits:system_bitdefault(),
@@ -80,88 +73,20 @@ module(Fs0, Opts0) ->
},
%% Expand the functions.
{Tfs,St1} = forms(Fs, define_functions(Fs, St0)),
- {Efs,St2} = expand_pmod(Tfs, St1),
%% Get the correct list of exported functions.
- Exports = case member(export_all, St2#expand.compile) of
- true -> gb_sets:to_list(St2#expand.defined);
- false -> St2#expand.exports
+ Exports = case member(export_all, St1#expand.compile) of
+ true -> gb_sets:to_list(St1#expand.defined);
+ false -> St1#expand.exports
end,
%% Generate all functions from stored info.
- {Ats,St3} = module_attrs(St2#expand{exports = Exports}),
+ {Ats,St3} = module_attrs(St1#expand{exports = Exports}),
{Mfs,St4} = module_predef_funcs(St3),
- {St4#expand.module, St4#expand.exports, Ats ++ Efs ++ Mfs,
+ {St4#expand.module, St4#expand.exports, Ats ++ Tfs ++ Mfs,
St4#expand.compile}.
compiler_options(Forms) ->
lists:flatten([C || {attribute,_,compile,C} <- Forms]).
-expand_pmod(Fs0, St0) ->
- case St0#expand.parameters of
- undefined ->
- {Fs0,St0};
- Ps0 ->
- Base = get_base(St0#expand.attributes),
- Ps = if is_atom(Base) ->
- ['BASE' | Ps0];
- true ->
- Ps0
- end,
- Def = gb_sets:to_list(St0#expand.defined),
- {Fs1,Xs,Ds} = sys_expand_pmod:forms(Fs0, Ps,
- St0#expand.exports,
- Def),
- St1 = St0#expand{exports=Xs,defined=gb_sets:from_list(Ds)},
- {Fs2,St2} = add_instance(Ps, Fs1, St1),
- {Fs3,St3} = ensure_new(Base, Ps0, Fs2, St2),
- {Fs3,St3#expand{attributes = [{abstract, 0, [true]}
- | St3#expand.attributes]}}
- end.
-
-get_base(As) ->
- case lists:keyfind(extends, 1, As) of
- {extends,_,[Base]} when is_atom(Base) ->
- Base;
- _ ->
- []
- end.
-
-ensure_new(Base, Ps, Fs, St) ->
- case has_new(Fs) of
- true ->
- {Fs, St};
- false ->
- add_new(Base, Ps, Fs, St)
- end.
-
-has_new([{function,_L,new,_A,_Cs} | _Fs]) ->
- true;
-has_new([_ | Fs]) ->
- has_new(Fs);
-has_new([]) ->
- false.
-
-add_new(Base, Ps, Fs, St) ->
- Vs = [{var,0,V} || V <- Ps],
- As = if is_atom(Base) ->
- [{call,0,{remote,0,{atom,0,Base},{atom,0,new}},Vs} | Vs];
- true ->
- Vs
- end,
- Body = [{call,0,{atom,0,instance},As}],
- add_func(new, Vs, Body, Fs, St).
-
-add_instance(Ps, Fs, St) ->
- Vs = [{var,0,V} || V <- Ps],
- AbsMod = [{tuple,0,[{atom,0,St#expand.module}|Vs]}],
- add_func(instance, Vs, AbsMod, Fs, St).
-
-add_func(Name, Args, Body, Fs, St) ->
- A = length(Args),
- F = {function,0,Name,A,[{clause,0,Args,[],Body}]},
- NA = {Name,A},
- {[F|Fs],St#expand{exports=add_element(NA, St#expand.exports),
- defined=gb_sets:add_element(NA, St#expand.defined)}}.
-
%% define_function(Form, State) -> State.
%% Add function to defined if form is a function.
@@ -241,15 +166,9 @@ forms([], St) -> {[],St}.
%% attribute(Attribute, Value, Line, State) -> State'.
%% Process an attribute, this just affects the state.
-attribute(module, {Module, As}, _L, St) ->
- M = package_to_string(Module),
- St#expand{module=list_to_atom(M),
- package=packages:strip_last(M),
- parameters=As};
attribute(module, Module, _L, St) ->
- M = package_to_string(Module),
- St#expand{module=list_to_atom(M),
- package=packages:strip_last(M)};
+ true = is_atom(Module),
+ St#expand{module=Module};
attribute(export, Es, _L, St) ->
St#expand{exports=union(from_list(Es), St#expand.exports)};
attribute(import, Is, _L, St) ->
@@ -312,8 +231,6 @@ pattern({tuple,Line,Ps}, St0) ->
%%pattern({struct,Line,Tag,Ps}, St0) ->
%% {TPs,TPsvs,St1} = pattern_list(Ps, St0),
%% {{tuple,Line,[{atom,Line,Tag}|TPs]},TPsvs,St1};
-pattern({record_field,_,_,_}=M, St) ->
- {expand_package(M, St),St}; % must be a package name
pattern({bin,Line,Es0}, St0) ->
{Es1,St1} = pattern_bin(Es0, St0),
{{bin,Line,Es1},St1};
@@ -404,8 +321,6 @@ expr({tuple,Line,Es0}, St0) ->
%%expr({struct,Line,Tag,Es0}, Vs, St0) ->
%% {Es1,Esvs,Esus,St1} = expr_list(Es0, Vs, St0),
%% {{tuple,Line,[{atom,Line,Tag}|Es1]},Esvs,Esus,St1};
-expr({record_field,_,_,_}=M, St) ->
- {expand_package(M, St),St}; % must be a package name
expr({bin,Line,Es0}, St0) ->
{Es1,St1} = expr_bin(Es0, St0),
{{bin,Line,Es1},St1};
@@ -448,15 +363,9 @@ expr({call,Line,{atom,La,N}=Atom,As0}, St0) ->
end
end
end;
-expr({call,Line,{record_field,_,_,_}=M,As0}, St0) ->
- expr({call,Line,expand_package(M, St0),As0}, St0);
-expr({call,Line,{remote,Lr,M,F},As0}, St0) ->
- M1 = expand_package(M, St0),
- {[M2,F1|As1],St1} = expr_list([M1,F|As0], St0),
- {{call,Line,{remote,Lr,M2,F1},As1},St1};
-expr({call,Line,{tuple,_,[{atom,_,_}=M,{atom,_,_}=F]},As}, St) ->
- %% Rewrite {Mod,Function}(Args...) to Mod:Function(Args...).
- expr({call,Line,{remote,Line,M,F},As}, St);
+expr({call,Line,{remote,Lr,M0,F},As0}, St0) ->
+ {[M1,F1|As1],St1} = expr_list([M0,F|As0], St0),
+ {{call,Line,{remote,Lr,M1,F1},As1},St1};
expr({call,Line,F,As0}, St0) ->
{[Fun1|As1],St1} = expr_list([F|As0], St0),
{{call,Line,Fun1,As1},St1};
@@ -669,32 +578,6 @@ string_to_conses(Line, Cs, Tail) ->
foldr(fun (C, T) -> {cons,Line,{char,Line,C},T} end, Tail, Cs).
-%% In syntax trees, module/package names are atoms or lists of atoms.
-
-package_to_string(A) when is_atom(A) -> atom_to_list(A);
-package_to_string(L) when is_list(L) -> packages:concat(L).
-
-expand_package({atom,L,A} = M, St) ->
- case dict:find(A, St#expand.mod_imports) of
- {ok, A1} ->
- {atom,L,A1};
- error ->
- case packages:is_segmented(A) of
- true ->
- M;
- false ->
- M1 = packages:concat(St#expand.package, A),
- {atom,L,list_to_atom(M1)}
- end
- end;
-expand_package(M, _St) ->
- case erl_parse:package_segments(M) of
- error ->
- M;
- M1 ->
- {atom,element(2,M),list_to_atom(package_to_string(M1))}
- end.
-
%% import(Line, Imports, State) ->
%% State'
%% imported(Name, Arity, State) ->
@@ -702,15 +585,10 @@ expand_package(M, _St) ->
%% Handle import declarations and test for imported functions. No need to
%% check when building imports as code is correct.
-import({Mod0,Fs}, St) ->
- Mod = list_to_atom(package_to_string(Mod0)),
+import({Mod,Fs}, St) ->
+ true = is_atom(Mod),
Mfs = from_list(Fs),
- St#expand{imports=add_imports(Mod, Mfs, St#expand.imports)};
-import(Mod0, St) ->
- Mod = package_to_string(Mod0),
- Key = list_to_atom(packages:last(Mod)),
- St#expand{mod_imports=dict:store(Key, list_to_atom(Mod),
- St#expand.mod_imports)}.
+ St#expand{imports=add_imports(Mod, Mfs, St#expand.imports)}.
add_imports(Mod, [F|Fs], Is) ->
add_imports(Mod, Fs, orddict:store(F, Mod, Is));
diff --git a/lib/compiler/src/v3_codegen.erl b/lib/compiler/src/v3_codegen.erl
index 812e85553f..6a13495523 100644
--- a/lib/compiler/src/v3_codegen.erl
+++ b/lib/compiler/src/v3_codegen.erl
@@ -123,15 +123,24 @@ cg_fun(Les, Hvs, Vdb, AtomMod, NameArity, Anno, St0) ->
put_reg(V, Reg)
end, [], Hvs),
stk=[]}, 0, Vdb),
- {B,_Aft,St} = cg_list(Les, 0, Vdb, Bef,
+ {B0,_Aft,St} = cg_list(Les, 0, Vdb, Bef,
St3#cg{bfail=0,
ultimate_failure=UltimateMatchFail,
is_top_block=true}),
+ B = fix_bs_match_strings(B0),
{Name,Arity} = NameArity,
Asm = [{label,Fi},line(Anno),{func_info,AtomMod,{atom,Name},Arity},
{label,Fl}|B++[{label,UltimateMatchFail},if_end]],
{Asm,Fl,St}.
+fix_bs_match_strings([{test,bs_match_string,F,[Ctx,BinList]}|Is])
+ when is_list(BinList) ->
+ I = {test,bs_match_string,F,[Ctx,list_to_bitstring(BinList)]},
+ [I|fix_bs_match_strings(Is)];
+fix_bs_match_strings([I|Is]) ->
+ [I|fix_bs_match_strings(Is)];
+fix_bs_match_strings([]) -> [].
+
%% cg(Lkexpr, Vdb, StackReg, State) -> {[Ainstr],StackReg,State}.
%% Generate code for a kexpr.
%% Split function into two steps for clarity, not efficiency.
@@ -714,7 +723,22 @@ select_bin_seg(#l{ke={val_clause,{bin_int,Ctx,Sz,U,Fs,Val,Es},B},i=I,vdb=Vdb},
I, Vdb, Bef, Ctx, St0),
{Bis,Aft,St2} = match_cg(B, Fail, Int, St1),
CtxReg = fetch_var(Ctx, Bef),
- {[{bs_restore2,CtxReg,{Ctx,Ivar}}|Mis] ++ Bis,Aft,St2}.
+ Is = case Mis ++ Bis of
+ [{test,bs_match_string,F,[OtherCtx,Bin1]},
+ {bs_save2,OtherCtx,_},
+ {bs_restore2,OtherCtx,_},
+ {test,bs_match_string,F,[OtherCtx,Bin2]}|Is0] ->
+ %% We used to do this optimization later, but it
+ %% turns out that in huge functions with many
+ %% bs_match_string instructions, it's a big win
+ %% to do the combination now. To avoid copying the
+ %% binary data again and again, we'll combine bitstrings
+ %% in a list and convert all of it to a bitstring later.
+ [{test,bs_match_string,F,[OtherCtx,[Bin1,Bin2]]}|Is0];
+ Is0 ->
+ Is0
+ end,
+ {[{bs_restore2,CtxReg,{Ctx,Ivar}}|Is],Aft,St2}.
select_extract_int([{var,Tl}], Val, {integer,Sz}, U, Fs, Vf,
I, Vdb, Bef, Ctx, St) ->
@@ -1386,22 +1410,32 @@ catch_cg(C, {var,R}, Le, Vdb, Bef, St0) ->
%%
%% put_list for constructing a cons is an atomic instruction
%% which can safely resuse one of the source registers as target.
-%% Also binaries can reuse a source register as target.
set_cg([{var,R}], {cons,Es}, Le, Vdb, Bef, St) ->
- [S1,S2] = map(fun ({var,V}) -> fetch_var(V, Bef);
- (Other) -> Other
- end, Es),
+ [S1,S2] = cg_reg_args(Es, Bef),
Int0 = clear_dead(Bef, Le#l.i, Vdb),
Int1 = Int0#sr{reg=put_reg(R, Int0#sr.reg)},
Ret = fetch_reg(R, Int1#sr.reg),
{[{put_list,S1,S2,Ret}], Int1, St};
set_cg([{var,R}], {binary,Segs}, Le, Vdb, Bef,
#cg{in_catch=InCatch, bfail=Bfail}=St) ->
+ %% At run-time, binaries are constructed in three stages:
+ %% 1) First the size of the binary is calculated.
+ %% 2) Then the binary is allocated.
+ %% 3) Then each field in the binary is constructed.
+ %% For simplicity, we use the target register to also hold the
+ %% size of the binary. Therefore the target register must *not*
+ %% be one of the source registers.
+
+ %% First allocate the target register.
Int0 = Bef#sr{reg=put_reg(R, Bef#sr.reg)},
Target = fetch_reg(R, Int0#sr.reg),
- Fail = {f,Bfail},
+
+ %% Also allocate a scratch register for size calculations.
Temp = find_scratch_reg(Int0#sr.reg),
+
+ %% First generate the code that constructs each field.
+ Fail = {f,Bfail},
PutCode = cg_bin_put(Segs, Fail, Bef),
{Sis,Int1} =
case InCatch of
@@ -1410,6 +1444,8 @@ set_cg([{var,R}], {binary,Segs}, Le, Vdb, Bef,
end,
MaxRegs = max_reg(Bef#sr.reg),
Aft = clear_dead(Int1, Le#l.i, Vdb),
+
+ %% Now generate the complete code for constructing the binary.
Code = cg_binary(PutCode, Target, Temp, Fail, MaxRegs, Le#l.a),
{Sis++Code,Aft,St};
set_cg([{var,R}], Con, Le, Vdb, Bef, St) ->
@@ -1419,10 +1455,8 @@ set_cg([{var,R}], Con, Le, Vdb, Bef, St) ->
Ais = case Con of
{tuple,Es} ->
[{put_tuple,length(Es),Ret}] ++ cg_build_args(Es, Bef);
- {var,V} -> % Normally removed by kernel optimizer.
- [{move,fetch_var(V, Int),Ret}];
Other ->
- [{move,Other,Ret}]
+ [{move,cg_reg_arg(Other, Int),Ret}]
end,
{Ais,clear_dead(Int, Le#l.i, Vdb),St}.
@@ -1576,8 +1610,7 @@ cg_gen_binsize([], _, _, _, _, Acc) -> Acc.
%% cg_bin_opt(Code0) -> Code
%% Optimize the size calculations for binary construction.
-cg_bin_opt([{move,Size,D},{bs_append,Fail,D,Extra,Regs0,U,Bin,Flags,D}|Is]) ->
- Regs = cg_bo_newregs(Regs0, D),
+cg_bin_opt([{move,Size,D},{bs_append,Fail,D,Extra,Regs,U,Bin,Flags,D}|Is]) ->
cg_bin_opt([{bs_append,Fail,Size,Extra,Regs,U,Bin,Flags,D}|Is]);
cg_bin_opt([{move,Size,D},{bs_private_append,Fail,D,U,Bin,Flags,D}|Is]) ->
cg_bin_opt([{bs_private_append,Fail,Size,U,Bin,Flags,D}|Is]);
@@ -1585,9 +1618,8 @@ cg_bin_opt([{move,{integer,0},D},{bs_add,_,[D,{integer,_}=S,1],Dst}|Is]) ->
cg_bin_opt([{move,S,Dst}|Is]);
cg_bin_opt([{move,{integer,0},D},{bs_add,Fail,[D,S,U],Dst}|Is]) ->
cg_bin_opt([{bs_add,Fail,[{integer,0},S,U],Dst}|Is]);
-cg_bin_opt([{move,{integer,Bytes},D},{Op,Fail,D,Extra,Regs0,Flags,D}|Is])
+cg_bin_opt([{move,{integer,Bytes},D},{Op,Fail,D,Extra,Regs,Flags,D}|Is])
when Op =:= bs_init2; Op =:= bs_init_bits ->
- Regs = cg_bo_newregs(Regs0, D),
cg_bin_opt([{Op,Fail,Bytes,Extra,Regs,Flags,D}|Is]);
cg_bin_opt([{move,Src1,Dst},{bs_add,Fail,[Dst,Src2,U],Dst}|Is]) ->
cg_bin_opt([{bs_add,Fail,[Src1,Src2,U],Dst}|Is]);
@@ -1595,20 +1627,9 @@ cg_bin_opt([I|Is]) ->
[I|cg_bin_opt(Is)];
cg_bin_opt([]) -> [].
-cg_bo_newregs(R, {x,X}) when R-1 =:= X -> R-1;
-cg_bo_newregs(R, _) -> R.
-
-%% Common for new and old binary code generation.
-
cg_bin_put({bin_seg,[],S0,U,T,Fs,[E0,Next]}, Fail, Bef) ->
- S1 = case S0 of
- {var,Sv} -> fetch_var(Sv, Bef);
- _ -> S0
- end,
- E1 = case E0 of
- {var,V} -> fetch_var(V, Bef);
- Other -> Other
- end,
+ S1 = cg_reg_arg(S0, Bef),
+ E1 = cg_reg_arg(E0, Bef),
{Format,Op} = case T of
integer -> {plain,bs_put_integer};
utf8 -> {utf,bs_put_utf8};
@@ -1626,9 +1647,7 @@ cg_bin_put({bin_seg,[],S0,U,T,Fs,[E0,Next]}, Fail, Bef) ->
cg_bin_put({bin_end,[]}, _, _) -> [].
cg_build_args(As, Bef) ->
- map(fun ({var,V}) -> {put,fetch_var(V, Bef)};
- (Other) -> {put,Other}
- end, As).
+ [{put,cg_reg_arg(A, Bef)} || A <- As].
%% return_cg([Val], Le, Vdb, Bef, St) -> {[Ainstr],Aft,St}.
%% break_cg([Val], Le, Vdb, Bef, St) -> {[Ainstr],Aft,St}.
@@ -1907,27 +1926,13 @@ fetch_var(V, Sr) ->
error -> fetch_stack(V, Sr#sr.stk)
end.
-% find_var(V, Sr) ->
-% case find_reg(V, Sr#sr.reg) of
-% {ok,R} -> {ok,R};
-% error ->
-% case find_stack(V, Sr#sr.stk) of
-% {ok,S} -> {ok,S};
-% error -> error
-% end
-% end.
-
load_vars(Vs, Regs) ->
foldl(fun ({var,V}, Rs) -> put_reg(V, Rs) end, Regs, Vs).
%% put_reg(Val, Regs) -> Regs.
-%% free_reg(Val, Regs) -> Regs.
%% find_reg(Val, Regs) -> ok{r{R}} | error.
%% fetch_reg(Val, Regs) -> r{R}.
%% Functions to interface the registers.
-%% put_reg puts a value into a free register,
-%% load_reg loads a value into a fixed register
-%% free_reg frees a register containing a specific value.
% put_regs(Vs, Rs) -> foldl(fun put_reg/2, Rs, Vs).
@@ -1938,10 +1943,6 @@ put_reg_1(V, [{reserved,I,V}|Rs], I) -> [{I,V}|Rs];
put_reg_1(V, [R|Rs], I) -> [R|put_reg_1(V, Rs, I+1)];
put_reg_1(V, [], I) -> [{I,V}].
-% free_reg(V, [{I,V}|Rs]) -> [free|Rs];
-% free_reg(V, [R|Rs]) -> [R|free_reg(V, Rs)];
-% free_reg(V, []) -> [].
-
fetch_reg(V, [{I,V}|_]) -> {x,I};
fetch_reg(V, [_|SRs]) -> fetch_reg(V, SRs).
@@ -1958,9 +1959,6 @@ find_scratch_reg([free|_], I) -> {x,I};
find_scratch_reg([_|Rs], I) -> find_scratch_reg(Rs, I+1);
find_scratch_reg([], I) -> {x,I}.
-%%copy_reg(Val, R, Regs) -> load_reg(Val, R, Regs).
-%%move_reg(Val, R, Regs) -> load_reg(Val, R, free_reg(Val, Regs)).
-
replace_reg_contents(Old, New, [{I,Old}|Rs]) -> [{I,New}|Rs];
replace_reg_contents(Old, New, [R|Rs]) -> [R|replace_reg_contents(Old, New, Rs)].
diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl
index b184987625..5f1c108f7c 100644
--- a/lib/compiler/src/v3_kernel.erl
+++ b/lib/compiler/src/v3_kernel.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -81,7 +81,7 @@
-export([module/2,format_error/1]).
-import(lists, [map/2,foldl/3,foldr/3,mapfoldl/3,splitwith/2,member/2,
- keymember/3,keyfind/3]).
+ keymember/3,keyfind/3,partition/2]).
-import(ordsets, [add_element/2,del_element/2,union/2,union/1,subtract/2]).
-import(cerl, [c_tuple/1]).
@@ -1081,9 +1081,44 @@ select_bin_con(Cs0) ->
end, Cs0),
select_bin_con_1(Cs1).
+
select_bin_con_1(Cs) ->
try
- select_bin_int(Cs)
+ %% The usual way to match literals is to first extract the
+ %% value to a register, and then compare the register to the
+ %% literal value. Extracting the value is good if we need
+ %% compare it more than once.
+ %%
+ %% But we would like to combine the extracting and the
+ %% comparing into a single instruction if we know that
+ %% a binary segment must contain specific integer value
+ %% or the matching will fail, like in this example:
+ %%
+ %% <<42:8,...>> ->
+ %% <<42:8,...>> ->
+ %% .
+ %% .
+ %% .
+ %% <<42:8,...>> ->
+ %% <<>> ->
+ %%
+ %% The first segment must either contain the integer 42
+ %% or the binary must end for the match to succeed.
+ %%
+ %% The way we do is to replace the generic #k_bin_seg{}
+ %% record with a #k_bin_int{} record if all clauses will
+ %% select the same literal integer (except for one or more
+ %% clauses that will end the binary).
+
+ {BinSegs0,BinEnd} =
+ partition(fun (C) ->
+ clause_con(C) =:= k_bin_seg
+ end, Cs),
+ BinSegs = select_bin_int(BinSegs0),
+ case BinEnd of
+ [] -> BinSegs;
+ [_|_] -> BinSegs ++ [{k_bin_end,BinEnd}]
+ end
catch
throw:not_possible ->
select_bin_con_2(Cs)
@@ -1097,7 +1132,7 @@ select_bin_con_2([]) -> [].
%% select_bin_int([Clause]) -> {k_bin_int,[Clause]}
%% If the first pattern in each clause selects the same integer,
-%% rewrite all clauses to use #k_bin_int{} (which will later to
+%% rewrite all clauses to use #k_bin_int{} (which will later be
%% translated to a bs_match_string/4 instruction).
%%
%% If it is not possible to do this rewrite, a 'not_possible'
@@ -1346,7 +1381,7 @@ clause_arg(#iclause{pats=[Arg|_]}) -> Arg.
clause_con(C) -> arg_con(clause_arg(C)).
-clause_val(C) -> arg_val(clause_arg(C)).
+clause_val(C) -> arg_val(clause_arg(C), C).
is_var_clause(C) -> clause_con(C) =:= k_var.
@@ -1377,7 +1412,7 @@ arg_con(Arg) ->
#k_var{} -> k_var
end.
-arg_val(Arg) ->
+arg_val(Arg, C) ->
case arg_arg(Arg) of
#k_literal{val=Lit} -> Lit;
#k_int{val=I} -> I;
@@ -1385,7 +1420,13 @@ arg_val(Arg) ->
#k_atom{val=A} -> A;
#k_tuple{es=Es} -> length(Es);
#k_bin_seg{size=S,unit=U,type=T,flags=Fs} ->
- {set_kanno(S, []),U,T,Fs}
+ case S of
+ #k_var{name=V} ->
+ #iclause{isub=Isub} = C,
+ {#k_var{name=get_vsub(V, Isub)},U,T,Fs};
+ _ ->
+ {set_kanno(S, []),U,T,Fs}
+ end
end.
%% ubody_used_vars(Expr, State) -> [UsedVar]
diff --git a/lib/compiler/test/Makefile b/lib/compiler/test/Makefile
index e047166ade..51b3064589 100644
--- a/lib/compiler/test/Makefile
+++ b/lib/compiler/test/Makefile
@@ -10,7 +10,7 @@ MODULES= \
apply_SUITE \
beam_validator_SUITE \
beam_disasm_SUITE \
- beam_expect_SUITE \
+ beam_except_SUITE \
bs_bincomp_SUITE \
bs_bit_binaries_SUITE \
bs_construct_SUITE \
@@ -29,7 +29,6 @@ MODULES= \
match_SUITE \
misc_SUITE \
num_bif_SUITE \
- pmod_SUITE \
receive_SUITE \
record_SUITE \
trycatch_SUITE \
@@ -39,7 +38,7 @@ MODULES= \
NO_OPT= \
andor \
apply \
- beam_expect \
+ beam_except \
bs_construct \
bs_match \
bs_utf \
@@ -76,6 +75,7 @@ INLINE= \
CORE_MODULES = \
bs_shadowed_size_var \
+ unused_multiple_values_error \
nested_call_in_case
diff --git a/lib/compiler/test/andor_SUITE.erl b/lib/compiler/test/andor_SUITE.erl
index f7388f1614..0d00769704 100644
--- a/lib/compiler/test/andor_SUITE.erl
+++ b/lib/compiler/test/andor_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -29,11 +29,12 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [t_case, t_and_or, t_andalso, t_orelse, inside, overlap,
- combined, in_case, before_and_inside_if].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [t_case,t_and_or,t_andalso,t_orelse,inside,overlap,
+ combined,in_case,before_and_inside_if]}].
init_per_suite(Config) ->
Config.
diff --git a/lib/compiler/test/beam_expect_SUITE.erl b/lib/compiler/test/beam_except_SUITE.erl
index 6f216eac4f..bf67eedd5f 100644
--- a/lib/compiler/test/beam_expect_SUITE.erl
+++ b/lib/compiler/test/beam_except_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -16,7 +16,7 @@
%%
%% %CopyrightEnd%
%%
--module(beam_expect_SUITE).
+-module(beam_except_SUITE).
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
diff --git a/lib/compiler/test/beam_validator_SUITE.erl b/lib/compiler/test/beam_validator_SUITE.erl
index 902867bc19..bc1a9e2b3b 100644
--- a/lib/compiler/test/beam_validator_SUITE.erl
+++ b/lib/compiler/test/beam_validator_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -47,17 +47,18 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [beam_files, compiler_bug, stupid_but_valid, xrange,
- yrange, stack, call_last, merge_undefined, uninit,
- unsafe_catch, dead_code, mult_labels,
- overwrite_catchtag, overwrite_trytag, accessing_tags,
- bad_catch_try, cons_guard, freg_range, freg_uninit,
- freg_state, bin_match, bin_aligned, bad_dsetel,
- state_after_fault_in_catch, no_exception_in_catch,
- undef_label, illegal_instruction, failing_gc_guard_bif].
+ [beam_files,{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [compiler_bug,stupid_but_valid,xrange,
+ yrange,stack,call_last,merge_undefined,uninit,
+ unsafe_catch,dead_code,mult_labels,
+ overwrite_catchtag,overwrite_trytag,accessing_tags,
+ bad_catch_try,cons_guard,freg_range,freg_uninit,
+ freg_state,bin_match,bin_aligned,bad_dsetel,
+ state_after_fault_in_catch,no_exception_in_catch,
+ undef_label,illegal_instruction,failing_gc_guard_bif]}].
init_per_suite(Config) ->
Config.
diff --git a/lib/compiler/test/bs_bit_binaries_SUITE.erl b/lib/compiler/test/bs_bit_binaries_SUITE.erl
index 30276f1259..8609a490f5 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-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -34,13 +34,15 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [misc, horrid_match, test_bitstr, test_bit_size,
- asymmetric_tests, big_asymmetric_tests,
- binary_to_and_from_list, big_binary_to_and_from_list,
- send_and_receive, send_and_receive_alot].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [misc,horrid_match,test_bitstr,test_bit_size,
+ asymmetric_tests,big_asymmetric_tests,
+ binary_to_and_from_list,big_binary_to_and_from_list,
+ send_and_receive,send_and_receive_alot]}].
+
init_per_suite(Config) ->
Config.
diff --git a/lib/compiler/test/bs_construct_SUITE.erl b/lib/compiler/test/bs_construct_SUITE.erl
index 9ab76449c7..4ea5235bb6 100644
--- a/lib/compiler/test/bs_construct_SUITE.erl
+++ b/lib/compiler/test/bs_construct_SUITE.erl
@@ -36,12 +36,14 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [two, test1, fail, float_bin, in_guard, in_catch,
- nasty_literals, side_effect, opt, otp_7556, float_arith,
- otp_8054].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [two,test1,fail,float_bin,in_guard,in_catch,
+ nasty_literals,side_effect,opt,otp_7556,float_arith,
+ otp_8054]}].
+
init_per_suite(Config) ->
Config.
@@ -360,6 +362,11 @@ in_catch(Config) when is_list(Config) ->
?line <<255>> = small(255, <<1,2,3,4,5,6,7,8,9>>),
?line <<1,2>> = small(<<7,8,9,10>>, 258),
?line <<>> = small(<<1,2,3,4,5>>, <<7,8,9,10>>),
+
+ <<15,240,0,42>> = small2(255, 42),
+ <<7:20>> = small2(<<1,2,3>>, 7),
+ <<300:12>> = small2(300, <<1,2,3>>),
+ <<>> = small2(<<1>>, <<2>>),
ok.
small(A, B) ->
@@ -381,6 +388,25 @@ small(A, B) ->
end,
<<ResA/binary,ResB/binary>>.
+small2(A, B) ->
+ case begin
+ case catch <<A:12>> of
+ {'EXIT',_} -> <<>>;
+ ResA0 -> ResA0
+ end
+ end of
+ ResA -> ok
+ end,
+ case begin
+ case catch <<B:20>> of
+ {'EXIT',_} -> <<>>;
+ ResB0 -> ResB0
+ end
+ end of
+ ResB -> ok
+ end,
+ <<ResA/binary-unit:1,ResB/binary-unit:1>>.
+
nasty_literals(Config) when is_list(Config) ->
case erlang:system_info(endian) of
big ->
diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl
index 86c8cb23f5..9f15845d33 100644
--- a/lib/compiler/test/bs_match_SUITE.erl
+++ b/lib/compiler/test/bs_match_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -33,7 +33,8 @@
matching_meets_construction/1,simon/1,matching_and_andalso/1,
otp_7188/1,otp_7233/1,otp_7240/1,otp_7498/1,
match_string/1,zero_width/1,bad_size/1,haystack/1,
- cover_beam_bool/1]).
+ cover_beam_bool/1,matched_out_size/1,follow_fail_branch/1,
+ no_partition/1]).
-export([coverage_id/1,coverage_external_ignore/2]).
@@ -44,19 +45,22 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [fun_shadow, int_float, otp_5269, null_fields, wiger,
- bin_tail, save_restore, shadowed_size_var,
- partitioned_bs_match, function_clause, unit,
- shared_sub_bins, bin_and_float, dec_subidentifiers,
- skip_optional_tag, wfbm, degenerated_match, bs_sum,
- coverage, multiple_uses, zero_label, followed_by_catch,
- matching_meets_construction, simon,
- matching_and_andalso, otp_7188, otp_7233, otp_7240,
- otp_7498, match_string, zero_width, bad_size, haystack,
- cover_beam_bool].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [fun_shadow,int_float,otp_5269,null_fields,wiger,
+ bin_tail,save_restore,shadowed_size_var,
+ partitioned_bs_match,function_clause,unit,
+ shared_sub_bins,bin_and_float,dec_subidentifiers,
+ skip_optional_tag,wfbm,degenerated_match,bs_sum,
+ coverage,multiple_uses,zero_label,followed_by_catch,
+ matching_meets_construction,simon,
+ matching_and_andalso,otp_7188,otp_7233,otp_7240,
+ otp_7498,match_string,zero_width,bad_size,haystack,
+ cover_beam_bool,matched_out_size,follow_fail_branch,
+ no_partition]}].
+
init_per_suite(Config) ->
Config.
@@ -1079,6 +1083,101 @@ do_cover_beam_bool(Bin, X) when X > 0 ->
do_cover_beam_bool(<<_,Bin/binary>>, X) ->
do_cover_beam_bool(Bin, X+1).
+matched_out_size(Config) when is_list(Config) ->
+ {253,16#DEADBEEF} = mos_int(<<8,253,16#DEADBEEF:32>>),
+ {6,16#BEEFDEAD} = mos_int(<<3,6:3,16#BEEFDEAD:32>>),
+ {53,16#CAFEDEADBEEFCAFE} = mos_int(<<16,53:16,16#CAFEDEADBEEFCAFE:64>>),
+ {23,16#CAFEDEADBEEFCAFE} = mos_int(<<5,23:5,16#CAFEDEADBEEFCAFE:64>>),
+
+ {<<1,2,3>>,4} = mos_bin(<<3,1,2,3,4,3>>),
+ {<<1,2,3,7>>,19,42} = mos_bin(<<4,1,2,3,7,19,4,42>>),
+ <<1,2,3,7>> = mos_bin(<<4,1,2,3,7,"abcdefghij">>),
+
+ ok.
+
+mos_int(<<L,I:L,X:32>>) ->
+ {I,X};
+mos_int(<<L,I:L,X:64>>) ->
+ {I,X}.
+
+mos_bin(<<L,Bin:L/binary,X:8,L>>) ->
+ L = byte_size(Bin),
+ {Bin,X};
+mos_bin(<<L,Bin:L/binary,X:8,L,Y:8>>) ->
+ L = byte_size(Bin),
+ {Bin,X,Y};
+mos_bin(<<L,Bin:L/binary,"abcdefghij">>) ->
+ L = byte_size(Bin),
+ Bin.
+
+follow_fail_branch(_) ->
+ 42 = ffb_1(<<0,1>>, <<0>>),
+ 8 = ffb_1(<<0,1>>, [a]),
+ 42 = ffb_2(<<0,1>>, <<0>>, 17),
+ 8 = ffb_2(<<0,1>>, [a], 0),
+ ok.
+
+ffb_1(<<_,T/bitstring>>, List) ->
+ case List of
+ <<_>> ->
+ 42;
+ [_|_] ->
+ %% The fail branch of the bs_start_match2 instruction
+ %% pointing to here would be ignored, making the compiler
+ %% incorrectly assume that the delayed sub-binary
+ %% optimization was safe.
+ bit_size(T)
+ end.
+
+ffb_2(<<_,T/bitstring>>, List, A) ->
+ case List of
+ <<_>> when A =:= 17 -> 42;
+ [_|_] -> bit_size(T)
+ end.
+
+no_partition(_) ->
+ one = no_partition_1(<<"string">>, a1),
+ {two,<<"string">>} = no_partition_1(<<"string">>, a2),
+ {two,<<>>} = no_partition_1(<<>>, a2),
+ {two,a} = no_partition_1(a, a2),
+ three = no_partition_1(undefined, a3),
+ {four,a,[]} = no_partition_1([a], a4),
+ {five,a,b} = no_partition_1({a,b}, a5),
+
+ one = no_partition_2(<<"string">>, a1),
+ two = no_partition_2(<<"string">>, a2),
+ two = no_partition_2(<<>>, a2),
+ two = no_partition_2(a, a2),
+ three = no_partition_2(undefined, a3),
+ four = no_partition_2(42, a4),
+ five = no_partition_2([], a5),
+ six = no_partition_2(42.0, a6),
+ ok.
+
+no_partition_1(<<"string">>, a1) ->
+ one;
+no_partition_1(V, a2) ->
+ {two,V};
+no_partition_1(undefined, a3) ->
+ three;
+no_partition_1([H|T], a4) ->
+ {four,H,T};
+no_partition_1({A,B}, a5) ->
+ {five,A,B}.
+
+no_partition_2(<<"string">>, a1) ->
+ one;
+no_partition_2(_, a2) ->
+ two;
+no_partition_2(undefined, a3) ->
+ three;
+no_partition_2(42, a4) ->
+ four;
+no_partition_2([], a5) ->
+ five;
+no_partition_2(42.0, a6) ->
+ six.
+
check(F, R) ->
R = F().
diff --git a/lib/compiler/test/compilation_SUITE.erl b/lib/compiler/test/compilation_SUITE.erl
index fed7bec7d4..8e7b7292cc 100644
--- a/lib/compiler/test/compilation_SUITE.erl
+++ b/lib/compiler/test/compilation_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -28,26 +28,30 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [self_compile_old_inliner, self_compile, compiler_1,
- compiler_3, compiler_5, beam_compiler_1,
- beam_compiler_2, beam_compiler_3, beam_compiler_4,
- beam_compiler_5, beam_compiler_6, beam_compiler_7,
- beam_compiler_8, beam_compiler_9, beam_compiler_10,
- beam_compiler_11, beam_compiler_12,
- nested_tuples_in_case_expr, otp_2330, guards,
- {group, vsn}, otp_2380, otp_2141, otp_2173, otp_4790,
- const_list_256, bin_syntax_1, bin_syntax_2,
- bin_syntax_3, bin_syntax_4, bin_syntax_5, bin_syntax_6,
- live_var, convopts, bad_functional_value,
- catch_in_catch, redundant_case, long_string, otp_5076,
- complex_guard, otp_5092, otp_5151, otp_5235, otp_5244,
- trycatch_4, opt_crash, otp_5404, otp_5436, otp_5481,
- otp_5553, otp_5632, otp_5714, otp_5872, otp_6121,
- otp_6121a, otp_6121b, otp_7202, otp_7345, on_load,
- string_table,otp_8949_a,otp_8949_a,split_cases].
+ [self_compile_old_inliner,self_compile,
+ {group,p}].
groups() ->
- [{vsn, [], [vsn_1, vsn_2, vsn_3]}].
+ [{vsn,[parallel],[vsn_1,vsn_2,vsn_3]},
+ {p,test_lib:parallel(),
+ [compiler_1,
+ compiler_3,compiler_5,beam_compiler_1,
+ beam_compiler_2,beam_compiler_3,beam_compiler_4,
+ beam_compiler_5,beam_compiler_6,beam_compiler_7,
+ beam_compiler_8,beam_compiler_9,beam_compiler_10,
+ beam_compiler_11,beam_compiler_12,
+ nested_tuples_in_case_expr,otp_2330,guards,
+ {group,vsn},otp_2380,otp_2141,otp_2173,otp_4790,
+ const_list_256,bin_syntax_1,bin_syntax_2,
+ bin_syntax_3,bin_syntax_4,bin_syntax_5,bin_syntax_6,
+ live_var,convopts,
+ catch_in_catch,redundant_case,long_string,otp_5076,
+ complex_guard,otp_5092,otp_5151,otp_5235,otp_5244,
+ trycatch_4,opt_crash,otp_5404,otp_5436,otp_5481,
+ otp_5553,otp_5632,otp_5714,otp_5872,otp_6121,
+ otp_6121a,otp_6121b,otp_7202,otp_7345,on_load,
+ string_table,otp_8949_a,otp_8949_a,split_cases,
+ beam_utils_liveopt]}].
init_per_suite(Config) ->
Config.
@@ -140,7 +144,6 @@ split({int, N}, <<N:16,B:N/binary,T/binary>>) ->
?comp(live_var).
?comp(trycatch_4).
-?comp(bad_functional_value).
?comp(catch_in_catch).
@@ -623,7 +626,7 @@ string_table(Config) when is_list(Config) ->
?line File = filename:join(DataDir, "string_table.erl"),
?line {ok,string_table,Beam,[]} = compile:file(File, [return, binary]),
?line {ok,{string_table,[StringTableChunk]}} = beam_lib:chunks(Beam, ["StrT"]),
- ?line {"StrT", <<"stringabletringtable">>} = StringTableChunk,
+ ?line {"StrT", <<"stringtable">>} = StringTableChunk,
ok.
otp_8949_a(Config) when is_list(Config) ->
@@ -681,4 +684,21 @@ do_split_cases(A) ->
end,
Z.
+-record(alarmInfo, {type,cause,origin}).
+
+beam_utils_liveopt(Config) ->
+ F = beam_utils_liveopt_fun(42, pebkac, user),
+ void = F(42, #alarmInfo{type=sctp,cause=pebkac,origin=user}),
+ ok.
+
+beam_utils_liveopt_fun(Peer, Cause, Origin) ->
+ fun(PeerNo, AlarmInfo)
+ when PeerNo == Peer andalso
+ AlarmInfo == #alarmInfo{type=sctp,
+ cause=Cause,
+ origin=Origin} ->
+ void
+ end.
+
+
id(I) -> I.
diff --git a/lib/compiler/test/compilation_SUITE_data/bad_functional_value.erl b/lib/compiler/test/compilation_SUITE_data/bad_functional_value.erl
deleted file mode 100644
index 126a573e83..0000000000
--- a/lib/compiler/test/compilation_SUITE_data/bad_functional_value.erl
+++ /dev/null
@@ -1,28 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(bad_functional_value).
-
--export([?MODULE/0,a/0]).
-
-?MODULE() ->
- ok.
-
-a() ->
- .list_to_atom("ok").
-
diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl
index 2cd75944f4..229e5a98a1 100644
--- a/lib/compiler/test/compile_SUITE.erl
+++ b/lib/compiler/test/compile_SUITE.erl
@@ -27,7 +27,7 @@
app_test/1,
file_1/1, forms_2/1, module_mismatch/1, big_file/1, outdir/1,
binary/1, makedep/1, cond_and_ifdef/1, listings/1, listings_big/1,
- other_output/1, package_forms/1, encrypted_abstr/1,
+ other_output/1, encrypted_abstr/1,
bad_record_use1/1, bad_record_use2/1, strict_record/1,
missing_testheap/1, cover/1, env/1, core/1, asm/1,
sys_pre_attributes/1]).
@@ -44,7 +44,7 @@ all() ->
test_lib:recompile(?MODULE),
[app_test, file_1, forms_2, module_mismatch, big_file, outdir,
binary, makedep, cond_and_ifdef, listings, listings_big,
- other_output, package_forms, encrypted_abstr,
+ other_output, encrypted_abstr,
{group, bad_record_use}, strict_record,
missing_testheap, cover, env, core, asm,
sys_pre_attributes].
@@ -410,32 +410,6 @@ other_output(Config) when is_list(Config) ->
?line test_server:timetrap_cancel(Dog),
ok.
-package_forms(Config) when is_list(Config) ->
- Fs = [{attribute,1,file,{"./p.erl",1}},
- {attribute,1,module,[p,p]},
- {attribute,3,compile,export_all},
- {attribute,1,file,
- {"/clearcase/otp/erts/lib/stdlib/include/qlc.hrl",1}},
- {attribute,6,file,{"./p.erl",6}},
- {function,7,q,0,
- [{clause,7,[],[],
- [{call,8,
- {remote,8,{atom,8,qlc},{atom,8,q}},
- [{tuple,-8,
- [{atom,-8,qlc_lc},
- {'fun',-8,
- {clauses,
- [{clause,-8,[],[],
- [{tuple,-8,
- [{atom,-8,simple_v1},
- {atom,-8,'X'},
- {'fun',-8,{clauses,[{clause,-8,[],[],[{nil,8}]}]}},
- {integer,-8,8}]}]}]}},
- {atom,-8,undefined}]}]}]}]},
- {eof,9}],
- {ok,'p.p',_} = compile:forms(Fs, ['S',report]),
- ok.
-
encrypted_abstr(Config) when is_list(Config) ->
?line Dog = test_server:timetrap(test_server:minutes(10)),
?line {Simple,Target} = files(Config, "encrypted_abstr"),
diff --git a/lib/compiler/test/core_SUITE.erl b/lib/compiler/test/core_SUITE.erl
index 06185bfc34..a40dc32d59 100644
--- a/lib/compiler/test/core_SUITE.erl
+++ b/lib/compiler/test/core_SUITE.erl
@@ -43,11 +43,13 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [dehydrated_itracer,nested_tries,seq_in_guard,make_effect_seq,
- eval_is_boolean,unsafe_case,nomatch_shadow,reversed_annos].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [dehydrated_itracer,nested_tries,seq_in_guard,make_effect_seq,
+ eval_is_boolean,unsafe_case,nomatch_shadow,reversed_annos]}].
+
init_per_suite(Config) ->
Config.
diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl
index 54bd52947e..abc9ab6a72 100644
--- a/lib/compiler/test/core_fold_SUITE.erl
+++ b/lib/compiler/test/core_fold_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -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,
t_element/1,setelement/1,t_length/1,append/1,t_apply/1,bifs/1,
- eq/1,nested_call_in_case/1,guard_try_catch/1,coverage/1]).
+ eq/1,nested_call_in_case/1,guard_try_catch/1,coverage/1,
+ unused_multiple_values_error/1,unused_multiple_values/1]).
-export([foo/0,foo/1,foo/2,foo/3]).
@@ -31,11 +32,14 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [t_element, setelement, t_length, append, t_apply, bifs,
- eq, nested_call_in_case, guard_try_catch, coverage].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [t_element,setelement,t_length,append,t_apply,bifs,
+ eq,nested_call_in_case,guard_try_catch,coverage,
+ unused_multiple_values_error,unused_multiple_values]}].
+
init_per_suite(Config) ->
Config.
@@ -67,6 +71,9 @@ t_element(Config) when is_list(Config) ->
?line {'EXIT',{badarg,_}} = (catch element(5, {a,b,c,d})),
?line {'EXIT',{badarg,_}} = (catch element(5, {a,b,X,d})),
?line {'EXIT',{badarg,_}} = (catch element(5.0, {a,b,X,d})),
+ {'EXIT',{badarg,_}} = (catch element(2, not_a_tuple)),
+ {'EXIT',{badarg,_}} = (catch element(2, [])),
+ {'EXIT',{badarg,_}} = (catch element(2, Tuple == 3)),
case id({a,b,c}) of
{_,_,_}=Tup ->
?line {'EXIT',{badarg,_}} = (catch element(4, Tup))
@@ -87,6 +94,9 @@ setelement(Config) when is_list(Config) ->
?line {'EXIT',{badarg,_}} = (catch setelement_crash({a,b,c,d,e,f})),
?line error = setelement_crash_2({a,b,c,d,e,f}, <<42>>),
+
+ {'EXIT',{badarg,_}} = (catch setelement(1, not_a_tuple, New)),
+
ok.
setelement_crash(Tuple) ->
@@ -281,3 +291,41 @@ cover_is_safe_bool_expr(X) ->
end.
id(I) -> I.
+
+unused_multiple_values_error(Config) when is_list(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ Dir = filename:dirname(code:which(?MODULE)),
+ Core = filename:join(Dir, "unused_multiple_values_error"),
+ Opts = [no_copt,clint,return,from_core,{outdir,PrivDir}
+ |test_lib:opt_opts(?MODULE)],
+ {error,[{unused_multiple_values_error,
+ [{core_lint,{return_mismatch,{hello,1}}}]}],
+ []} = c:c(Core, Opts),
+ ok.
+
+unused_multiple_values(Config) when is_list(Config) ->
+ put(unused_multiple_values, []),
+ [false] = test_unused_multiple_values(false),
+ [b,a,{a,b},false] = test_unused_multiple_values({a,b}),
+ ok.
+
+test_unused_multiple_values(X) ->
+ ok = do_unused_multiple_values(X),
+ get(unused_multiple_values).
+
+do_unused_multiple_values(X) ->
+ case do_something(X) of
+ false ->
+ A = false;
+ Res ->
+ {A,B} = Res,
+ do_something(A),
+ do_something(B)
+ end,
+ _ThisShouldNotFail = A,
+ ok.
+
+do_something(I) ->
+ put(unused_multiple_values,
+ [I|get(unused_multiple_values)]),
+ I.
diff --git a/lib/compiler/test/error_SUITE.erl b/lib/compiler/test/error_SUITE.erl
index fb51e013ce..859c4571ea 100644
--- a/lib/compiler/test/error_SUITE.erl
+++ b/lib/compiler/test/error_SUITE.erl
@@ -22,16 +22,21 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
- head_mismatch_line/1,warnings_as_errors/1, bif_clashes/1]).
+ head_mismatch_line/1,warnings_as_errors/1, bif_clashes/1,
+ transforms/1]).
+
+%% Used by transforms/1 test case.
+-export([parse_transform/2]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [head_mismatch_line, warnings_as_errors, bif_clashes].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [head_mismatch_line,warnings_as_errors,bif_clashes,transforms]}].
init_per_suite(Config) ->
Config.
@@ -216,6 +221,24 @@ warnings_as_errors(Config) when is_list(Config) ->
ok.
+transforms(Config) ->
+ Ts1 = [{undef_parse_transform,
+ <<"
+ -compile({parse_transform,non_existing}).
+ ">>,
+ [return],
+ {error,[{none,compile,{undef_parse_transform,non_existing}}],[]}}],
+ [] = run(Config, Ts1),
+ Ts2 = <<"
+ -compile({parse_transform,",?MODULE_STRING,"}).
+ ">>,
+ {error,[{none,compile,{parse_transform,?MODULE,{too_bad,_}}}],[]} =
+ run_test(Ts2, test_filename(Config), [], dont_write_beam),
+ ok.
+
+parse_transform(_, _) ->
+ error(too_bad).
+
run(Config, Tests) ->
?line File = test_filename(Config),
@@ -260,12 +283,14 @@ filter(X) ->
%% Compiles a test module and returns the list of errors and warnings.
test_filename(Conf) ->
- Filename = "errors_test.erl",
+ Filename = ["errors_test_",test_lib:uniq(),".erl"],
DataDir = ?config(priv_dir, Conf),
filename:join(DataDir, Filename).
run_test(Test0, File, Warnings, WriteBeam) ->
- ?line Test = ["-module(errors_test). ", Test0],
+ ModName = filename:rootname(filename:basename(File), ".erl"),
+ Mod = list_to_atom(ModName),
+ Test = ["-module(",ModName,"). ",Test0],
?line Opts = case WriteBeam of
dont_write_beam ->
[binary,return_errors|Warnings];
@@ -279,17 +304,17 @@ run_test(Test0, File, Warnings, WriteBeam) ->
%% Test result of compilation.
?line Res = case compile:file(File, Opts) of
- {ok,errors_test,_,[{_File,Ws}]} ->
+ {ok,Mod,_,[{_File,Ws}]} ->
%io:format("compile:file(~s,~p) ->~n~p~n",
% [File,Opts,Ws]),
{warning,Ws};
- {ok,errors_test,_,[]} ->
+ {ok,Mod,_,[]} ->
%io:format("compile:file(~s,~p) ->~n~p~n",
% [File,Opts,Ws]),
[];
- {ok,errors_test,[{_File,Ws}]} ->
+ {ok,Mod,[{_File,Ws}]} ->
{warning,Ws};
- {ok,errors_test,[]} ->
+ {ok,Mod,[]} ->
[];
{error,[{XFile,Es}],Ws} = _ZZ when is_list(XFile) ->
%io:format("compile:file(~s,~p) ->~n~p~n",
diff --git a/lib/compiler/test/guard_SUITE.erl b/lib/compiler/test/guard_SUITE.erl
index 40711783ed..5656d23090 100644
--- a/lib/compiler/test/guard_SUITE.erl
+++ b/lib/compiler/test/guard_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -39,17 +39,18 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [misc, const_cond, basic_not, complex_not, nested_nots,
- semicolon, complex_semicolon, comma, or_guard,
- more_or_guards, complex_or_guards, and_guard, xor_guard,
- more_xor_guards, build_in_guard, old_guard_tests, gbif,
- t_is_boolean, is_function_2, tricky, rel_ops,
- literal_type_tests, basic_andalso_orelse, traverse_dcd,
- check_qlc_hrl, andalso_semi, t_tuple_size, binary_part,
- bad_constants].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [misc,const_cond,basic_not,complex_not,nested_nots,
+ semicolon,complex_semicolon,comma,or_guard,
+ more_or_guards,complex_or_guards,and_guard,xor_guard,
+ more_xor_guards,build_in_guard,old_guard_tests,gbif,
+ t_is_boolean,is_function_2,tricky,rel_ops,
+ literal_type_tests,basic_andalso_orelse,traverse_dcd,
+ check_qlc_hrl,andalso_semi,t_tuple_size,binary_part,
+ bad_constants]}].
init_per_suite(Config) ->
Config.
diff --git a/lib/compiler/test/inline_SUITE.erl b/lib/compiler/test/inline_SUITE.erl
index 2e17d3fde6..d9b92766e4 100644
--- a/lib/compiler/test/inline_SUITE.erl
+++ b/lib/compiler/test/inline_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -32,17 +32,22 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [attribute, bsdecode, bsdes, barnes2, decode1, smith,
- itracer, pseudoknot, comma_splitter, lists, really_inlined, otp_7223,
- coverage].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [attribute,bsdecode,bsdes,barnes2,decode1,smith,
+ itracer,pseudoknot,comma_splitter,lists,really_inlined,otp_7223,
+ coverage]}].
init_per_suite(Config) ->
- Config.
+ Pa = "-pa " ++ filename:dirname(code:which(?MODULE)),
+ {ok,Node} = start_node(compiler, Pa),
+ [{testing_node,Node}|Config].
-end_per_suite(_Config) ->
+end_per_suite(Config) ->
+ Node = ?config(testing_node, Config),
+ ?t:stop_node(Node),
ok.
init_per_group(_GroupName, Config) ->
@@ -81,6 +86,7 @@ attribute(Config) when is_list(Config) ->
?comp(comma_splitter).
try_inline(Mod, Config) ->
+ Node = ?config(testing_node, Config),
?line Src = filename:join(?config(data_dir, Config), atom_to_list(Mod)),
?line Out = ?config(priv_dir,Config),
@@ -89,8 +95,6 @@ try_inline(Mod, Config) ->
?line {ok,Mod} = compile:file(Src, [{outdir,Out},report,bin_opt_info,clint]),
?line Dog = test_server:timetrap(test_server:minutes(10)),
- ?line Pa = "-pa " ++ filename:dirname(code:which(?MODULE)),
- ?line {ok,Node} = start_node(compiler, Pa),
?line NormalResult = rpc:call(Node, ?MODULE, load_and_call, [Out,Mod]),
?line test_server:timetrap_cancel(Dog),
@@ -125,7 +129,6 @@ try_inline(Mod, Config) ->
%% Delete Beam file.
?line ok = file:delete(filename:join(Out, atom_to_list(Mod)++code:objfile_extension())),
- ?line ?t:stop_node(Node),
ok.
compare(Same, Same) -> ok;
@@ -255,6 +258,49 @@ lists(Config) when is_list(Config) ->
%% Cleanup.
erase(?MODULE),
+
+ {'EXIT',{function_clause,[{?MODULE,_,[_,not_a_list],_}|_]}} =
+ (catch lists:map(fun (X) -> X end, not_a_list)),
+ {'EXIT',{function_clause,[{?MODULE,_,[_,not_a_list],_}|_]}} =
+ (catch lists:flatmap(fun (X) -> X end, not_a_list)),
+ {'EXIT',{function_clause,[{?MODULE,_,[_,not_a_list],_}|_]}} =
+ (catch lists:foreach(fun (X) -> X end, not_a_list)),
+ {'EXIT',{function_clause,[{?MODULE,_,[_,not_a_list],_}|_]}} =
+ (catch lists:filter(fun (_) -> true end, not_a_list)),
+ {'EXIT',{function_clause,[{?MODULE,_,[_,not_a_list],_}|_]}} =
+ (catch lists:any(fun (_) -> false end, not_a_list)),
+ {'EXIT',{function_clause,[{?MODULE,_,[_,not_a_list],_}|_]}} =
+ (catch lists:all(fun (_) -> true end, not_a_list)),
+ {'EXIT',{function_clause,[{?MODULE,_,[_,acc,not_a_list],_}|_]}} =
+ (catch lists:foldl(fun (X, Acc) -> {X,Acc} end, acc, not_a_list)),
+ {'EXIT',{function_clause,[{?MODULE,_,[_,acc,not_a_list],_}|_]}} =
+ (catch lists:foldr(fun (X, Acc) -> {X,Acc} end, acc, not_a_list)),
+ {'EXIT',{function_clause,[{?MODULE,_,[_,acc,not_a_list],_}|_]}} =
+ (catch lists:mapfoldl(fun (X, Acc) -> {X,Acc} end, acc, not_a_list)),
+ {'EXIT',{function_clause,[{?MODULE,_,[_,acc,not_a_list],_}|_]}} =
+ (catch lists:mapfoldr(fun (X, Acc) -> {X,Acc} end, acc, not_a_list)),
+
+ {'EXIT',{function_clause,[{?MODULE,_,[not_a_function,[]],_}|_]}} =
+ (catch lists:map(not_a_function, [])),
+ {'EXIT',{function_clause,[{?MODULE,_,[not_a_function,[]],_}|_]}} =
+ (catch lists:flatmap(not_a_function, [])),
+ {'EXIT',{function_clause,[{?MODULE,_,[not_a_function,[]],_}|_]}} =
+ (catch lists:foreach(not_a_function, [])),
+ {'EXIT',{function_clause,[{?MODULE,_,[not_a_function,[]],_}|_]}} =
+ (catch lists:filter(not_a_function, [])),
+ {'EXIT',{function_clause,[{?MODULE,_,[not_a_function,[]],_}|_]}} =
+ (catch lists:any(not_a_function, [])),
+ {'EXIT',{function_clause,[{?MODULE,_,[not_a_function,[]],_}|_]}} =
+ (catch lists:all(not_a_function, [])),
+ {'EXIT',{function_clause,[{?MODULE,_,[not_a_function,acc,[]],_}|_]}} =
+ (catch lists:foldl(not_a_function, acc, [])),
+ {'EXIT',{function_clause,[{?MODULE,_,[not_a_function,acc,[]],_}|_]}} =
+ (catch lists:foldr(not_a_function, acc, [])),
+ {'EXIT',{function_clause,[{?MODULE,_,[not_a_function,acc,[]],_}|_]}} =
+ (catch lists:mapfoldl(not_a_function, acc, [])),
+ {'EXIT',{function_clause,[{?MODULE,_,[not_a_function,acc,[]],_}|_]}} =
+ (catch lists:mapfoldr(not_a_function, acc, [])),
+
ok.
my_apply(M, F, A, Init) ->
@@ -293,9 +339,9 @@ otp_7223_2({a}) ->
1.
coverage(Config) when is_list(Config) ->
- ?line Src = filename:join(?config(data_dir, Config), bsdecode),
- ?line Out = ?config(priv_dir,Config),
- ?line {ok,Mod} = compile:file(Src, [{outdir,Out},report,{inline,0},clint]),
- ?line {ok,Mod} = compile:file(Src, [{outdir,Out},report,{inline,20},verbose,clint]),
- ?line ok = file:delete(filename:join(Out, "bsdecode"++code:objfile_extension())),
+ Mod = bsdecode,
+ Src = filename:join(?config(data_dir, Config), Mod),
+ {ok,Mod,_} = compile:file(Src, [binary,report,{inline,0},clint]),
+ {ok,Mod,_} = compile:file(Src, [binary,report,{inline,20},
+ verbose,clint]),
ok.
diff --git a/lib/compiler/test/match_SUITE.erl b/lib/compiler/test/match_SUITE.erl
index 9406d7de8f..ae7d764535 100644
--- a/lib/compiler/test/match_SUITE.erl
+++ b/lib/compiler/test/match_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -30,11 +30,13 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [pmatch, mixed, aliases, match_in_call, untuplify,
- shortcut_boolean, letify_guard, selectify, underscore, coverage].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [pmatch,mixed,aliases,match_in_call,untuplify,
+ shortcut_boolean,letify_guard,selectify,underscore,coverage]}].
+
init_per_suite(Config) ->
Config.
diff --git a/lib/compiler/test/misc_SUITE.erl b/lib/compiler/test/misc_SUITE.erl
index 0376c7ef3e..44c7161530 100644
--- a/lib/compiler/test/misc_SUITE.erl
+++ b/lib/compiler/test/misc_SUITE.erl
@@ -57,11 +57,12 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
-spec all() -> misc_SUITE_test_cases().
all() ->
test_lib:recompile(?MODULE),
- [tobias, empty_string, md5, silly_coverage,
- confused_literals, integer_encoding, override_bif].
+ [{group,p}].
groups() ->
- [].
+ [{p,[],%%test_lib:parallel(),
+ [tobias,empty_string,md5,silly_coverage,
+ confused_literals,integer_encoding,override_bif]}].
init_per_suite(Config) ->
Config.
@@ -182,6 +183,14 @@ silly_coverage(Config) when is_list(Config) ->
CodegenInput = {?MODULE,[{foo,0}],[],[{function,foo,0,[a|b],a,b,[]}]},
?line expect_error(fun() -> v3_codegen:module(CodegenInput, []) end),
+ %% beam_a
+ BeamAInput = {?MODULE,[{foo,0}],[],
+ [{function,foo,0,2,
+ [{label,1},
+ {func_info,{atom,?MODULE},{atom,foo},0},
+ {label,2}|non_proper_list]}],99},
+ expect_error(fun() -> beam_a:module(BeamAInput, []) end),
+
%% beam_block
BlockInput = {?MODULE,[{foo,0}],[],
[{function,foo,0,2,
@@ -263,6 +272,13 @@ silly_coverage(Config) when is_list(Config) ->
{block,[a|b]}]}],0},
?line expect_error(fun() -> beam_receive:module(ReceiveInput, []) end),
+ BeamZInput = {?MODULE,[{foo,0}],[],
+ [{function,foo,0,2,
+ [{label,1},
+ {func_info,{atom,?MODULE},{atom,foo},0},
+ {label,2}|non_proper_list]}],99},
+ expect_error(fun() -> beam_z:module(BeamZInput, []) end),
+
ok.
expect_error(Fun) ->
diff --git a/lib/compiler/test/pmod_SUITE.erl b/lib/compiler/test/pmod_SUITE.erl
deleted file mode 100644
index 5dd09a7245..0000000000
--- a/lib/compiler/test/pmod_SUITE.erl
+++ /dev/null
@@ -1,121 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(pmod_SUITE).
-
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2,
- init_per_testcase/2,end_per_testcase/2,
- basic/1, otp_8447/1]).
-
--include_lib("test_server/include/test_server.hrl").
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- test_lib:recompile(?MODULE),
- [basic, otp_8447].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
- Dog = test_server:timetrap(?t:minutes(1)),
- [{watchdog,Dog}|Config].
-
-end_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
- Dog = ?config(watchdog, Config),
- ?t:timetrap_cancel(Dog),
- ok.
-
-basic(Config) when is_list(Config) ->
- ?line basic_1(Config, []),
- ?line basic_1(Config, [inline]),
- ?line basic_1(Config, [{inline,500},inline]),
- ok.
-
-basic_1(Config, Opts) ->
- io:format("Options: ~p\n", [Opts]),
- ?line ok = compile_load(pmod_basic, Config, Opts),
-
- ?line Prop1 = pmod_basic:new([{a,xb},{b,true},{c,false}]),
- ?line Prop2 = pmod_basic:new([{y,zz}]),
- ?line io:format("Prop1 = ~p\n", [Prop1]),
- ?line io:format("Prop2 = ~p\n", [Prop2]),
-
- ?line {a,xb} = Prop1:lookup(a),
- ?line none = Prop1:lookup(glurf),
- ?line false = Prop1:or_props([]),
- ?line true = Prop1:or_props([b,c]),
- ?line true = Prop1:or_props([b,d]),
- ?line false = Prop1:or_props([d]),
-
- ?line none = Prop2:lookup(kalle),
- ?line {y,zz} = Prop2:lookup(y),
- ?line {a,xb} = Prop1:lookup(a),
-
- ?line Prop3 = Prop1:prepend({blurf,true}),
- ?line io:format("Prop3 = ~p\n", [Prop3]),
- ?line {blurf,true} = Prop3:lookup(blurf),
-
- Prop4 = Prop3:append(42),
- ?line io:format("Prop4 = ~p\n", [Prop4]),
- ?line {42,5} = Prop4:stupid_sum(),
-
- %% Some record guards.
- ?line ok = Prop4:bar({s,0}),
- ?line ok = Prop4:bar_bar({s,blurf}),
- ?line error = Prop4:bar_bar({s,a,b}),
- ?line error = Prop4:bar_bar([]),
-
- %% Call from a fun.
- Fun = fun(Arg) -> Prop4:bar(Arg) end,
- ?line ok = Fun({s,0}),
-
- [{y,[1,2]},{x,[5,19]}] = Prop4:collapse([{y,[2,1]},{x,[19,5]}]),
- ok.
-
-otp_8447(Config) when is_list(Config) ->
- ?line P = pmod_basic:new(foo),
- ?line [0,0,1,1,1,0,0,1] = P:bc1(),
- ?line <<10:4>> = P:bc2(),
- ok.
-
-compile_load(Module, Conf, Opts) ->
- ?line Dir = ?config(data_dir,Conf),
- ?line Src = filename:join(Dir, atom_to_list(Module)),
- ?line Out = ?config(priv_dir,Conf),
- ?line CompRc = compile:file(Src, [report,{outdir,Out}|Opts]),
- ?line {ok,Module} = CompRc,
- ?line code:purge(Module),
- ?line {module,Module} =
- code:load_abs(filename:join(Out, atom_to_list(Module))),
- ok.
diff --git a/lib/compiler/test/pmod_SUITE_data/pmod_basic.erl b/lib/compiler/test/pmod_SUITE_data/pmod_basic.erl
deleted file mode 100644
index 19cce452dc..0000000000
--- a/lib/compiler/test/pmod_SUITE_data/pmod_basic.erl
+++ /dev/null
@@ -1,83 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(pmod_basic, [Props]).
-
--export([lookup/1,or_props/1,prepend/1,append/1,stupid_sum/0]).
--export([bar/1,bar_bar/1]).
--export([bc1/0, bc2/0]).
--export([collapse/1]).
-
-lookup(Key) ->
- proplists:lookup(Key, Props).
-
-or_props(Keys) ->
- Res = or_props_1(Keys, false),
- true = is_bool(Res), %is_bool/1 does not use Props.
- Res.
-
-prepend(Term) ->
- new([Term|Props]).
-
-append(Term) ->
- pmod_basic:new(Props++[Term]).
-
-or_props_1([K|Ks], Acc) ->
- or_props_1(Ks, proplists:get_bool(K, Props) or Acc);
-or_props_1([], Acc) -> Acc.
-
-is_bool(true) -> true;
-is_bool(false) -> true;
-is_bool(_) -> false.
-
-stupid_sum() ->
- put(counter, 0),
- Res = stupid_sum_1(Props, 0),
- {Res,get(counter)}.
-
-stupid_sum_1([H|T], Sum0) ->
- try add(Sum0, H) of
- Sum -> stupid_sum_1(T, Sum)
- catch
- error:_ -> stupid_sum_1(T, Sum0)
- after
- bump()
- end;
-stupid_sum_1([], Sum) -> Sum.
-
-bump() ->
- put(counter, get(counter)+1).
-
-add(A, B) ->
- A+B.
-
--record(s, {a}).
-
-bar(S) when S#s.a == 0 -> ok.
-
-bar_bar(S) when is_record(S, s) -> ok;
-bar_bar(_) -> error.
-
-bc1() ->
- [A || <<A:1>> <= <<"9">> ].
-
-bc2() ->
- << <<A:1>> || A <- [1,0,1,0] >>.
-
-collapse(L) ->
- lists:keymap(fun lists:sort/1, 2, L).
diff --git a/lib/compiler/test/receive_SUITE.erl b/lib/compiler/test/receive_SUITE.erl
index 2a67615e5e..b91f2922fb 100644
--- a/lib/compiler/test/receive_SUITE.erl
+++ b/lib/compiler/test/receive_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -40,10 +40,12 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [recv, coverage, otp_7980, ref_opt, export].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [recv,coverage,otp_7980,ref_opt,export]}].
+
init_per_suite(Config) ->
Config.
diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/no_4.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/no_4.erl
new file mode 100644
index 0000000000..3ce222176b
--- /dev/null
+++ b/lib/compiler/test/receive_SUITE_data/ref_opt/no_4.erl
@@ -0,0 +1,12 @@
+-module(no_4).
+-compile(export_all).
+
+?MODULE() ->
+ ok.
+
+f(X) ->
+ {Pid,Ref} = spawn_monitor(fun() -> ok end),
+ r(Pid, Ref).
+
+r(_, _) ->
+ ok.
diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_10.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_10.erl
new file mode 100644
index 0000000000..7ce6e6103c
--- /dev/null
+++ b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_10.erl
@@ -0,0 +1,13 @@
+-module(yes_10).
+-compile(export_all).
+
+?MODULE() ->
+ ok.
+
+f() ->
+ Ref = make_ref(),
+ receive
+ %% Artifical example to cover more code in beam_receive.
+ {X,Y} when Ref =/= X, Ref =:= Y ->
+ ok
+ end.
diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_11.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_11.erl
new file mode 100644
index 0000000000..62f439fc42
--- /dev/null
+++ b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_11.erl
@@ -0,0 +1,21 @@
+-module(yes_11).
+-compile(export_all).
+
+?MODULE() ->
+ ok.
+
+%% Artifical example to cover more code in beam_receive.
+do_call(Process, Request) ->
+ Mref = erlang:monitor(process, Process),
+ Process ! Request,
+ receive
+ {X,Y,Z} when Mref =/= X, Z =:= 42, Mref =:= Y ->
+ error;
+ {X,Y,_} when Mref =/= X, Mref =:= Y ->
+ error;
+ {Mref, Reply} ->
+ erlang:demonitor(Mref, [flush]),
+ {ok, Reply};
+ {'DOWN', Mref, _, _, _} ->
+ error
+ end.
diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_12.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_12.erl
new file mode 100644
index 0000000000..efcfed6059
--- /dev/null
+++ b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_12.erl
@@ -0,0 +1,12 @@
+-module(yes_12).
+-compile(export_all).
+
+?MODULE() ->
+ ok.
+
+f() ->
+ {_,Ref} = spawn_monitor(fun() -> ok end),
+ receive
+ {'DOWN',Ref,_,_,Reason} ->
+ Reason
+ end.
diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_13.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_13.erl
new file mode 100644
index 0000000000..9e93d12ed6
--- /dev/null
+++ b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_13.erl
@@ -0,0 +1,12 @@
+-module(yes_13).
+-compile(export_all).
+
+?MODULE() ->
+ ok.
+
+f() ->
+ {Pid,Ref} = spawn_monitor(fun() -> ok end),
+ receive
+ {'DOWN',Ref,process,Pid,Reason} ->
+ Reason
+ end.
diff --git a/lib/compiler/test/record_SUITE.erl b/lib/compiler/test/record_SUITE.erl
index 363422ec7e..c9f5a2053e 100644
--- a/lib/compiler/test/record_SUITE.erl
+++ b/lib/compiler/test/record_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -42,12 +42,14 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [errors, record_test_2, record_test_3,
- record_access_in_guards, guard_opt, eval_once, foobar,
- missing_test_heap, nested_access, coverage].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [errors,record_test_2,record_test_3,
+ record_access_in_guards,guard_opt,eval_once,foobar,
+ missing_test_heap,nested_access,coverage]}].
+
init_per_suite(Config) ->
Config.
diff --git a/lib/compiler/test/test_lib.erl b/lib/compiler/test/test_lib.erl
index 2295592a38..a8befbecd9 100644
--- a/lib/compiler/test/test_lib.erl
+++ b/lib/compiler/test/test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -20,7 +20,8 @@
-include("test_server.hrl").
-compile({no_auto_import,[binary_part/2]}).
--export([recompile/1,opt_opts/1,get_data_dir/1,smoke_disasm/1,p_run/2,binary_part/2]).
+-export([recompile/1,parallel/0,uniq/0,opt_opts/1,get_data_dir/1,
+ smoke_disasm/1,p_run/2,binary_part/2]).
recompile(Mod) when is_atom(Mod) ->
case whereis(cover_server) of
@@ -43,6 +44,18 @@ smoke_disasm(File) when is_list(File) ->
Res = beam_disasm:file(File),
{beam_file,_Mod} = {element(1, Res),element(2, Res)}.
+parallel() ->
+ case ?t:is_cover() orelse erlang:system_info(schedulers) =:= 1 of
+ true -> [];
+ false -> [parallel]
+ end.
+
+uniq() ->
+ U0 = erlang:ref_to_list(make_ref()),
+ U1 = re:replace(U0, "^#Ref", ""),
+ U = re:replace(U1, "[^[A-Za-z0-9_]+", "_", [global]),
+ re:replace(U, "_*$", "", [{return,list}]).
+
%% Retrieve the "interesting" compiler options (options for optimization
%% and compatibility) for the given module.
diff --git a/lib/compiler/test/trycatch_SUITE.erl b/lib/compiler/test/trycatch_SUITE.erl
index 29119c0f5d..4530d08c77 100644
--- a/lib/compiler/test/trycatch_SUITE.erl
+++ b/lib/compiler/test/trycatch_SUITE.erl
@@ -32,13 +32,15 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [basic, lean_throw, try_of, try_after, catch_oops,
- after_oops, eclectic, rethrow, nested_of, nested_catch,
- nested_after, nested_horrid, last_call_optimization,
- bool, plain_catch_coverage, andalso_orelse, get_in_try].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [basic,lean_throw,try_of,try_after,catch_oops,
+ after_oops,eclectic,rethrow,nested_of,nested_catch,
+ nested_after,nested_horrid,last_call_optimization,
+ bool,plain_catch_coverage,andalso_orelse,get_in_try]}].
+
init_per_suite(Config) ->
Config.
diff --git a/lib/compiler/test/unused_multiple_values_error.core b/lib/compiler/test/unused_multiple_values_error.core
new file mode 100644
index 0000000000..e06587c936
--- /dev/null
+++ b/lib/compiler/test/unused_multiple_values_error.core
@@ -0,0 +1,11 @@
+module 'unused_multiple_values_error' ['hello'/1]
+ attributes []
+'hello'/1 =
+ fun (_cor0) ->
+ do
+ case _cor0 of
+ <_cor0> when 'true' ->
+ <'ok','ok'>
+ end
+ 'ok'
+end
diff --git a/lib/compiler/test/warnings_SUITE.erl b/lib/compiler/test/warnings_SUITE.erl
index f6a572abfa..f00bfe663b 100644
--- a/lib/compiler/test/warnings_SUITE.erl
+++ b/lib/compiler/test/warnings_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -55,12 +55,13 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [pattern, pattern2, pattern3, pattern4, guard,
- bad_arith, bool_cases, bad_apply, files, effect,
- bin_opt_info, bin_construction].
+ [{group,p}].
groups() ->
- [].
+ [{p,test_lib:parallel(),
+ [pattern,pattern2,pattern3,pattern4,guard,
+ bad_arith,bool_cases,bad_apply,files,effect,
+ bin_opt_info,bin_construction]}].
init_per_suite(Config) ->
Config.
@@ -556,9 +557,10 @@ run(Config, Tests) ->
%% Compiles a test module and returns the list of errors and warnings.
run_test(Conf, Test0, Warnings) ->
- Filename = 'warnings_test.erl',
+ Mod = "warnings_"++test_lib:uniq(),
+ Filename = Mod ++ ".erl",
?line DataDir = ?privdir,
- ?line Test = ["-module(warnings_test). ", Test0],
+ Test = ["-module(", Mod, "). ", Test0],
?line File = filename:join(DataDir, Filename),
?line Opts = [binary,export_all,return|Warnings],
?line ok = file:write_file(File, Test),
diff --git a/lib/compiler/vsn.mk b/lib/compiler/vsn.mk
index b77c82309f..90d2bff0ad 100644
--- a/lib/compiler/vsn.mk
+++ b/lib/compiler/vsn.mk
@@ -1 +1 @@
-COMPILER_VSN = 4.8.2
+COMPILER_VSN = 4.9.1