Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

inference: cleans up abstract interpretation code #55308

Merged
merged 1 commit into from
Jul 30, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 21 additions & 24 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
arginfo::ArgInfo, si::StmtInfo, @nospecialize(atype),
sv::AbsIntState, max_methods::Int)
𝕃ₚ, 𝕃ᵢ = ipo_lattice(interp), typeinf_lattice(interp)
⊑ₚ = ⊑(𝕃ₚ)
⊑ₚ, ⊔ₚ, ⊔ᵢ = partialorder(𝕃ₚ), join(𝕃ₚ), join(𝕃ᵢ)
if !should_infer_this_call(interp, sv)
add_remark!(interp, sv, "Skipped call in throw block")
# At this point we are guaranteed to end up throwing on this path,
Expand All @@ -37,7 +37,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
(; valid_worlds, applicable, info) = matches
update_valid_age!(sv, valid_worlds)
napplicable = length(applicable)
rettype = excttype = Bottom
rettype = exctype = Bottom
edges = MethodInstance[]
conditionals = nothing # keeps refinement information of call argument types when the return type is boolean
seen = 0 # number of signatures actually inferred
Expand Down Expand Up @@ -96,8 +96,8 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
const_results[i] = const_result
end
edge === nothing || push!(edges, edge)
this_rt = tmerge(this_rt, rt)
this_exct = tmerge(this_exct, exct)
this_rt = this_rt ⊔ₚ rt
this_exct = this_exct ⊔ₚ exct
if bail_out_call(interp, this_rt, sv)
break
end
Expand Down Expand Up @@ -156,17 +156,17 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
end
@assert !(this_conditional isa Conditional || this_rt isa MustAlias) "invalid lattice element returned from inter-procedural context"
seen += 1
rettype = tmerge(𝕃ₚ, rettype, this_rt)
excttype = tmerge(𝕃ₚ, excttype, this_exct)
rettype = rettype ⊔ₚ this_rt
exctype = exctype ⊔ₚ this_exct
if has_conditional(𝕃ₚ, sv) && this_conditional !== Bottom && is_lattice_bool(𝕃ₚ, rettype) && fargs !== nothing
if conditionals === nothing
conditionals = Any[Bottom for _ in 1:length(argtypes)],
Any[Bottom for _ in 1:length(argtypes)]
end
for i = 1:length(argtypes)
cnd = conditional_argtype(𝕃ᵢ, this_conditional, sig, argtypes, i)
conditionals[1][i] = tmerge(𝕃ᵢ, conditionals[1][i], cnd.thentype)
conditionals[2][i] = tmerge(𝕃ᵢ, conditionals[2][i], cnd.elsetype)
conditionals[1][i] = conditionals[1][i] ⊔ᵢ cnd.thentype
conditionals[2][i] = conditionals[2][i] ⊔ᵢ cnd.elsetype
end
end
if bail_out_call(interp, InferenceLoopState(sig, rettype, all_effects), sv)
Expand All @@ -182,14 +182,14 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),

if seen ≠ napplicable
# there is unanalyzed candidate, widen type and effects to the top
rettype = excttype = Any
rettype = exctype = Any
all_effects = Effects()
else
if (matches isa MethodMatches ? (!matches.fullmatch || any_ambig(matches)) :
(!all(matches.fullmatches) || any_ambig(matches)))
# Account for the fact that we may encounter a MethodError with a non-covered or ambiguous signature.
all_effects = Effects(all_effects; nothrow=false)
excttype = tmerge(𝕃ₚ, excttype, MethodError)
exctype = exctype ⊔ₚ MethodError
end
if sv isa InferenceState && fargs !== nothing
slotrefinements = collect_slot_refinements(𝕃ᵢ, applicable, argtypes, fargs, sv)
Expand Down Expand Up @@ -240,7 +240,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
end
end

return CallMeta(rettype, excttype, all_effects, info, slotrefinements)
return CallMeta(rettype, exctype, all_effects, info, slotrefinements)
end

