File 2452-Explicit-pass-RPO-to-beam_ssa-functions-cont.patch of Package erlang

From 35f10baeda472d82f568be6802bd4abda8da4195 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jos=C3=A9=20Valim?= <jose.valim@dashbit.co>
Date: Tue, 3 Nov 2020 12:21:50 +0100
Subject: [PATCH] Explicit pass RPO to beam_ssa functions (cont)

This patch finishes the work started on 0ce3fb91
by explicitly passing RPO to the remaining functions
in beam_ssa. This commit avoids the double RPO
computation in 5 other occasions.
---
 lib/compiler/src/beam_ssa.erl             | 48 +++++++++++------------
 lib/compiler/src/beam_ssa_bool.erl        |  4 +-
 lib/compiler/src/beam_ssa_bsm.erl         | 10 +++--
 lib/compiler/src/beam_ssa_opt.erl         |  6 ++-
 lib/compiler/src/beam_ssa_pre_codegen.erl | 41 +++++++++++--------
 5 files changed, 59 insertions(+), 50 deletions(-)

diff --git a/lib/compiler/src/beam_ssa.erl b/lib/compiler/src/beam_ssa.erl
index d5fe4b7d9c..76303b34cb 100644
--- a/lib/compiler/src/beam_ssa.erl
+++ b/lib/compiler/src/beam_ssa.erl
@@ -23,7 +23,7 @@
 -export([add_anno/3,get_anno/2,get_anno/3,
          between/4,
          clobbers_xregs/1,def/2,def_unused/3,
-         definitions/1,
+         definitions/2,
          dominators/2,dominators_from_predecessors/2,common_dominators/3,
          flatmapfold_instrs/4,
          fold_blocks/4,
@@ -32,13 +32,13 @@
          linearize/1,
          mapfold_blocks/4,
          mapfold_instrs/4,
-         merge_blocks/1,
+         merge_blocks/2,
          normalize/1,
          no_side_effect/1,
          predecessors/1,
          rename_vars/3,
          rpo/1,rpo/2,
-         split_blocks/3,
+         split_blocks/4,
          successors/1,successors/2,
          trim_unreachable/1,
          used/1,uses/2]).
@@ -344,8 +344,7 @@ successors(L, Blocks) ->
       Def :: ordsets:ordset(var_name()).
 
 def(Ls, Blocks) ->
-    Top = rpo(Ls, Blocks),
-    Blks = [map_get(L, Blocks) || L <- Top],
+    Blks = [map_get(L, Blocks) || L <- Ls],
     def_1(Blks, []).
 
 -spec def_unused(Ls, Used, Blocks) -> {Def,Unused} when
@@ -356,9 +355,8 @@ def(Ls, Blocks) ->
       Unused :: ordsets:ordset(var_name()).
 
 def_unused(Ls, Unused, Blocks) ->
-    Top = rpo(Ls, Blocks),
-    Blks = [map_get(L, Blocks) || L <- Top],
-    Preds = cerl_sets:from_list(Top),
+    Blks = [map_get(L, Blocks) || L <- Ls],
+    Preds = cerl_sets:from_list(Ls),
     def_unused_1(Blks, Preds, [], Unused).
 
 %% dominators(Labels, BlockMap) -> {Dominators,Numbering}.
@@ -533,11 +531,10 @@ between(From, To, Preds, Blocks) ->
 -spec rename_vars(Rename, [label()], block_map()) -> block_map() when
       Rename :: rename_map() | rename_proplist().
 
