https://github.com/Prabhuk updated 
https://github.com/llvm/llvm-project/pull/204266

>From d9350077f8146cf43ec702be2d386614e88c1966 Mon Sep 17 00:00:00 2001
From: prabhukr <[email protected]>
Date: Tue, 16 Jun 2026 16:15:50 -0700
Subject: [PATCH 01/13] Uncorrelate CFI and Callgraph related type metadata
 annotations

Note: This patch will be broken into separate smaller patches for clang
and llvm after discussion.

When -fexperimental-call-graph-section flag is set, it adds type
metadata to all the functions whose addresses are taken and does not
have local linkage. When this flag is set along with CFI, the type
metadata is added to all the vtable functions including destructors.
This changes which functions are to be treated as CFI functions and
includes such vtable entries to become part of the CFI check jumptables.

To disambiguate intentions of CFI and callgraph mechanisms, this patch
renames metadata set by callgraph mechanism to !callgraph
(MD_callgraph). This prevents inflating the list of CFI functions when
callgraph section is enabled along with CFI.
---
 clang/lib/CodeGen/CodeGenModule.cpp           | 14 +++++++------
 .../CodeGen/call-graph-section-callback.cpp   |  2 +-
 .../CodeGen/call-graph-section-templates.cpp  | 16 +++++++--------
 .../call-graph-section-virtual-methods.cpp    |  4 ++--
 clang/test/CodeGen/call-graph-section.c       | 14 ++++++-------
 clang/test/CodeGen/call-graph-section.cpp     | 20 +++++++++----------
 llvm/include/llvm/IR/FixedMetadataKinds.def   |  2 ++
 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp    |  2 +-
 llvm/lib/IR/Metadata.cpp                      |  6 +++---
 .../Transforms/IPO/ThinLTOBitcodeWriter.cpp   | 15 ++++++++++++++
 .../ARM/call-graph-section-addrtaken.ll       |  6 +++---
 .../ARM/call-graph-section-tailcall.ll        |  8 ++++----
 .../X86/call-graph-section-addrtaken.ll       |  6 +++---
 .../X86/call-graph-section-tailcall.ll        |  8 ++++----
 14 files changed, 71 insertions(+), 52 deletions(-)

