Skip to content

Commit fba99fd

Browse files
committed
enables inlining of anonymous functions
1 parent 3561f4b commit fba99fd

File tree

1 file changed

+120
-111
lines changed

1 file changed

+120
-111
lines changed

base/inference.jl

+120-111
Original file line numberDiff line numberDiff line change
@@ -2118,90 +2118,97 @@ end
21182118
# static parameters are ok if all the static parameter values are leaf types,
21192119
# meaning they are fully known.
21202120
function inlineable(f::ANY, e::Expr, atype::ANY, sv::StaticVarInfo, enclosing_ast::Expr)
2121-
if !(isa(f,Function) || isa(f,IntrinsicFunction))
2122-
return NF
2123-
end
2124-
atypes = atype.parameters
2125-
argexprs = e.args[2:end]
2121+
local linfo,
2122+
metharg::Type,
2123+
methsp::SimpleVector,
2124+
atypes = atype.parameters,
2125+
argexprs = e.args[2:end],
2126+
incompletematch = false,
2127+
isgf = false
2128+
if isa(f, LambdaStaticData)
2129+
linfo = f
2130+
metharg = Tuple
2131+
methsp = svec()
2132+
else
2133+
if !(isa(f,Function) || isa(f,IntrinsicFunction))
2134+
return NF
2135+
end
21262136

2127-
if is(f, typeassert) && length(atypes)==2
2128-
# typeassert(x::S, T) => x, when S<:T
2129-
if isType(atypes[2]) && isleaftype(atypes[2]) &&
2130-
atypes[1] <: atypes[2].parameters[1]
2131-
return (e.args[2],())
2137+
if is(f, typeassert) && length(atypes)==2
2138+
# typeassert(x::S, T) => x, when S<:T
2139+
if isType(atypes[2]) && isleaftype(atypes[2]) &&
2140+
atypes[1] <: atypes[2].parameters[1]
2141+
return (e.args[2],())
2142+
end
21322143
end
2133-
end
2134-
if length(atypes)==2 && is(f,unbox) && isa(atypes[2],DataType) && !atypes[2].mutable && atypes[2].pointerfree
2135-
# remove redundant unbox
2136-
return (e.args[3],())
2137-
end
2138-
topmod = _topmod()
2139-
if istopfunction(topmod, f, :isbits) && length(atypes)==1 && isType(atypes[1]) &&
2140-
effect_free(argexprs[1],sv,true) && isleaftype(atypes[1].parameters[1])
2141-
return (isbits(atypes[1].parameters[1]),())
2142-
end
2143-
# special-case inliners for known pure functions that compute types
2144-
if isType(e.typ)
2145-
if (is(f,apply_type) || is(f,fieldtype) ||
2146-
istopfunction(topmod, f, :typejoin) ||
2147-
istopfunction(topmod, f, :promote_type)) &&
2148-
isleaftype(e.typ.parameters[1])
2149-
return (e.typ.parameters[1],())
2144+
if length(atypes)==2 && is(f,unbox) && isa(atypes[2],DataType) && !atypes[2].mutable && atypes[2].pointerfree
2145+
# remove redundant unbox
2146+
return (e.args[3],())
2147+
end
2148+
topmod = _topmod()
2149+
if istopfunction(topmod, f, :isbits) && length(atypes)==1 && isType(atypes[1]) &&
2150+
effect_free(argexprs[1],sv,true) && isleaftype(atypes[1].parameters[1])
2151+
return (isbits(atypes[1].parameters[1]),())
2152+
end
2153+
# special-case inliners for known pure functions that compute types
2154+
if isType(e.typ)
2155+
if (is(f,apply_type) || is(f,fieldtype) ||
2156+
istopfunction(topmod, f, :typejoin) ||
2157+
istopfunction(topmod, f, :promote_type)) &&
2158+
isleaftype(e.typ.parameters[1])
2159+
return (e.typ.parameters[1],())
2160+
end
2161+
end
2162+
if isa(f,IntrinsicFunction)
2163+
return NF
21502164
end
2151-
end
2152-
if isa(f,IntrinsicFunction)
2153-
return NF
2154-
end
21552165

