File 2452-compiler-Remove-eta-conversion.patch of Package erlang

From 36656399c65d7b493238860b243c2dde6397ddc8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20H=C3=B6gberg?= <john@erlang.org>
Date: Tue, 21 Dec 2021 22:07:09 +0100
Subject: [PATCH 2/4] compiler: Remove eta conversion

This resurrects 750ecdea08fa5fa7e32b7f3019eed96c1699427e, which
was removed because it made HiPE unhappy.

Co-authored-by: Anthony Ramine <n.oxyde@gmail.com>
---
 erts/emulator/test/trace_local_SUITE.erl |  16 +--
 lib/compiler/src/Makefile                |   2 -
 lib/compiler/src/beam_dict.erl           |   8 +-
 lib/compiler/src/beam_ssa_funs.erl       | 152 -----------------------
 lib/compiler/src/compile.erl             |   5 -
 lib/compiler/src/compiler.app.src        |   1 -
 lib/compiler/src/v3_core.erl             |   2 +
 lib/compiler/src/v3_kernel.erl           |  34 ++---
 lib/compiler/test/compile_SUITE.erl      |   4 +-
 lib/tools/test/cprof_SUITE.erl           |  10 +-
 10 files changed, 39 insertions(+), 195 deletions(-)
 delete mode 100644 lib/compiler/src/beam_ssa_funs.erl

diff --git a/erts/emulator/test/trace_local_SUITE.erl b/erts/emulator/test/trace_local_SUITE.erl
index 8cf8c81b7a..5913da3381 100644
--- a/erts/emulator/test/trace_local_SUITE.erl
+++ b/erts/emulator/test/trace_local_SUITE.erl
@@ -803,16 +803,16 @@ exception_test(Opts, Func0, Args0) ->
     %% Func0 and Args0 are for the innermost call, now we will
     %% wrap them in wrappers...
     {Func1,Args1} =
-    case Function of
-        true  -> {fun exc/2,[Func0,Args0]};
-        false -> {Func0,Args0}
-    end,
+        case Function of
+            true  -> {fun(F, As) -> exc(F, As) end, [Func0,Args0]};
+            false -> {Func0,Args0}
+        end,
 
     {Func,Args} = 
-    case Apply of
-        true  -> {{erlang,apply},[Func1,Args1]};
-        false -> {Func1,Args1}
-    end,
+        case Apply of
+            true  -> {{erlang,apply},[Func1,Args1]};
+            false -> {Func1,Args1}
+        end,
 
     R1 = exc_slave(ExcOpts, Func, Args),
     Stack2 = [{?MODULE,exc_top,3,[]},{?MODULE,slave,2,[]}],
diff --git a/lib/compiler/src/Makefile b/lib/compiler/src/Makefile
index 54bf9bcb1f..b7dcb275ea 100644
--- a/lib/compiler/src/Makefile
+++ b/lib/compiler/src/Makefile
@@ -64,7 +64,6 @@ MODULES =  \
 	beam_ssa_bsm \
 	beam_ssa_codegen \
 	beam_ssa_dead \
-	beam_ssa_funs \
 	beam_ssa_lint \
 	beam_ssa_opt \
 	beam_ssa_pp \
@@ -205,7 +204,6 @@ $(EBIN)/beam_ssa_bsm.beam: beam_ssa.hrl
 $(EBIN)/beam_ssa_bool.beam: beam_ssa.hrl
 $(EBIN)/beam_ssa_codegen.beam: beam_ssa.hrl
 $(EBIN)/beam_ssa_dead.beam: beam_ssa.hrl
-$(EBIN)/beam_ssa_funs.beam: beam_ssa.hrl
 $(EBIN)/beam_ssa_lint.beam: beam_ssa.hrl
 $(EBIN)/beam_ssa_opt.beam: beam_ssa.hrl
 $(EBIN)/beam_ssa_pp.beam: beam_ssa.hrl
