Skip to content

Commit 06f196a

Browse files
committed
inference: improve constant-prop' heuristics
- remove `const_prop_rettype_heuristic` since it handles rare cases, where const-prop' doens't seem to be worthwhile, e.g. it won't be so useful to try to propagate `Const(Tuple{DataType,DataType})` for `Const(convert)(::Const(Tuple{DataType,DataType}), ::Tuple{DataType,DataType} -> Tuple{DataType,DataType}` - rename `is_allconst` to `is_all_overridden` - also minor refactors and improvements added
1 parent edd2866 commit 06f196a

File tree

3 files changed

+29
-37
lines changed

3 files changed

+29
-37
lines changed

base/compiler/abstractinterpretation.jl

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -583,18 +583,16 @@ function maybe_get_const_prop_profitable(interp::AbstractInterpreter, result::Me
583583
nargs::Int = method.nargs
584584
method.isva && (nargs -= 1)
585585
length(arginfo.argtypes) < nargs && return nothing
586-
if !(const_prop_argument_heuristic(interp, arginfo) || const_prop_rettype_heuristic(interp, result.rt))
586+
if !const_prop_argument_heuristic(interp, arginfo, sv)
587587
add_remark!(interp, sv, "[constprop] Disabled by argument and rettype heuristics")
588588
return nothing
589589
end
590-
allconst = is_allconst(arginfo)
591-
if !force
592-
if !const_prop_function_heuristic(interp, f, arginfo, nargs, allconst)
593-
add_remark!(interp, sv, "[constprop] Disabled by function heuristic")
594-
return nothing
595-
end
590+
all_overridden = is_all_overridden(arginfo)
591+
if !force && !const_prop_function_heuristic(interp, f, arginfo, nargs, all_overridden, sv)
592+
add_remark!(interp, sv, "[constprop] Disabled by function heuristic")
593+
return nothing
596594
end
597-
force |= allconst
595+
force |= all_overridden
598596
mi = specialize_method(match; preexisting=!force)
599597
if mi === nothing
600598
add_remark!(interp, sv, "[constprop] Failed to specialize")
@@ -618,11 +616,15 @@ function const_prop_entry_heuristic(interp::AbstractInterpreter, result::MethodC
618616
return false
619617
end
620618

621-
# see if propagating constants may be worthwhile
622-
function const_prop_argument_heuristic(interp::AbstractInterpreter, (; fargs, argtypes)::ArgInfo)
623-
for a in argtypes
619+
# determines heuristically whether if constant propagation can be worthwhile
620+
# by checking if any of given `argtypes` is "interesting" enough to be propagated
621+
function const_prop_argument_heuristic(_::AbstractInterpreter, (; fargs, argtypes)::ArgInfo, _::InferenceState)
622+
for i in 1:length(argtypes)
623+
a = argtypes[i]
624624
if isa(a, Conditional) && fargs !== nothing
625-
return is_const_prop_profitable_conditional(a, fargs)
625+
if is_const_prop_profitable_conditional(a, fargs)
626+
return true
627+
end
626628
end
627629
a = widenconditional(a)
628630
if has_nontrivial_const_info(a) && is_const_prop_profitable_arg(a)
@@ -662,22 +664,15 @@ function find_constrained_arg(cnd::Conditional, fargs::Vector{Any})
662664
end
663665
end
664666

665-
function const_prop_rettype_heuristic(interp::AbstractInterpreter, @nospecialize(rettype))
666-
return improvable_via_constant_propagation(rettype)
667-
end
668-
669-
function is_allconst((; fargs, argtypes)::ArgInfo)
667+
# checks if all argtypes has additional information other than what `Type` can provide
668+
function is_all_overridden((; fargs, argtypes)::ArgInfo)
670669
for a in argtypes
671670
if isa(a, Conditional) && fargs !== nothing
672671
if is_const_prop_profitable_conditional(a, fargs)
673672
continue
674673
end
675674
end
676-
a = widenconditional(a)
677-
# TODO unify these condition with `has_nontrivial_const_info`
678-
if !isa(a, Const) && !isconstType(a) && !isa(a, PartialStruct) && !isa(a, PartialOpaque)
679-
return false
680-
end
675+
is_forwardable_argtype(widenconditional(a)) || return false
681676
end
682677
return true
683678
end
@@ -691,7 +686,7 @@ end
691686

692687
function const_prop_function_heuristic(
693688
interp::AbstractInterpreter, @nospecialize(f), (; argtypes)::ArgInfo,
694-
nargs::Int, allconst::Bool)
689+
nargs::Int, all_overridden::Bool, _::InferenceState)
695690
if nargs > 1
696691
if istopfunction(f, :getindex) || istopfunction(f, :setindex!)
697692
arrty = argtypes[2]
@@ -708,7 +703,7 @@ function const_prop_function_heuristic(
708703
end
709704
end
710705
end
711-
if !allconst && (istopfunction(f, :+) || istopfunction(f, :-) || istopfunction(f, :*) ||
706+
if !all_overridden && (istopfunction(f, :+) || istopfunction(f, :-) || istopfunction(f, :*) ||
712707
istopfunction(f, :(==)) || istopfunction(f, :!=) ||
713708
istopfunction(f, :<=) || istopfunction(f, :>=) || istopfunction(f, :<) || istopfunction(f, :>) ||
714709
istopfunction(f, :<<) || istopfunction(f, :>>))
@@ -1250,7 +1245,7 @@ function abstract_invoke(interp::AbstractInterpreter, (; fargs, argtypes)::ArgIn
12501245
fargs′ = fargs[4:end]
12511246
pushfirst!(fargs′, fargs[1])
12521247
arginfo = ArgInfo(fargs′, argtypes′)
1253-
const_prop_argument_heuristic(interp, arginfo) || const_prop_rettype_heuristic(interp, rt) || return CallMeta(rt, InvokeCallInfo(match, nothing))
1248+
const_prop_argument_heuristic(interp, arginfo, sv) || return CallMeta(rt, InvokeCallInfo(match, nothing))
12541249
# # typeintersect might have narrowed signature, but the accuracy gain doesn't seem worth the cost involved with the lattice comparisons
12551250
# for i in 1:length(argtypes′)
12561251
# t, a = ti.parameters[i], argtypes′[i]

base/compiler/inferenceresult.jl

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,19 @@
33
function is_argtype_match(@nospecialize(given_argtype),
44
@nospecialize(cache_argtype),
55
overridden_by_const::Bool)
6-
if isa(given_argtype, Const) || isa(given_argtype, PartialStruct) ||
7-
isa(given_argtype, PartialOpaque) || isa(given_argtype, Conditional)
6+
if is_forwardable_argtype(given_argtype)
87
return is_lattice_equal(given_argtype, cache_argtype)
98
end
109
return !overridden_by_const
1110
end
1211

12+
function is_forwardable_argtype(@nospecialize x)
13+
return isa(x, Const) ||
14+
isa(x, Conditional) ||
15+
isa(x, PartialStruct) ||
16+
isa(x, PartialOpaque)
17+
end
18+
1319
# In theory, there could be a `cache` containing a matching `InferenceResult`
1420
# for the provided `linfo` and `given_argtypes`. The purpose of this function is
1521
# to return a valid value for `cache_lookup(linfo, argtypes, cache).argtypes`,
@@ -65,7 +71,7 @@ function matching_cache_argtypes(
6571
for i in 1:nargs
6672
given_argtype = given_argtypes[i]
6773
cache_argtype = cache_argtypes[i]
68-
if !is_argtype_match(given_argtype, cache_argtype, overridden_by_const[i])
74+
if !is_argtype_match(given_argtype, cache_argtype, false)
6975
# prefer the argtype we were given over the one computed from `linfo`
7076
cache_argtypes[i] = given_argtype
7177
overridden_by_const[i] = true

base/compiler/typeutils.jl

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -259,15 +259,6 @@ unioncomplexity(u::UnionAll) = max(unioncomplexity(u.body)::Int, unioncomplexity
259259
unioncomplexity(t::Core.TypeofVararg) = isdefined(t, :T) ? unioncomplexity(t.T)::Int : 0
260260
unioncomplexity(@nospecialize(x)) = 0
261261

262-
function improvable_via_constant_propagation(@nospecialize(t))
263-
if isconcretetype(t) && t <: Tuple
264-
for p in t.parameters
265-
p === DataType && return true
266-
end
267-
end
268-
return false
269-
end
270-
271262
# convert a Union of Tuple types to a Tuple of Unions
272263
function unswitchtupleunion(u::Union)
273264
ts = uniontypes(u)

0 commit comments

Comments
 (0)