https://gcc.gnu.org/g:52d9c2272f6366cd5b30e9540ce8ef16b482cee5
commit r16-2196-g52d9c2272f6366cd5b30e9540ce8ef16b482cee5 Author: Jan Hubicka <hubi...@ucw.cz> Date: Fri Jul 11 12:37:24 2025 +0200 Fix ICE in speculative devirtualization This patch fixes ICE bilding lto1 with autoprofiledbootstrap and in pr114790. What happens is that auto-fdo speculatively devirtualizes to a wrong target. This is due to a bug where it mixes up dwarf names and linkage names of inline functions I need to fix as well. Later we clone at WPA time. At ltrans time clone is materialized and call is turned into a direct call (this optimization is missed by ipa-cp propagation). At this time we should resolve speculation but we don't. As a result we get error from verifier after inlining complaining that there is speculative call with corresponding direct call lacking speculative flag. This seems long-lasting problem in cgraph_update_edges_for_call_stmt_node but I suppose it does not trigger since we usually speculate correctly or notice the direct call at WPA time already. Bootstrapped/regtested x86_64-linux. gcc/ChangeLog: PR ipa/114790 * cgraph.cc (cgraph_update_edges_for_call_stmt_node): Resolve devirtualization if call statement was optimized out or turned to direct call. gcc/testsuite/ChangeLog: * g++.dg/lto/pr114790_0.C: New test. * g++.dg/lto/pr114790_1.C: New test. Diff: --- gcc/cgraph.cc | 13 +++++++++++++ gcc/testsuite/g++.dg/lto/pr114790_0.C | 16 ++++++++++++++++ gcc/testsuite/g++.dg/lto/pr114790_1.C | 15 +++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc index 94a2e6e61058..32071a84bacc 100644 --- a/gcc/cgraph.cc +++ b/gcc/cgraph.cc @@ -1790,6 +1790,19 @@ cgraph_update_edges_for_call_stmt_node (cgraph_node *node, if (e) { + /* If call was devirtualized during cloning, mark edge + as resolved. */ + if (e->speculative) + { + if (new_stmt && is_gimple_call (new_stmt)) + { + tree decl = gimple_call_fndecl (new_stmt); + if (decl) + e = cgraph_edge::resolve_speculation (e, decl); + } + else + e = cgraph_edge::resolve_speculation (e, NULL); + } /* Keep calls marked as dead dead. */ if (new_stmt && is_gimple_call (new_stmt) && e->callee && fndecl_built_in_p (e->callee->decl, BUILT_IN_UNREACHABLE, diff --git a/gcc/testsuite/g++.dg/lto/pr114790_0.C b/gcc/testsuite/g++.dg/lto/pr114790_0.C new file mode 100644 index 000000000000..eed112df3897 --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/pr114790_0.C @@ -0,0 +1,16 @@ +// { dg-lto-do link } +// { dg-lto-options { { -w -flto -g -flto-partition=1to1 -O2 -shared -fPIC -fvisibility=hidden} } } +// { dg-require-effective-target fpic } +// { dg-require-effective-target shared } +struct APITracerContext { + virtual ~APITracerContext() = default; + virtual void releaseActivetracersList() = 0; +}; +struct APITracerContextImp : APITracerContext { + ~APITracerContextImp() override; + void releaseActivetracersList() override; +}; +struct APITracerContextImp globalAPITracerContextImp; +struct APITracerContextImp *pGlobalAPITracerContextImp = &globalAPITracerContextImp; +APITracerContextImp::~APITracerContextImp() {} + diff --git a/gcc/testsuite/g++.dg/lto/pr114790_1.C b/gcc/testsuite/g++.dg/lto/pr114790_1.C new file mode 100644 index 000000000000..511fae45be8b --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/pr114790_1.C @@ -0,0 +1,15 @@ +struct APITracerContext { + virtual void releaseActivetracersList() = 0; +}; +extern struct APITracerContextImp *pGlobalAPITracerContextImp; +struct APITracerContextImp : APITracerContext { void releaseActivetracersList();}; +int g(); +inline int +apiTracerWrapperImp( ) { + for (int i = 0; i < g(); i++) + pGlobalAPITracerContextImp->releaseActivetracersList(); +} +__attribute__((visibility("default"))) int +zeCommandListAppendMemoryCopyTracing() { + return apiTracerWrapperImp( ); +}