From cebf6f0c68d231af8dcdb6bdf149ae9d870e9e6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 30 Jan 2018 08:28:29 +0100 Subject: beam_type: Refactor simplifications of instructions --- lib/compiler/src/beam_type.erl | 103 ++++++++++++++++++++++------------ lib/compiler/test/beam_type_SUITE.erl | 25 ++++++++- 2 files changed, 90 insertions(+), 38 deletions(-) diff --git a/lib/compiler/src/beam_type.erl b/lib/compiler/src/beam_type.erl index 646480f596..56ee64db39 100644 --- a/lib/compiler/src/beam_type.erl +++ b/lib/compiler/src/beam_type.erl @@ -94,22 +94,28 @@ simplify_basic([I0|Is], Ts0, Acc) -> simplify_basic([], Ts, Acc) -> {reverse(Acc),Ts}. +%% simplify_instr(Instruction, Ts) -> [Instruction]. + +%% Simplify a simple instruction using type information. Return an +%% empty list if the instruction should be removed, or a list with +%% the original or modified instruction. + simplify_instr({set,[D],[{integer,Index},Reg],{bif,element,_}}=I, Ts) -> case max_tuple_size(Reg, Ts) of Sz when 0 < Index, Index =< Sz -> [{set,[D],[Reg],{get_tuple_element,Index-1}}]; _ -> [I] end; -simplify_instr({test,is_atom,_,[R]}=I, Ts) -> - case tdb_find(R, Ts) of - boolean -> []; - _ -> [I] - end; -simplify_instr({test,is_integer,_,[R]}=I, Ts) -> +simplify_instr({test,Test,Fail,[R]}=I, Ts) -> case tdb_find(R, Ts) of - integer -> []; - {integer,_} -> []; - _ -> [I] + any -> + [I]; + Type -> + case will_succeed(Test, Type) of + yes -> []; + no -> [{jump,Fail}]; + maybe -> [I] + end end; simplify_instr({set,[D],[TupleReg],{get_tuple_element,0}}=I, Ts) -> case tdb_find(TupleReg, Ts) of @@ -118,31 +124,17 @@ simplify_instr({set,[D],[TupleReg],{get_tuple_element,0}}=I, Ts) -> _ -> [I] end; -simplify_instr({test,is_tuple,_,[R]}=I, Ts) -> - case tdb_find(R, Ts) of - {tuple,_,_,_} -> []; - _ -> [I] - end; simplify_instr({test,test_arity,_,[R,Arity]}=I, Ts) -> case tdb_find(R, Ts) of {tuple,exact_size,Arity,_} -> []; _ -> [I] end; -simplify_instr({test,is_map,_,[R]}=I, Ts) -> - case tdb_find(R, Ts) of - map -> []; - _ -> [I] - end; -simplify_instr({test,is_nonempty_list,_,[R]}=I, Ts) -> - case tdb_find(R, Ts) of - nonempty_list -> []; - _ -> [I] - end; -simplify_instr({test,is_eq_exact,Fail,[R,{atom,_}=Atom]}=I, Ts) -> +simplify_instr({test,is_eq_exact,Fail,[R,{atom,A}=Atom]}=I, Ts) -> case tdb_find(R, Ts) of {atom,_}=Atom -> []; - {atom,_} -> [{jump,Fail}]; - _ -> [I] + boolean when is_boolean(A) -> [I]; + any -> [I]; + _ -> [{jump,Fail}] end; simplify_instr({test,is_record,_,[R,{atom,_}=Tag,{integer,Arity}]}=I, Ts) -> case tdb_find(R, Ts) of @@ -163,16 +155,6 @@ simplify_instr({test,bs_test_unit,_,[Src,Unit]}=I, Ts) -> {binary,U} when U rem Unit =:= 0 -> []; _ -> [I] end; -simplify_instr({test,is_binary,_,[Src]}=I, Ts) -> - case tdb_find(Src, Ts) of - {binary,U} when U rem 8 =:= 0 -> []; - _ -> [I] - end; -simplify_instr({test,is_bitstr,_,[Src]}=I, Ts) -> - case tdb_find(Src, Ts) of - {binary,_} -> []; - _ -> [I] - end; simplify_instr(I, _) -> [I]. simplify_select_val_int({select,select_val,R,_,L0}=I, {Min,Max}) -> @@ -201,6 +183,53 @@ eq_ranges([H], H, H) -> true; eq_ranges([H|T], H, Max) -> eq_ranges(T, H+1, Max); eq_ranges(_, _, _) -> false. +%% will_succeed(TestOperation, Type) -> yes|no|maybe. +%% Test whether TestOperation applied to an argument of type Type +%% will succeed. Return yes, no, or maybe. +%% +%% Type is a type as described in the comment for verified_type/1 at +%% the very end of this file, but it will *never* be 'any'. + +will_succeed(is_atom, Type) -> + case Type of + {atom,_} -> yes; + boolean -> yes; + _ -> no + end; +will_succeed(is_binary, Type) -> + case Type of + {binary,U} when U rem 8 =:= 0 -> yes; + {binary,_} -> maybe; + _ -> no + end; +will_succeed(is_bitstr, Type) -> + case Type of + {binary,_} -> yes; + _ -> no + end; +will_succeed(is_integer, Type) -> + case Type of + integer -> yes; + {integer,_} -> yes; + _ -> no + end; +will_succeed(is_map, Type) -> + case Type of + map -> yes; + _ -> no + end; +will_succeed(is_nonempty_list, Type) -> + case Type of + nonempty_list -> yes; + _ -> no + end; +will_succeed(is_tuple, Type) -> + case Type of + {tuple,_,_,_} -> yes; + _ -> no + end; +will_succeed(_, _) -> maybe. + %% simplify_float([Instruction], TypeDatabase) -> %% {[Instruction],TypeDatabase'} | not_possible %% Simplify floating point operations in blocks. diff --git a/lib/compiler/test/beam_type_SUITE.erl b/lib/compiler/test/beam_type_SUITE.erl index e33df809ff..541075af2a 100644 --- a/lib/compiler/test/beam_type_SUITE.erl +++ b/lib/compiler/test/beam_type_SUITE.erl @@ -122,7 +122,7 @@ do_integers_5(X0, Y0) -> 3 -> three end. -coverage(_Config) -> +coverage(Config) -> {'EXIT',{badarith,_}} = (catch id(1) bsl 0.5), {'EXIT',{badarith,_}} = (catch id(2.0) bsl 2), {'EXIT',{badarith,_}} = (catch a + 0.5), @@ -133,6 +133,29 @@ coverage(_Config) -> id(id(42) band 387439739874298734983787934283479243879), id(-1 band id(13)), + error = if + is_map(Config), is_integer(Config) -> ok; + true -> error + end, + error = if + is_map(Config), is_atom(Config) -> ok; + true -> error + end, + error = if + is_map(Config), is_tuple(Config) -> ok; + true -> error + end, + error = if + is_integer(Config), is_bitstring(Config) -> ok; + true -> error + end, + + ok = case Config of + <<_>> when is_binary(Config) -> + impossible; + [_|_] -> + ok + end, ok. booleans(_Config) -> -- cgit v1.2.3