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.
This commit is contained in:
Jan Hubicka
2025-07-11 12:37:24 +02:00
parent 89b9372d61
commit 52d9c2272f
3 changed files with 44 additions and 0 deletions

View File

@ -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,

View File

@ -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() {}

View File

@ -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( );
}