diff options
Diffstat (limited to 'lib/compiler')
-rw-r--r-- | lib/compiler/src/beam_block.erl | 35 | ||||
-rw-r--r-- | lib/compiler/src/cerl.erl | 6 | ||||
-rw-r--r-- | lib/compiler/src/core_lint.erl | 3 | ||||
-rw-r--r-- | lib/compiler/test/receive_SUITE.erl | 25 |
4 files changed, 49 insertions, 20 deletions
diff --git a/lib/compiler/src/beam_block.erl b/lib/compiler/src/beam_block.erl index 9c6f835ab0..c45874597a 100644 --- a/lib/compiler/src/beam_block.erl +++ b/lib/compiler/src/beam_block.erl @@ -36,12 +36,13 @@ function({function,Name,Arity,CLabel,Is0}, Lc0) -> %% Collect basic blocks and optimize them. Is2 = blockify(Is1), - Is3 = beam_utils:live_opt(Is2), - Is4 = opt_blocks(Is3), - Is5 = beam_utils:delete_live_annos(Is4), + 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(Is5, Lc0), + {Is,Lc} = bsm_opt(Is6, Lc0), %% Done. {{function,Name,Arity,CLabel,Is},Lc} @@ -156,11 +157,7 @@ opt_blocks([I|Is]) -> opt_blocks([]) -> []. opt_block(Is0) -> - %% We explicitly move any allocate instruction upwards before optimising - %% moves, to avoid any potential problems with the calculation of live - %% registers. - Is1 = move_allocates(Is0), - Is = find_fixpoint(fun opt/1, Is1), + Is = find_fixpoint(fun opt/1, Is0), opt_alloc(Is). find_fixpoint(OptFun, Is0) -> @@ -170,11 +167,21 @@ find_fixpoint(OptFun, Is0) -> end. %% move_allocates(Is0) -> Is -%% Move allocates upwards in the instruction stream, in the hope of -%% getting more possibilities for optimizing away moves later. - -move_allocates(Is) -> - move_allocates_1(reverse(Is), []). +%% Move allocate instructions upwards in the instruction stream, in the +%% hope of getting more possibilities for optimizing away moves later. +%% +%% NOTE: Moving allocation instructions is only safe because it is done +%% immediately after code generation so that we KNOW that if {x,X} is +%% initialized, all x registers with lower numbers are also initialized. +%% That assumption may not be true after other optimizations, such as +%% the beam_utils:live_opt/1 optimization. + +move_allocates([{block,Bl0}|Is]) -> + Bl = move_allocates_1(reverse(Bl0), []), + [{block,Bl}|move_allocates(Is)]; +move_allocates([I|Is]) -> + [I|move_allocates(Is)]; +move_allocates([]) -> []. move_allocates_1([{set,[],[],{alloc,_,_}=Alloc}|Is0], Acc0) -> {Is,Acc} = move_allocates_2(Alloc, Is0, Acc0), diff --git a/lib/compiler/src/cerl.erl b/lib/compiler/src/cerl.erl index d1fd9d40e2..4b74d60e9f 100644 --- a/lib/compiler/src/cerl.erl +++ b/lib/compiler/src/cerl.erl @@ -973,7 +973,7 @@ atom_name(Node) -> %% TODO: replace the use of the unofficial 'write_string/2'. --spec atom_lit(cerl()) -> string(). +-spec atom_lit(cerl()) -> nonempty_string(). atom_lit(Node) -> io_lib:write_string(atom_name(Node), $'). %' stupid Emacs. @@ -1079,7 +1079,7 @@ char_val(Node) -> %% %% @see c_char/1 --spec char_lit(c_literal()) -> string(). +-spec char_lit(c_literal()) -> nonempty_string(). char_lit(Node) -> io_lib:write_char(char_val(Node)). @@ -1178,7 +1178,7 @@ string_val(Node) -> %% %% @see c_string/1 --spec string_lit(c_literal()) -> string(). +-spec string_lit(c_literal()) -> nonempty_string(). string_lit(Node) -> io_lib:write_string(string_val(Node)). diff --git a/lib/compiler/src/core_lint.erl b/lib/compiler/src/core_lint.erl index 097577b371..b513a8965c 100644 --- a/lib/compiler/src/core_lint.erl +++ b/lib/compiler/src/core_lint.erl @@ -65,7 +65,8 @@ | {'return_mismatch', fa()} | {'undefined_function', fa()} | {'duplicate_var', cerl:var_name(), fa()} | {'unbound_var', cerl:var_name(), fa()} - | {'undefined_function', fa(), fa()}. + | {'undefined_function', fa(), fa()} + | {'tail_segment_not_at_end', fa()}. -type error() :: {module(), err_desc()}. -type warning() :: {module(), term()}. diff --git a/lib/compiler/test/receive_SUITE.erl b/lib/compiler/test/receive_SUITE.erl index fca3f0387b..2a592dd669 100644 --- a/lib/compiler/test/receive_SUITE.erl +++ b/lib/compiler/test/receive_SUITE.erl @@ -21,7 +21,7 @@ -module(receive_SUITE). -export([all/1,init_per_testcase/2,fin_per_testcase/2, - recv/1,coverage/1,otp_7980/1,ref_opt/1]). + recv/1,coverage/1,otp_7980/1,ref_opt/1,export/1]). -include("test_server.hrl"). @@ -36,7 +36,7 @@ fin_per_testcase(_Case, Config) -> all(suite) -> test_lib:recompile(?MODULE), - [recv,coverage,otp_7980,ref_opt]. + [recv,coverage,otp_7980,ref_opt,export]. -record(state, {ena = true}). @@ -205,4 +205,25 @@ collect_recv_opt_instrs(Code) -> end] || {function,_,_,_,Is} <- Code], lists:append(L). +export(Config) when is_list(Config) -> + Ref = make_ref(), + ?line self() ! {result,Ref,42}, + ?line 42 = export_1(Ref), + ?line {error,timeout} = export_1(Ref), + ok. + +export_1(Reference) -> + id(Reference), + receive + {result,Reference,Result} -> + Result + after 1 -> + Result = {error,timeout} + end, + %% Result ({x,1}) is used, but not the return value ({x,0}) + %% of the receive. Used to be incorrectly optimized + %% by beam_block. + id({build,self()}), + Result. + id(I) -> I. |