aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2018-08-21 08:17:24 +0200
committerBjörn Gustavsson <[email protected]>2018-09-12 14:19:04 +0200
commitbe092fb5fecfc382a45681d8de07fda27d77bf26 (patch)
treee25b4b4bec4ec57299b0a0684905ccf79e5289ab /lib/compiler
parentd3551827cc0221437098c5afa492637072f8a771 (diff)
downloadotp-be092fb5fecfc382a45681d8de07fda27d77bf26.tar.gz
otp-be092fb5fecfc382a45681d8de07fda27d77bf26.tar.bz2
otp-be092fb5fecfc382a45681d8de07fda27d77bf26.zip
Optimize 'and' and 'or' instructions
Diffstat (limited to 'lib/compiler')
-rw-r--r--lib/compiler/src/beam_ssa_codegen.erl14
-rw-r--r--lib/compiler/src/beam_ssa_opt.erl45
-rw-r--r--lib/compiler/src/beam_ssa_type.erl5
-rw-r--r--lib/compiler/test/compile_SUITE.erl3
4 files changed, 57 insertions, 10 deletions
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) ->