Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AbsInt: add interfaces to customize cases when cached results are used #53318

Merged
merged 1 commit into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 35 additions & 27 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1221,45 +1221,53 @@ function semi_concrete_eval_call(interp::AbstractInterpreter,
return nothing
end

const_prop_result(inf_result::InferenceResult) =
ConstCallResults(inf_result.result, inf_result.exc_result, ConstPropResult(inf_result),
inf_result.ipo_effects, inf_result.linfo)

# return cached constant analysis result
return_cached_result(::AbstractInterpreter, inf_result::InferenceResult, ::AbsIntState) =
const_prop_result(inf_result)

function const_prop_call(interp::AbstractInterpreter,
mi::MethodInstance, result::MethodCallResult, arginfo::ArgInfo, sv::AbsIntState,
concrete_eval_result::Union{Nothing, ConstCallResults}=nothing)
inf_cache = get_inference_cache(interp)
𝕃ᵢ = typeinf_lattice(interp)
inf_result = cache_lookup(𝕃ᵢ, mi, arginfo.argtypes, inf_cache)
if inf_result === nothing
# fresh constant prop'
argtypes = has_conditional(𝕃ᵢ, sv) ? ConditionalArgtypes(arginfo, sv) : SimpleArgtypes(arginfo.argtypes)
inf_result = InferenceResult(mi, argtypes, typeinf_lattice(interp))
if !any(inf_result.overridden_by_const)
add_remark!(interp, sv, "[constprop] Could not handle constant info in matching_cache_argtypes")
return nothing
end
frame = InferenceState(inf_result, #=cache_mode=#:local, interp)
if frame === nothing
add_remark!(interp, sv, "[constprop] Could not retrieve the source")
return nothing # this is probably a bad generated function (unsound), but just ignore it
end
frame.parent = sv
if !typeinf(interp, frame)
add_remark!(interp, sv, "[constprop] Fresh constant inference hit a cycle")
return nothing
end
@assert inf_result.result !== nothing
if concrete_eval_result !== nothing
# override return type and effects with concrete evaluation result if available
inf_result.result = concrete_eval_result.rt
inf_result.ipo_effects = concrete_eval_result.effects
end
else
if inf_result !== nothing
# found the cache for this constant prop'
if inf_result.result === nothing
add_remark!(interp, sv, "[constprop] Found cached constant inference in a cycle")
return nothing
end
@assert inf_result.linfo === mi "MethodInstance for cached inference result does not match"
return return_cached_result(interp, inf_result, sv)
end
# perform fresh constant prop'
argtypes = has_conditional(𝕃ᵢ, sv) ? ConditionalArgtypes(arginfo, sv) : SimpleArgtypes(arginfo.argtypes)
inf_result = InferenceResult(mi, argtypes, typeinf_lattice(interp))
if !any(inf_result.overridden_by_const)
add_remark!(interp, sv, "[constprop] Could not handle constant info in matching_cache_argtypes")
return nothing
end
frame = InferenceState(inf_result, #=cache_mode=#:local, interp)
if frame === nothing
add_remark!(interp, sv, "[constprop] Could not retrieve the source")
return nothing # this is probably a bad generated function (unsound), but just ignore it
end
frame.parent = sv
if !typeinf(interp, frame)
add_remark!(interp, sv, "[constprop] Fresh constant inference hit a cycle")
return nothing
end
@assert inf_result.result !== nothing
if concrete_eval_result !== nothing
# override return type and effects with concrete evaluation result if available
inf_result.result = concrete_eval_result.rt
inf_result.ipo_effects = concrete_eval_result.effects
end
return ConstCallResults(inf_result.result, inf_result.exc_result,
ConstPropResult(inf_result), inf_result.ipo_effects, mi)
return const_prop_result(inf_result)
end

# TODO implement MustAlias forwarding
Expand Down
20 changes: 13 additions & 7 deletions base/compiler/typeinfer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -818,23 +818,29 @@ struct EdgeCallResult
end
end

# return cached regular inference result
function return_cached_result(::AbstractInterpreter, codeinst::CodeInstance, caller::AbsIntState)
rt = cached_return_type(codeinst)
effects = ipo_effects(codeinst)
update_valid_age!(caller, WorldRange(min_world(codeinst), max_world(codeinst)))
return EdgeCallResult(rt, codeinst.exctype, codeinst.def, effects)
end

# compute (and cache) an inferred AST and return the current best estimate of the result type
function typeinf_edge(interp::AbstractInterpreter, method::Method, @nospecialize(atype), sparams::SimpleVector, caller::AbsIntState)
mi = specialize_method(method, atype, sparams)::MethodInstance
code = get(code_cache(interp), mi, nothing)
codeinst = get(code_cache(interp), mi, nothing)
force_inline = is_stmt_inline(get_curr_ssaflag(caller))
if code isa CodeInstance # return existing rettype if the code is already inferred
inferred = @atomic :monotonic code.inferred
if codeinst isa CodeInstance # return existing rettype if the code is already inferred
inferred = @atomic :monotonic codeinst.inferred
if inferred === nothing && force_inline
# we already inferred this edge before and decided to discard the inferred code,
# nevertheless we re-infer it here again in order to propagate the re-inferred
# source to the inliner as a volatile result
cache_mode = CACHE_MODE_VOLATILE
else
rt = cached_return_type(code)
effects = ipo_effects(code)
update_valid_age!(caller, WorldRange(min_world(code), max_world(code)))
return EdgeCallResult(rt, code.exctype, mi, effects)
@assert codeinst.def === mi "MethodInstance for cached edge does not match"
return return_cached_result(interp, codeinst, caller)
end
else
cache_mode = CACHE_MODE_GLOBAL # cache edge targets globally by default
Expand Down