aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnthony Ramine <[email protected]>2013-03-24 14:40:24 +0100
committerAnthony Ramine <[email protected]>2013-03-28 09:18:01 +0100
commit57d5d8450811eb7c79b1365ab13fec689f8decdd (patch)
treef70ab870e453b8611f4f5ed5516a547a799f061e
parentf285ee66678ae8761dc82b5ba0c023dd759091fc (diff)
downloadotp-57d5d8450811eb7c79b1365ab13fec689f8decdd.tar.gz
otp-57d5d8450811eb7c79b1365ab13fec689f8decdd.tar.bz2
otp-57d5d8450811eb7c79b1365ab13fec689f8decdd.zip
Fix optimization of some binary comprehensions
If a variable bound in a generator is used as the size of a segment in the comprehension body, v3_core uses this variable in the code generated to compute the initial size given to the `bs_init_writable` primop before the variable is actually bound, as in: << <<0:S>> || S <- Slist >> Reported-By: Peer Stritzinger
-rw-r--r--lib/compiler/src/v3_core.erl51
-rw-r--r--lib/compiler/test/bs_bincomp_SUITE.erl3
2 files changed, 33 insertions, 21 deletions
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index 01042cc56f..eea54b30a2 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -1187,9 +1187,9 @@ list_gen_pattern(P0, Line, St) ->
bc_initial_size(E, Q, St0) ->
try
- {ElemSzExpr,ElemSzPre,St1} = bc_elem_size(E, St0),
+ {ElemSzExpr,ElemSzPre,EVs,St1} = bc_elem_size(E, St0),
{V,St2} = new_var(St1),
- {GenSzExpr,GenSzPre,St3} = bc_gen_size(Q, St2),
+ {GenSzExpr,GenSzPre,St3} = bc_gen_size(Q, EVs, St2),
case ElemSzExpr of
#c_literal{val=ElemSz} when ElemSz rem 8 =:= 0 ->
NumBytesExpr = #c_literal{val=ElemSz div 8},
@@ -1214,11 +1214,13 @@ bc_initial_size(E, Q, St0) ->
bc_elem_size({bin,_,El}, St0) ->
case bc_elem_size_1(El, 0, []) of
{Bits,[]} ->
- {#c_literal{val=Bits},[],St0};
+ {#c_literal{val=Bits},[],[],St0};
{Bits,Vars0} ->
[{U,V0}|Pairs] = sort(Vars0),
F = bc_elem_size_combine(Pairs, U, [V0], []),
- bc_mul_pairs(F, #c_literal{val=Bits}, [], St0)
+ Vs = [V || {_,#c_var{name=V}} <- Vars0],
+ {E,Pre,St} = bc_mul_pairs(F, #c_literal{val=Bits}, [], St0),
+ {E,Pre,Vs,St}
end.
bc_elem_size_1([{bin_element,_,_,{integer,_,N},Flags}|Es], Bits, Vars) ->
@@ -1260,11 +1262,11 @@ bc_add_list_1([H|T], Pre, E, St0) ->
bc_add_list_1([], Pre, E, St) ->
{E,reverse(Pre),St}.
-bc_gen_size(Q, St) ->
- bc_gen_size_1(Q, #c_literal{val=1}, [], St).
+bc_gen_size(Q, EVs, St) ->
+ bc_gen_size_1(Q, EVs, #c_literal{val=1}, [], St).
-bc_gen_size_1([{generate,L,El,Gen}|Qs], E0, Pre0, St0) ->
- bc_verify_non_filtering(El),
+bc_gen_size_1([{generate,L,El,Gen}|Qs], EVs, E0, Pre0, St0) ->
+ bc_verify_non_filtering(El, EVs),
case Gen of
{var,_,ListVar} ->
Lanno = lineno_anno(L, St0),
@@ -1275,16 +1277,16 @@ bc_gen_size_1([{generate,L,El,Gen}|Qs], E0, Pre0, St0) ->
name=#c_literal{val=length},
args=[#c_var{name=ListVar}]}},
{E,Pre,St} = bc_gen_size_mul(E0, LenVar, [Set|Pre0], St1),
- bc_gen_size_1(Qs, E, Pre, St);
+ bc_gen_size_1(Qs, EVs, E, Pre, St);
_ ->
%% The only expressions we handle is literal lists.
Len = bc_list_length(Gen, 0),
{E,Pre,St} = bc_gen_size_mul(E0, #c_literal{val=Len}, Pre0, St0),
- bc_gen_size_1(Qs, E, Pre, St)
+ bc_gen_size_1(Qs, EVs, E, Pre, St)
end;
-bc_gen_size_1([{b_generate,_,El,Gen}|Qs], E0, Pre0, St0) ->
- bc_verify_non_filtering(El),
- {MatchSzExpr,Pre1,St1} = bc_elem_size(El, St0),
+bc_gen_size_1([{b_generate,_,El,Gen}|Qs], EVs, E0, Pre0, St0) ->
+ bc_verify_non_filtering(El, EVs),
+ {MatchSzExpr,Pre1,_,St1} = bc_elem_size(El, St0),
Pre2 = reverse(Pre1, Pre0),
{ResVar,St2} = new_var(St1),
{BitSizeExpr,Pre3,St3} = bc_gen_bit_size(Gen, Pre2, St2),
@@ -1292,10 +1294,10 @@ bc_gen_size_1([{b_generate,_,El,Gen}|Qs], E0, Pre0, St0) ->
MatchSzExpr)},
Pre4 = [Div|Pre3],
{E,Pre,St} = bc_gen_size_mul(E0, ResVar, Pre4, St3),
- bc_gen_size_1(Qs, E, Pre, St);
-bc_gen_size_1([], E, Pre, St) ->
+ bc_gen_size_1(Qs, EVs, E, Pre, St);
+bc_gen_size_1([], _, E, Pre, St) ->
{E,reverse(Pre),St};
-bc_gen_size_1(_, _, _, _) ->
+bc_gen_size_1(_, _, _, _, _) ->
throw(impossible).
bc_gen_bit_size({var,L,V}, Pre0, St0) ->
@@ -1312,13 +1314,20 @@ bc_gen_bit_size({bin,_,_}=Bin, Pre, St) ->
bc_gen_bit_size(_, _, _) ->
throw(impossible).
-bc_verify_non_filtering({bin,_,Els}) ->
- foreach(fun({bin_element,_,{var,_,_},_,_}) -> ok;
+bc_verify_non_filtering({bin,_,Els}, EVs) ->
+ foreach(fun({bin_element,_,{var,_,V},_,_}) ->
+ case member(V, EVs) of
+ true -> throw(impossible);
+ false -> ok
+ end;
(_) -> throw(impossible)
end, Els);
-bc_verify_non_filtering({var,_,_}) ->
- ok;
-bc_verify_non_filtering(_) ->
+bc_verify_non_filtering({var,_,V}, EVs) ->
+ case member(V, EVs) of
+ true -> throw(impossible);
+ false -> ok
+ end;
+bc_verify_non_filtering(_, _) ->
throw(impossible).
bc_list_length({string,_,Str}, Len) ->
diff --git a/lib/compiler/test/bs_bincomp_SUITE.erl b/lib/compiler/test/bs_bincomp_SUITE.erl
index d39e340429..451a9b1e3b 100644
--- a/lib/compiler/test/bs_bincomp_SUITE.erl
+++ b/lib/compiler/test/bs_bincomp_SUITE.erl
@@ -282,6 +282,9 @@ sizes(Config) when is_list(Config) ->
?line <<1,2,3,0>> = Fun13(7),
?line <<1,2,3,0,0>> = Fun13(8),
+ <<0:3>> = cs_default(<< <<0:S>> || S <- [0,1,2] >>),
+ <<0:3>> = cs_default(<< <<0:S>> || <<S>> <= <<0,1,2>> >>),
+
?line {'EXIT',_} = (catch << <<C:4>> || <<C:8>> <= {1,2,3} >>),
?line cs_end(),