aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2015-09-23 12:30:16 +0200
committerBjörn Gustavsson <[email protected]>2015-09-28 10:26:40 +0200
commitb66193afc3fe85072da4631c52c5ccec136caa05 (patch)
tree18fa64027bd9b301c7df8f8d2badefb0ad1e66fc /lib
parentc0c5943c3a2646a3383d974c2a1afcff8c5d16d3 (diff)
downloadotp-b66193afc3fe85072da4631c52c5ccec136caa05.tar.gz
otp-b66193afc3fe85072da4631c52c5ccec136caa05.tar.bz2
otp-b66193afc3fe85072da4631c52c5ccec136caa05.zip
beam_type: Improve optimizations by keeping track of booleans
There is an optimization in beam_block to simplify a select_val on a known boolean value. We can implement this optimization in a cleaner way in beam_type and it will also be applicable in more situations. (When I added the optimization to beam_type without removing the optimization from beam_block, the optimization was applied 66 times.)
Diffstat (limited to 'lib')
-rw-r--r--lib/compiler/src/beam_block.erl34
-rw-r--r--lib/compiler/src/beam_type.erl28
-rw-r--r--lib/compiler/test/beam_type_SUITE.erl15
3 files changed, 41 insertions, 36 deletions
diff --git a/lib/compiler/src/beam_block.erl b/lib/compiler/src/beam_block.erl
index 741fdbb973..10dbaf462c 100644
--- a/lib/compiler/src/beam_block.erl
+++ b/lib/compiler/src/beam_block.erl
@@ -58,33 +58,6 @@ blockify(Is) ->
blockify([{loop_rec,{f,Fail},{x,0}},{loop_rec_end,_Lbl},{label,Fail}|Is], Acc) ->
%% Useless instruction sequence.
blockify(Is, Acc);
-blockify([{test,is_atom,{f,Fail},[Reg]}=I|
- [{select,select_val,Reg,{f,Fail},
- [{atom,false},{f,_}=BrFalse,
- {atom,true}=AtomTrue,{f,_}=BrTrue]}|Is]=Is0],
- [{block,Bl}|_]=Acc) ->
- case is_last_bool(Bl, Reg) of
- false ->
- blockify(Is0, [I|Acc]);
- true ->
- %% The last instruction is a boolean operator/guard BIF that can't fail.
- %% We can convert the three-way branch to a two-way branch (eliminating
- %% the reference to the failure label).
- blockify(Is, [{jump,BrTrue},
- {test,is_eq_exact,BrFalse,[Reg,AtomTrue]}|Acc])
- end;
-blockify([{test,is_atom,{f,Fail},[Reg]}=I|
- [{select,select_val,Reg,{f,Fail},
- [{atom,true}=AtomTrue,{f,_}=BrTrue,
- {atom,false},{f,_}=BrFalse]}|Is]=Is0],
- [{block,Bl}|_]=Acc) ->
- case is_last_bool(Bl, Reg) of
- false ->
- blockify(Is0, [I|Acc]);
- true ->
- blockify(Is, [{jump,BrTrue},
- {test,is_eq_exact,BrFalse,[Reg,AtomTrue]}|Acc])
- end;
blockify([I|Is0]=IsAll, Acc) ->
case collect(I) of
error -> blockify(Is0, [I|Acc]);
@@ -94,13 +67,6 @@ blockify([I|Is0]=IsAll, Acc) ->
end;
blockify([], Acc) -> reverse(Acc).
-is_last_bool([{set,[Reg],As,{bif,N,_}}], Reg) ->
- Ar = length(As),
- erl_internal:new_type_test(N, Ar) orelse erl_internal:comp_op(N, Ar)
- orelse erl_internal:bool_op(N, Ar);
-is_last_bool([_|Is], Reg) -> is_last_bool(Is, Reg);
-is_last_bool([], _) -> false.
-
collect_block(Is) ->
collect_block(Is, []).
diff --git a/lib/compiler/src/beam_type.erl b/lib/compiler/src/beam_type.erl
index 17ce7082f6..4b45c28623 100644
--- a/lib/compiler/src/beam_type.erl
+++ b/lib/compiler/src/beam_type.erl
@@ -95,6 +95,11 @@ simplify_basic_1([{set,[D],[TupleReg],{get_tuple_element,0}}=I|Is0], Ts0, Acc) -
end;
simplify_basic_1([{set,_,_,{try_catch,_,_}}=I|Is], _Ts, Acc) ->
simplify_basic_1(Is, tdb_new(), [I|Acc]);
+simplify_basic_1([{test,is_atom,_,[R]}=I|Is], Ts, Acc) ->
+ case tdb_find(R, Ts) of
+ boolean -> simplify_basic_1(Is, Ts, Acc);
+ _ -> simplify_basic_1(Is, Ts, [I|Acc])
+ end;
simplify_basic_1([{test,is_integer,_,[R]}=I|Is], Ts, Acc) ->
case tdb_find(R, Ts) of
integer -> simplify_basic_1(Is, Ts, Acc);
@@ -148,6 +153,8 @@ simplify_basic_1([{select,select_val,Reg,_,_}=I0|Is], Ts, Acc) ->
I = case tdb_find(Reg, Ts) of
{integer,Range} ->
simplify_select_val_int(I0, Range);
+ boolean ->
+ simplify_select_val_bool(I0);
_ ->
I0
end,
@@ -166,6 +173,15 @@ simplify_select_val_int({select,select_val,R,_,L0}=I, {Min,Max}) ->
true -> simplify_select_val_1(L0, {integer,Max}, R, [])
end.
+simplify_select_val_bool({select,select_val,R,_,L}=I) ->
+ Vs = sort([V || {atom,V} <- L]),
+ case Vs of
+ [false,true] ->
+ simplify_select_val_1(L, {atom,false}, R, []);
+ _ ->
+ I
+ end.
+
simplify_select_val_1([Val,F|T], Val, R, Acc) ->
L = reverse(Acc, T),
{select,select_val,R,F,L};
@@ -414,6 +430,17 @@ update({set,[D],[{integer,I},Reg],{bif,element,_}}, Ts0) ->
tdb_update([{Reg,{tuple,I,[]}},{D,kill}], Ts0);
update({set,[D],[_Index,Reg],{bif,element,_}}, Ts0) ->
tdb_update([{Reg,{tuple,0,[]}},{D,kill}], Ts0);
+update({set,[D],Args,{bif,N,_}}, Ts0) ->
+ Ar = length(Args),
+ BoolOp = erl_internal:new_type_test(N, Ar) orelse
+ erl_internal:comp_op(N, Ar) orelse
+ erl_internal:bool_op(N, Ar),
+ case BoolOp of
+ true ->
+ tdb_update([{D,boolean}], Ts0);
+ false ->
+ tdb_update([{D,kill}], Ts0)
+ end;
update({set,[D],[S],{get_tuple_element,0}}, Ts) ->
tdb_update([{D,{tuple_element,S,0}}], Ts);
update({set,[D],[S],{alloc,_,{gc_bif,float,{f,0}}}}, Ts0) ->
@@ -828,6 +855,7 @@ merge_type_info(NewType, _) ->
verify_type(NewType),
NewType.
+verify_type(boolean) -> ok;
verify_type(integer) -> ok;
verify_type({integer,{Min,Max}})
when is_integer(Min), is_integer(Max) -> ok;
diff --git a/lib/compiler/test/beam_type_SUITE.erl b/lib/compiler/test/beam_type_SUITE.erl
index 8d99d76180..8d5c0190ed 100644
--- a/lib/compiler/test/beam_type_SUITE.erl
+++ b/lib/compiler/test/beam_type_SUITE.erl
@@ -21,7 +21,7 @@
-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
init_per_group/2,end_per_group/2,
- integers/1,coverage/1]).
+ integers/1,coverage/1,booleans/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -32,7 +32,8 @@ all() ->
groups() ->
[{p,[parallel],
[integers,
- coverage
+ coverage,
+ booleans
]}].
init_per_suite(Config) ->
@@ -83,5 +84,15 @@ coverage(_Config) ->
ok.
+booleans(_Config) ->
+ {'EXIT',{{case_clause,_},_}} = (catch do_booleans(42)),
+ ok.
+
+do_booleans(B) ->
+ case is_integer(B) of
+ yes -> yes;
+ no -> no
+ end.
+
id(I) ->
I.