From: Kyrylo Tkachov <[email protected]>
IPA-CP's good_cloning_opportunity_p accepts a clone when
EVALUATION = time_benefit * freq_sum / size_cost * 1000 >=
ipa-cp-eval-threshold
i.e. the per-call "benefit density" (time_benefit/size_cost) multiplied by the
summed frequency of all calls that would use the clone. Because freq_sum scales
with the number/hotness of callers, a function that is called from many hot
sites can clear the threshold with an arbitrarily small per-call benefit: a
large body gets duplicated even though knowing the propagated constant barely
simplifies it. This is common when the "specialised" parameter is not actually
consumed in the clone but merely forwarded as a runtime argument into a callee
that is itself neither inlined nor cloned, the modelled saving never
materialises, and EVALUATION does not account for the duplication's
code bloat cost.
727.cppcheck_r is the motivating case: GCC clones Token::Match for varid==0
(time_benefit ~6.8, size ~381) but varid==0 only flows as a runtime argument
into the un-inlined multiCompareImpl; ~600 such .constprop/.part/.isra clones
accumulate across the program. Suppressing the useless ones recovers +3.9%..
+8.0%.
Gate cloning on a frequency-independent minimum of the same benefit-density
metric IPA-CP already computes for ranking
(cloning_opportunity_ranking_evaluation,
time_benefit*1000/size_cost). A clone whose per-call benefit is below
--param=ipa-cp-min-clone-eval (permille of the cloned size, default 30 ~= 3%) is
rejected regardless of how high freq_sum is. 0 disables the check.
The 3% is, of course, somewhat arbitrary, but I think that is the nature
of all these IPA heuristics. Happy for better ideas.
A standalone reproducer is in the bugzilla PR. I can include it in the
patch, though I'm not sure how fragile and convoluted it is.
This patch gives ~9% on cppcheck on an aarch64 machine with -Ofast
-flto.
Bootstrapped and tested on aarch64-none-linux-gnu.
Any comments?
Signed-off-by: Kyrylo Tkachov <[email protected]>
gcc/ChangeLog:
PR ipa/125607
* params.opt (-param=ipa-cp-min-clone-eval=): New param.
* ipa-cp.cc (good_cloning_opportunity_p): Reject a clone whose
per-call time benefit is below ipa-cp-min-clone-eval ratio
cloned size.
---
gcc/ipa-cp.cc | 20 ++++++++++++++++++++
gcc/params.opt | 4 ++++
2 files changed, 24 insertions(+)
diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
index 9e0b698b8cb..f839624170d 100644
--- a/gcc/ipa-cp.cc
+++ b/gcc/ipa-cp.cc
@@ -3462,6 +3462,26 @@ good_cloning_opportunity_p (struct cgraph_node *node,
sreal time_benefit,
gcc_assert (size_cost > 0);
+ /* Refuse to duplicate a large body for a per-call benefit that is a
+ negligible fraction of the cloned size. A tiny TIME_BENEFIT relative to
+ SIZE_COST means the propagated constant barely simplifies the cloned body
+ -- typically it just flows through to an un-cloned/un-inlined callee, so
+ the modelled saving never materialises. The summed caller frequency can
+ still push EVALUATION over the threshold, but then the duplication's
+ I-cache/footprint cost (which EVALUATION does not model) makes the clone a
+ net loss. The minimum ratio is controlled by
--param=ipa-cp-min-clone-eval
+ (default 30, i.e. the benefit must be >= ~3% of the duplicated size; 0
disables
+ the check). */
+ int min_clone_eval = opt_for_fn (node->decl, param_ipa_cp_min_clone_eval);
+ if (time_benefit * 1000 < (sreal) size_cost * min_clone_eval)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, " good_cloning_opportunity_p: not cloning, "
+ "benefit %g negligible vs size %i\n",
+ time_benefit.to_double (), size_cost);
+ return false;
+ }
+
ipa_node_params *info = ipa_node_params_sum->get (node);
int num_sweeps = opt_for_fn (node->decl, param_ipa_cp_sweeps);
int eval_threshold = opt_for_fn (node->decl, param_ipa_cp_eval_threshold);
diff --git a/gcc/params.opt b/gcc/params.opt
index 90f9943c8cb..2c1081a2cce 100644
--- a/gcc/params.opt
+++ b/gcc/params.opt
@@ -253,6 +253,10 @@ The upper bound for sharing integer constants.
Common Joined UInteger Var(param_ipa_cp_eval_threshold) Init(1100) Param
Optimization
Threshold ipa-cp opportunity evaluation that is still considered beneficial to
clone.
+-param=ipa-cp-min-clone-eval=
+Common Joined UInteger Var(param_ipa_cp_min_clone_eval) Init(30) Param
Optimization
+Minimum ratio of estimated time benefit to cloned code size (scaled by 1000)
for IPA-CP to create a specialized clone, regardless of the summed frequency of
the calls that would use it.
+
-param=ipa-cp-loop-hint-bonus=
Common Joined UInteger Var(param_ipa_cp_loop_hint_bonus) Init(64) Param
Optimization
Compile-time bonus IPA-CP assigns to candidates which make loop bounds or
strides known.
--
2.50.1 (Apple Git-155)