Skip to content

Commit

Permalink
Merge pull request #16186 from JuliaLang/jb/inlineable2
Browse files Browse the repository at this point in the history
compute `inline_worthy` after inference and cache it
  • Loading branch information
vtjnash committed May 5, 2016
2 parents 63e0c60 + 7bdf9c6 commit 5533118
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 75 deletions.
133 changes: 61 additions & 72 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1840,6 +1840,29 @@ end

#### finalize and record the result of running type inference ####

function isinlineable(linfo::LambdaInfo)
inlineable = false
if isdefined(linfo, :def)
cost = 1000
if linfo.def.module === _topmod(linfo.def.module)
name = linfo.def.name
sig = linfo.def.sig
if ((name === :+ || name === :* || name === :min || name === :max) &&
sig == Tuple{sig.parameters[1],Any,Any,Any,Vararg{Any}})
inlineable = true
elseif (name === :next || name === :done || name === :unsafe_convert ||
name === :cconvert)
cost ÷= 4
end
end
if !inlineable
body = Expr(:block); body.args = linfo.code
inlineable = inline_worthy(body, cost)
end
end
return inlineable
end

# inference completed on `me`
# update the LambdaInfo and notify the edges
function finish(me::InferenceState)
Expand Down Expand Up @@ -1883,6 +1906,9 @@ function finish(me::InferenceState)
# finalize and record the linfo result
me.inferred = true

# determine and cache inlineability
me.linfo.inlineable = isinlineable(me.linfo)

me.linfo.inferred = true
me.linfo.inInference = false
me.linfo.pure = ispure
Expand All @@ -1904,6 +1930,7 @@ function finish(me::InferenceState)
out.ssavaluetypes = me.linfo.ssavaluetypes
out.rettype = me.linfo.rettype
out.pure = me.linfo.pure
out.inlineable = me.linfo.inlineable
end
if me.tfunc_bp !== nothing
me.tfunc_bp.func = me.linfo
Expand Down Expand Up @@ -2284,6 +2311,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
metharg = meth[1]::Type
methsp = meth[2]
method = meth[3]::Method
# check whether call can be inlined to just a quoted constant value
if isa(f, widenconst(ft)) && !method.isstaged && method.lambda_template.pure && (isType(e.typ) || isa(e.typ,Const))
# check if any arguments aren't effect_free and need to be kept around
stmts = Any[]
Expand Down Expand Up @@ -2315,21 +2343,6 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
end
end

spvals = Any[]
for i = 1:length(methsp)
si = methsp[i]
if isa(si, TypeVar)
return NF
end
push!(spvals, si)
end
for i=1:length(spvals)
si = spvals[i]
if isa(si,Symbol) || isa(si,SSAValue) || isa(si,Slot)
spvals[i] = QuoteNode(si)
end
end

## This code tries to limit the argument list length only when it is
## growing due to recursion.
## It might be helpful for some things, but turns out not to be
Expand All @@ -2356,37 +2369,11 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
# end
# end

methargs = metharg.parameters
nm = length(methargs)

(linfo, ty, inferred) = typeinf(method, metharg, methsp, true)
if is(linfo,nothing) || !inferred
return NF
end
ast = linfo.code

if !isa(ast,Array{Any,1})
ast = ccall(:jl_uncompress_ast, Any, (Any,Any), linfo, ast)
else
ast = astcopy(ast)
end
ast = ast::Array{Any,1}

body = Expr(:block)
body.args = ast
propagate_inbounds, _ = popmeta!(body, :propagate_inbounds)
cost::Int = 1000
if incompletematch
cost *= 4
end
if (istopfunction(topmod, f, :next) || istopfunction(topmod, f, :done) ||
istopfunction(topmod, f, :unsafe_convert) || istopfunction(topmod, f, :cconvert))
cost ÷= 4
end
inline_op = (istopfunction(topmod, f, :+) || istopfunction(topmod, f, :*) ||
istopfunction(topmod, f, :min) || istopfunction(topmod, f, :max)) &&
(4 <= length(argexprs) <= 10) && methsig == Tuple{widenconst(ft),Any,Any,Any,Vararg{Any}}
if !inline_op && !inline_worthy(body, cost)
if !linfo.inlineable
# TODO
#=
if incompletematch
Expand Down Expand Up @@ -2416,38 +2403,10 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
end

na = linfo.nargs

# check for vararg function
isva = false
if na > 0 && linfo.isva
if length(argexprs) < na - 1
return (Expr(:call, TopNode(:error), "too few arguments"), [])
end
# This appears to be redundant with tuple_elim_pass
#=
if false#=TODO=# && valen>0 && !occurs_outside_getfield(body, vaname, sv, valen)
# argument tuple is not used as a whole, so convert function body
# to one accepting the exact number of arguments we have.
newnames = unique_names(ast,valen)
replace_getfield!(ast, body, vaname, newnames, sv)
na = na-1+valen
# if the argument name is also used as a local variable,
# we need to keep it around as a variable name
for vi in vinflist
if vi[1] === vaname
if vi[3] != 0
vnew = unique_name(enclosing_ast, ast)
push!(enc_vinflist, Any[vnew, vi[2], vi[3]])
push!(spnames, vaname)
push!(spvals, vnew)
push!(enc_locllist, vnew)
end
break
end
end
else
=#
@assert length(argexprs) >= na-1
# construct tuple-forming expression for argument tail
vararg = mk_tuplecall(argexprs[na:end], sv)
argexprs = Any[argexprs[1:(na-1)]..., vararg]
Expand All @@ -2462,6 +2421,36 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference

@assert na == length(argexprs)

