File 2073-Optimize-is_function-1-2-calls.patch of Package erlang

From 904dfa9fd76b1dda1f8565219f3fe6c386f8aa6c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Wed, 24 Apr 2019 07:22:08 +0200
Subject: [PATCH 3/4] Optimize is_function/{1,2} calls

Remove is_function/1,2 tests if that are known to never fail.
---
 lib/compiler/src/beam_ssa.erl      |  2 +-
 lib/compiler/src/beam_ssa_type.erl | 78 ++++++++++++++++++++++++++++++++------
 2 files changed, 68 insertions(+), 12 deletions(-)

diff --git a/lib/compiler/src/beam_ssa.erl b/lib/compiler/src/beam_ssa.erl
index e8b77e382f..831e6489a9 100644
--- a/lib/compiler/src/beam_ssa.erl
+++ b/lib/compiler/src/beam_ssa.erl
@@ -79,7 +79,7 @@
 -type var_base()   :: atom() | non_neg_integer().
 
 -type literal_value() :: atom() | integer() | float() | list() |
-                         nil() | tuple() | map() | binary().
+                         nil() | tuple() | map() | binary() | fun().
 
 -type op()   :: {'bif',atom()} | {'float',float_op()} | prim_op() | cg_prim_op().
 -type anno() :: #{atom() := any()}.
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,7 +159,8 @@ 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);
         none ->
@@ -166,17 +168,24 @@ opt_finish_1([Arg | Args], [TypeMap | TypeMaps], ParamInfo)
             %% know the type for this argument.
             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;
-- 
2.16.4

openSUSE Build Service is sponsored by