File 3361-Enhance-the-optimization-of-the-try-catch-eliminatio.patch of Package erlang

From 1cfeca84ac84b549e9a7b3668316dbb3c5e783d9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Tue, 2 Mar 2021 08:41:13 +0100
Subject: [PATCH] Enhance the optimization of the try/catch elimination
 optimization

The `beam_ssa_opt:ssa_opt_try/1` optimization would sometimes fail to
eliminate a redundant `try`/`catch` construct because it only looked
for `new_try_tag` instructions at the beginning of an SSA block. Here
is an example:

    foobar({Anno}=T, V) ->
        try
            setelement(1, T, V)
        catch
            _Class:_Error:_Stack ->
                Anno
        end.

In the SSA code, the `get_tuple_element` instruction from the tuple
matching in the function head is at the beginning of the block with the
`new_try_tag` instruction:

    8:
      _10 = get_tuple_element _0, `0`
      @ssa_catch_tag = new_try_tag `'try'`
      br @ssa_catch_tag, ^6, ^5

Generalize the optimization to handle this example. While at it,
also make the optimization run faster by eliminating redundant
set update operations.
---
 lib/compiler/src/beam_ssa_opt.erl | 56 ++++++++++++++++++-------------
 1 file changed, 33 insertions(+), 23 deletions(-)

diff --git a/lib/compiler/src/beam_ssa_opt.erl b/lib/compiler/src/beam_ssa_opt.erl
index 165330cfff..1369445e5b 100644
--- a/lib/compiler/src/beam_ssa_opt.erl
+++ b/lib/compiler/src/beam_ssa_opt.erl
@@ -1494,35 +1494,45 @@ reduce_try_is([], Acc) ->
 %% unreachable landing pads, removing them from the set whenever we see a
 %% branch to that block. When we encounter a `new_try_tag` instruction that
 %% references a block in the unreachable set, we'll remove the try/catch.
-trim_try([{L, #b_blk{is=[#b_set{op=new_try_tag,dst=Tag}],
-                     last=Last0}=Blk0} | Bs],
-         Unreachable0, Killed0, Acc) ->
-    #b_br{succ=SuccLbl,fail=PadLbl} = Last0,
-    case sets:is_element(PadLbl, Unreachable0) of
-        true ->
-            %% The landing pad can't be reached in any way, remove the entire
-            %% try/catch.
-            Blk = Blk0#b_blk{is=[],
-                             last=#b_br{bool=#b_literal{val=true},
-                                        succ=SuccLbl,fail=SuccLbl}},
-
-            Unreachable = sets:del_element(PadLbl, Unreachable0),
-            Killed = sets:add_element(Tag, Killed0),
-            trim_try(Bs, Unreachable, Killed, [{L, Blk} | Acc]);
-        false ->
-            trim_try(Bs, Unreachable0, Killed0, [{L, Blk0} | Acc])
-    end;
 trim_try([{L, #b_blk{is=[#b_set{op=landingpad} | _]}=Blk}| Bs],
          Unreachable0, Killed, Acc) ->
     Unreachable1 = sets:add_element(L, Unreachable0),
-
     Successors = sets:from_list(beam_ssa:successors(Blk)),
     Unreachable = sets:subtract(Unreachable1, Successors),
     trim_try(Bs, Unreachable, Killed, [{L, Blk} | Acc]);
-trim_try([{L, Blk} | Bs], Unreachable0, Killed, Acc) ->
-    Successors = sets:from_list(beam_ssa:successors(Blk)),
-    Unreachable = sets:subtract(Unreachable0, Successors),
-    trim_try(Bs, Unreachable, Killed, [{L, Blk} | Acc]);
+trim_try([{L, #b_blk{last=#b_ret{}}=Blk} | Bs], Unreachable, Killed, Acc) ->
+    %% Nothing to update and nothing to optimize.
+    trim_try(Bs, Unreachable, Killed, [{L,Blk}|Acc]);
+trim_try([{L, Blk0} | Bs], Unreachable0, Killed0, Acc) ->
+    case sets:is_empty(Unreachable0) of
+        true ->
+            %% Nothing to update and nothing to optimize.
+            trim_try(Bs, Unreachable0, Killed0, [{L,Blk0}|Acc]);
+        false ->
+            #b_blk{is=Is0,last=Last0} = Blk0,
+            case reverse(Is0) of
+                [#b_set{op=new_try_tag,dst=Tag}|Is] ->
+                    #b_br{succ=SuccLbl,fail=PadLbl} = Last0,
+                    Unreachable = sets:del_element(PadLbl, Unreachable0),
+                    case sets:is_element(PadLbl, Unreachable0) of
+                        true ->
+                            %% The landing pad can't be reached in any way,
+                            %% remove the entire try/catch.
+                            Blk = Blk0#b_blk{is=reverse(Is),
+                                             last=#b_br{bool=#b_literal{val=true},
+                                                        succ=SuccLbl,fail=SuccLbl}},
+                            Killed = sets:add_element(Tag, Killed0),
+                            trim_try(Bs, Unreachable, Killed, [{L,Blk}|Acc]);
+                        false ->
+                            trim_try(Bs, Unreachable, Killed0, [{L,Blk0}|Acc])
+                    end;
+                _ ->
+                    %% Update the set of unreachable landing_pad blocks.
+                    Successors = sets:from_list(beam_ssa:successors(Blk0)),
+                    Unreachable = sets:subtract(Unreachable0, Successors),
+                    trim_try(Bs, Unreachable, Killed0, [{L,Blk0}|Acc])
+            end
+    end;
 trim_try([], _Unreachable, Killed, Acc0) ->
     case sets:is_empty(Killed) of
         true ->
-- 
2.26.2

openSUSE Build Service is sponsored by