-
Notifications
You must be signed in to change notification settings - Fork 35
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
Const-prop through tuple #71
Comments
I've had to work around a couple of things like this by just making them primitives to force a specialization but this is starting to get bothersome. It looks like in this case |
This appears to be fixed by JuliaLang/julia#28955: julia> code_typed(f, Tuple{Int})
1-element Array{Any,1}:
CodeInfo(
1 1 ─ %1 = (getfield)(args, 1)::Int64 │
│ %2 = (Core.tuple)(%1)::Tuple{Int64} │╻ outer
│ %3 = Core.tuple::typeof(tuple) ││
│ %4 = Main.Bool::Type{Bool} ││
│ %5 = invoke fallback($(QuoteNode(Cassette.Context{nametype(Ctx),Nothing,Cassette.NoPass,Nothing,Nothing}(nametype(Ctx)(), nothing, Cassette.NoPass(), nothing, nothing)))::Cassette.Context{nametype(Ctx),Nothing,Cassette.NoPass,Nothing,Nothing}, %3::Function, %4::Vararg{Any,N} where N)::Tuple{DataType}
│ %6 = Core._apply::typeof(_apply) │││╻ apply_args
│ (%6)(tuple, %5, %2)::Tuple{Type{Bool},Int64} ││││
└── return │
) => Nothing |
The extra _apply here is probably fixed by JuliaLang/julia#29622 |
Initial repro seems fixed indeed, but zooming out the general pattern as used by outer(A::AbstractArray, i...) = inner(Bool, A, i...)
inner(::Type{Bool}, A::AbstractArray, i...) = nothing
using Cassette
Cassette.@context Ctx
overdubbed = (args...) -> Cassette.overdub(Ctx(), outer, args...)
using InteractiveUtils
code_warntype(outer, Tuple{Vector{Int}, Int})
code_warntype(overdubbed, Tuple{Vector{Int}, Int})
Latest master of both Julia and Cassette. |
Looks like there's still some
at least this should be easier to handle now that we have |
Did some more digging here today through the If we look at the result for the overdubbed julia> r = p.cache[11]; # the one with the `Any` result
julia> r.linfo
MethodInstance for overdub(::Cassette.Context{nametype(Ctx),Nothing,Cassette.NoPass,Nothing,Nothing}, ::typeof(outer), ::Array{Int64,1}, ::Int64)
julia> r.src
CodeInfo(
1 1 ─ %1 = (Core.getfield)(##overdub_arguments#359, 2)::Array{Int64,1} │
│ %2 = (Core.getfield)(##overdub_arguments#359, 3)::Int64 │
└── goto #3 if not true │
2 ─ %4 = Main.Bool::Type{Bool} │
3 ─ %5 = φ (#2 => %4)::DataType │
│ %6 = φ (#2 => %1)::Array{Int64,1} │
└── goto #5 if not true │
4 ─ %8 = (Cassette.overdub)($(QuoteNode(Cassette.Context{nametype(Ctx),Nothing,Cassette.NoPass,Nothing,Nothing}(nametype(Ctx)(), nothing, Cassette.NoPass(), nothing, nothing))), inner, %5, %6, %2)::Any
5 ─ %9 = φ (#4 => %8, #3 => $(QuoteNode(Cassette.OverdubInstead())))::Any │
└── return %9 │
) Looks like there's a phi node there that's normalizing Plugging away further (on the branch from JuliaLang/julia#29893): julia> ctx = Ctx();
julia> tup(args...) = tuple(args...)
tup (generic function with 1 method)
julia> code_typed(tup, Tuple{Type{Bool},Int}, optimize = false)
1-element Array{Any,1}:
CodeInfo(
@ REPL[29]:1 within `tup'
1 ─ %1 = (Core._apply)(Main.tuple, args)::PartialTuple(Tuple{DataType,Int64}, Any[Const(Bool, false), Int64])
└── return %1
) => Tuple{DataType,Int64}
julia> code_typed(Cassette.overdub, Tuple{typeof(ctx), typeof(tup), Type{Bool},Int}, optimize = false)
1-element Array{Any,1}:
CodeInfo(
@ REPL[29]:1 within `tup'
1 ─ (#self# = (Core.getfield)(##overdub_arguments#359, 1))::Const(tup, false)
│ %2 = (Core.getfield)(##overdub_arguments#359, 2)::Const(Bool, false)
│ %3 = (Core.getfield)(##overdub_arguments#359, 3)::Int64
│ (args = (Core.tuple)(%2, %3))::PartialTuple(Tuple{DataType,Int64}, Any[Const(Bool, false), Int64])
│ (Cassette.prehook)(##overdub_context#358, Core._apply, Main.tuple, args::PartialTuple(Tuple{DataType,Int64}, Any[Const(Bool, false), Int64]))::Any
│ (##overdub_tmp#360 = (Cassette.execute)(##overdub_context#358, Core._apply, Main.tuple, args::PartialTuple(Tuple{DataType,Int64}, Any[Const(Bool, false), Int64])))::Const(OverdubInstead(), false)
│ %7 = (##overdub_tmp#360::Const(OverdubInstead(), false) isa Cassette.OverdubInstead)::Const(true, false)
└── goto #3 if not %7
2 ─ (##overdub_tmp#360 = (Cassette.overdub)(##overdub_context#358, Core._apply, Main.tuple, args::PartialTuple(Tuple{DataType,Int64}, Any[Const(Bool, false), Int64])))::Tuple{DataType,Int64}
3 ┄ (Cassette.posthook)(##overdub_context#358, ##overdub_tmp#360::Tuple{DataType,Int64}, Core._apply, Main.tuple, args::PartialTuple(Tuple{DataType,Int64}, Any[Const(Bool, false), Int64]))::Any
│ %11 = ##overdub_tmp#360::Tuple{DataType,Int64}::Tuple{DataType,Int64}
└── return %11
) => Tuple{DataType,Int64} Looks like the returned SSA values from overdubbed |
I don't think phi nodes are doing anything special here. They just tmerge together all the incoming values. In any case, you should be able to see this without the effects of optimization if the function you're interested in is the most top level function you pass to code_typed. |
@maleadt looks like your updated MWE is resolved now via JuliaLang/julia#30385. julia> outer(A::AbstractArray, i...) = inner(Bool, A, i...)
outer (generic function with 1 method)
julia> inner(::Type{Bool}, A::AbstractArray, i...) = nothing
inner (generic function with 1 method)
julia> using Cassette
julia> Cassette.@context Ctx
Cassette.Context{nametype(Ctx),M,P,T,B} where B<:Union{Nothing, IdDict{Module,Dict{Symbol,BindingMeta}}} where P<:Cassette.AbstractPass where T<:Union{Nothing, Tag} where M
julia> overdubbed = (args...) -> Cassette.overdub(Ctx(), outer, args...)
#4 (generic function with 1 method)
julia> using InteractiveUtils
julia> code_warntype(outer, Tuple{Vector{Int}, Int})
Body::Nothing
1 ─ return
julia> code_warntype(overdubbed, Tuple{Vector{Int}, Int})
Body::Nothing
1 ─ return
julia> versioninfo()
Julia Version 1.2.0-DEV.33
Commit 92ac90e5d7 (2018-12-18 20:54 UTC)
Platform Info:
OS: macOS (x86_64-apple-darwin17.5.0)
CPU: Intel(R) Core(TM) i7-7920HQ CPU @ 3.10GHz
WORD_SIZE: 64
LIBM: libopenlibm
LLVM: libLLVM-6.0.1 (ORCJIT, skylake) That improvement should hopefully be backported upcoming Julia patch releases. Closing this, but I suspect your real use case could run into different troubles due to JuliaLang/julia#28003, which still needs fixing upstream. Definitely open new issues if/when you find more MWEs, it's super appreciated! Thanks. |
The following fails to generate efficient code:
... whereas without overdubbing, we simply get:
Checking the code for
overdub
reveals why we get the invoke:Looks like a failure to const-prop the
Bool
argument through the argument tuple. But then again, the second element of the tuple isn't const, and I'm not sure whether that can be expressed withCompiler.Const
.This specific pattern arises with
checkbounds(::Array, ::Integer)
which calls tocheckbounds(Bool, ...)
(ie. passing aType{Bool}
), so this probably penalizes quite a lot of code as soon as it indexes arrays.The text was updated successfully, but these errors were encountered: