aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler/src/beam_ssa_type.erl
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2019-04-24 07:22:08 +0200
committerBjörn Gustavsson <[email protected]>2019-05-23 12:26:32 +0200
commit904dfa9fd76b1dda1f8565219f3fe6c386f8aa6c (patch)
tree05fe8c91a5bbabba5964510e8ea220af59a6096f /lib/compiler/src/beam_ssa_type.erl
parent50a2d448e775668a5cbd835c9ff5eae6058f8739 (diff)
downloadotp-904dfa9fd76b1dda1f8565219f3fe6c386f8aa6c.tar.gz
otp-904dfa9fd76b1dda1f8565219f3fe6c386f8aa6c.tar.bz2
otp-904dfa9fd76b1dda1f8565219f3fe6c386f8aa6c.zip
Optimize is_function/{1,2} calls
Remove is_function/1,2 tests if that are known to never fail.
Diffstat (limited to 'lib/compiler/src/beam_ssa_type.erl')
-rw-r--r--lib/compiler/src/beam_ssa_type.erl78
1 files changed, 67 insertions, 11 deletions
diff --git a/lib/compiler/src/beam_ssa_type.erl b/lib/compiler/src/beam_ssa_type.erl
index 82371f4ba3..15f646fcb7 100644
--- a/lib/compiler/src/beam_ssa_type.erl
+++ b/lib/compiler/src/beam_ssa_type.erl
@@ -41,8 +41,9 @@
%% Records that represent type information.
-record(t_atom, {elements=any :: 'any' | [atom()]}).
--record(t_integer, {elements=any :: 'any' | {integer(),integer()}}).
-record(t_bs_match, {type :: type()}).
+-record(t_fun, {arity=any :: arity() | 'any'}).
+-record(t_integer, {elements=any :: 'any' | {integer(),integer()}}).
-record(t_tuple, {size=0 :: integer(),
exact=false :: boolean(),
%% Known element types (1-based index), unknown elements are
@@ -50,8 +51,9 @@
elements=#{} :: #{ non_neg_integer() => type() }}).
-type type() :: 'any' | 'none' |
- #t_atom{} | #t_integer{} | #t_bs_match{} | #t_tuple{} |
- {'binary',pos_integer()} | 'cons' | 'float' | 'list' | 'map' | 'nil' | 'number'.
+ #t_atom{} | #t_bs_match{} | #t_fun{} | #t_integer{} | #t_tuple{} |
+ {'binary',pos_integer()} | 'cons' | 'float' |
+ 'list' | 'map' | 'nil' | 'number'.
-type type_db() :: #{beam_ssa:var_name():=type()}.
-spec opt_start(Linear, Args, Anno, FuncDb) -> {Linear, FuncDb} when
@@ -157,21 +159,29 @@ opt_finish_1([Arg | Args], [TypeMap | TypeMaps], ParamInfo)
map_size(TypeMap) =:= 0 ->
opt_finish_1(Args, TypeMaps, ParamInfo);
opt_finish_1([Arg | Args], [TypeMap | TypeMaps], ParamInfo0) ->
- case join(maps:values(TypeMap)) of
+ JoinedType0 = verified_type(join(maps:values(TypeMap))),
+ case validator_anno(JoinedType0) of
any ->
opt_finish_1(Args, TypeMaps, ParamInfo0);
JoinedType ->
- JoinedType = verified_type(JoinedType),
- ParamInfo = ParamInfo0#{ Arg => validator_anno(JoinedType) },
+ ParamInfo = ParamInfo0#{ Arg => JoinedType },
opt_finish_1(Args, TypeMaps, ParamInfo)
end;
opt_finish_1([], [], ParamInfo) ->
ParamInfo.
+validator_anno(any) ->
+ any;
+validator_anno(#t_fun{}) ->
+ %% There is no need make funs visible to beam_validator.
+ any;
validator_anno(#t_tuple{size=Size,exact=Exact,elements=Elements0}) ->
- Elements = maps:fold(fun(Index, Type, Acc) ->
+ Elements = maps:fold(fun(Index, Type0, Acc) ->
Key = beam_validator:type_anno(integer, Index),
- Acc#{ Key => validator_anno(Type) }
+ case validator_anno(Type0) of
+ any -> Acc;
+ Type -> Acc#{Key=>Type}
+ end
end, #{}, Elements0),
beam_validator:type_anno(tuple, Size, Exact, Elements);
validator_anno(#t_integer{elements={Same,Same}}) ->
@@ -413,6 +423,11 @@ simplify_remote_call(Mod, Name, Args0, I) ->
end
end.
+opt_call(#b_set{dst=Dst,args=[#b_var{}=Fun|Args]}=I, _D, Ts0, Ds0, Fdb) ->
+ Type = #t_fun{arity=length(Args)},
+ Ts = Ts0#{ Fun => Type, Dst => any },
+ Ds = Ds0#{ Dst => I },
+ {Ts, Ds, Fdb, I};
opt_call(#b_set{dst=Dst,args=[#b_local{}=Callee|Args]}=I0, D, Ts0, Ds0, Fdb0) ->
{Ts, Ds, I} = opt_local_call(I0, Ts0, Ds0, Fdb0),
case Fdb0 of
@@ -440,9 +455,15 @@ opt_local_call(#b_set{dst=Dst,args=[Id|_]}=I0, Ts0, Ds0, Fdb) ->
#{} -> any
end,
I = case Type of
- any -> I0;
- none -> I0;
- _ -> beam_ssa:add_anno(result_type, validator_anno(Type), I0)
+ none ->
+ I0;
+ _ ->
+ case validator_anno(Type) of
+ any ->
+ I0;
+ ValidatorType ->
+ beam_ssa:add_anno(result_type, ValidatorType, I0)
+ end
end,
Ts = Ts0#{ Dst => Type },
Ds = Ds0#{ Dst => I },
@@ -519,6 +540,18 @@ simplify(#b_set{op={bif,tuple_size},args=[Term]}=I, Ts) ->
_ ->
I
end;
+simplify(#b_set{op={bif,is_function},args=[Fun,#b_literal{val=Arity}]}=I, Ts)
+ when is_integer(Arity), Arity >= 0 ->
+ case get_type(Fun, Ts) of
+ #t_fun{arity=any} ->
+ I;
+ #t_fun{arity=Arity} ->
+ #b_literal{val=true};
+ any ->
+ I;
+ _ ->
+ #b_literal{val=false}
+ end;
simplify(#b_set{op={bif,Op0},args=Args}=I, Ts) when Op0 =:= '=='; Op0 =:= '/=' ->
Types = get_types(Args, Ts),
EqEq0 = case {meet(Types),join(Types)} of
@@ -913,6 +946,13 @@ type(bs_get_tail, _Args, _Ts, _Ds) ->
type(call, [#b_remote{mod=#b_literal{val=Mod},
name=#b_literal{val=Name}}|Args], Ts, _Ds) ->
case {Mod,Name,Args} of
+ {erlang,make_fun,[_,_,Arity0]} ->
+ case Arity0 of
+ #b_literal{val=Arity} when is_integer(Arity), Arity >= 0 ->
+ #t_fun{arity=Arity};
+ _ ->
+ #t_fun{}
+ end;
{erlang,setelement,[Pos,Tuple,Arg]} ->
case {get_type(Pos, Ts),get_type(Tuple, Ts)} of
{#t_integer{elements={Index,Index}},
@@ -981,6 +1021,8 @@ type(is_nonempty_list, [_], _Ts, _Ds) ->
t_boolean();
type(is_tagged_tuple, [_,#b_literal{},#b_literal{}], _Ts, _Ds) ->
t_boolean();
+type(make_fun, [#b_local{arity=TotalArity}|Env], _Ts, _Ds) ->
+ #t_fun{arity=TotalArity-length(Env)};
type(put_map, _Args, _Ts, _Ds) ->
map;
type(put_list, _Args, _Ts, _Ds) ->
@@ -1162,6 +1204,11 @@ will_succeed(is_float, Type) ->
number -> maybe;
_ -> no
end;
+will_succeed(is_function, Type) ->
+ case Type of
+ #t_fun{} -> yes;
+ _ -> no
+ end;
will_succeed(is_integer, Type) ->
case Type of
#t_integer{} -> yes;
@@ -1401,6 +1448,9 @@ get_type(#b_literal{val=Val}, _Ts) ->
t_atom(Val);
is_float(Val) ->
float;
+ is_function(Val) ->
+ {arity,Arity} = erlang:fun_info(Val, arity),
+ #t_fun{arity=Arity};
is_integer(Val) ->
t_integer(Val);
is_list(Val), Val =/= [] ->
@@ -1790,6 +1840,7 @@ join(#t_atom{elements=any}=T, #t_atom{elements=[_|_]}) -> T;
join(#t_atom{elements=[_|_]}, #t_atom{elements=any}=T) -> T;
join({binary,U1}, {binary,U2}) ->
{binary,gcd(U1, U2)};
+join(#t_fun{}, #t_fun{}) -> #t_fun{};
join(#t_integer{}, #t_integer{}) -> t_integer();
join(list, cons) -> list;
join(cons, list) -> list;
@@ -1907,6 +1958,10 @@ meet(#t_atom{elements=[_|_]}=T, #t_atom{elements=any}) ->
T;
meet(#t_atom{elements=any}, #t_atom{elements=[_|_]}=T) ->
T;
+meet(#t_fun{arity=any}, #t_fun{}=T) ->
+ T;
+meet(#t_fun{}=T, #t_fun{arity=any}) ->
+ T;
meet(#t_integer{elements={_,_}}=T, #t_integer{elements=any}) ->
T;
meet(#t_integer{elements=any}, #t_integer{elements={_,_}}=T) ->
@@ -1996,6 +2051,7 @@ verified_type(none=T) -> T;
verified_type(#t_atom{elements=any}=T) -> T;
verified_type(#t_atom{elements=[_|_]}=T) -> T;
verified_type({binary,U}=T) when is_integer(U) -> T;
+verified_type(#t_fun{arity=Arity}=T) when Arity =:= any; is_integer(Arity) -> T;
verified_type(#t_integer{elements=any}=T) -> T;
verified_type(#t_integer{elements={Min,Max}}=T)
when is_integer(Min), is_integer(Max) -> T;