Skip to content

Commit

Permalink
optimizer: fix #42840, the performance regression introduced by #42766 (
Browse files Browse the repository at this point in the history
  • Loading branch information
aviatesk committed Oct 29, 2021
1 parent 901a3a5 commit 83bd616
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 9 deletions.
2 changes: 1 addition & 1 deletion base/compiler/ssair/inlining.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1392,7 +1392,7 @@ function assemble_inline_todo!(ir::IRCode, state::InliningState)
ir, idx, stmt, info, sig,
state, sig.f === Core.invoke, todo) && continue
end
info = info.call
info = info.call # cascade to the non-constant handling
end

if isa(info, OpaqueClosureCallInfo)
Expand Down
51 changes: 43 additions & 8 deletions test/compiler/inline.jl
Original file line number Diff line number Diff line change
Expand Up @@ -393,18 +393,26 @@ let f(x) = (x...,)
@test code_typed(f, Tuple{Union{Int64, CartesianIndex{1}, CartesianIndex{3}}})[1][2] == Tuple{Int64}
end

# check if `x` is a statically-resolved call of a function whose name is `sym`
isinvoke(@nospecialize(x), sym::Symbol) = isinvoke(x, mi->mi.def.name===sym)
function isinvoke(@nospecialize(x), pred)
if Meta.isexpr(x, :invoke)
return pred(x.args[1]::Core.MethodInstance)
import Core.Compiler: argextype, singleton_type
const EMPTY_SPTYPES = Core.Compiler.EMPTY_SLOTTYPES

code_typed1(args...; kwargs...) = first(only(code_typed(args...; kwargs...)))::Core.CodeInfo
get_code(args...; kwargs...) = code_typed1(args...; kwargs...).code

# check if `x` is a dynamic call of a given function
function iscall((src, f)::Tuple{Core.CodeInfo,Function}, @nospecialize(x))
return iscall(x) do @nospecialize x
singleton_type(argextype(x, src, EMPTY_SPTYPES)) === f
end
return false
end
code_typed1(args...; kwargs...) = (first(only(code_typed(args...; kwargs...)))::Core.CodeInfo).code
iscall(pred, @nospecialize(x)) = Meta.isexpr(x, :call) && pred(x.args[1])

# check if `x` is a statically-resolved call of a function whose name is `sym`
isinvoke(sym::Symbol, @nospecialize(x)) = isinvoke(mi->mi.def.name===sym, x)
isinvoke(pred, @nospecialize(x)) = Meta.isexpr(x, :invoke) && pred(x.args[1]::Core.MethodInstance)

# https://github.com/JuliaLang/julia/issues/42754
# inline union-split constant-prop'ed sources
# inline union-split constant-prop'ed results
mutable struct X42754
# NOTE in order to confuse `fieldtype_tfunc`, we need to have at least two fields with different types
a::Union{Nothing, Int}
Expand All @@ -430,6 +438,33 @@ end

import Base: @constprop

# test union-split callsite with successful and unsuccessful constant-prop' results
@constprop :aggressive @inline f42840(xs, a::Int) = xs[a] # should be successful, and inlined
@constprop :none @noinline f42840(xs::AbstractVector, a::Int) = xs[a] # should be unsuccessful, but still statically resolved
let src = code_typed((Union{Tuple{Int,Int,Int}, Vector{Int}},)) do xs
f42840(xs, 2)
end |> only |> first
@test count(src.code) do @nospecialize x
iscall((src, getfield), x) # `(xs::Tuple{Int,Int,Int})[a::Const(2)]` => `getfield(xs, 2)`
end == 1
@test count(src.code) do @nospecialize x
isinvoke(:f42840, x)
end == 1
end
# a bit weird, but should handle this kind of case as well
@constprop :aggressive @noinline g42840(xs, a::Int) = xs[a] # should be successful, but only statically resolved
@constprop :none @inline g42840(xs::AbstractVector, a::Int) = xs[a] # should be unsuccessful, still inlined
let src = code_typed((Union{Tuple{Int,Int,Int}, Vector{Int}},)) do xs
g42840(xs, 2)
end |> only |> first
@test count(src.code) do @nospecialize x
iscall((src, Base.arrayref), x) # `(xs::Vector{Int})[a::Const(2)]` => `Base.arrayref(true, xs, 2)`
end == 1
@test count(src.code) do @nospecialize x
isinvoke(:g42840, x)
end == 1
end

# test single, non-dispatchtuple callsite inlining

@constprop :none @inline test_single_nondispatchtuple(@nospecialize(t)) =
Expand Down

0 comments on commit 83bd616

Please sign in to comment.