aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler/src
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2017-08-09 14:19:18 +0200
committerBjörn Gustavsson <[email protected]>2017-08-10 12:14:56 +0200
commit3e1d141e4d22708788af1a14401f257f4153fbae (patch)
tree669e57ef3cd513a78091c18cbfc9a2c2ac48c1f4 /lib/compiler/src
parente25f673d520342bfe7cd479ef6b850a57f8ab1ea (diff)
downloadotp-3e1d141e4d22708788af1a14401f257f4153fbae.tar.gz
otp-3e1d141e4d22708788af1a14401f257f4153fbae.tar.bz2
otp-3e1d141e4d22708788af1a14401f257f4153fbae.zip
Generalize optimization of "one-armed" cases
A 'case' expression will force a stack frame (essentially in the same way as a function call), unless it is at the end of a function. In sys_core_fold there is an optimization that can optimize one-armed cases such as: case Expr of Pat1 -> DoSomething; Pat2 -> erlang:error(bad) end, MoreCode. Because only one arm of the 'case' can succeed, the code after the case can be move into the successful arm: case Expr of Pat1 -> DoSomething, MoreCode; Pat2 -> erlang:error(bad) end. Thus, the 'case' is at the end of the function and it will no longer need a stack frame. However, the optimization in sys_core_fold would not be applied if there were more than one failing clause such as in this code: case Expr of Pat1 -> DoSomething, MoreCode; Pat2 -> erlang:error(bad); _ -> erlang:error(case_clause) end. Generalize the optimization to handle any number of failing clauses at the end of the case. Reported-by: bugs.erlang.org/browse/ERL-452
Diffstat (limited to 'lib/compiler/src')
-rw-r--r--lib/compiler/src/sys_core_fold.erl23
1 files changed, 10 insertions, 13 deletions
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index e0cd6da06f..21ad2980e2 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -2422,16 +2422,10 @@ move_let_into_expr(#c_let{vars=InnerVs0,body=InnerBody0}=Inner,
Outer#c_let{vars=OuterVs,arg=Arg,
body=Inner#c_let{vars=InnerVs,arg=OuterBody,body=InnerBody}};
move_let_into_expr(#c_let{vars=Lvs0,body=Lbody0}=Let,
- #c_case{arg=Cexpr0,clauses=[Ca0,Cb0|Cs]}=Case, Sub0) ->
- %% Test if there are no more clauses than Ca0 and Cb0, or if
- %% Cb0 is guaranteed to match.
- TwoClauses = Cs =:= [] orelse
- case Cb0 of
- #c_clause{pats=[#c_var{}],guard=#c_literal{val=true}} -> true;
- _ -> false
- end,
- case {TwoClauses,is_failing_clause(Ca0),is_failing_clause(Cb0)} of
- {true,false,true} ->
+ #c_case{arg=Cexpr0,clauses=[Ca0|Cs0]}=Case, Sub0) ->
+ case not is_failing_clause(Ca0) andalso
+ are_all_failing_clauses(Cs0) of
+ true ->
%% let <Lvars> = case <Case-expr> of
%% <Cpats> -> <Clause-body>;
%% <OtherCpats> -> erlang:error(...)
@@ -2467,8 +2461,8 @@ move_let_into_expr(#c_let{vars=Lvs0,body=Lbody0}=Let,
body=Lbody},
Ca = Ca0#c_clause{pats=CaPats,guard=G,body=B},
- Cb = clause(Cb0, Cexpr, value, Sub0),
- Case#c_case{arg=Cexpr,clauses=[Ca,Cb]}
+ Cs = [clause(C, Cexpr, value, Sub0) || C <- Cs0],
+ Case#c_case{arg=Cexpr,clauses=[Ca|Cs]}
catch
nomatch ->
%% This is not a defeat. The code will eventually
@@ -2476,7 +2470,7 @@ move_let_into_expr(#c_let{vars=Lvs0,body=Lbody0}=Let,
%% optimizations done in this module.
impossible
end;
- {_,_,_} -> impossible
+ false -> impossible
end;
move_let_into_expr(#c_let{vars=Lvs0,body=Lbody0}=Let,
#c_seq{arg=Sarg0,body=Sbody0}=Seq, Sub0) ->
@@ -2499,6 +2493,9 @@ move_let_into_expr(#c_let{vars=Lvs0,body=Lbody0}=Let,
body=Lbody}};
move_let_into_expr(_Let, _Expr, _Sub) -> impossible.
+are_all_failing_clauses(Cs) ->
+ all(fun is_failing_clause/1, Cs).
+
is_failing_clause(#c_clause{body=B}) ->
will_fail(B).