follow up the inlining unmatched type param PR#46484
Conversation
|
Thanks Shuhei! Another thing that I was working on but wanted to move along the PR was extending The only part I wasn't sure about was trying to do an |
This commit follows up #45062: - eliminate closure capturing, and improve type stability a bit - refactor the test structure so that they are more aligned with the other parts of tests
ba8d525 to
b26a44e
Compare
| end | ||
| i === nothing && return nothing | ||
| _any(j->has_typevar(sig.parameters[j], tvar), i+1:length(sig.parameters)) && return nothing | ||
| let sig=sig |
There was a problem hiding this comment.
Can you explain this? I guess it's related to closure capturing?
There was a problem hiding this comment.
Yeah, sometimes local variables used within closures cause capturing, which results in a case the local variable is instantiated as Core.Box. In that case we can use this let magic to prevent the capturing and get more type stability (see https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-captured this performance tips section for more details).
I caught this capturing with JET as follows:
julia> using JET
# the tweaked version
julia> @eval Core.Compiler @inline function _lift_svec_ref1(def::Expr, compact::IncrementalCompact)
m = argextype(def.args[2], compact)
isa(m, Const) || return nothing
m = m.val
isa(m, Method) || return nothing
# TODO: More general structural analysis of the intersection
length(def.args) >= 3 || return nothing
sig = m.sig
isa(sig, UnionAll) || return nothing
tvar = sig.var
sig = sig.body
isa(sig, DataType) || return nothing
sig.name === Tuple.name || return nothing
length(sig.parameters) >= 1 || return nothing
i = let sig=sig
findfirst(j->has_typevar(sig.parameters[j], tvar), 1:length(sig.parameters))
end
i === nothing && return nothing
let sig=sig
any(j->has_typevar(sig.parameters[j], tvar), i+1:length(sig.parameters))
end && return nothing
arg = sig.parameters[i]
isa(arg, DataType) || return nothing
rarg = def.args[2 + i]
isa(rarg, SSAValue) || return nothing
argdef = compact[rarg][:inst]
if isexpr(argdef, :new)
rarg = argdef.args[1]
isa(rarg, SSAValue) || return nothing
argdef = compact[rarg][:inst]
end
is_known_call(argdef, Core.apply_type, compact) || return nothing
length(argdef.args) == 3 || return nothing
applyT = argextype(argdef.args[2], compact)
isa(applyT, Const) || return nothing
applyT = applyT.val
isa(applyT, UnionAll) || return nothing
applyTvar = applyT.var
applyTbody = applyT.body
isa(applyTbody, DataType) || return nothing
applyTbody.name == arg.name || return nothing
length(applyTbody.parameters) == length(arg.parameters) == 1 || return nothing
applyTbody.parameters[1] === applyTvar || return nothing
arg.parameters[1] === tvar || return nothing
return LiftedValue(argdef.args[3])
end
_lift_svec_ref1 (generic function with 1 method)
julia> report_opt(Core.Compiler._lift_svec_ref1, (Expr,Core.Compiler.IncrementalCompact))
No errors detected
# the original version
julia> @eval Core.Compiler @inline function _lift_svec_ref2(def::Expr, compact::IncrementalCompact)
m = argextype(def.args[2], compact)
isa(m, Const) || return nothing
m = m.val
isa(m, Method) || return nothing
# TODO: More general structural analysis of the intersection
length(def.args) >= 3 || return nothing
sig = m.sig
isa(sig, UnionAll) || return nothing
tvar = sig.var
sig = sig.body
isa(sig, DataType) || return nothing
sig.name === Tuple.name || return nothing
length(sig.parameters) >= 1 || return nothing
i = findfirst(j->has_typevar(sig.parameters[j], tvar), 1:length(sig.parameters))
i === nothing && return nothing
any(j->has_typevar(sig.parameters[j], tvar), i+1:length(sig.parameters)) && return nothing
arg = sig.parameters[i]
isa(arg, DataType) || return nothing
rarg = def.args[2 + i]
isa(rarg, SSAValue) || return nothing
argdef = compact[rarg][:inst]
if isexpr(argdef, :new)
rarg = argdef.args[1]
isa(rarg, SSAValue) || return nothing
argdef = compact[rarg][:inst]
end
is_known_call(argdef, Core.apply_type, compact) || return nothing
length(argdef.args) == 3 || return nothing
applyT = argextype(argdef.args[2], compact)
isa(applyT, Const) || return nothing
applyT = applyT.val
isa(applyT, UnionAll) || return nothing
applyTvar = applyT.var
applyTbody = applyT.body
isa(applyTbody, DataType) || return nothing
applyTbody.name == arg.name || return nothing
length(applyTbody.parameters) == length(arg.parameters) == 1 || return nothing
applyTbody.parameters[1] === applyTvar || return nothing
arg.parameters[1] === tvar || return nothing
return LiftedValue(argdef.args[3])
end
_lift_svec_ref2 (generic function with 1 method)
julia> report_opt(Core.Compiler._lift_svec_ref2, (Expr,Core.Compiler.IncrementalCompact))
═════ 18 possible errors found ═════
┌ @ REPL[71]:16 1 Core.Compiler.:(:) Core.Compiler.length(getfield(sig, :contents).parameters)
│┌ @ range.jl:3 Core.Compiler.promote(a, b)
││┌ @ promotion.jl:381 Core.Compiler._promote(x, y)
│││┌ @ promotion.jl:357 R = Core.Compiler.promote_type(T, S)
││││┌ @ promotion.jl:307 Core.Compiler.promote_result(T, S, Core.Compiler.promote_rule(T, S), Core.Compiler.promote_rule(S, T))
│││││┌ @ promotion.jl:321 Core.Compiler.promote_type(T, S)
││││││┌ @ promotion.jl:307 Core.Compiler.promote_result(T, S, Core.Compiler.promote_rule(T, S), Core.Compiler.promote_rule(S, T))
│││││││┌ @ promotion.jl:324 Core.Compiler.typejoin(T, S)
││││││││┌ @ promotion.jl:36 Core.Compiler.typejoin(a, b.body)
│││││││││┌ @ promotion.jl:40 Core.Compiler.typejoin(b.a, b.b)
││││││││││┌ @ promotion.jl:126 Core.Compiler.UnionAll(%430, %432)
│││││││││││ runtime dispatch detected: Core.Compiler.UnionAll(%430::Any, %432::Any)::Any
││││││││││└────────────────────
│││││││││┌ @ promotion.jl:126 Core.Compiler.UnionAll(%408, %410)
││││││││││ runtime dispatch detected: Core.Compiler.UnionAll(%408::Any, %410::Any)::Any
│││││││││└────────────────────
││││││││┌ @ promotion.jl:126 Core.Compiler.UnionAll(%403, %405)
│││││││││ runtime dispatch detected: Core.Compiler.UnionAll(%403::Any, %405::Any)::Any
││││││││└────────────────────
││┌ @ promotion.jl:382 Core.Compiler.not_sametype(tuple(x, y), tuple(px, py))
│││┌ @ promotion.jl:399 Core.Compiler.sametype_error(x)
││││┌ @ promotion.jl:405 Core.Compiler.map(#43, input)
│││││┌ @ tuple.jl:274 f(t[1])
││││││┌ @ promotion.jl:406 %1()
│││││││ runtime dispatch detected: %1::Any(::Int64)::Any
││││││└────────────────────
││││┌ @ promotion.jl:405 Core.Compiler.error("promotion of types ", Core.Compiler.join(Core.Compiler.map(#43, input), ", ", " and "), " failed to change any arguments")
│││││┌ @ error.jl:44 Base.string(s...)
││││││┌ @ strings/io.jl:185 Base.print_to_string(xs...)
│││││││┌ @ strings/io.jl:144 print(%79, %82)
││││││││ runtime dispatch detected: print(%79::IOBuffer, %82::Any)::Any
│││││││└─────────────────────
┌ @ REPL[71]:2 sig = Core.Box()
│ captured variable `sig` detected
└──────────────
┌ @ REPL[71]:14 Core.Compiler.length(%69)
│ runtime dispatch detected: Core.Compiler.length(%69::Any)::Any
└───────────────
┌ @ REPL[71]:14 %70 Core.Compiler.:>= 1
│ runtime dispatch detected: (%70::Any Core.Compiler.:>= 1)::Any
└───────────────
┌ @ REPL[71]:16 Core.Compiler.length(%83)
│ runtime dispatch detected: Core.Compiler.length(%83::Any)::Any
└───────────────
┌ @ REPL[71]:16 1 Core.Compiler.:(:) %84
│ runtime dispatch detected: (1 Core.Compiler.:(:) %84::Any)::Any
└───────────────
┌ @ REPL[71]:16 Core.Compiler.findfirst(%77, %99)
│ runtime dispatch detected: Core.Compiler.findfirst(%77::Core.Compiler.var"#502#504", %99::Any)::Any
└───────────────
┌ @ REPL[71]:18 %100 Core.Compiler.:+ 1
│ runtime dispatch detected: (%100::Any Core.Compiler.:+ 1)::Any
└───────────────
┌ @ REPL[71]:18 Core.Compiler.length(%114)
│ runtime dispatch detected: Core.Compiler.length(%114::Any)::Any
└───────────────
┌ @ REPL[71]:18 %108 Core.Compiler.:(:) %115
│ runtime dispatch detected: (%108::Any Core.Compiler.:(:) %115::Any)::Any
└───────────────
┌ @ REPL[71]:18 Core.Compiler.any(%107, %116)
│ runtime dispatch detected: Core.Compiler.any(%107::Core.Compiler.var"#503#505", %116::Any)::Bool
└───────────────
┌ @ REPL[71]:20 %125[%100]
│ runtime dispatch detected: (%125::Any)[%100::Any]::Any
└───────────────
┌ @ REPL[71]:23 2 Core.Compiler.:+ %100
│ runtime dispatch detected: (2 Core.Compiler.:+ %100::Any)::Any
└───────────────
┌ @ REPL[71]:23 %130[%131]
│ runtime dispatch detected: (%130::Vector{Any})[%131::Any]::Any
└───────────────
That sounds to be a good improvement. Let's do it as a separate PR after finishing up the other immediate tasks assigned to us. |
This commit follows up #45062:
the other parts of tests