[llvm] 0aa6df6 - [Propeller] Encode address offsets of basic blocks relative to the end of the previous basic blocks.

Rahman Lavaee via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 28 07:43:19 PDT 2022


Author: Rahman Lavaee
Date: 2022-06-28T07:42:54-07:00
New Revision: 0aa6df65756d3ec7769e55424a41c7074849fe12

URL: https://github.com/llvm/llvm-project/commit/0aa6df65756d3ec7769e55424a41c7074849fe12
DIFF: https://github.com/llvm/llvm-project/commit/0aa6df65756d3ec7769e55424a41c7074849fe12.diff

LOG: [Propeller] Encode address offsets of basic blocks relative to the end of the previous basic blocks.

This is a resurrection of D106421 with the change that it keeps backward-compatibility. This means decoding the previous version of `LLVM_BB_ADDR_MAP` will work. This is required as the profile mapping tool is not released with LLVM (AutoFDO). As suggested by @jhenderson we rename the original  section type value to `SHT_LLVM_BB_ADDR_MAP_V0` and assign a new value to the `SHT_LLVM_BB_ADDR_MAP` section type. The new encoding adds a version byte to each function entry to specify the encoding version for that function.  This patch also adds a feature byte to be used with more flexibility in the future. An use-case example for the feature field is encoding multi-section functions more concisely using a different format.

Conceptually, the new encoding emits basic block offsets and sizes as label differences between each two consecutive basic block begin and end label. When decoding, offsets must be aggregated along with basic block sizes to calculate the final offsets of basic blocks relative to the function address.

This encoding uses smaller values compared to the existing one (offsets relative to function symbol).
Smaller values tend to occupy fewer bytes in ULEB128 encoding. As a result, we get about 17% total reduction in the size of the bb-address-map section (from about 11MB to 9MB for the clang PGO binary).
The extra two bytes (version and feature fields) incur a small 3% size overhead to the `LLVM_BB_ADDR_MAP` section size.

Reviewed By: jhenderson

Differential Revision: https://reviews.llvm.org/D121346

Added: 
    

Modified: 
    llvm/docs/Extensions.rst
    llvm/include/llvm/BinaryFormat/ELF.h
    llvm/include/llvm/MC/MCContext.h
    llvm/include/llvm/ObjectYAML/ELFYAML.h
    llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
    llvm/lib/CodeGen/BasicBlockSections.cpp
    llvm/lib/MC/MCSectionELF.cpp
    llvm/lib/Object/ELF.cpp
    llvm/lib/Object/ELFObjectFile.cpp
    llvm/lib/ObjectYAML/ELFEmitter.cpp
    llvm/lib/ObjectYAML/ELFYAML.cpp
    llvm/test/CodeGen/X86/basic-block-sections-labels-empty-function.ll
    llvm/test/CodeGen/X86/basic-block-sections-labels-functions-sections.ll
    llvm/test/CodeGen/X86/basic-block-sections-labels.ll
    llvm/test/tools/llvm-objdump/X86/elf-bbaddrmap-disassemble-symbolize-operands.yaml
    llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test
    llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml
    llvm/test/tools/yaml2obj/ELF/bb-addr-map.yaml
    llvm/tools/llvm-readobj/ELFDumper.cpp
    llvm/tools/obj2yaml/elf2yaml.cpp
    llvm/unittests/Object/ELFObjectFileTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/docs/Extensions.rst b/llvm/docs/Extensions.rst
index f0e54d0f52eab..65cae4f4dd237 100644
--- a/llvm/docs/Extensions.rst
+++ b/llvm/docs/Extensions.rst
@@ -401,11 +401,23 @@ This section stores the binary address of basic blocks along with other related
 metadata. This information can be used to map binary profiles (like perf
 profiles) directly to machine basic blocks.
 This section is emitted with ``-basic-block-sections=labels`` and will contain
-a BB address map table for every function which may be constructed as follows:
+a BB address map table for every function.
+
+The ``SHT_LLVM_BB_ADDR_MAP`` type provides backward compatibility to allow
+reading older versions of the BB address map generated by older compilers. Each
+function entry starts with a version byte which specifies the encoding version
+to use. The following versioning schemes are currently supported.
+
+Version 1 (newest): basic block address offsets are computed relative to the end
+of previous blocks.
+
+Example:
 
 .. code-block:: gas
 
   .section  ".llvm_bb_addr_map","", at llvm_bb_addr_map
+  .byte     1                             # version number
+  .byte     0                             # feature byte (reserved for future use)
   .quad     .Lfunc_begin0                 # address of the function
   .byte     2                             # number of basic blocks
   # BB record for BB_0
@@ -413,11 +425,30 @@ a BB address map table for every function which may be constructed as follows:
    .uleb128  .LBB_END0_0-.Lfunc_begin0    # BB_0 size
    .byte     x                            # BB_0 metadata
   # BB record for BB_1
-   .uleb128  .LBB0_1-.Lfunc_begin0        # BB_1 offset relative to function entry
-   .uleb128  .LBB_END0_1-.Lfunc_begin0    # BB_1 size
+   .uleb128  .LBB0_1-.LBB_END0_0          # BB_1 offset relative to the end of last block (BB_0).
+   .uleb128  .LBB_END0_1-.LBB0_1          # BB_1 size
    .byte     y                            # BB_1 metadata
 
-This creates a BB address map table for a function with two basic blocks.
+Version 0: basic block address offsets are computed relative to the function
+address. This uses the unversioned ``SHT_LLVM_BB_ADDR_MAP_V0`` section type and
+is semantically equivalent to using ``SHT_LLVM_BB_ADDR_MAP`` with a zero
+version field.
+
+Example:
+
+.. code-block:: gas
+
+  .section  ".llvm_bb_addr_map","", at llvm_bb_addr_map_v0
+  .quad     .Lfunc_begin0                 # address of the function
+  .byte     2                             # number of basic blocks
+  # BB record for BB_0
+   .uleb128  .Lfunc_beign0-.Lfunc_begin0  # BB_0 offset relative to the function entry (always zero)
+   .uleb128  .LBB_END0_0-.Lfunc_begin0    # BB_0 size
+   .byte     x                            # BB_0 metadata
+  # BB record for BB_1
+   .uleb128  .LBB0_1-.Lfunc_begin0        # BB_1 offset relative to the function entry
+   .uleb128  .LBB_END0_1-.LBB0_1          # BB_1 size
+   .byte     y                            # BB_1 metadata
 
 CodeView-Dependent
 ------------------