2156-
meth = _methods(f, atype, 1)
2157-
if meth === false || length(meth) != 1
2158-
return NF
2159-
end
2160-
meth = meth[1]::SimpleVector
2166+
local methfunc::Function
2167+
if isgeneric(f)
2168+
isgf = true
2169+
meth = _methods(f, atype, 1)
2170+
if meth === false || length(meth) != 1
2171+
return NF
2172+
end
2173+
meth = meth[1]::SimpleVector
2174+
linfo = try
2175+
func_for_method(meth[3],atype,meth[2])
2176+
catch
2177+
NF
2178+
end
2179+
if linfo === NF
2180+
return NF
2181+
end
2182+
metharg = meth[1]
2183+
methsp = meth[2]
2184+
methfunc = meth[3].func
2185+
methsig = meth[3].sig
2186+
if !(atype <: metharg)
2187+
incompletematch = true
2188+
if !inline_incompletematch_allowed || !isdefined(Main,:Base)
2189+
# provide global disable if this optimization is not desirable
2190+
# need Main.Base defined for MethodError
2191+
return NF
2192+
end
2193+
end
2194+
else
2195+
if !isdefined(f, :code)
2196+
return NF
2197+
end
2198+
linfo = f.code
2199+
metharg = Tuple
2200+
methsp = svec()
2201+
methfunc = f
2202+
end
21612203

2162-
local linfo
2163-
linfo = try
2164-
func_for_method(meth[3],atype,meth[2])
2165-
catch
2166-
NF
2167-
end
2168-
if linfo === NF
2169-
return NF
2204+
if length(methfunc.env) > 0
2205+
# can't inline something with an env
2206+
return NF
2207+
end
21702208
end
21712209
linfo = linfo::LambdaStaticData
21722210

