[llvm] [llvm][AsmPrinter] Add direct calls to callgraph section (PR #155706)

Prabhu Rajasekaran via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 28 13:49:01 PDT 2025


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

>From eb26a3bdf9bfba33531d9c48f6080946b148f03a Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Wed, 27 Aug 2025 22:11:28 +0000
Subject: [PATCH 1/5] [llvm][AsmPrinter] Add direct calls to callgraph section

Extend CallGraphSection to include metadata about direct calls. This
simplifies the design of tools that must parse .callgraph section to not
require dependency on MC layer.
---
 llvm/include/llvm/CodeGen/AsmPrinter.h     |  1 +
 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 37 ++++++++++++++++++++--
 2 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index 91c014236f6cb..e139eb7010dc5 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -214,6 +214,7 @@ class LLVM_ABI AsmPrinter : public MachineFunctionPass {
     /// Map type identifiers to callsite labels. Labels are generated for each
     /// indirect callsite in the function.
     SmallVector<std::pair<CGTypeId, MCSymbol *>> CallSiteLabels;
+    SmallVector<std::pair<MCSymbol *, MCSymbol *>> DirectCallSiteLabels;
   };
 
   enum CallGraphSectionFormatVersion : uint64_t {
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 1641c3eb535a9..4fe082481cbb0 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -78,6 +78,7 @@
 #include "llvm/IR/GlobalValue.h"
 #include "llvm/IR/GlobalVariable.h"
 #include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
 #include "llvm/IR/Mangler.h"
 #include "llvm/IR/Metadata.h"
 #include "llvm/IR/Module.h"
@@ -1733,6 +1734,14 @@ void AsmPrinter::emitCallGraphSection(const MachineFunction &MF,
   }
   FuncInfo.CallSiteLabels.clear();
 
+  const auto &DirectCallSiteLabels = FuncInfo.DirectCallSiteLabels;
+  OutStreamer->emitInt64(DirectCallSiteLabels.size());
+  for (const auto &[CallSiteAddrLabel, CalleeSymbol] : DirectCallSiteLabels) {
+    OutStreamer->emitSymbolValue(CallSiteAddrLabel, TM.getProgramPointerSize());
+    OutStreamer->emitSymbolValue(CalleeSymbol, TM.getProgramPointerSize());
+  }
+  FuncInfo.DirectCallSiteLabels.clear();
+
   OutStreamer->popSection();
 }
 
@@ -1872,9 +1881,28 @@ void AsmPrinter::emitIndirectCalleeLabels(
     const MachineInstr &MI) {
   // Only indirect calls have type identifiers set.
   const auto &CallSiteInfo = CallSitesInfoMap.find(&MI);
-  if (CallSiteInfo == CallSitesInfoMap.end())
+
+  // Handle direct callsite info
+  if (CallSiteInfo == CallSitesInfoMap.end()) {
+    const MachineOperand &CalleeOperand = MI.getOperand(0);
+    MCSymbol *CalleeSymbol = nullptr;
+    switch (CalleeOperand.getType()) {
+    case llvm::MachineOperand::MO_GlobalAddress:
+      CalleeSymbol = getSymbol(CalleeOperand.getGlobal());
+      break;
+    case llvm::MachineOperand::MO_ExternalSymbol:
+      CalleeSymbol = GetExternalSymbolSymbol(CalleeOperand.getSymbolName());
+      break;
+    default:
+      llvm_unreachable("Expect only direct call instructions to be handled.");
+    }
+    MCSymbol *S = MF->getContext().createTempSymbol();
+    OutStreamer->emitLabel(S);
+    FuncInfo.DirectCallSiteLabels.emplace_back(S, CalleeSymbol);
     return;
+  }
 
+  // Handle indirect callsite info.
   for (ConstantInt *CalleeTypeId : CallSiteInfo->second.CalleeTypeIds) {
     MCSymbol *S = MF->getContext().createTempSymbol();
     OutStreamer->emitLabel(S);
@@ -2064,8 +2092,13 @@ void AsmPrinter::emitFunctionBody() {
         break;
       }
 
-      if (TM.Options.EmitCallGraphSection && MI.isCall())
+      if (TM.Options.EmitCallGraphSection && MI.isCall()) {
+        llvm::outs() << "Dump MI for calls \n";
+        MI.dump();
+        llvm::outs() << "CallSitesInfoMap.size() " << CallSitesInfoMap.size()
+                     << "\n";
         emitIndirectCalleeLabels(FuncInfo, CallSitesInfoMap, MI);
+      }
 
       // If there is a post-instruction symbol, emit a label for it here.
       if (MCSymbol *S = MI.getPostInstrSymbol())

>From 2f4443a26926a7f02bff8c5c25831f128506bb15 Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Wed, 27 Aug 2025 22:15:59 +0000
Subject: [PATCH 2/5] Remove debug prints

---
 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 4fe082481cbb0..d4cbd8ff7e450 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -2093,10 +2093,6 @@ void AsmPrinter::emitFunctionBody() {
       }
 
       if (TM.Options.EmitCallGraphSection && MI.isCall()) {
-        llvm::outs() << "Dump MI for calls \n";
-        MI.dump();
-        llvm::outs() << "CallSitesInfoMap.size() " << CallSitesInfoMap.size()
-                     << "\n";
         emitIndirectCalleeLabels(FuncInfo, CallSitesInfoMap, MI);
       }
 

>From f3abc2f1faf93c65b0316214633131b1e585090d Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Wed, 27 Aug 2025 22:22:04 +0000
Subject: [PATCH 3/5] Rename AsmPrinter method name.

---
 llvm/include/llvm/CodeGen/AsmPrinter.h     | 10 +++++-----
 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp |  7 +++----
 2 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index e139eb7010dc5..2a4655e80a4c8 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -386,12 +386,12 @@ class LLVM_ABI AsmPrinter : public MachineFunctionPass {
   /// are available. Returns empty string otherwise.
   StringRef getConstantSectionSuffix(const Constant *C) const;
 
-  /// Generate and emit labels for callees of the indirect callsites which will
+  /// Generate and emit labels for callees of all callsites which will
   /// be used to populate the .callgraph section.
-  void emitIndirectCalleeLabels(
-      FunctionInfo &FuncInfo,
-      const MachineFunction::CallSiteInfoMap &CallSitesInfoMap,
-      const MachineInstr &MI);
+  void
+  emitCalleeLabels(FunctionInfo &FuncInfo,
+                   const MachineFunction::CallSiteInfoMap &CallSitesInfoMap,
+                   const MachineInstr &MI);
 
   //===------------------------------------------------------------------===//
   // XRay instrumentation implementation.
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index d4cbd8ff7e450..fdf548bb5b33b 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -1875,7 +1875,7 @@ static StringRef getMIMnemonic(const MachineInstr &MI, MCStreamer &Streamer) {
   return Name;
 }
 
-void AsmPrinter::emitIndirectCalleeLabels(
+void AsmPrinter::emitCalleeLabels(
     FunctionInfo &FuncInfo,
     const MachineFunction::CallSiteInfoMap &CallSitesInfoMap,
     const MachineInstr &MI) {
@@ -2092,9 +2092,8 @@ void AsmPrinter::emitFunctionBody() {
         break;
       }
 
-      if (TM.Options.EmitCallGraphSection && MI.isCall()) {
-        emitIndirectCalleeLabels(FuncInfo, CallSitesInfoMap, MI);
-      }
+      if (TM.Options.EmitCallGraphSection && MI.isCall())
+        emitCalleeLabels(FuncInfo, CallSitesInfoMap, MI);
 
       // If there is a post-instruction symbol, emit a label for it here.
       if (MCSymbol *S = MI.getPostInstrSymbol())

>From b76c9adad9804d77c45a5af0f50376c5e7698438 Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Thu, 28 Aug 2025 18:21:36 +0000
Subject: [PATCH 4/5] Cleanup callsite label generation function

---
 llvm/include/llvm/CodeGen/AsmPrinter.h     |  8 ++---
 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 36 +++++++++++-----------
 2 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index 2a4655e80a4c8..89333348232b0 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -388,10 +388,10 @@ class LLVM_ABI AsmPrinter : public MachineFunctionPass {
 
   /// Generate and emit labels for callees of all callsites which will
   /// be used to populate the .callgraph section.
-  void
-  emitCalleeLabels(FunctionInfo &FuncInfo,
-                   const MachineFunction::CallSiteInfoMap &CallSitesInfoMap,
-                   const MachineInstr &MI);
+  void emitCallsiteLabelsForCallgraph(
+      FunctionInfo &FuncInfo,
+      const MachineFunction::CallSiteInfoMap &CallSitesInfoMap,
+      const MachineInstr &MI);
 
   //===------------------------------------------------------------------===//
   // XRay instrumentation implementation.
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index fdf548bb5b33b..4319e8a15c193 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -1875,16 +1875,14 @@ static StringRef getMIMnemonic(const MachineInstr &MI, MCStreamer &Streamer) {
   return Name;
 }
 
-void AsmPrinter::emitCalleeLabels(
+void AsmPrinter::emitCallsiteLabelsForCallgraph(
     FunctionInfo &FuncInfo,
     const MachineFunction::CallSiteInfoMap &CallSitesInfoMap,
     const MachineInstr &MI) {
-  // Only indirect calls have type identifiers set.
-  const auto &CallSiteInfo = CallSitesInfoMap.find(&MI);
-
-  // Handle direct callsite info
-  if (CallSiteInfo == CallSitesInfoMap.end()) {
-    const MachineOperand &CalleeOperand = MI.getOperand(0);
+  assert(MI.isCall() && "Callsite labels are meant for call instruction only.");
+  const MachineOperand &CalleeOperand = MI.getOperand(0);
+  if (CalleeOperand.isGlobal() || CalleeOperand.isSymbol()) {
+    // Handle direct calls.
     MCSymbol *CalleeSymbol = nullptr;
     switch (CalleeOperand.getType()) {
     case llvm::MachineOperand::MO_GlobalAddress:
@@ -1894,20 +1892,22 @@ void AsmPrinter::emitCalleeLabels(
       CalleeSymbol = GetExternalSymbolSymbol(CalleeOperand.getSymbolName());
       break;
     default:
-      llvm_unreachable("Expect only direct call instructions to be handled.");
+      llvm_unreachable(
+          "Expected to only handle direct call instructions here.");
     }
     MCSymbol *S = MF->getContext().createTempSymbol();
     OutStreamer->emitLabel(S);
     FuncInfo.DirectCallSiteLabels.emplace_back(S, CalleeSymbol);
-    return;
-  }
-
-  // Handle indirect callsite info.
-  for (ConstantInt *CalleeTypeId : CallSiteInfo->second.CalleeTypeIds) {
-    MCSymbol *S = MF->getContext().createTempSymbol();
-    OutStreamer->emitLabel(S);
-    uint64_t CalleeTypeIdVal = CalleeTypeId->getZExtValue();
-    FuncInfo.CallSiteLabels.emplace_back(CalleeTypeIdVal, S);
+  } else {
+    // Handle indirect callsite info.
+    // Only indirect calls have type identifiers set.
+    const auto &CallSiteInfo = CallSitesInfoMap.find(&MI);
+    for (ConstantInt *CalleeTypeId : CallSiteInfo->second.CalleeTypeIds) {
+      MCSymbol *S = MF->getContext().createTempSymbol();
+      OutStreamer->emitLabel(S);
+      uint64_t CalleeTypeIdVal = CalleeTypeId->getZExtValue();
+      FuncInfo.CallSiteLabels.emplace_back(CalleeTypeIdVal, S);
+    }
   }
 }
 
@@ -2093,7 +2093,7 @@ void AsmPrinter::emitFunctionBody() {
       }
 
       if (TM.Options.EmitCallGraphSection && MI.isCall())
-        emitCalleeLabels(FuncInfo, CallSitesInfoMap, MI);
+        emitCallsiteLabelsForCallgraph(FuncInfo, CallSitesInfoMap, MI);
 
       // If there is a post-instruction symbol, emit a label for it here.
       if (MCSymbol *S = MI.getPostInstrSymbol())

>From bffbeb1514e36bcd8df9d1511a46e8cab6950776 Mon Sep 17 00:00:00 2001
From: prabhukr <prabhukr at google.com>
Date: Thu, 28 Aug 2025 20:47:53 +0000
Subject: [PATCH 5/5] Add tests for callgraph direct call sites info

---
 .../X86/call-graph-section-assembly.ll        | 27 ++++++++++++++++---
 1 file changed, 24 insertions(+), 3 deletions(-)

diff --git a/llvm/test/CodeGen/X86/call-graph-section-assembly.ll b/llvm/test/CodeGen/X86/call-graph-section-assembly.ll
index 11362873fb151..950e2f0bdd17a 100644
--- a/llvm/test/CodeGen/X86/call-graph-section-assembly.ll
+++ b/llvm/test/CodeGen/X86/call-graph-section-assembly.ll
@@ -1,9 +1,16 @@
-;; Test if temporary labels are generated for each indirect callsite with a callee_type metadata.
-;; Test if the .callgraph section contains the MD5 hash of callee type ids generated from
-;; generalized type id strings.
+;; Test if temporary labels are generated for each callsite.
+;; Test if the .callgraph section contains the MD5 hash of callees' type (type id)
+;; is correctly paired with its corresponding temporary label generated for indirect
+;; call sites annotated with !callee_type metadata.
+;; Test if the .callgraph section contains direct callsite temporary labels paired
+;; correctly with the corresponding callee symbol.
 
 ; 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)
+
 ; CHECK: ball:
 ; CHECK-NEXT: [[LABEL_FUNC:\.Lfunc_begin[0-9]+]]:
 define ptr @ball() {
@@ -11,12 +18,18 @@ entry:
   %fp_foo_val = load ptr, ptr null, align 8
    ; CHECK: [[LABEL_TMP0:\.L.*]]:
   call void (...) %fp_foo_val(), !callee_type !0
+   ; CHECK: [[LABEL_TMP_DIRECT0:\.L.*]]:
+  call void @direct_foo()
   %fp_bar_val = load ptr, ptr null, align 8
   ; CHECK: [[LABEL_TMP1:\.L.*]]:
   %call_fp_bar = call i32 %fp_bar_val(i8 0), !callee_type !2
+  ; CHECK: [[LABEL_TMP_DIRECT1:\.L.*]]:
+  %call_fp_bar_direct = call i32 @direct_bar(i8 1)
   %fp_baz_val = load ptr, ptr null, align 8
   ; CHECK: [[LABEL_TMP2:\.L.*]]:
   %call_fp_baz = call ptr %fp_baz_val(ptr null), !callee_type !4
+  ; CHECK: [[LABEL_TMP_DIRECT2:\.L.*]]:
+  %call_fp_baz_direct = call ptr @direct_baz(ptr null)
   ret ptr %call_fp_baz
 }
 
@@ -41,3 +54,11 @@ entry:
 ;; Test for MD5 hash of _ZTSFPvS_E.generalized and the generated temporary callsite label.
 ; CHECK-NEXT: .quad   8646233951371320954
 ; CHECK-NEXT: .quad   [[LABEL_TMP2]]
+;; Test for number of direct calls and {callsite_label, callee} pairs.
+; CHECK-NEXT: .quad	3
+; CHECK-NEXT: .quad	[[LABEL_TMP_DIRECT0]]
+; CHECK-NEXT: .quad	direct_foo
+; CHECK-NEXT: .quad	[[LABEL_TMP_DIRECT1]]
+; CHECK-NEXT: .quad	direct_bar
+; CHECK-NEXT: .quad	[[LABEL_TMP_DIRECT2]]
+; CHECK-NEXT: .quad	direct_baz



More information about the llvm-commits mailing list