Fix callee type generation (#186272)

The callee_type metadata is expected to be a list of generalized type
metadata by the IR verifier. But for indirect calls with internal
linkage the type metadata is just an integer. Avoid including them in
callee_type metadata.

This will reduce the precision of the generated call graph as the edges to internal linkage functions whose address were taken will not be present anymore. We need to handle this in the future.
This commit is contained in:
Prabhu Rajasekaran 2026-03-13 16:24:22 -07:00 committed by GitHub
parent 7449009719
commit 60669c1cfe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 43 additions and 2 deletions

View File

@ -3267,8 +3267,12 @@ void CodeGenModule::createFunctionTypeMetadataForIcall(const FunctionDecl *FD,
void CodeGenModule::createCalleeTypeMetadataForIcall(const QualType &QT,
llvm::CallBase *CB) {
// Only if needed for call graph section and only for indirect calls.
if (!CodeGenOpts.CallGraphSection || !CB->isIndirectCall())
// Only if needed for call graph section and only for indirect calls that are
// visible externally.
// TODO: Handle local linkage symbols so they are not left out of call graph
// reducing precision.
if (!CodeGenOpts.CallGraphSection || !CB->isIndirectCall() ||
!isExternallyVisible(QT->getLinkage()))
return;
llvm::Metadata *TypeIdMD = CreateMetadataIdentifierGeneralized(QT);

View File

@ -0,0 +1,37 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fexperimental-call-graph-section -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s
// Check that we do not generate callee_type metadata for indirect calls
// to functions with internal linkage (e.g., types in anonymous namespaces),
// as their type metadata identifiers are distinct MDNodes instead of
// generalized strings, which would fail the LLVM Verifier.
namespace {
class a;
class b {
public:
virtual void c(a);
};
class a {
public:
b &e;
void d() { e.c(*this); }
};
void b::c(a) {}
void f() {
a *g = nullptr;
g->d();
}
} // namespace
void test() {
f();
}
// CHECK-LABEL: define {{.*}} void @{{.*}}1a1dEv
// CHECK: %[[VFN:.*]] = getelementptr inbounds ptr, ptr %{{.*}}, i{{[0-9]+}} 0
// CHECK: %[[FP:.*]] = load ptr, ptr %[[VFN]], align {{[0-9]+}}
// CHECK: call void %[[FP]]({{.*}})
// CHECK-NOT: !callee_type
// CHECK: ret void