inference: fixes and improvements for backedge computation (#46741)
This commit consists of the following changes:
* inference: setup separate functions for each backedge kind
Also changes the argument list so that they are ordered as
`(caller, [backedge information])`.
* inference: fix backedge computation for const-prop'ed callsite
With this commit `abstract_call_method_with_const_args` doesn't add
backedge but rather returns the backedge to the caller, letting the
callers like `abstract_call_gf_by_type` and `abstract_invoke` take the
responsibility to add backedge to current context appropriately.
As a result, this fixes the backedge calculation for const-prop'ed
`invoke` callsite.
For example, for the following call graph,
```julia
foo(a::Int) = a > 0 ? :int : println(a)
foo(a::Integer) = a > 0 ? "integer" : println(a)
bar(a::Int) = @invoke foo(a::Integer)
```
Previously we added the wrong backedge `nothing, bar(Int64) from bar(Int64)`:
```julia
julia> last(only(code_typed(()->bar(42))))
String
julia> let m = only(methods(foo, (UInt,)))
@eval Core.Compiler for (sig, caller) in BackedgeIterator($m.specializations[1].backedges)
println(sig, ", ", caller)
end
end
Tuple{typeof(Main.foo), Integer}, bar(Int64) from bar(Int64)
nothing, bar(Int64) from bar(Int64)
```
but now we only add `invoke`-backedge:
```julia
julia> last(only(code_typed(()->bar(42))))
String
julia> let m = only(methods(foo, (UInt,)))
@eval Core.Compiler for (sig, caller) in BackedgeIterator($m.specializations[1].backedges)
println(sig, ", ", caller)
end
end
Tuple{typeof(Main.foo), Integer}, bar(Int64) from bar(Int64)
```
* inference: make `BackedgePair` struct
* add invalidation test for `invoke` call
* optimizer: fixup inlining backedge calculation
Should fix the following backedge calculation:
```julia
julia> m = which(unique, Tuple{Any})
unique(itr)
@ Base set.jl:170
julia> specs = collect(Iterators.filter(m.specializations) do mi
mi === nothing && return false
return mi.specTypes.parameters[end] === Vector{Int} # find specialization of `unique(::Any)` for `::Vector{Int}`
end)
Any[]
julia> Base._unique_dims([1,2,3],:) # no existing callers with specialization `Vector{Int}`, let's make one
3-element Vector{Int64}:
1
2
3
julia> mi = only(Iterators.filter(m.specializations) do mi
mi === nothing && return false
return mi.specTypes.parameters[end] === Vector{Int} # find specialization of `unique(::Any)` for `::Vector{Int}`
end)
MethodInstance for unique(::Vector{Int64})
julia> mi.def
unique(itr)
@ Base set.jl:170
julia> mi.backedges
3-element Vector{Any}:
Tuple{typeof(unique), Any}
MethodInstance for Base._unique_dims(::Vector{Int64}, ::Colon)
MethodInstance for Base._unique_dims(::Vector{Int64}, ::Colon) # <= now we don't register this backedge
```