Skip to content

Commit

Permalink
fix recursion detection in constant prop (#36148)
Browse files Browse the repository at this point in the history
  • Loading branch information
JeffBezanson authored Jun 6, 2020
1 parent d825de8 commit 87a416f
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 2 deletions.
22 changes: 20 additions & 2 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
# if there's a possibility we could constant-propagate a better result
# (hopefully without doing too much work), try to do that now
# TODO: it feels like this could be better integrated into abstract_call_method / typeinf_edge
const_rettype = abstract_call_method_with_const_args(interp, rettype, f, argtypes, applicable[nonbot]::SimpleVector, sv)
const_rettype = abstract_call_method_with_const_args(interp, rettype, f, argtypes, applicable[nonbot]::SimpleVector, sv, edgecycle)
if const_rettype rettype
# use the better result, if it's a refinement of rettype
rettype = const_rettype
Expand Down Expand Up @@ -185,7 +185,7 @@ function const_prop_profitable(@nospecialize(arg))
return false
end

function abstract_call_method_with_const_args(interp::AbstractInterpreter, @nospecialize(rettype), @nospecialize(f), argtypes::Vector{Any}, match::SimpleVector, sv::InferenceState)
function abstract_call_method_with_const_args(interp::AbstractInterpreter, @nospecialize(rettype), @nospecialize(f), argtypes::Vector{Any}, match::SimpleVector, sv::InferenceState, edgecycle::Bool)
method = match[3]::Method
nargs::Int = method.nargs
method.isva && (nargs -= 1)
Expand Down Expand Up @@ -259,6 +259,24 @@ function abstract_call_method_with_const_args(interp::AbstractInterpreter, @nosp
inf_cache = get_inference_cache(interp)
inf_result = cache_lookup(mi, argtypes, inf_cache)
if inf_result === nothing
if edgecycle
# if there might be a cycle, check to make sure we don't end up
# calling ourselves here.
infstate = sv
cyclei = 0
while !(infstate === nothing)
if method === infstate.linfo.def && any(infstate.result.overridden_by_const)
return Any
end
if cyclei < length(infstate.callers_in_cycle)
cyclei += 1
infstate = infstate.callers_in_cycle[cyclei]
else
cyclei = 0
infstate = infstate.parent
end
end
end
inf_result = InferenceResult(mi, argtypes)
frame = InferenceState(inf_result, #=cache=#false, interp)
frame === nothing && return Any # this is probably a bad generated function (unsound), but just ignore it
Expand Down
24 changes: 24 additions & 0 deletions test/compiler/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2623,3 +2623,27 @@ end
_size_ish(F::NotQRSparse, i::Integer) = size(getprop(F, :B), 1)
_call_size_ish(x) = _size_ish(x,1)
@test Base.return_types(_call_size_ish, (NotQRSparse,)) == Any[Int]

module TestConstPropRecursion
mutable struct Node
data
child::Node
sibling::Node
end

function Base.iterate(n::Node, state::Node = n.child)
n === state && return nothing
return state, state === state.sibling ? n : state.sibling
end

@inline function depth(node::Node, d)
childd = d + 1
for c in node
d = max(d, depth(c, childd))
end
return d
end

f(n) = depth(n, 1)
end
@test Base.return_types(TestConstPropRecursion.f, (TestConstPropRecursion.Node,)) == Any[Int]

0 comments on commit 87a416f

Please sign in to comment.