struct FailedMethodMatch
Expand Down Expand Up @@ -367,7 +367,7 @@ function from_interprocedural!(interp::AbstractInterpreter, @nospecialize(rt), s
arginfo::ArgInfo, @nospecialize(maybecondinfo))
rt = collect_limitations!(rt, sv)
if isa(rt, InterMustAlias)
rt = from_intermustalias(rt, arginfo, sv)
rt = from_intermustalias(typeinf_lattice(interp), rt, arginfo, sv)
elseif is_lattice_bool(ipo_lattice(interp), rt)
if maybecondinfo === nothing
rt = widenconditional(rt)
Expand All @@ -387,12 +387,13 @@ function collect_limitations!(@nospecialize(typ), sv::InferenceState)
return typ
end

function from_intermustalias(rt::InterMustAlias, arginfo::ArgInfo, sv::AbsIntState)
function from_intermustalias(𝕃ᵢ::AbstractLattice, rt::InterMustAlias, arginfo::ArgInfo, sv::AbsIntState)
fargs = arginfo.fargs
if fargs !== nothing && 1 ≤ rt.slot ≤ length(fargs)
arg = ssa_def_slot(fargs[rt.slot], sv)
if isa(arg, SlotNumber)
argtyp = widenslotwrapper(arginfo.argtypes[rt.slot])
⊑ = partialorder(𝕃ᵢ)
if rt.vartyp ⊑ argtyp
return MustAlias(arg, rt.vartyp, rt.fldidx, rt.fldtyp)
else
Expand All @@ -412,6 +413,7 @@ function from_interconditional(𝕃ᵢ::AbstractLattice, @nospecialize(rt), sv::
alias = nothing
thentype = elsetype = Any
condval = maybe_extract_const_bool(rt)
⊑, ⋤, ⊓ = partialorder(𝕃ᵢ), strictneqpartialorder(𝕃ᵢ), meet(𝕃ᵢ)
for i in 1:length(fargs)
# find the first argument which supports refinement,
# and intersect all equivalent arguments with it
Expand Down Expand Up @@ -447,24 +449,24 @@ function from_interconditional(𝕃ᵢ::AbstractLattice, @nospecialize(rt), sv::
end
if condval === false
thentype = Bottom
elseif ⊑(𝕃ᵢ, new_thentype, thentype)
elseif new_thentypethentype
thentype = new_thentype
else
thentype = tmeet(𝕃ᵢ, thentype, widenconst(new_thentype))
thentype = thentypewidenconst(new_thentype)
end
if condval === true
elsetype = Bottom
elseif ⊑(𝕃ᵢ, new_elsetype, elsetype)
elseif new_elsetypeelsetype
elsetype = new_elsetype
else
elsetype = tmeet(𝕃ᵢ, elsetype, widenconst(new_elsetype))
elsetype = elsetypewidenconst(new_elsetype)
end
if (slot > 0 || condval !== false) && ⋤(𝕃ᵢ, thentype, old)
if (slot > 0 || condval !== false) && thentypeold
slot = id
if !(arg isa SlotNumber) && argtyp isa MustAlias
alias = argtyp
end
elseif (slot > 0 || condval !== true) && ⋤(𝕃ᵢ, elsetype, old)
elseif (slot > 0 || condval !== true) && elsetypeold
slot = id
if !(arg isa SlotNumber) && argtyp isa MustAlias
alias = argtyp
Expand Down Expand Up @@ -1371,7 +1373,6 @@ function matching_cache_argtypes(𝕃::AbstractLattice, mi::MethodInstance,
given_argtypes = Vector{Any}(undef, length(argtypes))
def = mi.def::Method
nargs = Int(def.nargs)
local condargs = nothing
for i in 1:length(argtypes)
argtype = argtypes[i]
# forward `Conditional` if it conveys a constraint on any other argument
Expand All @@ -1388,10 +1389,6 @@ function matching_cache_argtypes(𝕃::AbstractLattice, mi::MethodInstance,
# TODO bail out here immediately rather than just propagating Bottom ?
given_argtypes[i] = Bottom
else
if condargs === nothing
condargs = Tuple{Int,Int}[]
end
push!(condargs, (slotid, i))
given_argtypes[i] = Conditional(slotid, thentype, elsetype)
end
continue
Expand Down