]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Add testcase for afdo offlining and fix two bugs
authorJan Hubicka <hubicka@ucw.cz>
Thu, 26 Jun 2025 08:48:20 +0000 (10:48 +0200)
committerJan Hubicka <hubicka@ucw.cz>
Thu, 26 Jun 2025 09:07:33 +0000 (11:07 +0200)
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.

gcc/auto-profile.cc
gcc/testsuite/gcc.dg/tree-prof/afdo-crossmodule-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-prof/afdo-crossmodule-1b.c [new file with mode: 0644]
gcc/timevar.def

index 3e0505ecd78e258d91f3b5981135cc4e750f7b4c..d19afd73fae74bf2303767e2cf0762c5986738ce 100644 (file)
@@ -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 (file)
index 0000000..d3986a6
--- /dev/null
@@ -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 (file)
index 0000000..dd53295
--- /dev/null
@@ -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.  */
index 02ace466da5964fb3e82ba92816e17d5ceff5032..4f60f04baa11071195fc26af7e237e8271a50b04 100644 (file)
@@ -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")