Skip to content

Commit 10013c5

Browse files
authored
Merge pull request #17185 from JuliaLang/jn/noinline-devirtualize
declassify call-site devirtualization as an inlining optimization
2 parents 878e451 + c0616b8 commit 10013c5

File tree

1 file changed

+41
-33
lines changed

1 file changed

+41
-33
lines changed

base/inference.jl

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,13 @@ type InferenceState
7272
fixedpoint::Bool
7373
typegotoredo::Bool
7474
inworkq::Bool
75+
# optimization
7576
optimize::Bool
77+
inlining::Bool
7678
needtree::Bool
7779
inferred::Bool
7880

79-
function InferenceState(linfo::LambdaInfo, optimize::Bool, needtree::Bool)
81+
function InferenceState(linfo::LambdaInfo, optimize::Bool, inlining::Bool, needtree::Bool)
8082
@assert isa(linfo.code,Array{Any,1})
8183
nslots = length(linfo.slotnames)
8284
nl = label_counter(linfo.code)+1
@@ -161,7 +163,7 @@ type InferenceState
161163
ssavalue_uses, ssavalue_init,
162164
ObjectIdDict(), #Dict{InferenceState, Vector{LineNum}}(),
163165
Vector{Tuple{InferenceState, Vector{LineNum}}}(),
164-
false, false, false, optimize, needtree, false)
166+
false, false, false, optimize, inlining, needtree, false)
165167
push!(active, frame)
166168
nactive[] += 1
167169
return frame
@@ -1408,6 +1410,8 @@ function unshare_linfo!(li::LambdaInfo)
14081410
return li
14091411
end
14101412

