[PATCH] [AutoFDO][IPA-CP] Handle zero-caller locals after AutoFDO early inlining

Kugan Vivekanandarajah <[email protected]> Tue, 4 Aug 2026 10:37:33 +1000
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
AutoFDO early inlining can inline all direct calls to a local
function while speculative call promotion keeps the function
address-taken.  The function consequently remains in the call graph
with no direct callers, triggering the -ftoplevel-reorder checking
assertion in IPA-CP.

Ordinary IPA devirtualization does not normally produce this state at
IPA-CP: it creates speculative edges before IPA-CP, but those edges are
inlined only by the later IPA inliner.  IPA-CP therefore still sees a
direct caller.  AutoFDO instead performs speculative inlining early, so
only its IPA_REF_ADDR may remain by the time IPA-CP runs.

When AutoFDO inlining is enabled, recognize zero-caller functions that
cannot be removed after their direct calls disappear and initialize
their lattices as variable.  Preserve the assertion for removable
locals and non-AutoFDO compilation.

gcc/ChangeLog:

	* ipa-cp.cc (initialize_node_lattices): Handle zero-caller local
	functions left after AutoFDO early inlining.

Regression tested on aarch64-linux-gnu with no new regressions

Signed-off-by: Kugan Vivekanandarajah <[email protected]>
---
 gcc/ipa-cp.cc | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
index c1b1f6201fd3..d68952ec8711 100644
--- a/gcc/ipa-cp.cc
+++ b/gcc/ipa-cp.cc
@@ -1443,7 +1443,18 @@ initialize_node_lattices (struct cgraph_node *node)
 						  NULL, true);
       else if (caller_count == 0)
 	{
-	  gcc_checking_assert (!opt_for_fn (node->decl, flag_toplevel_reorder));
+	  /* With -ftoplevel-reorder, a local body with no direct callers
+	     should already have been removed.  AutoFDO early-inline of a
+	     speculative call expands via gimple_ic (&target), so after all
+	     direct call edges are inlined the local can remain address-taken
+	     with unknown indirect uses; treat that as VARIABLE.  Ordinary
+	     IPA devirtualization does not need this exception: it creates
+	     speculative edges before IPA-CP, but inlines them only later, so
+	     IPA-CP still sees a direct caller.  */
+	  if (!(flag_auto_profile && flag_auto_profile_inlining
+		&& !node->can_remove_if_no_direct_calls_p (false)))
+	    gcc_checking_assert
+	      (!opt_for_fn (node->decl, flag_toplevel_reorder));
 	  variable = true;
 	}
     }
-- 
2.34.1