aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/compiler/src/beam_ssa.erl32
-rw-r--r--lib/compiler/src/beam_ssa_opt.erl17
-rw-r--r--lib/compiler/test/match_SUITE.erl12
3 files changed, 46 insertions, 15 deletions
diff --git a/lib/compiler/src/beam_ssa.erl b/lib/compiler/src/beam_ssa.erl
index 2ce00990e0..fc13ba06de 100644
--- a/lib/compiler/src/beam_ssa.erl
+++ b/lib/compiler/src/beam_ssa.erl
@@ -28,6 +28,7 @@
linearize/1,
mapfold_instrs_rpo/4,
normalize/1,
+ no_side_effect/1,
predecessors/1,
rename_vars/3,
rpo/1,rpo/2,
@@ -152,6 +153,37 @@ clobbers_xregs(#b_set{op=Op}) ->
_ -> false
end.
+%% no_side_effect(#b_set{}) -> true|false.
+%% Test whether this instruction has no side effect and thus is safe
+%% not to execute if its value is not used. Note that even if `true`
+%% is returned, the instruction could still be impure (e.g. bif:get).
+
+-spec no_side_effect(b_set()) -> boolean().
+
+no_side_effect(#b_set{op=Op}) ->
+ case Op of
+ {bif,_} -> true;
+ {float,get} -> true;
+ bs_init -> true;
+ bs_extract -> true;
+ bs_match -> true;
+ bs_start_match -> true;
+ bs_test_tail -> true;
+ bs_put -> true;
+ extract -> true;
+ get_hd -> true;
+ get_tl -> true;
+ get_tuple_element -> true;
+ has_map_field -> true;
+ is_nonempty_list -> true;
+ is_tagged_tuple -> true;
+ put_map -> true;
+ put_list -> true;
+ put_tuple -> true;
+ succeeded -> true;
+ _ -> false
+ end.
+
-spec predecessors(Blocks) -> #{BlockNumber:=[Predecessor]} when
Blocks :: block_map(),
BlockNumber :: label(),
diff --git a/lib/compiler/src/beam_ssa_opt.erl b/lib/compiler/src/beam_ssa_opt.erl
index 257e036719..5f3777072a 100644
--- a/lib/compiler/src/beam_ssa_opt.erl
+++ b/lib/compiler/src/beam_ssa_opt.erl
@@ -769,14 +769,14 @@ live_opt_is([#b_set{op=succeeded,dst=#b_var{name=SuccDst}=SuccDstVar,
end
end
end;
-live_opt_is([#b_set{op=Op,dst=#b_var{name=Dst}}=I|Is], Live0, Acc) ->
+live_opt_is([#b_set{dst=#b_var{name=Dst}}=I|Is], Live0, Acc) ->
case gb_sets:is_member(Dst, Live0) of
true ->
Live1 = gb_sets:union(Live0, gb_sets:from_ordset(beam_ssa:used(I))),
Live = gb_sets:delete_any(Dst, Live1),
live_opt_is(Is, Live, [I|Acc]);
false ->
- case is_pure(Op) of
+ case beam_ssa:no_side_effect(I) of
true ->
live_opt_is(Is, Live0, Acc);
false ->
@@ -787,19 +787,6 @@ live_opt_is([#b_set{op=Op,dst=#b_var{name=Dst}}=I|Is], Live0, Acc) ->
live_opt_is([], Live, Acc) ->
{Acc,Live}.
-is_pure({bif,_}) -> true;
-is_pure({float,get}) -> true;
-is_pure(bs_extract) -> true;
-is_pure(extract) -> true;
-is_pure(get_hd) -> true;
-is_pure(get_tl) -> true;
-is_pure(get_tuple_element) -> true;
-is_pure(is_nonempty_list) -> true;
-is_pure(is_tagged_tuple) -> true;
-is_pure(put_list) -> true;
-is_pure(put_tuple) -> true;
-is_pure(_) -> false.
-
live_opt_unused(#b_set{op=get_map_element}=Set) ->
{replace,Set#b_set{op=has_map_field}};
live_opt_unused(_) -> keep.
diff --git a/lib/compiler/test/match_SUITE.erl b/lib/compiler/test/match_SUITE.erl
index e3f842b668..46b543728d 100644
--- a/lib/compiler/test/match_SUITE.erl
+++ b/lib/compiler/test/match_SUITE.erl
@@ -254,6 +254,8 @@ non_matching_aliases(_Config) ->
none = mixed_aliases([d]),
none = mixed_aliases({a,42}),
none = mixed_aliases(42),
+ none = mixed_aliases(<<6789:16>>),
+ none = mixed_aliases(#{key=>value}),
{'EXIT',{{badmatch,42},_}} = (catch nomatch_alias(42)),
{'EXIT',{{badmatch,job},_}} = (catch entirely()),
@@ -279,6 +281,16 @@ mixed_aliases(<<X:8>> = x) -> {a,X};
mixed_aliases([b] = <<X:8>>) -> {b,X};
mixed_aliases(<<X:8>> = {a,X}) -> {c,X};
mixed_aliases([X] = <<X:8>>) -> {d,X};
+mixed_aliases(<<X:16>> = X) -> {e,X};
+mixed_aliases(X = <<X:16>>) -> {f,X};
+mixed_aliases(<<X:16,_/binary>> = X) -> {g,X};
+mixed_aliases(X = <<X:16,_/binary>>) -> {h,X};
+mixed_aliases(X = #{key:=X}) -> {i,X};
+mixed_aliases(#{key:=X} = X) -> {j,X};
+mixed_aliases([X] = #{key:=X}) -> {k,X};
+mixed_aliases(#{key:=X} = [X]) -> {l,X};
+mixed_aliases({a,X} = #{key:=X}) -> {m,X};
+mixed_aliases(#{key:=X} = {a,X}) -> {n,X};
mixed_aliases(_) -> none.
nomatch_alias(I) ->