Skip to content

@inline annotation lost during union splitting #51270

Open

Description

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

Metadata

Assignees

No one assigned

    Labels

    compiler:optimizerOptimization passes (mostly in base/compiler/ssair/)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions