So I’ve got a MWE here with a weird behavior.
Note: this seems to be actually fixed in v1.9. But I couldn’t track any relevant issues to PR.
I’m trying to elide some checking code with @boundscheck. (yes, the real use case is a numerical hot loop)
At first I was experimenting with positional arguments:
f2(x, a=0) = @boundscheck "not elided!"
Base.@propagate_inbounds f3(x, a=0) = @boundscheck "not elided!"
function caller(x)
@inbounds @show f2(x)
@inbounds @show f2(x, 2)
@inbounds @show f3(x)
@inbounds @show f3(x, 2)
nothing
end
caller(0)
# f2(x) = "not elided!"
# f2(x, 2) = nothing
# f3(x) = nothing
# f3(x, 2) = nothing
After I figured out how to work with @inbounds
and @boundscheck
properly, I faced some trouble with optional arguments (f2
).
But I figured it was because f2(x)
was calling f2(x, a)
without the “inbound-dedness” so f2(x)
boundschecks was not elided. This was fixed with propagate_inbounds
.
But now when I also found out the hard way that a similar thing appears to happen with keyword arguments and is not easily fixed.
f4(x; k=0) = @boundscheck "not elided!"
@propagate_inbounds f5(x; k=0) = @boundscheck "not elided!"
function caller(x)
@inbounds @show f4(x)
@inbounds @show f4(x, k=2)
@inbounds @show f5(x)
@inbounds @show f5(x, k=2)
nothing
end
caller(0)
# f4(x) = "not elided!"
# f4(x, k = 2) = "not elided!"
# f5(x) = nothing
# f5(x, k = 2) = "not elided!"
Does anyone know of a possible cause for specifying keyword argument to prevent proper inlining or skipping boundchecks?
Or maybe there is a common workaround?
I’ve tried removing the default value of 2
and/or specifying type k::Int64
but neither changes the behavior.
@code_typed does show very obviously the difference between v1.8.5 and v1.9
# V1.8.5
julia> @code_typed f5(1, k=2)
CodeInfo(
1 ─ nothing::Nothing
│ nothing::Nothing
│ nothing::Nothing
└── goto #3 if not true
2 ─ goto #4
3 ─ goto #4
4 ┄ %7 = φ (#2 => "not ellided!!!", #3 => nothing)::Union{Nothing, String}
└── return %7
) => Union{Nothing, String}
# v1.9
julia> @code_typed f5(1, k=2)
CodeInfo(
1 ─ nothing::Nothing
│ nothing::Nothing
│ nothing::Nothing
└── goto #3 if not $(Expr(:boundscheck))
2 ─ goto #4
3 ─ goto #4
4 ┄ %7 = φ (#2 => "not ellided!!!", #3 => nothing)::Union{Nothing, String}
└── return %7
) => Union{Nothing, String}