diff --git a/clang/lib/CodeGen/CodeGenModule.cpp 
b/clang/lib/CodeGen/CodeGenModule.cpp
index 41049d85121be..25675f99258b4 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -3395,17 +3395,19 @@ static bool hasExistingGeneralizedTypeMD(llvm::Function 
*F) {
 
 void CodeGenModule::createIndirectFunctionTypeMD(const FunctionDecl *FD,
                                                  llvm::Function *F) {
-  // 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() ||
       F->getFunction().hasAddressTaken(nullptr, /*IgnoreCallbackUses=*/true,
                                        /*IgnoreAssumeLikeCalls=*/true,
-                                       /*IgnoreLLVMUsed=*/false))
-    F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FD->getType()));
+                                       /*IgnoreLLVMUsed=*/false)) {
+    F->addMetadata(llvm::LLVMContext::MD_callgraph,
+                   *llvm::MDTuple::get(
+                       getLLVMContext(),
+                       {llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
+                            llvm::Type::getInt64Ty(getLLVMContext()), 0)),
+                        CreateMetadataIdentifierGeneralized(FD->getType())}));
+  }
 }
 
 void CodeGenModule::createFunctionTypeMetadataForIcall(const FunctionDecl *FD,
diff --git a/clang/test/CodeGen/call-graph-section-callback.cpp 
b/clang/test/CodeGen/call-graph-section-callback.cpp
index e9b0a1818e3a4..080fa07e41847 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-SAME: {{.*}} !type [[F_CALLBACK:![0-9]+]]
+// CHECK-SAME: {{.*}} !callgraph [[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 39030d27a4ea9..e6c43a41a86ab 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-SAME: {{.*}} !type [[F_TCLS2F1:![0-9]+]]
+  // FT-SAME: {{.*}} !callgraph [[F_TCLS2F1:![0-9]+]]
   void f1() {}
 
   // FT-LABEL: define {{.*}} void @_ZN4Cls2I4Cls1E2f2ES0_(
-  // FT-SAME: {{.*}} !type [[F_TCLS2F2:![0-9]+]]
+  // FT-SAME: {{.*}} !callgraph [[F_TCLS2F2:![0-9]+]]
   void f2(T a) {}
 
   // FT-LABEL: define {{.*}} void @_ZN4Cls2I4Cls1E2f3EPS0_(
-  // FT-SAME: {{.*}} !type [[F_TCLS2F3:![0-9]+]]
+  // FT-SAME: {{.*}} !callgraph [[F_TCLS2F3:![0-9]+]]
   void f3(T *a) {}
 
   // FT-LABEL: define {{.*}} void @_ZN4Cls2I4Cls1E2f4EPKS0_(
-  // FT-SAME: {{.*}} !type [[F_TCLS2F4:![0-9]+]]
+  // FT-SAME: {{.*}} !callgraph [[F_TCLS2F4:![0-9]+]]
   void f4(const T *a) {}
 
   // FT-LABEL: define {{.*}} void @_ZN4Cls2I4Cls1E2f5ERS0_(
-  // FT-SAME: {{.*}} !type [[F_TCLS2F5:![0-9]+]]
+  // FT-SAME: {{.*}} !callgraph [[F_TCLS2F5:![0-9]+]]
   void f5(T &a) {}
 
   // FT-LABEL: define {{.*}} void @_ZN4Cls2I4Cls1E2f6ERKS0_(
-  // FT-SAME: {{.*}} !type [[F_TCLS2F6:![0-9]+]]
+  // FT-SAME: {{.*}} !callgraph [[F_TCLS2F6:![0-9]+]]
   void f6(const T &a) {}
 
   // Mixed type function pointer member
@@ -58,7 +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]+]]
+// CST-SAME: {{.*}} !callgraph [[F_TCLS2F1:![0-9]+]]
 void foo() {
   // Methods for Cls2<Cls1> is checked above within the template description.
   Cls2<Cls1> Obj;
@@ -99,7 +99,7 @@ void foo() {
 }
 
 // CST-LABEL: define {{.*}} @_Z6T_funcI4Cls1EPT_S1_S2_PKS1_RS1_RS3_(
-// CST-SAME: {{.*}} !type [[F_TFUNC_CLS1:![0-9]+]]
+// CST-SAME: {{.*}} !callgraph [[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 afeeae146ec41..7aa7a8cf740ea 100644
--- a/clang/test/CodeGen/call-graph-section-virtual-methods.cpp
+++ b/clang/test/CodeGen/call-graph-section-virtual-methods.cpp
@@ -12,13 +12,13 @@
 class Base {
   public:
     // FT-LABEL: define {{.*}} @_ZN4Base2vfEPc(
-    // FT-SAME: {{.*}} !type [[F_TVF:![0-9]+]]
+    // FT-SAME: {{.*}} !callgraph [[F_TVF:![0-9]+]]
     virtual int vf(char *a) { return 0; };
   };
   
   class Derived : public Base {
   public:
-    // FT: define {{.*}} @_ZN7Derived2vfEPc({{.*}} !type [[F_TVF]]
+    // FT: define {{.*}} @_ZN7Derived2vfEPc({{.*}} !callgraph [[F_TVF]]
     int vf(char *a) override { return 1; };
   };
   
diff --git a/clang/test/CodeGen/call-graph-section.c 
b/clang/test/CodeGen/call-graph-section.c
index 69cdd59549190..9d8e99a9ad098 100644
--- a/clang/test/CodeGen/call-graph-section.c
+++ b/clang/test/CodeGen/call-graph-section.c
@@ -7,12 +7,12 @@
 // RUN: -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,MS %s
 
 // CHECK-LABEL: define {{(dso_local)?}} void @foo(
-// CHECK-SAME: {{.*}} !type [[F_TVOID:![0-9]+]]
+// CHECK-SAME: {{.*}} !callgraph [[F_TVOID:![0-9]+]]
 void foo() {
 }
 
 // CHECK-LABEL: define {{(dso_local)?}} void @bar(
-// CHECK-SAME: {{.*}} !type [[F_TVOID]]
+// CHECK-SAME: {{.*}} !callgraph [[F_TVOID]]
 void bar() {
   void (*fp)() = foo;
   // ITANIUM: call {{.*}}, !callee_type [[F_TVOID_CT:![0-9]+]]
@@ -21,19 +21,19 @@ void bar() {
 }
 
 // CHECK-LABEL: define {{(dso_local)?}} i32 @baz(
-// CHECK-SAME: {{.*}} !type [[F_TPRIMITIVE:![0-9]+]]
+// CHECK-SAME: {{.*}} !callgraph [[F_TPRIMITIVE:![0-9]+]]
 int baz(char a, float b, double c) {
   return 1;
 }
 
 // CHECK-LABEL: define {{(dso_local)?}} ptr @qux(
-// CHECK-SAME: {{.*}} !type [[F_TPTR:![0-9]+]]
+// CHECK-SAME: {{.*}} !callgraph [[F_TPTR:![0-9]+]]
 int *qux(char *a, float *b, double *c) {
   return 0;
 }
 
 // CHECK-LABEL: define {{(dso_local)?}} void @corge(
-// CHECK-SAME: {{.*}} !type [[F_TVOID]]
+// CHECK-SAME: {{.*}} !callgraph [[F_TVOID]]
 void corge() {
   int (*fp_baz)(char, float, double) = baz;  
   // CHECK: call i32 {{.*}}, !callee_type [[F_TPRIMITIVE_CT:![0-9]+]]
@@ -53,11 +53,11 @@ struct st2 {
 };
 
 // CHECK-LABEL: define {{(dso_local)?}} void @stparam(
-// CHECK-SAME: {{.*}} !type [[F_TSTRUCT:![0-9]+]]
+// CHECK-SAME: {{.*}} !callgraph [[F_TSTRUCT:![0-9]+]]
 void stparam(struct st2 a, struct st2 *b) {}
 
 // CHECK-LABEL: define {{(dso_local)?}} void @stf(
-// CHECK-SAME: {{.*}} !type [[F_TVOID]]
+// CHECK-SAME: {{.*}} !callgraph [[F_TVOID]]
 void stf() {
   struct st1 St1;
   St1.fp = qux;  
diff --git a/clang/test/CodeGen/call-graph-section.cpp 
b/clang/test/CodeGen/call-graph-section.cpp
index 86ed3ee2337a7..5265eda31ccf9 100644
--- a/clang/test/CodeGen/call-graph-section.cpp
+++ b/clang/test/CodeGen/call-graph-section.cpp
@@ -12,7 +12,7 @@
 class Cls1 {
 public:
   // FT-LABEL: define {{.*}} ptr @_ZN4Cls18receiverEPcPf(
-  // FT-SAME: {{.*}} !type [[F_TCLS1RECEIVER:![0-9]+]]
+  // FT-SAME: {{.*}} !callgraph [[F_TCLS1RECEIVER:![0-9]+]]
   static int *receiver(char *a, float *b) { return 0; }
 };
 
@@ -21,39 +21,39 @@ class Cls2 {
   int *(*fp)(char *, float *);
 
   // FT-LABEL: define {{.*}} i32 @_ZN4Cls22f1Ecfd(
-  // FT-SAME: {{.*}} !type [[F_TCLS2F1:![0-9]+]]
+  // FT-SAME: {{.*}} !callgraph [[F_TCLS2F1:![0-9]+]]
   int f1(char a, float b, double c) { return 0; }
 
   // FT-LABEL: define {{.*}} ptr @_ZN4Cls22f2EPcPfPd(
-  // FT-SAME: {{.*}} !type [[F_TCLS2F2:![0-9]+]]
+  // FT-SAME: {{.*}} !callgraph [[F_TCLS2F2:![0-9]+]]
   int *f2(char *a, float *b, double *c) { return 0; }
 
   // FT-LABEL: define {{.*}} void @_ZN4Cls22f3E4Cls1(
-  // FT-SAME: {{.*}} !type [[F_TCLS2F3F4:![0-9]+]]
+  // FT-SAME: {{.*}} !callgraph [[F_TCLS2F3F4:![0-9]+]]
   void f3(Cls1 a) {}
 
   // FT-LABEL: define {{.*}} void @_ZN4Cls22f4E4Cls1(
-  // FT-SAME: {{.*}} !type [[F_TCLS2F3F4]]
+  // FT-SAME: {{.*}} !callgraph [[F_TCLS2F3F4]]
   void f4(const Cls1 a) {}
 
   // FT-LABEL: define {{.*}} void @_ZN4Cls22f5EP4Cls1(
-  // FT-SAME: {{.*}} !type [[F_TCLS2F5:![0-9]+]]
+  // FT-SAME: {{.*}} !callgraph [[F_TCLS2F5:![0-9]+]]
   void f5(Cls1 *a) {}
 
   // FT-LABEL: define {{.*}} void @_ZN4Cls22f6EPK4Cls1(
-  // FT-SAME: {{.*}} !type [[F_TCLS2F6:![0-9]+]]
+  // FT-SAME: {{.*}} !callgraph [[F_TCLS2F6:![0-9]+]]
   void f6(const Cls1 *a) {}
 
   // FT-LABEL: define {{.*}} void @_ZN4Cls22f7ER4Cls1(
-  // FT-SAME: {{.*}} !type [[F_TCLS2F7:![0-9]+]]
+  // FT-SAME: {{.*}} !callgraph [[F_TCLS2F7:![0-9]+]]
   void f7(Cls1 &a) {}
 
   // FT-LABEL: define {{.*}} void @_ZN4Cls22f8ERK4Cls1(
-  // FT-SAME: {{.*}} !type [[F_TCLS2F8:![0-9]+]]
+  // FT-SAME: {{.*}} !callgraph [[F_TCLS2F8:![0-9]+]]
   void f8(const Cls1 &a) {}
 
   // FT-LABEL: define {{.*}} void @_ZNK4Cls22f9Ev(
-  // FT-SAME: {{.*}} !type [[F_TCLS2F9:![0-9]+]]
+  // FT-SAME: {{.*}} !callgraph [[F_TCLS2F9:![0-9]+]]
   void f9() const {}
 };
 
diff --git a/llvm/include/llvm/IR/FixedMetadataKinds.def 
b/llvm/include/llvm/IR/FixedMetadataKinds.def
index 552c1f60f2d38..a6c8d84b56ce5 100644
--- a/llvm/include/llvm/IR/FixedMetadataKinds.def
+++ b/llvm/include/llvm/IR/FixedMetadataKinds.def
@@ -64,3 +64,5 @@ LLVM_FIXED_MD_KIND(MD_inline_history, "inline_history", 49)
 LLVM_FIXED_MD_KIND(MD_elf_section_properties, "elf_section_properties", 50)
 LLVM_FIXED_MD_KIND(MD_unique_id, "guid", 51)
 LLVM_FIXED_MD_KIND(MD_mem_cache_hint, "mem.cache_hint", 52)
+LLVM_FIXED_MD_KIND(MD_callgraph, "callgraph", 53)
+
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp 
b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index cdb9d760606f6..84efbff3de598 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -1756,7 +1756,7 @@ void AsmPrinter::emitStackUsage(const MachineFunction 
&MF) {
 /// type metadata. Returns null if metadata cannot be found.
 static ConstantInt *extractNumericCGTypeId(const Function &F) {
   SmallVector<MDNode *, 2> Types;
-  F.getMetadata(LLVMContext::MD_type, Types);
+  F.getMetadata(LLVMContext::MD_callgraph, Types);
   for (const auto &Type : Types) {
     if (Type->hasGeneralizedMDString()) {
       MDString *MDGeneralizedTypeId = cast<MDString>(Type->getOperand(1));
diff --git a/llvm/lib/IR/Metadata.cpp b/llvm/lib/IR/Metadata.cpp
index 491c788fc4445..0194b8f0a2083 100644
--- a/llvm/lib/IR/Metadata.cpp
+++ b/llvm/lib/IR/Metadata.cpp
@@ -1891,14 +1891,14 @@ void GlobalObject::copyMetadata(const GlobalObject 
*Other, unsigned Offset) {
   Other->getAllMetadata(MDs);
   for (auto &MD : MDs) {
     // We need to adjust the type metadata offset.
-    if (Offset != 0 && MD.first == LLVMContext::MD_type) {
+    if (Offset != 0 && (MD.first == LLVMContext::MD_type ||
+                        MD.first == LLVMContext::MD_callgraph)) {
       auto *OffsetConst = cast<ConstantInt>(
           cast<ConstantAsMetadata>(MD.second->getOperand(0))->getValue());
       Metadata *TypeId = MD.second->getOperand(1);
       auto *NewOffsetMD = ConstantAsMetadata::get(ConstantInt::get(
           OffsetConst->getType(), OffsetConst->getValue() + Offset));
-      addMetadata(LLVMContext::MD_type,
-                  *MDNode::get(getContext(), {NewOffsetMD, TypeId}));
+      addMetadata(MD.first, *MDNode::get(getContext(), {NewOffsetMD, TypeId}));
       continue;
     }
     // If an offset adjustment was specified we need to modify the DIExpression
diff --git a/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp 
b/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
index c14c9b869525d..01a0f3385a3c0 100644
--- a/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
+++ b/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
@@ -169,6 +169,21 @@ void promoteTypeIds(Module &M, StringRef ModuleId) {
           LLVMContext::MD_type,
           *MDNode::get(M.getContext(), {MD->getOperand(0), I->second}));
     }
+
+    SmallVector<MDNode *, 1> CGMDs;
+    GO.getMetadata(LLVMContext::MD_callgraph, CGMDs);
+
+    GO.eraseMetadata(LLVMContext::MD_callgraph);
+    for (auto *MD : CGMDs) {
+      auto I = LocalToGlobal.find(MD->getOperand(1));
+      if (I == LocalToGlobal.end()) {
+        GO.addMetadata(LLVMContext::MD_callgraph, *MD);
+        continue;
+      }
+      GO.addMetadata(
+          LLVMContext::MD_callgraph,
+          *MDNode::get(M.getContext(), {MD->getOperand(0), I->second}));
+    }
   }
 }
 
diff --git a/llvm/test/CodeGen/ARM/call-graph-section-addrtaken.ll 
b/llvm/test/CodeGen/ARM/call-graph-section-addrtaken.ll
index 9e243aec1128d..8bb9230316288 100644
--- a/llvm/test/CodeGen/ARM/call-graph-section-addrtaken.ll
+++ b/llvm/test/CodeGen/ARM/call-graph-section-addrtaken.ll
@@ -5,16 +5,16 @@
 
 ; RUN: llc -mtriple=arm-unknown-linux --call-graph-section -o - < %s | 
FileCheck %s
 
-declare !type !0 void @_Z6doWorkPFviE(ptr)
+declare !callgraph !0 void @_Z6doWorkPFviE(ptr)
 
-define i32 @_Z4testv() !type !1 {
+define i32 @_Z4testv() !callgraph !1 {
 entry:
   call void @_Z6doWorkPFviE(ptr nonnull @_ZL10myCallbacki)
   ret i32 0
 }
 
 ; CHECK: _ZL10myCallbacki:
-define internal void @_ZL10myCallbacki(i32 %value) !type !2 {
+define internal void @_ZL10myCallbacki(i32 %value) !callgraph !2 {
 entry:
   %sink = alloca i32, align 4
   store volatile i32 %value, ptr %sink, align 4
diff --git a/llvm/test/CodeGen/ARM/call-graph-section-tailcall.ll 
b/llvm/test/CodeGen/ARM/call-graph-section-tailcall.ll
index 35e570bdde405..c6152ef7c732b 100644
--- a/llvm/test/CodeGen/ARM/call-graph-section-tailcall.ll
+++ b/llvm/test/CodeGen/ARM/call-graph-section-tailcall.ll
@@ -3,13 +3,13 @@
 ; RUN: llc -mtriple=arm-unknown-linux --call-graph-section -filetype=obj -o - 
< %s | \
 ; RUN: llvm-readelf -x .llvm.callgraph - | FileCheck %s
 
-define i32 @check_tailcall(ptr %func, i8 %x) !type !0 {
+define i32 @check_tailcall(ptr %func, i8 %x) !callgraph !0 {
 entry:
   %call = tail call i32 %func(i8 signext %x), !callee_type !1
   ret i32 %call
 }
 
-define i32 @main(i32 %argc) !type !3 {
+define i32 @main(i32 %argc) !callgraph !3 {
 entry:
   %andop = and i32 %argc, 1
   %cmp = icmp eq i32 %andop, 0
@@ -18,9 +18,9 @@ entry:
   ret i32 %call.i
 }
 
-declare !type !2 i32 @foo(i8 signext)
+declare !callgraph !2 i32 @foo(i8 signext)
 
-declare !type !2 i32 @bar(i8 signext)
+declare !callgraph !2 i32 @bar(i8 signext)
 
 !0 = !{i64 0, !"_ZTSFiPvcE.generalized"}
 !1 = !{!2}
diff --git a/llvm/test/CodeGen/X86/call-graph-section-addrtaken.ll 
b/llvm/test/CodeGen/X86/call-graph-section-addrtaken.ll
index ab8498d8d3451..42d46e005fce5 100644
--- a/llvm/test/CodeGen/X86/call-graph-section-addrtaken.ll
+++ b/llvm/test/CodeGen/X86/call-graph-section-addrtaken.ll
@@ -5,16 +5,16 @@
 
 ; RUN: llc -mtriple=x86_64-unknown-linux --call-graph-section -o - < %s | 
FileCheck %s
 
-declare !type !0 void @_Z6doWorkPFviE(ptr)
+declare !callgraph !0 void @_Z6doWorkPFviE(ptr)
 
-define i32 @_Z4testv() !type !1 {
+define i32 @_Z4testv() !callgraph !1 {
 entry:
   call void @_Z6doWorkPFviE(ptr nonnull @_ZL10myCallbacki)
   ret i32 0
 }
 
 ; CHECK: _ZL10myCallbacki:
-define internal void @_ZL10myCallbacki(i32 %value) !type !2 {
+define internal void @_ZL10myCallbacki(i32 %value) !callgraph !2 {
 entry:
   %sink = alloca i32, align 4
   store volatile i32 %value, ptr %sink, align 4
diff --git a/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll 
b/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll
index 49cc335bf7379..7246a02003445 100644
--- a/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll
+++ b/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll
@@ -6,13 +6,13 @@
 ; RUN: llc -mtriple=x86_64-unknown-linux --call-graph-section -filetype=obj -o 
- < %s | \
 ; RUN: llvm-readelf -x .llvm.callgraph - | FileCheck %s
 
-define i32 @check_tailcall(ptr %func, i8 %x) !type !0 {
+define i32 @check_tailcall(ptr %func, i8 %x) !callgraph !0 {
 entry:
   %call = tail call i32 %func(i8 signext %x), !callee_type !1
   ret i32 %call
 }
 
-define i32 @main(i32 %argc) !type !3 {
+define i32 @main(i32 %argc) !callgraph !3 {
 entry:
   %andop = and i32 %argc, 1
   %cmp = icmp eq i32 %andop, 0
@@ -21,9 +21,9 @@ entry:
   ret i32 %call.i
 }
 
-declare !type !2 i32 @foo(i8 signext)
+declare !callgraph !2 i32 @foo(i8 signext)
 
-declare !type !2 i32 @bar(i8 signext)
+declare !callgraph !2 i32 @bar(i8 signext)
 
 !0 = !{i64 0, !"_ZTSFiPvcE.generalized"}
 !1 = !{!2}

>From 973ab944bf99d79d1b6a432dd87d297d8dfecb5d Mon Sep 17 00:00:00 2001
From: prabhukr <[email protected]>
Date: Wed, 17 Jun 2026 17:50:40 -0700
Subject: [PATCH 02/13] remove has existing genaralized type metadata calls

---
 clang/lib/CodeGen/CodeGenModule.cpp | 15 ++++-----------
 1 file changed, 4 insertions(+), 11 deletions(-)

diff --git a/clang/lib/CodeGen/CodeGenModule.cpp 
b/clang/lib/CodeGen/CodeGenModule.cpp
index 25675f99258b4..e7f058dcd4776 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -3388,11 +3388,6 @@ 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::createIndirectFunctionTypeMD(const FunctionDecl *FD,
                                                  llvm::Function *F) {
   // All functions which are not internal linkage could be indirect targets.
@@ -3425,12 +3420,10 @@ void 
CodeGenModule::createFunctionTypeMetadataForIcall(const FunctionDecl *FD,
                                            /*GeneralizePointers=*/false);
   llvm::Metadata *MD = CreateMetadataIdentifierForType(FnType);
   F->addTypeMetadata(0, MD);
-  // Add the generalized identifier if not added already.
-  if (!hasExistingGeneralizedTypeMD(F)) {
-    QualType GenPtrFnType = GeneralizeFunctionType(getContext(), FD->getType(),
-                                                   
/*GeneralizePointers=*/true);
-    F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(GenPtrFnType));
-  }
+
+  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)

>From e001c26e5848a01acac3cde2414ac5d59418525d Mon Sep 17 00:00:00 2001
From: prabhukr <[email protected]>
Date: Thu, 18 Jun 2026 12:07:28 -0700
Subject: [PATCH 03/13] Drop vtable index from callgraph and callee type
 metadata

---
 clang/lib/CodeGen/CodeGenModule.cpp           |  9 ++---
 .../CodeGen/call-graph-section-callback.cpp   |  2 +-
 .../CodeGen/call-graph-section-templates.cpp  | 26 +++++++-------
 .../call-graph-section-virtual-methods.cpp    |  4 +--
 clang/test/CodeGen/call-graph-section.c       | 16 ++++-----
 clang/test/CodeGen/call-graph-section.cpp     | 36 +++++++++----------
 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp    | 12 ++++---
 llvm/lib/CodeGen/MachineFunction.cpp          |  2 +-
 llvm/lib/IR/Metadata.cpp                      |  6 ++--
 llvm/lib/IR/Verifier.cpp                      | 21 +++++------
 .../Transforms/IPO/ThinLTOBitcodeWriter.cpp   | 15 ++++----
 llvm/test/Assembler/callee-type-metadata.ll   |  4 +--
 .../calleetypeid-directcall-mismatched.ll     |  6 ++--
 .../callsite-emit-calleetypeid-tailcall.ll    |  4 +--
 .../AArch64/callsite-emit-calleetypeid.ll     |  2 +-
 .../ARM/call-graph-section-addrtaken.ll       |  6 ++--
 .../ARM/call-graph-section-assembly.ll        |  6 ++--
 .../ARM/call-graph-section-tailcall.ll        |  6 ++--
 llvm/test/CodeGen/ARM/call-graph-section.ll   |  6 ++--
 .../ARM/calleetypeid-directcall-mismatched.ll |  6 ++--
 .../callsite-emit-calleetypeid-tailcall.ll    |  4 +--
 .../CodeGen/ARM/callsite-emit-calleetypeid.ll |  2 +-
 ...te-info-ambiguous-indirect-call-typeid.mir |  4 +--
 .../CodeGen/MIR/X86/call-site-info-typeid.mir |  2 +-
 .../MIR/X86/callsite-emit-calleetypeid.ll     |  2 +-
 .../calleetypeid-directcall-mismatched.ll     |  6 ++--
 .../callsite-emit-calleetypeid-tailcall.ll    |  4 +--
 .../RISCV/callsite-emit-calleetypeid.ll       |  2 +-
 .../X86/call-graph-section-addrtaken.ll       |  6 ++--
 .../X86/call-graph-section-assembly.ll        |  6 ++--
 .../X86/call-graph-section-tailcall.ll        |  6 ++--
 llvm/test/CodeGen/X86/call-graph-section.ll   |  6 ++--
 .../X86/calleetypeid-directcall-mismatched.ll |  6 ++--
 .../callsite-emit-calleetypeid-tailcall.ll    |  4 +--
 .../CodeGen/X86/callsite-emit-calleetypeid.ll |  2 +-
 .../Inline/drop-callee-type-metadata.ll       | 12 +++----
 .../InstCombine/drop-callee-type-metadata.ll  |  6 ++--
 .../SimplifyCFG/merge-callee-type-metadata.ll | 12 +++----
 llvm/test/Verifier/callee-type-metadata.ll    | 12 +++----
 39 files changed, 144 insertions(+), 155 deletions(-)

diff --git a/clang/lib/CodeGen/CodeGenModule.cpp 
b/clang/lib/CodeGen/CodeGenModule.cpp
index e7f058dcd4776..ec9f46c341a60 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -3399,9 +3399,7 @@ void CodeGenModule::createIndirectFunctionTypeMD(const 
FunctionDecl *FD,
     F->addMetadata(llvm::LLVMContext::MD_callgraph,
                    *llvm::MDTuple::get(
                        getLLVMContext(),
-                       {llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
-                            llvm::Type::getInt64Ty(getLLVMContext()), 0)),
-                        CreateMetadataIdentifierGeneralized(FD->getType())}));
+                       {CreateMetadataIdentifierGeneralized(FD->getType())}));
   }
 }
 
@@ -3442,10 +3440,7 @@ void 
CodeGenModule::createCalleeTypeMetadataForIcall(const QualType &QT,
     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 *TypeTuple = llvm::MDTuple::get(getLLVMContext(), {TypeIdMD});
   llvm::MDTuple *MDN = llvm::MDNode::get(getLLVMContext(), {TypeTuple});
   CB->setMetadata(llvm::LLVMContext::MD_callee_type, MDN);
 }
diff --git a/clang/test/CodeGen/call-graph-section-callback.cpp 
b/clang/test/CodeGen/call-graph-section-callback.cpp
index 080fa07e41847..c943050d6d59f 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: [[F_CALLBACK]]   = !{i64 0, !"_ZTSFviE.generalized"}
+// CHECK: [[F_CALLBACK]]   = !{!"_ZTSFviE.generalized"}
diff --git a/clang/test/CodeGen/call-graph-section-templates.cpp 
b/clang/test/CodeGen/call-graph-section-templates.cpp
index e6c43a41a86ab..c26170585e8fd 100644
--- a/clang/test/CodeGen/call-graph-section-templates.cpp
+++ b/clang/test/CodeGen/call-graph-section-templates.cpp
@@ -44,12 +44,12 @@ class Cls2 {
   T *(*fp)(T a, T *b, const T *c, T &d, const T &e);
 };
 
-// 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"}
+// FT: [[F_TCLS2F1]] = !{!"_ZTSFvvE.generalized"}
+// FT: [[F_TCLS2F2]] = !{!"_ZTSFv4Cls1E.generalized"}
+// FT: [[F_TCLS2F3]] = !{!"_ZTSFvP4Cls1E.generalized"}
+// FT: [[F_TCLS2F4]] = !{!"_ZTSFvPK4Cls1E.generalized"}
+// FT: [[F_TCLS2F5]] = !{!"_ZTSFvR4Cls1E.generalized"}
+// FT: [[F_TCLS2F6]] = !{!"_ZTSFvRK4Cls1E.generalized"}
 
 
////////////////////////////////////////////////////////////////////////////////
 // Callsites (check for indirect callsite operand bundles)
@@ -101,17 +101,17 @@ void foo() {
 // CST-LABEL: define {{.*}} @_Z6T_funcI4Cls1EPT_S1_S2_PKS1_RS1_RS3_(
 // CST-SAME: {{.*}} !callgraph [[F_TFUNC_CLS1:![0-9]+]]
 
-// CST: [[F_TCLS2F1]] = !{i64 0, !"_ZTSFvvE.generalized"}
+// CST: [[F_TCLS2F1]] = !{!"_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_TFUNC_CLS1]] = !{!"_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_TCLS2F2]] = !{!"_ZTSFv4Cls1E.generalized"}
 // CST: [[F_TCLS2F3_CT]] = !{[[F_TCLS2F3:![0-9]+]]}
-// CST: [[F_TCLS2F3]] = !{i64 0, !"_ZTSFvP4Cls1E.generalized"}
+// CST: [[F_TCLS2F3]] = !{!"_ZTSFvP4Cls1E.generalized"}
 // CST: [[F_TCLS2F4_CT]] = !{[[F_TCLS2F4:![0-9]+]]}
-// CST: [[F_TCLS2F4]] = !{i64 0, !"_ZTSFvPK4Cls1E.generalized"}
+// CST: [[F_TCLS2F4]] = !{!"_ZTSFvPK4Cls1E.generalized"}
 // CST: [[F_TCLS2F5_CT]] = !{[[F_TCLS2F5:![0-9]+]]}
-// CST: [[F_TCLS2F5]] = !{i64 0, !"_ZTSFvR4Cls1E.generalized"}
+// CST: [[F_TCLS2F5]] = !{!"_ZTSFvR4Cls1E.generalized"}
 // CST: [[F_TCLS2F6_CT]] = !{[[F_TCLS2F6:![0-9]+]]}
-// CST: [[F_TCLS2F6]] = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"}
+// CST: [[F_TCLS2F6]] = !{!"_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 7aa7a8cf740ea..34c22c467080b 100644
--- a/clang/test/CodeGen/call-graph-section-virtual-methods.cpp
+++ b/clang/test/CodeGen/call-graph-section-virtual-methods.cpp
@@ -22,7 +22,7 @@ class Base {
     int vf(char *a) override { return 1; };
   };
   
-  // FT: [[F_TVF]] = !{i64 0, !"_ZTSFiPcE.generalized"}
+  // FT: [[F_TVF]] = !{!"_ZTSFiPcE.generalized"}
   
   
////////////////////////////////////////////////////////////////////////////////
   // Callsites (check for indirect callsite operand bundles)
@@ -53,4 +53,4 @@ class Base {
   }
 
   // CST: [[F_TVF_CT]] = !{[[F_TVF:![0-9]+]]}
-  // CST: [[F_TVF]] = !{i64 0, !"_ZTSFiPcE.generalized"}
+  // CST: [[F_TVF]] = !{!"_ZTSFiPcE.generalized"}
diff --git a/clang/test/CodeGen/call-graph-section.c 
b/clang/test/CodeGen/call-graph-section.c
index 9d8e99a9ad098..94581674dc5e3 100644
--- a/clang/test/CodeGen/call-graph-section.c
+++ b/clang/test/CodeGen/call-graph-section.c
@@ -74,20 +74,20 @@ void stf() {
   fp_stparam(St2, &St2);
 }
 
-// ITANIUM: [[F_TVOID]] = !{i64 0, !"_ZTSFvE.generalized"}
+// ITANIUM: [[F_TVOID]] = !{!"_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]] = !{!"_ZTSFicfdE.generalized"}
+// ITANIUM: [[F_TPTR]] = !{!"_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]] = !{!"_ZTSFv3st2PS_E.generalized"}
 // ITANIUM: [[F_TSTRUCT_CT]] = !{[[F_TSTRUCT:![0-9]+]]}
 
-// MS: [[F_TVOID]] = !{i64 0, !"[email protected]"}
+// MS: [[F_TVOID]] = !{!"[email protected]"}
 // MS: [[F_TVOID_CT]] = !{[[F_TVOID:![0-9]+]]}
-// MS: [[F_TPRIMITIVE]] = !{i64 0, !"[email protected]"}
-// MS: [[F_TPTR]] = !{i64 0, !"[email protected]"}
+// MS: [[F_TPRIMITIVE]] = !{!"[email protected]"}
+// MS: [[F_TPTR]] = !{!"[email protected]"}
 // 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]] = !{!"?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 5265eda31ccf9..a358ff9d2d551 100644
--- a/clang/test/CodeGen/call-graph-section.cpp
+++ b/clang/test/CodeGen/call-graph-section.cpp
@@ -57,15 +57,15 @@ class Cls2 {
   void f9() const {}
 };
 
-// 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"}
+// FT: [[F_TCLS1RECEIVER]] = !{!"_ZTSFPiPcPfE.generalized"}
+// FT: [[F_TCLS2F1]]   = !{!"_ZTSFicfdE.generalized"}
+// FT: [[F_TCLS2F2]]   = !{!"_ZTSFPiPcPfPdE.generalized"}
+// FT: [[F_TCLS2F3F4]] = !{!"_ZTSFv4Cls1E.generalized"}
+// FT: [[F_TCLS2F5]]   = !{!"_ZTSFvP4Cls1E.generalized"}
+// FT: [[F_TCLS2F6]]   = !{!"_ZTSFvPK4Cls1E.generalized"}
+// FT: [[F_TCLS2F7]]   = !{!"_ZTSFvR4Cls1E.generalized"}
+// FT: [[F_TCLS2F8]]   = !{!"_ZTSFvRK4Cls1E.generalized"}
+// FT: [[F_TCLS2F9]]   = !{!"_ZTSKFvvE.generalized"}
 
 
////////////////////////////////////////////////////////////////////////////////
 // Callsites (check for indirect callsites' callee_type metadata )
@@ -120,28 +120,28 @@ void foo() {
 }
 
 // CST: [[F_TCLS1RECEIVER_CT]] = !{[[F_TCLS1RECEIVER:![0-9]+]]}
-// CST: [[F_TCLS1RECEIVER]] = !{i64 0, !"_ZTSFPiPcPfE.generalized"}
+// CST: [[F_TCLS1RECEIVER]] = !{!"_ZTSFPiPcPfE.generalized"}
 
 // CST: [[F_TCLS2F1_CT]] = !{[[F_TCLS2F1:![0-9]+]]}
-// CST: [[F_TCLS2F1]]   = !{i64 0, !"_ZTSFicfdE.generalized"}
+// CST: [[F_TCLS2F1]]   = !{!"_ZTSFicfdE.generalized"}
 
 // CST: [[F_TCLS2F2_CT]] = !{[[F_TCLS2F2:![0-9]+]]}
-// CST: [[F_TCLS2F2]]   = !{i64 0, !"_ZTSFPiPcPfPdE.generalized"}
+// CST: [[F_TCLS2F2]]   = !{!"_ZTSFPiPcPfPdE.generalized"}
 
 // CST: [[F_TCLS2F3F4_CT]] = !{[[F_TCLS2F3F4:![0-9]+]]}
-// CST: [[F_TCLS2F3F4]] = !{i64 0, !"_ZTSFv4Cls1E.generalized"}
+// CST: [[F_TCLS2F3F4]] = !{!"_ZTSFv4Cls1E.generalized"}
 
 // CST: [[F_TCLS2F5_CT]] = !{[[F_TCLS2F5:![0-9]+]]}
-// CST: [[F_TCLS2F5]]   = !{i64 0, !"_ZTSFvP4Cls1E.generalized"}
+// CST: [[F_TCLS2F5]]   = !{!"_ZTSFvP4Cls1E.generalized"}
 
 // CST: [[F_TCLS2F6_CT]] = !{[[F_TCLS2F6:![0-9]+]]}
-// CST: [[F_TCLS2F6]]   = !{i64 0, !"_ZTSFvPK4Cls1E.generalized"}
+// CST: [[F_TCLS2F6]]   = !{!"_ZTSFvPK4Cls1E.generalized"}
 
 // CST: [[F_TCLS2F7_CT]] = !{[[F_TCLS2F7:![0-9]+]]}
-// CST: [[F_TCLS2F7]]   = !{i64 0, !"_ZTSFvR4Cls1E.generalized"}
+// CST: [[F_TCLS2F7]]   = !{!"_ZTSFvR4Cls1E.generalized"}
 
 // CST: [[F_TCLS2F8_CT]] = !{[[F_TCLS2F8:![0-9]+]]}
-// CST: [[F_TCLS2F8]]   = !{i64 0, !"_ZTSFvRK4Cls1E.generalized"}
+// CST: [[F_TCLS2F8]]   = !{!"_ZTSFvRK4Cls1E.generalized"}
 
 // CST: [[F_TCLS2F9_CT]] = !{[[F_TCLS2F9:![0-9]+]]}
-// CST: [[F_TCLS2F9]]   = !{i64 0, !"_ZTSKFvvE.generalized"}
+// CST: [[F_TCLS2F9]]   = !{!"_ZTSKFvvE.generalized"}
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp 
b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 84efbff3de598..acc3cfb0edc81 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -1758,11 +1758,13 @@ static ConstantInt *extractNumericCGTypeId(const 
Function &F) {
   SmallVector<MDNode *, 2> Types;
   F.getMetadata(LLVMContext::MD_callgraph, Types);
   for (const auto &Type : Types) {
-    if (Type->hasGeneralizedMDString()) {
-      MDString *MDGeneralizedTypeId = cast<MDString>(Type->getOperand(1));
-      uint64_t TypeIdVal = llvm::MD5Hash(MDGeneralizedTypeId->getString());
-      IntegerType *Int64Ty = Type::getInt64Ty(F.getContext());
-      return ConstantInt::get(Int64Ty, TypeIdVal);
+    if (Type->getNumOperands() == 1 && isa<MDString>(Type->getOperand(0))) {
+      MDString *MDGeneralizedTypeId = cast<MDString>(Type->getOperand(0));
+      if (MDGeneralizedTypeId->getString().ends_with(".generalized")) {
+        uint64_t TypeIdVal = llvm::MD5Hash(MDGeneralizedTypeId->getString());
+        IntegerType *Int64Ty = Type::getInt64Ty(F.getContext());
+        return ConstantInt::get(Int64Ty, TypeIdVal);
+      }
     }
   }
   return nullptr;
diff --git a/llvm/lib/CodeGen/MachineFunction.cpp 
b/llvm/lib/CodeGen/MachineFunction.cpp
index 2922922535333..c03fc8b5152af 100644
--- a/llvm/lib/CodeGen/MachineFunction.cpp
+++ b/llvm/lib/CodeGen/MachineFunction.cpp
@@ -758,7 +758,7 @@ MachineFunction::CallSiteInfo::CallSiteInfo(const CallBase 
&CB) {
 
   for (const MDOperand &Op : CalleeTypeList->operands()) {
     MDNode *TypeMD = cast<MDNode>(Op);
-    MDString *TypeIdStr = cast<MDString>(TypeMD->getOperand(1));
+    MDString *TypeIdStr = cast<MDString>(TypeMD->getOperand(0));
     // Compute numeric type id from generalized type id string
     uint64_t TypeIdVal = MD5Hash(TypeIdStr->getString());
     IntegerType *Int64Ty = Type::getInt64Ty(CB.getContext());
diff --git a/llvm/lib/IR/Metadata.cpp b/llvm/lib/IR/Metadata.cpp
index 0194b8f0a2083..491c788fc4445 100644
--- a/llvm/lib/IR/Metadata.cpp
+++ b/llvm/lib/IR/Metadata.cpp
@@ -1891,14 +1891,14 @@ void GlobalObject::copyMetadata(const GlobalObject 
*Other, unsigned Offset) {
   Other->getAllMetadata(MDs);
   for (auto &MD : MDs) {
     // We need to adjust the type metadata offset.
-    if (Offset != 0 && (MD.first == LLVMContext::MD_type ||
-                        MD.first == LLVMContext::MD_callgraph)) {
+    if (Offset != 0 && MD.first == LLVMContext::MD_type) {
       auto *OffsetConst = cast<ConstantInt>(
           cast<ConstantAsMetadata>(MD.second->getOperand(0))->getValue());
       Metadata *TypeId = MD.second->getOperand(1);
       auto *NewOffsetMD = ConstantAsMetadata::get(ConstantInt::get(
           OffsetConst->getType(), OffsetConst->getValue() + Offset));
-      addMetadata(MD.first, *MDNode::get(getContext(), {NewOffsetMD, TypeId}));
+      addMetadata(LLVMContext::MD_type,
+                  *MDNode::get(getContext(), {NewOffsetMD, TypeId}));
       continue;
     }
     // If an offset adjustment was specified we need to modify the DIExpression
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 18d6578dec646..7ab98d0b98cc5 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -5650,12 +5650,6 @@ void Verifier::visitCallsiteMetadata(Instruction &I, 
MDNode *MD) {
   visitCallStackMetadata(MD);
 }
 
-static inline bool isConstantIntMetadataOperand(const Metadata *MD) {
-  if (auto *VAL = dyn_cast<ValueAsMetadata>(MD))
-    return isa<ConstantInt>(VAL->getValue());
-  return false;
-}
-
 void Verifier::visitCalleeTypeMetadata(Instruction &I, MDNode *MD) {
   Check(isa<CallBase>(I), "!callee_type metadata should only exist on calls",
         &I);
@@ -5663,14 +5657,15 @@ void Verifier::visitCalleeTypeMetadata(Instruction &I, 
MDNode *MD) {
     Check(isa<MDNode>(Op),
           "The callee_type metadata must be a list of type metadata nodes", 
Op);
     auto *TypeMD = cast<MDNode>(Op);
-    Check(TypeMD->getNumOperands() == 2,
-          "Well-formed generalized type metadata must contain exactly two "
-          "operands",
+    Check(TypeMD->getNumOperands() == 1,
+          "Well-formed generalized callgraph metadata must contain exactly one 
"
+          "operand",
           Op);
-    Check(isConstantIntMetadataOperand(TypeMD->getOperand(0)) &&
-              mdconst::extract<ConstantInt>(TypeMD->getOperand(0))->isZero(),
-          "The first operand of type metadata for functions must be zero", Op);
-    Check(TypeMD->hasGeneralizedMDString(),
+    Check(isa<MDString>(TypeMD->getOperand(0)),
+          "The operand of type metadata for functions must be an MDString", 
Op);
+    Check(cast<MDString>(TypeMD->getOperand(0))
+              ->getString()
+              .ends_with(".generalized"),
           "Only generalized type metadata can be part of the callee_type "
           "metadata list",
           Op);
diff --git a/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp 
b/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
index 01a0f3385a3c0..a486979a58c2d 100644
--- a/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
+++ b/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
@@ -175,14 +175,15 @@ void promoteTypeIds(Module &M, StringRef ModuleId) {
 
     GO.eraseMetadata(LLVMContext::MD_callgraph);
     for (auto *MD : CGMDs) {
-      auto I = LocalToGlobal.find(MD->getOperand(1));
-      if (I == LocalToGlobal.end()) {
-        GO.addMetadata(LLVMContext::MD_callgraph, *MD);
-        continue;
+      if (MD->getNumOperands() == 1) {
+        auto I = LocalToGlobal.find(MD->getOperand(0));
+        if (I == LocalToGlobal.end()) {
+          GO.addMetadata(LLVMContext::MD_callgraph, *MD);
+          continue;
+        }
+        GO.addMetadata(LLVMContext::MD_callgraph,
+                       *MDNode::get(M.getContext(), {I->second}));
       }
-      GO.addMetadata(
-          LLVMContext::MD_callgraph,
-          *MDNode::get(M.getContext(), {MD->getOperand(0), I->second}));
     }
   }
 }
diff --git a/llvm/test/Assembler/callee-type-metadata.ll 
b/llvm/test/Assembler/callee-type-metadata.ll
index 9c3cfbe82fc13..305aedd0b2895 100644
--- a/llvm/test/Assembler/callee-type-metadata.ll
+++ b/llvm/test/Assembler/callee-type-metadata.ll
@@ -16,6 +16,6 @@ entry:
 
 declare !type !2 i32 @_Z3barc(i8 signext)
 
-!0 = !{i64 0, !"_ZTSFiPvcE.generalized"}
+!0 = !{!"_ZTSFiPvcE.generalized"}
 !1 = !{!2}
-!2 = !{i64 0, !"_ZTSFicE.generalized"}
+!2 = !{!"_ZTSFicE.generalized"}
diff --git a/llvm/test/CodeGen/AArch64/calleetypeid-directcall-mismatched.ll 
b/llvm/test/CodeGen/AArch64/calleetypeid-directcall-mismatched.ll
index c4c54175ecd9f..b0140a56dbc6a 100644
--- a/llvm/test/CodeGen/AArch64/calleetypeid-directcall-mismatched.ll
+++ b/llvm/test/CodeGen/AArch64/calleetypeid-directcall-mismatched.ll
@@ -25,8 +25,8 @@ entry:
 
 declare !type !2 i32 @fizz(i32, i32)
 
-!0 = !{i64 0, !"_ZTSFiiiiE.generalized"}
+!0 = !{!"_ZTSFiiiiE.generalized"}
 !1 = !{!2}
-!2 = !{i64 0, !"_ZTSFiiiE.generalized"}
+!2 = !{!"_ZTSFiiiE.generalized"}
 !3 = !{!4}
-!4 = !{i64 0, !"_ZTSFicE.generalized"}
+!4 = !{!"_ZTSFicE.generalized"}
diff --git a/llvm/test/CodeGen/AArch64/callsite-emit-calleetypeid-tailcall.ll 
b/llvm/test/CodeGen/AArch64/callsite-emit-calleetypeid-tailcall.ll
index b47607ec135ae..44cb4bba6e4b2 100644
--- a/llvm/test/CodeGen/AArch64/callsite-emit-calleetypeid-tailcall.ll
+++ b/llvm/test/CodeGen/AArch64/callsite-emit-calleetypeid-tailcall.ll
@@ -14,6 +14,6 @@ entry:
   ret i32 %call
 }
 
-!0 = !{i64 0, !"_ZTSFiPvcE.generalized"}
+!0 = !{!"_ZTSFiPvcE.generalized"}
 !1 = !{!2}
-!2 = !{i64 0, !"_ZTSFicE.generalized"}
+!2 = !{!"_ZTSFicE.generalized"}
diff --git a/llvm/test/CodeGen/AArch64/callsite-emit-calleetypeid.ll 
b/llvm/test/CodeGen/AArch64/callsite-emit-calleetypeid.ll
index 94b657c6ea908..c918558d8bd82 100644
--- a/llvm/test/CodeGen/AArch64/callsite-emit-calleetypeid.ll
+++ b/llvm/test/CodeGen/AArch64/callsite-emit-calleetypeid.ll
@@ -17,4 +17,4 @@ entry:
 }
 
 !0 = !{!1}
-!1 = !{i64 0, !"_ZTSFvcE.generalized"}
+!1 = !{!"_ZTSFvcE.generalized"}
diff --git a/llvm/test/CodeGen/ARM/call-graph-section-addrtaken.ll 
b/llvm/test/CodeGen/ARM/call-graph-section-addrtaken.ll
index 8bb9230316288..3ffdb65aed8dc 100644
--- a/llvm/test/CodeGen/ARM/call-graph-section-addrtaken.ll
+++ b/llvm/test/CodeGen/ARM/call-graph-section-addrtaken.ll
@@ -22,9 +22,9 @@ entry:
   ret void
 }
 
-!0 = !{i64 0, !"_ZTSFvPFviEE.generalized"}
-!1 = !{i64 0, !"_ZTSFivE.generalized"}
-!2 = !{i64 0, !"_ZTSFviE.generalized"}
+!0 = !{!"_ZTSFvPFviEE.generalized"}
+!1 = !{!"_ZTSFivE.generalized"}
+!2 = !{!"_ZTSFviE.generalized"}
 
 ; CHECK: .section .llvm.callgraph,"o",%llvm_call_graph,.text
 ;; Version
diff --git a/llvm/test/CodeGen/ARM/call-graph-section-assembly.ll 
b/llvm/test/CodeGen/ARM/call-graph-section-assembly.ll
index 8e8881ee722fb..d06b12636c7af 100644
--- a/llvm/test/CodeGen/ARM/call-graph-section-assembly.ll
+++ b/llvm/test/CodeGen/ARM/call-graph-section-assembly.ll
@@ -29,11 +29,11 @@ entry:
 }
 
 !0 = !{!1}
-!1 = !{i64 0, !"_ZTSFvE.generalized"}
+!1 = !{!"_ZTSFvE.generalized"}
 !2 = !{!3}
-!3 = !{i64 0, !"_ZTSFicE.generalized"}
+!3 = !{!"_ZTSFicE.generalized"}
 !4 = !{!5}
-!5 = !{i64 0, !"_ZTSFPvS_E.generalized"}
+!5 = !{!"_ZTSFPvS_E.generalized"}
 
 ; CHECK: .section .llvm.callgraph,"o",%llvm_call_graph,.text
 ;; Version
diff --git a/llvm/test/CodeGen/ARM/call-graph-section-tailcall.ll 
b/llvm/test/CodeGen/ARM/call-graph-section-tailcall.ll
index c6152ef7c732b..eeceea7bc73ab 100644
--- a/llvm/test/CodeGen/ARM/call-graph-section-tailcall.ll
+++ b/llvm/test/CodeGen/ARM/call-graph-section-tailcall.ll
@@ -22,10 +22,10 @@ declare !callgraph !2 i32 @foo(i8 signext)
 
 declare !callgraph !2 i32 @bar(i8 signext)
 
-!0 = !{i64 0, !"_ZTSFiPvcE.generalized"}
+!0 = !{!"_ZTSFiPvcE.generalized"}
 !1 = !{!2}
-!2 = !{i64 0, !"_ZTSFicE.generalized"}
-!3 = !{i64 0, !"_ZTSFiiE.generalized"}
+!2 = !{!"_ZTSFicE.generalized"}
+!3 = !{!"_ZTSFiiE.generalized"}
 
 ; CHECK:      Hex dump of section '.llvm.callgraph':
 ; CHECK-NEXT: 0x00000000 00050000 00008e19 0b7f3326 e3000154
diff --git a/llvm/test/CodeGen/ARM/call-graph-section.ll 
b/llvm/test/CodeGen/ARM/call-graph-section.ll
index 167cc6f3c73bd..9619de4669f32 100644
--- a/llvm/test/CodeGen/ARM/call-graph-section.ll
+++ b/llvm/test/CodeGen/ARM/call-graph-section.ll
@@ -22,12 +22,12 @@ entry:
 
 ;; Check that the numeric type id (md5 hash) for the below type ids are emitted
 ;; to the callgraph section.
-!0 = !{i64 0, !"_ZTSFvE.generalized"}
+!0 = !{!"_ZTSFvE.generalized"}
 !1 = !{!0}
-!2 = !{i64 0, !"_ZTSFicE.generalized"}
+!2 = !{!"_ZTSFicE.generalized"}
 !3 = !{!2}
 !4 = !{!5}
-!5 = !{i64 0, !"_ZTSFPvS_E.generalized"}
+!5 = !{!"_ZTSFPvS_E.generalized"}
 
 ;; Make sure following type IDs are in call graph section
 ;; 0x5eecb3e2444f731f, 0x814b8e305486bc59, 0xf897fd777ade6814
diff --git a/llvm/test/CodeGen/ARM/calleetypeid-directcall-mismatched.ll 
b/llvm/test/CodeGen/ARM/calleetypeid-directcall-mismatched.ll
index 8f7b0506a5e39..7969e904b2ffa 100644
--- a/llvm/test/CodeGen/ARM/calleetypeid-directcall-mismatched.ll
+++ b/llvm/test/CodeGen/ARM/calleetypeid-directcall-mismatched.ll
@@ -25,8 +25,8 @@ entry:
 
 declare !type !2 i32 @fizz(i32, i32)
 
-!0 = !{i64 0, !"_ZTSFiiiiE.generalized"}
+!0 = !{!"_ZTSFiiiiE.generalized"}
 !1 = !{!2}
-!2 = !{i64 0, !"_ZTSFiiiE.generalized"}
+!2 = !{!"_ZTSFiiiE.generalized"}
 !3 = !{!4}
-!4 = !{i64 0, !"_ZTSFicE.generalized"}
+!4 = !{!"_ZTSFicE.generalized"}
diff --git a/llvm/test/CodeGen/ARM/callsite-emit-calleetypeid-tailcall.ll 
b/llvm/test/CodeGen/ARM/callsite-emit-calleetypeid-tailcall.ll
index 05e1e8bf0502b..c5a33e61e85e0 100644
--- a/llvm/test/CodeGen/ARM/callsite-emit-calleetypeid-tailcall.ll
+++ b/llvm/test/CodeGen/ARM/callsite-emit-calleetypeid-tailcall.ll
@@ -14,6 +14,6 @@ entry:
   ret i32 %call
 }
 
-!0 = !{i64 0, !"_ZTSFiPvcE.generalized"}
+!0 = !{!"_ZTSFiPvcE.generalized"}
 !1 = !{!2}
-!2 = !{i64 0, !"_ZTSFicE.generalized"}
+!2 = !{!"_ZTSFicE.generalized"}
diff --git a/llvm/test/CodeGen/ARM/callsite-emit-calleetypeid.ll 
b/llvm/test/CodeGen/ARM/callsite-emit-calleetypeid.ll
index a65e5c5f8c015..7e1ab0068ff07 100644
--- a/llvm/test/CodeGen/ARM/callsite-emit-calleetypeid.ll
+++ b/llvm/test/CodeGen/ARM/callsite-emit-calleetypeid.ll
@@ -17,4 +17,4 @@ entry:
 }
 
 !0 = !{!1}
-!1 = !{i64 0, !"_ZTSFvcE.generalized"}
+!1 = !{!"_ZTSFvcE.generalized"}
diff --git 
a/llvm/test/CodeGen/MIR/X86/call-site-info-ambiguous-indirect-call-typeid.mir 
b/llvm/test/CodeGen/MIR/X86/call-site-info-ambiguous-indirect-call-typeid.mir
index cb78898f3a0d4..5573be87fbb2d 100644
--- 
a/llvm/test/CodeGen/MIR/X86/call-site-info-ambiguous-indirect-call-typeid.mir
+++ 
b/llvm/test/CodeGen/MIR/X86/call-site-info-ambiguous-indirect-call-typeid.mir
@@ -16,8 +16,8 @@
   }
   
   !0 = !{!1, !2}
-  !1 = !{i64 0, !"callee_type0.generalized"}
-  !2 = !{i64 0, !"callee_type2.generalized"}
+  !1 = !{!"callee_type0.generalized"}
+  !2 = !{!"callee_type2.generalized"}
 ...
 ---
 name:            ambiguous_caller
diff --git a/llvm/test/CodeGen/MIR/X86/call-site-info-typeid.mir 
b/llvm/test/CodeGen/MIR/X86/call-site-info-typeid.mir
index 303b8fac22a9c..dd835abab5256 100644
--- a/llvm/test/CodeGen/MIR/X86/call-site-info-typeid.mir
+++ b/llvm/test/CodeGen/MIR/X86/call-site-info-typeid.mir
@@ -16,7 +16,7 @@
   }
 
   !0 = !{!1}
-  !1 = !{i64 0, !"_ZTSFvcE.generalized"}
+  !1 = !{!"_ZTSFvcE.generalized"}
 ...
 ---
 name:            call_foo
diff --git a/llvm/test/CodeGen/MIR/X86/callsite-emit-calleetypeid.ll 
b/llvm/test/CodeGen/MIR/X86/callsite-emit-calleetypeid.ll
index fe1980e3f5605..c49d8152a7751 100644
--- a/llvm/test/CodeGen/MIR/X86/callsite-emit-calleetypeid.ll
+++ b/llvm/test/CodeGen/MIR/X86/callsite-emit-calleetypeid.ll
@@ -86,4 +86,4 @@ entry:
 }
 
 !0 = !{!1}
-!1 = !{i64 0, !"_ZTSFvcE.generalized"}
+!1 = !{!"_ZTSFvcE.generalized"}
diff --git a/llvm/test/CodeGen/RISCV/calleetypeid-directcall-mismatched.ll 
b/llvm/test/CodeGen/RISCV/calleetypeid-directcall-mismatched.ll
index 34493cec0eab0..e2c191fa03e27 100644
--- a/llvm/test/CodeGen/RISCV/calleetypeid-directcall-mismatched.ll
+++ b/llvm/test/CodeGen/RISCV/calleetypeid-directcall-mismatched.ll
@@ -26,8 +26,8 @@ entry:
 
 declare !type !2 i32 @fizz(i32, i32)
 
-!0 = !{i64 0, !"_ZTSFiiiiE.generalized"}
+!0 = !{!"_ZTSFiiiiE.generalized"}
 !1 = !{!2}
-!2 = !{i64 0, !"_ZTSFiiiE.generalized"}
+!2 = !{!"_ZTSFiiiE.generalized"}
 !3 = !{!4}
-!4 = !{i64 0, !"_ZTSFicE.generalized"}
+!4 = !{!"_ZTSFicE.generalized"}
diff --git a/llvm/test/CodeGen/RISCV/callsite-emit-calleetypeid-tailcall.ll 
b/llvm/test/CodeGen/RISCV/callsite-emit-calleetypeid-tailcall.ll
index 6e1fe92dac8f7..337820875b9df 100644
--- a/llvm/test/CodeGen/RISCV/callsite-emit-calleetypeid-tailcall.ll
+++ b/llvm/test/CodeGen/RISCV/callsite-emit-calleetypeid-tailcall.ll
@@ -15,6 +15,6 @@ entry:
   ret i32 %call
 }
 
-!0 = !{i64 0, !"_ZTSFiPvcE.generalized"}
+!0 = !{!"_ZTSFiPvcE.generalized"}
 !1 = !{!2}
-!2 = !{i64 0, !"_ZTSFicE.generalized"}
+!2 = !{!"_ZTSFicE.generalized"}
diff --git a/llvm/test/CodeGen/RISCV/callsite-emit-calleetypeid.ll 
b/llvm/test/CodeGen/RISCV/callsite-emit-calleetypeid.ll
index 1f91f4103abbb..ec7f4abc0bc2d 100644
--- a/llvm/test/CodeGen/RISCV/callsite-emit-calleetypeid.ll
+++ b/llvm/test/CodeGen/RISCV/callsite-emit-calleetypeid.ll
@@ -18,4 +18,4 @@ entry:
 }
 
 !0 = !{!1}
-!1 = !{i64 0, !"_ZTSFvcE.generalized"}
+!1 = !{!"_ZTSFvcE.generalized"}
diff --git a/llvm/test/CodeGen/X86/call-graph-section-addrtaken.ll 
b/llvm/test/CodeGen/X86/call-graph-section-addrtaken.ll
index 42d46e005fce5..06daa8fa38810 100644
--- a/llvm/test/CodeGen/X86/call-graph-section-addrtaken.ll
+++ b/llvm/test/CodeGen/X86/call-graph-section-addrtaken.ll
@@ -22,9 +22,9 @@ entry:
   ret void
 }
 
-!0 = !{i64 0, !"_ZTSFvPFviEE.generalized"}
-!1 = !{i64 0, !"_ZTSFivE.generalized"}
-!2 = !{i64 0, !"_ZTSFviE.generalized"}
+!0 = !{!"_ZTSFvPFviEE.generalized"}
+!1 = !{!"_ZTSFivE.generalized"}
+!2 = !{!"_ZTSFviE.generalized"}
 
 ; CHECK: .section .llvm.callgraph,"o",@llvm_call_graph,.text
 ;; Version
diff --git a/llvm/test/CodeGen/X86/call-graph-section-assembly.ll 
b/llvm/test/CodeGen/X86/call-graph-section-assembly.ll
index 02d71073b65c5..7d85ddee24fa1 100644
--- a/llvm/test/CodeGen/X86/call-graph-section-assembly.ll
+++ b/llvm/test/CodeGen/X86/call-graph-section-assembly.ll
@@ -29,11 +29,11 @@ entry:
 }
 
 !0 = !{!1}
-!1 = !{i64 0, !"_ZTSFvE.generalized"}
+!1 = !{!"_ZTSFvE.generalized"}
 !2 = !{!3}
-!3 = !{i64 0, !"_ZTSFicE.generalized"}
+!3 = !{!"_ZTSFicE.generalized"}
 !4 = !{!5}
-!5 = !{i64 0, !"_ZTSFPvS_E.generalized"}
+!5 = !{!"_ZTSFPvS_E.generalized"}
 
 ; CHECK: .section .llvm.callgraph,"o",@llvm_call_graph,.text
 ;; Version
diff --git a/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll 
b/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll
index 7246a02003445..753995a9733bf 100644
--- a/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll
+++ b/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll
@@ -25,10 +25,10 @@ declare !callgraph !2 i32 @foo(i8 signext)
 
 declare !callgraph !2 i32 @bar(i8 signext)
 
-!0 = !{i64 0, !"_ZTSFiPvcE.generalized"}
+!0 = !{!"_ZTSFiPvcE.generalized"}
 !1 = !{!2}
-!2 = !{i64 0, !"_ZTSFicE.generalized"}
-!3 = !{i64 0, !"_ZTSFiiE.generalized"}
+!2 = !{!"_ZTSFicE.generalized"}
+!3 = !{!"_ZTSFiiE.generalized"}
 
 ; CHECK: Hex dump of section '.llvm.callgraph':
 ; CHECK-NEXT: 0x00000000 00050000 00000000 00008e19 0b7f3326
diff --git a/llvm/test/CodeGen/X86/call-graph-section.ll 
b/llvm/test/CodeGen/X86/call-graph-section.ll
index 8a1c6ca627cb5..fec66ea5da588 100644
--- a/llvm/test/CodeGen/X86/call-graph-section.ll
+++ b/llvm/test/CodeGen/X86/call-graph-section.ll
@@ -25,12 +25,12 @@ entry:
 
 ;; Check that the numeric type id (md5 hash) for the below type ids are emitted
 ;; to the callgraph section.
-!0 = !{i64 0, !"_ZTSFvE.generalized"}
+!0 = !{!"_ZTSFvE.generalized"}
 !1 = !{!0}
-!2 = !{i64 0, !"_ZTSFicE.generalized"}
+!2 = !{!"_ZTSFicE.generalized"}
 !3 = !{!2}
 !4 = !{!5}
-!5 = !{i64 0, !"_ZTSFPvS_E.generalized"}
+!5 = !{!"_ZTSFPvS_E.generalized"}
 
 ;; Make sure following type IDs are in call graph section
 ;; 0x5eecb3e2444f731f, 0x814b8e305486bc59, 0xf897fd777ade6814
diff --git a/llvm/test/CodeGen/X86/calleetypeid-directcall-mismatched.ll 
b/llvm/test/CodeGen/X86/calleetypeid-directcall-mismatched.ll
index 7881ea7d59314..05edbfd649415 100644
--- a/llvm/test/CodeGen/X86/calleetypeid-directcall-mismatched.ll
+++ b/llvm/test/CodeGen/X86/calleetypeid-directcall-mismatched.ll
@@ -25,8 +25,8 @@ entry:
 
 declare !type !2 i32 @fizz(i32, i32)
 
-!0 = !{i64 0, !"_ZTSFiiiiE.generalized"}
+!0 = !{!"_ZTSFiiiiE.generalized"}
 !1 = !{!2}
-!2 = !{i64 0, !"_ZTSFiiiE.generalized"}
+!2 = !{!"_ZTSFiiiE.generalized"}
 !3 = !{!4}
-!4 = !{i64 0, !"_ZTSFicE.generalized"}
+!4 = !{!"_ZTSFicE.generalized"}
diff --git a/llvm/test/CodeGen/X86/callsite-emit-calleetypeid-tailcall.ll 
b/llvm/test/CodeGen/X86/callsite-emit-calleetypeid-tailcall.ll
index 8f6b7a6d7f240..9a868db8e4297 100644
--- a/llvm/test/CodeGen/X86/callsite-emit-calleetypeid-tailcall.ll
+++ b/llvm/test/CodeGen/X86/callsite-emit-calleetypeid-tailcall.ll
@@ -14,6 +14,6 @@ entry:
   ret i32 %call
 }
 
-!0 = !{i64 0, !"_ZTSFiPvcE.generalized"}
+!0 = !{!"_ZTSFiPvcE.generalized"}
 !1 = !{!2}
-!2 = !{i64 0, !"_ZTSFicE.generalized"}
+!2 = !{!"_ZTSFicE.generalized"}
diff --git a/llvm/test/CodeGen/X86/callsite-emit-calleetypeid.ll 
b/llvm/test/CodeGen/X86/callsite-emit-calleetypeid.ll
index e97a6ac75e111..5981b58bdf7e9 100644
--- a/llvm/test/CodeGen/X86/callsite-emit-calleetypeid.ll
+++ b/llvm/test/CodeGen/X86/callsite-emit-calleetypeid.ll
@@ -17,4 +17,4 @@ entry:
 }
 
 !0 = !{!1}
-!1 = !{i64 0, !"_ZTSFvcE.generalized"}
+!1 = !{!"_ZTSFvcE.generalized"}
diff --git a/llvm/test/Transforms/Inline/drop-callee-type-metadata.ll 
b/llvm/test/Transforms/Inline/drop-callee-type-metadata.ll
index 547588089c5b0..5495441a45738 100644
--- a/llvm/test/Transforms/Inline/drop-callee-type-metadata.ll
+++ b/llvm/test/Transforms/Inline/drop-callee-type-metadata.ll
@@ -29,13 +29,13 @@ entry:
 }
 declare !type !2 i32 @_Z3fooc(i8 signext)
 
-!0 = !{i64 0, !"_ZTSFiPvcE.generalized"}
+!0 = !{!"_ZTSFiPvcE.generalized"}
 !1 = !{!2}
-!2 = !{i64 0, !"_ZTSFicE.generalized"}
-!3 = !{i64 0, !"_ZTSFivE.generalized"}
+!2 = !{!"_ZTSFicE.generalized"}
+!3 = !{!"_ZTSFivE.generalized"}
 ;.
-; CHECK: [[META0]] = !{i64 0, !"_ZTSFiPvcE.generalized"}
+; CHECK: [[META0]] = !{!"_ZTSFiPvcE.generalized"}
 ; CHECK: [[META1]] = !{[[META2:![0-9]+]]}
-; CHECK: [[META2]] = !{i64 0, !"_ZTSFicE.generalized"}
-; CHECK: [[META3]] = !{i64 0, !"_ZTSFivE.generalized"}
+; CHECK: [[META2]] = !{!"_ZTSFicE.generalized"}
+; CHECK: [[META3]] = !{!"_ZTSFivE.generalized"}
 ;.
diff --git a/llvm/test/Transforms/InstCombine/drop-callee-type-metadata.ll 
b/llvm/test/Transforms/InstCombine/drop-callee-type-metadata.ll
index 83215f78be1b0..e5296f96690f5 100644
--- a/llvm/test/Transforms/InstCombine/drop-callee-type-metadata.ll
+++ b/llvm/test/Transforms/InstCombine/drop-callee-type-metadata.ll
@@ -17,9 +17,9 @@ entry:
 
 declare !type !2 i32 @_Z3fooc(i8 signext)
 
-!0 = !{i64 0, !"_ZTSFivE.generalized"}
+!0 = !{!"_ZTSFivE.generalized"}
 !1 = !{!2}
-!2 = !{i64 0, !"_ZTSFicE.generalized"}
+!2 = !{!"_ZTSFicE.generalized"}
 ;.
-; CHECK: [[META0]] = !{i64 0, !"_ZTSFivE.generalized"}
+; CHECK: [[META0]] = !{!"_ZTSFivE.generalized"}
 ;.
diff --git a/llvm/test/Transforms/SimplifyCFG/merge-callee-type-metadata.ll 
b/llvm/test/Transforms/SimplifyCFG/merge-callee-type-metadata.ll
index 3e56939b1642f..03bfb8e31d0b9 100644
--- a/llvm/test/Transforms/SimplifyCFG/merge-callee-type-metadata.ll
+++ b/llvm/test/Transforms/SimplifyCFG/merge-callee-type-metadata.ll
@@ -150,18 +150,18 @@ if.end:                                           ; preds 
= %if.else, %if.then
 
 declare ptr @_Znwm(i64)
 
-!0 = !{i64 0, !"callee_type0.generalized"}
-!1 = !{i64 0, !"callee_type1.generalized"}
-!2 = !{i64 0, !"callee_type2.generalized"}
+!0 = !{!"callee_type0.generalized"}
+!1 = !{!"callee_type1.generalized"}
+!2 = !{!"callee_type2.generalized"}
 !3 = !{!0}
 !4 = !{!2}
 !5 = !{!1, !2}
 !6 = !{!0, !2}
 ;.
 ; CHECK: [[META0]] = !{[[META1:![0-9]+]], [[META2:![0-9]+]]}
-; CHECK: [[META1]] = !{i64 0, !"callee_type2.generalized"}
-; CHECK: [[META2]] = !{i64 0, !"callee_type0.generalized"}
+; CHECK: [[META1]] = !{!"callee_type2.generalized"}
+; CHECK: [[META2]] = !{!"callee_type0.generalized"}
 ; CHECK: [[META3]] = !{[[META2]]}
 ; CHECK: [[META4]] = !{[[META2]], [[META1]], [[META5:![0-9]+]]}
-; CHECK: [[META5]] = !{i64 0, !"callee_type1.generalized"}
+; CHECK: [[META5]] = !{!"callee_type1.generalized"}
 ;.
diff --git a/llvm/test/Verifier/callee-type-metadata.ll 
b/llvm/test/Verifier/callee-type-metadata.ll
index 50cf37b941fe9..fc19ab72678e7 100644
--- a/llvm/test/Verifier/callee-type-metadata.ll
+++ b/llvm/test/Verifier/callee-type-metadata.ll
@@ -11,14 +11,12 @@ entry:
   %x_val = load i8, ptr %x.addr, align 1  
   ; CHECK: The callee_type metadata must be a list of type metadata nodes
   %call = call i32 %fptr(i8 signext %x_val), !callee_type !0
-  ; CHECK: Well-formed generalized type metadata must contain exactly two 
operands
+  ; CHECK: The operand of type metadata for functions must be an MDString
   %call1 = call i32 %fptr(i8 signext %x_val), !callee_type !2
-  ; CHECK: The first operand of type metadata for functions must be zero
+  ; CHECK: Well-formed generalized callgraph metadata must contain exactly one 
operand
   %call2 = call i32 %fptr(i8 signext %x_val), !callee_type !4
-  ; CHECK: The first operand of type metadata for functions must be zero
-  %call3 = call i32 %fptr(i8 signext %x_val), !callee_type !6
   ; CHECK: Only generalized type metadata can be part of the callee_type 
metadata list
-  %call4 = call i32 %fptr(i8 signext %x_val), !callee_type !8
+  %call3 = call i32 %fptr(i8 signext %x_val), !callee_type !6
   ret i32 %call
 }
 
@@ -27,7 +25,5 @@ entry:
 !2 = !{!2}
 !3 = !{i64 1, !"_ZTSFicE"}
 !4 = !{!3}
-!5 = !{!"expected_int", !"_ZTSFicE"}
+!5 = !{!"_ZTSFicE"}
 !6 = !{!5}
-!7 = !{i64 0, !"_ZTSFicE"}
-!8 = !{!7}

>From e11f3403b4c6f0fc5d7bdb89b42795e5141cffe3 Mon Sep 17 00:00:00 2001
From: prabhukr <[email protected]>
Date: Thu, 18 Jun 2026 12:15:39 -0700
Subject: [PATCH 04/13] Rename type metdata to callgraph metadata in comments
 and in IR verifier messages.

---
 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp |  2 +-
 llvm/lib/IR/Verifier.cpp                   | 16 +++++++++-------
 llvm/test/Verifier/callee-type-metadata.ll |  6 +++---
 3 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp 
b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index acc3cfb0edc81..c6671a4ffef25 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -1753,7 +1753,7 @@ void AsmPrinter::emitStackUsage(const MachineFunction 
&MF) {
 }
 
 /// Extracts a generalized numeric type identifier of a Function's type from
-/// type metadata. Returns null if metadata cannot be found.
+/// callgraph metadata. Returns null if metadata cannot be found.
 static ConstantInt *extractNumericCGTypeId(const Function &F) {
   SmallVector<MDNode *, 2> Types;
   F.getMetadata(LLVMContext::MD_callgraph, Types);
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 7ab98d0b98cc5..394a50fcac204 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -5655,18 +5655,20 @@ void Verifier::visitCalleeTypeMetadata(Instruction &I, 
MDNode *MD) {
         &I);
   for (Metadata *Op : MD->operands()) {
     Check(isa<MDNode>(Op),
-          "The callee_type metadata must be a list of type metadata nodes", 
Op);
-    auto *TypeMD = cast<MDNode>(Op);
-    Check(TypeMD->getNumOperands() == 1,
+          "The callee_type metadata must be a list of callgraph metadata 
nodes",
+          Op);
+    auto *CallgraphMD = cast<MDNode>(Op);
+    Check(CallgraphMD->getNumOperands() == 1,
           "Well-formed generalized callgraph metadata must contain exactly one 
"
           "operand",
           Op);
-    Check(isa<MDString>(TypeMD->getOperand(0)),
-          "The operand of type metadata for functions must be an MDString", 
Op);
-    Check(cast<MDString>(TypeMD->getOperand(0))
+    Check(isa<MDString>(CallgraphMD->getOperand(0)),
+          "The operand of callgraph metadata for functions must be an 
MDString",
+          Op);
+    Check(cast<MDString>(CallgraphMD->getOperand(0))
               ->getString()
               .ends_with(".generalized"),
-          "Only generalized type metadata can be part of the callee_type "
+          "Only generalized callgraph metadata can be part of the callee_type "
           "metadata list",
           Op);
   }
diff --git a/llvm/test/Verifier/callee-type-metadata.ll 
b/llvm/test/Verifier/callee-type-metadata.ll
index fc19ab72678e7..e40d36ae0f234 100644
--- a/llvm/test/Verifier/callee-type-metadata.ll
+++ b/llvm/test/Verifier/callee-type-metadata.ll
@@ -9,13 +9,13 @@ entry:
   store i8 %x, ptr %x.addr, align 1
   %fptr = load ptr, ptr %func.addr, align 8
   %x_val = load i8, ptr %x.addr, align 1  
-  ; CHECK: The callee_type metadata must be a list of type metadata nodes
+  ; CHECK: The callee_type metadata must be a list of callgraph metadata nodes
   %call = call i32 %fptr(i8 signext %x_val), !callee_type !0
-  ; CHECK: The operand of type metadata for functions must be an MDString
+  ; CHECK: The operand of callgraph metadata for functions must be an MDString
   %call1 = call i32 %fptr(i8 signext %x_val), !callee_type !2
   ; CHECK: Well-formed generalized callgraph metadata must contain exactly one 
operand
   %call2 = call i32 %fptr(i8 signext %x_val), !callee_type !4
-  ; CHECK: Only generalized type metadata can be part of the callee_type 
metadata list
+  ; CHECK: Only generalized callgraph metadata can be part of the callee_type 
metadata list
   %call3 = call i32 %fptr(i8 signext %x_val), !callee_type !6
   ret i32 %call
 }

>From 6b6f002841dbc62c61ed4b2fad273c070be7663f Mon Sep 17 00:00:00 2001
From: prabhukr <[email protected]>
Date: Thu, 18 Jun 2026 12:50:41 -0700
Subject: [PATCH 05/13] fix documentation/comments and remove unused helper.

---
 clang/lib/CodeGen/CodeGenModule.h             |  6 +--
 .../CodeGen/call-graph-section-internal.cpp   |  2 +-
 llvm/docs/CalleeTypeMetadata.rst              |  7 ++--
 llvm/docs/CallgraphMetadata.rst               | 38 +++++++++++++++++++
 llvm/docs/Reference.rst                       |  1 +
 llvm/include/llvm/IR/Metadata.h               |  7 ----
 6 files changed, 47 insertions(+), 14 deletions(-)
 create mode 100644 llvm/docs/CallgraphMetadata.rst

diff --git a/clang/lib/CodeGen/CodeGenModule.h 
b/clang/lib/CodeGen/CodeGenModule.h
index 959e02924a9f7..f6f672741ca95 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -1738,11 +1738,11 @@ class CodeGenModule : public CodeGenTypeCache {
   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.
+  /// Create and attach callgraph metadata if the function is a potential
+  /// indirect call target to support call graph section.
   void createIndirectFunctionTypeMD(const FunctionDecl *FD, llvm::Function *F);
 
-  /// Create and attach type metadata to the given call.
+  /// Create and attach callee_type metadata to the given call.
   void createCalleeTypeMetadataForIcall(const QualType &QT, llvm::CallBase 
*CB);
 
   /// Set type metadata to the given function.
diff --git a/clang/test/CodeGen/call-graph-section-internal.cpp 
b/clang/test/CodeGen/call-graph-section-internal.cpp
index aea48675dfa27..923cb4ed053b0 100644
--- a/clang/test/CodeGen/call-graph-section-internal.cpp
+++ b/clang/test/CodeGen/call-graph-section-internal.cpp
@@ -2,7 +2,7 @@
 
 // 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 
+// as their callgraph metadata identifiers are distinct MDNodes instead of 
 // generalized strings, which would fail the LLVM Verifier.
 
 namespace {
diff --git a/llvm/docs/CalleeTypeMetadata.rst b/llvm/docs/CalleeTypeMetadata.rst
index 45d0657966a8c..863f3de446bf2 100644
--- a/llvm/docs/CalleeTypeMetadata.rst
+++ b/llvm/docs/CalleeTypeMetadata.rst
@@ -7,11 +7,12 @@ Introduction
 This ``!callee_type`` metadata is introduced to support the generation of a 
call graph
 section in the object file.  The ``!callee_type`` metadata is used
 to identify the types of the intended callees of indirect call instructions. 
The ``!callee_type`` metadata is a
-list of one or more generalized ``!type`` metadata objects (See 
:doc:`TypeMetadata`) with each ``!type``
+list of one or more generalized ``!callgraph`` metadata objects (See 
:doc:`CallgraphMetadata`) with each ``!callgraph``
 metadata pointing to a callee's :ref:`type identifier 
<calleetype-type-identifier>`.
-LLVM's `Control Flow Integrity (CFI)`_ also uses the ``!type`` metadata in its 
implementation.
 
-.. _Control Flow Integrity (CFI): 
https://clang.llvm.org/docs/ControlFlowIntegrity.html
+While ``!callee_type`` and ``!callgraph`` are private to the Call Graph 
Section pipeline and contain no offsets,
+LLVM's `Control Flow Integrity (CFI)`_ uses a structurally similar ``!type`` 
metadata in its implementation (See :doc:`TypeMetadata`),
+which shares the same type identifier format but includes a leading offset for 
vtable compatibility.
 
 .. _calleetype-type-identifier:
 
diff --git a/llvm/docs/CallgraphMetadata.rst b/llvm/docs/CallgraphMetadata.rst
new file mode 100644
index 0000000000000..b85fc006872e4
--- /dev/null
+++ b/llvm/docs/CallgraphMetadata.rst
@@ -0,0 +1,38 @@
+==================
+Callgraph Metadata
+==================
+
+Introduction
+============
+
+The ``!callgraph`` metadata is introduced to support the generation of a call 
graph
+section in the object file. It associates a function definition with its 
generalized
+type identifier.
+
+Syntax
+======
+
+A ``!callgraph`` metadata node is attached to a function definition as follows:
+
+.. code-block:: llvm
+
+   define void @foo() !callgraph !0
+   !0 = !{!"_ZTSFvvE.generalized"}
+
+The metadata node is a 1-element tuple containing only the generalized type 
identifier
+as an ``MDString``, without any offset.
+
+Relation to Control Flow Integrity (CFI)
+========================================
+
+While ``!callgraph`` metadata is structurally similar to LLVM's ``!type`` 
metadata
+(which is used by `Control Flow Integrity (CFI)`_ and Whole Program 
Devirtualization),
+they serve different purposes:
+
+* **!type (CFI)**: Contains an offset (e.g., ``!{i64 0, 
!"_ZTSFvvE.generalized"}``) to support virtual table offset calculations and 
devirtualization. This requires ThinLTO symbol promotion and LTO splitting.
+* **!callgraph (Call Graph Section)**: Does not contain an offset. This is 
private to the Call Graph Section pipeline and bypasses ThinLTO promotion, 
avoiding unnecessary symbol export and LTO splitting bloat.
+
+The generalized type identifier format used by both is identical. For more 
details on the
+generalized type identifier format and CFI's metadata, see :doc:`TypeMetadata` 
and :doc:`CalleeTypeMetadata`.
+
+.. _Control Flow Integrity (CFI): 
https://clang.llvm.org/docs/ControlFlowIntegrity.html
diff --git a/llvm/docs/Reference.rst b/llvm/docs/Reference.rst
index 56e367388b1a8..eb6ad28ea1bd4 100644
--- a/llvm/docs/Reference.rst
+++ b/llvm/docs/Reference.rst
@@ -56,6 +56,7 @@ LLVM and API reference documentation.
    CIBestPractices
    AIToolPolicy
    CalleeTypeMetadata
+   CallgraphMetadata
    CallGraphSection
    InterfaceExportAnnotations
    PCSectionsMetadata
diff --git a/llvm/include/llvm/IR/Metadata.h b/llvm/include/llvm/IR/Metadata.h
index b9288740a7145..73adeb3416ab1 100644
--- a/llvm/include/llvm/IR/Metadata.h
+++ b/llvm/include/llvm/IR/Metadata.h
@@ -1255,13 +1255,6 @@ class MDNode : public Metadata {
   bool isReplaceable() const { return isTemporary() || isAlwaysReplaceable(); }
   bool isAlwaysReplaceable() const { return getMetadataID() == DIAssignIDKind; 
}
 
-  /// Check if this is a valid generalized type metadata node.
-  bool hasGeneralizedMDString() {
-    if (getNumOperands() < 2 || !isa<MDString>(getOperand(1)))
-      return false;
-    return 
cast<MDString>(getOperand(1))->getString().ends_with(".generalized");
-  }
-
   unsigned getNumTemporaryUses() const {
     assert(isTemporary() && "Only for temporaries");
     return Context.getReplaceableUses()->getNumUses();

>From 59917bb79bac3317729c7f716ed27c971df8c637 Mon Sep 17 00:00:00 2001
From: prabhukr <[email protected]>
Date: Thu, 18 Jun 2026 12:53:23 -0700
Subject: [PATCH 06/13] Copy callgraph metadata during function merging.

---
 llvm/lib/Transforms/IPO/MergeFunctions.cpp    |  2 ++
 .../MergeFunc/callgraph-function-merging.ll   | 25 +++++++++++++++++++
 2 files changed, 27 insertions(+)
 create mode 100644 llvm/test/Transforms/MergeFunc/callgraph-function-merging.ll

diff --git a/llvm/lib/Transforms/IPO/MergeFunctions.cpp 
b/llvm/lib/Transforms/IPO/MergeFunctions.cpp
index ac8a21ea24320..2d4cc9b9c138e 100644
--- a/llvm/lib/Transforms/IPO/MergeFunctions.cpp
+++ b/llvm/lib/Transforms/IPO/MergeFunctions.cpp
@@ -803,6 +803,7 @@ void MergeFunctions::writeThunk(Function *F, Function *G) {
     // Ensure CFI type metadata is propagated to the new function.
     copyMetadataIfPresent(G, NewG, "type");
     copyMetadataIfPresent(G, NewG, "kcfi_type");
+    copyMetadataIfPresent(G, NewG, "callgraph");
     removeUsers(G);
     G->replaceAllUsesWith(NewG);
     G->eraseFromParent();
@@ -900,6 +901,7 @@ void MergeFunctions::mergeTwoFunctions(Function *F, 
Function *G) {
     // Ensure CFI type metadata is propagated to the new function.
     copyMetadataIfPresent(F, NewF, "type");
     copyMetadataIfPresent(F, NewF, "kcfi_type");
+    copyMetadataIfPresent(F, NewF, "callgraph");
     removeUsers(F);
     F->replaceAllUsesWith(NewF);
 
diff --git a/llvm/test/Transforms/MergeFunc/callgraph-function-merging.ll 
b/llvm/test/Transforms/MergeFunc/callgraph-function-merging.ll
new file mode 100644
index 0000000000000..0202412f62fa3
--- /dev/null
+++ b/llvm/test/Transforms/MergeFunc/callgraph-function-merging.ll
@@ -0,0 +1,25 @@
+; RUN: opt -S -passes=mergefunc < %s | FileCheck %s
+
+; Verify that !callgraph metadata is correctly preserved and copied to the new
+; thunk/backing functions when two identical functions are merged, and that
+; the metadata nodes are correctly uniqued.
+
+declare void @dummy()
+
+; CHECK: define void @func1(ptr {{.*}}) {{.*}} !callgraph [[MD:![0-9]+]] {
+; CHECK: define void @func2(ptr {{.*}}) {{.*}} !callgraph [[MD]] {
+
+define void @func1(ptr %a) unnamed_addr !callgraph !0 {
+  call void @dummy()
+  ret void
+}
+
+define void @func2(ptr %a) unnamed_addr !callgraph !1 {
+  call void @dummy()
+  ret void
+}
+
+!0 = !{!"_ZTSFvPvE.generalized"}
+!1 = !{!"_ZTSFvPvE.generalized"}
+
+; CHECK: [[MD]] = !{!"_ZTSFvPvE.generalized"}

>From 2c2d0de3d1b4306591ace5e394a76a359cba6d79 Mon Sep 17 00:00:00 2001
From: prabhukr <[email protected]>
Date: Thu, 18 Jun 2026 13:38:25 -0700
Subject: [PATCH 07/13] Fix failing tests.

---
 .../AArch64/calleetypeid-directcall-mismatched.ll      |  4 ++--
 .../AArch64/callsite-emit-calleetypeid-tailcall.ll     |  2 +-
 llvm/test/CodeGen/ARM/call-graph-section-assembly.ll   |  6 +++---
 llvm/test/CodeGen/ARM/call-graph-section.ll            |  6 +++---
 .../CodeGen/ARM/calleetypeid-directcall-mismatched.ll  |  4 ++--
 .../CodeGen/ARM/callsite-emit-calleetypeid-tailcall.ll |  2 +-
 .../CodeGen/Mips/calleetypeid-directcall-mismatched.ll | 10 +++++-----
 .../Mips/callsite-emit-calleetypeid-tailcall.ll        |  6 +++---
 llvm/test/CodeGen/Mips/callsite-emit-calleetypeid.ll   |  2 +-
 .../RISCV/calleetypeid-directcall-mismatched.ll        |  4 ++--
 .../RISCV/callsite-emit-calleetypeid-tailcall.ll       |  2 +-
 llvm/test/CodeGen/X86/call-graph-section-assembly.ll   |  6 +++---
 llvm/test/CodeGen/X86/call-graph-section.ll            |  6 +++---
 .../CodeGen/X86/calleetypeid-directcall-mismatched.ll  |  4 ++--
 .../CodeGen/X86/callsite-emit-calleetypeid-tailcall.ll |  2 +-
 15 files changed, 33 insertions(+), 33 deletions(-)

diff --git a/llvm/test/CodeGen/AArch64/calleetypeid-directcall-mismatched.ll 
b/llvm/test/CodeGen/AArch64/calleetypeid-directcall-mismatched.ll
index b0140a56dbc6a..7aae1783de2cb 100644
--- a/llvm/test/CodeGen/AArch64/calleetypeid-directcall-mismatched.ll
+++ b/llvm/test/CodeGen/AArch64/calleetypeid-directcall-mismatched.ll
@@ -7,7 +7,7 @@
 ; CHECK-NEXT: - { bb: {{[0-9]+}}, offset: {{[0-9]+}}, fwdArgRegs: [] }
 ; CHECK-NEXT: - { bb: {{[0-9]+}}, offset: {{[0-9]+}}, fwdArgRegs: [] }
 ; CHECK-NEXT: - { bb: {{[0-9]+}}, offset: {{[0-9]+}}, fwdArgRegs: [] }
-define i32 @foo(i32 %x, i32 %y) !type !0 {
+define i32 @foo(i32 %x, i32 %y) !callgraph !0 {
 entry:
   ;; Call instruction with accurate callee_type.
   ;; callee_type should be dropped seemlessly.
@@ -23,7 +23,7 @@ entry:
   ret i32 %sub
 }
 
-declare !type !2 i32 @fizz(i32, i32)
+declare !callgraph !2 i32 @fizz(i32, i32)
 
 !0 = !{!"_ZTSFiiiiE.generalized"}
 !1 = !{!2}
diff --git a/llvm/test/CodeGen/AArch64/callsite-emit-calleetypeid-tailcall.ll 
b/llvm/test/CodeGen/AArch64/callsite-emit-calleetypeid-tailcall.ll
index 44cb4bba6e4b2..780a67695a170 100644
--- a/llvm/test/CodeGen/AArch64/callsite-emit-calleetypeid-tailcall.ll
+++ b/llvm/test/CodeGen/AArch64/callsite-emit-calleetypeid-tailcall.ll
@@ -5,7 +5,7 @@
 ;; computed as the type id from the callee_type metadata.
 ; RUN: llc --call-graph-section -mtriple aarch64-linux-gnu < %s 
-stop-after=finalize-isel -o - | FileCheck --match-full-lines %s
 
-define i32 @check_tailcall(ptr %func, i8 %x) !type !0 {
+define i32 @check_tailcall(ptr %func, i8 %x) !callgraph !0 {
 entry:
   ; CHECK: callSites:
   ; CHECK-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs: [], calleeTypeIds:
diff --git a/llvm/test/CodeGen/ARM/call-graph-section-assembly.ll 
b/llvm/test/CodeGen/ARM/call-graph-section-assembly.ll
index d06b12636c7af..74000dc4337bc 100644
--- a/llvm/test/CodeGen/ARM/call-graph-section-assembly.ll
+++ b/llvm/test/CodeGen/ARM/call-graph-section-assembly.ll
@@ -6,9 +6,9 @@
 
 ; RUN: llc -mtriple=arm-unknown-linux --call-graph-section -o - < %s | 
FileCheck %s
 
-declare !type !0 void @direct_foo()
-declare !type !1 i32 @direct_bar(i8)
-declare !type !2 ptr @direct_baz(ptr)
+declare !callgraph !0 void @direct_foo()
+declare !callgraph !1 i32 @direct_bar(i8)
+declare !callgraph !2 ptr @direct_baz(ptr)
 
 ; CHECK: ball:
 define ptr @ball() {
diff --git a/llvm/test/CodeGen/ARM/call-graph-section.ll 
b/llvm/test/CodeGen/ARM/call-graph-section.ll
index 9619de4669f32..4d7b3f44b9353 100644
--- a/llvm/test/CodeGen/ARM/call-graph-section.ll
+++ b/llvm/test/CodeGen/ARM/call-graph-section.ll
@@ -3,11 +3,11 @@
 ; RUN: llc -mtriple=arm-unknown-linux --call-graph-section -filetype=obj -o - 
< %s | \
 ; RUN: llvm-readelf -x .llvm.callgraph - | FileCheck %s
 
-declare !type !0 void @foo()
+declare !callgraph !0 void @foo()
 
-declare !type !1 i32 @bar(i8)
+declare !callgraph !1 i32 @bar(i8)
 
-declare !type !2 ptr @baz(ptr)
+declare !callgraph !2 ptr @baz(ptr)
 
 define void @main() {
 entry:
diff --git a/llvm/test/CodeGen/ARM/calleetypeid-directcall-mismatched.ll 
b/llvm/test/CodeGen/ARM/calleetypeid-directcall-mismatched.ll
index 7969e904b2ffa..6a474227e2b42 100644
--- a/llvm/test/CodeGen/ARM/calleetypeid-directcall-mismatched.ll
+++ b/llvm/test/CodeGen/ARM/calleetypeid-directcall-mismatched.ll
@@ -7,7 +7,7 @@
 ; CHECK-NEXT: - { bb: {{[0-9]+}}, offset: {{[0-9]+}}, fwdArgRegs: [] }
 ; CHECK-NEXT: - { bb: {{[0-9]+}}, offset: {{[0-9]+}}, fwdArgRegs: [] }
 ; CHECK-NEXT: - { bb: {{[0-9]+}}, offset: {{[0-9]+}}, fwdArgRegs: [] }
-define i32 @foo(i32 %x, i32 %y) !type !0 {
+define i32 @foo(i32 %x, i32 %y) !callgraph !0 {
 entry:
   ;; Call instruction with accurate callee_type.
   ;; callee_type should be dropped seemlessly.
@@ -23,7 +23,7 @@ entry:
   ret i32 %sub
 }
 
-declare !type !2 i32 @fizz(i32, i32)
+declare !callgraph !2 i32 @fizz(i32, i32)
 
 !0 = !{!"_ZTSFiiiiE.generalized"}
 !1 = !{!2}
diff --git a/llvm/test/CodeGen/ARM/callsite-emit-calleetypeid-tailcall.ll 
b/llvm/test/CodeGen/ARM/callsite-emit-calleetypeid-tailcall.ll
index c5a33e61e85e0..5233da75435ab 100644
--- a/llvm/test/CodeGen/ARM/callsite-emit-calleetypeid-tailcall.ll
+++ b/llvm/test/CodeGen/ARM/callsite-emit-calleetypeid-tailcall.ll
@@ -5,7 +5,7 @@
 ;; computed as the type id from the callee_type metadata.
 ; RUN: llc --call-graph-section -mtriple arm-linux-gnu < %s 
-stop-after=finalize-isel -o - | FileCheck --match-full-lines %s
 
-define i32 @check_tailcall(ptr %func, i8 %x) !type !0 {
+define i32 @check_tailcall(ptr %func, i8 %x) !callgraph !0 {
 entry:
   ; CHECK: callSites:
   ; CHECK-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs: [], calleeTypeIds:
diff --git a/llvm/test/CodeGen/Mips/calleetypeid-directcall-mismatched.ll 
b/llvm/test/CodeGen/Mips/calleetypeid-directcall-mismatched.ll
index a66a884dc844e..1a1bc63b24a97 100644
--- a/llvm/test/CodeGen/Mips/calleetypeid-directcall-mismatched.ll
+++ b/llvm/test/CodeGen/Mips/calleetypeid-directcall-mismatched.ll
@@ -7,7 +7,7 @@
 ; CHECK-NEXT: - { bb: {{[0-9]+}}, offset: {{[0-9]+}}, fwdArgRegs: [] }
 ; CHECK-NEXT: - { bb: {{[0-9]+}}, offset: {{[0-9]+}}, fwdArgRegs: [] }
 ; CHECK-NEXT: - { bb: {{[0-9]+}}, offset: {{[0-9]+}}, fwdArgRegs: [] }
-define i32 @foo(i32 %x, i32 %y) !type !0 {
+define i32 @foo(i32 %x, i32 %y) !callgraph !0 {
 entry:
   ;; Call instruction with accurate callee_type.
   ;; callee_type should be dropped seemlessly.
@@ -23,10 +23,10 @@ entry:
   ret i32 %sub
 }
 
-declare !type !2 i32 @fizz(i32, i32)
+declare !callgraph !2 i32 @fizz(i32, i32)
 
-!0 = !{i64 0, !"_ZTSFiiiiE.generalized"}
+!0 = !{!"_ZTSFiiiiE.generalized"}
 !1 = !{!2}
-!2 = !{i64 0, !"_ZTSFiiiE.generalized"}
+!2 = !{!"_ZTSFiiiE.generalized"}
 !3 = !{!4}
-!4 = !{i64 0, !"_ZTSFicE.generalized"}
+!4 = !{!"_ZTSFicE.generalized"}
diff --git a/llvm/test/CodeGen/Mips/callsite-emit-calleetypeid-tailcall.ll 
b/llvm/test/CodeGen/Mips/callsite-emit-calleetypeid-tailcall.ll
index e7f162c6daa77..efe2fb91a85fa 100644
--- a/llvm/test/CodeGen/Mips/callsite-emit-calleetypeid-tailcall.ll
+++ b/llvm/test/CodeGen/Mips/callsite-emit-calleetypeid-tailcall.ll
@@ -5,7 +5,7 @@
 ;; computed as the type id from the callee_type metadata.
 ; RUN: llc --call-graph-section -mtriple=mips-linux-gnu < %s 
-stop-after=finalize-isel -o - | FileCheck --match-full-lines %s
 
-define i32 @check_tailcall(ptr %func, i8 %x) !type !0 {
+define i32 @check_tailcall(ptr %func, i8 %x) !callgraph !0 {
 entry:
   ; CHECK: callSites:
   ; CHECK-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs: [], calleeTypeIds:
@@ -14,6 +14,6 @@ entry:
   ret i32 %call
 }
 
-!0 = !{i64 0, !"_ZTSFiPvcE.generalized"}
+!0 = !{!"_ZTSFiPvcE.generalized"}
 !1 = !{!2}
-!2 = !{i64 0, !"_ZTSFicE.generalized"}
+!2 = !{!"_ZTSFicE.generalized"}
diff --git a/llvm/test/CodeGen/Mips/callsite-emit-calleetypeid.ll 
b/llvm/test/CodeGen/Mips/callsite-emit-calleetypeid.ll
index 9f5e858412ed6..1b0c885bb8e44 100644
--- a/llvm/test/CodeGen/Mips/callsite-emit-calleetypeid.ll
+++ b/llvm/test/CodeGen/Mips/callsite-emit-calleetypeid.ll
@@ -17,4 +17,4 @@ entry:
 }
 
 !0 = !{!1}
-!1 = !{i64 0, !"_ZTSFvcE.generalized"}
+!1 = !{!"_ZTSFvcE.generalized"}
diff --git a/llvm/test/CodeGen/RISCV/calleetypeid-directcall-mismatched.ll 
b/llvm/test/CodeGen/RISCV/calleetypeid-directcall-mismatched.ll
index e2c191fa03e27..9bdb6cef6714f 100644
--- a/llvm/test/CodeGen/RISCV/calleetypeid-directcall-mismatched.ll
+++ b/llvm/test/CodeGen/RISCV/calleetypeid-directcall-mismatched.ll
@@ -8,7 +8,7 @@
 ; CHECK-NEXT: - { bb: {{[0-9]+}}, offset: {{[0-9]+}}, fwdArgRegs: [] }
 ; CHECK-NEXT: - { bb: {{[0-9]+}}, offset: {{[0-9]+}}, fwdArgRegs: [] }
 ; CHECK-NEXT: - { bb: {{[0-9]+}}, offset: {{[0-9]+}}, fwdArgRegs: [] }
-define i32 @foo(i32 %x, i32 %y) !type !0 {
+define i32 @foo(i32 %x, i32 %y) !callgraph !0 {
 entry:
   ;; Call instruction with accurate callee_type.
   ;; callee_type should be dropped seemlessly.
@@ -24,7 +24,7 @@ entry:
   ret i32 %sub
 }
 
-declare !type !2 i32 @fizz(i32, i32)
+declare !callgraph !2 i32 @fizz(i32, i32)
 
 !0 = !{!"_ZTSFiiiiE.generalized"}
 !1 = !{!2}
diff --git a/llvm/test/CodeGen/RISCV/callsite-emit-calleetypeid-tailcall.ll 
b/llvm/test/CodeGen/RISCV/callsite-emit-calleetypeid-tailcall.ll
index 337820875b9df..5b17a8a56664c 100644
--- a/llvm/test/CodeGen/RISCV/callsite-emit-calleetypeid-tailcall.ll
+++ b/llvm/test/CodeGen/RISCV/callsite-emit-calleetypeid-tailcall.ll
@@ -6,7 +6,7 @@
 ; RUN: llc --call-graph-section -mtriple riscv64 < %s 
-stop-after=finalize-isel -o - | FileCheck --match-full-lines %s
 ; RUN: llc --call-graph-section -mtriple riscv32 < %s 
-stop-after=finalize-isel -o - | FileCheck --match-full-lines %s
 
-define i32 @check_tailcall(ptr %func, i8 %x) !type !0 {
+define i32 @check_tailcall(ptr %func, i8 %x) !callgraph !0 {
 entry:
   ; CHECK: callSites:
   ; CHECK-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs: [], calleeTypeIds:
diff --git a/llvm/test/CodeGen/X86/call-graph-section-assembly.ll 
b/llvm/test/CodeGen/X86/call-graph-section-assembly.ll
index 7d85ddee24fa1..38e2c9cbc3b47 100644
--- a/llvm/test/CodeGen/X86/call-graph-section-assembly.ll
+++ b/llvm/test/CodeGen/X86/call-graph-section-assembly.ll
@@ -6,9 +6,9 @@
 
 ; RUN: llc -mtriple=x86_64-unknown-linux --call-graph-section -o - < %s | 
FileCheck %s
 
-declare !type !0 void @direct_foo()
-declare !type !1 i32 @direct_bar(i8)
-declare !type !2 ptr @direct_baz(ptr)
+declare !callgraph !0 void @direct_foo()
+declare !callgraph !1 i32 @direct_bar(i8)
+declare !callgraph !2 ptr @direct_baz(ptr)
 
 ; CHECK: ball:
 define ptr @ball() {
diff --git a/llvm/test/CodeGen/X86/call-graph-section.ll 
b/llvm/test/CodeGen/X86/call-graph-section.ll
index fec66ea5da588..2f08b0edc9ebf 100644
--- a/llvm/test/CodeGen/X86/call-graph-section.ll
+++ b/llvm/test/CodeGen/X86/call-graph-section.ll
@@ -6,11 +6,11 @@
 ; RUN: llc -mtriple=x86_64-unknown-linux --call-graph-section -filetype=obj -o 
- < %s | \
 ; RUN: llvm-readelf -x .llvm.callgraph - | FileCheck %s
 
-declare !type !0 void @foo()
+declare !callgraph !0 void @foo()
 
-declare !type !1 i32 @bar(i8)
+declare !callgraph !1 i32 @bar(i8)
 
-declare !type !2 ptr @baz(ptr)
+declare !callgraph !2 ptr @baz(ptr)
 
 define void @main() {
 entry:
diff --git a/llvm/test/CodeGen/X86/calleetypeid-directcall-mismatched.ll 
b/llvm/test/CodeGen/X86/calleetypeid-directcall-mismatched.ll
index 05edbfd649415..92d783055d3ba 100644
--- a/llvm/test/CodeGen/X86/calleetypeid-directcall-mismatched.ll
+++ b/llvm/test/CodeGen/X86/calleetypeid-directcall-mismatched.ll
@@ -7,7 +7,7 @@
 ; CHECK-NEXT: - { bb: {{[0-9]+}}, offset: {{[0-9]+}}, fwdArgRegs: [] }
 ; CHECK-NEXT: - { bb: {{[0-9]+}}, offset: {{[0-9]+}}, fwdArgRegs: [] }
 ; CHECK-NEXT: - { bb: {{[0-9]+}}, offset: {{[0-9]+}}, fwdArgRegs: [] }
-define i32 @foo(i32 %x, i32 %y) !type !0 {
+define i32 @foo(i32 %x, i32 %y) !callgraph !0 {
 entry:
   ;; Call instruction with accurate callee_type.
   ;; callee_type should be dropped seemlessly.
@@ -23,7 +23,7 @@ entry:
   ret i32 %sub
 }
 
-declare !type !2 i32 @fizz(i32, i32)
+declare !callgraph !2 i32 @fizz(i32, i32)
 
 !0 = !{!"_ZTSFiiiiE.generalized"}
 !1 = !{!2}
diff --git a/llvm/test/CodeGen/X86/callsite-emit-calleetypeid-tailcall.ll 
b/llvm/test/CodeGen/X86/callsite-emit-calleetypeid-tailcall.ll
index 9a868db8e4297..91fc652c8b05e 100644
--- a/llvm/test/CodeGen/X86/callsite-emit-calleetypeid-tailcall.ll
+++ b/llvm/test/CodeGen/X86/callsite-emit-calleetypeid-tailcall.ll
@@ -5,7 +5,7 @@
 ;; computed as the type id from the callee_type metadata.
 ; RUN: llc --call-graph-section -mtriple=x86_64-unknown-linux < %s 
-stop-after=finalize-isel -o - | FileCheck --match-full-lines %s
 
-define i32 @check_tailcall(ptr %func, i8 %x) !type !0 {
+define i32 @check_tailcall(ptr %func, i8 %x) !callgraph !0 {
 entry:
   ; CHECK: callSites:
   ; CHECK-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs: [], calleeTypeIds:

>From 790f9cf8e65bf4c956b69c5036d02395dd4335c1 Mon Sep 17 00:00:00 2001
From: prabhukr <[email protected]>
Date: Thu, 18 Jun 2026 13:47:57 -0700
Subject: [PATCH 08/13] Fix docs builder failure

---
 llvm/docs/CalleeTypeMetadata.rst | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/llvm/docs/CalleeTypeMetadata.rst b/llvm/docs/CalleeTypeMetadata.rst
index 863f3de446bf2..89fba989beb3b 100644
--- a/llvm/docs/CalleeTypeMetadata.rst
+++ b/llvm/docs/CalleeTypeMetadata.rst
@@ -32,3 +32,5 @@ To avoid mismatched pointer types, generalizations are 
applied.
 Pointers in return and argument types are treated as equivalent as long as the 
qualifiers for the 
 type they point to match. For example, ``char*``, ``char**``, and ``int*`` are 
considered equivalent
 types. However, ``char*`` and ``const char*`` are considered distinct types.
+
+.. _Control Flow Integrity (CFI): 
https://clang.llvm.org/docs/ControlFlowIntegrity.html

>From 0f65063123c075143bd7cbb1380d17a4914743b3 Mon Sep 17 00:00:00 2001
From: prabhukr <[email protected]>
Date: Tue, 23 Jun 2026 13:13:35 -0700
Subject: [PATCH 09/13] Modify callgraph doc introduction as suggested.

---
 llvm/docs/CallgraphMetadata.rst | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/llvm/docs/CallgraphMetadata.rst b/llvm/docs/CallgraphMetadata.rst
index b85fc006872e4..a9bb2857a1773 100644
--- a/llvm/docs/CallgraphMetadata.rst
+++ b/llvm/docs/CallgraphMetadata.rst
@@ -5,9 +5,10 @@ Callgraph Metadata
 Introduction
 ============
 
-The ``!callgraph`` metadata is introduced to support the generation of a call 
graph
-section in the object file. It associates a function definition with its 
generalized
-type identifier.
+The ``!callgraph`` metadata associates a function definition with its type 
identifier.
+It uses the same generalized type encoding as the `!type` metadata used for 
CFI and
+WPD, and allows us to emit a call graph section in the object file that can be 
used to
+compute a conservative and precise static call graph in a linked binary.
 
 Syntax
 ======

>From 9d7c59dbda97894c34091b48271e924d3f07f857 Mon Sep 17 00:00:00 2001
From: prabhukr <[email protected]>
Date: Tue, 23 Jun 2026 13:25:58 -0700
Subject: [PATCH 10/13] Move from rst to md file for documentation.

---
 llvm/docs/CallgraphMetadata.md  | 31 ++++++++++++++++++++++++++
 llvm/docs/CallgraphMetadata.rst | 39 ---------------------------------
 2 files changed, 31 insertions(+), 39 deletions(-)
 create mode 100644 llvm/docs/CallgraphMetadata.md
 delete mode 100644 llvm/docs/CallgraphMetadata.rst

diff --git a/llvm/docs/CallgraphMetadata.md b/llvm/docs/CallgraphMetadata.md
new file mode 100644
index 0000000000000..ab14da149d99d
--- /dev/null
+++ b/llvm/docs/CallgraphMetadata.md
@@ -0,0 +1,31 @@
+# Callgraph Metadata
+
+## Introduction
+
+The `!callgraph` metadata associates a function definition with its type 
identifier.
+It uses the same generalized type encoding as the `!type` metadata used for 
CFI and
+WPD, and allows us to emit a call graph section in the object file that can be 
used to
+compute a conservative and precise static call graph in a linked binary.
+
+## Syntax
+
+A `!callgraph` metadata node is attached to a function definition as follows:
+
+```llvm
+define void @foo() !callgraph !0
+!0 = !{!"_ZTSFvvE.generalized"}
+```
+
+The metadata node is a 1-element tuple containing only the generalized type 
identifier as `MDString`.
+
+## Relation to Control Flow Integrity (CFI)
+
+While `!callgraph` metadata is structurally similar to LLVM's `!type` metadata
+(which is used by [Control Flow Integrity 
(CFI)](https://clang.llvm.org/docs/ControlFlowIntegrity.html) and Whole Program 
Devirtualization),
+they serve different purposes:
+
+* **!type (CFI)**: Contains an offset (e.g., `!{i64 0, 
!"_ZTSFvvE.generalized"}`) to support virtual table offset calculations and 
devirtualization.
+* **!callgraph (Call Graph Section)**: Does not contain an offset. This is 
private to the Call Graph Section pipeline.
+
+The generalized type identifier format used by both is identical. For more 
details on the
+generalized type identifier format and CFI's metadata, see [](TypeMetadata) 
and [](CalleeTypeMetadata).
diff --git a/llvm/docs/CallgraphMetadata.rst b/llvm/docs/CallgraphMetadata.rst
deleted file mode 100644
index a9bb2857a1773..0000000000000
--- a/llvm/docs/CallgraphMetadata.rst
+++ /dev/null
@@ -1,39 +0,0 @@
-==================
-Callgraph Metadata
-==================
-
-Introduction
-============
-
-The ``!callgraph`` metadata associates a function definition with its type 
identifier.
-It uses the same generalized type encoding as the `!type` metadata used for 
CFI and
-WPD, and allows us to emit a call graph section in the object file that can be 
used to
-compute a conservative and precise static call graph in a linked binary.
-
-Syntax
-======
-
-A ``!callgraph`` metadata node is attached to a function definition as follows:
-
-.. code-block:: llvm
-
-   define void @foo() !callgraph !0
-   !0 = !{!"_ZTSFvvE.generalized"}
-
-The metadata node is a 1-element tuple containing only the generalized type 
identifier
-as an ``MDString``, without any offset.
-
-Relation to Control Flow Integrity (CFI)
-========================================
-
-While ``!callgraph`` metadata is structurally similar to LLVM's ``!type`` 
metadata
-(which is used by `Control Flow Integrity (CFI)`_ and Whole Program 
Devirtualization),
-they serve different purposes:
-
-* **!type (CFI)**: Contains an offset (e.g., ``!{i64 0, 
!"_ZTSFvvE.generalized"}``) to support virtual table offset calculations and 
devirtualization. This requires ThinLTO symbol promotion and LTO splitting.
-* **!callgraph (Call Graph Section)**: Does not contain an offset. This is 
private to the Call Graph Section pipeline and bypasses ThinLTO promotion, 
avoiding unnecessary symbol export and LTO splitting bloat.
-
-The generalized type identifier format used by both is identical. For more 
details on the
-generalized type identifier format and CFI's metadata, see :doc:`TypeMetadata` 
and :doc:`CalleeTypeMetadata`.
-
-.. _Control Flow Integrity (CFI): 
https://clang.llvm.org/docs/ControlFlowIntegrity.html

>From 3df84d6513362f6e7f18ebfc78a1c6252da4fad5 Mon Sep 17 00:00:00 2001
From: prabhukr <[email protected]>
Date: Tue, 23 Jun 2026 13:43:54 -0700
Subject: [PATCH 11/13] Add release notes for callgraph metadata IR change.

---
 llvm/docs/ReleaseNotes.md | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index df4ced91e8f5e..8302dc228dad1 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -97,6 +97,11 @@ Makes programs 10x faster by doing Special New Thing.
 * The ``modular-format`` attribute now supports the ``fixed`` aspect for C
   ISO 18037 fixed-point ``printf`` specifiers.
 
+* Added support for ``callgraph`` metadata. The `!callgraph` metadata
+  associates a function definition with its type identifier and used for call
+  graph section generation. See [CallgraphMetadata](CallgraphMetadata.md) for
+  details.
+
 ### Changes to LLVM infrastructure
 
 * Removed ``Constant::isZeroValue``. It was functionally identical to

>From eb69d791e2ed14644fdf0729f9a6c83f977d1109 Mon Sep 17 00:00:00 2001
From: prabhukr <[email protected]>
Date: Tue, 23 Jun 2026 13:52:47 -0700
Subject: [PATCH 12/13] Remove changes from Reference.rst file

---
 llvm/docs/Reference.rst | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/docs/Reference.rst b/llvm/docs/Reference.rst
index eb6ad28ea1bd4..56e367388b1a8 100644
--- a/llvm/docs/Reference.rst
+++ b/llvm/docs/Reference.rst
@@ -56,7 +56,6 @@ LLVM and API reference documentation.
    CIBestPractices
    AIToolPolicy
    CalleeTypeMetadata
-   CallgraphMetadata
    CallGraphSection
    InterfaceExportAnnotations
    PCSectionsMetadata

>From e4d28bc599dc2e2d16eee9bb51723af18a57e454 Mon Sep 17 00:00:00 2001
From: prabhukr <[email protected]>
Date: Tue, 23 Jun 2026 13:56:13 -0700
Subject: [PATCH 13/13] Move changes from reference.rst to reference.md after
 merging with upstream main branch.

---
 llvm/docs/Reference.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/llvm/docs/Reference.md b/llvm/docs/Reference.md
index cddcc9056128d..90d43a23ed70c 100644
--- a/llvm/docs/Reference.md
+++ b/llvm/docs/Reference.md
@@ -56,6 +56,7 @@ ContentAddressableStorage
 CIBestPractices
 AIToolPolicy
 CalleeTypeMetadata
+CallgraphMetadata
 CallGraphSection
 InterfaceExportAnnotations
 PCSectionsMetadata

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to