Skip to content

Commit f085913

Browse files
authored
constprop: Add facility for widening arguments before constprop (#54036)
There are various situations where we may want to constprop with something other than the most precise concrete arguments in order to make the resulting cache more useful to other call sites. One particular example of this might be a method where non-concrete inference already discovered that one argument is unused: ``` function foo(a, b::DispatchOnly) expensive_to_compile(a) end ``` Right now, we will generally perform constprop for every different value of `b`, even though we already have the information that `b` is unused. Another example is external absints that may want to treat certain types fully symbolically. They may want to substitute concrete values for an abstract domain. This adds the facility to do both of these things by 1. Adding an appropriate interp hook in the constprop path 2. Adding a WidendedSimpleArgtypes wrapper that's like SimpleArgtypes but works around an issue where we would override cache information using values from concrete eval, which is not legal if the argtypes were widened.
1 parent a7fd6a7 commit f085913

File tree

2 files changed

+21
-6
lines changed

2 files changed

+21
-6
lines changed

base/compiler/abstractinterpretation.jl

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,20 +1243,25 @@ const_prop_result(inf_result::InferenceResult) =
12431243
return_cached_result(::AbstractInterpreter, inf_result::InferenceResult, ::AbsIntState) =
12441244
const_prop_result(inf_result)
12451245

1246+
function compute_forwarded_argtypes(interp::AbstractInterpreter, arginfo::ArgInfo, sv::AbsIntState)
1247+
𝕃ᵢ = typeinf_lattice(interp)
1248+
return has_conditional(𝕃ᵢ, sv) ? ConditionalSimpleArgtypes(arginfo, sv) : SimpleArgtypes(arginfo.argtypes)
1249+
end
1250+
12461251
function const_prop_call(interp::AbstractInterpreter,
12471252
mi::MethodInstance, result::MethodCallResult, arginfo::ArgInfo, sv::AbsIntState,
12481253
concrete_eval_result::Union{Nothing, ConstCallResults}=nothing)
12491254
inf_cache = get_inference_cache(interp)
12501255
𝕃ᵢ = typeinf_lattice(interp)
1251-
argtypes = has_conditional(𝕃ᵢ, sv) ? ConditionalArgtypes(arginfo, sv) : SimpleArgtypes(arginfo.argtypes)
1256+
forwarded_argtypes = compute_forwarded_argtypes(interp, arginfo, sv)
12521257
# use `cache_argtypes` that has been constructed for fresh regular inference if available
12531258
volatile_inf_result = result.volatile_inf_result
12541259
if volatile_inf_result !== nothing
12551260
cache_argtypes = volatile_inf_result.inf_result.argtypes
12561261
else
12571262
cache_argtypes = matching_cache_argtypes(𝕃ᵢ, mi)
12581263
end
1259-
argtypes = matching_cache_argtypes(𝕃ᵢ, mi, argtypes, cache_argtypes)
1264+
argtypes = matching_cache_argtypes(𝕃ᵢ, mi, forwarded_argtypes, cache_argtypes)
12601265
inf_result = cache_lookup(𝕃ᵢ, mi, argtypes, inf_cache)
12611266
if inf_result !== nothing
12621267
# found the cache for this constant prop'
@@ -1290,7 +1295,10 @@ function const_prop_call(interp::AbstractInterpreter,
12901295
return nothing
12911296
end
12921297
@assert inf_result.result !== nothing
1293-
if concrete_eval_result !== nothing
1298+
# ConditionalSimpleArgtypes is allowed, because the only case in which it modifies
1299+
# the argtypes is when one of the argtypes is a `Conditional`, which case
1300+
# concrete_eval_result will not be available.
1301+
if concrete_eval_result !== nothing && isa(forwarded_argtypes, Union{SimpleArgtypes, ConditionalSimpleArgtypes})
12941302
# override return type and effects with concrete evaluation result if available
12951303
inf_result.result = concrete_eval_result.rt
12961304
inf_result.ipo_effects = concrete_eval_result.effects
@@ -1300,13 +1308,13 @@ end
13001308

13011309
# TODO implement MustAlias forwarding
13021310

1303-
struct ConditionalArgtypes
1311+
struct ConditionalSimpleArgtypes
13041312
arginfo::ArgInfo
13051313
sv::InferenceState
13061314
end
13071315

13081316
function matching_cache_argtypes(𝕃::AbstractLattice, mi::MethodInstance,
1309-
conditional_argtypes::ConditionalArgtypes,
1317+
conditional_argtypes::ConditionalSimpleArgtypes,
13101318
cache_argtypes::Vector{Any})
13111319
(; arginfo, sv) = conditional_argtypes
13121320
(; fargs, argtypes) = arginfo

base/compiler/inferenceresult.jl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,15 @@ struct SimpleArgtypes
99
argtypes::Vector{Any}
1010
end
1111

12+
# Like `SimpleArgtypes`, but allows the argtypes to be wider than the current call.
13+
# As a result, it is not legal to refine the cache result with information more
14+
# precise than was it deducible from the `WidenedSimpleArgtypes`.
15+
struct WidenedArgtypes
16+
argtypes::Vector{Any}
17+
end
18+
1219
function matching_cache_argtypes(𝕃::AbstractLattice, mi::MethodInstance,
13-
simple_argtypes::SimpleArgtypes,
20+
simple_argtypes::Union{SimpleArgtypes, WidenedArgtypes},
1421
cache_argtypes::Vector{Any})
1522
(; argtypes) = simple_argtypes
1623
given_argtypes = Vector{Any}(undef, length(argtypes))

0 commit comments

Comments
 (0)