File 3281-Eliminate-moves-in-catches.patch of Package erlang

From c439e8d8a83b7986719f1c324638c4e5ce2bc1aa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Tue, 1 Feb 2022 10:00:26 +0100
Subject: [PATCH] Eliminate moves in catches

Consider this function:

    foo(X) ->
        try
            {ok, bar(1, [X])}
        catch
            _:_:_ -> error
        end.

Compiled with OTP 24, the first part of the function looks like this:

    {allocate,1,1}.
    {'try',{y,0},{f,3}}.
    {test_heap,2,1}.
    {put_list,{x,0},nil,{x,1}}.
    {move,{integer,1},{x,0}}.
    {line,[{location,"t.erl",6}]}.
    {call,2,{f,5}}.

Here there is an `allocate` instruction, and after the `try` a
`test_heap` instruction. d5fb2115710fb7 (in #5652) hoists the
building of the list and combines the `allocate` and `test_heap`
instructions:

    {allocate_heap,1,2,1}.
    {put_list,{x,0},nil,{x,0}}.
    {'try',{y,0},{f,3}}.
    {move,{x,0},{x,1}}.           %Extra move instruction.
    {move,{integer,1},{x,0}}.
    {line,[{location,"t.erl",6}]}.
    {call,2,{f,5}}. % bar/2

Unfortunately, an extra `move` instruction is introduced because
the `put_list` instruction places its result `{x,0}` instead of
`{x,1}`.

This commit extends an existing optimization in `beam_ssa_pre_codegen`
so that the `move` instruction can be eliminated:

    {allocate_heap,1,2,1}.
    {put_list,{x,0},nil,{x,1}}.
    {'try',{y,0},{f,3}}.
    {move,{integer,1},{x,0}}.
    {line,[{location,"t.erl",6}]}.
    {call,2,{f,5}}. % bar/2

Now the `put_list` places its result directly into `{x,1}`.
---
 lib/compiler/src/beam_ssa_codegen.erl     | 2 +-
 lib/compiler/src/beam_ssa_pre_codegen.erl | 6 ++++++
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/lib/compiler/src/beam_ssa_codegen.erl b/lib/compiler/src/beam_ssa_codegen.erl
index 23ae72b993..62aa4aa539 100644
--- a/lib/compiler/src/beam_ssa_codegen.erl
+++ b/lib/compiler/src/beam_ssa_codegen.erl
@@ -393,7 +393,7 @@ classify_heap_need(landingpad) -> gc;
 classify_heap_need(landingpad) -> gc;
 classify_heap_need(match_fail) -> gc;
 classify_heap_need(nop) -> neutral;
-classify_heap_need(new_try_tag) -> gc;
+classify_heap_need(new_try_tag) -> neutral;
 classify_heap_need(old_make_fun) -> gc;
 classify_heap_need(peek_message) -> gc;
 classify_heap_need(put_map) -> gc;
diff --git a/lib/compiler/src/beam_ssa_pre_codegen.erl b/lib/compiler/src/beam_ssa_pre_codegen.erl
index be736a9c5f..b39292e15d 100644
--- a/lib/compiler/src/beam_ssa_pre_codegen.erl
+++ b/lib/compiler/src/beam_ssa_pre_codegen.erl
@@ -2715,6 +2715,12 @@ reserve_terminator(L, Is, #b_br{bool=#b_var{},succ=Succ,fail=Fail},
                         #{Arg:=Reg} -> #{Arg=>Reg};
                         #{} -> #{}
                     end;
+                #b_set{op=new_try_tag} ->
+                    %% We know that no X registers will be used at the
+                    %% failure label (a block starting with the
+                    %% landingpad instruction), so we can pick up
+                    %% register hints from the success label.
+                    reserve_terminator_1(L, Succ, Is, Blocks, XsMap, Res);
                 _ ->
                     %% Register hints from the success block may not
                     %% be safe at the failure block, and vice versa.
-- 
2.34.1

openSUSE Build Service is sponsored by