Hi,
this patch fixes an ICE reported as PR128226.

If a function has many calls, but not enough to cross the call_site_hash
creation threshold and was brought over this threshold with callback
edges, the previously created callback edges wouldn't be added to
call_site_hash.  This was intentional up until the addition of internal
callback edges, as we want to hash their carrying edge instead.
However, in the case of internal callbacks, the callback edge is the
only one (and hence the right one) to hash.  Because of the early
return, the slot would be empty, leading to an ICE during ipa-fnsummary.
This patch changes the check to only act on callbacks with carrying edges.

The testcase in the PR is really convoluted and doesn't showcase the
issue in my opinion, so I came up with the testcase in the patch.  It's
the best I could come up with, even though it's a bit unusual.

Bootstrapped and regtested on x86_64-linux with no new regressions.
Pre-approved by Martin Jambor.

Best regards,
Josef

-- >8 --

This patch fixes the early return in
cgraph_add_edge_to_call_site_hash for internal callback edges.

Callback edges are created much later than other callgraph edges.  If
the function doesn't have its call_site_hash yet, the creation of
callback edges can bring it over the threshold and trigger the
call_site_hash's construction.  However, callback edges created prior to
crossing the threshold (i.e. callback edges constructed in the first 100
edges) won't be added to the call_site_hash due to the early return.

This is actually the desired behavior for regular callback edges, as we
want to hash their carrying edges instead.  The trouble arises for
the recently added internal callback edges, as they don't have a
carrying edge, leaving the slot empty.  In their case, the callback
edge is actually the correct one to hash.  This can lead to segfaults
when fetching the edge after call_site_hash's construction, as is the
case for PR128226.

This patch fixes the early return to only apply to callback edges with
carrying edges.

The original testcase is long, complicated and doesn't demonstrate the
problem well, so I've created this one instead.

Assisted-by: Claude Opus 5.5 (testcase)

        PR ipa/128226

gcc/ChangeLog:

        * cgraph.cc (cgraph_add_edge_to_call_site_hash): Only skip callback
        edges with carrying edges.

gcc/testsuite/ChangeLog:

        * g++.dg/ipa/pr128226.C: New test.

Signed-off-by: Josef Melcr <[email protected]>
---
 gcc/cgraph.cc                       |  8 ++++----
 gcc/testsuite/g++.dg/ipa/pr128226.C | 22 ++++++++++++++++++++++
 2 files changed, 26 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ipa/pr128226.C

diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc
index 3448bc37714..748fe579a22 100644
--- a/gcc/cgraph.cc
+++ b/gcc/cgraph.cc
@@ -870,10 +870,10 @@ cgraph_add_edge_to_call_site_hash (cgraph_edge *e)
      one indirect); always hash the direct one.  */
   if (e->speculative && e->indirect_unknown_callee)
     return;
-  /* We always want to hash the carrying edge of a callback, not the edges
-     pointing to the callbacks themselves, as their call statement doesn't
-     exist.  */
-  if (e->callback)
+  /* Callback edges share the call statement of the carrying edge, so hash
+     the carrying edge instead.  Internal callback edges have no carrying
+     edge, so hash the callback edge directly.  */
+  if (e->callback_with_carrying_edge_p ())
     return;
   cgraph_edge **slot = e->caller->call_site_hash->find_slot_with_hash
       (e->call_stmt, cgraph_edge_hasher::hash (e->call_stmt), INSERT);
diff --git a/gcc/testsuite/g++.dg/ipa/pr128226.C 
b/gcc/testsuite/g++.dg/ipa/pr128226.C
new file mode 100644
index 00000000000..ec5f437500f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/pr128226.C
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O1" } */
+
+/* The 100 calls alone do not cross the call_site_hash construction threshold
+   in cgraph_node::get_edge, but together with the internal callback edges
+   created for the assumes, they do.  We are testing whether the internal
+   callback edges are added to call_site_hash.  */
+
+#define CALL(x) (x) ()
+#define CALL5(x) CALL (x), CALL (x), CALL (x), CALL (x), CALL (x)
+#define CALL25(x) CALL5 (x), CALL5 (x), CALL5 (x), CALL5 (x), CALL5 (x)
+#define CALL100(x) CALL25 (x), CALL25 (x), CALL25 (x), CALL25 (x)
+
+bool foo ();
+
+void
+bar ()
+{
+  __attribute__ ((assume (foo ())));
+  __attribute__ ((assume (foo ())));
+  CALL100 (foo);
+}
-- 
2.56.0

Reply via email to