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); +}
