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")

Reply via email to