From 57d5d8450811eb7c79b1365ab13fec689f8decdd Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sun, 24 Mar 2013 14:40:24 +0100 Subject: 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 --- lib/compiler/src/v3_core.erl | 51 ++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 21 deletions(-) (limited to 'lib/compiler/src') 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) -> -- cgit v1.2.3