[llvm] 6fb87b2 - [llvm][AsmPrinter] Call graph section format. (#159866)

via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 10 12:20:15 PDT 2025


Author: Prabhu Rajasekaran
Date: 2025-10-10T12:20:11-07:00
New Revision: 6fb87b231f59e0e9df061cecec53aa746c838e92

URL: https://github.com/llvm/llvm-project/commit/6fb87b231f59e0e9df061cecec53aa746c838e92
DIFF: https://github.com/llvm/llvm-project/commit/6fb87b231f59e0e9df061cecec53aa746c838e92.diff

LOG: [llvm][AsmPrinter] Call graph section format. (#159866)

Make .callgraph section's layout efficient in space. Document the layout
of the section.

Added: 
    llvm/docs/CallGraphSection.md
    llvm/test/CodeGen/ARM/call-graph-section-addrtaken.ll
    llvm/test/CodeGen/ARM/call-graph-section-assembly.ll
    llvm/test/CodeGen/ARM/call-graph-section-tailcall.ll
    llvm/test/CodeGen/ARM/call-graph-section.ll
    llvm/test/CodeGen/X86/call-graph-section-addrtaken.ll

Modified: 
    llvm/docs/CodeGenerator.rst
    llvm/docs/Reference.rst
    llvm/include/llvm/CodeGen/AsmPrinter.h
    llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
    llvm/test/CodeGen/X86/call-graph-section-assembly.ll
    llvm/test/CodeGen/X86/call-graph-section-tailcall.ll
    llvm/test/CodeGen/X86/call-graph-section.ll

Removed: 
    


################################################################################
diff  --git a/llvm/docs/CallGraphSection.md b/llvm/docs/CallGraphSection.md
new file mode 100644
index 0000000000000..8b18727098545
--- /dev/null
+++ b/llvm/docs/CallGraphSection.md
@@ -0,0 +1,18 @@
+# .callgraph Section Layout
+
+The `.callgraph` section is used to store call graph information for each function. The section contains a series of records, with each record corresponding to a single function.
+
+## Per Function Record Layout
+
+Each record in the `.callgraph` section has the following binary layout:
+
+| Field                                  | Type          | Size (bits) | Description                                                                                             |
+| -------------------------------------- | ------------- | ----------- | ------------------------------------------------------------------------------------------------------- |
+| Format Version                         | `uint8_t`     | 8           | The version of the record format. The current version is 0.                                             |
+| Flags                                  | `uint8_t`     | 8           | A bitfield where: Bit 0 is set if the function is a potential indirect call target; Bit 1 is set if there are direct callees; Bit 2 is set if there are indirect callees. The remaining 5 bits are reserved. |
+| Function Entry PC                      | `uintptr_t`   | 32/64       | The address of the function's entry point.                                                              |
+| Function Type ID                       | `uint64_t`    | 64          | The type ID of the function. This field is non-zero if the function is a potential indirect call target and its type is known. |
+| Number of Unique Direct Callees        | `ULEB128`     | Variable    | The number of unique direct call destinations from this function. This field is only present if there is at least one direct callee. |
+| Direct Callees Array                   | `uintptr_t[]` | Variable    | An array of unique direct callee entry point addresses. This field is only present if there is at least one direct callee. |
+| Number of Unique Indirect Target Type IDs| `ULEB128`     | Variable    | The number of unique indirect call target type IDs. This field is only present if there is at least one indirect target type ID. |
+| Indirect Target Type IDs Array         | `uint64_t[]`  | Variable    | An array of unique indirect call target type IDs. This field is only present if there is at least one indirect target type ID. |

diff  --git a/llvm/docs/CodeGenerator.rst b/llvm/docs/CodeGenerator.rst
index 7486054b55c9f..fc704a3cdd51f 100644
--- a/llvm/docs/CodeGenerator.rst
+++ b/llvm/docs/CodeGenerator.rst
@@ -1662,6 +1662,13 @@ and stack sizes (unsigned LEB128). The stack size values only include the space
 allocated in the function prologue. Functions with dynamic stack allocations are
 not included.
 
+Emitting function call graph information
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A section containing metadata on function call graph will be emitted when
+``TargetOptions::EmitCallGraphSection`` is set (--call-graph-section). Layout of
+this section is documented in detail at :doc:`CallGraphSection`.
+
 VLIW Packetizer
 ---------------
 

diff  --git a/llvm/docs/Reference.rst b/llvm/docs/Reference.rst
index 5d842d339f8c9..9b1bf1be9c8bf 100644
--- a/llvm/docs/Reference.rst
+++ b/llvm/docs/Reference.rst
@@ -15,6 +15,7 @@ LLVM and API reference documentation.
    BranchWeightMetadata
    Bugpoint
    CalleeTypeMetadata
+   CallGraphSection
    CIBestPractices
    CommandGuide/index
    ContentAddressableStorage

diff  --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index 4c744a2c0a4d2..19ca44429af4d 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -198,26 +198,13 @@ class LLVM_ABI AsmPrinter : public MachineFunctionPass {
     /// and targets.
     using CGTypeId = uint64_t;
 
-    /// Map type identifiers to callsite labels. Labels are generated for each
-    /// indirect callsite in the function.
-    SmallVector<std::pair<CGTypeId, MCSymbol *>> CallSiteLabels;
+    /// Unique target type IDs.
+    SmallSet<CGTypeId, 4> IndirectCalleeTypeIDs;
+    /// Unique direct callees.
     SmallSet<MCSymbol *, 4> DirectCallees;
   };
 
-  /// Enumeration of function kinds, and their mapping to function kind values
-  /// stored in callgraph section entries.
-  enum class FunctionKind : uint64_t {
-    /// Function cannot be target to indirect calls.
-    NOT_INDIRECT_TARGET = 0,
-
-    /// Function may be target to indirect calls but its type id is unknown.
-    INDIRECT_TARGET_UNKNOWN_TID = 1,
-
-    /// Function may be target to indirect calls and its type id is known.
-    INDIRECT_TARGET_KNOWN_TID = 2,
-  };
-
-  enum CallGraphSectionFormatVersion : uint64_t {
+  enum CallGraphSectionFormatVersion : uint8_t {
     V_0 = 0,
   };
 
@@ -386,9 +373,9 @@ class LLVM_ABI AsmPrinter : public MachineFunctionPass {
   /// are available. Returns empty string otherwise.
   StringRef getConstantSectionSuffix(const Constant *C) const;
 
-  /// Iff MI is an indirect call, generate and emit a label after the callsites
-  /// which will be used to populate the .callgraph section. For direct
-  /// callsites add the callee symbol to direct callsites list of FuncCGInfo.
+  /// If MI is an indirect call, add expected type IDs to indirect type ids
+  /// list. If MI is a direct call add the callee symbol to direct callsites
+  /// list of FuncCGInfo.
   void handleCallsiteForCallgraph(
       FunctionCallGraphInfo &FuncCGInfo,
       const MachineFunction::CallSiteInfoMap &CallSitesInfoMap,

diff  --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 10df9c1f97eae..219bbc9d5cdd4 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -20,6 +20,7 @@
 #include "WinException.h"
 #include "llvm/ADT/APFloat.h"
 #include "llvm/ADT/APInt.h"
+#include "llvm/ADT/BitmaskEnum.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
@@ -205,6 +206,17 @@ class AddrLabelMapCallbackPtr final : CallbackVH {
 };
 } // namespace
 
+namespace callgraph {
+LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
+enum Flags : uint8_t {
+  None = 0,
+  IsIndirectTarget = 1u << 0,
+  HasDirectCallees = 1u << 1,
+  HasIndirectCallees = 1u << 2,
+  LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue*/ HasIndirectCallees)
+};
+} // namespace callgraph
+
 class llvm::AddrLabelMap {
   MCContext &Context;
   struct AddrLabelSymEntry {
@@ -1683,63 +1695,65 @@ void AsmPrinter::emitCallGraphSection(const MachineFunction &MF,
   OutStreamer->pushSection();
   OutStreamer->switchSection(FuncCGSection);
 
-  // Emit format version number.
-  OutStreamer->emitInt64(CallGraphSectionFormatVersion::V_0);
-
-  // Emit function's self information, which is composed of:
-  //  1) FunctionEntryPc
-  //  2) FunctionKind: Whether the function is indirect target, and if so,
-  //     whether its type id is known.
-  //  3) FunctionTypeId: Emit only when the function is an indirect target
-  //     and its type id is known.
-
-  // Emit function entry pc.
   const MCSymbol *FunctionSymbol = getFunctionBegin();
-  OutStreamer->emitSymbolValue(FunctionSymbol, TM.getProgramPointerSize());
-
+  const Function &F = MF.getFunction();
   // If this function has external linkage or has its address taken and
   // it is not a callback, then anything could call it.
-  const Function &F = MF.getFunction();
   bool IsIndirectTarget =
       !F.hasLocalLinkage() || F.hasAddressTaken(nullptr,
                                                 /*IgnoreCallbackUses=*/true,
                                                 /*IgnoreAssumeLikeCalls=*/true,
                                                 /*IgnoreLLVMUsed=*/false);
 
-  // FIXME: FunctionKind takes a few values but emitted as a 64-bit value.
-  // Can be optimized to occupy 2 bits instead.
-  // Emit function kind, and type id if available.
-  if (!IsIndirectTarget) {
-    OutStreamer->emitInt64(
-        static_cast<uint64_t>(FunctionKind::NOT_INDIRECT_TARGET));
-  } else {
-    if (const auto *TypeId = extractNumericCGTypeId(F)) {
-      OutStreamer->emitInt64(
-          static_cast<uint64_t>(FunctionKind::INDIRECT_TARGET_KNOWN_TID));
-      OutStreamer->emitInt64(TypeId->getZExtValue());
-    } else {
-      OutStreamer->emitInt64(
-          static_cast<uint64_t>(FunctionKind::INDIRECT_TARGET_UNKNOWN_TID));
-    }
-  }
+  const auto &DirectCallees = FuncCGInfo.DirectCallees;
+  const auto &IndirectCalleeTypeIDs = FuncCGInfo.IndirectCalleeTypeIDs;
+
+  using namespace callgraph;
+  Flags CGFlags = Flags::None;
+  if (IsIndirectTarget)
+    CGFlags |= Flags::IsIndirectTarget;
+  if (DirectCallees.size() > 0)
+    CGFlags |= Flags::HasDirectCallees;
+  if (IndirectCalleeTypeIDs.size() > 0)
+    CGFlags |= Flags::HasIndirectCallees;
+
+  // Emit function's call graph information.
+  // 1) CallGraphSectionFormatVersion
+  // 2) Flags
+  //    a. LSB bit 0 is set to 1 if the function is a potential indirect
+  //       target.
+  //    b. LSB bit 1 is set to 1 if there are direct callees.
+  //    c. LSB bit 2 is set to 1 if there are indirect callees.
+  //    d. Rest of the 5 bits in Flags are reserved for any future use.
+  // 3) Function entry PC.
+  // 4) FunctionTypeID if the function is indirect target and its type id
+  //    is known, otherwise it is set to 0.
+  // 5) Number of unique direct callees, if at least one exists.
+  // 6) For each unique direct callee, the callee's PC.
+  // 7) Number of unique indirect target type IDs, if at least one exists.
+  // 8) Each unique indirect target type id.
+  OutStreamer->emitInt8(CallGraphSectionFormatVersion::V_0);
+  OutStreamer->emitInt8(static_cast<uint8_t>(CGFlags));
+  OutStreamer->emitSymbolValue(FunctionSymbol, TM.getProgramPointerSize());
+  const auto *TypeId = extractNumericCGTypeId(F);
+  if (IsIndirectTarget && TypeId)
+    OutStreamer->emitInt64(TypeId->getZExtValue());
+  else
+    OutStreamer->emitInt64(0);
 
-  // Emit callsite labels, where each element is a pair of type id and
-  // indirect callsite pc.
-  const auto &CallSiteLabels = FuncCGInfo.CallSiteLabels;
-  OutStreamer->emitInt64(CallSiteLabels.size());
-  for (const auto &[TypeId, Label] : CallSiteLabels) {
-    OutStreamer->emitInt64(TypeId);
-    OutStreamer->emitSymbolValue(Label, TM.getProgramPointerSize());
+  if (DirectCallees.size() > 0) {
+    OutStreamer->emitULEB128IntValue(DirectCallees.size());
+    for (const auto &CalleeSymbol : DirectCallees)
+      OutStreamer->emitSymbolValue(CalleeSymbol, TM.getProgramPointerSize());
+    FuncCGInfo.DirectCallees.clear();
   }
-  FuncCGInfo.CallSiteLabels.clear();
-
-  const auto &DirectCallees = FuncCGInfo.DirectCallees;
-  OutStreamer->emitInt64(DirectCallees.size());
-  for (const auto &CalleeSymbol : DirectCallees) {
-    OutStreamer->emitSymbolValue(CalleeSymbol, TM.getProgramPointerSize());
+  if (IndirectCalleeTypeIDs.size() > 0) {
+    OutStreamer->emitULEB128IntValue(IndirectCalleeTypeIDs.size());
+    for (const auto &CalleeTypeId : IndirectCalleeTypeIDs)
+      OutStreamer->emitInt64(CalleeTypeId);
+    FuncCGInfo.IndirectCalleeTypeIDs.clear();
   }
-  FuncCGInfo.DirectCallees.clear();
-
+  // End of emitting call graph section contents.
   OutStreamer->popSection();
 }
 
@@ -1877,8 +1891,7 @@ void AsmPrinter::handleCallsiteForCallgraph(
     FunctionCallGraphInfo &FuncCGInfo,
     const MachineFunction::CallSiteInfoMap &CallSitesInfoMap,
     const MachineInstr &MI) {
-  assert(MI.isCall() &&
-         "Callsite labels are meant for call instructions only.");
+  assert(MI.isCall() && "This method is meant for call instructions only.");
   const MachineOperand &CalleeOperand = MI.getOperand(0);
   if (CalleeOperand.isGlobal() || CalleeOperand.isSymbol()) {
     // Handle direct calls.
@@ -1903,10 +1916,8 @@ void AsmPrinter::handleCallsiteForCallgraph(
   // Handle indirect callsite info.
   // Only indirect calls have type identifiers set.
   for (ConstantInt *CalleeTypeId : CallSiteInfo->second.CalleeTypeIds) {
-    MCSymbol *S = MF->getContext().createTempSymbol();
-    OutStreamer->emitLabel(S);
     uint64_t CalleeTypeIdVal = CalleeTypeId->getZExtValue();
-    FuncCGInfo.CallSiteLabels.emplace_back(CalleeTypeIdVal, S);
+    FuncCGInfo.IndirectCalleeTypeIDs.insert(CalleeTypeIdVal);
   }
 }
 

diff  --git a/llvm/test/CodeGen/ARM/call-graph-section-addrtaken.ll b/llvm/test/CodeGen/ARM/call-graph-section-addrtaken.ll
new file mode 100644
index 0000000000000..a2d6ca9cd6bb5
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/call-graph-section-addrtaken.ll
@@ -0,0 +1,39 @@
+;; Test if a potential indirect call target function which has internal linkage and
+;; address taken has its type ID emitted to callgraph section.
+;; This test also makes sure that callback functions which meet the above constraint
+;; are handled correctly.
+
+; RUN: llc -mtriple=arm-unknown-linux --call-graph-section -o - < %s | FileCheck %s
+
+declare !type !0 void @_Z6doWorkPFviE(ptr)
+
+define i32 @_Z4testv() !type !1 {
+entry:
+  call void @_Z6doWorkPFviE(ptr nonnull @_ZL10myCallbacki)
+  ret i32 0
+}
+
+; CHECK: _ZL10myCallbacki:
+; CHECK-NEXT: [[LABEL_FUNC:\.Lfunc_begin[0-9]+]]:
+define internal void @_ZL10myCallbacki(i32 %value) !type !2 {
+entry:
+  %sink = alloca i32, align 4
+  store volatile i32 %value, ptr %sink, align 4
+  %i1 = load volatile i32, ptr %sink, align 4
+  ret void
+}
+
+!0 = !{i64 0, !"_ZTSFvPFviEE.generalized"}
+!1 = !{i64 0, !"_ZTSFivE.generalized"}
+!2 = !{i64 0, !"_ZTSFviE.generalized"}
+
+; CHECK: .section .callgraph,"o",%progbits,.text
+;; Version
+; CHECK-NEXT: .byte   0
+;; Flags -- Potential indirect target so LSB is set to 1. Other bits are 0.
+; CHECK-NEXT: .byte   1
+;; Function Entry PC
+; CHECK-NEXT: .long   [[LABEL_FUNC]]
+;; Function type ID -5212364466660467813
+; CHECK-NEXT: .long	1154849691
+; CHECK-NEXT: .long	3081369122

diff  --git a/llvm/test/CodeGen/ARM/call-graph-section-assembly.ll b/llvm/test/CodeGen/ARM/call-graph-section-assembly.ll
new file mode 100644
index 0000000000000..bf5249eb6c208
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/call-graph-section-assembly.ll
@@ -0,0 +1,63 @@
+;; Test if temporary labels are generated for each indirect 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 unique direct callees.
+
+; 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)
+
+; CHECK: ball:
+; CHECK-NEXT: [[LABEL_FUNC:\.Lfunc_begin[0-9]+]]:
+define ptr @ball() {
+entry:
+  call void @direct_foo()
+  %fp_foo_val = load ptr, ptr null, align 8   
+  call void (...) %fp_foo_val(), !callee_type !0   
+  call void @direct_foo()
+  %fp_bar_val = load ptr, ptr null, align 8  
+  %call_fp_bar = call i32 %fp_bar_val(i8 0), !callee_type !2  
+  %call_fp_bar_direct = call i32 @direct_bar(i8 1)
+  %fp_baz_val = load ptr, ptr null, align 8
+  %call_fp_baz = call ptr %fp_baz_val(ptr null), !callee_type !4
+  call void @direct_foo()
+  %call_fp_baz_direct = call ptr @direct_baz(ptr null)
+  call void @direct_foo()
+  ret ptr %call_fp_baz
+}
+
+!0 = !{!1}
+!1 = !{i64 0, !"_ZTSFvE.generalized"}
+!2 = !{!3}
+!3 = !{i64 0, !"_ZTSFicE.generalized"}
+!4 = !{!5}
+!5 = !{i64 0, !"_ZTSFPvS_E.generalized"}
+
+; CHECK: .section .callgraph,"o",%progbits,.text
+;; Version
+; CHECK-NEXT: .byte   0
+;; Flags
+; CHECK-NEXT: .byte   7
+;; Function Entry PC
+; CHECK-NEXT: .long   [[LABEL_FUNC]]
+;; Function type ID -- set to 0 as no type metadata attached to function.
+; CHECK-NEXT: .long   0
+; CHECK-NEXT: .long   0
+;; Number of unique direct callees.
+; CHECK-NEXT: .byte	  3
+;; Direct callees.
+; CHECK-NEXT: .long	direct_foo
+; CHECK-NEXT: .long	direct_bar
+; CHECK-NEXT: .long	direct_baz
+;; Number of unique indirect target type IDs.
+; CHECK-NEXT: .byte   3
+;; Indirect type IDs.
+; CHECK-NEXT: .long 838288420
+; CHECK-NEXT: .long 1053552373
+; CHECK-NEXT: .long 1505527380
+; CHECK-NEXT: .long 814631809
+; CHECK-NEXT: .long 342417018
+; CHECK-NEXT: .long 2013108216

diff  --git a/llvm/test/CodeGen/ARM/call-graph-section-tailcall.ll b/llvm/test/CodeGen/ARM/call-graph-section-tailcall.ll
new file mode 100644
index 0000000000000..d5776030a8564
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/call-graph-section-tailcall.ll
@@ -0,0 +1,34 @@
+;; Tests that we store the type identifiers in .callgraph section of the object file for tailcalls.
+
+; RUN: llc -mtriple=arm-unknown-linux --call-graph-section -filetype=obj -o - < %s | \
+; RUN: llvm-readelf -x .callgraph - | FileCheck %s
+
+define i32 @check_tailcall(ptr %func, i8 %x) !type !0 {
+entry:
+  %call = tail call i32 %func(i8 signext %x), !callee_type !1
+  ret i32 %call
+}
+
+define i32 @main(i32 %argc) !type !3 {
+entry:
+  %andop = and i32 %argc, 1
+  %cmp = icmp eq i32 %andop, 0
+  %foo.bar = select i1 %cmp, ptr @foo, ptr @bar
+  %call.i = tail call i32 %foo.bar(i8 signext 97), !callee_type !1
+  ret i32 %call.i
+}
+
+declare !type !2 i32 @foo(i8 signext)
+
+declare !type !2 i32 @bar(i8 signext)
+
+!0 = !{i64 0, !"_ZTSFiPvcE.generalized"}
+!1 = !{!2}
+!2 = !{i64 0, !"_ZTSFicE.generalized"}
+!3 = !{i64 0, !"_ZTSFiiE.generalized"}
+
+; CHECK:      Hex dump of section '.callgraph':
+; CHECK-NEXT: 0x00000000 00050000 00008e19 0b7f3326 e3000154
+; CHECK-NEXT: 0x00000010 86bc5981 4b8e3000 05100000 00a150b8
+;; Verify that the type id 0x308e4b8159bc8654 is in section.
+; CHECK-NEXT: 0x00000020 3e0cfe3c b2015486 bc59814b 8e30

diff  --git a/llvm/test/CodeGen/ARM/call-graph-section.ll b/llvm/test/CodeGen/ARM/call-graph-section.ll
new file mode 100644
index 0000000000000..928a1067c81e4
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/call-graph-section.ll
@@ -0,0 +1,37 @@
+;; Tests that we store the type identifiers in .callgraph section of the object file.
+
+; RUN: llc -mtriple=arm-unknown-linux --call-graph-section -filetype=obj -o - < %s | \
+; RUN: llvm-readelf -x .callgraph - | FileCheck %s
+
+declare !type !0 void @foo()
+
+declare !type !1 i32 @bar(i8)
+
+declare !type !2 ptr @baz(ptr)
+
+define void @main() {
+entry:
+  %fp_foo_val = load ptr, ptr null, align 8
+  call void (...) %fp_foo_val(), !callee_type !1
+  %fp_bar_val = load ptr, ptr null, align 8
+  %call_fp_bar = call i32 %fp_bar_val(i8 0), !callee_type !3
+  %fp_baz_val = load ptr, ptr null, align 8
+  %call_fp_baz = call ptr %fp_baz_val(ptr null), !callee_type !4
+  ret void
+}
+
+;; Check that the numeric type id (md5 hash) for the below type ids are emitted
+;; to the callgraph section.
+!0 = !{i64 0, !"_ZTSFvE.generalized"}
+!1 = !{!0}
+!2 = !{i64 0, !"_ZTSFicE.generalized"}
+!3 = !{!2}
+!4 = !{!5}
+!5 = !{i64 0, !"_ZTSFPvS_E.generalized"}
+
+;; Make sure following type IDs are in call graph section
+;; 0x5eecb3e2444f731f, 0x814b8e305486bc59, 0xf897fd777ade6814
+; CHECK: Hex dump of section '.callgraph':
+; CHECK-NEXT: 0x00000000 00050000 00000000 00000000 00000324
+; CHECK-NEXT: 0x00000010 44f731f5 eecb3e54 86bc5981 4b8e307a
+; CHECK-NEXT: 0x00000020 de6814f8 97fd77

diff  --git a/llvm/test/CodeGen/X86/call-graph-section-addrtaken.ll b/llvm/test/CodeGen/X86/call-graph-section-addrtaken.ll
new file mode 100644
index 0000000000000..2aea9c1dde1c5
--- /dev/null
+++ b/llvm/test/CodeGen/X86/call-graph-section-addrtaken.ll
@@ -0,0 +1,38 @@
+;; Test if a potential indirect call target function which has internal linkage and
+;; address taken has its type ID emitted to callgraph section.
+;; This test also makes sure that callback functions which meet the above constraint
+;; are handled correctly.
+
+; RUN: llc -mtriple=x86_64-unknown-linux --call-graph-section -o - < %s | FileCheck %s
+
+declare !type !0 void @_Z6doWorkPFviE(ptr)
+
+define i32 @_Z4testv() !type !1 {
+entry:
+  call void @_Z6doWorkPFviE(ptr nonnull @_ZL10myCallbacki)
+  ret i32 0
+}
+
+; CHECK: _ZL10myCallbacki:
+; CHECK-NEXT: [[LABEL_FUNC:\.Lfunc_begin[0-9]+]]:
+define internal void @_ZL10myCallbacki(i32 %value) !type !2 {
+entry:
+  %sink = alloca i32, align 4
+  store volatile i32 %value, ptr %sink, align 4
+  %i1 = load volatile i32, ptr %sink, align 4
+  ret void
+}
+
+!0 = !{i64 0, !"_ZTSFvPFviEE.generalized"}
+!1 = !{i64 0, !"_ZTSFivE.generalized"}
+!2 = !{i64 0, !"_ZTSFviE.generalized"}
+
+; CHECK: .section .callgraph,"o", at progbits,.text
+;; Version
+; CHECK-NEXT: .byte   0
+;; Flags -- Potential indirect target so LSB is set to 1. Other bits are 0.
+; CHECK-NEXT: .byte   1
+;; Function Entry PC
+; CHECK-NEXT: .quad   [[LABEL_FUNC]]
+;; Function type ID
+; CHECK-NEXT: .quad   -5212364466660467813

diff  --git a/llvm/test/CodeGen/X86/call-graph-section-assembly.ll b/llvm/test/CodeGen/X86/call-graph-section-assembly.ll
index f0dbc31222c89..1aabf66d471c8 100644
--- a/llvm/test/CodeGen/X86/call-graph-section-assembly.ll
+++ b/llvm/test/CodeGen/X86/call-graph-section-assembly.ll
@@ -15,16 +15,13 @@ declare !type !2 ptr @direct_baz(ptr)
 define ptr @ball() {
 entry:
   call void @direct_foo()
-  %fp_foo_val = load ptr, ptr null, align 8
-   ; CHECK: [[LABEL_TMP0:\.L.*]]:
+  %fp_foo_val = load ptr, ptr null, align 8   
   call void (...) %fp_foo_val(), !callee_type !0   
   call void @direct_foo()
-  %fp_bar_val = load ptr, ptr null, align 8
-  ; CHECK: [[LABEL_TMP1:\.L.*]]:
+  %fp_bar_val = load ptr, ptr null, align 8  
   %call_fp_bar = call i32 %fp_bar_val(i8 0), !callee_type !2  
   %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
   call void @direct_foo()
   %call_fp_baz_direct = call ptr @direct_baz(ptr null)
@@ -32,29 +29,31 @@ entry:
   ret ptr %call_fp_baz
 }
 
-; CHECK: .section .callgraph,"o", at progbits,.text
-
-; CHECK-NEXT: .quad   0
-; CHECK-NEXT: .quad   [[LABEL_FUNC]]
-; CHECK-NEXT: .quad   1
-; CHECK-NEXT: .quad   3
 !0 = !{!1}
 !1 = !{i64 0, !"_ZTSFvE.generalized"}
-;; Test for MD5 hash of _ZTSFvE.generalized and the generated temporary callsite label.
-; CHECK-NEXT: .quad   4524972987496481828
-; CHECK-NEXT: .quad   [[LABEL_TMP0]]
 !2 = !{!3}
 !3 = !{i64 0, !"_ZTSFicE.generalized"}
-;; Test for MD5 hash of _ZTSFicE.generalized and the generated temporary callsite label.
-; CHECK-NEXT: .quad   3498816979441845844
-; CHECK-NEXT: .quad   [[LABEL_TMP1]]
 !4 = !{!5}
 !5 = !{i64 0, !"_ZTSFPvS_E.generalized"}
-;; 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: .section .callgraph,"o", at progbits,.text
+;; Version
+; CHECK-NEXT: .byte   0
+;; Flags
+; CHECK-NEXT: .byte   7
+;; Function Entry PC
+; CHECK-NEXT: .quad   [[LABEL_FUNC]]
+;; Function type ID -- set to 0 as no type metadata attached to function.
+; CHECK-NEXT: .quad   0
+;; Number of unique direct callees.
+; CHECK-NEXT: .byte	  3
+;; Direct callees.
 ; CHECK-NEXT: .quad	direct_foo
 ; CHECK-NEXT: .quad	direct_bar
 ; CHECK-NEXT: .quad	direct_baz
+;; Number of unique indirect target type IDs.
+; CHECK-NEXT: .byte   3
+;; Indirect type IDs.
+; CHECK-NEXT: .quad   4524972987496481828
+; CHECK-NEXT: .quad   3498816979441845844
+; CHECK-NEXT: .quad   8646233951371320954

diff  --git a/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll b/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll
index fa14a98008b45..34dc5b831de6d 100644
--- a/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll
+++ b/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll
@@ -22,13 +22,14 @@ declare !type !2 i32 @foo(i8 signext)
 
 declare !type !2 i32 @bar(i8 signext)
 
-;; Check that the numeric type id (md5 hash) for the below type ids are emitted
-;; to the callgraph section.
-
-; CHECK: Hex dump of section '.callgraph':
-
 !0 = !{i64 0, !"_ZTSFiPvcE.generalized"}
 !1 = !{!2}
-; CHECK-DAG: 5486bc59 814b8e30
 !2 = !{i64 0, !"_ZTSFicE.generalized"}
 !3 = !{i64 0, !"_ZTSFiiE.generalized"}
+
+; CHECK: Hex dump of section '.callgraph':
+; CHECK-NEXT: 0x00000000 00050000 00000000 00008e19 0b7f3326
+; CHECK-NEXT: 0x00000010 e3000154 86bc5981 4b8e3000 05000000
+;; Verify that the type id 0x308e4b8159bc8654 is in section.
+; CHECK-NEXT: 0x00000020 00000000 00a150b8 3e0cfe3c b2015486
+; CHECK-NEXT: 0x00000030 bc59814b 8e30

diff  --git a/llvm/test/CodeGen/X86/call-graph-section.ll b/llvm/test/CodeGen/X86/call-graph-section.ll
index 66d009cf1221d..c144a24439725 100644
--- a/llvm/test/CodeGen/X86/call-graph-section.ll
+++ b/llvm/test/CodeGen/X86/call-graph-section.ll
@@ -22,15 +22,16 @@ entry:
 
 ;; Check that the numeric type id (md5 hash) for the below type ids are emitted
 ;; to the callgraph section.
-
-; CHECK: Hex dump of section '.callgraph':
-
-; CHECK-DAG: 2444f731 f5eecb3e
 !0 = !{i64 0, !"_ZTSFvE.generalized"}
 !1 = !{!0}
-; CHECK-DAG: 5486bc59 814b8e30
 !2 = !{i64 0, !"_ZTSFicE.generalized"}
 !3 = !{!2}
-; CHECK-DAG: 7ade6814 f897fd77
 !4 = !{!5}
 !5 = !{i64 0, !"_ZTSFPvS_E.generalized"}
+
+;; Make sure following type IDs are in call graph section
+;; 0x5eecb3e2444f731f, 0x814b8e305486bc59, 0xf897fd777ade6814
+; CHECK:      Hex dump of section '.callgraph':
+; CHECK-NEXT: 0x00000000 00050000 00000000 00000000 00000000
+; CHECK-NEXT: 0x00000010 00000324 44f731f5 eecb3e54 86bc5981
+; CHECK-NEXT: 0x00000020 4b8e307a de6814f8 97fd77


        


More information about the llvm-commits mailing list