From be092fb5fecfc382a45681d8de07fda27d77bf26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 21 Aug 2018 08:17:24 +0200 Subject: Optimize 'and' and 'or' instructions --- lib/compiler/src/beam_ssa_codegen.erl | 14 ++++++++++- lib/compiler/src/beam_ssa_opt.erl | 45 ++++++++++++++++++++++++++++++----- lib/compiler/src/beam_ssa_type.erl | 5 ++++ lib/compiler/test/compile_SUITE.erl | 3 --- 4 files changed, 57 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/compiler/src/beam_ssa_codegen.erl b/lib/compiler/src/beam_ssa_codegen.erl index 006c41c0e0..becfe56b3a 100644 --- a/lib/compiler/src/beam_ssa_codegen.erl +++ b/lib/compiler/src/beam_ssa_codegen.erl @@ -1180,6 +1180,16 @@ cg_copy_1([#cg_set{dst=Dst0,args=Args}|T], St) -> end; cg_copy_1([], _St) -> []. +bif_to_test('and', [V1,V2], Fail) -> + [{test,is_eq_exact,Fail,[V1,{atom,true}]}, + {test,is_eq_exact,Fail,[V2,{atom,true}]}]; +bif_to_test('or', [V1,V2], {f,Lbl}=Fail) when Lbl =/= 0 -> + %% Labels are spaced 2 apart. We can create a new + %% label by incrementing the Fail label. + SuccLabel = Lbl + 1, + [{test,is_eq_exact,{f,SuccLabel},[V1,{atom,false}]}, + {test,is_eq_exact,Fail,[V2,{atom,true}]}, + {label,SuccLabel}]; bif_to_test('not', [Var], Fail) -> [{test,is_eq_exact,Fail,[Var,{atom,false}]}]; bif_to_test(Name, Args, Fail) -> @@ -1785,7 +1795,9 @@ is_gc_bif(Bif, Args) -> %% new_label(St) -> {L,St}. new_label(#cg{lcount=Next}=St) -> - {Next,St#cg{lcount=Next+1}}. + %% Advance the label counter by 2 to allow us to create + %% a label for 'or' by incrementing an existing label. + {Next,St#cg{lcount=Next+2}}. %% call_line(tail|body, Func, Anno) -> [] | [{line,...}]. %% Produce a line instruction if it will be needed by the diff --git a/lib/compiler/src/beam_ssa_opt.erl b/lib/compiler/src/beam_ssa_opt.erl index da466a3316..257e036719 100644 --- a/lib/compiler/src/beam_ssa_opt.erl +++ b/lib/compiler/src/beam_ssa_opt.erl @@ -941,6 +941,22 @@ misc_opt_is([#b_set{op=phi}=I0|Is], Sub0, Acc) -> false -> misc_opt_is(Is, Sub0, [I|Acc]) end; +misc_opt_is([#b_set{op={bif,'and'}}=I0], Sub, Acc) -> + #b_set{dst=Dst,args=Args} = I = sub(I0, Sub), + case eval_and(Args) of + error -> + misc_opt_is([], Sub, [I|Acc]); + Val -> + misc_opt_is([], Sub#{Dst=>Val}, Acc) + end; +misc_opt_is([#b_set{op={bif,'or'}}=I0], Sub, Acc) -> + #b_set{dst=Dst,args=Args} = I = sub(I0, Sub), + case eval_or(Args) of + error -> + misc_opt_is([], Sub, [I|Acc]); + Val -> + misc_opt_is([], Sub#{Dst=>Val}, Acc) + end; misc_opt_is([#b_set{}=I0|Is], Sub, Acc) -> #b_set{op=Op,dst=Dst,args=Args} = I = sub(I0, Sub), case make_literal(Op, Args) of @@ -973,6 +989,20 @@ make_literal_list([_|_], _) -> make_literal_list([], Acc) -> reverse(Acc). +eval_and(Args) -> + case Args of + [_,#b_literal{val=false}=Res] -> Res; + [Res,#b_literal{val=true}] -> Res; + [_,_] -> error + end. + +eval_or(Args) -> + case Args of + [Res,#b_literal{val=false}] -> Res; + [_,#b_literal{val=true}=Res] -> Res; + [_,_] -> error + end. + %%% %%% Merge blocks. %%% @@ -1283,20 +1313,23 @@ rel2fam(S0) -> S = sofs:rel2fam(S1), sofs:to_external(S). -sub(#b_set{op=phi,args=Args}=I, Sub) -> +sub(I, Sub) -> + beam_ssa:normalize(sub_1(I, Sub)). + +sub_1(#b_set{op=phi,args=Args}=I, Sub) -> I#b_set{args=[{sub_arg(A, Sub),P} || {A,P} <- Args]}; -sub(#b_set{args=Args}=I, Sub) -> +sub_1(#b_set{args=Args}=I, Sub) -> I#b_set{args=[sub_arg(A, Sub) || A <- Args]}; -sub(#b_br{bool=#b_var{}=Old}=Br, Sub) -> +sub_1(#b_br{bool=#b_var{}=Old}=Br, Sub) -> New = sub_arg(Old, Sub), Br#b_br{bool=New}; -sub(#b_switch{arg=#b_var{}=Old}=Sw, Sub) -> +sub_1(#b_switch{arg=#b_var{}=Old}=Sw, Sub) -> New = sub_arg(Old, Sub), Sw#b_switch{arg=New}; -sub(#b_ret{arg=#b_var{}=Old}=Ret, Sub) -> +sub_1(#b_ret{arg=#b_var{}=Old}=Ret, Sub) -> New = sub_arg(Old, Sub), Ret#b_ret{arg=New}; -sub(Last, _) -> Last. +sub_1(Last, _) -> Last. sub_arg(#b_remote{mod=Mod,name=Name}=Rem, Sub) -> Rem#b_remote{mod=sub_arg(Mod, Sub),name=sub_arg(Name, Sub)}; diff --git a/lib/compiler/src/beam_ssa_type.erl b/lib/compiler/src/beam_ssa_type.erl index ae926960bf..8ad520df63 100644 --- a/lib/compiler/src/beam_ssa_type.erl +++ b/lib/compiler/src/beam_ssa_type.erl @@ -449,6 +449,11 @@ type(succeeded, [#b_var{name=Src}], Ts, Ds) -> #b_set{op={bif,Bif},args=BifArgs} -> Types = get_types(BifArgs, Ts), case {Bif,Types} of + {BoolOp,[T1,T2]} when BoolOp =:= 'and'; BoolOp =:= 'or' -> + case t_is_boolean(T1) andalso t_is_boolean(T2) of + true -> t_atom(true); + false -> t_boolean() + end; {byte_size,[{binary,_}]} -> t_atom(true); {bit_size,[{binary,_}]} -> diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl index 8d8fc23027..2ec0bfdf83 100644 --- a/lib/compiler/test/compile_SUITE.erl +++ b/lib/compiler/test/compile_SUITE.erl @@ -1250,11 +1250,8 @@ do_opt_guards_fun([]) -> []. is_exception(guard_SUITE, {'-complex_not/1-fun-4-',1}) -> true; is_exception(guard_SUITE, {'-complex_not/1-fun-5-',1}) -> true; is_exception(guard_SUITE, {bad_guards,1}) -> true; -is_exception(guard_SUITE, {bad_guards_2,2}) -> true; is_exception(guard_SUITE, {bad_guards_3,2}) -> true; -is_exception(guard_SUITE, {csemi7,3}) -> true; is_exception(guard_SUITE, {nested_not_2b,4}) -> true; -is_exception(guard_SUITE, {tricky_1,2}) -> true; is_exception(_, _) -> false. sys_pre_attributes(Config) -> -- cgit v1.2.3