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

openSUSE Build Service is sponsored by