spvals = Any[]
for i = 1:length(methsp)
si = methsp[i]
if isa(si, TypeVar)
return NF
end
push!(spvals, si)
end
for i=1:length(spvals)
si = spvals[i]
if isa(si,Symbol) || isa(si,SSAValue) || isa(si,Slot)
spvals[i] = QuoteNode(si)
end
end

methargs = metharg.parameters
nm = length(methargs)

ast = linfo.code
if !isa(ast,Array{Any,1})
ast = ccall(:jl_uncompress_ast, Any, (Any,Any), linfo, ast)
else
ast = astcopy(ast)
end
ast = ast::Array{Any,1}

body = Expr(:block)
body.args = ast
propagate_inbounds, _ = popmeta!(body, :propagate_inbounds)

# see if each argument occurs only once in the body expression
stmts = Any[]
stmts_free = true # true = all entries of stmts are effect_free
Expand Down Expand Up @@ -2728,7 +2717,7 @@ end
# doesn't work on Tuples of TypeVars
const inline_incompletematch_allowed = false

inline_worthy(body, cost::Integer) = true
inline_worthy(body::ANY, cost::Integer) = true
function inline_worthy(body::Expr, cost::Integer=1000) # precondition: 0 < cost; nominal cost = 1000
if popmeta!(body, :inline)[1]
return true
Expand Down
2 changes: 2 additions & 0 deletions src/alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,7 @@ JL_DLLEXPORT jl_lambda_info_t *jl_new_lambda_info_uninit(jl_svec_t *sparam_syms)
li->inCompile = 0;
li->def = NULL;
li->pure = 0;
li->inlineable = 0;
return li;
}

Expand Down Expand Up @@ -473,6 +474,7 @@ static jl_lambda_info_t *jl_copy_lambda(jl_lambda_info_t *linfo)
new_linfo->ssavaluetypes = linfo->ssavaluetypes;
new_linfo->sparam_vals = linfo->sparam_vals;
new_linfo->pure = linfo->pure;
new_linfo->inlineable = linfo->inlineable;
new_linfo->nargs = linfo->nargs;
new_linfo->isva = linfo->isva;
new_linfo->rettype = linfo->rettype;
Expand Down
2 changes: 2 additions & 0 deletions src/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,7 @@ static void jl_serialize_value_(ios_t *s, jl_value_t *v)
jl_serialize_value(s, (jl_value_t*)li->unspecialized_ducttape);
write_int8(s, li->inferred);
write_int8(s, li->pure);
write_int8(s, li->inlineable);
write_int8(s, li->isva);
write_int32(s, li->nargs);
jl_serialize_value(s, (jl_value_t*)li->def);
Expand Down Expand Up @@ -1483,6 +1484,7 @@ static jl_value_t *jl_deserialize_value_(ios_t *s, jl_value_t *vtag, jl_value_t
if (li->unspecialized_ducttape) jl_gc_wb(li, li->unspecialized_ducttape);
li->inferred = read_int8(s);
li->pure = read_int8(s);
li->inlineable = read_int8(s);
li->isva = read_int8(s);
li->nargs = read_int32(s);
li->def = (jl_method_t*)jl_deserialize_value(s, (jl_value_t**)&li->def);
Expand Down
8 changes: 5 additions & 3 deletions src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -3547,7 +3547,7 @@ void jl_init_types(void)
jl_lambda_info_type =
jl_new_datatype(jl_symbol("LambdaInfo"),
jl_any_type, jl_emptysvec,
jl_svec(24,
jl_svec(25,
jl_symbol("code"),
jl_symbol("slotnames"),
jl_symbol("slottypes"),
Expand All @@ -3563,14 +3563,15 @@ void jl_init_types(void)
jl_symbol("isva"),
jl_symbol("inferred"),
jl_symbol("pure"),
jl_symbol("inlineable"),
jl_symbol("inInference"),
jl_symbol("inCompile"),
jl_symbol("jlcall_api"),
jl_symbol(""),
jl_symbol("fptr"),
jl_symbol(""), jl_symbol(""),
jl_symbol(""), jl_symbol("")),
jl_svec(24,
jl_svec(25,
jl_any_type,
jl_array_any_type,
jl_any_type,
Expand All @@ -3590,6 +3591,7 @@ void jl_init_types(void)
jl_bool_type,
jl_bool_type,
jl_bool_type,
jl_bool_type,
jl_any_type,
jl_any_type, jl_any_type,
jl_int32_type, jl_int32_type),
Expand Down Expand Up @@ -3644,9 +3646,9 @@ void jl_init_types(void)
jl_svecset(jl_simplevector_type->types, 0, jl_long_type);
jl_svecset(jl_typename_type->types, 6, jl_long_type);
jl_svecset(jl_methtable_type->types, 3, jl_long_type);
jl_svecset(jl_lambda_info_type->types, 19, jl_voidpointer_type);
jl_svecset(jl_lambda_info_type->types, 20, jl_voidpointer_type);
jl_svecset(jl_lambda_info_type->types, 21, jl_voidpointer_type);
jl_svecset(jl_lambda_info_type->types, 22, jl_voidpointer_type);

jl_compute_field_offsets(jl_datatype_type);
jl_compute_field_offsets(jl_typename_type);
Expand Down
1 change: 1 addition & 0 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ typedef struct _jl_lambda_info_t {
int8_t isva;
int8_t inferred;
int8_t pure;
int8_t inlineable;
int8_t inInference; // flags to tell if inference is running on this function
int8_t inCompile; // flag to tell if codegen is running on this function
int8_t jlcall_api; // the c-abi for fptr; 0 = jl_fptr_t, 1 = jl_fptr_sparam_t
Expand Down

0 comments on commit 5533118

Please sign in to comment.