Skip to content

Commit 382129f

Browse files
committed
optimizer: fix #42840, the performance regression introduced by #42766 (#42841)
1 parent 901a3a5 commit 382129f

File tree

2 files changed

+47
-13
lines changed

2 files changed

+47
-13
lines changed

base/compiler/ssair/inlining.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1392,7 +1392,7 @@ function assemble_inline_todo!(ir::IRCode, state::InliningState)
13921392
ir, idx, stmt, info, sig,
13931393
state, sig.f === Core.invoke, todo) && continue
13941394
end
1395-
info = info.call
1395+
info = info.call # cascade to the non-constant handling
13961396
end
13971397

13981398
if isa(info, OpaqueClosureCallInfo)

test/compiler/inline.jl

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -393,24 +393,31 @@ let f(x) = (x...,)
393393
@test code_typed(f, Tuple{Union{Int64, CartesianIndex{1}, CartesianIndex{3}}})[1][2] == Tuple{Int64}
394394
end
395395

396-
# check if `x` is a statically-resolved call of a function whose name is `sym`
397-
isinvoke(@nospecialize(x), sym::Symbol) = isinvoke(x, mi->mi.def.name===sym)
398-
function isinvoke(@nospecialize(x), pred)
399-
if Meta.isexpr(x, :invoke)
400-
return pred(x.args[1]::Core.MethodInstance)
396+
import Core.Compiler: argextype, singleton_type
397+
398+
code_typed1(args...; kwargs...) = first(only(code_typed(args...; kwargs...)))::Core.CodeInfo
399+
get_code(args...; kwargs...) = code_typed1(args...; kwargs...).code
400+
401+
# check if `x` is a dynamic call of a given function
402+
function iscall((src, f)::Tuple{Core.CodeInfo,Function}, @nospecialize(x))
403+
return iscall(x) do @nospecialize x
404+
singleton_type(argextype(x, src, Any[])) === f
401405
end
402-
return false
403406
end
404-
code_typed1(args...; kwargs...) = (first(only(code_typed(args...; kwargs...)))::Core.CodeInfo).code
407+
iscall(pred, @nospecialize(x)) = Meta.isexpr(x, :call) && pred(x.args[1])
408+
409+
# check if `x` is a statically-resolved call of a function whose name is `sym`
410+
isinvoke(sym::Symbol, @nospecialize(x)) = isinvoke(mi->mi.def.name===sym, x)
411+
isinvoke(pred, @nospecialize(x)) = Meta.isexpr(x, :invoke) && pred(x.args[1]::Core.MethodInstance)
405412

406413
# https://github.com/JuliaLang/julia/issues/42754
407-
# inline union-split constant-prop'ed sources
414+
# inline union-split constant-prop'ed results
408415
mutable struct X42754
409416
# NOTE in order to confuse `fieldtype_tfunc`, we need to have at least two fields with different types
410417
a::Union{Nothing, Int}
411418
b::Symbol
412419
end
413-
let code = code_typed1((X42754, Union{Nothing,Int})) do x, a
420+
let code = get_code((X42754, Union{Nothing,Int})) do x, a
414421
# this `setproperty` call would be union-split and constant-prop will happen for
415422
# each signature: inlining would fail if we don't use constant-prop'ed source
416423
# since the approximate inlining cost of `convert(fieldtype(X, sym), a)` would
@@ -430,12 +437,39 @@ end
430437

431438
import Base: @constprop
432439

440+
# test union-split callsite with successful and unsuccessful constant-prop' results
441+
@constprop :aggressive @inline f42840(xs, a::Int) = xs[a] # should be successful, and inlined
442+
@constprop :none @noinline f42840(xs::AbstractVector, a::Int) = xs[a] # should be unsuccessful, but still statically resolved
443+
let src = code_typed1((Union{Tuple{Int,Int,Int}, Vector{Int}},)) do xs
444+
f42840(xs, 2)
445+
end
446+
@test count(src.code) do @nospecialize x
447+
iscall((src, getfield), x) # `(xs::Tuple{Int,Int,Int})[a::Const(2)]` => `getfield(xs, 2)`
448+
end == 1
449+
@test count(src.code) do @nospecialize x
450+
isinvoke(:f42840, x)
451+
end == 1
452+
end
453+
# a bit weird, but should handle this kind of case as well
454+
@constprop :aggressive @noinline g42840(xs, a::Int) = xs[a] # should be successful, but only statically resolved
455+
@constprop :none @inline g42840(xs::AbstractVector, a::Int) = xs[a] # should be unsuccessful, still inlined
456+
let src = code_typed1((Union{Tuple{Int,Int,Int}, Vector{Int}},)) do xs
457+
g42840(xs, 2)
458+
end
459+
@test count(src.code) do @nospecialize x
460+
iscall((src, Base.arrayref), x) # `(xs::Vector{Int})[a::Const(2)]` => `Base.arrayref(true, xs, 2)`
461+
end == 1
462+
@test count(src.code) do @nospecialize x
463+
isinvoke(:g42840, x)
464+
end == 1
465+
end
466+
433467
# test single, non-dispatchtuple callsite inlining
434468

435469
@constprop :none @inline test_single_nondispatchtuple(@nospecialize(t)) =
436470
isa(t, DataType) && t.name === Type.body.name
437471
let
438-
code = code_typed1((Any,)) do x
472+
code = get_code((Any,)) do x
439473
test_single_nondispatchtuple(x)
440474
end
441475
@test all(code) do @nospecialize(x)
@@ -451,7 +485,7 @@ end
451485
@constprop :aggressive @inline test_single_nondispatchtuple(c, @nospecialize(t)) =
452486
c && isa(t, DataType) && t.name === Type.body.name
453487
let
454-
code = code_typed1((Any,)) do x
488+
code = get_code((Any,)) do x
455489
test_single_nondispatchtuple(true, x)
456490
end
457491
@test all(code) do @nospecialize(x)
@@ -481,7 +515,7 @@ let m = Module()
481515
end
482516
end
483517

484-
$code_typed1(setter, (Vector{Foo},))
518+
$get_code(setter, (Vector{Foo},))
485519
end
486520

487521
@test !any(x->isinvoke(x, :setproperty!), code)

0 commit comments

Comments
 (0)