Skip to content

Commit cdd2f30

Browse files
authored
inference: prioritize force_constant_prop over const_prop_entry_heuristic (#41882)
Currently our constant-prop' heuristics work in the following way: 1. `const_prop_entry_heuristic` 2. `const_prop_argument_heuristic` & `const_prop_rettype_heuristic` 3. `force_const_prop` custom heuristic & `!const_prop_function_heuristic` 4. `MethodInstance` specialization and `const_prop_methodinstance_heuristic` This PR changes it so that the step 1. now works like: 1. `force_const_prop` custom heuristic & `const_prop_entry_heuristic` and the steps 2., 3. and 4. don't change This change particularly allows us to more forcibly constant-propagate for `getproperty` and `setproperty!`, and inline them more, e.g.: ```julia # if we don't force constant-prop', `T = fieldtype(Foo, ::Symbol)` will be union-split to # `Union{Type{Any},Type{Int}` and it will make `convert(T, nothing)` too costly # and it leads to inlining failure mutable struct Foo val _::Int end function setter(xs) for x in xs x.val = nothing # `setproperty!` can be inlined with this PR end end ``` It might be useful because now we can intervene into the constant-prop' heuristic in a more reliable way with the `aggressive_constprop` interface. I did the simple benchmark below, and it looks like this change doesn't cause the latency problem for this particular example: ```zsh ~/julia master aviatesk@amdci2 6s ❯ ./usr/bin/julia -e '@time using Plots; @time plot(rand(10,3))' 3.708500 seconds (7.28 M allocations: 506.128 MiB, 3.45% gc time, 1.13% compilation time) 2.817794 seconds (3.45 M allocations: 195.127 MiB, 7.84% gc time, 53.76% compilation time) ~/julia avi/forceconstantprop aviatesk@amdci2 6s ❯ ./usr/bin/julia -e '@time using Plots; @time plot(rand(10,3))' 3.622109 seconds (7.02 M allocations: 481.710 MiB, 4.19% gc time, 1.17% compilation time) 2.863419 seconds (3.44 M allocations: 194.210 MiB, 8.02% gc time, 53.53% compilation time) ```
1 parent 292f1a9 commit cdd2f30

File tree

2 files changed

+36
-6
lines changed

2 files changed

+36
-6
lines changed

base/compiler/abstractinterpretation.jl

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -567,16 +567,21 @@ end
567567
function maybe_get_const_prop_profitable(interp::AbstractInterpreter, result::MethodCallResult,
568568
@nospecialize(f), argtypes::Vector{Any}, match::MethodMatch,
569569
sv::InferenceState)
570-
const_prop_entry_heuristic(interp, result, sv) || return nothing
570+
if !InferenceParams(interp).ipo_constant_propagation
571+
add_remark!(interp, sv, "[constprop] Disabled by parameter")
572+
return nothing
573+
end
571574
method = match.method
575+
force = force_const_prop(interp, f, method)
576+
force || const_prop_entry_heuristic(interp, result, sv) || return nothing
572577
nargs::Int = method.nargs
573578
method.isva && (nargs -= 1)
574-
if length(argtypes) < nargs
579+
length(argtypes) < nargs && return nothing
580+
if !(const_prop_argument_heuristic(interp, argtypes) || const_prop_rettype_heuristic(interp, result.rt))
581+
add_remark!(interp, sv, "[constprop] Disabled by argument and rettype heuristics")
575582
return nothing
576583
end
577-
const_prop_argument_heuristic(interp, argtypes) || const_prop_rettype_heuristic(interp, result.rt) || return nothing
578584
allconst = is_allconst(argtypes)
579-
force = force_const_prop(interp, f, method)
580585
if !force
581586
if !const_prop_function_heuristic(interp, f, argtypes, nargs, allconst)
582587
add_remark!(interp, sv, "[constprop] Disabled by function heuristic")
@@ -599,10 +604,12 @@ end
599604

600605
function const_prop_entry_heuristic(interp::AbstractInterpreter, result::MethodCallResult, sv::InferenceState)
601606
if call_result_unused(sv) && result.edgecycle
602-
add_remark!(interp, sv, "[constprop] Edgecycle with unused result")
607+
add_remark!(interp, sv, "[constprop] Disabled by entry heuristic (edgecycle with unused result)")
603608
return false
604609
end
605-
return is_improvable(result.rt) && InferenceParams(interp).ipo_constant_propagation
610+
is_improvable(result.rt) && return true
611+
add_remark!(interp, sv, "[constprop] Disabled by entry heuristic (unimprovable return type)")
612+
return false
606613
end
607614

608615
# see if propagating constants may be worthwhile

test/compiler/inline.jl

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,29 @@ end
498498
end
499499
end
500500

501+
# force constant-prop' for `setproperty!`
502+
let m = Module()
503+
ci = @eval m begin
504+
# if we don't force constant-prop', `T = fieldtype(Foo, ::Symbol)` will be union-split to
505+
# `Union{Type{Any},Type{Int}` and it will make `convert(T, nothing)` too costly
506+
# and it leads to inlining failure
507+
mutable struct Foo
508+
val
509+
_::Int
510+
end
511+
512+
function setter(xs)
513+
for x in xs
514+
x.val = nothing
515+
end
516+
end
517+
518+
$code_typed1(setter, (Vector{Foo},))
519+
end
520+
521+
@test !any(x->isinvoke(x, :setproperty!), ci.code)
522+
end
523+
501524
# Issue #41299 - inlining deletes error check in :>
502525
g41299(f::Tf, args::Vararg{Any,N}) where {Tf,N} = f(args...)
503526
@test_throws TypeError g41299(>:, 1, 2)

0 commit comments

Comments
 (0)