https://gcc.gnu.org/g:c157eca33eb0098df1dc715c19672e923f4d2d98

commit r16-6800-gc157eca33eb0098df1dc715c19672e923f4d2d98
Author: Josef Melcr <[email protected]>
Date:   Mon Dec 8 15:35:33 2025 +0100

    ipa/122852: Don't delete unreachable callback edges.
    
    Hi,
    previously, callback edges of a carrying edge redirected to
    __builtin_unreachable  were deleted, as I thought they would
    mess with the callgraph, given that they were no longer correct.
    In some cases, the edges would be deleted when duplicating
    a fn summary, producing a segfault. This patch changes this
    behavior.  It redirects the callback edges to __builtin_unreachable and
    adds an exception for such cases in the verifier.  Callback edges are
    now also required to point to __builtin_unreachable if their carrying
    edge is pointing to __builtin_unreachable.
    
    Bootstrapped and regtested on x86_64-linux, no regressions.
    
    OK for master?
    
    Thanks,
    Josef
    
            PR ipa/122852
    
    gcc/ChangeLog:
    
            * cgraph.cc (cgraph_node::verify_node): Verify that callback
            edges are unreachable when the carrying edge is unreachable.
            * ipa-fnsummary.cc (redirect_to_unreachable): Redirect callback
            edges to unreachable when redirecting the carrying edge.
    
    libgomp/ChangeLog:
    
            * testsuite/libgomp.c/pr122852.c: New test.
    
    Signed-off-by: Josef Melcr <[email protected]>

Diff:
---
 gcc/cgraph.cc                          | 13 ++++++++++++-
 gcc/ipa-fnsummary.cc                   |  5 ++++-
 libgomp/testsuite/libgomp.c/pr122852.c | 24 ++++++++++++++++++++++++
 3 files changed, 40 insertions(+), 2 deletions(-)

diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc
index b594b0acc318..91ff2775de13 100644
--- a/gcc/cgraph.cc
+++ b/gcc/cgraph.cc
@@ -4404,7 +4404,8 @@ cgraph_node::verify_node (void)
            }
 
          if (e->has_callback
-             && !callback_is_special_cased (e->callee->decl, e->call_stmt))
+             && !callback_is_special_cased (e->callee->decl, e->call_stmt)
+             && !fndecl_built_in_p (e->callee->decl, BUILT_IN_UNREACHABLE))
            {
              int ncallbacks = 0;
              int nfound_edges = 0;
@@ -4431,6 +4432,16 @@ cgraph_node::verify_node (void)
                }
            }
 
+         if (e->has_callback
+             && fndecl_built_in_p (e->callee->decl, BUILT_IN_UNREACHABLE))
+           for (cgraph_edge *cbe = e->first_callback_edge (); cbe;
+                cbe = cbe->next_callback_edge ())
+             if (!fndecl_built_in_p (cbe->callee->decl, BUILT_IN_UNREACHABLE))
+               error ("callback-carrying edge is pointing towards "
+                      "__builtin_unreachable, but its callback edge %s -> %s "
+                      "is not",
+                      cbe->caller->name (), cbe->callee->name ());
+
          if (!e->aux && !e->speculative && !e->callback && !e->has_callback)
            {
              error ("edge %s->%s has no corresponding call_stmt",
diff --git a/gcc/ipa-fnsummary.cc b/gcc/ipa-fnsummary.cc
index 80b82a9bf702..e187231dfb64 100644
--- a/gcc/ipa-fnsummary.cc
+++ b/gcc/ipa-fnsummary.cc
@@ -272,7 +272,10 @@ redirect_to_unreachable (struct cgraph_edge *e)
   if (callee)
     callee->remove_symbol_and_inline_clones ();
   if (e->has_callback)
-    e->purge_callback_edges ();
+    for (cgraph_edge *cbe = e->first_callback_edge (); cbe;
+        cbe = cbe->next_callback_edge ())
+      /* If the carrying edge is unreachable, so are the callback calls.  */
+      redirect_to_unreachable (cbe);
   return e;
 }
 
diff --git a/libgomp/testsuite/libgomp.c/pr122852.c 
b/libgomp/testsuite/libgomp.c/pr122852.c
new file mode 100644
index 000000000000..1a36fe9c0fc8
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/pr122852.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target fopenmp } */
+/* { dg-options "-O2 -fopenmp" } */
+
+int a, b, c;
+
+static void
+foo (int g)
+{
+  int f = c ? c : 2;
+  if (c)
+    b = 3;
+  if (!g)
+    for (int d = 0; d < f; ++d)
+#pragma omp parallel
+      while (a)
+       ;
+}
+
+void
+bar (void)
+{
+  foo (1);
+}

Reply via email to