diff  --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h
index 529953c59278b..27890c16c2fd4 100644
--- a/llvm/include/llvm/BinaryFormat/ELF.h
+++ b/llvm/include/llvm/BinaryFormat/ELF.h
@@ -981,12 +981,15 @@ enum : unsigned {
   SHT_LLVM_ADDRSIG = 0x6fff4c03,        // List of address-significant symbols
                                         // for safe ICF.
   SHT_LLVM_DEPENDENT_LIBRARIES =
-      0x6fff4c04,                    // LLVM Dependent Library Specifiers.
-  SHT_LLVM_SYMPART = 0x6fff4c05,     // Symbol partition specification.
-  SHT_LLVM_PART_EHDR = 0x6fff4c06,   // ELF header for loadable partition.
-  SHT_LLVM_PART_PHDR = 0x6fff4c07,   // Phdrs for loadable partition.
-  SHT_LLVM_BB_ADDR_MAP = 0x6fff4c08, // LLVM Basic Block Address Map.
+      0x6fff4c04,                  // LLVM Dependent Library Specifiers.
+  SHT_LLVM_SYMPART = 0x6fff4c05,   // Symbol partition specification.
+  SHT_LLVM_PART_EHDR = 0x6fff4c06, // ELF header for loadable partition.
+  SHT_LLVM_PART_PHDR = 0x6fff4c07, // Phdrs for loadable partition.
+  SHT_LLVM_BB_ADDR_MAP_V0 =
+      0x6fff4c08, // LLVM Basic Block Address Map (old version kept for
+                  // backward-compatibility).
   SHT_LLVM_CALL_GRAPH_PROFILE = 0x6fff4c09, // LLVM Call Graph Profile.
+  SHT_LLVM_BB_ADDR_MAP = 0x6fff4c0a,        // LLVM Basic Block Address Map.
   // Android's experimental support for SHT_RELR sections.
   // https://android.googlesource.com/platform/bionic/+/b7feec74547f84559a1467aca02708ff61346d2a/libc/include/elf.h#512
   SHT_ANDROID_RELR = 0x6fffff00,   // Relocation entries; only offsets.

diff  --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h
index d996e3ff66e58..a0e18891ed902 100644
--- a/llvm/include/llvm/MC/MCContext.h
+++ b/llvm/include/llvm/MC/MCContext.h
@@ -172,6 +172,9 @@ class MCContext {
   /// for the LocalLabelVal and adds it to the map if needed.
   unsigned GetInstance(unsigned LocalLabelVal);
 
+  /// LLVM_BB_ADDR_MAP version to emit.
+  uint8_t BBAddrMapVersion = 1;
+
   /// The file name of the log file from the environment variable
   /// AS_SECURE_LOG_FILE.  Which must be set before the .secure_log_unique
   /// directive is used or it is an error.
@@ -679,6 +682,8 @@ class MCContext {
   // Create and save a copy of STI and return a reference to the copy.
   MCSubtargetInfo &getSubtargetCopy(const MCSubtargetInfo &STI);
 
+  uint8_t getBBAddrMapVersion() const { return BBAddrMapVersion; }
+
   /// @}
 
   /// \name Dwarf Management

diff  --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h
index 95bf5237869a7..ddd5dd9cf3c96 100644
--- a/llvm/include/llvm/ObjectYAML/ELFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h
@@ -161,6 +161,8 @@ struct BBAddrMapEntry {
     llvm::yaml::Hex64 Size;
     llvm::yaml::Hex64 Metadata;
   };
+  uint8_t Version;
+  llvm::yaml::Hex8 Feature;
   llvm::yaml::Hex64 Address;
   Optional<uint64_t> NumBlocks;
   Optional<std::vector<BBEntry>> BBEntries;

diff  --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 593ef04cf8ed5..c7fef2f8162be 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -1327,19 +1327,27 @@ void AsmPrinter::emitBBAddrMapSection(const MachineFunction &MF) {
 
   OutStreamer->pushSection();
   OutStreamer->switchSection(BBAddrMapSection);
+  OutStreamer->AddComment("version");
+  OutStreamer->emitInt8(OutStreamer->getContext().getBBAddrMapVersion());
+  OutStreamer->AddComment("feature");
+  OutStreamer->emitInt8(0);
+  OutStreamer->AddComment("function address");
   OutStreamer->emitSymbolValue(FunctionSymbol, getPointerSize());
-  // Emit the total number of basic blocks in this function.
+  OutStreamer->AddComment("number of basic blocks");
   OutStreamer->emitULEB128IntValue(MF.size());
+  const MCSymbol *PrevMBBEndSymbol = FunctionSymbol;
   // Emit BB Information for each basic block in the funciton.
   for (const MachineBasicBlock &MBB : MF) {
     const MCSymbol *MBBSymbol =
         MBB.isEntryBlock() ? FunctionSymbol : MBB.getSymbol();
-    // Emit the basic block offset.
-    emitLabelDifferenceAsULEB128(MBBSymbol, FunctionSymbol);
+    // Emit the basic block offset relative to the end of the previous block.
+    // This is zero unless the block is padded due to alignment.
+    emitLabelDifferenceAsULEB128(MBBSymbol, PrevMBBEndSymbol);
     // Emit the basic block size. When BBs have alignments, their size cannot
     // always be computed from their offsets.
     emitLabelDifferenceAsULEB128(MBB.getEndSymbol(), MBBSymbol);
     OutStreamer->emitULEB128IntValue(getBBAddrMapMetadata(MBB));
+    PrevMBBEndSymbol = MBB.getEndSymbol();
   }
   OutStreamer->popSection();
 }

diff  --git a/llvm/lib/CodeGen/BasicBlockSections.cpp b/llvm/lib/CodeGen/BasicBlockSections.cpp
index b6b018cca8ae8..f05f5b9f99477 100644
--- a/llvm/lib/CodeGen/BasicBlockSections.cpp
+++ b/llvm/lib/CodeGen/BasicBlockSections.cpp
@@ -60,7 +60,7 @@
 // Basic Block Labels
 // ==================
 //
-// With -fbasic-block-sections=labels, we emit the offsets of BB addresses of
+// With -fbasic-block-sections=labels, we encode the offsets of BB addresses of
 // every function into the .llvm_bb_addr_map section. Along with the function
 // symbols, this allows for mapping of virtual addresses in PMU profiles back to
 // the corresponding basic blocks. This logic is implemented in AsmPrinter. This

diff  --git a/llvm/lib/MC/MCSectionELF.cpp b/llvm/lib/MC/MCSectionELF.cpp
index 3724a22aa558a..27dc1826819b9 100644
--- a/llvm/lib/MC/MCSectionELF.cpp
+++ b/llvm/lib/MC/MCSectionELF.cpp
@@ -165,6 +165,8 @@ void MCSectionELF::printSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
     OS << "llvm_sympart";
   else if (Type == ELF::SHT_LLVM_BB_ADDR_MAP)
     OS << "llvm_bb_addr_map";
+  else if (Type == ELF::SHT_LLVM_BB_ADDR_MAP_V0)
+    OS << "llvm_bb_addr_map_v0";
   else
     report_fatal_error("unsupported type 0x" + Twine::utohexstr(Type) +
                        " for section " + getName());

diff  --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp
index bcef7ce894991..6acf4543be5a8 100644
--- a/llvm/lib/Object/ELF.cpp
+++ b/llvm/lib/Object/ELF.cpp
@@ -295,6 +295,7 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) {
     STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_SYMPART);
     STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_PART_EHDR);
     STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_PART_PHDR);
+    STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_BB_ADDR_MAP_V0);
     STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_BB_ADDR_MAP);
     STRINGIFY_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES);
     STRINGIFY_ENUM_CASE(ELF, SHT_GNU_HASH);
@@ -640,7 +641,6 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec) const {
 
   DataExtractor::Cursor Cur(0);
   Error ULEBSizeErr = Error::success();
-
   // Helper to extract and decode the next ULEB128 value as uint32_t.
   // Returns zero and sets ULEBSizeErr if the ULEB128 value exceeds the uint32_t
   // limit.
@@ -660,18 +660,34 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec) const {
     return static_cast<uint32_t>(Value);
   };
 
+  uint8_t Version = 0;
   while (!ULEBSizeErr && Cur && Cur.tell() < Content.size()) {
+    if (Sec.sh_type == ELF::SHT_LLVM_BB_ADDR_MAP) {
+      Version = Data.getU8(Cur);
+      if (!Cur)
+        break;
+      if (Version > 1)
+        return createError("unsupported SHT_LLVM_BB_ADDR_MAP version: " +
+                           Twine(static_cast<int>(Version)));
+      Data.getU8(Cur); // Feature byte
+    }
     uintX_t Address = static_cast<uintX_t>(Data.getAddress(Cur));
     uint32_t NumBlocks = ReadULEB128AsUInt32();
     std::vector<BBAddrMap::BBEntry> BBEntries;
+    uint32_t PrevBBEndOffset = 0;
     for (uint32_t BlockID = 0; !ULEBSizeErr && Cur && (BlockID < NumBlocks);
          ++BlockID) {
       uint32_t Offset = ReadULEB128AsUInt32();
       uint32_t Size = ReadULEB128AsUInt32();
       uint32_t Metadata = ReadULEB128AsUInt32();
+      if (Version >= 1) {
+        // Offset is calculated relative to the end of the previous BB.
+        Offset += PrevBBEndOffset;
+        PrevBBEndOffset = Offset + Size;
+      }
       BBEntries.push_back({Offset, Size, Metadata});
     }
-    FunctionEntries.push_back({Address, BBEntries});
+    FunctionEntries.push_back({Address, std::move(BBEntries)});
   }
   // Either Cur is in the error state, or ULEBSizeError is set (not both), but
   // we join the two errors here to be safe.