2173-
## This code tries to limit the argument list length only when it is
2174-
## growing due to recursion.
2175-
## It might be helpful for some things, but turns out not to be
2176-
## necessary to get max performance from recursive varargs functions.
2177-
# if length(atypes) > MAX_TUPLETYPE_LEN
2178-
# # check call stack to see if this argument list is growing
2179-
# st = inference_stack
2180-
# while !isa(st, EmptyCallStack)
2181-
# if st.ast === linfo.def.ast && length(atypes) > length(st.types)
2182-
# atypes = limit_tuple_type(atypes)
2183-
# meth = _methods(f, atypes, 1)
2184-
# if meth === false || length(meth) != 1
2185-
# return NF
2186-
# end
2187-
# meth = meth[1]::Tuple
2188-
# linfo2 = meth[3].func.code
2189-
# if linfo2 !== linfo
2190-
# return NF
2191-
# end
2192-
# linfo = linfo2
2193-
# break
2194-
# end
2195-
# st = st.prev
2196-
# end
2197-
# end
2198-
2199-
if !isa(linfo,LambdaStaticData) || length(meth[3].func.env) > 0
2200-
return NF
2201-
end
2202-
2203-
sp = meth[2]::SimpleVector
2204-
sp = svec(sp..., linfo.sparams...)
2211+
sp = svec(methsp..., linfo.sparams...)
22052212
spvals = Any[ sp[i] for i in 2:2:length(sp) ]
22062213
for i=1:length(spvals)
22072214
si = spvals[i]
@@ -2213,21 +2220,10 @@ function inlineable(f::ANY, e::Expr, atype::ANY, sv::StaticVarInfo, enclosing_as
22132220
end
22142221
end
22152222

2216-
metharg = meth[1]::Type
22172223
methargs = metharg.parameters
22182224
nm = length(methargs)
2219-
if !(atype <: metharg)
2220-
incompletematch = true
2221-
if !inline_incompletematch_allowed || !isdefined(Main,:Base)
2222-
# provide global disable if this optimization is not desirable
2223-
# need Main.Base defined for MethodError
2224-
return NF
2225-
end
2226-
else
2227-
incompletematch = false
2228-
end
22292225

2230-
(ast, ty) = typeinf(linfo, metharg, meth[2], linfo, true, true)
2226+
(ast, ty) = typeinf(linfo, metharg, methsp, linfo, true, true)
22312227
if is(ast,())
22322228
return NF
22332229
end
@@ -2255,18 +2251,18 @@ function inlineable(f::ANY, e::Expr, atype::ANY, sv::StaticVarInfo, enclosing_as
22552251
if is(f, next) || is(f, done) || is(f, unsafe_convert) || is(f, cconvert)
22562252
cost ÷= 4
22572253
end
2258-
inline_op = (f===(+) || f===(*) || f===min || f===max) && (3 <= length(argexprs) <= 9) &&
2259-
meth[3].sig == Tuple{Any,Any,Any,Vararg{Any}}
2254+
inline_op = isgeneric(f) && (f===(+) || f===(*) || f===min || f===max) && (3 <= length(argexprs) <= 9) &&
2255+
methsig == Tuple{Any,Any,Any,Vararg{Any}}
22602256
if !inline_op && !inline_worthy(body, cost)
22612257
if incompletematch
22622258
# inline a typeassert-based call-site, rather than a
22632259
# full generic lookup, using the inliner to handle
22642260
# all the fiddly details
22652261
numarg = length(argexprs)
22662262
newnames = unique_names(ast,numarg)
2267-
sp = ()
2263+
methsp = sp
2264+
sp = svec()
22682265
spvals = []
2269-
meth = svec(metharg, sp)
22702266
locals = []
22712267
newcall = Expr(:call, e.args[1])
22722268
newcall.typ = ty
@@ -2297,7 +2293,10 @@ function inlineable(f::ANY, e::Expr, atype::ANY, sv::StaticVarInfo, enclosing_as
22972293
na = length(args)
22982294

22992295
isva = false
2300-
if na>0 && is_rest_arg(ast.args[1][na])
2296+
if na > 0 && is_rest_arg(ast.args[1][na])
2297+
if length(argexprs) < na - 1
2298+
return (Expr(:call, TopNode(:error), "too few arguments"), [])
2299+
end
23012300
vaname = args[na]
23022301
len_argexprs = length(argexprs)
23032302
valen = len_argexprs-na+1
@@ -2334,12 +2333,15 @@ function inlineable(f::ANY, e::Expr, atype::ANY, sv::StaticVarInfo, enclosing_as
23342333
isva = true
23352334
end
23362335
elseif na != length(argexprs)
2337-
# we have a method match only because an earlier
2338-
# inference step shortened our call args list, even
2339-
# though we have too many arguments to actually
2340-
# call this function
2341-
@assert isvarargtype(atypes[na])
2342-
return NF
2336+
if isgf
2337+
# we have a method match only because an earlier
2338+
# inference step shortened our call args list, even
2339+
# though we have too many arguments to actually
2340+
# call this function
2341+
@assert isvarargtype(atypes[na])
2342+
return NF
2343+
end
2344+
return (Expr(:call, TopNode(:error), "wrong number of arguments"), [])
23432345
end
23442346

23452347
@assert na == length(argexprs)
@@ -2558,7 +2560,7 @@ function inlineable(f::ANY, e::Expr, atype::ANY, sv::StaticVarInfo, enclosing_as
25582560
lastexpr = pop!(body.args)
25592561
if isa(lastexpr,LabelNode)
25602562
push!(body.args, lastexpr)
2561-
push!(body.args, Expr(:call,:error,"fatal error in type inference"))
2563+
push!(body.args, Expr(:call, TopNode(:error), "fatal error in type inference"))
25622564
lastexpr = nothing
25632565
else
25642566
@assert isa(lastexpr,Expr) "inference.jl:1774"
@@ -2745,18 +2747,25 @@ function inlining_pass(e::Expr, sv, ast)
27452747
end
27462748
end
27472749
end
2748-
f1 = f = isconstantfunc(arg1, sv)
2749-
if !is(f,false)
2750-
f = _ieval(f)
2751-
end
2752-
if (!isa(f,Function) && !isa(f,IntrinsicFunction) &&
2753-
(f1 !== false || typeintersect(exprtype(arg1,sv), Function) === Bottom))
2754-
modu = (inference_stack::CallStack).mod
2755-
if !_iisdefined(:call)
2756-
return (e,stmts)
2750+
2751+
if isa(e.args[1], LambdaStaticData)
2752+
f = e.args[1]
2753+
else
2754+
f1 = f = isconstantfunc(arg1, sv)
2755+
if !is(f,false)
2756+
f = _ieval(f)
2757+
end
2758+
if (!isa(f,Function) && !isa(f,IntrinsicFunction) &&
2759+
(f1 !== false || typeintersect(exprtype(arg1,sv), Function) === Bottom))
2760+
modu = (inference_stack::CallStack).mod
2761+
if !_iisdefined(:call)
2762+
return (e,stmts)
2763+
end
2764+
f = _ieval(:call)
2765+
e.args = Any[is_global(sv,:call) ? (:call) : GlobalRef(modu, :call), e.args...]
2766+
elseif f1 === false
2767+
return (e, stmts)
27572768
end
2758-
f = _ieval(:call)
2759-
e.args = Any[is_global(sv,:call) ? (:call) : GlobalRef(modu, :call), e.args...]
27602769
end
27612770

27622771
if isdefined(Main, :Base) &&

0 commit comments

Comments
 (0)