Skip to content

Commit

Permalink
allow inlining of call1 sites, where the types may not match exactly
Browse files Browse the repository at this point in the history
  • Loading branch information
vtjnash committed Jun 9, 2014
1 parent 6a07ad5 commit f4357ac
Showing 1 changed file with 60 additions and 13 deletions.
73 changes: 60 additions & 13 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1858,7 +1858,7 @@ function without_linenums(a::Array{Any,1})
l
end

const _pure_builtins = {tuple, tupleref, tuplelen, fieldtype, apply_type, is, isa, typeof} # known affect-free calls (also effect-free)
const _pure_builtins = {tuple, tupleref, tuplelen, fieldtype, apply_type, is, isa, typeof, typeassert} # known affect-free calls (also effect-free)
const _pure_builtins_volatile = {getfield, arrayref} # known effect-free calls (might not be affect-free)

function is_pure_builtin(f)
Expand Down Expand Up @@ -2039,12 +2039,13 @@ function inlineable(f, e::Expr, atypes, sv, enclosing_ast)
# end
# end

# when 1 method matches the inferred types, there is still a chance
# of a no-method error at run time, unless the inferred types are a
# subset of the method signature.
if !(atypes <: meth[1])
return NF
# Undef is a bad type
for ty in atypes
if Undef <: ty
return NF
end
end

if !isa(linfo,LambdaStaticData) || meth[3].func.env !== ()
return NF
end
Expand Down Expand Up @@ -2093,6 +2094,7 @@ function inlineable(f, e::Expr, atypes, sv, enclosing_ast)
args = f_argnames(ast)
na = length(args)

isva = false
if na>0 && is_rest_arg(ast.args[1][na])
vaname = args[na]
len_argexprs = length(argexprs)
Expand Down Expand Up @@ -2127,6 +2129,7 @@ function inlineable(f, e::Expr, atypes, sv, enclosing_ast)
# construct tuple-forming expression for argument tail
vararg = mk_tuplecall(argexprs[na:end])
argexprs = {argexprs[1:(na-1)]..., vararg}
isva = true
end
end
@assert na == length(argexprs)
Expand Down Expand Up @@ -2163,10 +2166,47 @@ function inlineable(f, e::Expr, atypes, sv, enclosing_ast)
# see if each argument occurs only once in the body expression
stmts = {}
stmts_free = true # true = all entries of stmts are effect_free
for i=length(args):-1:1 # stmts_free needs to be calculated in reverse-argument order

methargs = meth[1]
nm = length(methargs)
for i=na:-1:1 # stmts_free needs to be calculated in reverse-argument order
a = args[i]
aei = argexprs[i]
aeitype = exprtype(aei)
aeitype = argtype = typeintersect(exprtype(aei),Any) # remove Undef
if aeitype == ANY
aeitype = Any
end
if isva
if nm == 0
methitype = ()
elseif i > nm
methitype = methargs[end]
if isvarargtype(methitype)
methitype = (methitype,)
else
methitype = ()
end
else
methitype = tuple(methargs[i:end]...)
end
isva = false
else
if i < nm
methitype = methargs[i]
else
methitype = methargs[end]
if isvarargtype(methitype)
methitype = (methitype::Vararg).parameters[1]
else
@assert i==nm
end
end
end
needtypeassert = false
if !(aeitype <: methitype)
needtypeassert = true
aeitype = methitype
end

islocal = false # if the argument name is also used as a local variable,
# we need to keep it as a variable name
Expand All @@ -2185,7 +2225,7 @@ function inlineable(f, e::Expr, atypes, sv, enclosing_ast)
# ok for argument to occur more than once if the actual argument
# is a symbol or constant, or is not affected by previous statements
# that will exist after the inlining pass finishes
affect_free = stmts_free && !islocal # false = previous statements might affect the result of evaluating argument
affect_free = stmts_free && !islocal && !needtypeassert # false = previous statements might affect the result of evaluating argument
occ = 0
for j = length(body.args):-1:1
b = body.args[j]
Expand All @@ -2201,14 +2241,21 @@ function inlineable(f, e::Expr, atypes, sv, enclosing_ast)
end
end
free = effect_free(aei,sv,true)
if ((occ==0 && is(aeitype,None)) || islocal || (occ > 1 && !inline_worthy(aei, occ)) ||
(affect_free && !free) || (!affect_free && !effect_free(aei,sv,false)))
if occ != 0 # islocal=true is implied
if ((occ==0 && is(aeitype,None)) || islocal || needtypeassert || (occ > 1 && !inline_worthy(aei, occ)) ||
(affect_free && !free) || (!affect_free && !effect_free(aei,sv,false)))
if occ != 0 || needtypeassert # islocal=true is implied
# introduce variable for this argument
vnew = unique_name(enclosing_ast, ast)
add_variable(enclosing_ast, vnew, aeitype, !islocal)
unshift!(stmts, Expr(:(=), vnew, aei))
argexprs[i] = aeitype===Any ? vnew : SymbolNode(vnew,aeitype)
if needtypeassert
vnew2 = unique_name(enclosing_ast, ast)
add_variable(enclosing_ast, vnew2, argtype, true)
push!(stmts, Expr(:(=), vnew, Expr(:call, TopNode(:typeassert), vnew2, aeitype)))
else
vnew2 = vnew
end
unshift!(stmts, Expr(:(=), vnew2, aei))
stmts_free &= free
elseif !free && !isType(aeitype)
unshift!(stmts, aei)
Expand Down

0 comments on commit f4357ac

Please sign in to comment.