File 2865-Move-map-optimizations-from-beam_peep-to-beam_block.patch of Package erlang

From 9bdec7da24722a13c0fe870ffd64c29f3635fff3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Fri, 20 Aug 2021 07:07:55 +0200
Subject: [PATCH 5/7] Move map optimizations from beam_peep to beam_block

As a preparation for removing the beam_peep pass, move the remaining
useful optimizations to beam_block.
---
 lib/compiler/src/beam_block.erl | 71 ++++++++++++++++++++++++++++++++-
 1 file changed, 69 insertions(+), 2 deletions(-)

diff --git a/lib/compiler/src/beam_block.erl b/lib/compiler/src/beam_block.erl
index e8d024b20b..3b191db676 100644
--- a/lib/compiler/src/beam_block.erl
+++ b/lib/compiler/src/beam_block.erl
@@ -22,7 +22,8 @@
 -module(beam_block).
 
 -export([module/2]).
--import(lists, [keysort/2,reverse/1,reverse/2,splitwith/2]).
+-import(lists, [keysort/2,member/2,reverse/1,reverse/2,
+                splitwith/2,usort/1]).
 
 -spec module(beam_utils:module_code(), [compile:option()]) ->
                     {'ok',beam_utils:module_code()}.
@@ -35,7 +36,8 @@ function({function,Name,Arity,CLabel,Is0}) ->
     try
         Is1 = swap_opt(Is0),
         Is2 = blockify(Is1),
-        Is = embed_lines(Is2),
+        Is3 = embed_lines(Is2),
+        Is = opt_maps(Is3),
         {function,Name,Arity,CLabel,Is}
     catch
         Class:Error:Stack ->
@@ -216,3 +218,68 @@ sort_on_yreg([{set,[Dst],[Src],move}|_]=Moves) ->
         {{x,_},{y,_}} ->
             keysort(3, Moves)
     end.
+
+%%%
+%%% Coalesce adjacent get_map_elements and has_map_fields instructions.
+%%%
+
+opt_maps(Is) ->
+    opt_maps(Is, []).
+
+opt_maps([{get_map_elements,Fail,Src,List}=I|Is], Acc0) ->
+    case simplify_get_map_elements(Fail, Src, List, Acc0) of
+        {ok,Acc} ->
+            opt_maps(Is, Acc);
+        error ->
+            opt_maps(Is, [I|Acc0])
+    end;
+opt_maps([{test,has_map_fields,Fail,Ops}=I|Is], Acc0) ->
+    case simplify_has_map_fields(Fail, Ops, Acc0) of
+        {ok,Acc} ->
+            opt_maps(Is, Acc);
+        error ->
+            opt_maps(Is, [I|Acc0])
+    end;
+opt_maps([I|Is], Acc) ->
+    opt_maps(Is, [I|Acc]);
+opt_maps([], Acc) -> reverse(Acc).
+
+simplify_get_map_elements(Fail, Src, {list,[Key,Dst]},
+                          [{get_map_elements,Fail,Src,{list,List1}}|Acc]) ->
+    case are_keys_literals([Key]) andalso are_keys_literals(List1) andalso
+        not is_source_overwritten(Src, List1) of
+        true ->
+            case member(Key, List1) of
+                true ->
+                    %% The key is already in the other list. That is
+                    %% very unusual, because there are optimizations to get
+                    %% rid of duplicate keys. Therefore, don't try to
+                    %% do anything smart here; just keep the
+                    %% get_map_elements instructions separate.
+                    error;
+                false ->
+                    List = [Key,Dst|List1],
+                    {ok,[{get_map_elements,Fail,Src,{list,List}}|Acc]}
+            end;
+        false ->
+            error
+    end;
+simplify_get_map_elements(_, _, _, _) -> error.
+
+simplify_has_map_fields(Fail, [Src|Keys0],
+                        [{test,has_map_fields,Fail,[Src|Keys1]}|Acc]) ->
+    case are_keys_literals(Keys0) andalso are_keys_literals(Keys1) of
+        true ->
+            Keys = usort(Keys0 ++ Keys1),
+            {ok,[{test,has_map_fields,Fail,[Src|Keys]}|Acc]};
+        false ->
+            error
+    end;
+simplify_has_map_fields(_, _, _) -> error.
+
+are_keys_literals([{x,_}|_]) -> false;
+are_keys_literals([{y,_}|_]) -> false;
+are_keys_literals([_|_]) -> true.
+
+is_source_overwritten(Src, [_Key,Src]) -> true;
+is_source_overwritten(_, _) -> false.
-- 
2.31.1

openSUSE Build Service is sponsored by