File 2324-Generalize-optimization-of-one-armed-cases.patch of Package erlang

From 3e1d141e4d22708788af1a14401f257f4153fbae Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Wed, 9 Aug 2017 14:19:18 +0200
Subject: [PATCH] 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
---
 lib/compiler/src/sys_core_fold.erl    | 23 ++++++++++-------------
 lib/compiler/test/core_fold_SUITE.erl | 28 ++++++++++++++++++++++++++--
 2 files changed, 36 insertions(+), 15 deletions(-)

diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index e0cd6da06..21ad2980e 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).
 
-- 
2.14.1

openSUSE Build Service is sponsored by