1413+
inlining_enabled() = (JLOptions().can_inline == 1)
1414+
14111415
#### entry points for inferring a LambdaInfo given a type signature ####
14121416
function typeinf_edge(method::Method, atypes::ANY, sparams::SimpleVector, needtree::Bool, optimize::Bool, cached::Bool, caller)
14131417
local code = nothing
@@ -1510,7 +1514,7 @@ function typeinf_edge(method::Method, atypes::ANY, sparams::SimpleVector, needtr
15101514
else
15111515
# inference not started yet, make a new frame for a new lambda
15121516
linfo.inInference = true
1513-
frame = InferenceState(unshare_linfo!(linfo::LambdaInfo), optimize, needtree)
1517+
frame = InferenceState(unshare_linfo!(linfo::LambdaInfo), optimize, inlining_enabled(), needtree)
15141518
end
15151519
frame = frame::InferenceState
15161520

@@ -1571,7 +1575,7 @@ function typeinf_ext(linfo::LambdaInfo)
15711575
else
15721576
# toplevel lambda - infer directly
15731577
linfo.inInference = true
1574-
frame = InferenceState(linfo, true, true)
1578+
frame = InferenceState(linfo, true, inlining_enabled(), true)
15751579
typeinf_loop(frame)
15761580
@assert frame.inferred # TODO: deal with this better
15771581
return linfo
@@ -1921,10 +1925,8 @@ function finish(me::InferenceState)
19211925
# if we start to create `SSAValue` in type inference when not
19221926
# optimizing and use unoptimized IR in codegen.
19231927
gotoifnot_elim_pass!(me.linfo, me)
1924-
if JLOptions().can_inline == 1
1925-
inlining_pass!(me.linfo, me)
1926-
inbounds_meta_elim_pass!(me.linfo.code)
1927-
end
1928+
inlining_pass!(me.linfo, me)
1929+
inbounds_meta_elim_pass!(me.linfo.code)
19281930
alloc_elim_pass!(me.linfo, me)
19291931
getfield_elim_pass!(me.linfo, me)
19301932
reindex_labels!(me.linfo, me)
@@ -2322,28 +2324,30 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
23222324
end
23232325
end
23242326
topmod = _topmod(sv)
2325-
if istopfunction(topmod, f, :isbits) && length(atypes)==2 && isType(atypes[2]) &&
2326-
effect_free(argexprs[2],sv,true) && isleaftype(atypes[2].parameters[1])
2327-
return (isbits(atypes[2].parameters[1]),())
2328-
end
23292327
# special-case inliners for known pure functions that compute types
2330-
if isType(e.typ) && !has_typevars(e.typ.parameters[1],true)
2331-
if (is(f, apply_type) || is(f, fieldtype) || is(f, typeof) ||
2332-
istopfunction(topmod, f, :typejoin) ||
2333-
istopfunction(topmod, f, :promote_type))
2334-
# XXX: compute effect_free for the actual arguments
2335-
if length(argexprs) < 2 || effect_free(argexprs[2], sv, true)
2336-
return (e.typ.parameters[1],())
2337-
else
2338-
return (e.typ.parameters[1], Any[argexprs[2]])
2328+
if sv.inlining
2329+
if isType(e.typ) && !has_typevars(e.typ.parameters[1],true)
2330+
if (is(f, apply_type) || is(f, fieldtype) || is(f, typeof) ||
2331+
istopfunction(topmod, f, :typejoin) ||
2332+
istopfunction(topmod, f, :promote_type))
2333+
# XXX: compute effect_free for the actual arguments
2334+
if length(argexprs) < 2 || effect_free(argexprs[2], sv, true)
2335+
return (e.typ.parameters[1],())
2336+
else
2337+
return (e.typ.parameters[1], Any[argexprs[2]])
2338+
end
23392339
end
23402340
end
2341-
end
2342-
if is(f, Core.kwfunc) && length(argexprs) == 2 && isa(e.typ, Const)
2343-
if effect_free(argexprs[2], sv, true)
2344-
return (e.typ.val, ())
2345-
else
2346-
return (e.typ.val, Any[argexprs[2]])
2341+
if istopfunction(topmod, f, :isbits) && length(atypes)==2 && isType(atypes[2]) &&
2342+
effect_free(argexprs[2],sv,true) && isleaftype(atypes[2].parameters[1])
2343+
return (isbits(atypes[2].parameters[1]),())
2344+
end
2345+
if is(f, Core.kwfunc) && length(argexprs) == 2 && isa(e.typ, Const)
2346+
if effect_free(argexprs[2], sv, true)
2347+
return (e.typ.val, ())
2348+
else
2349+
return (e.typ.val, Any[argexprs[2]])
2350+
end
23472351
end
23482352
end
23492353
if isa(f, IntrinsicFunction) || ft IntrinsicFunction ||
@@ -2352,11 +2356,6 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
23522356
end
23532357

23542358
atype_unlimited = argtypes_to_type(atypes)
2355-
if length(atype_unlimited.parameters) - 1 > MAX_TUPLETYPE_LEN
2356-
atype = limit_tuple_type(atype_unlimited)
2357-
else
2358-
atype = atype_unlimited
2359-
end
23602359
function invoke_NF()
23612360
# converts a :call to :invoke
23622361
cache_linfo = ccall(:jl_get_spec_lambda, Any, (Any,), atype_unlimited)
@@ -2366,6 +2365,15 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
23662365
end
23672366
return NF
23682367
end
2368+
if !sv.inlining
2369+
return invoke_NF()
2370+
end
2371+
2372+
if length(atype_unlimited.parameters) - 1 > MAX_TUPLETYPE_LEN
2373+
atype = limit_tuple_type(atype_unlimited)
2374+
else
2375+
atype = atype_unlimited
2376+
end
23692377
meth = _methods_by_ftype(atype, 1)
23702378
if meth === false || length(meth) != 1
23712379
return invoke_NF()
@@ -2943,7 +2951,7 @@ function inlining_pass(e::Expr, sv, linfo)
29432951
end
29442952
end
29452953

2946-
if isdefined(Main, :Base) &&
2954+
if sv.inlining && isdefined(Main, :Base) &&
29472955
((isdefined(Main.Base, :^) && is(f, Main.Base.:^)) ||
29482956
(isdefined(Main.Base, :.^) && is(f, Main.Base.:.^)))
29492957
if length(e.args) == 3 && isa(e.args[3],Union{Int32,Int64})

0 commit comments

Comments
 (0)