https://gcc.gnu.org/g:7b28a7dc9dfb277ef1f053dda84899837f8ed0c1
commit r16-1699-g7b28a7dc9dfb277ef1f053dda84899837f8ed0c1 Author: Jan Hubicka <hubi...@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")