aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler/src/v3_kernel.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/compiler/src/v3_kernel.erl')
-rw-r--r--lib/compiler/src/v3_kernel.erl41
1 files changed, 38 insertions, 3 deletions
diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl
index b184987625..b69ad416db 100644
--- a/lib/compiler/src/v3_kernel.erl
+++ b/lib/compiler/src/v3_kernel.erl
@@ -81,7 +81,7 @@
-export([module/2,format_error/1]).
-import(lists, [map/2,foldl/3,foldr/3,mapfoldl/3,splitwith/2,member/2,
- keymember/3,keyfind/3]).
+ keymember/3,keyfind/3,partition/2]).
-import(ordsets, [add_element/2,del_element/2,union/2,union/1,subtract/2]).
-import(cerl, [c_tuple/1]).
@@ -1081,9 +1081,44 @@ select_bin_con(Cs0) ->
end, Cs0),
select_bin_con_1(Cs1).
+
select_bin_con_1(Cs) ->
try
- select_bin_int(Cs)
+ %% The usual way to match literals is to first extract the
+ %% value to a register, and then compare the register to the
+ %% literal value. Extracting the value is good if we need
+ %% compare it more than once.
+ %%
+ %% But we would like to combine the extracting and the
+ %% comparing into a single instruction if we know that
+ %% a binary segment must contain specific integer value
+ %% or the matching will fail, like in this example:
+ %%
+ %% <<42:8,...>> ->
+ %% <<42:8,...>> ->
+ %% .
+ %% .
+ %% .
+ %% <<42:8,...>> ->
+ %% <<>> ->
+ %%
+ %% The first segment must either contain the integer 42
+ %% or the binary must end for the match to succeed.
+ %%
+ %% The way we do is to replace the generic #k_bin_seg{}
+ %% record with a #k_bin_int{} record if all clauses will
+ %% select the same literal integer (except for one or more
+ %% clauses that will end the binary).
+
+ {BinSegs0,BinEnd} =
+ partition(fun (C) ->
+ clause_con(C) =:= k_bin_seg
+ end, Cs),
+ BinSegs = select_bin_int(BinSegs0),
+ case BinEnd of
+ [] -> BinSegs;
+ [_|_] -> BinSegs ++ [{k_bin_end,BinEnd}]
+ end
catch
throw:not_possible ->
select_bin_con_2(Cs)
@@ -1097,7 +1132,7 @@ select_bin_con_2([]) -> [].
%% select_bin_int([Clause]) -> {k_bin_int,[Clause]}
%% If the first pattern in each clause selects the same integer,
-%% rewrite all clauses to use #k_bin_int{} (which will later to
+%% rewrite all clauses to use #k_bin_int{} (which will later be
%% translated to a bs_match_string/4 instruction).
%%
%% If it is not possible to do this rewrite, a 'not_possible'