[llvm] [SHT_LLVM_BB_ADDR_MAP] Encode and decode callsite offsets in a newly-introduced SHT_LLVM_BB_ADDR_MAP version. (PR #144426)

Rahman Lavaee via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 17 16:51:39 PDT 2025


https://github.com/rlavaee updated https://github.com/llvm/llvm-project/pull/144426

>From 0b2502822555c9ea7a7b0fff3976553bf0d87f39 Mon Sep 17 00:00:00 2001
From: Rahman Lavaee <rahmanl at google.com>
Date: Mon, 16 Jun 2025 18:59:42 +0000
Subject: [PATCH] Introduce the new SHT_LLVM_BB_ADDR_MAP version 3, to allow
 encoding callsite offsets.

---
 llvm/include/llvm/Object/ELFTypes.h           | 22 +++--
 llvm/include/llvm/ObjectYAML/ELFYAML.h        | 21 +++++
 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp    |  7 +-
 llvm/lib/Object/ELF.cpp                       | 33 ++++++-
 llvm/lib/ObjectYAML/ELFEmitter.cpp            | 13 ++-
 llvm/lib/ObjectYAML/ELFYAML.cpp               |  1 +
 .../tools/llvm-readobj/ELF/bb-addr-map.test   | 10 +-
 llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml | 30 +++---
 llvm/test/tools/yaml2obj/ELF/bb-addr-map.yaml | 48 +++++++---
 llvm/tools/llvm-readobj/ELFDumper.cpp         |  2 +
 llvm/tools/obj2yaml/elf2yaml.cpp              | 14 ++-
 llvm/unittests/Object/ELFObjectFileTest.cpp   | 94 ++++++++++++-------
 llvm/unittests/Object/ELFTypesTest.cpp        | 31 +++---
 13 files changed, 230 insertions(+), 96 deletions(-)

diff --git a/llvm/include/llvm/Object/ELFTypes.h b/llvm/include/llvm/Object/ELFTypes.h
index 87e4dbe448091..d7a468f1116d7 100644
--- a/llvm/include/llvm/Object/ELFTypes.h
+++ b/llvm/include/llvm/Object/ELFTypes.h
@@ -831,6 +831,7 @@ struct BBAddrMap {
     bool BrProb : 1;
     bool MultiBBRange : 1;
     bool OmitBBEntries : 1;
+    bool CallsiteOffsets : 1;
 
     bool hasPGOAnalysis() const { return FuncEntryCount || BBFreq || BrProb; }
 
@@ -842,7 +843,8 @@ struct BBAddrMap {
              (static_cast<uint8_t>(BBFreq) << 1) |
              (static_cast<uint8_t>(BrProb) << 2) |
              (static_cast<uint8_t>(MultiBBRange) << 3) |
-             (static_cast<uint8_t>(OmitBBEntries) << 4);
+             (static_cast<uint8_t>(OmitBBEntries) << 4) |
+             (static_cast<uint8_t>(CallsiteOffsets) << 5);
     }
 
     // Decodes from minimum bit width representation and validates no
@@ -851,7 +853,7 @@ struct BBAddrMap {
       Features Feat{
           static_cast<bool>(Val & (1 << 0)), static_cast<bool>(Val & (1 << 1)),
           static_cast<bool>(Val & (1 << 2)), static_cast<bool>(Val & (1 << 3)),
-          static_cast<bool>(Val & (1 << 4))};
+          static_cast<bool>(Val & (1 << 4)), static_cast<bool>(Val & (1 << 5))};
       if (Feat.encode() != Val)
         return createStringError(
             std::error_code(), "invalid encoding for BBAddrMap::Features: 0x%x",
@@ -861,9 +863,10 @@ struct BBAddrMap {
 
     bool operator==(const Features &Other) const {
       return std::tie(FuncEntryCount, BBFreq, BrProb, MultiBBRange,
-                      OmitBBEntries) ==
+                      OmitBBEntries, CallsiteOffsets) ==
              std::tie(Other.FuncEntryCount, Other.BBFreq, Other.BrProb,
-                      Other.MultiBBRange, Other.OmitBBEntries);
+                      Other.MultiBBRange, Other.OmitBBEntries,
+                      Other.CallsiteOffsets);
     }
   };
 
@@ -914,13 +917,18 @@ struct BBAddrMap {
     uint32_t Size = 0;   // Size of the basic block.
     Metadata MD = {false, false, false, false,
                    false}; // Metdata for this basic block.
+    // Offsets of callsites (end of call instructions), relative to the basic
+    // block start.
+    SmallVector<uint32_t, 1> CallsiteOffsets;
 
-    BBEntry(uint32_t ID, uint32_t Offset, uint32_t Size, Metadata MD)
-        : ID(ID), Offset(Offset), Size(Size), MD(MD){};
+    BBEntry(uint32_t ID, uint32_t Offset, uint32_t Size, Metadata MD,
+            SmallVector<uint32_t, 1> CallsiteOffsets)
+        : ID(ID), Offset(Offset), Size(Size), MD(MD),
+          CallsiteOffsets(std::move(CallsiteOffsets)) {}
 
     bool operator==(const BBEntry &Other) const {
       return ID == Other.ID && Offset == Other.Offset && Size == Other.Size &&
-             MD == Other.MD;
+             MD == Other.MD && CallsiteOffsets == Other.CallsiteOffsets;
     }
 
     bool hasReturn() const { return MD.HasReturn; }
diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h
index dfdfa055d65fa..27feb9a3eb892 100644
--- a/llvm/include/llvm/ObjectYAML/ELFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h
@@ -162,6 +162,13 @@ struct BBAddrMapEntry {
     llvm::yaml::Hex64 AddressOffset;
     llvm::yaml::Hex64 Size;
     llvm::yaml::Hex64 Metadata;
+    std::optional<std::vector<llvm::yaml::Hex64>> CallsiteOffsets;
+
+    bool NumCallsiteOffsets() const {
+      if (!CallsiteOffsets.has_value())
+        return 0;
+      return CallsiteOffsets->size();
+    }
   };
   uint8_t Version;
   llvm::yaml::Hex8 Feature;
@@ -180,6 +187,20 @@ struct BBAddrMapEntry {
       return 0;
     return BBRanges->front().BaseAddress;
   }
+
+  // Returns if any BB entries have non-empty callsite offsets.
+  bool hasAnyCallsiteOffsets() const {
+    if (!BBRanges)
+      return false;
+    for (const ELFYAML::BBAddrMapEntry::BBRangeEntry &BBR : *BBRanges) {
+      if (!BBR.BBEntries)
+        continue;
+      for (const ELFYAML::BBAddrMapEntry::BBEntry &BBE : *BBR.BBEntries)
+        if (BBE.CallsiteOffsets && !BBE.CallsiteOffsets->empty())
+          return true;
+    }
+    return false;
+  }
 };
 
 struct PGOAnalysisMapEntry {
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index a2c3b50b24670..107be4ea5324d 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -1426,9 +1426,12 @@ getBBAddrMapFeature(const MachineFunction &MF, int NumMBBSectionRanges) {
         "BB entries info is required for BBFreq and BrProb "
         "features");
   }
-  return {FuncEntryCountEnabled, BBFreqEnabled, BrProbEnabled,
+  return {FuncEntryCountEnabled,
+          BBFreqEnabled,
+          BrProbEnabled,
           MF.hasBBSections() && NumMBBSectionRanges > 1,
-          static_cast<bool>(BBAddrMapSkipEmitBBEntries)};
+          static_cast<bool>(BBAddrMapSkipEmitBBEntries),
+          false};
 }
 
 void AsmPrinter::emitBBAddrMapSection(const MachineFunction &MF) {
diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp
index e6864ca508a54..753f9d38b919f 100644
--- a/llvm/lib/Object/ELF.cpp
+++ b/llvm/lib/Object/ELF.cpp
@@ -837,7 +837,7 @@ decodeBBAddrMapImpl(const ELFFile<ELFT> &EF,
       Version = Data.getU8(Cur);
       if (!Cur)
         break;
-      if (Version > 2)
+      if (Version > 3)
         return createError("unsupported SHT_LLVM_BB_ADDR_MAP version: " +
                            Twine(static_cast<int>(Version)));
       Feature = Data.getU8(Cur); // Feature byte
@@ -847,12 +847,18 @@ decodeBBAddrMapImpl(const ELFFile<ELFT> &EF,
       if (!FeatEnableOrErr)
         return FeatEnableOrErr.takeError();
       FeatEnable = *FeatEnableOrErr;
-      if (Feature != 0 && Version < 2 && Cur)
+      if (FeatEnable.hasPGOAnalysis() && Version < 2)
         return createError(
             "version should be >= 2 for SHT_LLVM_BB_ADDR_MAP when "
             "PGO features are enabled: version = " +
             Twine(static_cast<int>(Version)) +
             " feature = " + Twine(static_cast<int>(Feature)));
+      if (FeatEnable.CallsiteOffsets && Version < 3)
+        return createError(
+            "version should be >= 3 for SHT_LLVM_BB_ADDR_MAP when "
+            "callsite offsets feature is enabled: version = " +
+            Twine(static_cast<int>(Version)) +
+            " feature = " + Twine(static_cast<int>(Feature)));
     }
     uint32_t NumBlocksInBBRange = 0;
     uint32_t NumBBRanges = 1;
@@ -893,7 +899,25 @@ decodeBBAddrMapImpl(const ELFFile<ELFT> &EF,
                             ? readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr)
                             : BlockIndex;
           uint32_t Offset = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
-          uint32_t Size = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
+          // Read the callsite offsets.
+          uint32_t LastCallsiteOffset = 0;
+          SmallVector<uint32_t, 1> CallsiteOffsets;
+          if (FeatEnable.CallsiteOffsets) {
+            uint32_t NumCallsites =
+                readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
+            CallsiteOffsets.reserve(NumCallsites);
+            for (uint32_t CallsiteIndex = 0;
+                 !ULEBSizeErr && Cur && (CallsiteIndex < NumCallsites);
+                 ++CallsiteIndex) {
+              LastCallsiteOffset +=
+                  readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
+              CallsiteOffsets.push_back(LastCallsiteOffset);
+            }
+            if (!Cur || ULEBSizeErr)
+              break;
+          }
+          uint32_t Size = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr) +
+                          LastCallsiteOffset;
           uint32_t MD = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
           if (Version >= 1) {
             // Offset is calculated relative to the end of the previous BB.
@@ -906,7 +930,8 @@ decodeBBAddrMapImpl(const ELFFile<ELFT> &EF,
             MetadataDecodeErr = MetadataOrErr.takeError();
             break;
           }
-          BBEntries.push_back({ID, Offset, Size, *MetadataOrErr});
+          BBEntries.push_back(
+              {ID, Offset, Size, *MetadataOrErr, CallsiteOffsets});
         }
         TotalNumBlocks += BBEntries.size();
       }
diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp
index 9ae76a71ede5e..6de87a88d0060 100644
--- a/llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -1452,7 +1452,7 @@ void ELFState<ELFT>::writeSectionContent(
   for (const auto &[Idx, E] : llvm::enumerate(*Section.Entries)) {
     // Write version and feature values.
     if (Section.Type == llvm::ELF::SHT_LLVM_BB_ADDR_MAP) {
-      if (E.Version > 2)
+      if (E.Version > 3)
         WithColor::warning() << "unsupported SHT_LLVM_BB_ADDR_MAP version: "
                              << static_cast<int>(E.Version)
                              << "; encoding using the most recent version";
@@ -1483,6 +1483,8 @@ void ELFState<ELFT>::writeSectionContent(
     if (!E.BBRanges)
       continue;
     uint64_t TotalNumBlocks = 0;
+    bool EmitCallsiteOffsets =
+        FeatureOrErr->CallsiteOffsets || E.hasAnyCallsiteOffsets();
     for (const ELFYAML::BBAddrMapEntry::BBRangeEntry &BBR : *E.BBRanges) {
       // Write the base address of the range.
       CBA.write<uintX_t>(BBR.BaseAddress, ELFT::Endianness);
@@ -1500,6 +1502,15 @@ void ELFState<ELFT>::writeSectionContent(
         if (Section.Type == llvm::ELF::SHT_LLVM_BB_ADDR_MAP && E.Version > 1)
           SHeader.sh_size += CBA.writeULEB128(BBE.ID);
         SHeader.sh_size += CBA.writeULEB128(BBE.AddressOffset);
+        if (EmitCallsiteOffsets) {
+          size_t NumCallsiteOffsets =
+              BBE.CallsiteOffsets ? BBE.CallsiteOffsets->size() : 0;
+          SHeader.sh_size += CBA.writeULEB128(NumCallsiteOffsets);
+          if (BBE.CallsiteOffsets) {
+            for (uint32_t Offset : *BBE.CallsiteOffsets)
+              SHeader.sh_size += CBA.writeULEB128(Offset);
+          }
+        }
         SHeader.sh_size += CBA.writeULEB128(BBE.Size);
         SHeader.sh_size += CBA.writeULEB128(BBE.Metadata);
       }
diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp
index 520e956fdab9f..c38f86e4f4f1b 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -1882,6 +1882,7 @@ void MappingTraits<ELFYAML::BBAddrMapEntry::BBEntry>::mapping(
   IO.mapRequired("AddressOffset", E.AddressOffset);
   IO.mapRequired("Size", E.Size);
   IO.mapRequired("Metadata", E.Metadata);
+  IO.mapOptional("CallsiteOffsets", E.CallsiteOffsets);
 }
 
 void MappingTraits<ELFYAML::PGOAnalysisMapEntry>::mapping(
diff --git a/llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test b/llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test
index c5d071c11d1de..5d7bc8baa9b25 100644
--- a/llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test
+++ b/llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test
@@ -49,7 +49,8 @@
 # CHECK-NEXT:           {
 # CHECK-NEXT:             ID: 2
 # CHECK-NEXT:             Offset: 0x3
-# CHECK-NEXT:             Size: 0x4
+# CHECK-NEXT:             Callsite Offsets: [1, 3]
+# CHECK-NEXT:             Size: 0x7
 # CHECK-NEXT:             HasReturn: Yes
 # CHECK-NEXT:             HasTailCall: No
 # CHECK-NEXT:             IsEHPad: Yes
@@ -75,7 +76,7 @@
 # CHECK-NEXT:             HasTailCall: No
 # CHECK-NEXT:             IsEHPad: No
 # CHECK-NEXT:             CanFallThrough: Yes
-# CHECK-NEXT:            HasIndirectBranch: No
+# CHECK-NEXT:             HasIndirectBranch: No
 # CHECK-NEXT:           }
 # CHECK-NEXT:         ]
 # CHECK-NEXT:       }
@@ -143,8 +144,8 @@ Sections:
     ShSize: [[SIZE=<none>]]
     Link:   .text
     Entries:
-      - Version: 2
-        Feature: 0x8
+      - Version: 3
+        Feature: 0x28
         BBRanges:
           - BaseAddress: [[ADDR=0x11111]]
             BBEntries:
@@ -158,6 +159,7 @@ Sections:
                 AddressOffset: 0x3
                 Size:          0x4
                 Metadata:      0x15
+                CallsiteOffsets: [ 0x1 , 0x2 ]
       - Version: 2
         BBRanges:
           - BaseAddress: 0x22222
diff --git a/llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml b/llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml
index 8dbf97ef2bc12..861cb94692947 100644
--- a/llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml
+++ b/llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml
@@ -14,7 +14,7 @@
 # VALID-NEXT:   - Name: .llvm_bb_addr_map
 # VALID-NEXT:     Type: SHT_LLVM_BB_ADDR_MAP
 # VALID-NEXT:     Entries:
-# VALID-NEXT:       - Version: 2
+# VALID-NEXT:       - Version: 3
 # VALID-NEXT:         BBRanges:
 ## The 'BaseAddress' field is omitted when it's zero.
 # VALID-NEXT:           - BBEntries:
@@ -30,15 +30,16 @@
 # VALID-NEXT:               AddressOffset: 0xFFFFFFFFFFFFFFF7
 # VALID-NEXT:               Size:          0xFFFFFFFFFFFFFFF8
 # VALID-NEXT:               Metadata:      0xFFFFFFFFFFFFFFF9
-# VALID-NEXT:       - Version: 2
-# VALID-NEXT:         Feature: 0x8
+# VALID-NEXT:       - Version: 3
+# VALID-NEXT:         Feature: 0x28
 # VALID-NEXT:         BBRanges:
 # VALID-NEXT:           - BaseAddress: 0xFFFFFFFFFFFFFF20
 # VALID-NEXT:             BBEntries:
-# VALID-NEXT:               - ID:            6
-# VALID-NEXT:                 AddressOffset: 0xA
-# VALID-NEXT:                 Size:          0xB
-# VALID-NEXT:                 Metadata:      0xC
+# VALID-NEXT:               - ID:              6
+# VALID-NEXT:                 AddressOffset:   0xA
+# VALID-NEXT:                 Size:            0xB
+# VALID-NEXT:                 Metadata:        0xC
+# VALID-NEXT:                 CallsiteOffsets: [ 0x1, 0x2 ]
 
 --- !ELF
 FileHeader:
@@ -50,7 +51,7 @@ Sections:
     Type:   SHT_LLVM_BB_ADDR_MAP
     ShSize: [[SIZE=<none>]]
     Entries:
-      - Version: 2
+      - Version: 3
         Feature: 0x0
         BBRanges:
           - BaseAddress: 0x0
@@ -67,17 +68,18 @@ Sections:
                 AddressOffset: 0xFFFFFFFFFFFFFFF7
                 Size:          0xFFFFFFFFFFFFFFF8
                 Metadata:      0xFFFFFFFFFFFFFFF9
-      - Version:   2
-        Feature:   0x8
+      - Version:   3
+        Feature:   0x28
         NumBBRanges: [[NUMBBRANGES=<none>]]
         BBRanges:
           - BaseAddress:   0xFFFFFFFFFFFFFF20
             NumBlocks: [[NUMBLOCKS=<none>]]
             BBEntries:
-             - ID:            6
-               AddressOffset: 0xA
-               Size:          0xB
-               Metadata:      0xC
+             - ID:              6
+               AddressOffset:   0xA
+               Size:            0xB
+               Metadata:        0xC
+               CallsiteOffsets: [ 0x1, 0x2 ]
 
 ## Check obj2yaml can dump empty .llvm_bb_addr_map sections.
 
diff --git a/llvm/test/tools/yaml2obj/ELF/bb-addr-map.yaml b/llvm/test/tools/yaml2obj/ELF/bb-addr-map.yaml
index 709938babffbf..9fd0577b1e0fd 100644
--- a/llvm/test/tools/yaml2obj/ELF/bb-addr-map.yaml
+++ b/llvm/test/tools/yaml2obj/ELF/bb-addr-map.yaml
@@ -36,7 +36,8 @@
 # Case 4: Specify Entries.
 # CHECK:        Name: .llvm_bb_addr_map (1)
 # CHECK:        SectionData (
-# CHECK-NEXT:     0000: 02002000 00000000 0000010B 010203
+# CHECK-NEXT:     0000: 03002000 00000000 0000010B 01020102
+# CHECK-NEXT:     0010: 0203
 # CHECK-NEXT:   )
 
 # Case 5: Specify Entries and omit the Address field.
@@ -44,28 +45,32 @@
 # CHECK:        Address:
 # CHECK-SAME:   {{^ 0x0$}}
 # CHECK:        SectionData (
-# CHECK-NEXT:     0000: 02000000 00000000 0000010C 010203
+# CHECK-NEXT:     0000: 03000000 00000000 0000010C 010203
 # CHECK-NEXT:   )
 
 # Case 6: Override the NumBlocks field.
 # CHECK:        Name: .llvm_bb_addr_map (1)
 # CHECK:        SectionData (
-# CHECK-NEXT:     0000: 02002000 00000000 0000020D 010203
+# CHECK-NEXT:     0000: 03002000 00000000 0000020D 010203
 # CHECK-NEXT:   )
 
 # Case 7: Specify empty BBRanges.
 # CHECK:        Name: .llvm_bb_addr_map (1)
 # CHECK:        SectionData (
-# CHECK-NEXT:     0000: 020000
+# CHECK-NEXT:     0000: 030000
 # CHECK-NEXT:   )
 
 # Case 8: Specify empty BBRanges with multi-bb-range.
 # CHECK:        Name: .llvm_bb_addr_map (1)
 # CHECK:        SectionData (
-# CHECK-NEXT:     0000: 020800
+# CHECK-NEXT:     0000: 030800
 # CHECK-NEXT:   )
 
-
+# Case 9: Specify empty CallsiteOffsets.
+# CHECK:        Name: .llvm_bb_addr_map (1)
+# CHECK:        SectionData (
+# CHECK-NEXT:     0000: 03202000 00000000 0000010E 01000203
+# CHECK-NEXT:   )
 
 
 --- !ELF
@@ -100,7 +105,7 @@ Sections:
   - Name: '.llvm_bb_addr_map (4)'
     Type: SHT_LLVM_BB_ADDR_MAP
     Entries:
-      - Version: 2
+      - Version: 3
         BBRanges:
           - BaseAddress: 0x0000000000000020
             BBEntries:
@@ -108,13 +113,14 @@ Sections:
                 AddressOffset: 0x00000001
                 Size:          0x00000002
                 Metadata:      0x00000003
+                CallsiteOffsets: [0x1, 0x2]
 
 ## 5) When specifying the description with Entries, the 'Address' field will be
 ##    zero when omitted.
   - Name: '.llvm_bb_addr_map (5)'
     Type: SHT_LLVM_BB_ADDR_MAP
     Entries:
-      - Version: 2
+      - Version: 3
         BBRanges:
           - BBEntries:
             - ID:            12
@@ -127,7 +133,7 @@ Sections:
   - Name: '.llvm_bb_addr_map (6)'
     Type: SHT_LLVM_BB_ADDR_MAP
     Entries:
-      - Version:   2
+      - Version: 3
         BBRanges:
           - BaseAddress:   0x0000000000000020
             NumBlocks: 2
@@ -142,7 +148,7 @@ Sections:
   - Name: '.llvm_bb_addr_map (7)'
     Type: SHT_LLVM_BB_ADDR_MAP
     Entries:
-      - Version: 2
+      - Version: 3
         BBRanges: []
 
 ## 8) We can produce a SHT_LLVM_BB_ADDR_MAP section from a multi-bb-range
@@ -150,10 +156,26 @@ Sections:
   - Name: '.llvm_bb_addr_map (8)'
     Type: SHT_LLVM_BB_ADDR_MAP
     Entries:
-      - Version: 2
+      - Version: 3
         Feature: 0x8
         BBRanges: []
 
+## 9) We can produce a SHT_LLVM_BB_ADDR_MAP section from a description
+##    with empty callsite offsets.
+  - Name: '.llvm_bb_addr_map (9)'
+    Type: SHT_LLVM_BB_ADDR_MAP
+    Entries:
+      - Version: 3
+        Feature: 0x20
+        BBRanges:
+          - BaseAddress: 0x0000000000000020
+            BBEntries:
+             - ID:              14
+               AddressOffset:   0x00000001
+               Size:            0x00000002
+               Metadata:        0x00000003
+               CallsiteOffsets: []
+
 ## Check we can't use Entries at the same time as either Content or Size.
 # RUN: not yaml2obj --docnum=2 -DCONTENT="00" %s 2>&1 | FileCheck %s --check-prefix=INVALID
 # RUN: not yaml2obj --docnum=2 -DSIZE="0" %s 2>&1 | FileCheck %s --check-prefix=INVALID
@@ -175,7 +197,7 @@ Sections:
 
 ## Check that yaml2obj generates a warning when we use unsupported versions.
 # RUN: yaml2obj --docnum=3  %s 2>&1 | FileCheck %s --check-prefix=INVALID-VERSION
-# INVALID-VERSION: warning: unsupported SHT_LLVM_BB_ADDR_MAP version: 3; encoding using the most recent version
+# INVALID-VERSION: warning: unsupported SHT_LLVM_BB_ADDR_MAP version: 4; encoding using the most recent version
 
 --- !ELF
 FileHeader:
@@ -187,4 +209,4 @@ Sections:
     Type: SHT_LLVM_BB_ADDR_MAP
     Entries:
 ##  Specify unsupported version
-      - Version: 3
+      - Version: 4
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index abaf6077ba9e7..7250d0a129cf5 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -7878,6 +7878,8 @@ void LLVMELFDumper<ELFT>::printBBAddrMaps(bool PrettyPGOAnalysis) {
             DictScope BBED(W);
             W.printNumber("ID", BBE.ID);
             W.printHex("Offset", BBE.Offset);
+            if (!BBE.CallsiteOffsets.empty())
+              W.printList("Callsite Offsets", BBE.CallsiteOffsets);
             W.printHex("Size", BBE.Size);
             W.printBoolean("HasReturn", BBE.hasReturn());
             W.printBoolean("HasTailCall", BBE.hasTailCall());
diff --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp
index c56ed15501b40..53455b8c7580a 100644
--- a/llvm/tools/obj2yaml/elf2yaml.cpp
+++ b/llvm/tools/obj2yaml/elf2yaml.cpp
@@ -899,7 +899,7 @@ ELFDumper<ELFT>::dumpBBAddrMapSection(const Elf_Shdr *Shdr) {
   while (Cur && Cur.tell() < Content.size()) {
     if (Shdr->sh_type == ELF::SHT_LLVM_BB_ADDR_MAP) {
       Version = Data.getU8(Cur);
-      if (Cur && Version > 2)
+      if (Cur && Version > 3)
         return createStringError(
             errc::invalid_argument,
             "invalid SHT_LLVM_BB_ADDR_MAP section version: " +
@@ -934,9 +934,19 @@ ELFDumper<ELFT>::dumpBBAddrMapSection(const Elf_Shdr *Shdr) {
            ++BlockIndex) {
         uint32_t ID = Version >= 2 ? Data.getULEB128(Cur) : BlockIndex;
         uint64_t Offset = Data.getULEB128(Cur);
+        std::optional<std::vector<llvm::yaml::Hex64>> CallsiteOffsets;
+        if (FeatureOrErr->CallsiteOffsets) {
+          uint32_t NumCallsites = Data.getULEB128(Cur);
+          CallsiteOffsets = std::vector<llvm::yaml::Hex64>(NumCallsites, 0);
+          for (uint32_t CallsiteIndex = 0; Cur && CallsiteIndex < NumCallsites;
+               ++CallsiteIndex) {
+            (*CallsiteOffsets)[CallsiteIndex] = Data.getULEB128(Cur);
+          }
+        }
         uint64_t Size = Data.getULEB128(Cur);
         uint64_t Metadata = Data.getULEB128(Cur);
-        BBEntries.push_back({ID, Offset, Size, Metadata});
+        BBEntries.push_back(
+            {ID, Offset, Size, Metadata, std::move(CallsiteOffsets)});
       }
       TotalNumBlocks += BBEntries.size();
       BBRanges.push_back({BaseAddress, /*NumBlocks=*/{}, BBEntries});
diff --git a/llvm/unittests/Object/ELFObjectFileTest.cpp b/llvm/unittests/Object/ELFObjectFileTest.cpp
index 1073df95c379a..423f92ea07b39 100644
--- a/llvm/unittests/Object/ELFObjectFileTest.cpp
+++ b/llvm/unittests/Object/ELFObjectFileTest.cpp
@@ -531,7 +531,7 @@ TEST(ELFObjectFileTest, InvalidDecodeBBAddrMap) {
   // Check that we can detect unsupported versions.
   SmallString<128> UnsupportedVersionYamlString(CommonYamlString);
   UnsupportedVersionYamlString += R"(
-      - Version: 3
+      - Version: 4
         BBRanges:
           - BaseAddress: 0x11111
             BBEntries:
@@ -543,12 +543,12 @@ TEST(ELFObjectFileTest, InvalidDecodeBBAddrMap) {
   {
     SCOPED_TRACE("unsupported version");
     DoCheck(UnsupportedVersionYamlString,
-            "unsupported SHT_LLVM_BB_ADDR_MAP version: 3");
+            "unsupported SHT_LLVM_BB_ADDR_MAP version: 4");
   }
 
   SmallString<128> ZeroBBRangesYamlString(CommonYamlString);
   ZeroBBRangesYamlString += R"(
-      - Version: 2
+      - Version: 3
         Feature: 0x8
         BBRanges: []
 )";
@@ -561,7 +561,7 @@ TEST(ELFObjectFileTest, InvalidDecodeBBAddrMap) {
 
   SmallString<128> CommonVersionedYamlString(CommonYamlString);
   CommonVersionedYamlString += R"(
-      - Version: 2
+      - Version: 3
         BBRanges:
           - BaseAddress: 0x11111
             BBEntries:
@@ -669,6 +669,26 @@ TEST(ELFObjectFileTest, InvalidDecodeBBAddrMap) {
 )";
   DoCheck(OverLimitNumBBRanges,
           "ULEB128 value at offset 0x2 exceeds UINT32_MAX (0x100000000)");
+
+  // Check that we can detect unsupported version for callsite offsets.
+  SmallString<128> UnsupportedLowVersionYamlString(CommonYamlString);
+  UnsupportedLowVersionYamlString += R"(
+      - Version: 2
+        Feature: 0x20
+        BBRanges:
+          - BBEntries:
+              - AddressOffset:   0x0
+                Size:            0x1
+                Metadata:        0x2
+                CallsiteOffsets: [ 0x1 ]
+)";
+
+  {
+    SCOPED_TRACE("unsupported version");
+    DoCheck(UnsupportedLowVersionYamlString,
+            "version should be >= 3 for SHT_LLVM_BB_ADDR_MAP when callsite"
+            " offsets feature is enabled: version = 2 feature = 32");
+  }
 }
 
 // Test for the ELFObjectFile::readBBAddrMap API.
@@ -684,19 +704,21 @@ TEST(ELFObjectFileTest, ReadBBAddrMap) {
     Type: SHT_LLVM_BB_ADDR_MAP
     Link: 1
     Entries:
-      - Version: 2
+      - Version: 3
+        Feature: 0x20
         BBRanges:
           - BaseAddress: 0x11111
             BBEntries:
-              - ID:            1
-                AddressOffset: 0x0
-                Size:          0x1
-                Metadata:      0x2
+              - ID:              1
+                AddressOffset:   0x0
+                Size:            0x1
+                Metadata:        0x2
+                CallsiteOffsets: [ 0x1 , 0x1 ]
   - Name: .llvm_bb_addr_map_2
     Type: SHT_LLVM_BB_ADDR_MAP
     Link: 1
     Entries:
-      - Version: 2
+      - Version: 3
         Feature: 0x8
         BBRanges:
           - BaseAddress: 0x22222
@@ -738,14 +760,15 @@ TEST(ELFObjectFileTest, ReadBBAddrMap) {
 )");
 
   BBAddrMap E1 = {
-      {{0x11111, {{1, 0x0, 0x1, {false, true, false, false, false}}}}}};
+      {{0x11111,
+        {{1, 0x0, 0x3, {false, true, false, false, false}, {0x1, 0x2}}}}}};
   BBAddrMap E2 = {
-      {{0x22222, {{2, 0x0, 0x2, {false, false, true, false, false}}}},
-       {0xFFFFF, {{15, 0xF0, 0xF1, {true, true, true, true, true}}}}}};
+      {{0x22222, {{2, 0x0, 0x2, {false, false, true, false, false}, {}}}},
+       {0xFFFFF, {{15, 0xF0, 0xF1, {true, true, true, true, true}, {}}}}}};
   BBAddrMap E3 = {
-      {{0x33333, {{0, 0x0, 0x3, {false, true, true, false, false}}}}}};
+      {{0x33333, {{0, 0x0, 0x3, {false, true, true, false, false}, {}}}}}};
   BBAddrMap E4 = {
-      {{0x44444, {{0, 0x0, 0x4, {false, false, false, true, true}}}}}};
+      {{0x44444, {{0, 0x0, 0x4, {false, false, false, true, true}, {}}}}}};
 
   std::vector<BBAddrMap> Section0BBAddrMaps = {E4};
   std::vector<BBAddrMap> Section1BBAddrMaps = {E3};
@@ -1137,28 +1160,29 @@ TEST(ELFObjectFileTest, ReadPGOAnalysisMap) {
 )");
 
   BBAddrMap E1 = {
-      {{0x11111, {{1, 0x0, 0x1, {false, true, false, false, false}}}}}};
-  PGOAnalysisMap P1 = {892, {}, {true, false, false, false, false}};
+      {{0x11111, {{1, 0x0, 0x1, {false, true, false, false, false}, {}}}}}};
+  PGOAnalysisMap P1 = {892, {}, {true, false, false, false, false, false}};
   BBAddrMap E2 = {
-      {{0x22222, {{2, 0x0, 0x2, {false, false, true, false, false}}}}}};
-  PGOAnalysisMap P2 = {
-      {}, {{BlockFrequency(343), {}}}, {false, true, false, false, false}};
+      {{0x22222, {{2, 0x0, 0x2, {false, false, true, false, false}, {}}}}}};
+  PGOAnalysisMap P2 = {{},
+                       {{BlockFrequency(343), {}}},
+                       {false, true, false, false, false, false}};
   BBAddrMap E3 = {{{0x33333,
-                    {{0, 0x0, 0x3, {false, true, true, false, false}},
-                     {1, 0x3, 0x3, {false, false, true, false, false}},
-                     {2, 0x6, 0x3, {false, false, false, false, false}}}}}};
+                    {{0, 0x0, 0x3, {false, true, true, false, false}, {}},
+                     {1, 0x3, 0x3, {false, false, true, false, false}, {}},
+                     {2, 0x6, 0x3, {false, false, false, false, false}, {}}}}}};
   PGOAnalysisMap P3 = {{},
                        {{{},
                          {{1, BranchProbability::getRaw(0x1111'1111)},
                           {2, BranchProbability::getRaw(0xeeee'eeee)}}},
                         {{}, {{2, BranchProbability::getRaw(0xffff'ffff)}}},
                         {{}, {}}},
-                       {false, false, true, false, false}};
+                       {false, false, true, false, false, false}};
   BBAddrMap E4 = {{{0x44444,
-                    {{0, 0x0, 0x4, {false, false, false, true, true}},
-                     {1, 0x4, 0x4, {false, false, false, false, false}},
-                     {2, 0x8, 0x4, {false, false, false, false, false}},
-                     {3, 0xc, 0x4, {false, false, false, false, false}}}}}};
+                    {{0, 0x0, 0x4, {false, false, false, true, true}, {}},
+                     {1, 0x4, 0x4, {false, false, false, false, false}, {}},
+                     {2, 0x8, 0x4, {false, false, false, false, false}, {}},
+                     {3, 0xc, 0x4, {false, false, false, false, false}, {}}}}}};
   PGOAnalysisMap P4 = {
       1000,
       {{BlockFrequency(1000),
@@ -1170,22 +1194,22 @@ TEST(ELFObjectFileTest, ReadPGOAnalysisMap) {
          {3, BranchProbability::getRaw(0xeeee'eeee)}}},
        {BlockFrequency(18), {{3, BranchProbability::getRaw(0xffff'ffff)}}},
        {BlockFrequency(1000), {}}},
-      {true, true, true, false, false}};
+      {true, true, true, false, false, false}};
   BBAddrMap E5 = {
-      {{0x55555, {{2, 0x0, 0x2, {false, false, true, false, false}}}}}};
-  PGOAnalysisMap P5 = {{}, {}, {false, false, false, false, false}};
+      {{0x55555, {{2, 0x0, 0x2, {false, false, true, false, false}, {}}}}}};
+  PGOAnalysisMap P5 = {{}, {}, {false, false, false, false, false, false}};
   BBAddrMap E6 = {
       {{0x66666,
-        {{0, 0x0, 0x6, {false, true, true, false, false}},
-         {1, 0x6, 0x6, {false, false, true, false, false}}}},
-       {0x666661, {{2, 0x0, 0x6, {false, false, false, false, false}}}}}};
+        {{0, 0x0, 0x6, {false, true, true, false, false}, {}},
+         {1, 0x6, 0x6, {false, false, true, false, false}, {}}}},
+       {0x666661, {{2, 0x0, 0x6, {false, false, false, false, false}, {}}}}}};
   PGOAnalysisMap P6 = {{},
                        {{{},
                          {{1, BranchProbability::getRaw(0x2222'2222)},
                           {2, BranchProbability::getRaw(0xcccc'cccc)}}},
                         {{}, {{2, BranchProbability::getRaw(0x8888'8888)}}},
                         {{}, {}}},
-                       {false, false, true, true, false}};
+                       {false, false, true, true, false, false}};
 
   std::vector<BBAddrMap> Section0BBAddrMaps = {E4, E5, E6};
   std::vector<BBAddrMap> Section1BBAddrMaps = {E3};
diff --git a/llvm/unittests/Object/ELFTypesTest.cpp b/llvm/unittests/Object/ELFTypesTest.cpp
index 13130dde80ef1..f88931b5f544c 100644
--- a/llvm/unittests/Object/ELFTypesTest.cpp
+++ b/llvm/unittests/Object/ELFTypesTest.cpp
@@ -101,18 +101,21 @@ static_assert(
     "PGOAnalysisMap should use the same type for basic block ID as BBAddrMap");
 
 TEST(ELFTypesTest, BBAddrMapFeaturesEncodingTest) {
-  const std::array<BBAddrMap::Features, 9> Decoded = {
-      {{false, false, false, false, false},
-       {true, false, false, false, false},
-       {false, true, false, false, false},
-       {false, false, true, false, false},
-       {false, false, false, true, false},
-       {true, true, false, false, false},
-       {false, true, true, false, false},
-       {false, true, true, true, false},
-       {true, true, true, true, false}}};
-  const std::array<uint8_t, 9> Encoded = {
-      {0b0000, 0b0001, 0b0010, 0b0100, 0b1000, 0b0011, 0b0110, 0b1110, 0b1111}};
+  const std::array<BBAddrMap::Features, 11> Decoded = {
+      {{false, false, false, false, false, false},
+       {true, false, false, false, false, false},
+       {false, true, false, false, false, false},
+       {false, false, true, false, false, false},
+       {false, false, false, true, false, false},
+       {true, true, false, false, false, false},
+       {false, true, true, false, false, false},
+       {false, true, true, true, false, false},
+       {true, true, true, true, false, false},
+       {false, false, false, false, true, false},
+       {false, false, false, false, false, true}}};
+  const std::array<uint8_t, 11> Encoded = {{0b0000, 0b0001, 0b0010, 0b0100,
+                                            0b1000, 0b0011, 0b0110, 0b1110,
+                                            0b1111, 0b1'0000, 0b10'0000}};
   for (const auto &[Feat, EncodedVal] : llvm::zip(Decoded, Encoded))
     EXPECT_EQ(Feat.encode(), EncodedVal);
   for (const auto &[Feat, EncodedVal] : llvm::zip(Decoded, Encoded)) {
@@ -125,9 +128,9 @@ TEST(ELFTypesTest, BBAddrMapFeaturesEncodingTest) {
 
 TEST(ELFTypesTest, BBAddrMapFeaturesInvalidEncodingTest) {
   const std::array<std::string, 2> Errors = {
-      "invalid encoding for BBAddrMap::Features: 0x20",
+      "invalid encoding for BBAddrMap::Features: 0x40",
       "invalid encoding for BBAddrMap::Features: 0xf0"};
-  const std::array<uint8_t, 2> Values = {{0b10'0000, 0b1111'0000}};
+  const std::array<uint8_t, 2> Values = {{0b100'0000, 0b1111'0000}};
   for (const auto &[Val, Error] : llvm::zip(Values, Errors)) {
     EXPECT_THAT_ERROR(BBAddrMap::Features::decode(Val).takeError(),
                       FailedWithMessage(Error));



More information about the llvm-commits mailing list