diff  --git a/llvm/lib/Object/ELFObjectFile.cpp b/llvm/lib/Object/ELFObjectFile.cpp
index dcd2965116480..e6f99eb013bad 100644
--- a/llvm/lib/Object/ELFObjectFile.cpp
+++ b/llvm/lib/Object/ELFObjectFile.cpp
@@ -678,7 +678,8 @@ readBBAddrMapImpl(const ELFFile<ELFT> &EF,
   std::vector<BBAddrMap> BBAddrMaps;
   const auto &Sections = cantFail(EF.sections());
   for (const Elf_Shdr &Sec : Sections) {
-    if (Sec.sh_type != ELF::SHT_LLVM_BB_ADDR_MAP)
+    if (Sec.sh_type != ELF::SHT_LLVM_BB_ADDR_MAP &&
+        Sec.sh_type != ELF::SHT_LLVM_BB_ADDR_MAP_V0)
       continue;
     if (TextSectionIndex) {
       Expected<const Elf_Shdr *> TextSecOrErr = EF.getSection(Sec.sh_link);

diff  --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp
index d86005ca093c2..f5611ed1197bd 100644
--- a/llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -1393,6 +1393,16 @@ void ELFState<ELFT>::writeSectionContent(
     return;
 
   for (const ELFYAML::BBAddrMapEntry &E : *Section.Entries) {
+    // Write version and feature values.
+    if (Section.Type == llvm::ELF::SHT_LLVM_BB_ADDR_MAP) {
+      if (E.Version > 1)
+        WithColor::warning() << "unsupported SHT_LLVM_BB_ADDR_MAP version: "
+                             << static_cast<int>(E.Version)
+                             << "; encoding using the most recent version";
+      CBA.write(E.Version);
+      CBA.write(E.Feature);
+      SHeader.sh_size += 2;
+    }
     // Write the address of the function.
     CBA.write<uintX_t>(E.Address, ELFT::TargetEndianness);
     // Write number of BBEntries (number of basic blocks in the function). This

diff  --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp
index bcae5a2c4c9ee..cdd180cdc15d4 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -654,6 +654,7 @@ void ScalarEnumerationTraits<ELFYAML::ELF_SHT>::enumeration(
   ECase(SHT_LLVM_SYMPART);
   ECase(SHT_LLVM_PART_EHDR);
   ECase(SHT_LLVM_PART_PHDR);
+  ECase(SHT_LLVM_BB_ADDR_MAP_V0);
   ECase(SHT_LLVM_BB_ADDR_MAP);
   ECase(SHT_GNU_ATTRIBUTES);
   ECase(SHT_GNU_HASH);
@@ -1639,6 +1640,7 @@ void MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::mapping(
       Section.reset(new ELFYAML::CallGraphProfileSection());
     sectionMapping(IO, *cast<ELFYAML::CallGraphProfileSection>(Section.get()));
     break;
+  case ELF::SHT_LLVM_BB_ADDR_MAP_V0:
   case ELF::SHT_LLVM_BB_ADDR_MAP:
     if (!IO.outputting())
       Section.reset(new ELFYAML::BBAddrMapSection());
@@ -1768,6 +1770,8 @@ void MappingTraits<ELFYAML::StackSizeEntry>::mapping(
 void MappingTraits<ELFYAML::BBAddrMapEntry>::mapping(
     IO &IO, ELFYAML::BBAddrMapEntry &E) {
   assert(IO.getContext() && "The IO context is not initialized");
+  IO.mapRequired("Version", E.Version);
+  IO.mapOptional("Feature", E.Feature, Hex8(0));
   IO.mapOptional("Address", E.Address, Hex64(0));
   IO.mapOptional("NumBlocks", E.NumBlocks);
   IO.mapOptional("BBEntries", E.BBEntries);

diff  --git a/llvm/test/CodeGen/X86/basic-block-sections-labels-empty-function.ll b/llvm/test/CodeGen/X86/basic-block-sections-labels-empty-function.ll
index 4d814b5b61c77..f878fdf045b11 100644
--- a/llvm/test/CodeGen/X86/basic-block-sections-labels-empty-function.ll
+++ b/llvm/test/CodeGen/X86/basic-block-sections-labels-empty-function.ll
@@ -18,4 +18,6 @@ entry:
 ; CHECK:	func:
 ; CHECK:	.Lfunc_begin1:
 ; CHECK:		.section	.llvm_bb_addr_map,"o", at llvm_bb_addr_map,.text{{$}}
-; CHECK:		.quad	.Lfunc_begin1
+; CHECK-NEXT:		.byte 1			# version
+; CHECK-NEXT:		.byte 0			# feature
+; CHECK-NEXT:		.quad	.Lfunc_begin1	# function address

diff  --git a/llvm/test/CodeGen/X86/basic-block-sections-labels-functions-sections.ll b/llvm/test/CodeGen/X86/basic-block-sections-labels-functions-sections.ll
index d2a2a7bfd52e3..46031e89bcc73 100644
--- a/llvm/test/CodeGen/X86/basic-block-sections-labels-functions-sections.ll
+++ b/llvm/test/CodeGen/X86/basic-block-sections-labels-functions-sections.ll
@@ -10,7 +10,9 @@ define dso_local i32 @_Z3barv() {
 ; CHECK-LABEL:	_Z3barv:
 ; CHECK-NEXT:	[[BAR_BEGIN:.Lfunc_begin[0-9]+]]:
 ; CHECK:		.section .llvm_bb_addr_map,"o", at llvm_bb_addr_map,.text._Z3barv{{$}}
-; CHECK-NEXT:		.quad [[BAR_BEGIN]]
+; CHECK-NEXT:		.byte 1			# version
+; CHECK-NEXT:		.byte 0			# feature
+; CHECK-NEXT:		.quad [[BAR_BEGIN]]	# function address
 
 
 define dso_local i32 @_Z3foov() {
@@ -21,7 +23,9 @@ define dso_local i32 @_Z3foov() {
 ; CHECK-LABEL:	_Z3foov:
 ; CHECK-NEXT:	[[FOO_BEGIN:.Lfunc_begin[0-9]+]]:
 ; CHECK:		.section  .llvm_bb_addr_map,"o", at llvm_bb_addr_map,.text._Z3foov{{$}}
-; CHECK-NEXT:		.quad [[FOO_BEGIN]]
+; CHECK-NEXT:		.byte 1			# version
+; CHECK-NEXT:		.byte 0			# feature
+; CHECK-NEXT:		.quad [[FOO_BEGIN]]	# function address
 
 
 define linkonce_odr dso_local i32 @_Z4fooTIiET_v() comdat {
@@ -32,4 +36,6 @@ define linkonce_odr dso_local i32 @_Z4fooTIiET_v() comdat {
 ; CHECK-LABEL:	_Z4fooTIiET_v:
 ; CHECK-NEXT:	[[FOOCOMDAT_BEGIN:.Lfunc_begin[0-9]+]]:
 ; CHECK:		.section .llvm_bb_addr_map,"Go", at llvm_bb_addr_map,_Z4fooTIiET_v,comdat,.text._Z4fooTIiET_v{{$}}
-; CHECK-NEXT:		.quad [[FOOCOMDAT_BEGIN]]
+; CHECK-NEXT:		.byte 1				# version
+; CHECK-NEXT:		.byte 0				# feature
+; CHECK-NEXT:		.quad [[FOOCOMDAT_BEGIN]]	# function address

diff  --git a/llvm/test/CodeGen/X86/basic-block-sections-labels.ll b/llvm/test/CodeGen/X86/basic-block-sections-labels.ll
index d71559fbbf2cd..64be901052491 100644
--- a/llvm/test/CodeGen/X86/basic-block-sections-labels.ll
+++ b/llvm/test/CodeGen/X86/basic-block-sections-labels.ll
@@ -46,17 +46,19 @@ declare i32 @__gxx_personality_v0(...)
 ; UNIQ:			.section	.llvm_bb_addr_map,"o", at llvm_bb_addr_map,.text._Z3bazb{{$}}
 ;; Verify that with -unique-section-names=false, the unique id of the text section gets assigned to the llvm_bb_addr_map section.
 ; NOUNIQ:		.section	.llvm_bb_addr_map,"o", at llvm_bb_addr_map,.text,unique,1
-; CHECK-NEXT:	.quad	.Lfunc_begin0
-; CHECK-NEXT:	.byte	4
+; CHECK-NEXT:   .byte   1		# version
+; CHECK-NEXT:   .byte   0		# feature
+; CHECK-NEXT:	.quad	.Lfunc_begin0	# function address
+; CHECK-NEXT:	.byte	4		# number of basic blocks
 ; CHECK-NEXT:	.uleb128 .Lfunc_begin0-.Lfunc_begin0
 ; CHECK-NEXT:	.uleb128 .LBB_END0_0-.Lfunc_begin0
 ; CHECK-NEXT:	.byte	8
-; CHECK-NEXT:	.uleb128 .LBB0_1-.Lfunc_begin0
+; CHECK-NEXT:	.uleb128 .LBB0_1-.LBB_END0_0
 ; CHECK-NEXT:	.uleb128 .LBB_END0_1-.LBB0_1
 ; CHECK-NEXT:	.byte	8
-; CHECK-NEXT:	.uleb128 .LBB0_2-.Lfunc_begin0
+; CHECK-NEXT:	.uleb128 .LBB0_2-.LBB_END0_1
 ; CHECK-NEXT:	.uleb128 .LBB_END0_2-.LBB0_2
 ; CHECK-NEXT:	.byte	1
-; CHECK-NEXT:	.uleb128 .LBB0_3-.Lfunc_begin0
+; CHECK-NEXT:	.uleb128 .LBB0_3-.LBB_END0_2
 ; CHECK-NEXT:	.uleb128 .LBB_END0_3-.LBB0_3
 ; CHECK-NEXT:	.byte	5

diff  --git a/llvm/test/tools/llvm-objdump/X86/elf-bbaddrmap-disassemble-symbolize-operands.yaml b/llvm/test/tools/llvm-objdump/X86/elf-bbaddrmap-disassemble-symbolize-operands.yaml
index 38a1cddd3edf6..dc8483520dd8a 100644
--- a/llvm/test/tools/llvm-objdump/X86/elf-bbaddrmap-disassemble-symbolize-operands.yaml
+++ b/llvm/test/tools/llvm-objdump/X86/elf-bbaddrmap-disassemble-symbolize-operands.yaml
@@ -80,18 +80,19 @@ Sections:
     Type:   SHT_LLVM_BB_ADDR_MAP
     Link:   .text
     Entries:
-      - Address: 0x4000
+      - Version: 1
+        Address: 0x4000
         BBEntries:
           - AddressOffset: 0x0
             Size:          0x1
             Metadata:      0x1
-          - AddressOffset: 0x1
+          - AddressOffset: 0x0
             Size:          0x6
             Metadata:      0x0
-          - AddressOffset: 0x8
-            Size:          0x3
+          - AddressOffset: 0x1
+            Size:          0x4
             Metadata:      0x0
-          - AddressOffset: 0xc
+          - AddressOffset: 0x0
             Size:          0x1
             Metadata:      0x2
 Symbols:
@@ -130,33 +131,35 @@ Sections:
     Type:   SHT_LLVM_BB_ADDR_MAP
     Link:   .text.foo
     Entries:
-      - Address: 0x4000
+      - Version: 1
+        Address: 0x4000
         BBEntries:
           - AddressOffset: 0x0
             Size:          0x1
             Metadata:      0x1
-          - AddressOffset: 0x1
+          - AddressOffset: 0x0
             Size:          0x6
             Metadata:      0x0
-          - AddressOffset: 0x8
-            Size:          0x3
+          - AddressOffset: 0x1
+            Size:          0x4
             Metadata:      0x0
-          - AddressOffset: 0xc
+          - AddressOffset: 0x0
             Size:          0x1
             Metadata:      0x2
   - Name:   bb_addr_map.bar
     Type:   SHT_LLVM_BB_ADDR_MAP
     Link:   .text.bar
     Entries:
-      - Address: 0x5000
+      - Version: 1
+        Address: 0x5000
         BBEntries:
           - AddressOffset: 0x0
             Size:          0x1
             Metadata:      0x1
-          - AddressOffset: 0x5
+          - AddressOffset: 0x4
             Size:          0x2
             Metadata:      0x0
-          - AddressOffset: 0x7
+          - AddressOffset: 0x0
             Size:          0x6
             Metadata:      0x0
 

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 0545cd959104a..0f2fa50ccd438 100644
--- a/llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test
+++ b/llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test
@@ -1,75 +1,62 @@
 ## This test checks how we handle the --bb-addr-map option.
 
-# Check 64-bit:
-# RUN: yaml2obj %s -DBITS=64 -DADDR=0x999999999 -o %t1.x64.o
-# RUN: llvm-readobj %t1.x64.o --bb-addr-map 2>&1 | FileCheck %s -DADDR=0x999999999 -DFILE=%t1.x64.o --check-prefix=LLVM
-
+## Check 64-bit:
+# RUN: yaml2obj --docnum=1 %s -DBITS=64 -DADDR=0x999999999 -o %t1.x64.o
+# RUN: llvm-readobj %t1.x64.o --bb-addr-map 2>&1 | FileCheck %s -DADDR=0x999999999 -DFILE=%t1.x64.o --check-prefix=CHECK
 # RUN: llvm-readelf %t1.x64.o --bb-addr-map | FileCheck %s --check-prefix=GNU
 
+## Check 64-bit:
+# RUN: yaml2obj --docnum=1 %s -DBITS=64 -DADDR=0x999999999 -o %t1.v1.x64.o
+# RUN: llvm-readobj %t1.v1.x64.o --bb-addr-map 2>&1 | FileCheck %s -DADDR=0x999999999 -DFILE=%t1.v1.x64.o --check-prefix=CHECK
+
 ## Check 32-bit:
-# RUN: yaml2obj %s -DBITS=32 -o %t1.x32.o
-# RUN: llvm-readobj %t1.x32.o --bb-addr-map 2>&1 | FileCheck -DADDR=0x11111 %s -DFILE=%t1.x32.o --check-prefix=LLVM
+# RUN: yaml2obj --docnum=1 %s -DBITS=32 -o %t1.x32.o
+# RUN: llvm-readobj %t1.x32.o --bb-addr-map 2>&1 | FileCheck -DADDR=0x11111 %s -DFILE=%t1.x32.o --check-prefix=CHECK
 # RUN: llvm-readelf %t1.x32.o --bb-addr-map | FileCheck %s --check-prefix=GNU
 
 ## Check that a malformed section can be handled.
-# RUN: yaml2obj %s -DBITS=32 -DSIZE=4 -o %t2.o
-# RUN: llvm-readobj %t2.o --bb-addr-map 2>&1 | FileCheck %s -DOFFSET=0x00000004 -DFILE=%t2.o --check-prefix=TRUNCATED
+# RUN: yaml2obj --docnum=1 %s -DBITS=32 -DSIZE=6 -o %t2.o
+# RUN: llvm-readobj %t2.o --bb-addr-map 2>&1 | FileCheck %s -DOFFSET=0x00000006 -DFILE=%t2.o --check-prefix=TRUNCATED
 
-# LLVM:      BBAddrMap [
-# LLVM-NEXT:   Function {
-# LLVM-NEXT:     At: [[ADDR]]
-# LLVM-NEXT: warning: '[[FILE]]': could not identify function symbol for address ([[ADDR]]) in SHT_LLVM_BB_ADDR_MAP section with index 3
-# LLVM-NEXT:     Name: <?>
-# LLVM-NEXT:     BB entries [
-# LLVM-NEXT:       {
-# LLVM-NEXT:         Offset: 0x0
-# LLVM-NEXT:         Size: 0x1
-# LLVM-NEXT:         HasReturn: No
-# LLVM-NEXT:         HasTailCall: Yes
-# LLVM-NEXT:         IsEHPad: No
-# LLVM-NEXT:         CanFallThrough: No
-# LLVM-NEXT:       }
-# LLVM-NEXT:       {
-# LLVM-NEXT:         Offset: 0x3
-# LLVM-NEXT:         Size: 0x4
-# LLVM-NEXT:         HasReturn: Yes
-# LLVM-NEXT:         HasTailCall: No
-# LLVM-NEXT:         IsEHPad: Yes
-# LLVM-NEXT:         CanFallThrough: No
-# LLVM-NEXT:       }
-# LLVM-NEXT:     ]
-# LLVM-NEXT:   }
-# LLVM-NEXT:   Function {
-# LLVM-NEXT:     At: 0x22222
-# LLVM-NEXT:     Name: foo
-# LLVM-NEXT:     BB entries [
-# LLVM-NEXT:       {
-# LLVM-NEXT:         Offset: 0x6
-# LLVM-NEXT:         Size: 0x7
-# LLVM-NEXT:         HasReturn: No
-# LLVM-NEXT:         HasTailCall: No
-# LLVM-NEXT:         IsEHPad: No
-# LLVM-NEXT:         CanFallThrough: Yes
-# LLVM-NEXT:       }
-# LLVM-NEXT:     ]
-# LLVM-NEXT:   }
-# LLVM-NEXT: ]
-# LLVM-NEXT: BBAddrMap [
-# LLVM-NEXT:   Function {
-# LLVM-NEXT:     At: 0x33333
-# LLVM-NEXT:     Name: bar
-# LLVM-NEXT:     BB entries [
-# LLVM-NEXT:       {
-# LLVM-NEXT:         Offset: 0x9
-# LLVM-NEXT:         Size: 0xA
-# LLVM-NEXT:         HasReturn: Yes
-# LLVM-NEXT:         HasTailCall: Yes
-# LLVM-NEXT:         IsEHPad: No
-# LLVM-NEXT:         CanFallThrough: Yes
-# LLVM-NEXT:       }
-# LLVM-NEXT:     ]
-# LLVM-NEXT:   }
-# LLVM-NEXT: ]
+# CHECK:      BBAddrMap [
+# CHECK-NEXT:   Function {
+# CHECK-NEXT:     At: [[ADDR]]
+# CHECK-NEXT: warning: '[[FILE]]': could not identify function symbol for address ([[ADDR]]) in SHT_LLVM_BB_ADDR_MAP section with index 3
+# CHECK-NEXT:     Name: <?>
+# CHECK-NEXT:     BB entries [
+# CHECK-NEXT:       {
+# CHECK-NEXT:         Offset: 0x0
+# CHECK-NEXT:         Size: 0x1
+# CHECK-NEXT:         HasReturn: No
+# CHECK-NEXT:         HasTailCall: Yes
+# CHECK-NEXT:         IsEHPad: No
+# CHECK-NEXT:         CanFallThrough: No
+# CHECK-NEXT:       }
+# CHECK-NEXT:       {
+# CHECK-NEXT:         Offset: 0x4
+# CHECK-NEXT:         Size: 0x4
+# CHECK-NEXT:         HasReturn: Yes
+# CHECK-NEXT:         HasTailCall: No
+# CHECK-NEXT:         IsEHPad: Yes
+# CHECK-NEXT:         CanFallThrough: No
+# CHECK-NEXT:       }
+# CHECK-NEXT:     ]
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Function {
+# CHECK-NEXT:     At: 0x22222
+# CHECK-NEXT:     Name: foo
+# CHECK-NEXT:     BB entries [
+# CHECK-NEXT:       {
+# CHECK-NEXT:         Offset: 0x6
+# CHECK-NEXT:         Size: 0x7
+# CHECK-NEXT:         HasReturn: No
+# CHECK-NEXT:         HasTailCall: No
+# CHECK-NEXT:         IsEHPad: No
+# CHECK-NEXT:         CanFallThrough: Yes
+# CHECK-NEXT:       }
+# CHECK-NEXT:     ]
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
 
 # GNU: GNUStyle::printBBAddrMaps not implemented
 
@@ -90,6 +77,14 @@
 # TRUNCATED-NEXT:         IsEHPad: No
 # TRUNCATED-NEXT:         CanFallThrough: Yes
 # TRUNCATED-NEXT:       }
+# TRUNCATED-NEXT:       {
+# TRUNCATED-NEXT:         Offset: 0x1F
+# TRUNCATED-NEXT:         Size: 0xD
+# TRUNCATED-NEXT:         HasReturn: No
+# TRUNCATED-NEXT:         HasTailCall: Yes
+# TRUNCATED-NEXT:         IsEHPad: Yes
+# TRUNCATED-NEXT:         CanFallThrough: Yes
+# TRUNCATED-NEXT:       }
 # TRUNCATED-NEXT:     ]
 # TRUNCATED-NEXT:   }
 # TRUNCATED-NEXT: ]
@@ -106,12 +101,13 @@ Sections:
   - Name:   .text.bar
     Type:   SHT_PROGBITS
     Flags:  [SHF_ALLOC]
-  - Name:   bb_addr_map_1
+  - Name:   .llvm_bb_addr_map
     Type:   SHT_LLVM_BB_ADDR_MAP
     ShSize: [[SIZE=<none>]]
     Link:   .text
     Entries:
-      - Address: [[ADDR=0x11111]]
+      - Version: 1
+        Address: [[ADDR=0x11111]]
         BBEntries:
           - AddressOffset: 0x0
             Size:          0x1
@@ -119,23 +115,28 @@ Sections:
           - AddressOffset: 0x3
             Size:          0x4
             Metadata:      0x5
-      - Address: 0x22222
+      - Version: 1
+        Address: 0x22222
         BBEntries:
           - AddressOffset: 0x6
             Size:          0x7
             Metadata:      0x8
-  - Name:   dummy_section
-    Type:   SHT_PROGBITS
-    Size:   16
-  - Name:   bb_addr_map_2
-    Type:   SHT_LLVM_BB_ADDR_MAP
-    Link:   .text.bar
+  - Name: dummy_section
+    Type: SHT_PROGBITS
+    Size: 16
+  - Name: '.llvm_bb_addr_map (1)'
+    Type: SHT_LLVM_BB_ADDR_MAP
+    Link: .text.bar
     Entries:
-      - Address: 0x33333
+      - Version: 1
+        Address: 0x33333
         BBEntries:
           - AddressOffset: 0x9
             Size:          0xa
             Metadata:      0xb
+          - AddressOffset: 0xc
+            Size:          0xd
+            Metadata:      0xe
 Symbols:
   - Name:    foo
     Section: .text
@@ -145,3 +146,67 @@ Symbols:
     Section: .text.bar
     Type:    STT_FUNC
     Value:   0x33333
+
+## Check that using the SHT_LLVM_BB_ADDR_MAP_V0 section type generates the same
+## result as using the SHT_LLVM_BB_ADDR_MAP section type with Version=0.
+## The Version field is required even for SHT_LLVM_BB_ADDR_MAP_V0 but it
+## should not impact the result. This unideal behavior will be gone once
+## SHT_LLVM_BB_ADDR_MAP_V0 is deprecated.
+
+# RUN: yaml2obj --docnum=2 %s -DVERSION=255 -DSECTION_TYPE=SHT_LLVM_BB_ADDR_MAP_V0 -o %t2.type0
+# RUN: llvm-readobj %t2.type0 --bb-addr-map 2>&1 | FileCheck %s --check-prefix=V0
+
+# RUN: yaml2obj --docnum=2 %s -DVERSION=0 -DSECTION_TYPE=SHT_LLVM_BB_ADDR_MAP -o %t2.version0
+# RUN: llvm-readobj %t2.version0 --bb-addr-map 2>&1 | FileCheck %s --check-prefix=V0
+
+# V0:      BBAddrMap [
+# V0-NEXT:   Function {
+# V0-NEXT:     At:   0x11111
+# V0-NEXT:     Name: foo
+# V0-NEXT:     BB entries [
+# V0-NEXT:       {
+# V0-NEXT:         Offset: 0x1
+# V0-NEXT:         Size: 0x2
+# V0-NEXT:         HasReturn:
+# V0-NEXT:         HasTailCall:
+# V0-NEXT:         IsEHPad:
+# V0-NEXT:         CanFallThrough:
+# V0-NEXT:       }
+# V0-NEXT:       {
+# V0-NEXT:         Offset: 0x4
+# V0-NEXT:         Size: 0x5
+# V0-NEXT:         HasReturn:
+# V0-NEXT:         HasTailCall:
+# V0-NEXT:         IsEHPad:
+# V0-NEXT:         CanFallThrough:
+# V0-NEXT:       }
+# V0-NEXT:     ]
+# V0-NEXT:   }
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+Sections:
+  - Name:  .text.foo
+    Type:  SHT_PROGBITS
+    Flags: [SHF_ALLOC]
+  - Name:  .llvm_bb_addr_map
+    Type:  [[SECTION_TYPE]]
+    Link:  .text.foo
+    Entries:
+      - Version: [[VERSION]]
+        Address: 0x11111
+        BBEntries:
+          - AddressOffset: 0x1
+            Size:          0x2
+            Metadata:      0x3
+          - AddressOffset: 0x4
+            Size:          0x5
+            Metadata:      0x6
+Symbols:
+  - Name:    foo
+    Section: .text.foo
+    Type:    STT_FUNC
+    Value:   0x11111

diff  --git a/llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml b/llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml
index b5218f91ea00a..fcd650d3331ce 100644
--- a/llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml
+++ b/llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml
@@ -7,29 +7,33 @@
 
 # VALID:      --- !ELF
 # VALID-NEXT: FileHeader:
-# VALID-NEXT:   Class:   ELFCLASS64
-# VALID-NEXT:   Data:    ELFDATA2LSB
-# VALID-NEXT:   Type:    ET_EXEC
+# VALID-NEXT:   Class: ELFCLASS64
+# VALID-NEXT:   Data:  ELFDATA2LSB
+# VALID-NEXT:   Type:  ET_EXEC
 # VALID-NEXT: Sections:
 # VALID-NEXT:   - Name: .llvm_bb_addr_map
 # VALID-NEXT:     Type: SHT_LLVM_BB_ADDR_MAP
 # VALID-NEXT:     Entries:
 ## The 'Address' field is omitted when it's zero.
+# VALID-NEXT:       - Version: 1
+# VALID-NEXT:         Feature: 0xFF
 # VALID-NEXT:         BBEntries:
-# VALID-NEXT:           - AddressOffset:    0x1
-# VALID-NEXT:             Size:             0x2
-# VALID-NEXT:             Metadata:         0x3
-# VALID-NEXT:           - AddressOffset:    0x4
-# VALID-NEXT:             Size:             0x5
-# VALID-NEXT:             Metadata:         0x6
-# VALID-NEXT:           - AddressOffset:    0xFFFFFFFFFFFFFFF7
-# VALID-NEXT:             Size:             0xFFFFFFFFFFFFFFF8
-# VALID-NEXT:             Metadata:         0xFFFFFFFFFFFFFFF9
-# VALID-NEXT:       - Address:   0xFFFFFFFFFFFFFF20
+# VALID-NEXT:           - AddressOffset: 0x1
+# VALID-NEXT:             Size:          0x2
+# VALID-NEXT:             Metadata:      0x3
+# VALID-NEXT:           - AddressOffset: 0x4
+# VALID-NEXT:             Size:          0x5
+# VALID-NEXT:             Metadata:      0x6
+# VALID-NEXT:           - AddressOffset: 0xFFFFFFFFFFFFFFF7
+# VALID-NEXT:             Size:          0xFFFFFFFFFFFFFFF8
+# VALID-NEXT:             Metadata:      0xFFFFFFFFFFFFFFF9
+# VALID-NEXT:       - Version: 1
+# VALID-NEXT:         Feature: 0xEE
+# VALID-NEXT:         Address: 0xFFFFFFFFFFFFFF20
 # VALID-NEXT:         BBEntries:
-# VALID-NEXT:           - AddressOffset:    0xA
-# VALID-NEXT:             Size:             0xB
-# VALID-NEXT:             Metadata:         0xC
+# VALID-NEXT:           - AddressOffset: 0xA
+# VALID-NEXT:             Size:          0xB
+# VALID-NEXT:             Metadata:      0xC
 
 --- !ELF
 FileHeader:
@@ -37,27 +41,31 @@ FileHeader:
   Data:  ELFDATA2LSB
   Type:  ET_EXEC
 Sections:
-  - Name:    .llvm_bb_addr_map
-    Type:    SHT_LLVM_BB_ADDR_MAP
-    ShSize:    [[SIZE=<none>]]
+  - Name:   .llvm_bb_addr_map
+    Type:   SHT_LLVM_BB_ADDR_MAP
+    ShSize: [[SIZE=<none>]]
     Entries:
-      - Address:   0x0
-        NumBlocks: [[NUMBLOCKS=<none>]]
+      - Version: 1
+        Feature: 0xFF
+        Address: 0x0
         BBEntries:
-          - AddressOffset:    0x1
-            Size:             0x2
-            Metadata:         0x3
-          - AddressOffset:    0x4
-            Size:             0x5
-            Metadata:         0x6
-          - AddressOffset:    0xFFFFFFFFFFFFFFF7
-            Size:             0xFFFFFFFFFFFFFFF8
-            Metadata:         0xFFFFFFFFFFFFFFF9
-      - Address:   0xFFFFFFFFFFFFFF20
+          - AddressOffset: 0x1
+            Size:          0x2
+            Metadata:      0x3
+          - AddressOffset: 0x4
+            Size:          0x5
+            Metadata:      0x6
+          - AddressOffset: 0xFFFFFFFFFFFFFFF7
+            Size:          0xFFFFFFFFFFFFFFF8
+            Metadata:      0xFFFFFFFFFFFFFFF9
+      - Version:   1
+        Feature:   0xEE
+        Address:   0xFFFFFFFFFFFFFF20
+        NumBlocks: [[NUMBLOCKS=<none>]]
         BBEntries:
-          - AddressOffset:    0xA
-            Size:             0xB
-            Metadata:         0xC
+          - AddressOffset: 0xA
+            Size:          0xB
+            Metadata:      0xC
 
 ## Check obj2yaml can dump empty .llvm_bb_addr_map sections.
 
@@ -95,18 +103,20 @@ Sections:
 # MULTI-NEXT:   Data:  ELFDATA2LSB
 # MULTI-NEXT:   Type:  ET_EXEC
 # MULTI-NEXT: Sections:
-# MULTI-NEXT:   - Name:    .llvm_bb_addr_map
-# MULTI-NEXT:     Type:    SHT_LLVM_BB_ADDR_MAP
+# MULTI-NEXT:   - Name: .llvm_bb_addr_map
+# MULTI-NEXT:     Type: SHT_LLVM_BB_ADDR_MAP
 # MULTI-NEXT:     Entries:
-## The 'Address' field is omitted when it's zero.
-# MULTI-NEXT:       - BBEntries:
-# MULTI-NEXT:           - AddressOffset:    0x1
-# MULTI-NEXT:             Size:             0x2
-# MULTI-NEXT:             Metadata:         0x3
-# MULTI-NEXT:   - Name:    '.llvm_bb_addr_map (1)'
-# MULTI-NEXT:     Type:    SHT_LLVM_BB_ADDR_MAP
+## Fields 'Address' and 'Feature' are omitted when they are zero.
+# MULTI-NEXT:       - Version: 0
+# MULTI-NEXT:         BBEntries:
+# MULTI-NEXT:           - AddressOffset: 0x1
+# MULTI-NEXT:             Size:          0x2
+# MULTI-NEXT:             Metadata:      0x3
+# MULTI-NEXT:   - Name: '.llvm_bb_addr_map (1)'
+# MULTI-NEXT:     Type: SHT_LLVM_BB_ADDR_MAP
 # MULTI-NEXT:     Entries:
-# MULTI-NEXT:       - Address: 0x20
+# MULTI-NEXT:       - Version:   0
+# MULTI-NEXT:         Address:   0x20
 # MULTI-NEXT:         BBEntries: []
 
 --- !ELF
@@ -115,19 +125,23 @@ FileHeader:
   Data:  ELFDATA2LSB
   Type:  ET_EXEC
 Sections:
-  - Name:    .llvm_bb_addr_map
-    Type:    SHT_LLVM_BB_ADDR_MAP
+  - Name: .llvm_bb_addr_map
+    Type: SHT_LLVM_BB_ADDR_MAP
     Entries:
-## Check that obj2yaml does not emit the Address field when it's zero.
-      - Address:   0x0
+## Check that obj2yaml does not emit the 'Address' and 'Feature' fields when
+## they are zero.
+      - Version: 0
+        Feature: 0x0
+        Address: 0x0
         BBEntries:
-          - AddressOffset:    0x1
-            Size:             0x2
-            Metadata:         0x3
-  - Name:    '.llvm_bb_addr_map (1)'
-    Type:    SHT_LLVM_BB_ADDR_MAP
+          - AddressOffset: 0x1
+            Size:          0x2
+            Metadata:      0x3
+  - Name: '.llvm_bb_addr_map (1)'
+    Type:  SHT_LLVM_BB_ADDR_MAP
     Entries:
-      - Address:   0x20
+      - Version: 0
+        Address: 0x20
 
 ## Check that obj2yaml uses the "Content" tag to describe an .llvm_bb_addr_map section
 ## when it can't extract the entries, for example, when the section is truncated, or
@@ -141,11 +155,47 @@ Sections:
 
 # INVALID:           --- !ELF
 # INVALID-NEXT:      FileHeader:
-# INVALID-NEXT:        Class:   ELFCLASS64
-# INVALID-NEXT:        Data:    ELFDATA2LSB
-# INVALID-NEXT:        Type:    ET_EXEC
+# INVALID-NEXT:        Class: ELFCLASS64
+# INVALID-NEXT:        Data:  ELFDATA2LSB
+# INVALID-NEXT:        Type:  ET_EXEC
 # INVALID-NEXT:      Sections:
-# INVALID-NEXT:        - Name: .llvm_bb_addr_map
-# INVALID-NEXT:          Type: SHT_LLVM_BB_ADDR_MAP
+# INVALID-NEXT:        - Name:    .llvm_bb_addr_map
+# INVALID-NEXT:          Type:    SHT_LLVM_BB_ADDR_MAP
 # BADNUMBLOCKS-NEXT:     Content: {{([[:xdigit:]]+)}}{{$}}
-# TRUNCATED-NEXT:        Content: '{{([[:xdigit:]]{16})}}'{{$}}
+# TRUNCATED-NEXT:        Content: {{([[:xdigit:]]{16})}}{{$}}
+
+## Check obj2yaml for SHT_LLVM_BB_ADDR_MAP_V0.
+# RUN: yaml2obj --docnum=4 %s -o %t6
+# RUN: obj2yaml %t6 | FileCheck %s --check-prefix=V0
+
+# V0:      --- !ELF
+# V0-NEXT: FileHeader:
+# V0-NEXT:   Class: ELFCLASS64
+# V0-NEXT:   Data:  ELFDATA2LSB
+# V0-NEXT:   Type:  ET_EXEC
+# V0-NEXT: Sections:
+# V0-NEXT:   - Name: .llvm_bb_addr_map
+# V0-NEXT:     Type: SHT_LLVM_BB_ADDR_MAP_V0
+# V0-NEXT:     Entries:
+# V0-NEXT:       - Version: 0
+# V0-NEXT:         Address: 0x1111
+# V0-NEXT:         BBEntries:
+# V0-NEXT:           - AddressOffset: 0x1
+# V0-NEXT:             Size:          0x2
+# V0-NEXT:             Metadata:      0x3
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+Sections:
+  - Name: .llvm_bb_addr_map
+    Type: SHT_LLVM_BB_ADDR_MAP_V0
+    Entries:
+      - Version: 0
+        Address: 0x1111
+        BBEntries:
+          - AddressOffset: 0x1
+            Size:          0x2
+            Metadata:      0x3

diff  --git a/llvm/test/tools/yaml2obj/ELF/bb-addr-map.yaml b/llvm/test/tools/yaml2obj/ELF/bb-addr-map.yaml
index 8318fc4df1da3..1ca30f9bb4ba1 100644
--- a/llvm/test/tools/yaml2obj/ELF/bb-addr-map.yaml
+++ b/llvm/test/tools/yaml2obj/ELF/bb-addr-map.yaml
@@ -7,7 +7,7 @@
 # CHECK:      Section {
 # CHECK:        Index: 1
 # CHECK-NEXT:   Name: .llvm_bb_addr_map (1)
-# CHECK-NEXT:   Type: SHT_LLVM_BB_ADDR_MAP (0x6FFF4C08)
+# CHECK-NEXT:   Type: SHT_LLVM_BB_ADDR_MAP (0x6FFF4C0A)
 # CHECK-NEXT:   Flags [ (0x0)
 # CHECK-NEXT:   ]
 # CHECK-NEXT:   Address: 0x0
@@ -36,7 +36,7 @@
 # Case 4: Specify Entries.
 # CHECK:        Name: .llvm_bb_addr_map (1)
 # CHECK:        SectionData (
-# CHECK-NEXT:     0000: 20000000 00000000 01010203
+# CHECK-NEXT:     0000: 01002000 00000000 00000101 0203
 # CHECK-NEXT:   )
 
 # Case 5: Specify Entries and omit the Address field.
@@ -44,13 +44,13 @@
 # CHECK:        Address:
 # CHECK-SAME:   {{^ 0x0$}}
 # CHECK:        SectionData (
-# CHECK-NEXT:     0000: 00000000 00000000 01010203
+# CHECK-NEXT:     0000: 00000000 00000000 00000101 0203
 # CHECK-NEXT:   )
 
 # Case 6: Override the NumBlocks field.
 # CHECK:        Name: .llvm_bb_addr_map (1)
 # CHECK:        SectionData (
-# CHECK-NEXT:     0000: 20000000 00000000 02010203
+# CHECK-NEXT:     0000: 01002000 00000000 00000201 0203
 # CHECK-NEXT:   )
 
 --- !ELF
@@ -71,47 +71,50 @@ Sections:
 
 ## 2) We can produce an empty .llvm_bb_addr_map section from a description
 ##    with empty section content.
-  - Name:    '.llvm_bb_addr_map (2)'
-    Type:    SHT_LLVM_BB_ADDR_MAP
+  - Name: '.llvm_bb_addr_map (2)'
+    Type: SHT_LLVM_BB_ADDR_MAP
 
 ## 3) We can produce a zero .llvm_bb_addr_map section of a specific size when
 ##    we specify the size only.
-  - Name:    '.llvm_bb_addr_map (3)'
-    Type:    SHT_LLVM_BB_ADDR_MAP
-    Size:    8
+  - Name: '.llvm_bb_addr_map (3)'
+    Type: SHT_LLVM_BB_ADDR_MAP
+    Size: 8
 
 ## 4) We can produce an .llvm_bb_addr_map section from a description with
 ##    Entries.
-  - Name:    '.llvm_bb_addr_map (4)'
-    Type:    SHT_LLVM_BB_ADDR_MAP
+  - Name: '.llvm_bb_addr_map (4)'
+    Type: SHT_LLVM_BB_ADDR_MAP
     Entries:
-      - Address:   0x0000000000000020
+      - Version: 1
+        Address: 0x0000000000000020
         BBEntries:
-          - AddressOffset:    0x00000001
-            Size:             0x00000002
-            Metadata:         0x00000003
+          - AddressOffset: 0x00000001
+            Size:          0x00000002
+            Metadata:      0x00000003
 
 ## 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
+  - Name: '.llvm_bb_addr_map (5)'
+    Type: SHT_LLVM_BB_ADDR_MAP
     Entries:
-      - BBEntries:
-          - AddressOffset:    0x00000001
-            Size:             0x00000002
-            Metadata:         0x00000003
+      - Version: 0
+        BBEntries:
+          - AddressOffset: 0x00000001
+            Size:          0x00000002
+            Metadata:      0x00000003
 
 ## 6) We can override the NumBlocks field with a value 
diff erent from the
 ##    actual number of BB Entries.
-  - Name:    '.llvm_bb_addr_map (6)'
-    Type:    SHT_LLVM_BB_ADDR_MAP
+  - Name: '.llvm_bb_addr_map (6)'
+    Type: SHT_LLVM_BB_ADDR_MAP
     Entries:
-      - Address:   0x0000000000000020
+      - Version:   1
+        Address:   0x0000000000000020
         NumBlocks: 2
         BBEntries:
-          - AddressOffset:    0x00000001
-            Size:             0x00000002
-            Metadata:         0x00000003
+          - AddressOffset: 0x00000001
+            Size:          0x00000002
+            Metadata:      0x00000003
 
 ## 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
@@ -131,3 +134,19 @@ Sections:
     Entries: []
     Content: [[CONTENT=<none>]]
     Size:    [[SIZE=<none>]]
+
+## 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: 2; encoding using the most recent version
+
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+  Type:  ET_EXEC
+Sections:
+  - Name: '.llvm_bb_addr_map'
+    Type: SHT_LLVM_BB_ADDR_MAP
+    Entries:
+##  Specify unsupported version
+      - Version: 2

diff  --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index faf38bd33e227..9f10a9e07320f 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -7028,8 +7028,10 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printCGProfile() {
 template <class ELFT> void LLVMELFDumper<ELFT>::printBBAddrMaps() {
   bool IsRelocatable = this->Obj.getHeader().e_type == ELF::ET_REL;
   for (const Elf_Shdr &Sec : cantFail(this->Obj.sections())) {
-    if (Sec.sh_type != SHT_LLVM_BB_ADDR_MAP)
+    if (Sec.sh_type != SHT_LLVM_BB_ADDR_MAP &&
+        Sec.sh_type != SHT_LLVM_BB_ADDR_MAP_V0) {
       continue;
+    }
     Optional<const Elf_Shdr *> FunctionSec = None;
     if (IsRelocatable)
       FunctionSec =

diff  --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp
index 9426996d3d415..8363700df9f92 100644
--- a/llvm/tools/obj2yaml/elf2yaml.cpp
+++ b/llvm/tools/obj2yaml/elf2yaml.cpp
@@ -626,6 +626,7 @@ ELFDumper<ELFT>::dumpSections() {
     case ELF::SHT_LLVM_CALL_GRAPH_PROFILE:
       return
           [this](const Elf_Shdr *S) { return dumpCallGraphProfileSection(S); };
+    case ELF::SHT_LLVM_BB_ADDR_MAP_V0:
     case ELF::SHT_LLVM_BB_ADDR_MAP:
       return [this](const Elf_Shdr *S) { return dumpBBAddrMapSection(S); };
     case ELF::SHT_STRTAB:
@@ -889,7 +890,18 @@ ELFDumper<ELFT>::dumpBBAddrMapSection(const Elf_Shdr *Shdr) {
 
   std::vector<ELFYAML::BBAddrMapEntry> Entries;
   DataExtractor::Cursor Cur(0);
+  uint8_t Version = 0;
+  uint8_t Feature = 0;
   while (Cur && Cur.tell() < Content.size()) {
+    if (Shdr->sh_type == ELF::SHT_LLVM_BB_ADDR_MAP) {
+      Version = Data.getU8(Cur);
+      if (Cur && Version > 1)
+        return createStringError(
+            errc::invalid_argument,
+            "invalid SHT_LLVM_BB_ADDR_MAP section version: " +
+                Twine(static_cast<int>(Version)));
+      Feature = Data.getU8(Cur);
+    }
     uint64_t Address = Data.getAddress(Cur);
     uint64_t NumBlocks = Data.getULEB128(Cur);
     std::vector<ELFYAML::BBAddrMapEntry::BBEntry> BBEntries;
@@ -900,7 +912,8 @@ ELFDumper<ELFT>::dumpBBAddrMapSection(const Elf_Shdr *Shdr) {
       uint64_t Metadata = Data.getULEB128(Cur);
       BBEntries.push_back({Offset, Size, Metadata});
     }
-    Entries.push_back({Address, /*NumBlocks=*/{}, BBEntries});
+    Entries.push_back(
+        {Version, Feature, Address, /*NumBlocks=*/{}, std::move(BBEntries)});
   }
 
   if (!Cur) {

diff  --git a/llvm/unittests/Object/ELFObjectFileTest.cpp b/llvm/unittests/Object/ELFObjectFileTest.cpp
index ca22fb0cdeef4..877a140f969a7 100644
--- a/llvm/unittests/Object/ELFObjectFileTest.cpp
+++ b/llvm/unittests/Object/ELFObjectFileTest.cpp
@@ -505,14 +505,10 @@ TEST(ELFObjectFileTest, InvalidDecodeBBAddrMap) {
   Data:  ELFDATA2LSB
   Type:  ET_EXEC
 Sections:
-  - Name: .llvm_bb_addr_map
-    Type: SHT_LLVM_BB_ADDR_MAP
+  - Type: SHT_LLVM_BB_ADDR_MAP
+    Name: .llvm_bb_addr_map
     Entries:
       - Address: 0x11111
-        BBEntries:
-          - AddressOffset: 0x0
-            Size:          0x1
-            Metadata:      0x2
 )");
 
   auto DoCheck = [&](StringRef YamlString, const char *ErrMsg) {
@@ -529,19 +525,41 @@ TEST(ELFObjectFileTest, InvalidDecodeBBAddrMap) {
                       FailedWithMessage(ErrMsg));
   };
 
+  // Check that we can detect unsupported versions.
+  SmallString<128> UnsupportedVersionYamlString(CommonYamlString);
+  UnsupportedVersionYamlString += R"(
+        Version: 2
+        BBEntries:
+          - AddressOffset: 0x0
+            Size:          0x1
+            Metadata:      0x2
+)";
+
+  DoCheck(UnsupportedVersionYamlString,
+          "unsupported SHT_LLVM_BB_ADDR_MAP version: 2");
+
+  SmallString<128> CommonVersionedYamlString(CommonYamlString);
+  CommonVersionedYamlString += R"(
+        Version: 1
+        BBEntries:
+          - AddressOffset: 0x0
+            Size:          0x1
+            Metadata:      0x2
+)";
+
   // Check that we can detect the malformed encoding when the section is
   // truncated.
-  SmallString<128> TruncatedYamlString(CommonYamlString);
+  SmallString<128> TruncatedYamlString(CommonVersionedYamlString);
   TruncatedYamlString += R"(
-    ShSize: 0x8
+    ShSize: 0xa
 )";
-  DoCheck(TruncatedYamlString, "unable to decode LEB128 at offset 0x00000008: "
+  DoCheck(TruncatedYamlString, "unable to decode LEB128 at offset 0x0000000a: "
                                "malformed uleb128, extends past end");
 
   // Check that we can detect when the encoded BB entry fields exceed the UINT32
   // limit.
-  SmallVector<SmallString<128>, 3> OverInt32LimitYamlStrings(3,
-                                                             CommonYamlString);
+  SmallVector<SmallString<128>, 3> OverInt32LimitYamlStrings(
+      3, CommonVersionedYamlString);
   OverInt32LimitYamlStrings[0] += R"(
           - AddressOffset: 0x100000000
             Size:          0xFFFFFFFF
@@ -561,11 +579,11 @@ TEST(ELFObjectFileTest, InvalidDecodeBBAddrMap) {
 )";
 
   DoCheck(OverInt32LimitYamlStrings[0],
-          "ULEB128 value at offset 0xc exceeds UINT32_MAX (0x100000000)");
+          "ULEB128 value at offset 0xe exceeds UINT32_MAX (0x100000000)");
   DoCheck(OverInt32LimitYamlStrings[1],
-          "ULEB128 value at offset 0x11 exceeds UINT32_MAX (0x100000000)");
+          "ULEB128 value at offset 0x13 exceeds UINT32_MAX (0x100000000)");
   DoCheck(OverInt32LimitYamlStrings[2],
-          "ULEB128 value at offset 0x16 exceeds UINT32_MAX (0x100000000)");
+          "ULEB128 value at offset 0x18 exceeds UINT32_MAX (0x100000000)");
 
   // Check the proper error handling when the section has fields exceeding
   // UINT32 and is also truncated. This is for checking that we don't generate
@@ -574,34 +592,34 @@ TEST(ELFObjectFileTest, InvalidDecodeBBAddrMap) {
       3, OverInt32LimitYamlStrings[1]);
   // Truncate before the end of the 5-byte field.
   OverInt32LimitAndTruncated[0] += R"(
-    ShSize: 0x15
+    ShSize: 0x17
 )";
   // Truncate at the end of the 5-byte field.
   OverInt32LimitAndTruncated[1] += R"(
-    ShSize: 0x16
+    ShSize: 0x18
 )";
   // Truncate after the end of the 5-byte field.
   OverInt32LimitAndTruncated[2] += R"(
-    ShSize: 0x17
+    ShSize: 0x19
 )";
 
   DoCheck(OverInt32LimitAndTruncated[0],
-          "unable to decode LEB128 at offset 0x00000011: malformed uleb128, "
+          "unable to decode LEB128 at offset 0x00000013: malformed uleb128, "
           "extends past end");
   DoCheck(OverInt32LimitAndTruncated[1],
-          "ULEB128 value at offset 0x11 exceeds UINT32_MAX (0x100000000)");
+          "ULEB128 value at offset 0x13 exceeds UINT32_MAX (0x100000000)");
   DoCheck(OverInt32LimitAndTruncated[2],
-          "ULEB128 value at offset 0x11 exceeds UINT32_MAX (0x100000000)");
+          "ULEB128 value at offset 0x13 exceeds UINT32_MAX (0x100000000)");
 
   // Check for proper error handling when the 'NumBlocks' field is overridden
   // with an out-of-range value.
-  SmallString<128> OverLimitNumBlocks(CommonYamlString);
+  SmallString<128> OverLimitNumBlocks(CommonVersionedYamlString);
   OverLimitNumBlocks += R"(
         NumBlocks: 0x100000000
 )";
 
   DoCheck(OverLimitNumBlocks,
-          "ULEB128 value at offset 0x8 exceeds UINT32_MAX (0x100000000)");
+          "ULEB128 value at offset 0xa exceeds UINT32_MAX (0x100000000)");
 }
 
 // Test for the ELFObjectFile::readBBAddrMap API.
@@ -617,7 +635,8 @@ TEST(ELFObjectFileTest, ReadBBAddrMap) {
     Type: SHT_LLVM_BB_ADDR_MAP
     Link: 1
     Entries:
-      - Address: 0x11111
+      - Version: 1
+        Address: 0x11111
         BBEntries:
           - AddressOffset: 0x0
             Size:          0x1
@@ -626,16 +645,18 @@ TEST(ELFObjectFileTest, ReadBBAddrMap) {
     Type: SHT_LLVM_BB_ADDR_MAP
     Link: 1
     Entries:
-      - Address: 0x22222
+      - Version: 1
+        Address: 0x22222
         BBEntries:
           - AddressOffset: 0x0
             Size:          0x2
             Metadata:      0x4
   - Name: .llvm_bb_addr_map
-    Type: SHT_LLVM_BB_ADDR_MAP
+    Type: SHT_LLVM_BB_ADDR_MAP_V0
   # Link: 0 (by default)
     Entries:
-      - Address: 0x33333
+      - Version: 0
+        Address: 0x33333
         BBEntries:
           - AddressOffset: 0x0
             Size:          0x3
@@ -697,8 +718,9 @@ TEST(ELFObjectFileTest, ReadBBAddrMap) {
 )";
 
   DoCheckFails(InvalidLinkedYamlString, /*TextSectionIndex=*/1,
-               "unable to get the linked-to section for SHT_LLVM_BB_ADDR_MAP "
-               "section with index 3: invalid section index: 10");
+               "unable to get the linked-to section for "
+               "SHT_LLVM_BB_ADDR_MAP_V0 section with index 3: invalid section "
+               "index: 10");
   // Linked sections are not checked when we don't target a specific text
   // section.
   DoCheckSucceeds(InvalidLinkedYamlString, /*TextSectionIndex=*/None,
@@ -711,7 +733,7 @@ TEST(ELFObjectFileTest, ReadBBAddrMap) {
 )";
 
   DoCheckFails(TruncatedYamlString, /*TextSectionIndex=*/None,
-               "unable to read SHT_LLVM_BB_ADDR_MAP section with index 3: "
+               "unable to read SHT_LLVM_BB_ADDR_MAP_V0 section with index 3: "
                "unable to decode LEB128 at offset 0x00000008: malformed "
                "uleb128, extends past end");
   // Check that we can read the other section's bb-address-maps which are


        


More information about the llvm-commits mailing list