-rename_vars(Rename, From, Blocks) when is_list(Rename) ->
-    rename_vars(maps:from_list(Rename), From, Blocks);
-rename_vars(Rename, From, Blocks) when is_map(Rename)->
-    Top = rpo(From, Blocks),
-    Preds = cerl_sets:from_list(Top),
+rename_vars(Rename, Labels, Blocks) when is_list(Rename) ->
+    rename_vars(maps:from_list(Rename), Labels, Blocks);
+rename_vars(Rename, Labels, Blocks) when is_map(Rename)->
+    Preds = cerl_sets:from_list(Labels),
     F = fun(#b_set{op=phi,args=Args0}=Set) ->
                 Args = rename_phi_vars(Args0, Preds, Rename),
                 normalize(Set#b_set{args=Args});
@@ -551,23 +548,23 @@ rename_vars(Rename, From, Blocks) when is_map(Rename)->
            (#b_ret{arg=Arg}=Ret) ->
                 normalize(Ret#b_ret{arg=rename_var(Arg, Rename)})
         end,
-    map_instrs_1(Top, F, Blocks).
+    map_instrs_1(Labels, F, Blocks).
 
 %% split_blocks(Predicate, Blocks0, Count0) -> {Blocks,Count}.
 %%  Call Predicate(Instruction) for each instruction in all
 %%  blocks. If Predicate/1 returns true, split the block
 %%  before this instruction.
 
--spec split_blocks(Pred, Blocks0, Count0) -> {Blocks,Count} when
+-spec split_blocks(Labels, Pred, Blocks0, Count0) -> {Blocks,Count} when
+      Labels :: [label()],
       Pred :: fun((b_set()) -> boolean()),
       Blocks :: block_map(),
-      Count0 :: beam_ssa:label(),
+      Count0 :: label(),
       Blocks0 :: block_map(),
       Blocks :: block_map(),
-      Count :: beam_ssa:label().
+      Count :: label().
 
-split_blocks(P, Blocks, Count) ->
-    Ls = rpo(Blocks),
+split_blocks(Ls, P, Blocks, Count) ->
     split_blocks_1(Ls, P, Blocks, Count).
 
 -spec trim_unreachable(SSA0) -> SSA when
@@ -601,14 +598,13 @@ used(#b_switch{arg=#b_var{}=V}) ->
     [V];
 used(_) -> [].
 
--spec definitions(Blocks :: block_map()) -> definition_map().
-definitions(Blocks) ->
-    Top = rpo(Blocks),
+-spec definitions(Labels :: [label()], Blocks :: block_map()) -> definition_map().
+definitions(Labels, Blocks) ->
     fold_instrs(fun(#b_set{ dst = Var }=I, Acc) ->
                             Acc#{Var => I};
                        (_Terminator, Acc) ->
                             Acc
-                    end, Top, #{}, Blocks).
+                    end, Labels, #{}, Blocks).
 
 %% uses(Labels, BlockMap) -> UsageMap
 %%  Traverse the blocks given by labels and builds a usage map
@@ -630,15 +626,15 @@ fold_uses_block(Lbl, #b_blk{is=Is,last=Last}, UseMap0) ->
         end,
     F(Last, foldl(F, UseMap0, Is)).
 
--spec merge_blocks(block_map()) -> block_map().
+-spec merge_blocks([label()], block_map()) -> block_map().
 
-merge_blocks(Blocks) ->
+merge_blocks(Labels, Blocks) ->
     Preds = predecessors(Blocks),
 
     %% We must traverse the blocks in reverse postorder to avoid
     %% embedding succeeded:guard instructions into the middle of
     %% blocks when this function is called from beam_ssa_bool.
-    merge_blocks_1(rpo(Blocks), Preds, Blocks).
+    merge_blocks_1(Labels, Preds, Blocks).
 
 %%%
 %%% Internal functions.
diff --git a/lib/compiler/src/beam_ssa_bool.erl b/lib/compiler/src/beam_ssa_bool.erl
index 5fa60c3b19..b3b41e68c3 100644
--- a/lib/compiler/src/beam_ssa_bool.erl
+++ b/lib/compiler/src/beam_ssa_bool.erl
@@ -160,7 +160,7 @@ opt_function(#b_function{bs=Blocks0,cnt=Count0}=F) ->
             %% To ensure that, trim before merging.
 
             Blocks3 = beam_ssa:trim_unreachable(Blocks2),
-            Blocks = beam_ssa:merge_blocks(Blocks3),
+            Blocks = beam_ssa:merge_blocks(beam_ssa:rpo(Blocks3), Blocks3),
             F#b_function{bs=Blocks,cnt=Count};
         true ->
             %% There are no boolean operators that can be optimized in
@@ -1504,7 +1504,7 @@ join_inits_1([], VarMap) ->
 %%%
 %%% We don't try merge blocks during the conversion because it would
 %%% be difficult to keep phi nodes up to date. We will call
-%%% beam_ssa:merge_blocks/1 before returning from this pass to do all
+%%% beam_ssa:merge_blocks/2 before returning from this pass to do all
 %%% block merging.
 %%%
 
diff --git a/lib/compiler/src/beam_ssa_bsm.erl b/lib/compiler/src/beam_ssa_bsm.erl
index 9984c3586f..59872290a6 100644
--- a/lib/compiler/src/beam_ssa_bsm.erl
+++ b/lib/compiler/src/beam_ssa_bsm.erl
@@ -459,12 +459,14 @@ combine_matches(#b_function{bs=Blocks0,cnt=Counter0}=F, ModInfo) ->
                           {Block0#b_blk{is=Is}, State}
                   end,
                   RPO,
-                  #cm{ definitions = beam_ssa:definitions(Blocks0),
+                  #cm{ definitions = beam_ssa:definitions(RPO, Blocks0),
                        dominators = Dominators,
                        blocks = Blocks0 },
                   Blocks0),
 
-            Blocks2 = beam_ssa:rename_vars(State#cm.renames, [0], Blocks1),
+            %% The fun in mapfold_blocks does not update terminators,
+            %% so we can reuse the RPO computed for Blocks0.
+            Blocks2 = beam_ssa:rename_vars(State#cm.renames, RPO, Blocks1),
 
             {Blocks, Counter} = alias_matched_binaries(Blocks2, Counter0,
                                                        State#cm.match_aliases),
@@ -852,10 +854,10 @@ skip_outgoing_tail_extraction({Fs0, ModInfo}) ->
 skip_outgoing_tail_extraction(#b_function{bs=Blocks0}=F, ModInfo) ->
     case funcinfo_get(F, has_bsm_ops, ModInfo) of
         true ->
-            State0 = #sote{ definitions = beam_ssa:definitions(Blocks0),
+            RPO = beam_ssa:rpo(Blocks0),
+            State0 = #sote{ definitions = beam_ssa:definitions(RPO, Blocks0),
                             mod_info = ModInfo },
 
-            RPO = beam_ssa:rpo(Blocks0),
             {Blocks1, State} = beam_ssa:mapfold_instrs(
                                  fun sote_rewrite_calls/2, RPO, State0, Blocks0),
 
diff --git a/lib/compiler/src/beam_ssa_opt.erl b/lib/compiler/src/beam_ssa_opt.erl
index e08f60d7b3..3cd25ff273 100644
--- a/lib/compiler/src/beam_ssa_opt.erl
+++ b/lib/compiler/src/beam_ssa_opt.erl
@@ -453,7 +453,8 @@ ssa_opt_trim_unreachable({#opt_st{ssa=Blocks}=St, FuncDb}) ->
     {St#opt_st{ssa=beam_ssa:trim_unreachable(Blocks)}, FuncDb}.
 
 ssa_opt_merge_blocks({#opt_st{ssa=Blocks0}=St, FuncDb}) ->
-    Blocks = beam_ssa:merge_blocks(Blocks0),
+    RPO = beam_ssa:rpo(Blocks0),
+    Blocks = beam_ssa:merge_blocks(RPO, Blocks0),
     {St#opt_st{ssa=Blocks}, FuncDb}.
 
 %%%
@@ -472,7 +473,8 @@ ssa_opt_split_blocks({#opt_st{ssa=Blocks0,cnt=Count0}=St, FuncDb}) ->
            (#b_set{op=make_fun}) -> true;
            (_) -> false
         end,
-    {Blocks,Count} = beam_ssa:split_blocks(P, Blocks0, Count0),
+    RPO = beam_ssa:rpo(Blocks0),
+    {Blocks,Count} = beam_ssa:split_blocks(RPO, P, Blocks0, Count0),
     {St#opt_st{ssa=Blocks,cnt=Count}, FuncDb}.
 
 %%%
diff --git a/lib/compiler/src/beam_ssa_pre_codegen.erl b/lib/compiler/src/beam_ssa_pre_codegen.erl
index 57fbc33558..78f9571e46 100644
--- a/lib/compiler/src/beam_ssa_pre_codegen.erl
+++ b/lib/compiler/src/beam_ssa_pre_codegen.erl
@@ -750,7 +750,8 @@ sanitize([], Count, Blocks0, Values) ->
                  map_size(Values) =:= 0 ->
                      Blocks0;
                  true ->
-                     beam_ssa:rename_vars(Values, [0], Blocks0)
+                     RPO = beam_ssa:rpo(Blocks0),
+                     beam_ssa:rename_vars(Values, RPO, Blocks0)
              end,
 
     %% Unreachable blocks can cause problems for the dominator calculations.
@@ -1511,7 +1512,8 @@ fix_receives_1([{L,Blk}|Ls], Blocks0, Count0) ->
         #b_blk{is=[#b_set{op=peek_message}|_]} ->
             Rm = find_rm_blocks(L, Blocks0),
             LoopExit = find_loop_exit(Rm, Blocks0),
-            Defs0 = beam_ssa:def([L], Blocks0),
+            RPO = beam_ssa:rpo([L], Blocks0),
+            Defs0 = beam_ssa:def(RPO, Blocks0),
             CommonUsed = recv_common(Defs0, LoopExit, Blocks0),
             {Blocks1,Count1} = recv_crit_edges(Rm, LoopExit, Blocks0, Count0),
             {Blocks2,Count2} = recv_fix_common(CommonUsed, LoopExit, Rm,
@@ -1530,7 +1532,8 @@ recv_common(_Defs, none, _Blocks) ->
     %% in the tail position of a function.
     [];
 recv_common(Defs, Exit, Blocks) ->
-    {ExitDefs,ExitUnused} = beam_ssa:def_unused([Exit], Defs, Blocks),
+    RPO = beam_ssa:rpo([Exit], Blocks),
+    {ExitDefs,ExitUnused} = beam_ssa:def_unused(RPO, Defs, Blocks),
     Def = ordsets:subtract(Defs, ExitDefs),
     ordsets:subtract(Def, ExitUnused).
 
@@ -1592,7 +1595,8 @@ rce_reroute_terminator(#b_switch{list=List0}=Last, Exit, New) ->
 
 recv_fix_common([Msg0|T], Exit, Rm, Blocks0, Count0) ->
     {Msg,Count1} = new_var('@recv', Count0),
-    Blocks1 = beam_ssa:rename_vars(#{Msg0=>Msg}, [Exit], Blocks0),
+    RPO = beam_ssa:rpo([Exit], Blocks0),
+    Blocks1 = beam_ssa:rename_vars(#{Msg0=>Msg}, RPO, Blocks0),
     N = length(Rm),
     {MsgVars,Count} = new_vars(duplicate(N, '@recv'), Count1),
     PhiArgs = fix_exit_phi_args(MsgVars, Rm, Exit, Blocks1),
@@ -1607,7 +1611,8 @@ recv_fix_common([], _, _, Blocks, Count) ->
 
 recv_fix_common_1([V|Vs], [Rm|Rms], Msg, Blocks0) ->
     Ren = #{Msg=>V},
-    Blocks1 = beam_ssa:rename_vars(Ren, [Rm], Blocks0),
+    RPO = beam_ssa:rpo([Rm], Blocks0),
+    Blocks1 = beam_ssa:rename_vars(Ren, RPO, Blocks0),
     #b_blk{is=Is0} = Blk0 = map_get(Rm, Blocks1),
     Copy = #b_set{op=copy,dst=V,args=[Msg]},
     Is = insert_after_phis(Is0, [Copy]),
@@ -1637,12 +1642,13 @@ exit_predecessors([], _Exit, _Blocks) -> [].
 %%  later used within a clause of the receive.
 
 fix_receive([L|Ls], Defs, Blocks0, Count0) ->
-    {RmDefs,Unused} = beam_ssa:def_unused([L], Defs, Blocks0),
+    RPO = beam_ssa:rpo([L], Blocks0),
+    {RmDefs,Unused} = beam_ssa:def_unused(RPO, Defs, Blocks0),
     Def = ordsets:subtract(Defs, RmDefs),
     Used = ordsets:subtract(Def, Unused),
     {NewVars,Count} = new_vars([Base || #b_var{name=Base} <- Used], Count0),
     Ren = zip(Used, NewVars),
-    Blocks1 = beam_ssa:rename_vars(Ren, [L], Blocks0),
+    Blocks1 = beam_ssa:rename_vars(Ren, RPO, Blocks0),
     #b_blk{is=Is0} = Blk1 = map_get(L, Blocks1),
     CopyIs = [#b_set{op=copy,dst=New,args=[Old]} || {Old,New} <- Ren],
     Is = insert_after_phis(Is0, CopyIs),
@@ -1667,8 +1673,8 @@ find_loop_exit([_,_|_]=RmBlocks, Blocks) ->
     RPO = beam_ssa:rpo(Blocks),
     {Dominators,_} = beam_ssa:dominators(RPO, Blocks),
     RmSet = cerl_sets:from_list(RmBlocks),
-    Rpo = beam_ssa:rpo(RmBlocks, Blocks),
-    find_loop_exit_1(Rpo, RmSet, Dominators, Blocks);
+    RmRPO = beam_ssa:rpo(RmBlocks, Blocks),
+    find_loop_exit_1(RmRPO, RmSet, Dominators, Blocks);
 find_loop_exit(_, _) ->
     %% There is (at most) a single clause. There is no common
     %% loop exit block.
@@ -2342,10 +2348,11 @@ reserve_yregs(#st{frames=Frames}=St0) ->
 reserve_yregs_1(L, #st{ssa=Blocks0,cnt=Count0,res=Res0}=St) ->
     Blk = map_get(L, Blocks0),
     Yregs = ordsets:from_list(cerl_sets:to_list(beam_ssa:get_anno(yregs, Blk))),
-    {Def,Unused} = beam_ssa:def_unused([L], Yregs, Blocks0),
+    RPO = beam_ssa:rpo([L], Blocks0),
+    {Def,Unused} = beam_ssa:def_unused(RPO, Yregs, Blocks0),
     UsedYregs = ordsets:subtract(Yregs, Unused),
     DefBefore = ordsets:subtract(UsedYregs, Def),
-    {BeforeVars,Blocks,Count} = rename_vars(DefBefore, L, Blocks0, Count0),
+    {BeforeVars,Blocks,Count} = rename_vars(DefBefore, L, RPO, Blocks0, Count0),
     InsideVars = ordsets:subtract(UsedYregs, DefBefore),
     ResTryTags0 = reserve_try_tags(L, Blocks),
     ResTryTags = [{V,{Reg,Count}} || {V,Reg} <- ResTryTags0],
@@ -2403,12 +2410,12 @@ update_act_map([L|Ls], Active0, ActMap0) ->
     end;
 update_act_map([], _, ActMap) -> ActMap.
 
-rename_vars([], _, Blocks, Count) ->
+rename_vars([], _, _, Blocks, Count) ->
     {[],Blocks,Count};
-rename_vars(Vs, L, Blocks0, Count0) ->
+rename_vars(Vs, L, RPO, Blocks0, Count0) ->
     {NewVars,Count} = new_vars([Base || #b_var{name=Base} <- Vs], Count0),
     Ren = zip(Vs, NewVars),
-    Blocks1 = beam_ssa:rename_vars(Ren, [L], Blocks0),
+    Blocks1 = beam_ssa:rename_vars(Ren, RPO, Blocks0),
     #b_blk{is=Is0} = Blk0 = map_get(L, Blocks1),
     CopyIs = [#b_set{op=copy,dst=New,args=[Old]} || {Old,New} <- Ren],
     Is = insert_after_phis(Is0, CopyIs),
@@ -2434,7 +2441,8 @@ frame_size(#st{frames=Frames,regs=Regs,ssa=Blocks0}=St) ->
     St#st{ssa=Blocks}.
 
 frame_size_1(L, Regs, Blocks0) ->
-    Def = beam_ssa:def([L], Blocks0),
+    RPO = beam_ssa:rpo([L], Blocks0),
+    Def = beam_ssa:def(RPO, Blocks0),
     Yregs0 = [map_get(V, Regs) || V <- Def, is_yreg(map_get(V, Regs))],
     Yregs = ordsets:from_list(Yregs0),
     FrameSize = length(ordsets:from_list(Yregs)),
@@ -2480,7 +2488,8 @@ turn_yregs(#st{frames=Frames,regs=Regs0,ssa=Blocks}=St) ->
     Regs1 = foldl(fun(L, A) ->
                           Blk = map_get(L, Blocks),
                           FrameSize = beam_ssa:get_anno(frame_size, Blk),
-                          Def = beam_ssa:def([L], Blocks),
+                          RPO = beam_ssa:rpo([L], Blocks),
+                          Def = beam_ssa:def(RPO, Blocks),
                           [turn_yregs_1(Def, FrameSize, Regs0)|A]
                   end, [], Frames),
     Regs = maps:merge(Regs0, maps:from_list(append(Regs1))),
-- 
2.26.2

openSUSE Build Service is sponsored by