Skip to content

Commit

Permalink
Partially revert 44512 to handle duplicated spec_types inlining bug
Browse files Browse the repository at this point in the history
  • Loading branch information
Ian Atol committed Apr 27, 2022
1 parent 28dbf82 commit b2ea6d1
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 14 deletions.
79 changes: 68 additions & 11 deletions base/compiler/ssair/inlining.jl
Original file line number Diff line number Diff line change
Expand Up @@ -880,7 +880,7 @@ function validate_sparams(sparams::SimpleVector)
end

function analyze_method!(match::MethodMatch, argtypes::Vector{Any},
flag::UInt8, state::InliningState)
flag::UInt8, state::InliningState, check_sparams::Bool=false)
method = match.method
spec_types = match.spec_types

Expand All @@ -902,7 +902,7 @@ function analyze_method!(match::MethodMatch, argtypes::Vector{Any},
end
end

#validate_sparams(match.sparams) || return nothing
check_sparams && (validate_sparams(match.sparams) || return nothing)

et = state.et

Expand Down Expand Up @@ -1238,6 +1238,9 @@ function analyze_single_call!(
cases = InliningCase[]
local any_fully_covered = false
local handled_all_cases = true
local revisit_idx = nothing
local only_method = nothing
local meth::MethodLookupResult
for i in 1:length(infos)
meth = infos[i].results
if meth.ambig
Expand All @@ -1248,14 +1251,64 @@ function analyze_single_call!(
# No applicable methods; try next union split
handled_all_cases = false
continue
else
if length(meth) == 1 && only_method !== false
if only_method === nothing
only_method = meth[1].method
elseif only_method !== meth[1].method
only_method = false
end
else
only_method = false
end
end
for match in meth
handled_all_cases &= handle_match!(match, argtypes, flag, state, cases, true)
for (j, match) in enumerate(meth)
if !isdispatchtuple(match.spec_types)
if !match.fully_covers
handled_all_cases = false
continue
end
if revisit_idx === nothing
revisit_idx = (i, j)
else
handled_all_cases = false
revisit_idx = nothing
end
else
handled_all_cases &= handle_match!(match, argtypes, flag, state, cases, true)
end
any_fully_covered |= match.fully_covers
end
end

if !handled_all_cases
atype = argtypes_to_type(argtypes)
if handled_all_cases && revisit_idx !== nothing
# If there's only one case that's not a dispatchtuple, we can
# still unionsplit by visiting all the other cases first.
# This is useful for code like:
# foo(x::Int) = 1
# foo(@nospecialize(x::Any)) = 2
# where we where only a small number of specific dispatchable
# cases are split off from an ::Any typed fallback.
(i, j) = revisit_idx
match = infos[i].results[j]
handled_all_cases &= handle_match!(match, argtypes, flag, state, cases, true, true)
elseif length(cases) == 0 && only_method isa Method
# if the signature is fully covered and there is only one applicable method,
# we can try to inline it even if the signature is not a dispatch tuple.
# -- But don't try it if we already tried to handle the match in the revisit_idx
# case, because that'll (necessarily) be the same 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::SimpleVector, only_method, true)
else
@assert length(meth) == 1
match = meth[1]
end
handle_match!(match, argtypes, flag, state, cases, true, false) || return nothing
any_fully_covered = handled_all_cases = match.fully_covers
elseif !handled_all_cases
# if we've not seen all candidates, union split is valid only for dispatch tuples
filter!(case::InliningCase->isdispatchtuple(case.sig), cases)
end
Expand Down Expand Up @@ -1313,14 +1366,18 @@ end

function handle_match!(
match::MethodMatch, argtypes::Vector{Any}, flag::UInt8, state::InliningState,
cases::Vector{InliningCase}, allow_abstract::Bool = false)
cases::Vector{InliningCase}, allow_abstract::Bool = false, check_sparams::Bool=false)
spec_types = match.spec_types
allow_abstract || isdispatchtuple(spec_types) || return false
# we may see duplicated dispatch signatures here when a signature gets widened
# during abstract interpretation: for the purpose of inlining, we can just skip
# processing this dispatch candidate
_any(case->case.sig === spec_types, cases) && return true
item = analyze_method!(match, argtypes, flag, state)
if check_sparams
# we may see duplicated dispatch signatures here when a signature gets widened
# during abstract interpretation: for the purpose of inlining, we can just skip
# processing this dispatch candidate
_any(case->case.sig === spec_types, cases) && return true
item = analyze_method!(match, argtypes, flag, state, true)
else
item = analyze_method!(match, argtypes, flag, state)
end
item === nothing && return false
push!(cases, InliningCase(spec_types, item))
return true
Expand Down
7 changes: 4 additions & 3 deletions src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -1614,10 +1614,11 @@ JL_CALLABLE(jl_f__svec_ref)
JL_TYPECHK(_svec_ref, simplevector, (jl_value_t*)s);
JL_TYPECHK(_svec_ref, long, i);
ssize_t idx = jl_unbox_long(i);
if (idx < 1 || idx > jl_svec_len(s)) {
jl_bounds_error_int(s, i);
size_t len = jl_svec_len(s);
if (idx < 1 || idx > len) {
jl_bounds_error_int((jl_value_t*)s, idx);
}
return jl_svec_ref(s, jl_unbox_long(i)-1);
return jl_svec_ref(s, idx-1);
}

static int equiv_field_types(jl_value_t *old, jl_value_t *ft)
Expand Down

0 comments on commit b2ea6d1

Please sign in to comment.