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