Skip to content

Commit

Permalink
Relax constraints on inlining for some single calls
Browse files Browse the repository at this point in the history
  • Loading branch information
Ian Atol committed Nov 17, 2021
1 parent bc8337a commit f0fc7cd
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 18 deletions.
32 changes: 14 additions & 18 deletions base/compiler/ssair/inlining.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1169,26 +1169,22 @@ function analyze_single_call!(
end
end

# if the signature is fully covered and there is only one applicable method,
# if the signature is fully or mostly covered and there is only one applicable method,
# we can try to inline it even if the signature is not a dispatch tuple
if atype <: signature_union
if length(cases) == 0 && only_method isa Method
if length(infos) > 1
(metharg, methsp) = ccall(:jl_type_intersection_with_env, Any, (Any, Any),
atype, only_method.sig)::SimpleVector
match = MethodMatch(metharg, methsp, only_method, true)
else
meth = meth::MethodLookupResult
@assert length(meth) == 1
match = meth[1]
end
item = analyze_method!(match, argtypes, state, flag)
item === nothing && return
push!(cases, InliningCase(match.spec_types, item))
fully_covered = true
if length(cases) == 0 && only_method isa Method
if length(infos) > 1
(metharg, methsp) = ccall(:jl_type_intersection_with_env, Any, (Any, Any),
atype, only_method.sig)::SimpleVector
match = MethodMatch(metharg, methsp, only_method, true)
else
meth = meth::MethodLookupResult
@assert length(meth) == 1
match = meth[1]
end
else
fully_covered = false
item = analyze_method!(match, argtypes, state, flag)
item === nothing && return
push!(cases, InliningCase(match.spec_types, item))
fully_covered = atype <: match.spec_types
end

# If we only have one case and that case is fully covered, we may either
Expand Down
30 changes: 30 additions & 0 deletions test/compiler/inline.jl
Original file line number Diff line number Diff line change
Expand Up @@ -817,3 +817,33 @@ let
invoke(xs) = validate_unionsplit_inlining(true, xs[1])
@test invoke(Any[10]) === false
end

# issue 43104

@inline isGoodType(@nospecialize x::Type) =
x !== Any && !(@noinline Base.has_free_typevars(x))
let # aggressive static dispatch of single, abstract method match
src = code_typed((Type, Any,)) do x, y
isGoodType(x), isGoodType(y)
end |> only |> first
# both callsite should be inlined
@test count(isinvoke(:has_free_typevars), src.code) == 2
# `isGoodType(y::Any)` isn't fully covered, thus a runtime type check and fallback dynamic dispatch should be inserted
@test count(iscall((src,isGoodType)), src.code) == 1
end

@noinline function checkBadType!(@nospecialize x::Type)
if x === Any || Base.has_free_typevars(x)
println(x)
end
return nothing
end
let # aggressive inlining of single, abstract method match
src = code_typed((Type, Any,)) do x, y
checkBadType!(x), checkBadType!(y)
end |> only |> first
# both callsite should be resolved statically
@test count(isinvoke(:checkBadType!), src.code) == 2
# `checkBadType!(y::Any)` isn't fully covered, thus a runtime type check and fallback dynamic dispatch should be inserted
@test count(iscall((src,checkBadType!)), src.code) == 1
end

0 comments on commit f0fc7cd

Please sign in to comment.