[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