diff options
Diffstat (limited to 'lib/compiler')
-rw-r--r-- | lib/compiler/src/beam_receive.erl | 92 | ||||
-rw-r--r-- | lib/compiler/src/beam_utils.erl | 94 | ||||
-rw-r--r-- | lib/compiler/src/compile.erl | 3 | ||||
-rw-r--r-- | lib/compiler/src/v3_core.erl | 51 | ||||
-rw-r--r-- | lib/compiler/test/andor_SUITE.erl | 33 | ||||
-rw-r--r-- | lib/compiler/test/bs_bincomp_SUITE.erl | 3 | ||||
-rw-r--r-- | lib/compiler/test/receive_SUITE.erl | 13 | ||||
-rw-r--r-- | lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.S | 71 | ||||
-rw-r--r-- | lib/compiler/test/receive_SUITE_data/ref_opt/yes_5.erl | 6 |
9 files changed, 237 insertions, 129 deletions
diff --git a/lib/compiler/src/beam_receive.erl b/lib/compiler/src/beam_receive.erl index 3dd5ed182e..97a9188ee7 100644 --- a/lib/compiler/src/beam_receive.erl +++ b/lib/compiler/src/beam_receive.erl @@ -151,20 +151,20 @@ opt_recv(Is, Regs, D) -> opt_recv([{label,L}=Lbl,{loop_rec,{f,Fail},_}=Loop|Is], D, R0, _, Acc) -> R = regs_kill_not_live(0, R0), - case regs_to_list(R) of - [{y,_}=RefReg] -> - %% We now have the new reference in the Y register RefReg + case regs_empty(R) of + false -> + %% We now have the new reference in Y registers %% and the current instruction is the beginning of a %% receive statement. We must now verify that only messages %% that contain the reference will be matched. - case opt_ref_used(Is, RefReg, Fail, D) of + case opt_ref_used(Is, R, Fail, D) of false -> no; true -> RecvSet = {recv_set,{f,L}}, {yes,reverse(Acc, [RecvSet,Lbl,Loop|Is]),L} end; - [] -> + true -> no end; opt_recv([I|Is], D, R0, L0, Acc) -> @@ -226,9 +226,9 @@ opt_update_regs_bl([{set,Ds,_,_}|Is], Regs0) -> opt_update_regs_bl(Is, Regs); opt_update_regs_bl([], Regs) -> Regs. -%% opt_ref_used([Instruction], RefRegister, FailLabel, LabelIndex) -> true|false +%% opt_ref_used([Instruction], RefRegs, FailLabel, LabelIndex) -> true|false %% Return 'true' if it is certain that only messages that contain the same -%% reference as in RefRegister can be matched out. Otherwise return 'false'. +%% reference as in RefRegs can be matched out. Otherwise return 'false'. %% %% Basically, we follow all possible paths through the receive statement. %% If all paths are safe, we return 'true'. @@ -236,7 +236,7 @@ opt_update_regs_bl([], Regs) -> Regs. %% A branch to FailLabel is safe, because it exits the receive statement %% and no further message may be matched out. %% -%% If a path hits an comparision between RefRegister and part of the message, +%% If a path hits an comparision between RefRegs and part of the message, %% that path is safe (any messages that may be matched further down the %% path is guaranteed to contain the reference). %% @@ -245,11 +245,11 @@ opt_update_regs_bl([], Regs) -> Regs. %% we hit an unrecognized instruction, we also give up and return %% 'false' (the optimization may be unsafe). -opt_ref_used(Is, RefReg, Fail, D) -> +opt_ref_used(Is, RefRegs, Fail, D) -> Done = gb_sets:singleton(Fail), Regs = regs_init_x0(), try - _ = opt_ref_used_1(Is, RefReg, D, Done, Regs), + _ = opt_ref_used_1(Is, RefRegs, D, Done, Regs), true catch throw:not_used -> @@ -258,37 +258,39 @@ opt_ref_used(Is, RefReg, Fail, D) -> %% This functions only returns if all paths through the receive %% statement are safe, and throws an 'not_used' term otherwise. -opt_ref_used_1([{block,Bl}|Is], RefReg, D, Done, Regs0) -> +opt_ref_used_1([{block,Bl}|Is], RefRegs, D, Done, Regs0) -> Regs = opt_ref_used_bl(Bl, Regs0), - opt_ref_used_1(Is, RefReg, D, Done, Regs); -opt_ref_used_1([{test,is_eq_exact,{f,Fail},Args}|Is], RefReg, D, Done0, Regs) -> - Done = opt_ref_used_at(Fail, RefReg, D, Done0, Regs), - case is_ref_msg_comparison(Args, RefReg, Regs) of + opt_ref_used_1(Is, RefRegs, D, Done, Regs); +opt_ref_used_1([{test,is_eq_exact,{f,Fail},Args}|Is], + RefRegs, D, Done0, Regs) -> + Done = opt_ref_used_at(Fail, RefRegs, D, Done0, Regs), + case is_ref_msg_comparison(Args, RefRegs, Regs) of false -> - opt_ref_used_1(Is, RefReg, D, Done, Regs); + opt_ref_used_1(Is, RefRegs, D, Done, Regs); true -> %% The instructions that follow (Is) can only be executed - %% if the message contains the same reference as in RefReg. + %% if the message contains the same reference as in RefRegs. Done end; -opt_ref_used_1([{test,is_ne_exact,{f,Fail},Args}|Is], RefReg, D, Done0, Regs) -> - Done = opt_ref_used_1(Is, RefReg, D, Done0, Regs), - case is_ref_msg_comparison(Args, RefReg, Regs) of +opt_ref_used_1([{test,is_ne_exact,{f,Fail},Args}|Is], + RefRegs, D, Done0, Regs) -> + Done = opt_ref_used_1(Is, RefRegs, D, Done0, Regs), + case is_ref_msg_comparison(Args, RefRegs, Regs) of false -> - opt_ref_used_at(Fail, RefReg, D, Done, Regs); + opt_ref_used_at(Fail, RefRegs, D, Done, Regs); true -> Done end; -opt_ref_used_1([{test,_,{f,Fail},_}|Is], RefReg, D, Done0, Regs) -> - Done = opt_ref_used_at(Fail, RefReg, D, Done0, Regs), - opt_ref_used_1(Is, RefReg, D, Done, Regs); -opt_ref_used_1([{select,_,_,{f,Fail},List}|_], RefReg, D, Done, Regs) -> +opt_ref_used_1([{test,_,{f,Fail},_}|Is], RefRegs, D, Done0, Regs) -> + Done = opt_ref_used_at(Fail, RefRegs, D, Done0, Regs), + opt_ref_used_1(Is, RefRegs, D, Done, Regs); +opt_ref_used_1([{select,_,_,{f,Fail},List}|_], RefRegs, D, Done, Regs) -> Lbls = [F || {f,F} <- List] ++ [Fail], - opt_ref_used_in_all(Lbls, RefReg, D, Done, Regs); -opt_ref_used_1([{label,Lbl}|Is], RefReg, D, Done, Regs) -> + opt_ref_used_in_all(Lbls, RefRegs, D, Done, Regs); +opt_ref_used_1([{label,Lbl}|Is], RefRegs, D, Done, Regs) -> case gb_sets:is_member(Lbl, Done) of true -> Done; - false -> opt_ref_used_1(Is, RefReg, D, Done, Regs) + false -> opt_ref_used_1(Is, RefRegs, D, Done, Regs) end; opt_ref_used_1([{loop_rec_end,_}|_], _, _, Done, _) -> Done; @@ -296,27 +298,25 @@ opt_ref_used_1([_I|_], _RefReg, _D, _Done, _Regs) -> %% The optimization may be unsafe. throw(not_used). -%% is_ref_msg_comparison(Args, RefReg, RegisterSet) -> true|false. +%% is_ref_msg_comparison(Args, RefRegs, RegisterSet) -> true|false. %% Return 'true' if Args denotes a comparison between the %% reference and message or part of the message. -is_ref_msg_comparison([R,RefReg], RefReg, Regs) -> - regs_is_member(R, Regs); -is_ref_msg_comparison([RefReg,R], RefReg, Regs) -> - regs_is_member(R, Regs); -is_ref_msg_comparison([_,_], _, _) -> false. - -opt_ref_used_in_all([L|Ls], RefReg, D, Done0, Regs) -> - Done = opt_ref_used_at(L, RefReg, D, Done0, Regs), - opt_ref_used_in_all(Ls, RefReg, D, Done, Regs); +is_ref_msg_comparison([R1,R2], RefRegs, Regs) -> + (regs_is_member(R2, RefRegs) andalso regs_is_member(R1, Regs)) orelse + (regs_is_member(R1, RefRegs) andalso regs_is_member(R2, Regs)). + +opt_ref_used_in_all([L|Ls], RefRegs, D, Done0, Regs) -> + Done = opt_ref_used_at(L, RefRegs, D, Done0, Regs), + opt_ref_used_in_all(Ls, RefRegs, D, Done, Regs); opt_ref_used_in_all([], _, _, Done, _) -> Done. -opt_ref_used_at(Fail, RefReg, D, Done0, Regs) -> +opt_ref_used_at(Fail, RefRegs, D, Done0, Regs) -> case gb_sets:is_member(Fail, Done0) of true -> Done0; false -> Is = beam_utils:code_at(Fail, D), - Done = opt_ref_used_1(Is, RefReg, D, Done0, Regs), + Done = opt_ref_used_1(Is, RefRegs, D, Done0, Regs), gb_sets:add(Fail, Done) end. @@ -408,15 +408,3 @@ regs_all_members([], _) -> true. regs_is_member({x,N}, {Regs,_}) -> Regs band (1 bsl N) =/= 0; regs_is_member({y,N}, {_,Regs}) -> Regs band (1 bsl N) =/= 0; regs_is_member(_, _) -> false. - -%% regs_to_list(RegisterSet) -> [Register] -%% Convert the register set to an explicit list of registers. -regs_to_list({Xregs,Yregs}) -> - regs_to_list_1(Xregs, 0, x, regs_to_list_1(Yregs, 0, y, [])). - -regs_to_list_1(0, _, _, Acc) -> - Acc; -regs_to_list_1(Regs, N, Tag, Acc) when (Regs band 1) =:= 1 -> - regs_to_list_1(Regs bsr 1, N+1, Tag, [{Tag,N}|Acc]); -regs_to_list_1(Regs, N, Tag, Acc) -> - regs_to_list_1(Regs bsr 1, N+1, Tag, Acc). diff --git a/lib/compiler/src/beam_utils.erl b/lib/compiler/src/beam_utils.erl index 8af0447f63..554c14f57a 100644 --- a/lib/compiler/src/beam_utils.erl +++ b/lib/compiler/src/beam_utils.erl @@ -61,7 +61,7 @@ is_killed_block(R, Is) -> %% to determine the kill state across branches. is_killed(R, Is, D) -> - St = #live{bl=fun check_killed_block/2,lbl=D,res=gb_trees:empty()}, + St = #live{bl=check_killed_block_fun(),lbl=D,res=gb_trees:empty()}, case check_liveness(R, Is, St) of {killed,_} -> true; {used,_} -> false; @@ -72,7 +72,7 @@ is_killed(R, Is, D) -> %% Determine whether Reg is killed at label Lbl. is_killed_at(R, Lbl, D) when is_integer(Lbl) -> - St0 = #live{bl=fun check_killed_block/2,lbl=D,res=gb_trees:empty()}, + St0 = #live{bl=check_killed_block_fun(),lbl=D,res=gb_trees:empty()}, case check_liveness_at(R, Lbl, St0) of {killed,_} -> true; {used,_} -> false; @@ -87,7 +87,7 @@ is_killed_at(R, Lbl, D) when is_integer(Lbl) -> %% across branches. is_not_used(R, Is, D) -> - St = #live{bl=check_used_block_fun(D),lbl=D,res=gb_trees:empty()}, + St = #live{bl=fun check_used_block/3,lbl=D,res=gb_trees:empty()}, case check_liveness(R, Is, St) of {killed,_} -> true; {used,_} -> false; @@ -102,7 +102,7 @@ is_not_used(R, Is, D) -> %% across branches. is_not_used_at(R, Lbl, D) -> - St = #live{bl=check_used_block_fun(D),lbl=D,res=gb_trees:empty()}, + St = #live{bl=fun check_used_block/3,lbl=D,res=gb_trees:empty()}, case check_liveness_at(R, Lbl, St) of {killed,_} -> true; {used,_} -> false; @@ -246,10 +246,10 @@ combine_heap_needs(H1, H2) when is_integer(H1), is_integer(H2) -> check_liveness(R, [{set,_,_,_}=I|_], St) -> erlang:error(only_allowed_in_blocks, [R,I,St]); -check_liveness(R, [{block,Blk}|Is], #live{bl=BlockCheck}=St) -> - case BlockCheck(R, Blk) of - transparent -> check_liveness(R, Is, St); - Other when is_atom(Other) -> {Other,St} +check_liveness(R, [{block,Blk}|Is], #live{bl=BlockCheck}=St0) -> + case BlockCheck(R, Blk, St0) of + {transparent,St} -> check_liveness(R, Is, St); + {Other,_}=Res when is_atom(Other) -> Res end; check_liveness(R, [{label,_}|Is], St) -> check_liveness(R, Is, St); @@ -533,6 +533,9 @@ check_liveness_fail(R, Op, Args, Fail, St) -> %% %% (Unknown instructions will cause an exception.) +check_killed_block_fun() -> + fun(R, Is, St) -> {check_killed_block(R, Is),St} end. + check_killed_block({x,X}, [{set,_,_,{alloc,Live,_}}|_]) -> if X >= Live -> killed; @@ -563,50 +566,51 @@ check_killed_block(_, []) -> transparent. %% %% (Unknown instructions will cause an exception.) -check_used_block_fun(D) -> - fun(R, Is) -> check_used_block(R, Is, D) end. - -check_used_block({x,X}=R, [{set,Ds,Ss,{alloc,Live,Op}}|Is], D) -> +check_used_block({x,X}=R, [{set,Ds,Ss,{alloc,Live,Op}}|Is], St) -> if - X >= Live -> killed; + X >= Live -> {killed,St}; + true -> check_used_block_1(R, Ss, Ds, Op, Is, St) + end; +check_used_block(R, [{set,Ds,Ss,Op}|Is], St) -> + check_used_block_1(R, Ss, Ds, Op, Is, St); +check_used_block(R, [{'%live',Live}|Is], St) -> + case R of + {x,X} when X >= Live -> {killed,St}; + _ -> check_used_block(R, Is, St) + end; +check_used_block(_, [], St) -> {transparent,St}. + +check_used_block_1(R, Ss, Ds, Op, Is, St0) -> + case member(R, Ss) of true -> - case member(R, Ss) orelse - is_reg_used_at(R, Op, D) of - true -> used; - false -> + {used,St0}; + false -> + case is_reg_used_at(R, Op, St0) of + {true,St} -> + {used,St}; + {false,St} -> case member(R, Ds) of - true -> killed; - false -> check_used_block(R, Is, D) + true -> {killed,St}; + false -> check_used_block(R, Is, St) end end - end; -check_used_block(R, [{set,Ds,Ss,Op}|Is], D) -> - case member(R, Ss) orelse - is_reg_used_at(R, Op, D) of - true -> used; - false -> - case member(R, Ds) of - true -> killed; - false -> check_used_block(R, Is, D) - end - end; -check_used_block(R, [{'%live',Live}|Is], D) -> - case R of - {x,X} when X >= Live -> killed; - _ -> check_used_block(R, Is, D) - end; -check_used_block(_, [], _) -> transparent. + end. -is_reg_used_at(R, {gc_bif,_,{f,Lbl}}, D) -> - is_reg_used_at_1(R, Lbl, D); -is_reg_used_at(R, {bif,_,{f,Lbl}}, D) -> - is_reg_used_at_1(R, Lbl, D); -is_reg_used_at(_, _, _) -> false. +is_reg_used_at(R, {gc_bif,_,{f,Lbl}}, St) -> + is_reg_used_at_1(R, Lbl, St); +is_reg_used_at(R, {bif,_,{f,Lbl}}, St) -> + is_reg_used_at_1(R, Lbl, St); +is_reg_used_at(_, _, St) -> + {false,St}. -is_reg_used_at_1(_, 0, _) -> - false; -is_reg_used_at_1(R, Lbl, D) -> - not is_not_used_at(R, Lbl, D). +is_reg_used_at_1(_, 0, St) -> + {false,St}; +is_reg_used_at_1(R, Lbl, St0) -> + case check_liveness_at(R, Lbl, St0) of + {killed,St} -> {false,St}; + {used,St} -> {true,St}; + {unknown,St} -> {true,St} + end. index_labels_1([{label,Lbl}|Is0], Acc) -> Is = lists:dropwhile(fun({label,_}) -> true; 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"}}, 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/andor_SUITE.erl b/lib/compiler/test/andor_SUITE.erl index 0d00769704..4ffbe07e32 100644 --- a/lib/compiler/test/andor_SUITE.erl +++ b/lib/compiler/test/andor_SUITE.erl @@ -21,7 +21,8 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, t_case/1,t_and_or/1,t_andalso/1,t_orelse/1,inside/1,overlap/1, - combined/1,in_case/1,before_and_inside_if/1]). + combined/1,in_case/1,before_and_inside_if/1, + slow_compilation/1]). -include_lib("test_server/include/test_server.hrl"). @@ -472,6 +473,36 @@ before_and_inside_if_2(XDo1, XDo2, Do3) -> end, {CH1,CH2}. + +-record(state, {stack = []}). + +slow_compilation(_) -> + %% The function slow_compilation_1 used to compile very slowly. + ok = slow_compilation_1({a}, #state{}). + +slow_compilation_1(T1, #state{stack = [T2|_]}) + when element(1, T2) == a, element(1, T1) == b, element(1, T1) == c -> + ok; +slow_compilation_1(T, _) + when element(1, T) == a1; element(1, T) == b1; element(1, T) == c1 -> + ok; +slow_compilation_1(T, _) + when element(1, T) == a2; element(1, T) == b2; element(1, T) == c2 -> + ok; +slow_compilation_1(T, _) when element(1, T) == a -> + ok; +slow_compilation_1(T, _) + when + element(1, T) == a, + (element(1, T) == b) and (element(1, T) == c) -> + ok; +slow_compilation_1(_, T) when element(1, T) == a -> + ok; +slow_compilation_1(_, T) when element(1, T) == b -> + ok; +slow_compilation_1(T, _) when element(1, T) == a -> + ok. + %% Utilities. check(V1, V0) -> 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(), diff --git a/lib/compiler/test/receive_SUITE.erl b/lib/compiler/test/receive_SUITE.erl index b91f2922fb..e60584d4ab 100644 --- a/lib/compiler/test/receive_SUITE.erl +++ b/lib/compiler/test/receive_SUITE.erl @@ -188,7 +188,7 @@ ref_opt(Config) when is_list(Config) -> ref_opt_1(Config) -> ?line DataDir = ?config(data_dir, Config), ?line PrivDir = ?config(priv_dir, Config), - ?line Sources = filelib:wildcard(filename:join([DataDir,"ref_opt","*.erl"])), + Sources = filelib:wildcard(filename:join([DataDir,"ref_opt","*.{erl,S}"])), ?line test_lib:p_run(fun(Src) -> do_ref_opt(Src, PrivDir) end, Sources), @@ -196,10 +196,15 @@ ref_opt_1(Config) -> do_ref_opt(Source, PrivDir) -> try - {ok,Mod} = c:c(Source, [{outdir,PrivDir}]), + Ext = filename:extension(Source), + {ok,Mod} = compile:file(Source, [report_errors,report_warnings, + {outdir,PrivDir}] ++ + [from_asm || Ext =:= ".S" ]), + Base = filename:rootname(filename:basename(Source), Ext), + code:purge(list_to_atom(Base)), + BeamFile = filename:join(PrivDir, Base), + code:load_abs(BeamFile), ok = Mod:Mod(), - Base = filename:rootname(filename:basename(Source), ".erl"), - BeamFile = filename:join(PrivDir, Base), {beam_file,Mod,_,_,_,Code} = beam_disasm:file(BeamFile), case Base of "no_"++_ -> diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.S b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.S new file mode 100644 index 0000000000..fd14228135 --- /dev/null +++ b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.S @@ -0,0 +1,71 @@ +{module, yes_14}. %% version = 0 + +{exports, [{f,2},{module_info,0},{module_info,1},{yes_14,0}]}. + +{attributes, []}. + +{labels, 12}. + + +{function, yes_14, 0, 2}. + {label,1}. + {func_info,{atom,yes_14},{atom,yes_14},0}. + {label,2}. + {move,{atom,ok},{x,0}}. + return. + + +{function, f, 2, 4}. + {label,3}. + {func_info,{atom,yes_14},{atom,f},2}. + {label,4}. + {allocate_heap,2,3,2}. + {move,{x,0},{y,1}}. + {put_tuple,2,{y,0}}. + {put,{atom,data}}. + {put,{x,1}}. + {call_ext,0,{extfunc,erlang,make_ref,0}}. % Ref in [x0] + {test_heap,4,1}. + {put_tuple,3,{x,1}}. + {put,{atom,request}}. + {put,{x,0}}. + {put,{y,0}}. + {move,{x,0},{y,0}}. % Ref in [x0,y0] + {move,{y,1},{x,0}}. % Ref in [y0] + {kill,{y,1}}. + send. + {move,{y,0},{x,0}}. % Ref in [x0,y0] + {move,{x,0},{y,1}}. % Ref in [x0,y0,y1] + {label,5}. + {loop_rec,{f,7},{x,0}}. % Ref in [y0,y1] + {test,is_tuple,{f,6},[{x,0}]}. + {test,test_arity,{f,6},[{x,0},2]}. + {get_tuple_element,{x,0},0,{x,1}}. + {get_tuple_element,{x,0},1,{x,2}}. + {test,is_eq_exact,{f,6},[{x,1},{atom,reply}]}. + {test,is_eq_exact,{f,6},[{x,2},{y,1}]}. + remove_message. + {move,{atom,ok},{x,0}}. + {deallocate,2}. + return. + {label,6}. + {loop_rec_end,{f,5}}. + {label,7}. + {wait,{f,5}}. + + +{function, module_info, 0, 9}. + {label,8}. + {func_info,{atom,yes_14},{atom,module_info},0}. + {label,9}. + {move,{atom,yes_14},{x,0}}. + {call_ext_only,1,{extfunc,erlang,get_module_info,1}}. + + +{function, module_info, 1, 11}. + {label,10}. + {func_info,{atom,yes_14},{atom,module_info},1}. + {label,11}. + {move,{x,0},{x,1}}. + {move,{atom,yes_14},{x,0}}. + {call_ext_only,2,{extfunc,erlang,get_module_info,2}}. diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_5.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_5.erl index 3f02fba6a6..5070e3e546 100644 --- a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_5.erl +++ b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_5.erl @@ -24,11 +24,7 @@ do_call(Process, Label, Request, Timeout) -> {'DOWN', Mref, _, _, Reason} -> exit(Reason) after Timeout -> - erlang:demonitor(Mref), - receive - {'DOWN', Mref, _, _, _} -> true - after 0 -> true - end, + erlang:demonitor(Mref, [flush]), exit(timeout) end catch |