Open
Description
openedon Sep 11, 2023
This is condensed from a much larger example, in the original f
was simply large not marked @noinline
@noinline f(arg) = Base.inferencebarrier(arg)
function g(arg)
@inline f(arg)
end
julia> code_typed(g, (Union{Int},))
1-element Vector{Any}:
CodeInfo(
1 ─ return arg
) => Any
julia> code_typed(g, (Union{Float64, Int},))
1-element Vector{Any}:
CodeInfo(
1 ─ %1 = Main.f::typeof(f)
│ %2 = (isa)(arg, Float64)::Bool
└── goto #3 if not %2
2 ─ %4 = π (arg, Float64)
└── goto #6
3 ─ %6 = (isa)(arg, Int64)::Bool
└── goto #5 if not %6
4 ─ %8 = π (arg, Int64)
│ %9 = invoke %1(%8::Int64)::Any
└── goto #6
5 ─ Core.throw(ErrorException("fatal error in type inference (type bound)"))::Union{}
└── unreachable
6 ┄ %13 = φ (#2 => %4, #4 => %9)::Any
└── return %13
) => Any
Note how we have a invoke %1
, instead of it being inlined.
This also raises a second question. Should functions marked with an statement @inline
always be union-split?
I can see pro and cons. If the method would be the same after union-splitting then we IMO shouldn't split and instead
push the argument union forward.
Came up in the context of #50958 where I now need to write
# for val.initial_value::Union{Nothing, LogState}
# get(scope.values, val, val.initial_value) get's union-split.
@noinline function getindex_slow(scope::Scope, val::ScopedValue{T})::T where T
@inline get(()->val.initial_value, scope.values, val)::T
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment