Skip to content

Commit 1dae0e0

Browse files
committed
fix #16434, superlinear compiler run time on large functions
improves the algorithm in `type_annotate!` to look only at uses of variables instead of (all variables)*(all statements)
1 parent 6591216 commit 1dae0e0

File tree

1 file changed

+45
-28
lines changed

1 file changed

+45
-28
lines changed

base/inference.jl

Lines changed: 45 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1966,14 +1966,32 @@ function finish(me::InferenceState)
19661966
nothing
19671967
end
19681968

1969-
function eval_annotate(e::ANY, vtypes::ANY, sv::InferenceState, undefs)
1969+
function record_slot_type!(id, vt::ANY, slottypes)
1970+
if vt !== Bottom
1971+
otherTy = slottypes[id]
1972+
if otherTy === Bottom
1973+
slottypes[id] = vt
1974+
elseif otherTy !== Any && !typeseq(otherTy, vt)
1975+
slottypes[id] = Any
1976+
end
1977+
end
1978+
end
1979+
1980+
function eval_annotate(e::ANY, vtypes::ANY, sv::InferenceState, undefs, pass)
19701981
if isa(e, Slot)
1971-
t = abstract_eval(e, vtypes, sv)
1972-
s = vtypes[e.id]
1973-
if s.undef
1974-
undefs[e.id] = true
1982+
id = (e::Slot).id
1983+
s = vtypes[id]
1984+
vt = widenconst(s.typ)
1985+
if pass == 1
1986+
# first pass: find used-undef variables and type-constant variables
1987+
if s.undef
1988+
undefs[id] = true
1989+
end
1990+
record_slot_type!(id, vt, sv.linfo.slottypes)
1991+
return e
19751992
end
1976-
return t === sv.linfo.slottypes[e.id] ? e : TypedSlot(e.id, t)
1993+
# second pass: add type annotations where needed
1994+
return vt === sv.linfo.slottypes[id] ? e : TypedSlot(id, vt)
19771995
end
19781996

19791997
if !isa(e,Expr)
@@ -1985,14 +2003,14 @@ function eval_annotate(e::ANY, vtypes::ANY, sv::InferenceState, undefs)
19852003
if is(head,:static_typeof) || is(head,:line) || is(head,:const)
19862004
return e
19872005
elseif is(head,:(=))
1988-
e.args[2] = eval_annotate(e.args[2], vtypes, sv, undefs)
2006+
e.args[2] = eval_annotate(e.args[2], vtypes, sv, undefs, pass)
19892007
return e
19902008
end
19912009
i0 = is(head,:method) ? 2 : 1
19922010
for i=i0:length(e.args)
19932011
subex = e.args[i]
19942012
if !(isa(subex,Number) || isa(subex,AbstractString))
1995-
e.args[i] = eval_annotate(subex, vtypes, sv, undefs)
2013+
e.args[i] = eval_annotate(subex, vtypes, sv, undefs, pass)
19962014
end
19972015
end
19982016
return e
@@ -2013,38 +2031,31 @@ end
20132031
# annotate types of all symbols in AST
20142032
function type_annotate!(linfo::LambdaInfo, states::Array{Any,1}, sv::ANY, nargs)
20152033
nslots = length(states[1])
2016-
for i = 1:nslots
2034+
nargs = linfo.nargs
2035+
for i = 1:nargs
2036+
linfo.slottypes[i] = widenconst(states[1][i].typ)
2037+
end
2038+
for i = nargs+1:nslots
20172039
linfo.slottypes[i] = Bottom
20182040
end
20192041
undefs = fill(false, nslots)
20202042
body = linfo.code::Array{Any,1}
20212043
nexpr = length(body)
2022-
for i=1:nexpr
2023-
# identify variables always used as the same type
2024-
st_i = states[i]
2025-
if st_i !== ()
2026-
for j = 1:nslots
2027-
vt = widenconst(st_i[j].typ)
2028-
if vt !== Bottom
2029-
otherTy = linfo.slottypes[j]
2030-
if otherTy === Bottom
2031-
linfo.slottypes[j] = vt
2032-
elseif otherTy !== Any && !typeseq(otherTy, vt)
2033-
linfo.slottypes[j] = Any
2034-
end
2035-
end
2036-
end
2037-
end
2038-
end
20392044
i = 1
20402045
optimize = sv.optimize::Bool
20412046
while i <= nexpr
20422047
st_i = states[i]
2048+
expr = body[i]
20432049
if st_i !== ()
20442050
# st_i === () => unreached statement (see issue #7836)
2045-
body[i] = eval_annotate(body[i], st_i, sv, undefs)
2051+
eval_annotate(expr, st_i, sv, undefs, 1)
2052+
if isa(expr, Expr) && expr.head == :(=) && i < nexpr && isa(expr.args[1],Slot) && states[i+1] !== ()
2053+
# record type of assigned slot by looking at the next statement.
2054+
# this is needed in case the slot is never used (which makes eval_annotate miss it).
2055+
id = expr.args[1].id
2056+
record_slot_type!(id, widenconst(states[i+1][id].typ), linfo.slottypes)
2057+
end
20462058
elseif optimize
2047-
expr = body[i]
20482059
if isa(expr, Expr) && expr_cannot_delete(expr::Expr)
20492060
i += 1
20502061
continue
@@ -2058,6 +2069,12 @@ function type_annotate!(linfo::LambdaInfo, states::Array{Any,1}, sv::ANY, nargs)
20582069
end
20592070
i += 1
20602071
end
2072+
for i = 1:nexpr
2073+
st_i = states[i]
2074+
if st_i !== ()
2075+
body[i] = eval_annotate(body[i], st_i, sv, undefs, 2)
2076+
end
2077+
end
20612078

20622079
# mark used-undef variables
20632080
for i = 1:nslots

0 commit comments

Comments
 (0)