File 2071-beam_ssa_opt-Do-more-strength-reduction-in-ssa_opt_l.patch of Package erlang
From c6a806eee17fbf9ff60b34acfe464b38e988128a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Tue, 26 May 2020 09:41:29 +0200
Subject: [PATCH 1/3] beam_ssa_opt: Do more strength reduction in ssa_opt_live
---
lib/compiler/src/beam_ssa_opt.erl | 37 ++++++++++++++++++++++---------
lib/compiler/test/map_SUITE.erl | 13 +++++++++++
2 files changed, 39 insertions(+), 11 deletions(-)
diff --git a/lib/compiler/src/beam_ssa_opt.erl b/lib/compiler/src/beam_ssa_opt.erl
index d77b7756e8..3c8f409e0b 100644
--- a/lib/compiler/src/beam_ssa_opt.erl
+++ b/lib/compiler/src/beam_ssa_opt.erl
@@ -1342,23 +1342,38 @@ live_opt_is([#b_set{op=phi,dst=Dst}=I|Is], Live, Acc) ->
false ->
live_opt_is(Is, Live, Acc)
end;
-live_opt_is([#b_set{op={succeeded,_},dst=SuccDst,args=[MapDst]}=SuccI,
- #b_set{op=get_map_element,dst=MapDst}=MapI | Is],
+live_opt_is([#b_set{op={succeeded,guard},dst=SuccDst,args=[Dst]}=SuccI,
+ #b_set{op=Op,dst=Dst}=I0|Is],
Live0, Acc) ->
case {gb_sets:is_member(SuccDst, Live0),
- gb_sets:is_member(MapDst, Live0)} of
+ gb_sets:is_member(Dst, Live0)} of
{true, true} ->
Live = gb_sets:delete(SuccDst, Live0),
- live_opt_is([MapI | Is], Live, [SuccI | Acc]);
+ live_opt_is([I0|Is], Live, [SuccI|Acc]);
{true, false} ->
- %% 'get_map_element' is unused; replace 'succeeded' with
- %% 'has_map_field'
- NewI = MapI#b_set{op=has_map_field,dst=SuccDst},
- live_opt_is([NewI | Is], Live0, Acc);
+ %% The result of the instruction before {succeeded,guard} is
+ %% unused. Attempt to perform a strength reduction.
+ case Op of
+ {bif,'not'} ->
+ I = I0#b_set{op={bif,is_boolean},dst=SuccDst},
+ live_opt_is([I|Is], Live0, Acc);
+ {bif,tuple_size} ->
+ I = I0#b_set{op={bif,is_tuple},dst=SuccDst},
+ live_opt_is([I|Is], Live0, Acc);
+ bs_start_match ->
+ [#b_literal{val=new},Bin] = I0#b_set.args,
+ I = I0#b_set{op={bif,is_bitstring},args=[Bin],dst=SuccDst},
+ live_opt_is([I|Is], Live0, Acc);
+ get_map_element ->
+ I = I0#b_set{op=has_map_field,dst=SuccDst},
+ live_opt_is([I|Is], Live0, Acc);
+ _ ->
+ Live1 = gb_sets:delete(SuccDst, Live0),
+ Live = gb_sets:add(Dst, Live1),
+ live_opt_is([I0|Is], Live, [SuccI|Acc])
+ end;
{false, true} ->
- %% 'succeeded' is unused (we know it will succeed); discard it and
- %% keep 'get_map_element'
- live_opt_is([MapI | Is], Live0, Acc);
+ live_opt_is([I0|Is], Live0, Acc);
{false, false} ->
live_opt_is(Is, Live0, Acc)
end;
diff --git a/lib/compiler/test/map_SUITE.erl b/lib/compiler/test/map_SUITE.erl
index 3c5c6214bc..d0455877f5 100644
--- a/lib/compiler/test/map_SUITE.erl
+++ b/lib/compiler/test/map_SUITE.erl
@@ -1263,6 +1263,10 @@ t_guard_bifs(Config) when is_list(Config) ->
true = map_is_key_head_not(#{}),
false = map_is_key_head_not(not_a_map),
+ b = map_get_head_badmap1(),
+ b = map_get_head_badmap2(),
+ b = map_get_head_badmap3(),
+
true = map_guard_body(#{a=>1}),
false = map_guard_body({}),
true = map_guard_pattern(#{a=>1, <<"hi">> => "hi" }),
@@ -1337,6 +1341,15 @@ map_get_head(_) -> false.
map_get_head_not(M) when not map_get(a, M) -> true;
map_get_head_not(_) -> false.
+map_get_head_badmap1() when map_get(key, not_a_map), false -> a;
+map_get_head_badmap1() -> b.
+
+map_get_head_badmap2() when map_get(key, not_a_map), true -> a;
+map_get_head_badmap2() -> b.
+
+map_get_head_badmap3() when map_get(key, not_a_map) -> a;
+map_get_head_badmap3() -> b.
+
map_is_key_head(M) when is_map_key(a, M) -> true;
map_is_key_head(_) -> false.
--
2.26.2