File 4871-Improve-optimization-of-binary-matching.patch of Package erlang
From cadd19e84478edc6e62e6b125a4d37745e913ca8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Wed, 7 Dec 2022 12:30:53 +0100
Subject: [PATCH] Improve optimization of binary matching
The pattern matching compiler conservatively assumed that binary
patterns can never be re-ordered. Actually it is safe to re-order
clauses that match binaries if the first segment in each clause
match the same number of bits. Re-ordering clauses can help
generating better code and also help detect redundant clauses.
For the following code:
word(<<"AND">>) -> <<"and">>;
word(<<"AS">>) -> <<"as">>;
word(<<"A">>) -> <<"a">>;
word(<<"AS">>) -> <<"as">>.
the compiler will now generate the following warning:
t.erl:6:1: Warning: this clause cannot match because a previous clause at line 5 always matches
% 6| word(<<"AS">>) -> <<"as">>;
% | ^
The compiler will also generate slightly better code for the same
example without the redundant clause:
word(<<"AND">>) -> <<"and">>;
word(<<"AS">>) -> <<"as">>;
word(<<"A">>) -> <<"a">>.
Closes #6535
---
lib/compiler/src/v3_kernel.erl | 23 +++++++++++++++++++++--
lib/compiler/test/warnings_SUITE.erl | 7 ++++++-
2 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl
index b2ddf1afd5..70b2b56d68 100644
--- a/lib/compiler/src/v3_kernel.erl
+++ b/lib/compiler/src/v3_kernel.erl
@@ -1375,8 +1375,9 @@ select_bin_int([#iclause{pats=[#k_bin_seg{anno=A,type=integer,
true -> throw(not_possible);
false -> ok
end,
- Cs = select_bin_int_1(Cs0, Bits, Fl, Val),
- [{k_bin_int,[C#iclause{pats=[P|Ps]}|Cs]}];
+ Cs1 = [C#iclause{pats=[P|Ps]}|select_bin_int_1(Cs0, Bits, Fl, Val)],
+ Cs = reorder_bin_ints(Cs1),
+ [{k_bin_int,Cs}];
select_bin_int(_) -> throw(not_possible).
select_bin_int_1([#iclause{pats=[#k_bin_seg{anno=A,type=integer,
@@ -1419,6 +1420,24 @@ match_fun(Val) ->
{match,Bs}
end.
+reorder_bin_ints([_]=Cs) ->
+ Cs;
+reorder_bin_ints(Cs0) ->
+ %% It is safe to reorder clauses that matches binaries if the
+ %% first segments for all of them match the same number of bits.
+ Cs = sort([{reorder_bin_int_sort_key(C),C} || C <- Cs0]),
+ [C || {_,C} <- Cs].
+
+reorder_bin_int_sort_key(#iclause{pats=[Pats|_]}) ->
+ case Pats of
+ #k_bin_int{val=Val,next=#k_bin_end{}} ->
+ %% Sort before clauses with additional segments. This usually results in
+ %% better code.
+ [Val];
+ #k_bin_int{val=Val} ->
+ [Val,more]
+ end.
+
%% match_value([Var], Con, [Clause], Default, State) -> {SelectExpr,State}.
%% At this point all the clauses have the same constructor, we must
%% now separate them according to value.
diff --git a/lib/compiler/test/warnings_SUITE.erl b/lib/compiler/test/warnings_SUITE.erl
index 9b860de951..ed8e324377 100644
--- a/lib/compiler/test/warnings_SUITE.erl
+++ b/lib/compiler/test/warnings_SUITE.erl
@@ -159,10 +159,15 @@ pattern3(Config) when is_list(Config) ->
f({A,_}) -> {ok,A};
f([_|_]=B) -> {ok,B};
f({urk,nisse}) -> urka_glurka.
+ word(<<\"AND\">>) -> <<\"and\">>;
+ word(<<\"AS\">>) -> <<\"as\">>;
+ word(<<\"A\">>) -> <<\"a\">>;
+ word(<<\"AS\">>) -> <<\"as\">>.
">>,
[nowarn_unused_vars],
{warnings,
- [{{4,13},v3_kernel,{nomatch,{shadow,2}}}]}}],
+ [{{4,13},v3_kernel,{nomatch,{shadow,2}}},
+ {{8,13},v3_kernel,{nomatch,{shadow,6}}}]}}],
[] = run(Config, Ts),
ok.
--
2.35.3