[clang] [clang] callee_type metadata for indirect calls (PR #163233)
Prabhu Rajasekaran via cfe-commits
cfe-commits at lists.llvm.org
Tue Oct 14 10:39:35 PDT 2025
https://github.com/Prabhuk updated https://github.com/llvm/llvm-project/pull/163233
>From dd765116839109d2a3e7b74f2528e7651514fdb4 Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Mon, 13 Oct 2025 10:53:15 -0700
Subject: [PATCH 01/10] [clang] callee_type metadata for indirect calls
Create and add generalized type identifier metadata to indirect calls,
and to functions which are potential indirect call targets.
The functions carry the !type metadata. The indirect callsites carry a
list of !type metadata values under !callee_type metadata.
RFC: https://discourse.llvm.org/t/rfc-call-graph-information-from-clang-llvm-for-c-c/88255
---
clang/lib/CodeGen/CGCall.cpp | 18 ++-
clang/lib/CodeGen/CodeGenModule.cpp | 44 +++++-
clang/lib/CodeGen/CodeGenModule.h | 3 +
.../CodeGen/call-graph-section-templates.cpp | 114 +++++++++++++++
.../call-graph-section-virtual-methods.cpp | 55 +++++++
clang/test/CodeGen/call-graph-section.c | 83 +++++++++++
clang/test/CodeGen/call-graph-section.cpp | 138 ++++++++++++++++++
7 files changed, 447 insertions(+), 8 deletions(-)
create mode 100644 clang/test/CodeGen/call-graph-section-templates.cpp
create mode 100644 clang/test/CodeGen/call-graph-section-virtual-methods.cpp
create mode 100644 clang/test/CodeGen/call-graph-section.c
create mode 100644 clang/test/CodeGen/call-graph-section.cpp
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index df28641904c04..00e0daf32fb59 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -5937,8 +5937,24 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
CI->getCalledFunction()->getName().starts_with("_Z4sqrt")) {
SetSqrtFPAccuracy(CI);
}
- if (callOrInvoke)
+ if (callOrInvoke) {
*callOrInvoke = CI;
+ if (CGM.getCodeGenOpts().CallGraphSection) {
+ QualType CST;
+ if (TargetDecl && TargetDecl->getFunctionType())
+ CST = QualType(TargetDecl->getFunctionType(), 0);
+ else if (const auto *FPT =
+ Callee.getAbstractInfo().getCalleeFunctionProtoType())
+ CST = QualType(FPT, 0);
+ else
+ llvm_unreachable(
+ "Cannot find the callee type to generate callee_type metadata.");
+
+ // Set type identifier metadata of indirect calls for call graph section.
+ if (!CST.isNull())
+ CGM.createCalleeTypeMetadataForIcall(CST, *callOrInvoke);
+ }
+ }
// If this is within a function that has the guard(nocf) attribute and is an
// indirect call, add the "guard_nocf" attribute to this call to indicate that
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 8d019d4b2da25..b626afc92e822 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -2841,8 +2841,9 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
// In the cross-dso CFI mode with canonical jump tables, we want !type
// attributes on definitions only.
- if (CodeGenOpts.SanitizeCfiCrossDso &&
- CodeGenOpts.SanitizeCfiCanonicalJumpTables) {
+ if ((CodeGenOpts.SanitizeCfiCrossDso &&
+ CodeGenOpts.SanitizeCfiCanonicalJumpTables) ||
+ CodeGenOpts.CallGraphSection) {
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
// Skip available_externally functions. They won't be codegen'ed in the
// current module anyway.
@@ -3054,9 +3055,21 @@ static void setLinkageForGV(llvm::GlobalValue *GV, const NamedDecl *ND) {
GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
}
+static bool hasExistingGeneralizedTypeMD(llvm::Function *F) {
+ llvm::MDNode *MD = F->getMetadata(llvm::LLVMContext::MD_type);
+ return MD && MD->hasGeneralizedMDString();
+}
+
void CodeGenModule::createFunctionTypeMetadataForIcall(const FunctionDecl *FD,
llvm::Function *F) {
- // Only if we are checking indirect calls.
+ if (CodeGenOpts.CallGraphSection && !hasExistingGeneralizedTypeMD(F) &&
+ (!F->hasLocalLinkage() ||
+ F->getFunction().hasAddressTaken(nullptr, /*IgnoreCallbackUses=*/true,
+ /*IgnoreAssumeLikeCalls=*/true,
+ /*IgnoreLLVMUsed=*/false)))
+ F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FD->getType()));
+
+ // Add additional metadata only if we are checking indirect calls with CFI.
if (!LangOpts.Sanitize.has(SanitizerKind::CFIICall))
return;
@@ -3069,10 +3082,12 @@ void CodeGenModule::createFunctionTypeMetadataForIcall(const FunctionDecl *FD,
/*GeneralizePointers=*/false);
llvm::Metadata *MD = CreateMetadataIdentifierForType(FnType);
F->addTypeMetadata(0, MD);
-
- QualType GenPtrFnType = GeneralizeFunctionType(getContext(), FD->getType(),
- /*GeneralizePointers=*/true);
- F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(GenPtrFnType));
+ // Add the generalized identifier if not added already.
+ if (!hasExistingGeneralizedTypeMD(F)) {
+ QualType GenPtrFnType = GeneralizeFunctionType(getContext(), FD->getType(),
+ /*GeneralizePointers=*/true);
+ F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(GenPtrFnType));
+ }
// Emit a hash-based bit set entry for cross-DSO calls.
if (CodeGenOpts.SanitizeCfiCrossDso)
@@ -3080,6 +3095,21 @@ void CodeGenModule::createFunctionTypeMetadataForIcall(const FunctionDecl *FD,
F->addTypeMetadata(0, llvm::ConstantAsMetadata::get(CrossDsoTypeId));
}
+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())
+ return;
+
+ llvm::Metadata *TypeIdMD = CreateMetadataIdentifierGeneralized(QT);
+ llvm::MDTuple *TypeTuple = llvm::MDTuple::get(
+ getLLVMContext(), {llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
+ llvm::Type::getInt64Ty(getLLVMContext()), 0)),
+ TypeIdMD});
+ llvm::MDTuple *MDN = llvm::MDNode::get(getLLVMContext(), {TypeTuple});
+ CB->setMetadata(llvm::LLVMContext::MD_callee_type, MDN);
+}
+
void CodeGenModule::setKCFIType(const FunctionDecl *FD, llvm::Function *F) {
llvm::LLVMContext &Ctx = F->getContext();
llvm::MDBuilder MDB(Ctx);
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 3971b296b3f80..a323621136c90 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -1644,6 +1644,9 @@ class CodeGenModule : public CodeGenTypeCache {
void createFunctionTypeMetadataForIcall(const FunctionDecl *FD,
llvm::Function *F);
+ /// Create and attach type metadata to the given call.
+ void createCalleeTypeMetadataForIcall(const QualType &QT, llvm::CallBase *CB);
+
/// Set type metadata to the given function.
void setKCFIType(const FunctionDecl *FD, llvm::Function *F);
diff --git a/clang/test/CodeGen/call-graph-section-templates.cpp b/clang/test/CodeGen/call-graph-section-templates.cpp
new file mode 100644
index 0000000000000..6621eff37daa8
--- /dev/null
+++ b/clang/test/CodeGen/call-graph-section-templates.cpp
@@ -0,0 +1,114 @@
+// Tests that we assign appropriate identifiers to indirect calls and targets
+// specifically for C++ templates.
+
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fexperimental-call-graph-section \
+// RUN: -emit-llvm -o %t %s
+// RUN: FileCheck --check-prefix=FT %s < %t
+// RUN: FileCheck --check-prefix=CST %s < %t
+
+////////////////////////////////////////////////////////////////////////////////
+// Class definitions and template classes (check for indirect target metadata)
+
+class Cls1 {};
+
+// Cls2 is instantiated with T=Cls1 in foo(). Following checks are for this
+// instantiation.
+template <class T>
+class Cls2 {
+public:
+ // FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f1Ev({{.*}} !type [[F_TCLS2F1:![0-9]+]]
+ void f1() {}
+
+ // FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f2ES0_({{.*}} !type [[F_TCLS2F2:![0-9]+]]
+ void f2(T a) {}
+
+ // FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f3EPS0_({{.*}} !type [[F_TCLS2F3:![0-9]+]]
+ void f3(T *a) {}
+
+ // FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f4EPKS0_({{.*}} !type [[F_TCLS2F4:![0-9]+]]
+ void f4(const T *a) {}
+
+ // FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f5ERS0_({{.*}} !type [[F_TCLS2F5:![0-9]+]]
+ void f5(T &a) {}
+
+ // FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f6ERKS0_({{.*}} !type [[F_TCLS2F6:![0-9]+]]
+ void f6(const T &a) {}
+
+ // Mixed type function pointer member
+ T *(*fp)(T a, T *b, const T *c, T &d, const T &e);
+};
+
+// FT-DAG: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFvvE.generalized"}
+// FT-DAG: [[F_TCLS2F2]] = !{i64 0, !"_ZTSFv4Cls1E.generalized"}
+// FT-DAG: [[F_TCLS2F3]] = !{i64 0, !"_ZTSFvP4Cls1E.generalized"}
+// FT-DAG: [[F_TCLS2F4]] = !{i64 0, !"_ZTSFvPK4Cls1E.generalized"}
+// FT-DAG: [[F_TCLS2F5]] = !{i64 0, !"_ZTSFvR4Cls1E.generalized"}
+// FT-DAG: [[F_TCLS2F6]] = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"}
+
+////////////////////////////////////////////////////////////////////////////////
+// Callsites (check for indirect callsite operand bundles)
+
+template <class T>
+T *T_func(T a, T *b, const T *c, T &d, const T &e) { return b; }
+
+// CST-LABEL: define {{.*}} @_Z3foov
+void foo() {
+ // Methods for Cls2<Cls1> is checked above within the template description.
+ Cls2<Cls1> Obj;
+
+ Obj.fp = T_func<Cls1>;
+ Cls1 Cls1Obj;
+
+ // CST: call noundef ptr %{{.*}}, !callee_type [[F_TFUNC_CLS1_CT:![0-9]+]]
+ Obj.fp(Cls1Obj, &Cls1Obj, &Cls1Obj, Cls1Obj, Cls1Obj);
+
+ // Make indirect calls to Cls2's member methods
+ auto fp_f1 = &Cls2<Cls1>::f1;
+ auto fp_f2 = &Cls2<Cls1>::f2;
+ auto fp_f3 = &Cls2<Cls1>::f3;
+ auto fp_f4 = &Cls2<Cls1>::f4;
+ auto fp_f5 = &Cls2<Cls1>::f5;
+ auto fp_f6 = &Cls2<Cls1>::f6;
+
+ auto *Obj2Ptr = &Obj;
+
+ // CST: call void %{{.*}}, !callee_type [[F_TCLS2F1_CT:![0-9]+]]
+ (Obj2Ptr->*fp_f1)();
+
+ // CST: call void %{{.*}}, !callee_type [[F_TCLS2F2_CT:![0-9]+]]
+ (Obj2Ptr->*fp_f2)(Cls1Obj);
+
+ // CST: call void %{{.*}}, !callee_type [[F_TCLS2F3_CT:![0-9]+]]
+ (Obj2Ptr->*fp_f3)(&Cls1Obj);
+
+ // CST: call void %{{.*}}, !callee_type [[F_TCLS2F4_CT:![0-9]+]]
+ (Obj2Ptr->*fp_f4)(&Cls1Obj);
+
+ // CST: call void %{{.*}}, !callee_type [[F_TCLS2F5_CT:![0-9]+]]
+ (Obj2Ptr->*fp_f5)(Cls1Obj);
+
+ // CST: call void %{{.*}}, !callee_type [[F_TCLS2F6_CT:![0-9]+]]
+ (Obj2Ptr->*fp_f6)(Cls1Obj);
+}
+
+// CST: define {{.*}} @_Z6T_funcI4Cls1EPT_S1_S2_PKS1_RS1_RS3_({{.*}} !type [[F_TFUNC_CLS1:![0-9]+]]
+// CST-DAG: [[F_TFUNC_CLS1_CT]] = !{[[F_TFUNC_CLS1:![0-9]+]]}
+// CST-DAG: [[F_TFUNC_CLS1]] = !{i64 0, !"_ZTSFP4Cls1S_S0_PKS_RS_RS1_E.generalized"}
+
+// CST-DAG: [[F_TCLS2F1_CT]] = !{[[F_TCLS2F1:![0-9]+]]}
+// CST-DAG: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFvvE.generalized"}
+
+// CST-DAG: [[F_TCLS2F2_CT]] = !{[[F_TCLS2F2:![0-9]+]]}
+// CST-DAG: [[F_TCLS2F2]] = !{i64 0, !"_ZTSFv4Cls1E.generalized"}
+
+// CST-DAG: [[F_TCLS2F3_CT]] = !{[[F_TCLS2F3:![0-9]+]]}
+// CST-DAG: [[F_TCLS2F3]] = !{i64 0, !"_ZTSFvP4Cls1E.generalized"}
+
+// CST-DAG: [[F_TCLS2F4_CT]] = !{[[F_TCLS2F4:![0-9]+]]}
+// CST-DAG: [[F_TCLS2F4]] = !{i64 0, !"_ZTSFvPK4Cls1E.generalized"}
+
+// CST-DAG: [[F_TCLS2F5_CT]] = !{[[F_TCLS2F5:![0-9]+]]}
+// CST-DAG: [[F_TCLS2F5]] = !{i64 0, !"_ZTSFvR4Cls1E.generalized"}
+
+// CST-DAG: [[F_TCLS2F6_CT]] = !{[[F_TCLS2F6:![0-9]+]]}
+// CST-DAG: [[F_TCLS2F6]] = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"}
diff --git a/clang/test/CodeGen/call-graph-section-virtual-methods.cpp b/clang/test/CodeGen/call-graph-section-virtual-methods.cpp
new file mode 100644
index 0000000000000..d95e54053f766
--- /dev/null
+++ b/clang/test/CodeGen/call-graph-section-virtual-methods.cpp
@@ -0,0 +1,55 @@
+// Tests that we assign appropriate identifiers to indirect calls and targets
+// specifically for virtual methods.
+
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fexperimental-call-graph-section \
+// RUN: -emit-llvm -o %t %s
+// RUN: FileCheck --check-prefix=FT %s < %t
+// RUN: FileCheck --check-prefix=CST %s < %t
+
+////////////////////////////////////////////////////////////////////////////////
+// Class definitions (check for indirect target metadata)
+
+class Base {
+ public:
+ // FT-DAG: define {{.*}} @_ZN4Base2vfEPc({{.*}} !type [[F_TVF:![0-9]+]]
+ virtual int vf(char *a) { return 0; };
+ };
+
+ class Derived : public Base {
+ public:
+ // FT-DAG: define {{.*}} @_ZN7Derived2vfEPc({{.*}} !type [[F_TVF]]
+ int vf(char *a) override { return 1; };
+ };
+
+ // FT-DAG: [[F_TVF]] = !{i64 0, !"_ZTSFiPcE.generalized"}
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Callsites (check for indirect callsite operand bundles)
+
+ // CST-LABEL: define {{.*}} @_Z3foov
+ void foo() {
+ auto B = Base();
+ auto D = Derived();
+
+ Base *Bptr = &B;
+ Base *BptrToD = &D;
+ Derived *Dptr = &D;
+
+ auto FpBaseVf = &Base::vf;
+ auto FpDerivedVf = &Derived::vf;
+
+ // CST: call noundef i32 %{{.*}}, !callee_type [[F_TVF_CT:![0-9]+]]
+ (Bptr->*FpBaseVf)(0);
+
+ // CST: call noundef i32 %{{.*}}, !callee_type [[F_TVF_CT:![0-9]+]]
+ (BptrToD->*FpBaseVf)(0);
+
+ // CST: call noundef i32 %{{.*}}, !callee_type [[F_TVF_CT:![0-9]+]]
+ (Dptr->*FpBaseVf)(0);
+
+ // CST: call noundef i32 %{{.*}}, !callee_type [[F_TVF_CT:![0-9]+]]
+ (Dptr->*FpDerivedVf)(0);
+ }
+
+ // CST-DAG: [[F_TVF_CT]] = !{[[F_TVF:![0-9]+]]}
+ // CST-DAG: [[F_TVF]] = !{i64 0, !"_ZTSFiPcE.generalized"}
diff --git a/clang/test/CodeGen/call-graph-section.c b/clang/test/CodeGen/call-graph-section.c
new file mode 100644
index 0000000000000..7aefb81859a93
--- /dev/null
+++ b/clang/test/CodeGen/call-graph-section.c
@@ -0,0 +1,83 @@
+// Tests that we assign appropriate identifiers to indirect calls and targets.
+
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fexperimental-call-graph-section \
+// RUN: -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,ITANIUM %s
+
+// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fexperimental-call-graph-section \
+// RUN: -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,MS %s
+
+// CHECK-DAG: define {{(dso_local)?}} void @foo({{.*}} !type [[F_TVOID:![0-9]+]]
+void foo() {
+}
+
+// CHECK-DAG: define {{(dso_local)?}} void @bar({{.*}} !type [[F_TVOID]]
+void bar() {
+ void (*fp)() = foo;
+ // CHECK: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]]
+ fp();
+}
+
+// CHECK-DAG: define {{(dso_local)?}} i32 @baz({{.*}} !type [[F_TPRIMITIVE:![0-9]+]]
+int baz(char a, float b, double c) {
+ return 1;
+}
+
+// CHECK-DAG: define {{(dso_local)?}} ptr @qux({{.*}} !type [[F_TPTR:![0-9]+]]
+int *qux(char *a, float *b, double *c) {
+ return 0;
+}
+
+// CHECK-DAG: define {{(dso_local)?}} void @corge({{.*}} !type [[F_TVOID]]
+void corge() {
+ int (*fp_baz)(char, float, double) = baz;
+ // CHECK: call i32 {{.*}}, !callee_type [[F_TPRIMITIVE_CT:![0-9]+]]
+ fp_baz('a', .0f, .0);
+
+ int *(*fp_qux)(char *, float *, double *) = qux;
+ // CHECK: call ptr {{.*}}, !callee_type [[F_TPTR_CT:![0-9]+]]
+ fp_qux(0, 0, 0);
+}
+
+struct st1 {
+ int *(*fp)(char *, float *, double *);
+};
+
+struct st2 {
+ struct st1 m;
+};
+
+// CHECK-DAG: define {{(dso_local)?}} void @stparam({{.*}} !type [[F_TSTRUCT:![0-9]+]]
+void stparam(struct st2 a, struct st2 *b) {}
+
+// CHECK-DAG: define {{(dso_local)?}} void @stf({{.*}} !type [[F_TVOID]]
+void stf() {
+ struct st1 St1;
+ St1.fp = qux;
+ // CHECK: call ptr {{.*}}, !callee_type [[F_TPTR_CT:![0-9]+]]
+ St1.fp(0, 0, 0);
+
+ struct st2 St2;
+ St2.m.fp = qux;
+ // CHECK: call ptr {{.*}}, !callee_type [[F_TPTR_CT:![0-9]+]]
+ St2.m.fp(0, 0, 0);
+
+ // CHECK: call void {{.*}}, !callee_type [[F_TSTRUCT_CT:![0-9]+]]
+ void (*fp_stparam)(struct st2, struct st2 *) = stparam;
+ fp_stparam(St2, &St2);
+}
+
+// CHECK-DAG: [[F_TVOID_CT]] = !{[[F_TVOID:![0-9]+]]}
+// ITANIUM-DAG: [[F_TVOID]] = !{i64 0, !"_ZTSFvE.generalized"}
+// MS-DAG: [[F_TVOID]] = !{i64 0, !"?6AX at Z.generalized"}
+
+// CHECK-DAG: [[F_TPRIMITIVE_CT]] = !{[[F_TPRIMITIVE:![0-9]+]]}
+// ITANIUM-DAG: [[F_TPRIMITIVE]] = !{i64 0, !"_ZTSFicfdE.generalized"}
+// MS-DAG: [[F_TPRIMITIVE]] = !{i64 0, !"?6AHDMN at Z.generalized"}
+
+// CHECK-DAG: [[F_TPTR_CT]] = !{[[F_TPTR:![0-9]+]]}
+// ITANIUM-DAG: [[F_TPTR]] = !{i64 0, !"_ZTSFPiPcPfPdE.generalized"}
+// MS-DAG: [[F_TPTR]] = !{i64 0, !"?6APEAHPEADPEAMPEAN at Z.generalized"}
+
+// CHECK-DAG: [[F_TSTRUCT_CT]] = !{[[F_TSTRUCT:![0-9]+]]}
+// ITANIUM-DAG: [[F_TSTRUCT]] = !{i64 0, !"_ZTSFv3st2PS_E.generalized"}
+// MS-DAG: [[F_TSTRUCT]] = !{i64 0, !"?6AXUst2@@PEAU0@@Z.generalized"}
diff --git a/clang/test/CodeGen/call-graph-section.cpp b/clang/test/CodeGen/call-graph-section.cpp
new file mode 100644
index 0000000000000..85bb12535709f
--- /dev/null
+++ b/clang/test/CodeGen/call-graph-section.cpp
@@ -0,0 +1,138 @@
+// Tests that we assign appropriate identifiers to indirect calls and targets
+// specifically for C++ class and instance methods.
+
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fexperimental-call-graph-section \
+// RUN: -emit-llvm -o %t %s
+// RUN: FileCheck --check-prefix=FT %s < %t
+// RUN: FileCheck --check-prefix=CST %s < %t
+
+////////////////////////////////////////////////////////////////////////////////
+// Class definitions (check for indirect target metadata)
+
+class Cls1 {
+public:
+ // FT-DAG: define {{.*}} ptr @_ZN4Cls18receiverEPcPf({{.*}} !type [[F_TCLS1RECEIVER:![0-9]+]]
+ static int *receiver(char *a, float *b) { return 0; }
+};
+
+class Cls2 {
+public:
+ int *(*fp)(char *, float *);
+
+ // FT-DAG: define {{.*}} i32 @_ZN4Cls22f1Ecfd({{.*}} !type [[F_TCLS2F1:![0-9]+]]
+ int f1(char a, float b, double c) { return 0; }
+
+ // FT-DAG: define {{.*}} ptr @_ZN4Cls22f2EPcPfPd({{.*}} !type [[F_TCLS2F2:![0-9]+]]
+ int *f2(char *a, float *b, double *c) { return 0; }
+
+ // FT-DAG: define {{.*}} void @_ZN4Cls22f3E4Cls1({{.*}} !type [[F_TCLS2F3F4:![0-9]+]]
+ void f3(Cls1 a) {}
+
+ // FT-DAG: define {{.*}} void @_ZN4Cls22f4E4Cls1({{.*}} !type [[F_TCLS2F3F4]]
+ void f4(const Cls1 a) {}
+
+ // FT-DAG: define {{.*}} void @_ZN4Cls22f5EP4Cls1({{.*}} !type [[F_TCLS2F5:![0-9]+]]
+ void f5(Cls1 *a) {}
+
+ // FT-DAG: define {{.*}} void @_ZN4Cls22f6EPK4Cls1({{.*}} !type [[F_TCLS2F6:![0-9]+]]
+ void f6(const Cls1 *a) {}
+
+ // FT-DAG: define {{.*}} void @_ZN4Cls22f7ER4Cls1({{.*}} !type [[F_TCLS2F7:![0-9]+]]
+ void f7(Cls1 &a) {}
+
+ // FT-DAG: define {{.*}} void @_ZN4Cls22f8ERK4Cls1({{.*}} !type [[F_TCLS2F8:![0-9]+]]
+ void f8(const Cls1 &a) {}
+
+ // FT-DAG: define {{.*}} void @_ZNK4Cls22f9Ev({{.*}} !type [[F_TCLS2F9:![0-9]+]]
+ void f9() const {}
+};
+
+// FT-DAG: [[F_TCLS1RECEIVER]] = !{i64 0, !"_ZTSFPiPcPfE.generalized"}
+// FT-DAG: [[F_TCLS2F2]] = !{i64 0, !"_ZTSFPiPcPfPdE.generalized"}
+// FT-DAG: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFicfdE.generalized"}
+// FT-DAG: [[F_TCLS2F3F4]] = !{i64 0, !"_ZTSFv4Cls1E.generalized"}
+// FT-DAG: [[F_TCLS2F5]] = !{i64 0, !"_ZTSFvP4Cls1E.generalized"}
+// FT-DAG: [[F_TCLS2F6]] = !{i64 0, !"_ZTSFvPK4Cls1E.generalized"}
+// FT-DAG: [[F_TCLS2F7]] = !{i64 0, !"_ZTSFvR4Cls1E.generalized"}
+// FT-DAG: [[F_TCLS2F8]] = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"}
+// FT-DAG: [[F_TCLS2F9]] = !{i64 0, !"_ZTSKFvvE.generalized"}
+
+////////////////////////////////////////////////////////////////////////////////
+// Callsites (check for indirect callsites' callee_type metadata )
+
+// CST-LABEL: define {{.*}} @_Z3foov
+void foo() {
+ Cls2 ObjCls2;
+ ObjCls2.fp = &Cls1::receiver;
+
+ // CST: call noundef ptr %{{.*}}, !callee_type [[F_TCLS1RECEIVER_CT:![0-9]+]]
+ ObjCls2.fp(0, 0);
+
+ auto fp_f1 = &Cls2::f1;
+ auto fp_f2 = &Cls2::f2;
+ auto fp_f3 = &Cls2::f3;
+ auto fp_f4 = &Cls2::f4;
+ auto fp_f5 = &Cls2::f5;
+ auto fp_f6 = &Cls2::f6;
+ auto fp_f7 = &Cls2::f7;
+ auto fp_f8 = &Cls2::f8;
+ auto fp_f9 = &Cls2::f9;
+
+ Cls2 *ObjCls2Ptr = &ObjCls2;
+ Cls1 Cls1Param;
+
+ // CST: call noundef i32 %{{.*}}, !callee_type [[F_TCLS2F1_CT:![0-9]+]]
+ (ObjCls2Ptr->*fp_f1)(0, 0, 0);
+
+ // CST: call noundef ptr %{{.*}}, !callee_type [[F_TCLS2F2_CT:![0-9]+]]
+ (ObjCls2Ptr->*fp_f2)(0, 0, 0);
+
+ // CST: call void %{{.*}}, !callee_type [[F_TCLS2F3F4_CT:![0-9]+]]
+ (ObjCls2Ptr->*fp_f3)(Cls1Param);
+
+ // CST: call void %{{.*}}, !callee_type [[F_TCLS2F3F4_CT:![0-9]+]]
+ (ObjCls2Ptr->*fp_f4)(Cls1Param);
+
+ // CST: call void %{{.*}}, !callee_type [[F_TCLS2F5_CT:![0-9]+]]
+ (ObjCls2Ptr->*fp_f5)(&Cls1Param);
+
+ // CST: call void %{{.*}}, !callee_type [[F_TCLS2F6_CT:![0-9]+]]
+ (ObjCls2Ptr->*fp_f6)(&Cls1Param);
+
+ // CST: call void %{{.*}}, !callee_type [[F_TCLS2F7_CT:![0-9]+]]
+ (ObjCls2Ptr->*fp_f7)(Cls1Param);
+
+ // CST: call void %{{.*}}, !callee_type [[F_TCLS2F8_CT:![0-9]+]]
+ (ObjCls2Ptr->*fp_f8)(Cls1Param);
+
+ // CST: call void %{{.*}}, !callee_type [[F_TCLS2F9_CT:![0-9]+]]
+ (ObjCls2Ptr->*fp_f9)();
+}
+
+
+// CST-DAG: [[F_TCLS1RECEIVER_CT]] = !{[[F_TCLS1RECEIVER:![0-9]+]]}
+// CST-DAG: [[F_TCLS1RECEIVER]] = !{i64 0, !"_ZTSFPiPcPfE.generalized"}
+
+// CST-DAG: [[F_TCLS2F2_CT]] = !{[[F_TCLS2F2:![0-9]+]]}
+// CST-DAG: [[F_TCLS2F2]] = !{i64 0, !"_ZTSFPiPcPfPdE.generalized"}
+
+// CST-DAG: [[F_TCLS2F1_CT]] = !{[[F_TCLS2F1:![0-9]+]]}
+// CST-DAG: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFicfdE.generalized"}
+
+// CST-DAG: [[F_TCLS2F3F4_CT]] = !{[[F_TCLS2F3F4:![0-9]+]]}
+// CST-DAG: [[F_TCLS2F3F4]] = !{i64 0, !"_ZTSFv4Cls1E.generalized"}
+
+// CST-DAG: [[F_TCLS2F5_CT]] = !{[[F_TCLS2F5:![0-9]+]]}
+// CST-DAG: [[F_TCLS2F5]] = !{i64 0, !"_ZTSFvP4Cls1E.generalized"}
+
+// CST-DAG: [[F_TCLS2F6_CT]] = !{[[F_TCLS2F6:![0-9]+]]}
+// CST-DAG: [[F_TCLS2F6]] = !{i64 0, !"_ZTSFvPK4Cls1E.generalized"}
+
+// CST-DAG: [[F_TCLS2F7_CT]] = !{[[F_TCLS2F7:![0-9]+]]}
+// CST-DAG: [[F_TCLS2F7]] = !{i64 0, !"_ZTSFvR4Cls1E.generalized"}
+
+// CST-DAG: [[F_TCLS2F8_CT]] = !{[[F_TCLS2F8:![0-9]+]]}
+// CST-DAG: [[F_TCLS2F8]] = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"}
+
+// CST-DAG: [[F_TCLS2F9_CT]] = !{[[F_TCLS2F9:![0-9]+]]}
+// CST-DAG: [[F_TCLS2F9]] = !{i64 0, !"_ZTSKFvvE.generalized"}
>From 4bedac1a02097132fba24a5b037d264fc77472f1 Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Mon, 13 Oct 2025 13:52:58 -0700
Subject: [PATCH 02/10] Refactor call graph type metadata addition code out of
CFI flow.
---
clang/lib/CodeGen/CodeGenModule.cpp | 29 +++++++++++++++++++++++------
clang/lib/CodeGen/CodeGenModule.h | 9 +++++++--
2 files changed, 30 insertions(+), 8 deletions(-)
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index b626afc92e822..dd6635362ddb8 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -2848,7 +2848,16 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
// Skip available_externally functions. They won't be codegen'ed in the
// current module anyway.
if (getContext().GetGVALinkageForFunction(FD) != GVA_AvailableExternally)
- createFunctionTypeMetadataForIcall(FD, F);
+ createFunctionTypeMetadataForIcallForCFI(FD, F);
+ }
+ }
+
+ if (CodeGenOpts.CallGraphSection) {
+ if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+ // Skip available_externally functions. They won't be codegen'ed in the
+ // current module anyway.
+ if (getContext().GetGVALinkageForFunction(FD) != GVA_AvailableExternally)
+ createFunctionTypeMDForIcallForCallGraph(FD, F);
}
}
@@ -3060,16 +3069,24 @@ static bool hasExistingGeneralizedTypeMD(llvm::Function *F) {
return MD && MD->hasGeneralizedMDString();
}
-void CodeGenModule::createFunctionTypeMetadataForIcall(const FunctionDecl *FD,
- llvm::Function *F) {
- if (CodeGenOpts.CallGraphSection && !hasExistingGeneralizedTypeMD(F) &&
+void CodeGenModule::createFunctionTypeMDForIcallForCallGraph(
+ const FunctionDecl *FD, llvm::Function *F) {
+ // Add additional metadata if we are emitting call graph section
+ if (!CodeGenOpts.CallGraphSection)
+ return;
+
+ if (!hasExistingGeneralizedTypeMD(F) &&
(!F->hasLocalLinkage() ||
F->getFunction().hasAddressTaken(nullptr, /*IgnoreCallbackUses=*/true,
/*IgnoreAssumeLikeCalls=*/true,
/*IgnoreLLVMUsed=*/false)))
F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FD->getType()));
+}
+
+void CodeGenModule::createFunctionTypeMetadataForIcallForCFI(
+ const FunctionDecl *FD, llvm::Function *F) {
- // Add additional metadata only if we are checking indirect calls with CFI.
+ // Only if we are checking indirect calls.
if (!LangOpts.Sanitize.has(SanitizerKind::CFIICall))
return;
@@ -3243,7 +3260,7 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
// jump table.
if (!CodeGenOpts.SanitizeCfiCrossDso ||
!CodeGenOpts.SanitizeCfiCanonicalJumpTables)
- createFunctionTypeMetadataForIcall(FD, F);
+ createFunctionTypeMetadataForIcallForCFI(FD, F);
if (LangOpts.Sanitize.has(SanitizerKind::KCFI))
setKCFIType(FD, F);
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index a323621136c90..15b9e9176ae40 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -1641,8 +1641,13 @@ class CodeGenModule : public CodeGenTypeCache {
llvm::Metadata *CreateMetadataIdentifierGeneralized(QualType T);
/// Create and attach type metadata to the given function.
- void createFunctionTypeMetadataForIcall(const FunctionDecl *FD,
- llvm::Function *F);
+ void createFunctionTypeMetadataForIcallForCFI(const FunctionDecl *FD,
+ llvm::Function *F);
+
+ /// Create and attach type metadata if the function is a potential indirect
+ /// call target to support call graph section.
+ void createFunctionTypeMDForIcallForCallGraph(const FunctionDecl *FD,
+ llvm::Function *F);
/// Create and attach type metadata to the given call.
void createCalleeTypeMetadataForIcall(const QualType &QT, llvm::CallBase *CB);
>From 369ac05246699c5450652921ad64c5b88a743033 Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Mon, 13 Oct 2025 14:02:30 -0700
Subject: [PATCH 03/10] Clean up adding type metadata for potential indirect
targets.
---
clang/lib/CodeGen/CodeGenModule.cpp | 36 +++++++++++++----------------
clang/lib/CodeGen/CodeGenModule.h | 7 +++---
2 files changed, 19 insertions(+), 24 deletions(-)
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index dd6635362ddb8..f348181ac454c 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -2848,17 +2848,13 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
// Skip available_externally functions. They won't be codegen'ed in the
// current module anyway.
if (getContext().GetGVALinkageForFunction(FD) != GVA_AvailableExternally)
- createFunctionTypeMetadataForIcallForCFI(FD, F);
+ createFunctionTypeMetadataForIcall(FD, F);
}
}
if (CodeGenOpts.CallGraphSection) {
- if (auto *FD = dyn_cast<FunctionDecl>(D)) {
- // Skip available_externally functions. They won't be codegen'ed in the
- // current module anyway.
- if (getContext().GetGVALinkageForFunction(FD) != GVA_AvailableExternally)
- createFunctionTypeMDForIcallForCallGraph(FD, F);
- }
+ if (auto *FD = dyn_cast<FunctionDecl>(D))
+ createIndirectFunctionTypeMD(FD, F);
}
// Emit type metadata on member functions for member function pointer checks.
@@ -3069,22 +3065,22 @@ static bool hasExistingGeneralizedTypeMD(llvm::Function *F) {
return MD && MD->hasGeneralizedMDString();
}
-void CodeGenModule::createFunctionTypeMDForIcallForCallGraph(
- const FunctionDecl *FD, llvm::Function *F) {
- // Add additional metadata if we are emitting call graph section
- if (!CodeGenOpts.CallGraphSection)
+void CodeGenModule::createIndirectFunctionTypeMD(const FunctionDecl *FD,
+ llvm::Function *F) {
+ // Return if generalized type metadata is already attached.
+ if (hasExistingGeneralizedTypeMD(F))
return;
-
- if (!hasExistingGeneralizedTypeMD(F) &&
- (!F->hasLocalLinkage() ||
- F->getFunction().hasAddressTaken(nullptr, /*IgnoreCallbackUses=*/true,
- /*IgnoreAssumeLikeCalls=*/true,
- /*IgnoreLLVMUsed=*/false)))
+ // All functions which are not internal linkage could be indirect targets.
+ // Address taken functions with internal linkage could be indirect targets.
+ if (!F->hasLocalLinkage() &&
+ F->getFunction().hasAddressTaken(nullptr, /*IgnoreCallbackUses=*/true,
+ /*IgnoreAssumeLikeCalls=*/true,
+ /*IgnoreLLVMUsed=*/false))
F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FD->getType()));
}
-void CodeGenModule::createFunctionTypeMetadataForIcallForCFI(
- const FunctionDecl *FD, llvm::Function *F) {
+void CodeGenModule::createFunctionTypeMetadataForIcall(const FunctionDecl *FD,
+ llvm::Function *F) {
// Only if we are checking indirect calls.
if (!LangOpts.Sanitize.has(SanitizerKind::CFIICall))
@@ -3260,7 +3256,7 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
// jump table.
if (!CodeGenOpts.SanitizeCfiCrossDso ||
!CodeGenOpts.SanitizeCfiCanonicalJumpTables)
- createFunctionTypeMetadataForIcallForCFI(FD, F);
+ createFunctionTypeMetadataForIcall(FD, F);
if (LangOpts.Sanitize.has(SanitizerKind::KCFI))
setKCFIType(FD, F);
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 15b9e9176ae40..a253bcda2d06c 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -1641,13 +1641,12 @@ class CodeGenModule : public CodeGenTypeCache {
llvm::Metadata *CreateMetadataIdentifierGeneralized(QualType T);
/// Create and attach type metadata to the given function.
- void createFunctionTypeMetadataForIcallForCFI(const FunctionDecl *FD,
- llvm::Function *F);
+ void createFunctionTypeMetadataForIcall(const FunctionDecl *FD,
+ llvm::Function *F);
/// Create and attach type metadata if the function is a potential indirect
/// call target to support call graph section.
- void createFunctionTypeMDForIcallForCallGraph(const FunctionDecl *FD,
- llvm::Function *F);
+ void createIndirectFunctionTypeMD(const FunctionDecl *FD, llvm::Function *F);
/// Create and attach type metadata to the given call.
void createCalleeTypeMetadataForIcall(const QualType &QT, llvm::CallBase *CB);
>From 2112b81d8012166653ae4fa2c706772c9a910dbc Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Mon, 13 Oct 2025 15:48:27 -0700
Subject: [PATCH 04/10] More cleanups.
---
clang/lib/CodeGen/CodeGenModule.cpp | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index f348181ac454c..68d2ba4821688 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -2841,9 +2841,8 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
// In the cross-dso CFI mode with canonical jump tables, we want !type
// attributes on definitions only.
- if ((CodeGenOpts.SanitizeCfiCrossDso &&
- CodeGenOpts.SanitizeCfiCanonicalJumpTables) ||
- CodeGenOpts.CallGraphSection) {
+ if (CodeGenOpts.SanitizeCfiCrossDso &&
+ CodeGenOpts.SanitizeCfiCanonicalJumpTables) {
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
// Skip available_externally functions. They won't be codegen'ed in the
// current module anyway.
@@ -3070,9 +3069,10 @@ void CodeGenModule::createIndirectFunctionTypeMD(const FunctionDecl *FD,
// Return if generalized type metadata is already attached.
if (hasExistingGeneralizedTypeMD(F))
return;
+
// All functions which are not internal linkage could be indirect targets.
// Address taken functions with internal linkage could be indirect targets.
- if (!F->hasLocalLinkage() &&
+ if (!F->hasLocalLinkage() ||
F->getFunction().hasAddressTaken(nullptr, /*IgnoreCallbackUses=*/true,
/*IgnoreAssumeLikeCalls=*/true,
/*IgnoreLLVMUsed=*/false))
@@ -3258,6 +3258,9 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
!CodeGenOpts.SanitizeCfiCanonicalJumpTables)
createFunctionTypeMetadataForIcall(FD, F);
+ if (CodeGenOpts.CallGraphSection)
+ createIndirectFunctionTypeMD(FD, F);
+
if (LangOpts.Sanitize.has(SanitizerKind::KCFI))
setKCFIType(FD, F);
>From 9ac4b00e1f70929fa15f2e5d85719b7ad60a3535 Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Mon, 13 Oct 2025 15:51:06 -0700
Subject: [PATCH 05/10] Format fixes.
---
clang/lib/CodeGen/CodeGenModule.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 68d2ba4821688..436d6eff89399 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -3081,7 +3081,6 @@ void CodeGenModule::createIndirectFunctionTypeMD(const FunctionDecl *FD,
void CodeGenModule::createFunctionTypeMetadataForIcall(const FunctionDecl *FD,
llvm::Function *F) {
-
// Only if we are checking indirect calls.
if (!LangOpts.Sanitize.has(SanitizerKind::CFIICall))
return;
>From a9345a7ad323334a5f02caac0648881c9db1cd22 Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Mon, 13 Oct 2025 16:34:18 -0700
Subject: [PATCH 06/10] Add test to cover callback/internal
linkage/addresstaken case.
---
.../CodeGen/call-graph-section-callback.cpp | 29 +++++++++++++++++++
1 file changed, 29 insertions(+)
create mode 100644 clang/test/CodeGen/call-graph-section-callback.cpp
diff --git a/clang/test/CodeGen/call-graph-section-callback.cpp b/clang/test/CodeGen/call-graph-section-callback.cpp
new file mode 100644
index 0000000000000..0404f888d0b1f
--- /dev/null
+++ b/clang/test/CodeGen/call-graph-section-callback.cpp
@@ -0,0 +1,29 @@
+// Tests that callback function whose address is taken is attached Type ID metadata
+// as it is a potential indirect call target.
+
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fexperimental-call-graph-section \
+// RUN: -emit-llvm -o %t %s
+// RUN: FileCheck %s < %t
+
+////////////////////////////////////////////////////////////////////////////////
+typedef void (*CallbackFn)(int);
+
+// Callback function with "internal" linkage.
+// CHECK-DAG: define internal void @_ZL10myCallbacki({{.*}} !type [[F_CALLBACK:![0-9]+]]
+static void myCallback(int value)
+{
+ volatile int sink = value;
+ (void)sink;
+}
+
+int takeCallbackAddress() {
+ // Take the address of the callback explicitly (address-taken function)
+ CallbackFn cb = &myCallback;
+ // Store the address in a volatile pointer to keep it observable
+ volatile void* addr = (void*)cb;
+ (void)addr;
+
+ return 0;
+}
+
+// CHECK-DAG: [[F_CALLBACK]] = !{i64 0, !"_ZTSFviE.generalized"}
>From ed7ced5b8d41fff77c5803750c8d89aa67075c52 Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Mon, 13 Oct 2025 16:51:26 -0700
Subject: [PATCH 07/10] Use CHECK-LABEL by breaking up the check line into 2.
---
clang/test/CodeGen/call-graph-section.c | 21 ++++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/clang/test/CodeGen/call-graph-section.c b/clang/test/CodeGen/call-graph-section.c
index 7aefb81859a93..ae6b6ce311003 100644
--- a/clang/test/CodeGen/call-graph-section.c
+++ b/clang/test/CodeGen/call-graph-section.c
@@ -6,28 +6,33 @@
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fexperimental-call-graph-section \
// RUN: -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,MS %s
-// CHECK-DAG: define {{(dso_local)?}} void @foo({{.*}} !type [[F_TVOID:![0-9]+]]
+// CHECK-LABEL: define {{(dso_local)?}} void @foo(
+// CHECK: {{.*}} !type [[F_TVOID:![0-9]+]]
void foo() {
}
-// CHECK-DAG: define {{(dso_local)?}} void @bar({{.*}} !type [[F_TVOID]]
+// CHECK-LABEL: define {{(dso_local)?}} void @bar(
+// CHECK: {{.*}} !type [[F_TVOID]]
void bar() {
void (*fp)() = foo;
// CHECK: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]]
fp();
}
-// CHECK-DAG: define {{(dso_local)?}} i32 @baz({{.*}} !type [[F_TPRIMITIVE:![0-9]+]]
+// CHECK-LABEL: define {{(dso_local)?}} i32 @baz(
+// CHECK: {{.*}} !type [[F_TPRIMITIVE:![0-9]+]]
int baz(char a, float b, double c) {
return 1;
}
-// CHECK-DAG: define {{(dso_local)?}} ptr @qux({{.*}} !type [[F_TPTR:![0-9]+]]
+// CHECK-LABEL: define {{(dso_local)?}} ptr @qux(
+// CHECK: {{.*}} !type [[F_TPTR:![0-9]+]]
int *qux(char *a, float *b, double *c) {
return 0;
}
-// CHECK-DAG: define {{(dso_local)?}} void @corge({{.*}} !type [[F_TVOID]]
+// CHECK-LABEL: define {{(dso_local)?}} void @corge(
+// CHECK: {{.*}} !type [[F_TVOID]]
void corge() {
int (*fp_baz)(char, float, double) = baz;
// CHECK: call i32 {{.*}}, !callee_type [[F_TPRIMITIVE_CT:![0-9]+]]
@@ -46,10 +51,12 @@ struct st2 {
struct st1 m;
};
-// CHECK-DAG: define {{(dso_local)?}} void @stparam({{.*}} !type [[F_TSTRUCT:![0-9]+]]
+// CHECK-LABEL: define {{(dso_local)?}} void @stparam(
+// CHECK: {{.*}} !type [[F_TSTRUCT:![0-9]+]]
void stparam(struct st2 a, struct st2 *b) {}
-// CHECK-DAG: define {{(dso_local)?}} void @stf({{.*}} !type [[F_TVOID]]
+// CHECK-LABEL: define {{(dso_local)?}} void @stf(
+// CHECK: {{.*}} !type [[F_TVOID]]
void stf() {
struct st1 St1;
St1.fp = qux;
>From e348ff86be52be19f4d0ef67de732f22303906b3 Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Mon, 13 Oct 2025 16:54:08 -0700
Subject: [PATCH 08/10] Use LABEL instead of DAG in tests.
---
clang/test/CodeGen/call-graph-section-callback.cpp | 3 ++-
clang/test/CodeGen/call-graph-section-virtual-methods.cpp | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/clang/test/CodeGen/call-graph-section-callback.cpp b/clang/test/CodeGen/call-graph-section-callback.cpp
index 0404f888d0b1f..8d1442d5a8ecd 100644
--- a/clang/test/CodeGen/call-graph-section-callback.cpp
+++ b/clang/test/CodeGen/call-graph-section-callback.cpp
@@ -9,7 +9,8 @@
typedef void (*CallbackFn)(int);
// Callback function with "internal" linkage.
-// CHECK-DAG: define internal void @_ZL10myCallbacki({{.*}} !type [[F_CALLBACK:![0-9]+]]
+// CHECK-LABEL: define internal void @_ZL10myCallbacki(
+// CHECK: {{.*}} !type [[F_CALLBACK:![0-9]+]]
static void myCallback(int value)
{
volatile int sink = value;
diff --git a/clang/test/CodeGen/call-graph-section-virtual-methods.cpp b/clang/test/CodeGen/call-graph-section-virtual-methods.cpp
index d95e54053f766..e06d526c12d72 100644
--- a/clang/test/CodeGen/call-graph-section-virtual-methods.cpp
+++ b/clang/test/CodeGen/call-graph-section-virtual-methods.cpp
@@ -11,7 +11,8 @@
class Base {
public:
- // FT-DAG: define {{.*}} @_ZN4Base2vfEPc({{.*}} !type [[F_TVF:![0-9]+]]
+ // FT-LABEL: define {{.*}} @_ZN4Base2vfEPc(
+ // FT: {{.*}} !type [[F_TVF:![0-9]+]]
virtual int vf(char *a) { return 0; };
};
>From ca97344b00afa0e2811297c666ac647810fb5bc5 Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Tue, 14 Oct 2025 10:11:01 -0700
Subject: [PATCH 09/10] Remove expensive DAG based checks from tests.
---
.../CodeGen/call-graph-section-callback.cpp | 2 +-
.../CodeGen/call-graph-section-templates.cpp | 68 ++++++-------
.../call-graph-section-virtual-methods.cpp | 8 +-
clang/test/CodeGen/call-graph-section.c | 96 ++++++++++++-------
clang/test/CodeGen/call-graph-section.cpp | 85 ++++++++--------
5 files changed, 146 insertions(+), 113 deletions(-)
diff --git a/clang/test/CodeGen/call-graph-section-callback.cpp b/clang/test/CodeGen/call-graph-section-callback.cpp
index 8d1442d5a8ecd..f12da23f33a6a 100644
--- a/clang/test/CodeGen/call-graph-section-callback.cpp
+++ b/clang/test/CodeGen/call-graph-section-callback.cpp
@@ -27,4 +27,4 @@ int takeCallbackAddress() {
return 0;
}
-// CHECK-DAG: [[F_CALLBACK]] = !{i64 0, !"_ZTSFviE.generalized"}
+// CHECK: [[F_CALLBACK]] = !{i64 0, !"_ZTSFviE.generalized"}
diff --git a/clang/test/CodeGen/call-graph-section-templates.cpp b/clang/test/CodeGen/call-graph-section-templates.cpp
index 6621eff37daa8..eb342c6c3e6cf 100644
--- a/clang/test/CodeGen/call-graph-section-templates.cpp
+++ b/clang/test/CodeGen/call-graph-section-templates.cpp
@@ -16,34 +16,40 @@ class Cls1 {};
template <class T>
class Cls2 {
public:
- // FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f1Ev({{.*}} !type [[F_TCLS2F1:![0-9]+]]
+ // FT-LABEL: define {{.*}} void @_ZN4Cls2I4Cls1E2f1Ev(
+ // FT: {{.*}} !type [[F_TCLS2F1:![0-9]+]]
void f1() {}
- // FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f2ES0_({{.*}} !type [[F_TCLS2F2:![0-9]+]]
+ // FT-LABEL: define {{.*}} void @_ZN4Cls2I4Cls1E2f2ES0_(
+ // FT: {{.*}} !type [[F_TCLS2F2:![0-9]+]]
void f2(T a) {}
- // FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f3EPS0_({{.*}} !type [[F_TCLS2F3:![0-9]+]]
+ // FT-LABEL: define {{.*}} void @_ZN4Cls2I4Cls1E2f3EPS0_(
+ // FT: {{.*}} !type [[F_TCLS2F3:![0-9]+]]
void f3(T *a) {}
- // FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f4EPKS0_({{.*}} !type [[F_TCLS2F4:![0-9]+]]
+ // FT-LABEL: define {{.*}} void @_ZN4Cls2I4Cls1E2f4EPKS0_(
+ // FT: {{.*}} !type [[F_TCLS2F4:![0-9]+]]
void f4(const T *a) {}
- // FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f5ERS0_({{.*}} !type [[F_TCLS2F5:![0-9]+]]
+ // FT-LABEL: define {{.*}} void @_ZN4Cls2I4Cls1E2f5ERS0_(
+ // FT: {{.*}} !type [[F_TCLS2F5:![0-9]+]]
void f5(T &a) {}
- // FT: define {{.*}} void @_ZN4Cls2I4Cls1E2f6ERKS0_({{.*}} !type [[F_TCLS2F6:![0-9]+]]
+ // FT-LABEL: define {{.*}} void @_ZN4Cls2I4Cls1E2f6ERKS0_(
+ // FT: {{.*}} !type [[F_TCLS2F6:![0-9]+]]
void f6(const T &a) {}
// Mixed type function pointer member
T *(*fp)(T a, T *b, const T *c, T &d, const T &e);
};
-// FT-DAG: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFvvE.generalized"}
-// FT-DAG: [[F_TCLS2F2]] = !{i64 0, !"_ZTSFv4Cls1E.generalized"}
-// FT-DAG: [[F_TCLS2F3]] = !{i64 0, !"_ZTSFvP4Cls1E.generalized"}
-// FT-DAG: [[F_TCLS2F4]] = !{i64 0, !"_ZTSFvPK4Cls1E.generalized"}
-// FT-DAG: [[F_TCLS2F5]] = !{i64 0, !"_ZTSFvR4Cls1E.generalized"}
-// FT-DAG: [[F_TCLS2F6]] = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"}
+// FT: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFvvE.generalized"}
+// FT: [[F_TCLS2F2]] = !{i64 0, !"_ZTSFv4Cls1E.generalized"}
+// FT: [[F_TCLS2F3]] = !{i64 0, !"_ZTSFvP4Cls1E.generalized"}
+// FT: [[F_TCLS2F4]] = !{i64 0, !"_ZTSFvPK4Cls1E.generalized"}
+// FT: [[F_TCLS2F5]] = !{i64 0, !"_ZTSFvR4Cls1E.generalized"}
+// FT: [[F_TCLS2F6]] = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"}
////////////////////////////////////////////////////////////////////////////////
// Callsites (check for indirect callsite operand bundles)
@@ -91,24 +97,20 @@ void foo() {
(Obj2Ptr->*fp_f6)(Cls1Obj);
}
-// CST: define {{.*}} @_Z6T_funcI4Cls1EPT_S1_S2_PKS1_RS1_RS3_({{.*}} !type [[F_TFUNC_CLS1:![0-9]+]]
-// CST-DAG: [[F_TFUNC_CLS1_CT]] = !{[[F_TFUNC_CLS1:![0-9]+]]}
-// CST-DAG: [[F_TFUNC_CLS1]] = !{i64 0, !"_ZTSFP4Cls1S_S0_PKS_RS_RS1_E.generalized"}
-
-// CST-DAG: [[F_TCLS2F1_CT]] = !{[[F_TCLS2F1:![0-9]+]]}
-// CST-DAG: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFvvE.generalized"}
-
-// CST-DAG: [[F_TCLS2F2_CT]] = !{[[F_TCLS2F2:![0-9]+]]}
-// CST-DAG: [[F_TCLS2F2]] = !{i64 0, !"_ZTSFv4Cls1E.generalized"}
-
-// CST-DAG: [[F_TCLS2F3_CT]] = !{[[F_TCLS2F3:![0-9]+]]}
-// CST-DAG: [[F_TCLS2F3]] = !{i64 0, !"_ZTSFvP4Cls1E.generalized"}
-
-// CST-DAG: [[F_TCLS2F4_CT]] = !{[[F_TCLS2F4:![0-9]+]]}
-// CST-DAG: [[F_TCLS2F4]] = !{i64 0, !"_ZTSFvPK4Cls1E.generalized"}
-
-// CST-DAG: [[F_TCLS2F5_CT]] = !{[[F_TCLS2F5:![0-9]+]]}
-// CST-DAG: [[F_TCLS2F5]] = !{i64 0, !"_ZTSFvR4Cls1E.generalized"}
-
-// CST-DAG: [[F_TCLS2F6_CT]] = !{[[F_TCLS2F6:![0-9]+]]}
-// CST-DAG: [[F_TCLS2F6]] = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"}
+// CST-LABEL: define {{.*}} @_Z6T_funcI4Cls1EPT_S1_S2_PKS1_RS1_RS3_(
+// CST: {{.*}} !type [[F_TFUNC_CLS1:![0-9]+]]
+
+// CST: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFvvE.generalized"}
+// CST: [[F_TFUNC_CLS1_CT]] = !{[[F_TFUNC_CLS1:![0-9]+]]}
+// CST: [[F_TFUNC_CLS1]] = !{i64 0, !"_ZTSFP4Cls1S_S0_PKS_RS_RS1_E.generalized"}
+// CST: [[F_TCLS2F1_CT]] = !{[[F_TCLS2F1:![0-9]+]]}
+// CST: [[F_TCLS2F2_CT]] = !{[[F_TCLS2F2:![0-9]+]]}
+// CST: [[F_TCLS2F2]] = !{i64 0, !"_ZTSFv4Cls1E.generalized"}
+// CST: [[F_TCLS2F3_CT]] = !{[[F_TCLS2F3:![0-9]+]]}
+// CST: [[F_TCLS2F3]] = !{i64 0, !"_ZTSFvP4Cls1E.generalized"}
+// CST: [[F_TCLS2F4_CT]] = !{[[F_TCLS2F4:![0-9]+]]}
+// CST: [[F_TCLS2F4]] = !{i64 0, !"_ZTSFvPK4Cls1E.generalized"}
+// CST: [[F_TCLS2F5_CT]] = !{[[F_TCLS2F5:![0-9]+]]}
+// CST: [[F_TCLS2F5]] = !{i64 0, !"_ZTSFvR4Cls1E.generalized"}
+// CST: [[F_TCLS2F6_CT]] = !{[[F_TCLS2F6:![0-9]+]]}
+// CST: [[F_TCLS2F6]] = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"}
diff --git a/clang/test/CodeGen/call-graph-section-virtual-methods.cpp b/clang/test/CodeGen/call-graph-section-virtual-methods.cpp
index e06d526c12d72..04ab2fb503422 100644
--- a/clang/test/CodeGen/call-graph-section-virtual-methods.cpp
+++ b/clang/test/CodeGen/call-graph-section-virtual-methods.cpp
@@ -18,11 +18,11 @@ class Base {
class Derived : public Base {
public:
- // FT-DAG: define {{.*}} @_ZN7Derived2vfEPc({{.*}} !type [[F_TVF]]
+ // FT: define {{.*}} @_ZN7Derived2vfEPc({{.*}} !type [[F_TVF]]
int vf(char *a) override { return 1; };
};
- // FT-DAG: [[F_TVF]] = !{i64 0, !"_ZTSFiPcE.generalized"}
+ // FT: [[F_TVF]] = !{i64 0, !"_ZTSFiPcE.generalized"}
////////////////////////////////////////////////////////////////////////////////
// Callsites (check for indirect callsite operand bundles)
@@ -52,5 +52,5 @@ class Base {
(Dptr->*FpDerivedVf)(0);
}
- // CST-DAG: [[F_TVF_CT]] = !{[[F_TVF:![0-9]+]]}
- // CST-DAG: [[F_TVF]] = !{i64 0, !"_ZTSFiPcE.generalized"}
+ // CST: [[F_TVF_CT]] = !{[[F_TVF:![0-9]+]]}
+ // CST: [[F_TVF]] = !{i64 0, !"_ZTSFiPcE.generalized"}
diff --git a/clang/test/CodeGen/call-graph-section.c b/clang/test/CodeGen/call-graph-section.c
index ae6b6ce311003..216d92a8bb80f 100644
--- a/clang/test/CodeGen/call-graph-section.c
+++ b/clang/test/CodeGen/call-graph-section.c
@@ -1,45 +1,58 @@
// Tests that we assign appropriate identifiers to indirect calls and targets.
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fexperimental-call-graph-section \
-// RUN: -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,ITANIUM %s
+// RUN: -emit-llvm -o - %s | FileCheck --check-prefixes=ITANIUM %s
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fexperimental-call-graph-section \
-// RUN: -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,MS %s
+// RUN: -emit-llvm -o - %s | FileCheck --check-prefixes=MS %s
-// CHECK-LABEL: define {{(dso_local)?}} void @foo(
-// CHECK: {{.*}} !type [[F_TVOID:![0-9]+]]
+// ITANIUM-LABEL: define {{(dso_local)?}} void @foo(
+// ITANIUM: {{.*}} !type [[F_TVOID:![0-9]+]]
+// MS-LABEL: define {{(dso_local)?}} void @foo(
+// MS: {{.*}} !type [[F_TVOID:![0-9]+]]
void foo() {
}
-// CHECK-LABEL: define {{(dso_local)?}} void @bar(
-// CHECK: {{.*}} !type [[F_TVOID]]
+// ITANIUM-LABEL: define {{(dso_local)?}} void @bar(
+// ITANIUM: {{.*}} !type [[F_TVOID]]
+// MS-LABEL: define {{(dso_local)?}} void @bar(
+// MS: {{.*}} !type [[F_TVOID]]
void bar() {
void (*fp)() = foo;
- // CHECK: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]]
+ // ITANIUM: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]]
+ // MS: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]]
fp();
}
-// CHECK-LABEL: define {{(dso_local)?}} i32 @baz(
-// CHECK: {{.*}} !type [[F_TPRIMITIVE:![0-9]+]]
+// ITANIUM-LABEL: define {{(dso_local)?}} i32 @baz(
+// ITANIUM: {{.*}} !type [[F_TPRIMITIVE:![0-9]+]]
+// MS-LABEL: define {{(dso_local)?}} i32 @baz(
+// MS: {{.*}} !type [[F_TPRIMITIVE:![0-9]+]]
int baz(char a, float b, double c) {
return 1;
}
-// CHECK-LABEL: define {{(dso_local)?}} ptr @qux(
-// CHECK: {{.*}} !type [[F_TPTR:![0-9]+]]
+// ITANIUM-LABEL: define {{(dso_local)?}} ptr @qux(
+// ITANIUM: {{.*}} !type [[F_TPTR:![0-9]+]]
+// MS-LABEL: define {{(dso_local)?}} ptr @qux(
+// MS: {{.*}} !type [[F_TPTR:![0-9]+]]
int *qux(char *a, float *b, double *c) {
return 0;
}
-// CHECK-LABEL: define {{(dso_local)?}} void @corge(
-// CHECK: {{.*}} !type [[F_TVOID]]
+// ITANIUM-LABEL: define {{(dso_local)?}} void @corge(
+// ITANIUM: {{.*}} !type [[F_TVOID]]
+// MS-LABEL: define {{(dso_local)?}} void @corge(
+// MS: {{.*}} !type [[F_TVOID]]
void corge() {
int (*fp_baz)(char, float, double) = baz;
- // CHECK: call i32 {{.*}}, !callee_type [[F_TPRIMITIVE_CT:![0-9]+]]
+ // ITANIUM: call i32 {{.*}}, !callee_type [[F_TPRIMITIVE_CT:![0-9]+]]
+ // MS: call i32 {{.*}}, !callee_type [[F_TPRIMITIVE_CT:![0-9]+]]
fp_baz('a', .0f, .0);
int *(*fp_qux)(char *, float *, double *) = qux;
- // CHECK: call ptr {{.*}}, !callee_type [[F_TPTR_CT:![0-9]+]]
+ // ITANIUM: call ptr {{.*}}, !callee_type [[F_TPTR_CT:![0-9]+]]
+ // MS: call ptr {{.*}}, !callee_type [[F_TPTR_CT:![0-9]+]]
fp_qux(0, 0, 0);
}
@@ -51,40 +64,49 @@ struct st2 {
struct st1 m;
};
-// CHECK-LABEL: define {{(dso_local)?}} void @stparam(
-// CHECK: {{.*}} !type [[F_TSTRUCT:![0-9]+]]
+// ITANIUM-LABEL: define {{(dso_local)?}} void @stparam(
+// ITANIUM: {{.*}} !type [[F_TSTRUCT:![0-9]+]]
+// MS-LABEL: define {{(dso_local)?}} void @stparam(
+// MS: {{.*}} !type [[F_TSTRUCT:![0-9]+]]
void stparam(struct st2 a, struct st2 *b) {}
-// CHECK-LABEL: define {{(dso_local)?}} void @stf(
-// CHECK: {{.*}} !type [[F_TVOID]]
+// ITANIUM-LABEL: define {{(dso_local)?}} void @stf(
+// ITANIUM: {{.*}} !type [[F_TVOID]]
+// MS-LABEL: define {{(dso_local)?}} void @stf(
+// MS: {{.*}} !type [[F_TVOID]]
void stf() {
struct st1 St1;
St1.fp = qux;
- // CHECK: call ptr {{.*}}, !callee_type [[F_TPTR_CT:![0-9]+]]
+ // ITANIUM: call ptr {{.*}}, !callee_type [[F_TPTR_CT:![0-9]+]]
+ // MS: call ptr {{.*}}, !callee_type [[F_TPTR_CT:![0-9]+]]
St1.fp(0, 0, 0);
struct st2 St2;
St2.m.fp = qux;
- // CHECK: call ptr {{.*}}, !callee_type [[F_TPTR_CT:![0-9]+]]
+ // ITANIUM: call ptr {{.*}}, !callee_type [[F_TPTR_CT:![0-9]+]]
+ // MS: call ptr {{.*}}, !callee_type [[F_TPTR_CT:![0-9]+]]
St2.m.fp(0, 0, 0);
- // CHECK: call void {{.*}}, !callee_type [[F_TSTRUCT_CT:![0-9]+]]
+ // ITANIUM: call void {{.*}}, !callee_type [[F_TSTRUCT_CT:![0-9]+]]
+ // MS: call void {{.*}}, !callee_type [[F_TSTRUCT_CT:![0-9]+]]
void (*fp_stparam)(struct st2, struct st2 *) = stparam;
fp_stparam(St2, &St2);
}
-// CHECK-DAG: [[F_TVOID_CT]] = !{[[F_TVOID:![0-9]+]]}
-// ITANIUM-DAG: [[F_TVOID]] = !{i64 0, !"_ZTSFvE.generalized"}
-// MS-DAG: [[F_TVOID]] = !{i64 0, !"?6AX at Z.generalized"}
-
-// CHECK-DAG: [[F_TPRIMITIVE_CT]] = !{[[F_TPRIMITIVE:![0-9]+]]}
-// ITANIUM-DAG: [[F_TPRIMITIVE]] = !{i64 0, !"_ZTSFicfdE.generalized"}
-// MS-DAG: [[F_TPRIMITIVE]] = !{i64 0, !"?6AHDMN at Z.generalized"}
-
-// CHECK-DAG: [[F_TPTR_CT]] = !{[[F_TPTR:![0-9]+]]}
-// ITANIUM-DAG: [[F_TPTR]] = !{i64 0, !"_ZTSFPiPcPfPdE.generalized"}
-// MS-DAG: [[F_TPTR]] = !{i64 0, !"?6APEAHPEADPEAMPEAN at Z.generalized"}
-
-// CHECK-DAG: [[F_TSTRUCT_CT]] = !{[[F_TSTRUCT:![0-9]+]]}
-// ITANIUM-DAG: [[F_TSTRUCT]] = !{i64 0, !"_ZTSFv3st2PS_E.generalized"}
-// MS-DAG: [[F_TSTRUCT]] = !{i64 0, !"?6AXUst2@@PEAU0@@Z.generalized"}
+// ITANIUM: [[F_TVOID]] = !{i64 0, !"_ZTSFvE.generalized"}
+// ITANIUM: [[F_TVOID_CT]] = !{[[F_TVOID:![0-9]+]]}
+// ITANIUM: [[F_TPRIMITIVE]] = !{i64 0, !"_ZTSFicfdE.generalized"}
+// ITANIUM: [[F_TPTR]] = !{i64 0, !"_ZTSFPiPcPfPdE.generalized"}
+// ITANIUM: [[F_TPRIMITIVE_CT]] = !{[[F_TPRIMITIVE:![0-9]+]]}
+// ITANIUM: [[F_TPTR_CT]] = !{[[F_TPTR:![0-9]+]]}
+// ITANIUM: [[F_TSTRUCT]] = !{i64 0, !"_ZTSFv3st2PS_E.generalized"}
+// ITANIUM: [[F_TSTRUCT_CT]] = !{[[F_TSTRUCT:![0-9]+]]}
+
+// MS: [[F_TVOID]] = !{i64 0, !"?6AX at Z.generalized"}
+// MS: [[F_TVOID_CT]] = !{[[F_TVOID:![0-9]+]]}
+// MS: [[F_TPRIMITIVE]] = !{i64 0, !"?6AHDMN at Z.generalized"}
+// MS: [[F_TPTR]] = !{i64 0, !"?6APEAHPEADPEAMPEAN at Z.generalized"}
+// MS: [[F_TPRIMITIVE_CT]] = !{[[F_TPRIMITIVE:![0-9]+]]}
+// MS: [[F_TPTR_CT]] = !{[[F_TPTR:![0-9]+]]}
+// MS: [[F_TSTRUCT]] = !{i64 0, !"?6AXUst2@@PEAU0@@Z.generalized"}
+// MS: [[F_TSTRUCT_CT]] = !{[[F_TSTRUCT:![0-9]+]]}
diff --git a/clang/test/CodeGen/call-graph-section.cpp b/clang/test/CodeGen/call-graph-section.cpp
index 85bb12535709f..df0840f1b105e 100644
--- a/clang/test/CodeGen/call-graph-section.cpp
+++ b/clang/test/CodeGen/call-graph-section.cpp
@@ -11,7 +11,8 @@
class Cls1 {
public:
- // FT-DAG: define {{.*}} ptr @_ZN4Cls18receiverEPcPf({{.*}} !type [[F_TCLS1RECEIVER:![0-9]+]]
+ // FT-LABEL: define {{.*}} ptr @_ZN4Cls18receiverEPcPf(
+ // FT: {{.*}} !type [[F_TCLS1RECEIVER:![0-9]+]]
static int *receiver(char *a, float *b) { return 0; }
};
@@ -19,43 +20,52 @@ class Cls2 {
public:
int *(*fp)(char *, float *);
- // FT-DAG: define {{.*}} i32 @_ZN4Cls22f1Ecfd({{.*}} !type [[F_TCLS2F1:![0-9]+]]
+ // FT-LABEL: define {{.*}} i32 @_ZN4Cls22f1Ecfd(
+ // FT: {{.*}} !type [[F_TCLS2F1:![0-9]+]]
int f1(char a, float b, double c) { return 0; }
- // FT-DAG: define {{.*}} ptr @_ZN4Cls22f2EPcPfPd({{.*}} !type [[F_TCLS2F2:![0-9]+]]
+ // FT-LABEL: define {{.*}} ptr @_ZN4Cls22f2EPcPfPd(
+ // FT: {{.*}} !type [[F_TCLS2F2:![0-9]+]]
int *f2(char *a, float *b, double *c) { return 0; }
- // FT-DAG: define {{.*}} void @_ZN4Cls22f3E4Cls1({{.*}} !type [[F_TCLS2F3F4:![0-9]+]]
+ // FT-LABEL: define {{.*}} void @_ZN4Cls22f3E4Cls1(
+ // FT: {{.*}} !type [[F_TCLS2F3F4:![0-9]+]]
void f3(Cls1 a) {}
- // FT-DAG: define {{.*}} void @_ZN4Cls22f4E4Cls1({{.*}} !type [[F_TCLS2F3F4]]
+ // FT-LABEL: define {{.*}} void @_ZN4Cls22f4E4Cls1(
+ // FT: {{.*}} !type [[F_TCLS2F3F4]]
void f4(const Cls1 a) {}
- // FT-DAG: define {{.*}} void @_ZN4Cls22f5EP4Cls1({{.*}} !type [[F_TCLS2F5:![0-9]+]]
+ // FT-LABEL: define {{.*}} void @_ZN4Cls22f5EP4Cls1(
+ // FT: {{.*}} !type [[F_TCLS2F5:![0-9]+]]
void f5(Cls1 *a) {}
- // FT-DAG: define {{.*}} void @_ZN4Cls22f6EPK4Cls1({{.*}} !type [[F_TCLS2F6:![0-9]+]]
+ // FT-LABEL: define {{.*}} void @_ZN4Cls22f6EPK4Cls1(
+ // FT: {{.*}} !type [[F_TCLS2F6:![0-9]+]]
void f6(const Cls1 *a) {}
- // FT-DAG: define {{.*}} void @_ZN4Cls22f7ER4Cls1({{.*}} !type [[F_TCLS2F7:![0-9]+]]
+ // FT-LABEL: define {{.*}} void @_ZN4Cls22f7ER4Cls1(
+ // FT: {{.*}} !type [[F_TCLS2F7:![0-9]+]]
void f7(Cls1 &a) {}
- // FT-DAG: define {{.*}} void @_ZN4Cls22f8ERK4Cls1({{.*}} !type [[F_TCLS2F8:![0-9]+]]
+ // FT-LABEL: define {{.*}} void @_ZN4Cls22f8ERK4Cls1(
+ // FT: {{.*}} !type [[F_TCLS2F8:![0-9]+]]
void f8(const Cls1 &a) {}
- // FT-DAG: define {{.*}} void @_ZNK4Cls22f9Ev({{.*}} !type [[F_TCLS2F9:![0-9]+]]
+ // FT-LABEL: define {{.*}} void @_ZNK4Cls22f9Ev(
+ // FT: {{.*}} !type [[F_TCLS2F9:![0-9]+]]
void f9() const {}
};
-// FT-DAG: [[F_TCLS1RECEIVER]] = !{i64 0, !"_ZTSFPiPcPfE.generalized"}
-// FT-DAG: [[F_TCLS2F2]] = !{i64 0, !"_ZTSFPiPcPfPdE.generalized"}
-// FT-DAG: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFicfdE.generalized"}
-// FT-DAG: [[F_TCLS2F3F4]] = !{i64 0, !"_ZTSFv4Cls1E.generalized"}
-// FT-DAG: [[F_TCLS2F5]] = !{i64 0, !"_ZTSFvP4Cls1E.generalized"}
-// FT-DAG: [[F_TCLS2F6]] = !{i64 0, !"_ZTSFvPK4Cls1E.generalized"}
-// FT-DAG: [[F_TCLS2F7]] = !{i64 0, !"_ZTSFvR4Cls1E.generalized"}
-// FT-DAG: [[F_TCLS2F8]] = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"}
-// FT-DAG: [[F_TCLS2F9]] = !{i64 0, !"_ZTSKFvvE.generalized"}
+// FT: [[F_TCLS1RECEIVER]] = !{i64 0, !"_ZTSFPiPcPfE.generalized"}
+// FT: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFicfdE.generalized"}
+// FT: [[F_TCLS2F2]] = !{i64 0, !"_ZTSFPiPcPfPdE.generalized"}
+// FT: [[F_TCLS2F3F4]] = !{i64 0, !"_ZTSFv4Cls1E.generalized"}
+// FT: [[F_TCLS2F5]] = !{i64 0, !"_ZTSFvP4Cls1E.generalized"}
+// FT: [[F_TCLS2F6]] = !{i64 0, !"_ZTSFvPK4Cls1E.generalized"}
+// FT: [[F_TCLS2F7]] = !{i64 0, !"_ZTSFvR4Cls1E.generalized"}
+// FT: [[F_TCLS2F8]] = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"}
+// FT: [[F_TCLS2F9]] = !{i64 0, !"_ZTSKFvvE.generalized"}
////////////////////////////////////////////////////////////////////////////////
// Callsites (check for indirect callsites' callee_type metadata )
@@ -109,30 +119,29 @@ void foo() {
(ObjCls2Ptr->*fp_f9)();
}
+// CST: [[F_TCLS1RECEIVER_CT]] = !{[[F_TCLS1RECEIVER:![0-9]+]]}
+// CST: [[F_TCLS1RECEIVER]] = !{i64 0, !"_ZTSFPiPcPfE.generalized"}
-// CST-DAG: [[F_TCLS1RECEIVER_CT]] = !{[[F_TCLS1RECEIVER:![0-9]+]]}
-// CST-DAG: [[F_TCLS1RECEIVER]] = !{i64 0, !"_ZTSFPiPcPfE.generalized"}
+// CST: [[F_TCLS2F1_CT]] = !{[[F_TCLS2F1:![0-9]+]]}
+// CST: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFicfdE.generalized"}
-// CST-DAG: [[F_TCLS2F2_CT]] = !{[[F_TCLS2F2:![0-9]+]]}
-// CST-DAG: [[F_TCLS2F2]] = !{i64 0, !"_ZTSFPiPcPfPdE.generalized"}
+// CST: [[F_TCLS2F2_CT]] = !{[[F_TCLS2F2:![0-9]+]]}
+// CST: [[F_TCLS2F2]] = !{i64 0, !"_ZTSFPiPcPfPdE.generalized"}
-// CST-DAG: [[F_TCLS2F1_CT]] = !{[[F_TCLS2F1:![0-9]+]]}
-// CST-DAG: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFicfdE.generalized"}
+// CST: [[F_TCLS2F3F4_CT]] = !{[[F_TCLS2F3F4:![0-9]+]]}
+// CST: [[F_TCLS2F3F4]] = !{i64 0, !"_ZTSFv4Cls1E.generalized"}
-// CST-DAG: [[F_TCLS2F3F4_CT]] = !{[[F_TCLS2F3F4:![0-9]+]]}
-// CST-DAG: [[F_TCLS2F3F4]] = !{i64 0, !"_ZTSFv4Cls1E.generalized"}
+// CST: [[F_TCLS2F5_CT]] = !{[[F_TCLS2F5:![0-9]+]]}
+// CST: [[F_TCLS2F5]] = !{i64 0, !"_ZTSFvP4Cls1E.generalized"}
-// CST-DAG: [[F_TCLS2F5_CT]] = !{[[F_TCLS2F5:![0-9]+]]}
-// CST-DAG: [[F_TCLS2F5]] = !{i64 0, !"_ZTSFvP4Cls1E.generalized"}
+// CST: [[F_TCLS2F6_CT]] = !{[[F_TCLS2F6:![0-9]+]]}
+// CST: [[F_TCLS2F6]] = !{i64 0, !"_ZTSFvPK4Cls1E.generalized"}
-// CST-DAG: [[F_TCLS2F6_CT]] = !{[[F_TCLS2F6:![0-9]+]]}
-// CST-DAG: [[F_TCLS2F6]] = !{i64 0, !"_ZTSFvPK4Cls1E.generalized"}
+// CST: [[F_TCLS2F7_CT]] = !{[[F_TCLS2F7:![0-9]+]]}
+// CST: [[F_TCLS2F7]] = !{i64 0, !"_ZTSFvR4Cls1E.generalized"}
-// CST-DAG: [[F_TCLS2F7_CT]] = !{[[F_TCLS2F7:![0-9]+]]}
-// CST-DAG: [[F_TCLS2F7]] = !{i64 0, !"_ZTSFvR4Cls1E.generalized"}
+// CST: [[F_TCLS2F8_CT]] = !{[[F_TCLS2F8:![0-9]+]]}
+// CST: [[F_TCLS2F8]] = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"}
-// CST-DAG: [[F_TCLS2F8_CT]] = !{[[F_TCLS2F8:![0-9]+]]}
-// CST-DAG: [[F_TCLS2F8]] = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"}
-
-// CST-DAG: [[F_TCLS2F9_CT]] = !{[[F_TCLS2F9:![0-9]+]]}
-// CST-DAG: [[F_TCLS2F9]] = !{i64 0, !"_ZTSKFvvE.generalized"}
+// CST: [[F_TCLS2F9_CT]] = !{[[F_TCLS2F9:![0-9]+]]}
+// CST: [[F_TCLS2F9]] = !{i64 0, !"_ZTSKFvvE.generalized"}
>From 36cd62f84b0c4dedc5f1d684a03fb91d2a708d7f Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Tue, 14 Oct 2025 10:36:00 -0700
Subject: [PATCH 10/10] Use -SAME to define variables after -LABEL checks.
---
.../CodeGen/call-graph-section-callback.cpp | 2 +-
.../CodeGen/call-graph-section-templates.cpp | 15 ++--
.../call-graph-section-virtual-methods.cpp | 2 +-
clang/test/CodeGen/call-graph-section.c | 71 +++++++------------
clang/test/CodeGen/call-graph-section.cpp | 18 ++---
5 files changed, 45 insertions(+), 63 deletions(-)
diff --git a/clang/test/CodeGen/call-graph-section-callback.cpp b/clang/test/CodeGen/call-graph-section-callback.cpp
index f12da23f33a6a..e9b0a1818e3a4 100644
--- a/clang/test/CodeGen/call-graph-section-callback.cpp
+++ b/clang/test/CodeGen/call-graph-section-callback.cpp
@@ -10,7 +10,7 @@ typedef void (*CallbackFn)(int);
// Callback function with "internal" linkage.
// CHECK-LABEL: define internal void @_ZL10myCallbacki(
-// CHECK: {{.*}} !type [[F_CALLBACK:![0-9]+]]
+// CHECK-SAME: {{.*}} !type [[F_CALLBACK:![0-9]+]]
static void myCallback(int value)
{
volatile int sink = value;
diff --git a/clang/test/CodeGen/call-graph-section-templates.cpp b/clang/test/CodeGen/call-graph-section-templates.cpp
index eb342c6c3e6cf..39030d27a4ea9 100644
--- a/clang/test/CodeGen/call-graph-section-templates.cpp
+++ b/clang/test/CodeGen/call-graph-section-templates.cpp
@@ -17,27 +17,27 @@ template <class T>
class Cls2 {
public:
// FT-LABEL: define {{.*}} void @_ZN4Cls2I4Cls1E2f1Ev(
- // FT: {{.*}} !type [[F_TCLS2F1:![0-9]+]]
+ // FT-SAME: {{.*}} !type [[F_TCLS2F1:![0-9]+]]
void f1() {}
// FT-LABEL: define {{.*}} void @_ZN4Cls2I4Cls1E2f2ES0_(
- // FT: {{.*}} !type [[F_TCLS2F2:![0-9]+]]
+ // FT-SAME: {{.*}} !type [[F_TCLS2F2:![0-9]+]]
void f2(T a) {}
// FT-LABEL: define {{.*}} void @_ZN4Cls2I4Cls1E2f3EPS0_(
- // FT: {{.*}} !type [[F_TCLS2F3:![0-9]+]]
+ // FT-SAME: {{.*}} !type [[F_TCLS2F3:![0-9]+]]
void f3(T *a) {}
// FT-LABEL: define {{.*}} void @_ZN4Cls2I4Cls1E2f4EPKS0_(
- // FT: {{.*}} !type [[F_TCLS2F4:![0-9]+]]
+ // FT-SAME: {{.*}} !type [[F_TCLS2F4:![0-9]+]]
void f4(const T *a) {}
// FT-LABEL: define {{.*}} void @_ZN4Cls2I4Cls1E2f5ERS0_(
- // FT: {{.*}} !type [[F_TCLS2F5:![0-9]+]]
+ // FT-SAME: {{.*}} !type [[F_TCLS2F5:![0-9]+]]
void f5(T &a) {}
// FT-LABEL: define {{.*}} void @_ZN4Cls2I4Cls1E2f6ERKS0_(
- // FT: {{.*}} !type [[F_TCLS2F6:![0-9]+]]
+ // FT-SAME: {{.*}} !type [[F_TCLS2F6:![0-9]+]]
void f6(const T &a) {}
// Mixed type function pointer member
@@ -58,6 +58,7 @@ template <class T>
T *T_func(T a, T *b, const T *c, T &d, const T &e) { return b; }
// CST-LABEL: define {{.*}} @_Z3foov
+// CST-SAME: {{.*}} !type [[F_TCLS2F1:![0-9]+]]
void foo() {
// Methods for Cls2<Cls1> is checked above within the template description.
Cls2<Cls1> Obj;
@@ -98,7 +99,7 @@ void foo() {
}
// CST-LABEL: define {{.*}} @_Z6T_funcI4Cls1EPT_S1_S2_PKS1_RS1_RS3_(
-// CST: {{.*}} !type [[F_TFUNC_CLS1:![0-9]+]]
+// CST-SAME: {{.*}} !type [[F_TFUNC_CLS1:![0-9]+]]
// CST: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFvvE.generalized"}
// CST: [[F_TFUNC_CLS1_CT]] = !{[[F_TFUNC_CLS1:![0-9]+]]}
diff --git a/clang/test/CodeGen/call-graph-section-virtual-methods.cpp b/clang/test/CodeGen/call-graph-section-virtual-methods.cpp
index 04ab2fb503422..afeeae146ec41 100644
--- a/clang/test/CodeGen/call-graph-section-virtual-methods.cpp
+++ b/clang/test/CodeGen/call-graph-section-virtual-methods.cpp
@@ -12,7 +12,7 @@
class Base {
public:
// FT-LABEL: define {{.*}} @_ZN4Base2vfEPc(
- // FT: {{.*}} !type [[F_TVF:![0-9]+]]
+ // FT-SAME: {{.*}} !type [[F_TVF:![0-9]+]]
virtual int vf(char *a) { return 0; };
};
diff --git a/clang/test/CodeGen/call-graph-section.c b/clang/test/CodeGen/call-graph-section.c
index 216d92a8bb80f..69cdd59549190 100644
--- a/clang/test/CodeGen/call-graph-section.c
+++ b/clang/test/CodeGen/call-graph-section.c
@@ -1,22 +1,18 @@
// Tests that we assign appropriate identifiers to indirect calls and targets.
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fexperimental-call-graph-section \
-// RUN: -emit-llvm -o - %s | FileCheck --check-prefixes=ITANIUM %s
+// RUN: -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,ITANIUM %s
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fexperimental-call-graph-section \
-// RUN: -emit-llvm -o - %s | FileCheck --check-prefixes=MS %s
+// RUN: -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,MS %s
-// ITANIUM-LABEL: define {{(dso_local)?}} void @foo(
-// ITANIUM: {{.*}} !type [[F_TVOID:![0-9]+]]
-// MS-LABEL: define {{(dso_local)?}} void @foo(
-// MS: {{.*}} !type [[F_TVOID:![0-9]+]]
+// CHECK-LABEL: define {{(dso_local)?}} void @foo(
+// CHECK-SAME: {{.*}} !type [[F_TVOID:![0-9]+]]
void foo() {
}
-// ITANIUM-LABEL: define {{(dso_local)?}} void @bar(
-// ITANIUM: {{.*}} !type [[F_TVOID]]
-// MS-LABEL: define {{(dso_local)?}} void @bar(
-// MS: {{.*}} !type [[F_TVOID]]
+// CHECK-LABEL: define {{(dso_local)?}} void @bar(
+// CHECK-SAME: {{.*}} !type [[F_TVOID]]
void bar() {
void (*fp)() = foo;
// ITANIUM: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]]
@@ -24,35 +20,27 @@ void bar() {
fp();
}
-// ITANIUM-LABEL: define {{(dso_local)?}} i32 @baz(
-// ITANIUM: {{.*}} !type [[F_TPRIMITIVE:![0-9]+]]
-// MS-LABEL: define {{(dso_local)?}} i32 @baz(
-// MS: {{.*}} !type [[F_TPRIMITIVE:![0-9]+]]
+// CHECK-LABEL: define {{(dso_local)?}} i32 @baz(
+// CHECK-SAME: {{.*}} !type [[F_TPRIMITIVE:![0-9]+]]
int baz(char a, float b, double c) {
return 1;
}
-// ITANIUM-LABEL: define {{(dso_local)?}} ptr @qux(
-// ITANIUM: {{.*}} !type [[F_TPTR:![0-9]+]]
-// MS-LABEL: define {{(dso_local)?}} ptr @qux(
-// MS: {{.*}} !type [[F_TPTR:![0-9]+]]
+// CHECK-LABEL: define {{(dso_local)?}} ptr @qux(
+// CHECK-SAME: {{.*}} !type [[F_TPTR:![0-9]+]]
int *qux(char *a, float *b, double *c) {
return 0;
}
-// ITANIUM-LABEL: define {{(dso_local)?}} void @corge(
-// ITANIUM: {{.*}} !type [[F_TVOID]]
-// MS-LABEL: define {{(dso_local)?}} void @corge(
-// MS: {{.*}} !type [[F_TVOID]]
+// CHECK-LABEL: define {{(dso_local)?}} void @corge(
+// CHECK-SAME: {{.*}} !type [[F_TVOID]]
void corge() {
- int (*fp_baz)(char, float, double) = baz;
- // ITANIUM: call i32 {{.*}}, !callee_type [[F_TPRIMITIVE_CT:![0-9]+]]
- // MS: call i32 {{.*}}, !callee_type [[F_TPRIMITIVE_CT:![0-9]+]]
+ int (*fp_baz)(char, float, double) = baz;
+ // CHECK: call i32 {{.*}}, !callee_type [[F_TPRIMITIVE_CT:![0-9]+]]
fp_baz('a', .0f, .0);
- int *(*fp_qux)(char *, float *, double *) = qux;
- // ITANIUM: call ptr {{.*}}, !callee_type [[F_TPTR_CT:![0-9]+]]
- // MS: call ptr {{.*}}, !callee_type [[F_TPTR_CT:![0-9]+]]
+ int *(*fp_qux)(char *, float *, double *) = qux;
+ // CHECK: call ptr {{.*}}, !callee_type [[F_TPTR_CT:![0-9]+]]
fp_qux(0, 0, 0);
}
@@ -64,31 +52,24 @@ struct st2 {
struct st1 m;
};
-// ITANIUM-LABEL: define {{(dso_local)?}} void @stparam(
-// ITANIUM: {{.*}} !type [[F_TSTRUCT:![0-9]+]]
-// MS-LABEL: define {{(dso_local)?}} void @stparam(
-// MS: {{.*}} !type [[F_TSTRUCT:![0-9]+]]
+// CHECK-LABEL: define {{(dso_local)?}} void @stparam(
+// CHECK-SAME: {{.*}} !type [[F_TSTRUCT:![0-9]+]]
void stparam(struct st2 a, struct st2 *b) {}
-// ITANIUM-LABEL: define {{(dso_local)?}} void @stf(
-// ITANIUM: {{.*}} !type [[F_TVOID]]
-// MS-LABEL: define {{(dso_local)?}} void @stf(
-// MS: {{.*}} !type [[F_TVOID]]
+// CHECK-LABEL: define {{(dso_local)?}} void @stf(
+// CHECK-SAME: {{.*}} !type [[F_TVOID]]
void stf() {
struct st1 St1;
- St1.fp = qux;
- // ITANIUM: call ptr {{.*}}, !callee_type [[F_TPTR_CT:![0-9]+]]
- // MS: call ptr {{.*}}, !callee_type [[F_TPTR_CT:![0-9]+]]
+ St1.fp = qux;
+ // CHECK: call ptr {{.*}}, !callee_type [[F_TPTR_CT:![0-9]+]]
St1.fp(0, 0, 0);
struct st2 St2;
- St2.m.fp = qux;
- // ITANIUM: call ptr {{.*}}, !callee_type [[F_TPTR_CT:![0-9]+]]
- // MS: call ptr {{.*}}, !callee_type [[F_TPTR_CT:![0-9]+]]
+ St2.m.fp = qux;
+ // CHECK: call ptr {{.*}}, !callee_type [[F_TPTR_CT:![0-9]+]]
St2.m.fp(0, 0, 0);
-
- // ITANIUM: call void {{.*}}, !callee_type [[F_TSTRUCT_CT:![0-9]+]]
- // MS: call void {{.*}}, !callee_type [[F_TSTRUCT_CT:![0-9]+]]
+
+ // CHECK: call void {{.*}}, !callee_type [[F_TSTRUCT_CT:![0-9]+]]
void (*fp_stparam)(struct st2, struct st2 *) = stparam;
fp_stparam(St2, &St2);
}
diff --git a/clang/test/CodeGen/call-graph-section.cpp b/clang/test/CodeGen/call-graph-section.cpp
index df0840f1b105e..4077ab458b60c 100644
--- a/clang/test/CodeGen/call-graph-section.cpp
+++ b/clang/test/CodeGen/call-graph-section.cpp
@@ -21,39 +21,39 @@ class Cls2 {
int *(*fp)(char *, float *);
// FT-LABEL: define {{.*}} i32 @_ZN4Cls22f1Ecfd(
- // FT: {{.*}} !type [[F_TCLS2F1:![0-9]+]]
+ // FT-SAME: {{.*}} !type [[F_TCLS2F1:![0-9]+]]
int f1(char a, float b, double c) { return 0; }
// FT-LABEL: define {{.*}} ptr @_ZN4Cls22f2EPcPfPd(
- // FT: {{.*}} !type [[F_TCLS2F2:![0-9]+]]
+ // FT-SAME: {{.*}} !type [[F_TCLS2F2:![0-9]+]]
int *f2(char *a, float *b, double *c) { return 0; }
// FT-LABEL: define {{.*}} void @_ZN4Cls22f3E4Cls1(
- // FT: {{.*}} !type [[F_TCLS2F3F4:![0-9]+]]
+ // FT-SAME: {{.*}} !type [[F_TCLS2F3F4:![0-9]+]]
void f3(Cls1 a) {}
// FT-LABEL: define {{.*}} void @_ZN4Cls22f4E4Cls1(
- // FT: {{.*}} !type [[F_TCLS2F3F4]]
+ // FT-SAME: {{.*}} !type [[F_TCLS2F3F4]]
void f4(const Cls1 a) {}
// FT-LABEL: define {{.*}} void @_ZN4Cls22f5EP4Cls1(
- // FT: {{.*}} !type [[F_TCLS2F5:![0-9]+]]
+ // FT-SAME: {{.*}} !type [[F_TCLS2F5:![0-9]+]]
void f5(Cls1 *a) {}
// FT-LABEL: define {{.*}} void @_ZN4Cls22f6EPK4Cls1(
- // FT: {{.*}} !type [[F_TCLS2F6:![0-9]+]]
+ // FT-SAME: {{.*}} !type [[F_TCLS2F6:![0-9]+]]
void f6(const Cls1 *a) {}
// FT-LABEL: define {{.*}} void @_ZN4Cls22f7ER4Cls1(
- // FT: {{.*}} !type [[F_TCLS2F7:![0-9]+]]
+ // FT-SAME: {{.*}} !type [[F_TCLS2F7:![0-9]+]]
void f7(Cls1 &a) {}
// FT-LABEL: define {{.*}} void @_ZN4Cls22f8ERK4Cls1(
- // FT: {{.*}} !type [[F_TCLS2F8:![0-9]+]]
+ // FT-SAME: {{.*}} !type [[F_TCLS2F8:![0-9]+]]
void f8(const Cls1 &a) {}
// FT-LABEL: define {{.*}} void @_ZNK4Cls22f9Ev(
- // FT: {{.*}} !type [[F_TCLS2F9:![0-9]+]]
+ // FT-SAME: {{.*}} !type [[F_TCLS2F9:![0-9]+]]
void f9() const {}
};
More information about the cfe-commits
mailing list