[gcc r16-1699] Add testcase for afdo offlining and fix two bugs
Jan Hubicka
hubicka@gcc.gnu.org
Thu Jun 26 09:07:39 GMT 2025
https://gcc.gnu.org/g:7b28a7dc9dfb277ef1f053dda84899837f8ed0c1
commit r16-1699-g7b28a7dc9dfb277ef1f053dda84899837f8ed0c1
Author: Jan Hubicka <hubicka@ucw.cz>
Date: Thu Jun 26 10:48:20 2025 +0200
Add testcase for afdo offlining and fix two bugs
This patch adds a testcase that offlining works and profile info is not lost.
While doing it I noticed a pasto that made the dump to be "afdo" and not
"afdo_offline" and also that not all functions are processed as the range
for does not expect new values to be put to the vector. Fixed thus.
gcc/ChangeLog:
* auto-profile.cc (function_instance::merge): Add TODO.
(autofdo_source_profile::offline_external_functions):
Do not use range for on the worklist.
* timevar.def (TV_IPA_AUTOFDO_OFFLINE): New timevar.
gcc/testsuite/ChangeLog:
* gcc.dg/tree-prof/afdo-crossmodule-1.c: New test.
* gcc.dg/tree-prof/afdo-crossmodule-1b.c: New test.
Diff:
---
gcc/auto-profile.cc | 93 ++++++++++++----------
.../gcc.dg/tree-prof/afdo-crossmodule-1.c | 29 +++++++
.../gcc.dg/tree-prof/afdo-crossmodule-1b.c | 10 +++
gcc/timevar.def | 1 +
4 files changed, 90 insertions(+), 43 deletions(-)
diff --git a/gcc/auto-profile.cc b/gcc/auto-profile.cc
index 3e0505ecd78e..d19afd73fae7 100644
--- a/gcc/auto-profile.cc
+++ b/gcc/auto-profile.cc
@@ -800,7 +800,11 @@ function_instance::merge (function_instance *other,
Otherwise turn FN toplevel. Return true if new toplevel function
was introduced.
If new toplevel functions are created and NEW_FUNCTIONS != NULL,
- add them to NEW_FUNCTIONS. */
+ add them to NEW_FUNCTIONS.
+
+ TODO: When offlining indirect call we lose information about the
+ call target. It should be possible to add it into
+ targets histogram. */
bool
function_instance::offline (function_instance *fn,
@@ -1118,46 +1122,49 @@ autofdo_source_profile::offline_external_functions ()
may introduce new functions by offlining. */
for (auto const &iter : map_)
fns.safe_push (iter.second);
- for (function_instance *f : fns)
- if (!seen.contains (afdo_string_table->get_index
- (afdo_string_table->get_name (f->name ()))))
- {
- f->offline_if_in_set (seen, fns);
- if (dump_file)
- fprintf (dump_file, "Removing external %s\n",
- afdo_string_table->get_name (f->name ()));
- map_.erase (afdo_string_table->get_index
- (afdo_string_table->get_name (f->name ())));
- delete f;
- }
- else
- {
- f->remove_external_functions (seen, to_symbol_name, fns);
- int index = afdo_string_table->get_index
- (afdo_string_table->get_name (f->name ()));
- int *newn = to_symbol_name.get (index);
- if (newn)
- {
- if (map_.count (*newn))
- {
- if (dump_file)
- fprintf (dump_file, "Merging duplicate symbol %s\n",
- afdo_string_table->get_name (f->name ()));
- function_instance *to = map_[index];
- if (to != f)
- {
- map_[index]->merge (f);
- delete f;
- }
- }
- else
- {
- auto iter = map_.find (index);
- map_[*newn] = iter->second;
- map_.erase (iter);
- }
- }
- }
+ for (unsigned int i = 0; i < fns.length (); i++)
+ {
+ function_instance *f = fns[i];
+ if (!seen.contains (afdo_string_table->get_index
+ (afdo_string_table->get_name (f->name ()))))
+ {
+ f->offline_if_in_set (seen, fns);
+ if (dump_file)
+ fprintf (dump_file, "Removing external %s\n",
+ afdo_string_table->get_name (f->name ()));
+ map_.erase (afdo_string_table->get_index
+ (afdo_string_table->get_name (f->name ())));
+ delete f;
+ }
+ else
+ {
+ f->remove_external_functions (seen, to_symbol_name, fns);
+ int index = afdo_string_table->get_index
+ (afdo_string_table->get_name (f->name ()));
+ int *newn = to_symbol_name.get (index);
+ if (newn)
+ {
+ if (map_.count (*newn))
+ {
+ if (dump_file)
+ fprintf (dump_file, "Merging duplicate symbol %s\n",
+ afdo_string_table->get_name (f->name ()));
+ function_instance *to = map_[index];
+ if (to != f)
+ {
+ map_[index]->merge (f);
+ delete f;
+ }
+ }
+ else
+ {
+ auto iter = map_.find (index);
+ map_[*newn] = iter->second;
+ map_.erase (iter);
+ }
+ }
+ }
+ }
if (dump_file)
for (auto const &iter : map_)
{
@@ -2950,7 +2957,7 @@ namespace
const pass_data pass_data_ipa_auto_profile_offline = {
SIMPLE_IPA_PASS, "afdo_offline", /* name */
OPTGROUP_NONE, /* optinfo_flags */
- TV_IPA_AUTOFDO, /* tv_id */
+ TV_IPA_AUTOFDO_OFFLINE, /* tv_id */
0, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
@@ -2962,7 +2969,7 @@ class pass_ipa_auto_profile_offline : public simple_ipa_opt_pass
{
public:
pass_ipa_auto_profile_offline (gcc::context *ctxt)
- : simple_ipa_opt_pass (pass_data_ipa_auto_profile, ctxt)
+ : simple_ipa_opt_pass (pass_data_ipa_auto_profile_offline, ctxt)
{
}
diff --git a/gcc/testsuite/gcc.dg/tree-prof/afdo-crossmodule-1.c b/gcc/testsuite/gcc.dg/tree-prof/afdo-crossmodule-1.c
new file mode 100644
index 000000000000..d3986a6d5215
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-prof/afdo-crossmodule-1.c
@@ -0,0 +1,29 @@
+/* { dg-require-effective-target lto } */
+/* { dg-additional-sources "afdo-crossmodule-1b.c" } */
+/* { dg-options "-O3 -flto -fdump-ipa-afdo_offline -fdump-tree-einline-details" } */
+/* { dg-require-profiling "-fauto-profile" } */
+volatile int c;
+
+int foo2 ()
+{
+ c++;
+ return 1;
+}
+int foo (int (*fooptr) ())
+{
+ return fooptr ();
+}
+extern int bar (int (*fooptr) (int (*)()));
+
+int
+main()
+{
+ int n = 1000000;
+ int s = 0;
+ for (int i = 0; i < n; i++)
+ s += bar (foo);
+ return n != s;
+}
+/* { dg-final-use-autofdo { scan-ipa-dump "Removing external inline: main:5 bar" "afdo_offline"} } */
+/* { dg-final-use-autofdo { scan-ipa-dump "Offlining function inlined to other module: bar:2 main:5 foo" "afdo_offline"} } */
+/* { dg-final-use-autofdo { scan-tree-dump "Indirect call -> speculative call foo.. => foo2" "einline"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-prof/afdo-crossmodule-1b.c b/gcc/testsuite/gcc.dg/tree-prof/afdo-crossmodule-1b.c
new file mode 100644
index 000000000000..dd532952f973
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-prof/afdo-crossmodule-1b.c
@@ -0,0 +1,10 @@
+extern int foo2 ();
+
+int bar (int (*fooptr) (int (*)()))
+{
+ return fooptr (foo2);
+}
+/* { dg-final-use-autofdo { scan-ipa-dump "Offlining function inlined to other module: main:5 bar" "afdo_offline"} } */
+/* { dg-final-use-autofdo { scan-ipa-dump "Offlining function inlined to other module: bar:2 main:5 foo" "afdo_offline"} } */
+/* It would be nice to speculate call to foo, but offlining does not preserve jump target
+ and currently afdo does not do cross-module indirect call promotion. */
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 02ace466da59..4f60f04baa11 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -101,6 +101,7 @@ DEFTIMEVAR (TV_WHOPR_LTRANS , "whopr ltrans")
DEFTIMEVAR (TV_IPA_REFERENCE , "ipa reference")
DEFTIMEVAR (TV_IPA_PROFILE , "ipa profile")
DEFTIMEVAR (TV_IPA_AUTOFDO , "auto profile")
+DEFTIMEVAR (TV_IPA_AUTOFDO_OFFLINE , "auto profile offline")
DEFTIMEVAR (TV_IPA_PURE_CONST , "ipa pure const")
DEFTIMEVAR (TV_IPA_ICF , "ipa icf")
DEFTIMEVAR (TV_IPA_PTA , "ipa points-to")
More information about the Gcc-cvs
mailing list