diff --git a/lib/compiler/src/beam_dict.erl b/lib/compiler/src/beam_dict.erl
index f6651ae119..36bdb01df5 100644
--- a/lib/compiler/src/beam_dict.erl
+++ b/lib/compiler/src/beam_dict.erl
@@ -285,15 +285,17 @@ string_table(#asm{strings=Strings,string_offset=Size}) ->
 
 -spec lambda_table(bdict()) -> {non_neg_integer(), [<<_:192>>]}.
 
-lambda_table(#asm{locals=Loc0,lambdas={NumLambdas,Lambdas0}}) ->
+lambda_table(#asm{locals=Loc0,exports=Ext0,lambdas={NumLambdas,Lambdas0}}) ->
     Lambdas1 = sofs:relation(Lambdas0),
     Loc = sofs:relation([{Lbl,{F,A}} || {F,A,Lbl} <- Loc0]),
-    Lambdas2 = sofs:relative_product1(Lambdas1, Loc),
+    Ext = sofs:relation([{Lbl,{F,A}} || {F,A,Lbl} <- Ext0]),
+    All = sofs:union(Loc, Ext),
+    Lambdas2 = sofs:relative_product1(Lambdas1, All),
     %% Initialize OldUniq to 0. It will be set to an unique value
     %% based on the MD5 checksum of the BEAM code for the module.
     OldUniq = 0,
     Lambdas = [<<F:32,A:32,Lbl:32,Index:32,NumFree:32,OldUniq:32>> ||
-		  {{Index,Lbl,NumFree},{F,A}} <- sofs:to_external(Lambdas2)],
+                  {{Index,Lbl,NumFree},{F,A}} <- sofs:to_external(Lambdas2)],
     {NumLambdas,Lambdas}.
 
 %% Returns the literal table.
diff --git a/lib/compiler/src/beam_ssa_funs.erl b/lib/compiler/src/beam_ssa_funs.erl
deleted file mode 100644
index a7b648bc47..0000000000
--- a/lib/compiler/src/beam_ssa_funs.erl
+++ /dev/null
@@ -1,152 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2018-2021. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%%     http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%%
-%%% If a fun is defined locally and only used for calls, it can be replaced
-%%% with direct calls to the relevant function. This greatly speeds up "named
-%%% functions" (which rely on make_fun to recreate themselves) and macros that
-%%% wrap their body in a fun.
-%%%
-
--module(beam_ssa_funs).
-
--export([module/2]).
-
--include("beam_ssa.hrl").
-
--import(lists, [foldl/3]).
-
--spec module(Module, Options) -> Result when
-      Module :: beam_ssa:b_module(),
-      Options :: [compile:option()],
-      Result :: {ok, beam_ssa:b_module()}.
-
-module(#b_module{body=Fs0}=Module, _Opts) ->
-    Trampolines = foldl(fun find_trampolines/2, #{}, Fs0),
-    Fs = [lfo(F, Trampolines) || F <- Fs0],
-    {ok, Module#b_module{body=Fs}}.
-
-%% If a function does absolutely nothing beyond calling another function with
-%% the same arguments in the same order, we can shave off a call by short-
-%% circuiting it.
-find_trampolines(#b_function{args=Args,bs=Blocks}=F, Trampolines) ->
-    case map_get(0, Blocks) of
-        #b_blk{is=[#b_set{op=call,
-                          args=[#b_local{}=Actual | Args],
-                          dst=Dst}],
-               last=#b_ret{arg=Dst}} ->
-            {_, Name, Arity} = beam_ssa:get_anno(func_info, F),
-            Trampoline = #b_local{name=#b_literal{val=Name},arity=Arity},
-            Trampolines#{Trampoline => Actual};
-        _ ->
-            Trampolines
-    end.
-
-lfo(#b_function{bs=Blocks0}=F, Trampolines) ->
-    Linear0 = beam_ssa:linearize(Blocks0),
-    Linear = lfo_optimize(Linear0, lfo_analyze(Linear0, #{}), Trampolines),
-    F#b_function{bs=maps:from_list(Linear)}.
-
-%% Gather a map of the locally defined funs that are only used for calls.
-lfo_analyze([{_L,#b_blk{is=Is,last=Last}}|Bs], LFuns0) ->
-    LFuns = lfo_analyze_last(Last, lfo_analyze_is(Is, LFuns0)),
-    lfo_analyze(Bs, LFuns);
-lfo_analyze([], LFuns) ->
-    LFuns.
-
-lfo_analyze_is([#b_set{op=make_fun,
-                       dst=Dst,
-                       args=[#b_local{} | FreeVars]}=Def | Is],
-               LFuns0) ->
-    LFuns = maps:put(Dst, Def, maps:without(FreeVars, LFuns0)),
-    lfo_analyze_is(Is, LFuns);
-lfo_analyze_is([#b_set{op=call,
-                       args=[Fun | CallArgs]} | Is],
-               LFuns) when is_map_key(Fun, LFuns) ->
-    #b_set{args=[#b_local{arity=Arity} | FreeVars]} = map_get(Fun, LFuns),
-    case length(CallArgs) + length(FreeVars) of
-        Arity ->
-            lfo_analyze_is(Is, maps:without(CallArgs, LFuns));
-        _ ->
-            %% This will `badarity` at runtime, and it's easier to disable the
-            %% optimization than to simulate it.
-            lfo_analyze_is(Is, maps:without([Fun | CallArgs], LFuns))
-    end;
-lfo_analyze_is([#b_set{args=Args} | Is], LFuns) when map_size(LFuns) =/= 0 ->
-    %% We disqualify funs that are used outside calls because this forces them
-    %% to be created anyway, and the slight performance gain from direct calls
-    %% is not enough to offset the potential increase in stack frame size (the
-    %% free variables need to be kept alive until the call).
-    lfo_analyze_is(Is, maps:without(Args, LFuns));
-lfo_analyze_is([_ | Is], LFuns) ->
-    lfo_analyze_is(Is, LFuns);
-lfo_analyze_is([], LFuns) ->
-    LFuns.
-
-lfo_analyze_last(#b_switch{arg=Arg}, LFuns) ->
-    maps:remove(Arg, LFuns);
-lfo_analyze_last(#b_ret{arg=Arg}, LFuns) ->
-    maps:remove(Arg, LFuns);
-lfo_analyze_last(_, LFuns) ->
-    LFuns.
-
-%% Replace all calls of suitable funs with a direct call to their
-%% implementation. Liveness optimization will get rid of the make_fun
-%% instruction.
-lfo_optimize(Linear, LFuns, _Trampolines) when map_size(LFuns) =:= 0 ->
-    Linear;
-lfo_optimize(Linear, LFuns, Trampolines) ->
-    lfo_optimize_1(Linear, LFuns, Trampolines).
-
-lfo_optimize_1([{L,#b_blk{is=Is0}=Blk}|Bs], LFuns, Trampolines) ->
-    Is = lfo_optimize_is(Is0, LFuns, Trampolines),
-    [{L,Blk#b_blk{is=Is}} | lfo_optimize_1(Bs, LFuns, Trampolines)];
-lfo_optimize_1([], _LFuns, _Trampolines) ->
-    [].
-
-lfo_optimize_is([#b_set{op=call,
-                        args=[Fun | CallArgs]}=Call0 | Is],
-                LFuns, Trampolines) when is_map_key(Fun, LFuns) ->
-    #b_set{args=[Local | FreeVars]} = map_get(Fun, LFuns),
-    Args = [lfo_short_circuit(Local, Trampolines) | CallArgs ++ FreeVars],
-    Call = beam_ssa:add_anno(local_fun_opt, Fun, Call0#b_set{args=Args}),
-    [Call | lfo_optimize_is(Is, LFuns, Trampolines)];
-lfo_optimize_is([I | Is], LFuns, Trampolines) ->
-    [I | lfo_optimize_is(Is, LFuns, Trampolines)];
-lfo_optimize_is([], _LFuns, _Trampolines) ->
-    [].
-
-lfo_short_circuit(Call, Trampolines) ->
-    lfo_short_circuit(Call, Trampolines, sets:new([{version, 2}])).
-
-lfo_short_circuit(Call, Trampolines, Seen0) ->
-    %% Beware of infinite loops! Get out if this call has been seen before.
-    case sets:is_element(Call, Seen0) of
-        true ->
-            Call;
-        false ->
-            case Trampolines of
-                #{Call := Other} ->
-                    Seen = sets:add_element(Call, Seen0),
-                    lfo_short_circuit(Other, Trampolines, Seen);
-                #{} ->
-                    Call
-            end
-    end.
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index b65750d153..f364b56645 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -876,10 +876,6 @@ kernel_passes() ->
        {iff,dssabsm,{listing,"ssabsm"}},
        {unless,no_bsm_opt,{iff,ssalint,{pass,beam_ssa_lint}}},
 
-       {unless,no_fun_opt,{pass,beam_ssa_funs}},
-       {iff,dssafuns,{listing,"ssafuns"}},
-       {unless,no_fun_opt,{iff,ssalint,{pass,beam_ssa_lint}}},
-
        {unless,no_ssa_opt,{pass,beam_ssa_opt}},
        {iff,dssaopt,{listing,"ssaopt"}},
        {unless,no_ssa_opt,{iff,ssalint,{pass,beam_ssa_lint}}},
@@ -2054,7 +2050,6 @@ pre_load() ->
 	 beam_ssa_bsm,
 	 beam_ssa_codegen,
 	 beam_ssa_dead,
-         beam_ssa_funs,
 	 beam_ssa_opt,
 	 beam_ssa_pre_codegen,
 	 beam_ssa_recv,
diff --git a/lib/compiler/src/compiler.app.src b/lib/compiler/src/compiler.app.src
index e257c8fc3a..5e8135bd1e 100644
--- a/lib/compiler/src/compiler.app.src
+++ b/lib/compiler/src/compiler.app.src
@@ -40,7 +40,6 @@
              beam_ssa_bsm,
              beam_ssa_codegen,
              beam_ssa_dead,
-             beam_ssa_funs,
              beam_ssa_lint,
              beam_ssa_opt,
              beam_ssa_pp,
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index 2223db6608..6bf87e131c 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -723,6 +723,8 @@ expr({'catch',L,E0}, St0) ->
     Lanno = lineno_anno(L, St1),
     {#icatch{anno=#a{anno=Lanno},body=Eps ++ [E1]},[],St1};
 expr({'fun',L,{function,F,A}}, St0) ->
+    %% Generate a new name for eta conversion of local funs (`fun local/123`)
+    %% in case `no_shared_fun_wrappers` is given.
     {Fname,St1} = new_fun_name(St0),
     Lanno = full_anno(L, St1),
     Id = {0,0,Fname},
diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl
index cf6df77d68..aa3fc033eb 100644
--- a/lib/compiler/src/v3_kernel.erl
+++ b/lib/compiler/src/v3_kernel.erl
@@ -78,10 +78,9 @@
 -export([module/2,format_error/1]).
 
 -import(lists, [all/2,droplast/1,flatten/1,foldl/3,foldr/3,
-                map/2,mapfoldl/3,member/2,
-		keyfind/3,keyreplace/4,
-                last/1,partition/2,reverse/1,
-                sort/1,sort/2,splitwith/2]).
+                map/2,mapfoldl/3,member/2,keyfind/3,last/1,
+                partition/2,reverse/1,sort/1,sort/2,
+                splitwith/2]).
 -import(ordsets, [add_element/2,intersection/2,
                   subtract/2,union/2,union/1]).
 
@@ -234,25 +233,19 @@ gexpr_test_add(Ke, St0) ->
 %% expr(Cexpr, Sub, State) -> {Kexpr,[PreKexpr],State}.
 %%  Convert a Core expression, flattening it at the same time.
 
-expr(#c_var{anno=A0,name={Name,Arity}}=Fname, Sub, St) ->
-    Vs = [#c_var{name=list_to_atom("V" ++ integer_to_list(V))} ||
-             V <- integers(1, Arity)],
+expr(#c_var{anno=A,name={Name0,Arity}}=Fname, Sub, St) ->
     case St#kern.no_shared_fun_wrappers of
         false ->
-            %% Generate a (possibly shared) wrapper function for calling
-            %% this function.
-            Wrapper0 = ["-fun.",atom_to_list(Name),"/",integer_to_list(Arity),"-"],
-            Wrapper = list_to_atom(flatten(Wrapper0)),
-            Id = {id,{0,0,Wrapper}},
-            A = keyreplace(id, 1, A0, Id),
-            Fun = #c_fun{anno=A,vars=Vs,body=#c_apply{anno=A,op=Fname,args=Vs}},
-            expr(Fun, Sub, St);
+            Name = get_fsub(Name0, Arity, Sub),
+            {#k_local{anno=A,name=Name,arity=Arity},[],St};
         true ->
             %% For backward compatibility with OTP 22 and earlier,
             %% use the pre-generated name for the fun wrapper.
             %% There will be one wrapper function for each occurrence
             %% of `fun F/A`.
-            Fun = #c_fun{anno=A0,vars=Vs,body=#c_apply{anno=A0,op=Fname,args=Vs}},
+            Vs = [#c_var{name=list_to_atom("V" ++ integer_to_list(V))} ||
+                  V <- integers(1, Arity)],
+            Fun = #c_fun{anno=A,vars=Vs,body=#c_apply{anno=A,op=Fname,args=Vs}},
             expr(Fun, Sub, St)
     end;
 expr(#c_var{anno=A,name=V}, Sub, St) ->
@@ -1991,6 +1984,15 @@ uexpr(#ifun{anno=A,vars=Vs,body=B0}, {break,Rs}, St0) ->
 	    args=[Local|Fvs],
  	    ret=Rs},
      Free,add_local_function(Fun, St)};
+uexpr(#k_local{anno=A,name=Name,arity=Arity}, {break,Rs}, St) ->
+    Free = lit_list_vars(get_free(Name, Arity, St)),
+    Fvs = make_vars(Free),
+    FreeCount = length(Fvs),
+    Bif = #k_bif{anno=A,
+                 op=#k_internal{name=make_fun,arity=FreeCount+1},
+                 args=[#k_local{name=Name,arity=Arity+FreeCount} | Fvs],
+                 ret=Rs},
+    {Bif,Free,St};
 uexpr(#k_letrec_goto{anno=A,first=F0,then=T0}=MatchAlt, Br, St0) ->
     Rs = break_rets(Br),
     {F1,Fu,St1} = ubody(F0, Br, St0),
diff --git a/lib/tools/test/cprof_SUITE.erl b/lib/tools/test/cprof_SUITE.erl
index 8eb7476f57..d27371414a 100644
--- a/lib/tools/test/cprof_SUITE.erl
+++ b/lib/tools/test/cprof_SUITE.erl
@@ -203,9 +203,8 @@ on_load_test(Config) ->
     N2 = cprof:pause(),
     {Module,0,[]} = cprof:analyse(Module),
     M4__4 = M*4 - 4,
-    M10_7 = M*10 - 7,
-    {?MODULE,M10_7,[{{?MODULE,succ,1},M4__4},
-                    {{?MODULE,'-fun.succ/1-',1},M4__4},
+    M6_3 = M*6 - 3,
+    {?MODULE,M6_3,[{{?MODULE,succ,1},M4__4},
                     {{?MODULE,seq_r,4},M},
                     {{?MODULE,seq,3},M},
                     {{?MODULE,seq_r,3},1}]}
@@ -234,11 +233,10 @@ modules_test(Config) ->
     N = cprof:pause(),
     Lr = lists:reverse(L),
     M4_4 = M*4 - 4,
-    M10_7 = M*10 - 7,
+    M6_3 = M*6 - 3,
     M2__1 = M*2 + 1,
     {Tot,ModList} = cprof:analyse(),
-    {value,{?MODULE,M10_7,[{{?MODULE,succ,1},M4_4},
-                           {{?MODULE,'-fun.succ/1-',1},M4_4},
+    {value,{?MODULE,M6_3,[{{?MODULE,succ,1},M4_4},
                            {{?MODULE,seq_r,4},M},
                            {{?MODULE,seq,3},M},
                            {{?MODULE,seq_r,3},1}]}} =
-- 
2.31.1

openSUSE Build Service is sponsored by