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 From fa4f5ba69957ce79e5f7781af26d183cdb0b77b0 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sun, 24 Mar 2013 15:14:41 +0100 Subject: Add a new option +clint0 to the compiler This option makes the compiler run the Core Erlang linting pass before any optimization pass, which can crash if the given code has unbound variables, something that is detected by core_lint. --- lib/compiler/src/compile.erl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib/compiler/src') diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl index 497af2b52c..745f1d5cf9 100644 --- a/lib/compiler/src/compile.erl +++ b/lib/compiler/src/compile.erl @@ -599,7 +599,8 @@ standard_passes() -> core_passes() -> %% Optimization and transforms of Core Erlang code. - [{delay, + [{iff,clint0,?pass(core_lint_module)}, + {delay, [{unless,no_copt, [{core_old_inliner,fun test_old_inliner/1,fun core_old_inliner/1}, {iff,doldinline,{listing,"oldinline"}}, -- cgit v1.2.3