https://gcc.gnu.org/g:2508fac25d2722bf779c1e3e407a264c0a00312d
commit r17-646-g2508fac25d2722bf779c1e3e407a264c0a00312d Author: Martin Jambor <[email protected]> Date: Thu May 21 14:05:18 2026 +0200 ipa-cp: Adjust general IPA-CP cloning heuristics This winter I have had a long look at the effects of different values of parameter param_ipa_cp_eval_threshold on performance on SPEC 2017 and on how they affect code size - and how quickly we reach growth size limit in param_ipa_cp_unit_growth - when compiling these benchmarks bit also, cc1 in an -O3 bootstrap and clang. After going through the numbers, it turns out that we tend to clone a bit too much and especially that we hit the overall growth limit way too quickly. As a result this patch does two things. First, it raises the heuristics cost/benefit threshold to 1100 (from 500) which is the value at which I started to see cloning benefits. Second, it reverts a recent change to get_max_overall_size where the size limit also depended on the current call-graph sweep. We only want the threshold to gradually come down (now to 1100), not the size constraints also, it turned out to defeat the initial purpose. gcc/ChangeLog: 2026-04-07 Martin Jambor <[email protected]> * ipa-cp.cc (get_max_overall_size): Remove parameter CUR_SWEEP and its use. (decide_about_value): Adjust the call to get_max_overall_size. (decide_whether_version_node): Likewise. * params.opt (param_ipa_cp_eval_threshold): Initialize to 1100. libgomp/ChangeLog: 2026-04-07 Martin Jambor <[email protected]> * testsuite/libgomp.c/ipcp-cb-spec1.c: Set lower param ipa-cp-eval-threshold. gcc/testsuite/ChangeLog: 2026-04-07 Martin Jambor <[email protected]> * gcc.dg/ipa/ipa-5.c: Adjust dump. * gcc.dg/independent-cloneids-1.c: Set lower param ipa-cp-eval-threshold. * gcc.dg/vla-1.c: Likewise. * g++.dg/ipa/devirt-2.C: Add an extra caller of the to-be-cloned function. Diff: --- gcc/ipa-cp.cc | 23 +++++++++-------------- gcc/params.opt | 2 +- gcc/testsuite/g++.dg/ipa/devirt-2.C | 10 ++++++++++ gcc/testsuite/gcc.dg/independent-cloneids-1.c | 2 +- gcc/testsuite/gcc.dg/ipa/ipa-5.c | 2 +- gcc/testsuite/gcc.dg/vla-1.c | 2 +- libgomp/testsuite/libgomp.c/ipcp-cb-spec1.c | 2 +- 7 files changed, 24 insertions(+), 19 deletions(-) diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc index c1b1f6201fd3..ce77acf8e0da 100644 --- a/gcc/ipa-cp.cc +++ b/gcc/ipa-cp.cc @@ -3620,25 +3620,21 @@ perform_estimation_of_a_value (cgraph_node *node, val->local_size_cost = size; } -/* Get the overall limit of growth based on parameters extracted from growth, - and CUR_SWEEP, which is the number of the current sweep of IPA-CP over the - call-graph in the decision stage. It does not really make sense to mix - functions with different overall growth limits or even number of sweeps but - it is possible and if it happens, we do not want to select one limit at - random, so get the limits from NODE. */ +/* Get the overall limit of growth based on parameters extracted from NODE. It + does not really make sense to mix functions with different overall growth + limits or even number of sweeps but it is possible and if it happens, we do + not want to select one limit at random, so get the limits from NODE. */ static long -get_max_overall_size (cgraph_node *node, int cur_sweep) +get_max_overall_size (cgraph_node *node) { long max_new_size = orig_overall_size; long large_unit = opt_for_fn (node->decl, param_ipa_cp_large_unit_insns); if (max_new_size < large_unit) max_new_size = large_unit; - int num_sweeps = opt_for_fn (node->decl, param_ipa_cp_sweeps); - gcc_assert (cur_sweep <= num_sweeps); int unit_growth = opt_for_fn (node->decl, param_ipa_cp_unit_growth); - max_new_size += ((max_new_size * unit_growth * cur_sweep) - / num_sweeps) / 100 + 1; + max_new_size += max_new_size * unit_growth / 100 + 1; + return max_new_size; } @@ -5958,8 +5954,7 @@ decide_about_value (struct cgraph_node *node, int index, HOST_WIDE_INT offset, perhaps_add_new_callers (node, val); return false; } - else if (val->local_size_cost + overall_size - > get_max_overall_size (node, cur_sweep)) + else if (val->local_size_cost + overall_size > get_max_overall_size (node)) { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " Ignoring candidate value because " @@ -6337,7 +6332,7 @@ decide_whether_version_node (struct cgraph_node *node, int cur_sweep) stats.called_without_ipa_profile, cur_sweep)) { - if (size + overall_size <= get_max_overall_size (node, cur_sweep)) + if (size + overall_size <= get_max_overall_size (node)) { if (!dbg_cnt (ipa_cp_values)) return ret; diff --git a/gcc/params.opt b/gcc/params.opt index 9eeb1f3fa64e..90f9943c8cb4 100644 --- a/gcc/params.opt +++ b/gcc/params.opt @@ -250,7 +250,7 @@ Common Joined UInteger Var(param_integer_share_limit) Init(251) IntegerRange(2, The upper bound for sharing integer constants. -param=ipa-cp-eval-threshold= -Common Joined UInteger Var(param_ipa_cp_eval_threshold) Init(500) Param Optimization +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-loop-hint-bonus= diff --git a/gcc/testsuite/g++.dg/ipa/devirt-2.C b/gcc/testsuite/g++.dg/ipa/devirt-2.C index 3fffe278ecea..6a81140e03d9 100644 --- a/gcc/testsuite/g++.dg/ipa/devirt-2.C +++ b/gcc/testsuite/g++.dg/ipa/devirt-2.C @@ -48,6 +48,16 @@ int __attribute__ ((noinline,noclone,noipa)) get_input(void) return 1; } +int extra (int init) +{ + class B b; + int i; + for (i = init; i < get_input(); i++) + if (b.middleman (get_input ()) != 3) + abort (); + return 0; +} + int main (int argc, char *argv[]) { class B b; diff --git a/gcc/testsuite/gcc.dg/independent-cloneids-1.c b/gcc/testsuite/gcc.dg/independent-cloneids-1.c index efbc1c51da0b..c6e9581cbce4 100644 --- a/gcc/testsuite/gcc.dg/independent-cloneids-1.c +++ b/gcc/testsuite/gcc.dg/independent-cloneids-1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -fipa-cp -fipa-cp-clone -fdump-rtl-final" } */ +/* { dg-options "-O3 -fipa-cp -fipa-cp-clone -fdump-rtl-final --param ipa-cp-eval-threshold=500" } */ /* { dg-skip-if "Odd label definition syntax" { mmix-*-* } } */ extern int printf (const char *, ...); diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-5.c b/gcc/testsuite/gcc.dg/ipa/ipa-5.c index e4f77a967682..a6678b12c7c1 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipa-5.c +++ b/gcc/testsuite/gcc.dg/ipa/ipa-5.c @@ -27,6 +27,6 @@ int main () return 0; } -/* { dg-final { scan-ipa-dump-times "Creating a specialized node" 3 "cp" } } */ +/* { dg-final { scan-ipa-dump-times "Creating a specialized node" 2 "cp" } } */ /* { dg-final { scan-ipa-dump "replacing param .1 c with const 3" "cp" } } */ /* { dg-final { scan-ipa-dump "replacing param .0 a with const 7" "cp" } } */ diff --git a/gcc/testsuite/gcc.dg/vla-1.c b/gcc/testsuite/gcc.dg/vla-1.c index 2ab2b7a48acf..52a1d9772d9f 100644 --- a/gcc/testsuite/gcc.dg/vla-1.c +++ b/gcc/testsuite/gcc.dg/vla-1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-g -O3 -fdump-tree-optimized -fvar-tracking-assignments -fno-selective-scheduling -fno-selective-scheduling2 -fno-ipa-vrp" } */ +/* { dg-options "-g -O3 -fdump-tree-optimized -fvar-tracking-assignments -fno-selective-scheduling -fno-selective-scheduling2 -fno-ipa-vrp --param ipa-cp-eval-threshold=1" } */ int __attribute__((noinline)) f1 (int i) diff --git a/libgomp/testsuite/libgomp.c/ipcp-cb-spec1.c b/libgomp/testsuite/libgomp.c/ipcp-cb-spec1.c index ff82f4c2f29d..a2ab03f692a4 100644 --- a/libgomp/testsuite/libgomp.c/ipcp-cb-spec1.c +++ b/libgomp/testsuite/libgomp.c/ipcp-cb-spec1.c @@ -1,7 +1,7 @@ /* Test that GOMP_task is special cased when cpyfn is NULL. */ /* { dg-do run } */ -/* { dg-options "-O3 -fopenmp -std=gnu99 -fdump-ipa-cp-details" } */ +/* { dg-options "-O3 -fopenmp -std=gnu99 -fdump-ipa-cp-details --param ipa-cp-eval-threshold=1" } */ /* { dg-require-effective-target fopenmp } */ void test(int c) {
