The following fails to generate efficient code:
inner(::Type{Bool}, i) = nothing
outer(I...) = inner(Bool, I...)
using Cassette
Cassette.@context Ctx
f = (args...) -> Cassette.overdub(Ctx(), outer, args...)
code_warntype(f, Tuple{Int})
Body::ANY
10 1 ─ %1 = Cassette.overdub::Core.Compiler.Const(Cassette.overdub, false)
│ %2 = (getfield)(args, 1)::Int64
│ %3 = invoke %1($(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}, outer::typeof(outer), %2::Int64)::ANY
└── return %3
... whereas without overdubbing, we simply get:
Body::Nothing
2 1 ─ return
Checking the code for overdub reveals why we get the invoke:
code_warntype(Cassette.overdub, Tuple{typeof(Ctx()), typeof(outer), Int})
Body::ANY
2 1 ─ %1 = (Core.getfield)(##overdub_arguments#369, 2)::Int64
│ %2 = (Core.tuple)(%1)::Tuple{Int64}
└── goto #3 if not true
2 ─ %4 = Core.tuple::Core.Compiler.Const(tuple, false)
│ %5 = Main.Bool::Core.Compiler.Const(Bool, false)
└── %6 = (%4)(%5)::Tuple{DataType}
3 ─ %7 = φ (#2 => %6, #1 => $(QuoteNode(Cassette.OverdubInstead())))::UNION{OVERDUBINSTEAD, TUPLE{DATATYPE}}
│ %8 = π (%7, Core.Compiler.Const((Bool,), false))
└── goto #5 if not true
4 ─ %10 = Core._apply::typeof(Core._apply)
│ %11 = (%10)(tuple, %8, %2)::Tuple{DataType,Int64}
│ %12 = (getfield)(%11, 1)::DATATYPE
│ %13 = (getfield)(%11, 2)::Int64
└── %14 = (Cassette.overdub)($(QuoteNode(Cassette.Context{nametype(Ctx),Nothing,Cassette.NoPass,Nothing,Nothing}(nametype(Ctx)(), nothing, Cassette.NoPass(), nothing, nothing))), inner, %12, %13)::ANY
5 ─ %15 = φ (#4 => %14, #3 => $(QuoteNode(Cassette.OverdubInstead())))::ANY
└── return %15
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 with Compiler.Const.
This specific pattern arises with checkbounds(::Array, ::Integer) which calls to checkbounds(Bool, ...) (ie. passing a Type{Bool}), so this probably penalizes quite a lot of code as soon as it indexes arrays.
The following fails to generate efficient code:
... whereas without overdubbing, we simply get:
Checking the code for
overdubreveals why we get the invoke:Looks like a failure to const-prop the
Boolargument 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.