[lld] [llvm] [clang] [SHT_LLVM_BB_ADDR_MAP] Allow basic-block-sections and labels be used … (PR #74128)

Rahman Lavaee via cfe-commits cfe-commits at lists.llvm.org
Fri Dec 1 11:00:09 PST 2023


https://github.com/rlavaee created https://github.com/llvm/llvm-project/pull/74128

…together by decoupling the handling of the two features.

Today `-split-machine-functions` (MFS) and `-fbasic-block-sections={all,list}` cannot be combined with `-basic-block-sections=labels` (the labels option will be ignored). The inconsistency comes from the way basic block address map -- the underlying mechanism for basic block labels -- encodes basic block addresses (https://lists.llvm.org/pipermail/llvm-dev/2020-July/143512.html).  Specifically, basic block offsets are computed relative to the function begin symbol. This relies on functions being contiguous which is not the case for MFS and basic block section binaries. This means Propeller cannot use binary profiles collected from these binaries, which limits the applicability of Propeller for iterative optimization.

To make the BB address map feature work with BB section binaries, we propose modifying the encoding of the BB address map as follows.

The current encoding emits the address of each function and its number of basic blocks, followed by basic block entries for each basic block.

|  Address of the function                           | //Address//      |   -> 8 bytes (pointer size)
|  Number of basic blocks in this function |//NumBlocks// |   -> ULEB128
|  BB entry #1
|  BB entry #2
|   ...
|  BB entry #//NumBlocks//

To make this work for basic block sections, we treat each basic block section similar to a function, except that basic block sections of the same function must be encapsulated in the same structure so we can map all of them to their single function.

We modify the encoding to first emit the number of basic block sections (BB ranges) in the function. Then we emit the address map of each basic block section section as before: the base address of the section, its number of blocks, and BB entries for its basic block. The first section in the BB address map is always the function entry section.

|  Number of sections for this function   | //NumBBRanges//) |     -> ULEB128

| Section //0// begin address                     |//BaseAddress[0]//  |   -> 8 bytes (pointer size)
| Number of basic blocks in section //0// |//NumBlocks[0]//    |   -> ULEB128
| BB entries for Section //0//
.
.
.
| Section //K// begin address                      |//BaseAddress[K]// |   -> 8 bytes (pointer size)
| Number of basic blocks in section //K//  |//NumBlocks[K]//   |   -> ULEB128
| BB entries for Section //K//

The encoding of basic block entries remains as before with the minor change that each basic block offset is now computed relative to the begin symbol of its containing BB section.

This patch adds a new boolean codegen option `-basic-block-address-map`. Correspondingly, the front-end flag `-fbasic-block-address-map` and LLD flag `--lto-basic-block-address-map` are introduced. Analogously, we add a new TargetOption field `BBAddrMap`. This means BB address maps are either generated for all functions in the compiling unit, or for none (depending on `TargetOptions::BBAddrMap`).

This patch disables the old `-fbasic-block-sections=labels` value option but does not remove it. A subsequent patch will remove the obsolete option.

We refactor the `BasicBlockSections` pass by separating the BB address map and BB sections handing to their own functions (named `handleBBAddrMap` and `handleBBSections`).  `handleBBSections` renumbers basic blocks and places them in their assigned sections. `handleBBAddrMap` is invoked after `handleBBSections` (if requested) and only renumbers the blocks.

- New tests added: # A codgen test `basic-block-labels-with-sections.ll` to exercise the combination of `-basic-block-address-map` with `-basic-block-sections=list`. # A driver sanity test for the `-fbasic-block-address-map` option. # An LLD test for testing the `--lto-basic-block-address-map` option. This reuses the LLVM IR from `lld/test/ELF/lto/basic-block-sections.ll`.
- Renamed and modified the two existing codegen tests for basic block address map (`basic-block-sections-labels-functions-sections.ll` and `basic-block-sections-labels.ll`)

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

>From 3f82059172f7e9020ff14e41063208c6d67b7cce Mon Sep 17 00:00:00 2001
From: Rahman Lavaee <rahmanl at google.com>
Date: Fri, 10 Nov 2023 20:16:31 +0000
Subject: [PATCH] [SHT_LLVM_BB_ADDR_MAP] Allow basic-block-sections and labels
 be used together by decoupling the handling of the two features.

Today `-split-machine-functions` (MFS) and `-fbasic-block-sections={all,list}` cannot be combined with `-basic-block-sections=labels` (the labels option will be ignored).
The inconsistency comes from the way basic block address map -- the underlying mechanism for basic block labels -- encodes basic block addresses (https://lists.llvm.org/pipermail/llvm-dev/2020-July/143512.html).  Specifically, basic block offsets are computed relative to the function begin symbol. This relies on functions being contiguous which is not the case for MFS and basic block section binaries. This means Propeller cannot use binary profiles collected from these binaries, which limits the applicability of Propeller for iterative optimization.

To make the BB address map feature work with BB section binaries, we propose modifying the encoding of the BB address map as follows.

The current encoding emits the address of each function and its number of basic blocks, followed by basic block entries for each basic block.

|  Address of the function                           | //Address//      |   -> 8 bytes (pointer size)
|  Number of basic blocks in this function |//NumBlocks// |   -> ULEB128
|  BB entry #1
|  BB entry #2
|   ...
|  BB entry #//NumBlocks//

To make this work for basic block sections, we treat each basic block section similar to a function, except that basic block sections of the same function must be encapsulated in the same structure so we can map all of them to their single function.

We modify the encoding to first emit the number of basic block sections (BB ranges) in the function. Then we emit the address map of each basic block section section as before: the base address of the section, its number of blocks, and BB entries for its basic block. The first section in the BB address map is always the function entry section.

|  Number of sections for this function   | //NumBBRanges//) |     -> ULEB128

| Section //0// begin address                     |//BaseAddress[0]//  |   -> 8 bytes (pointer size)
| Number of basic blocks in section //0// |//NumBlocks[0]//    |   -> ULEB128
| BB entries for Section //0//
.
.
.
| Section //K// begin address                      |//BaseAddress[K]// |   -> 8 bytes (pointer size)
| Number of basic blocks in section //K//  |//NumBlocks[K]//   |   -> ULEB128
| BB entries for Section //K//

The encoding of basic block entries remains as before with the minor change that each basic block offset is now computed relative to the begin symbol of its containing BB section.

This patch adds a new boolean codegen option `-basic-block-address-map`. Correspondingly, the front-end flag `-fbasic-block-address-map` and LLD flag `--lto-basic-block-address-map` are introduced.
Analogously, we add a new TargetOption field `BBAddrMap`. This means BB address maps are either generated for all functions in the compiling unit, or for none (depending on `TargetOptions::BBAddrMap`).

This patch disables the old `-fbasic-block-sections=labels` value option but does not remove it. A subsequent patch will remove the obsolete option.

We refactor the `BasicBlockSections` pass by separating the BB address map and BB sections handing to their own functions (named `handleBBAddrMap` and `handleBBSections`).  `handleBBSections` renumbers basic blocks and places them in their assigned sections. `handleBBAddrMap` is invoked after `handleBBSections` (if requested) and only renumbers the blocks.

- New tests added:
   # A codgen test `basic-block-labels-with-sections.ll` to exercise the combination of `-basic-block-address-map` with `-basic-block-sections=list`.
   # A driver sanity test for the `-fbasic-block-address-map` option.
   # An LLD test for testing the `--lto-basic-block-address-map` option. This reuses the LLVM IR from `lld/test/ELF/lto/basic-block-sections.ll`.
- Renamed and modified the two existing codegen tests for basic block address map (`basic-block-sections-labels-functions-sections.ll` and `basic-block-sections-labels.ll`)

Differential Revision: https://reviews.llvm.org/D97526
---
 clang/include/clang/Basic/CodeGenOptions.def  |   1 +
 clang/include/clang/Driver/Options.td         |   4 +
 clang/lib/CodeGen/BackendUtil.cpp             |   1 +
 clang/lib/Driver/ToolChains/Clang.cpp         |  11 +
 clang/test/Driver/basic-block-address-map.c   |   8 +
 lld/ELF/Config.h                              |   3 +
 lld/ELF/Driver.cpp                            |   3 +
 lld/ELF/LTO.cpp                               |   2 +
 lld/ELF/Options.td                            |   3 +
 lld/test/ELF/lto/basic-block-address-map.ll   |  28 ++
 llvm/include/llvm/CodeGen/CommandFlags.h      |   2 +
 llvm/include/llvm/Object/ELFTypes.h           |  36 ++-
 llvm/include/llvm/ObjectYAML/ELFYAML.h        |  21 +-
 llvm/include/llvm/Target/TargetOptions.h      |   6 +-
 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp    |  63 +++-
 llvm/lib/CodeGen/BasicBlockSections.cpp       |  37 ++-
 llvm/lib/CodeGen/CommandFlags.cpp             |   7 +
 llvm/lib/CodeGen/MachineFunction.cpp          |   1 +
 llvm/lib/CodeGen/TargetPassConfig.cpp         |  28 +-
 llvm/lib/Object/ELF.cpp                       | 105 ++++---
 llvm/lib/ObjectYAML/ELFEmitter.cpp            |  44 ++-
 llvm/lib/ObjectYAML/ELFYAML.cpp               |   8 +-
 ...ic-block-address-map-function-sections.ll} |   1 +
 ...k-address-map-with-basic-block-sections.ll |  71 +++++
 .../X86/basic-block-address-map-with-mfs.ll   |  73 +++++
 ...s-labels.ll => basic-block-address-map.ll} |   2 +
 ...ddrmap-disassemble-symbolize-operands.yaml | 120 ++++----
 .../elf-bbaddrmap-symbolize-relocatable.yaml  |  22 +-
 .../ELF/bb-addr-map-relocatable.test          | 107 ++++---
 .../tools/llvm-readobj/ELF/bb-addr-map.test   | 277 ++++++++++--------
 llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml | 205 +++++++------
 llvm/test/tools/yaml2obj/ELF/bb-addr-map.yaml |  39 +--
 llvm/tools/llvm-objdump/llvm-objdump.cpp      |  44 +--
 llvm/tools/llvm-readobj/ELFDumper.cpp         |  39 ++-
 llvm/tools/obj2yaml/elf2yaml.cpp              |  43 ++-
 llvm/unittests/Object/ELFObjectFileTest.cpp   | 130 ++++----
 36 files changed, 1050 insertions(+), 545 deletions(-)
 create mode 100644 clang/test/Driver/basic-block-address-map.c
 create mode 100644 lld/test/ELF/lto/basic-block-address-map.ll
 rename llvm/test/CodeGen/X86/{basic-block-sections-labels-functions-sections.ll => basic-block-address-map-function-sections.ll} (94%)
 create mode 100644 llvm/test/CodeGen/X86/basic-block-address-map-with-basic-block-sections.ll
 create mode 100644 llvm/test/CodeGen/X86/basic-block-address-map-with-mfs.ll
 rename llvm/test/CodeGen/X86/{basic-block-sections-labels.ll => basic-block-address-map.ll} (90%)

diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index 675645cd534ed76..132dcbd3432c3e4 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -96,6 +96,7 @@ ENUM_CODEGENOPT(InlineAsmDialect, InlineAsmDialectKind, 1, IAD_ATT)
 CODEGENOPT(ForbidGuardVariables , 1, 0) ///< Issue errors if C++ guard variables
                                         ///< are required.
 CODEGENOPT(FunctionSections  , 1, 0) ///< Set when -ffunction-sections is enabled.
+CODEGENOPT(BBAddrMap  , 1, 0) ///< Set when -fbasic-block-address-map is enabled.
 CODEGENOPT(InstrumentFunctions , 1, 0) ///< Set when -finstrument-functions is
                                        ///< enabled.
 CODEGENOPT(InstrumentFunctionsAfterInlining , 1, 0) ///< Set when
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 7dd2755350f7a56..97c558ae8a93cf1 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -3921,6 +3921,10 @@ defm function_sections : BoolFOption<"function-sections",
   PosFlag<SetTrue, [], [ClangOption, CC1Option],
           "Place each function in its own section">,
   NegFlag<SetFalse>>;
+defm basic_block_address_map : BoolFOption<"basic-block-address-map",
+  CodeGenOpts<"BBAddrMap">, DefaultFalse,
+  PosFlag<SetTrue, [], [CC1Option], "Emit the basic block address map section.">,
+  NegFlag<SetFalse>>;
 def fbasic_block_sections_EQ : Joined<["-"], "fbasic-block-sections=">, Group<f_Group>,
   Visibility<[ClangOption, CC1Option, CC1AsOption]>,
   HelpText<"Place each function's basic blocks in unique sections (ELF Only)">,
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index a7a47d17723cb73..91693cc18ff9b26 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -369,6 +369,7 @@ static bool initTargetOptions(DiagnosticsEngine &Diags,
                               LangOptions::FPModeKind::FPM_FastHonorPragmas);
   Options.ApproxFuncFPMath = LangOpts.ApproxFunc;
 
+  Options.BBAddrMap = CodeGenOpts.BBAddrMap;
   Options.BBSections =
       llvm::StringSwitch<llvm::BasicBlockSection>(CodeGenOpts.BBSections)
           .Case("all", llvm::BasicBlockSection::All)
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 2d73f42772a29dc..fdd8f0c33ba1401 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5927,6 +5927,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
     CmdArgs.push_back("-ffunction-sections");
   }
 
+  if (Arg *A = Args.getLastArg(options::OPT_fbasic_block_address_map,
+                               options::OPT_fno_basic_block_address_map)) {
+    if (Triple.isX86() && Triple.isOSBinFormatELF()) {
+      if (A->getOption().matches(options::OPT_fbasic_block_address_map))
+        A->render(Args, CmdArgs);
+    } else {
+      D.Diag(diag::err_drv_unsupported_opt_for_target)
+          << A->getAsString(Args) << TripleStr;
+    }
+  }
+
   if (Arg *A = Args.getLastArg(options::OPT_fbasic_block_sections_EQ)) {
     StringRef Val = A->getValue();
     if (Triple.isX86() && Triple.isOSBinFormatELF()) {
diff --git a/clang/test/Driver/basic-block-address-map.c b/clang/test/Driver/basic-block-address-map.c
new file mode 100644
index 000000000000000..022f972b412d6b5
--- /dev/null
+++ b/clang/test/Driver/basic-block-address-map.c
@@ -0,0 +1,8 @@
+// RUN: %clang -### -target x86_64 -fbasic-block-address-map %s -S 2>&1 | FileCheck -check-prefix=CHECK-PRESENT %s
+// CHECK-PRESENT: -fbasic-block-address-map
+
+// RUN: %clang -### -target x86_64 -fno-basic-block-address-map %s -S 2>&1 | FileCheck %s --check-prefix=CHECK-ABSENT
+// CHECK-ABSENT-NOT: -fbasic-block-address-map
+
+// RUN: not %clang -c -target x86_64-apple-darwin10 -fbasic-block-address-map %s -S 2>&1 | FileCheck -check-prefix=CHECK-TRIPLE %s
+// CHECK-TRIPLE: error: unsupported option '-fbasic-block-address-map' for target
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 56229334f9a44ae..ffdb6ca9584cd07 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -187,6 +187,7 @@ struct Config {
   llvm::StringRef cmseOutputLib;
   StringRef zBtiReport = "none";
   StringRef zCetReport = "none";
+  bool ltoBBAddrMap;
   llvm::StringRef ltoBasicBlockSections;
   std::pair<llvm::StringRef, llvm::StringRef> thinLTOObjectSuffixReplace;
   llvm::StringRef thinLTOPrefixReplaceOld;
@@ -249,6 +250,8 @@ struct Config {
   bool ltoPGOWarnMismatch;
   bool ltoDebugPassManager;
   bool ltoEmitAsm;
+  bool ltoNewPassManager;
+  bool ltoPseudoProbeForProfiling;
   bool ltoUniqueBasicBlockSectionNames;
   bool ltoValidateAllVtablesHaveTypeInfos;
   bool ltoWholeProgramVisibility;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 6290880c43d3b95..3d21ef15ea18b21 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -1319,6 +1319,9 @@ static void readConfigs(opt::InputArgList &args) {
   config->ltoObjPath = args.getLastArgValue(OPT_lto_obj_path_eq);
   config->ltoPartitions = args::getInteger(args, OPT_lto_partitions, 1);
   config->ltoSampleProfile = args.getLastArgValue(OPT_lto_sample_profile);
+  config->ltoBBAddrMap =
+      args.hasFlag(OPT_lto_basic_block_address_map,
+                   OPT_no_lto_basic_block_address_map, false);
   config->ltoBasicBlockSections =
       args.getLastArgValue(OPT_lto_basic_block_sections);
   config->ltoUniqueBasicBlockSectionNames =
diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp
index 504c12aac6c5696..9fb0b18cd0ea676 100644
--- a/lld/ELF/LTO.cpp
+++ b/lld/ELF/LTO.cpp
@@ -59,6 +59,8 @@ static lto::Config createConfig() {
   c.Options.FunctionSections = true;
   c.Options.DataSections = true;
 
+  c.Options.BBAddrMap = config->ltoBBAddrMap;
+
   // Check if basic block sections must be used.
   // Allowed values for --lto-basic-block-sections are "all", "labels",
   // "<file name specifying basic block ids>", or none.  This is the equivalent
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index c2c9cabc92a4da4..c10a73e2d9c36f9 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -637,6 +637,9 @@ def save_temps_eq: JJ<"save-temps=">, HelpText<"Save select intermediate LTO com
   Values<"resolution,preopt,promote,internalize,import,opt,precodegen,prelink,combinedindex">;
 def lto_basic_block_sections: JJ<"lto-basic-block-sections=">,
   HelpText<"Enable basic block sections for LTO">;
+defm lto_basic_block_address_map: BB<"lto-basic-block-address-map",
+  "Emit basic block address map for LTO",
+  "Do not emit basic block address map for LTO (default)">;
 defm lto_unique_basic_block_section_names: BB<"lto-unique-basic-block-section-names",
     "Give unique names to every basic block section for LTO",
     "Do not give unique names to every basic block section for LTO (default)">;
diff --git a/lld/test/ELF/lto/basic-block-address-map.ll b/lld/test/ELF/lto/basic-block-address-map.ll
new file mode 100644
index 000000000000000..9bcd3ee62e046fb
--- /dev/null
+++ b/lld/test/ELF/lto/basic-block-address-map.ll
@@ -0,0 +1,28 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld %t.o -o %t --lto-basic-block-address-map --lto-O0 --save-temps
+; RUN: llvm-readobj -s %t.lto.o | FileCheck --check-prefix=SECNAMES %s
+
+; SECNAMES: Type: SHT_LLVM_BB_ADDR_MAP
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nounwind uwtable
+define dso_local void @foo(i32 %b) local_unnamed_addr {
+entry:
+  %tobool.not = icmp eq i32 %b, 0
+  br i1 %tobool.not, label %if.end, label %if.then
+
+if.then:                                          ; preds = %entry
+  tail call void @foo(i32 0)
+  br label %if.end
+
+if.end:                                           ; preds = %entry, %if.then
+  ret void
+}
+
+define void @_start() {
+  call void @foo(i32 1)
+  ret void
+}
diff --git a/llvm/include/llvm/CodeGen/CommandFlags.h b/llvm/include/llvm/CodeGen/CommandFlags.h
index 6407dde5bcd6c78..73c9c7ce9a5e1f3 100644
--- a/llvm/include/llvm/CodeGen/CommandFlags.h
+++ b/llvm/include/llvm/CodeGen/CommandFlags.h
@@ -156,6 +156,8 @@ struct RegisterCodeGenFlags {
   RegisterCodeGenFlags();
 };
 
+bool getEnableBBAddrMap();
+
 llvm::BasicBlockSection getBBSectionsMode(llvm::TargetOptions &Options);
 
 /// Common utility function tightly tied to the options listed here. Initializes
diff --git a/llvm/include/llvm/Object/ELFTypes.h b/llvm/include/llvm/Object/ELFTypes.h
index 4670abc867de63c..dda58f17b65cc2a 100644
--- a/llvm/include/llvm/Object/ELFTypes.h
+++ b/llvm/include/llvm/Object/ELFTypes.h
@@ -837,7 +837,7 @@ struct BBAddrMap {
     };
 
     uint32_t ID;     // Unique ID of this basic block.
-    uint32_t Offset; // Offset of basic block relative to function start.
+    uint32_t Offset; // Offset of basic block relative to the base address.
     uint32_t Size;   // Size of the basic block.
     Metadata MD;     // Metdata for this basic block.
 
@@ -856,23 +856,35 @@ struct BBAddrMap {
     bool hasIndirectBranch() const { return MD.HasIndirectBranch; }
   };
 
-  BBAddrMap(uint64_t Addr, std::vector<BBEntry> BBEntries)
-      : Addr(Addr), BBEntries(std::move(BBEntries)) {}
+  // Struct representing the BBAddrMap information for a contiguous range of
+  // basic blocks (a function or a basic block section).
+  struct BBRangeEntry {
+    uint64_t BaseAddress;           // Base address of the range.
+    std::vector<BBEntry> BBEntries; // Basic block entries for this range.
+
+    // Equality operator for unit testing.
+    bool operator==(const BBRangeEntry &Other) const {
+      return BaseAddress == Other.BaseAddress &&
+             std::equal(BBEntries.begin(), BBEntries.end(),
+                        Other.BBEntries.begin());
+    }
+  };
 
-  // Returns the address of the corresponding function.
-  uint64_t getFunctionAddress() const { return Addr; }
+  // All ranges for this function. The first range always corresponds to the
+  // function entry.
+  std::vector<BBRangeEntry> BBRanges;
 
-  // Returns the basic block entries for this function.
-  const std::vector<BBEntry> &getBBEntries() const { return BBEntries; }
+  // Returns the function address associated with this BBAddrMap, which is
+  // stored as the `BaseAddress` of its first BBRangeEntry. Returns 0 if BBRanges is empty.
+  uint64_t getFunctionAddress() const {
+    if (BBRanges.empty()) return 0;
+    return BBRanges.front().BaseAddress;
+  }
 
   // Equality operator for unit testing.
   bool operator==(const BBAddrMap &Other) const {
-    return Addr == Other.Addr && std::equal(BBEntries.begin(), BBEntries.end(),
-                                            Other.BBEntries.begin());
+    return std::equal(BBRanges.begin(), BBRanges.end(), Other.BBRanges.begin());
   }
-
-  uint64_t Addr;                  // Function address
-  std::vector<BBEntry> BBEntries; // Basic block entries for this function.
 };
 
 } // end namespace object.
diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h
index 1ba41232f552e3a..4876e925bf5c960 100644
--- a/llvm/include/llvm/ObjectYAML/ELFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h
@@ -165,9 +165,15 @@ struct BBAddrMapEntry {
   };
   uint8_t Version;
   llvm::yaml::Hex8 Feature;
-  llvm::yaml::Hex64 Address;
-  std::optional<uint64_t> NumBlocks;
-  std::optional<std::vector<BBEntry>> BBEntries;
+
+  struct BBRangeEntry {
+    llvm::yaml::Hex64 BaseAddress;
+    std::optional<uint64_t> NumBlocks;
+    std::optional<std::vector<BBEntry>> BBEntries;
+  };
+
+  std::optional<uint64_t> NumBBRanges;
+  std::optional<std::vector<BBRangeEntry>> BBRanges;
 };
 
 struct StackSizeEntry {
@@ -737,6 +743,7 @@ bool shouldAllocateFileSpace(ArrayRef<ProgramHeader> Phdrs,
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::StackSizeEntry)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::BBAddrMapEntry)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::BBAddrMapEntry::BBEntry)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::BBAddrMapEntry::BBRangeEntry)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::DynamicEntry)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::LinkerOption)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::CallGraphEntryWeight)
@@ -898,11 +905,15 @@ template <> struct MappingTraits<ELFYAML::StackSizeEntry> {
 };
 
 template <> struct MappingTraits<ELFYAML::BBAddrMapEntry> {
-  static void mapping(IO &IO, ELFYAML::BBAddrMapEntry &Rel);
+  static void mapping(IO &IO, ELFYAML::BBAddrMapEntry &E);
+};
+
+template <> struct MappingTraits<ELFYAML::BBAddrMapEntry::BBRangeEntry> {
+  static void mapping(IO &IO, ELFYAML::BBAddrMapEntry::BBRangeEntry &E);
 };
 
 template <> struct MappingTraits<ELFYAML::BBAddrMapEntry::BBEntry> {
-  static void mapping(IO &IO, ELFYAML::BBAddrMapEntry::BBEntry &Rel);
+  static void mapping(IO &IO, ELFYAML::BBAddrMapEntry::BBEntry &E);
 };
 
 template <> struct MappingTraits<ELFYAML::GnuHashHeader> {
diff --git a/llvm/include/llvm/Target/TargetOptions.h b/llvm/include/llvm/Target/TargetOptions.h
index 4df897c047a38ac..4a39c539e70a944 100644
--- a/llvm/include/llvm/Target/TargetOptions.h
+++ b/llvm/include/llvm/Target/TargetOptions.h
@@ -147,7 +147,7 @@ namespace llvm {
           TrapUnreachable(false), NoTrapAfterNoreturn(false), TLSSize(0),
           EmulatedTLS(false), EnableIPRA(false), EmitStackSizeSection(false),
           EnableMachineOutliner(false), EnableMachineFunctionSplitter(false),
-          SupportsDefaultOutlining(false), EmitAddrsig(false),
+          SupportsDefaultOutlining(false), EmitAddrsig(false), BBAddrMap(false),
           EmitCallSiteInfo(false), SupportsDebugEntryValues(false),
           EnableDebugEntryValues(false), ValueTrackingVariableLocations(false),
           ForceDwarfFrameSection(false), XRayFunctionIndex(true),
@@ -313,6 +313,10 @@ namespace llvm {
     /// Emit address-significance table.
     unsigned EmitAddrsig : 1;
 
+    // Emit the SHT_LLVM_BB_ADDR_MAP section containing basic block address
+    // which can be used to map virtual addresses to machine basic blocks.
+    unsigned BBAddrMap : 1;
+
     /// Emit basic blocks into separate sections.
     BasicBlockSection BBSections = BasicBlockSection::None;
 
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 15ff39883680369..5229dc393520b1c 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -1366,16 +1366,48 @@ void AsmPrinter::emitBBAddrMapSection(const MachineFunction &MF) {
   uint8_t BBAddrMapVersion = OutStreamer->getContext().getBBAddrMapVersion();
   OutStreamer->emitInt8(BBAddrMapVersion);
   OutStreamer->AddComment("feature");
-  OutStreamer->emitInt8(0);
-  OutStreamer->AddComment("function address");
-  OutStreamer->emitSymbolValue(FunctionSymbol, getPointerSize());
-  OutStreamer->AddComment("number of basic blocks");
-  OutStreamer->emitULEB128IntValue(MF.size());
-  const MCSymbol *PrevMBBEndSymbol = FunctionSymbol;
-  // Emit BB Information for each basic block in the function.
+  bool HasBBSections = MF.hasBBSections() && (MBBSectionRanges.size() > 1);
+  uint8_t BBAddrMapFeature = HasBBSections << 7;
+  OutStreamer->emitInt8(BBAddrMapFeature);
+  if (HasBBSections) {
+    OutStreamer->AddComment("number of basic block ranges");
+    OutStreamer->emitULEB128IntValue(MBBSectionRanges.size());
+  }
+  // Number of blocks in each MBB section.
+  MapVector<unsigned, unsigned> MBBSectionNumBlocks;
+  const MCSymbol *PrevMBBEndSymbol = nullptr;
+  if (!HasBBSections) {
+    OutStreamer->AddComment("function address");
+    OutStreamer->emitSymbolValue(FunctionSymbol, getPointerSize());
+    OutStreamer->AddComment("number of basic blocks");
+    OutStreamer->emitULEB128IntValue(MF.size());
+    PrevMBBEndSymbol = FunctionSymbol;
+  } else {
+    unsigned BBCount = 0;
+    for (const MachineBasicBlock &MBB : MF) {
+      BBCount++;
+      if (MBB.isEndSection()) {
+        // Store each section's basic block count when it ends.
+        MBBSectionNumBlocks[MBB.getSectionIDNum()] = BBCount;
+        // Reset the count for the next section.
+        BBCount = 0;
+      }
+    }
+  }
+  // Emit the BB entry for each basic block in the function.
   for (const MachineBasicBlock &MBB : MF) {
     const MCSymbol *MBBSymbol =
         MBB.isEntryBlock() ? FunctionSymbol : MBB.getSymbol();
+    bool IsBeginSection =
+        HasBBSections && (MBB.isBeginSection() || MBB.isEntryBlock());
+    if (IsBeginSection) {
+      OutStreamer->AddComment("base address");
+      OutStreamer->emitSymbolValue(MBBSymbol, getPointerSize());
+      OutStreamer->AddComment("number of basic blocks");
+      OutStreamer->emitULEB128IntValue(
+          MBBSectionNumBlocks[MBB.getSectionIDNum()]);
+      PrevMBBEndSymbol = MBBSymbol;
+    }
     // TODO: Remove this check when version 1 is deprecated.
     if (BBAddrMapVersion > 1) {
       OutStreamer->AddComment("BB id");
@@ -1769,7 +1801,7 @@ void AsmPrinter::emitFunctionBody() {
     // We must emit temporary symbol for the end of this basic block, if either
     // we have BBLabels enabled or if this basic blocks marks the end of a
     // section.
-    if (MF->hasBBLabels() ||
+    if (MF->hasBBLabels() || MF->getTarget().Options.BBAddrMap ||
         (MAI->hasDotTypeDotSizeDirective() && MBB.isEndSection()))
       OutStreamer->emitLabel(MBB.getEndSymbol());
 
@@ -1921,7 +1953,8 @@ void AsmPrinter::emitFunctionBody() {
 
   // Emit section containing BB address offsets and their metadata, when
   // BB labels are requested for this function. Skip empty functions.
-  if (MF->hasBBLabels() && HasAnyRealCode)
+  if ((MF->hasBBLabels() || MF->getTarget().Options.BBAddrMap) &&
+      HasAnyRealCode)
     emitBBAddrMapSection(*MF);
 
   // Emit sections containing instruction and function PCs.
@@ -1944,7 +1977,7 @@ void AsmPrinter::emitFunctionBody() {
   // MBB profile information has been set
   if (MBBProfileDumpFileOutput && !MF->empty() &&
       MF->getFunction().getEntryCount()) {
-    if (!MF->hasBBLabels()) {
+    if (!MF->hasBBLabels() && !MF->getTarget().Options.BBAddrMap) {
       MF->getContext().reportError(
           SMLoc(),
           "Unable to find BB labels for MBB profile dump. -mbb-profile-dump "
@@ -2484,9 +2517,9 @@ void AsmPrinter::SetupMachineFunction(MachineFunction &MF) {
   bool NeedsLocalForSize = MAI->needsLocalForSize();
   if (F.hasFnAttribute("patchable-function-entry") ||
       F.hasFnAttribute("function-instrument") ||
-      F.hasFnAttribute("xray-instruction-threshold") ||
-      needFuncLabels(MF) || NeedsLocalForSize ||
-      MF.getTarget().Options.EmitStackSizeSection || MF.hasBBLabels()) {
+      F.hasFnAttribute("xray-instruction-threshold") || needFuncLabels(MF) ||
+      NeedsLocalForSize || MF.getTarget().Options.EmitStackSizeSection ||
+      MF.getTarget().Options.BBAddrMap || MF.hasBBLabels()) {
     CurrentFnBegin = createTempSymbol("func_begin");
     if (NeedsLocalForSize)
       CurrentFnSymForSize = CurrentFnBegin;
@@ -3920,7 +3953,9 @@ bool AsmPrinter::shouldEmitLabelForBasicBlock(
   // With `-fbasic-block-sections=`, a label is needed for every non-entry block
   // in the labels mode (option `=labels`) and every section beginning in the
   // sections mode (`=all` and `=list=`).
-  if ((MF->hasBBLabels() || MBB.isBeginSection()) && !MBB.isEntryBlock())
+  if ((MF->hasBBLabels() || MF->getTarget().Options.BBAddrMap ||
+       MBB.isBeginSection()) &&
+      !MBB.isEntryBlock())
     return true;
   // A label is needed for any block with at least one predecessor (when that
   // predecessor is not the fallthrough predecessor, or if it is an EH funclet
diff --git a/llvm/lib/CodeGen/BasicBlockSections.cpp b/llvm/lib/CodeGen/BasicBlockSections.cpp
index 42997d2287d61d7..cec05dbeb21de63 100644
--- a/llvm/lib/CodeGen/BasicBlockSections.cpp
+++ b/llvm/lib/CodeGen/BasicBlockSections.cpp
@@ -57,10 +57,10 @@
 //    function into potentially several disjoint pieces, and CFI needs to be
 //    emitted per cluster. This also bloats the object file and binary sizes.
 //
-// Basic Block Labels
+// Basic Block Address Map
 // ==================
 //
-// With -fbasic-block-sections=labels, we encode the offsets of BB addresses of
+// With -fbasic-block-address-map, we emit 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
@@ -118,6 +118,10 @@ class BasicBlockSections : public MachineFunctionPass {
   /// Identify basic blocks that need separate sections and prepare to emit them
   /// accordingly.
   bool runOnMachineFunction(MachineFunction &MF) override;
+
+private:
+  bool handleBBSections(MachineFunction &MF);
+  bool handleBBAddrMap(MachineFunction &MF);
 };
 
 } // end anonymous namespace
@@ -280,10 +284,12 @@ bool llvm::hasInstrProfHashMismatch(MachineFunction &MF) {
   return false;
 }
 
-bool BasicBlockSections::runOnMachineFunction(MachineFunction &MF) {
+// Identify, arrange, and modify basic blocks which need separate sections
+// according to the specification provided by the -fbasic-block-sections flag.
+bool BasicBlockSections::handleBBSections(MachineFunction &MF) {
   auto BBSectionsType = MF.getTarget().getBBSectionsType();
-  assert(BBSectionsType != BasicBlockSection::None &&
-         "BB Sections not enabled!");
+  if (BBSectionsType == BasicBlockSection::None)
+    return false;
 
   // Check for source drift. If the source has changed since the profiles
   // were obtained, optimizing basic blocks might be sub-optimal.
@@ -300,7 +306,7 @@ bool BasicBlockSections::runOnMachineFunction(MachineFunction &MF) {
 
   if (BBSectionsType == BasicBlockSection::Labels) {
     MF.setBBSectionsType(BBSectionsType);
-    return false;
+    return true;
   }
 
   DenseMap<UniqueBBID, BBClusterInfo> FuncClusterInfo;
@@ -360,6 +366,25 @@ bool BasicBlockSections::runOnMachineFunction(MachineFunction &MF) {
   return true;
 }
 
+// When the BB address map needs to be generated, this renumbers basic blocks to
+// make them appear in increasing order of their IDs in the function. This
+// avoids the need to store basic block IDs in the BB address map section, since
+// they can be determined implicitly.
+bool BasicBlockSections::handleBBAddrMap(MachineFunction &MF) {
+  if (!MF.getTarget().Options.BBAddrMap)
+    return false;
+  MF.RenumberBlocks();
+  return true;
+}
+
+bool BasicBlockSections::runOnMachineFunction(MachineFunction &MF) {
+  // First handle the basic block sections.
+  auto R1 = handleBBSections(MF);
+  // Handle basic block address map after basic block sections are finalized.
+  auto R2 = handleBBAddrMap(MF);
+  return R1 || R2;
+}
+
 void BasicBlockSections::getAnalysisUsage(AnalysisUsage &AU) const {
   AU.setPreservesAll();
   AU.addRequired<BasicBlockSectionsProfileReader>();
diff --git a/llvm/lib/CodeGen/CommandFlags.cpp b/llvm/lib/CodeGen/CommandFlags.cpp
index c6d7827f36dfd63..37fb945fbe84381 100644
--- a/llvm/lib/CodeGen/CommandFlags.cpp
+++ b/llvm/lib/CodeGen/CommandFlags.cpp
@@ -90,6 +90,7 @@ CGOPT_EXP(bool, DataSections)
 CGOPT_EXP(bool, FunctionSections)
 CGOPT(bool, IgnoreXCOFFVisibility)
 CGOPT(bool, XCOFFTracebackTable)
+CGOPT(bool, EnableBBAddrMap)
 CGOPT(std::string, BBSections)
 CGOPT(unsigned, TLSSize)
 CGOPT_EXP(bool, EmulatedTLS)
@@ -389,6 +390,11 @@ codegen::RegisterCodeGenFlags::RegisterCodeGenFlags() {
       cl::init(true));
   CGBINDOPT(XCOFFTracebackTable);
 
+  static cl::opt<bool> EnableBBAddrMap(
+      "basic-block-address-map",
+      cl::desc("Emit the basic block address map section"), cl::init(false));
+  CGBINDOPT(EnableBBAddrMap);
+
   static cl::opt<std::string> BBSections(
       "basic-block-sections",
       cl::desc("Emit basic blocks into separate sections"),
@@ -562,6 +568,7 @@ codegen::InitTargetOptionsFromCodeGenFlags(const Triple &TheTriple) {
   Options.FunctionSections = getFunctionSections();
   Options.IgnoreXCOFFVisibility = getIgnoreXCOFFVisibility();
   Options.XCOFFTracebackTable = getXCOFFTracebackTable();
+  Options.BBAddrMap = getEnableBBAddrMap();
   Options.BBSections = getBBSectionsMode(Options);
   Options.UniqueSectionNames = getUniqueSectionNames();
   Options.UniqueBasicBlockSectionNames = getUniqueBasicBlockSectionNames();
diff --git a/llvm/lib/CodeGen/MachineFunction.cpp b/llvm/lib/CodeGen/MachineFunction.cpp
index 07eb0ba7f45c2e3..7beba4cf5213489 100644
--- a/llvm/lib/CodeGen/MachineFunction.cpp
+++ b/llvm/lib/CodeGen/MachineFunction.cpp
@@ -466,6 +466,7 @@ MachineFunction::CreateMachineBasicBlock(const BasicBlock *BB,
   // `-basic-block-sections=list` to allow robust mapping of profiles to basic
   // blocks.
   if (Target.getBBSectionsType() == BasicBlockSection::Labels ||
+      Target.Options.BBAddrMap ||
       Target.getBBSectionsType() == BasicBlockSection::List)
     MBB->setBBID(BBID.has_value() ? *BBID : UniqueBBID{NextBBID++, 0});
   return MBB;
diff --git a/llvm/lib/CodeGen/TargetPassConfig.cpp b/llvm/lib/CodeGen/TargetPassConfig.cpp
index 1f7c949cd6031b1..405b658b774755f 100644
--- a/llvm/lib/CodeGen/TargetPassConfig.cpp
+++ b/llvm/lib/CodeGen/TargetPassConfig.cpp
@@ -1259,19 +1259,13 @@ void TargetPassConfig::addMachinePasses() {
     addPass(createMIRAddFSDiscriminatorsPass(
         sampleprof::FSDiscriminatorPass::PassLast));
 
+  bool NeedsBBSections =
+      TM->getBBSectionsType() != llvm::BasicBlockSection::None;
   // Machine function splitter uses the basic block sections feature. Both
-  // cannot be enabled at the same time. Basic block sections takes precedence.
-  // FIXME: In principle, BasicBlockSection::Labels and splitting can used
-  // together. Update this check once we have addressed any issues.
-  if (TM->getBBSectionsType() != llvm::BasicBlockSection::None) {
-    if (TM->getBBSectionsType() == llvm::BasicBlockSection::List) {
-      addPass(llvm::createBasicBlockSectionsProfileReaderPass(
-          TM->getBBSectionsFuncListBuf()));
-      addPass(llvm::createBasicBlockPathCloningPass());
-    }
-    addPass(llvm::createBasicBlockSectionsPass());
-  } else if (TM->Options.EnableMachineFunctionSplitter ||
-             EnableMachineFunctionSplitter) {
+  // cannot be enabled at the same time. We do not apply machine function
+  // splitter if -basic-block-sections is requested.
+  if (!NeedsBBSections && (TM->Options.EnableMachineFunctionSplitter ||
+                           EnableMachineFunctionSplitter)) {
     const std::string ProfileFile = getFSProfileFile(TM);
     if (!ProfileFile.empty()) {
       if (EnableFSDiscriminator) {
@@ -1288,6 +1282,16 @@ void TargetPassConfig::addMachinePasses() {
     }
     addPass(createMachineFunctionSplitterPass());
   }
+  // We run the BasicBlockSections pass if either we need BB sections or BB
+  // address map (or both).
+  if (NeedsBBSections || TM->Options.BBAddrMap) {
+    if (TM->getBBSectionsType() == llvm::BasicBlockSection::List) {
+      addPass(llvm::createBasicBlockSectionsProfileReaderPass(
+          TM->getBBSectionsFuncListBuf()));
+      addPass(llvm::createBasicBlockPathCloningPass());
+    }
+    addPass(llvm::createBasicBlockSectionsPass());
+  }
 
   addPostBBSections();
 
diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp
index 1d73a6ffa73f5f9..7d69f19cece56e7 100644
--- a/llvm/lib/Object/ELF.cpp
+++ b/llvm/lib/Object/ELF.cpp
@@ -667,6 +667,17 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec,
     for (Elf_Rela Rela : *Relas)
       FunctionOffsetTranslations[Rela.r_offset] = Rela.r_addend;
   }
+  auto GetAddressForRelocation =
+      [&](unsigned RelocationOffsetInSection) -> Expected<unsigned> {
+    auto FOTIterator =
+        FunctionOffsetTranslations.find(RelocationOffsetInSection);
+    if (FOTIterator == FunctionOffsetTranslations.end()) {
+      return createError("failed to get relocation data for offset: " +
+                         Twine::utohexstr(RelocationOffsetInSection) +
+                         " in section " + describe(*this, Sec));
+    }
+    return FOTIterator->second;
+  };
   Expected<ArrayRef<uint8_t>> ContentsOrErr = getSectionContents(Sec);
   if (!ContentsOrErr)
     return ContentsOrErr.takeError();
@@ -697,6 +708,7 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec,
   };
 
   uint8_t Version = 0;
+  uint8_t Feature = 0;
   while (!ULEBSizeErr && !MetadataDecodeErr && Cur &&
          Cur.tell() < Content.size()) {
     if (Sec.sh_type == ELF::SHT_LLVM_BB_ADDR_MAP) {
@@ -706,46 +718,69 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec,
       if (Version > 2)
         return createError("unsupported SHT_LLVM_BB_ADDR_MAP version: " +
                            Twine(static_cast<int>(Version)));
-      Data.getU8(Cur); // Feature byte
-    }
-    uint64_t SectionOffset = Cur.tell();
-    uintX_t Address = static_cast<uintX_t>(Data.getAddress(Cur));
-    if (!Cur)
-      return Cur.takeError();
-    if (IsRelocatable) {
-      assert(Address == 0);
-      auto FOTIterator = FunctionOffsetTranslations.find(SectionOffset);
-      if (FOTIterator == FunctionOffsetTranslations.end()) {
-        return createError("failed to get relocation data for offset: " +
-                           Twine::utohexstr(SectionOffset) + " in section " +
-                           describe(*this, Sec));
-      }
-      Address = FOTIterator->second;
+      Feature = Data.getU8(Cur);
     }
-    uint32_t NumBlocks = ReadULEB128AsUInt32();
+    uint32_t NumBlocks = 0;
+    uint32_t NumBBRanges = 1;
+    uintX_t RangeBaseAddress = 0;
     std::vector<BBAddrMap::BBEntry> BBEntries;
-    uint32_t PrevBBEndOffset = 0;
-    for (uint32_t BlockIndex = 0;
-         !MetadataDecodeErr && !ULEBSizeErr && Cur && (BlockIndex < NumBlocks);
-         ++BlockIndex) {
-      uint32_t ID = Version >= 2 ? ReadULEB128AsUInt32() : BlockIndex;
-      uint32_t Offset = ReadULEB128AsUInt32();
-      uint32_t Size = ReadULEB128AsUInt32();
-      uint32_t MD = ReadULEB128AsUInt32();
-      if (Version >= 1) {
-        // Offset is calculated relative to the end of the previous BB.
-        Offset += PrevBBEndOffset;
-        PrevBBEndOffset = Offset + Size;
+    bool MultiBBRangeFeature = Feature & 0x80;
+    if (MultiBBRangeFeature) {
+      NumBBRanges = ReadULEB128AsUInt32();
+    } else {
+      uint64_t RelocationOffsetInSection = Cur.tell();
+      RangeBaseAddress = static_cast<uintX_t>(Data.getAddress(Cur));
+      if (!Cur)
+        return Cur.takeError();
+      if (IsRelocatable) {
+        Expected<unsigned> AddressOrErr =
+            GetAddressForRelocation(RelocationOffsetInSection);
+        if (!AddressOrErr)
+          return AddressOrErr.takeError();
+        RangeBaseAddress = *AddressOrErr;
       }
-      Expected<BBAddrMap::BBEntry::Metadata> MetadataOrErr =
-          BBAddrMap::BBEntry::Metadata::decode(MD);
-      if (!MetadataOrErr) {
-        MetadataDecodeErr = MetadataOrErr.takeError();
-        break;
+      NumBlocks = ReadULEB128AsUInt32();
+    }
+    std::vector<BBAddrMap::BBRangeEntry> BBRangeEntries;
+    for (uint32_t BBRangeIndex = 0; BBRangeIndex < NumBBRanges;
+         ++BBRangeIndex) {
+      uint32_t PrevBBEndOffset = 0;
+      if (MultiBBRangeFeature) {
+        uint64_t RelocationOffsetInSection = Cur.tell();
+        RangeBaseAddress = static_cast<uintX_t>(Data.getAddress(Cur));
+        if (IsRelocatable) {
+          assert(RangeBaseAddress == 0);
+          Expected<unsigned> AddressOrErr =
+              GetAddressForRelocation(RelocationOffsetInSection);
+          if (!AddressOrErr)
+            return AddressOrErr.takeError();
+          RangeBaseAddress = *AddressOrErr;
+        }
+        NumBlocks = ReadULEB128AsUInt32();
+      }
+      for (uint32_t BlockIndex = 0; !MetadataDecodeErr && !ULEBSizeErr && Cur &&
+                                    (BlockIndex < NumBlocks);
+           ++BlockIndex) {
+        uint32_t ID = Version >= 2 ? ReadULEB128AsUInt32() : BlockIndex;
+        uint32_t Offset = ReadULEB128AsUInt32();
+        uint32_t Size = ReadULEB128AsUInt32();
+        uint32_t MD = ReadULEB128AsUInt32();
+        if (Version >= 1) {
+          // Offset is calculated relative to the end of the previous BB.
+          Offset += PrevBBEndOffset;
+          PrevBBEndOffset = Offset + Size;
+        }
+        Expected<BBAddrMap::BBEntry::Metadata> MetadataOrErr =
+            BBAddrMap::BBEntry::Metadata::decode(MD);
+        if (!MetadataOrErr) {
+          MetadataDecodeErr = MetadataOrErr.takeError();
+          break;
+        }
+        BBEntries.push_back({ID, Offset, Size, *MetadataOrErr});
       }
-      BBEntries.push_back({ID, Offset, Size, *MetadataOrErr});
+      BBRangeEntries.push_back({RangeBaseAddress, std::move(BBEntries)});
     }
-    FunctionEntries.emplace_back(Address, std::move(BBEntries));
+    FunctionEntries.push_back({std::move(BBRangeEntries)});
   }
   // Either Cur is in the error state, or we have an error in ULEBSizeErr or
   // MetadataDecodeErr (but not both), but we join all errors here to be safe.
diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp
index 40f81f867efa423..15690657fdb589f 100644
--- a/llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -1404,22 +1404,36 @@ void ELFState<ELFT>::writeSectionContent(
       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
-    // is overridden by the 'NumBlocks' YAML field when specified.
-    uint64_t NumBlocks =
-        E.NumBlocks.value_or(E.BBEntries ? E.BBEntries->size() : 0);
-    SHeader.sh_size += sizeof(uintX_t) + CBA.writeULEB128(NumBlocks);
-    // Write all BBEntries.
-    if (!E.BBEntries)
+    if (E.Feature & 0x80) {
+      // Write the number of basic block ranges, which is overridden by the
+      // 'NumBBRanges' field when specified.
+      uint32_t NumBBRanges =
+          E.NumBBRanges.value_or(E.BBRanges ? E.BBRanges->size() : 0);
+      SHeader.sh_size += CBA.writeULEB128(NumBBRanges);
+    } else {
+      assert(!E.BBRanges || E.BBRanges->size() <= 1);
+    }
+    if (!E.BBRanges)
       continue;
-    for (const ELFYAML::BBAddrMapEntry::BBEntry &BBE : *E.BBEntries) {
-      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) +
-                         CBA.writeULEB128(BBE.Size) +
-                         CBA.writeULEB128(BBE.Metadata);
+    for (const ELFYAML::BBAddrMapEntry::BBRangeEntry &BBR : *E.BBRanges) {
+      // Write the base address of the range.
+      CBA.write<uintX_t>(BBR.BaseAddress, ELFT::TargetEndianness);
+      // Write number of BBEntries (number of basic blocks in this basic block
+      // range). This is overridden by the 'NumBlocks' YAML field when
+      // specified.
+      uint64_t NumBlocks =
+          BBR.NumBlocks.value_or(BBR.BBEntries ? BBR.BBEntries->size() : 0);
+      SHeader.sh_size += sizeof(uintX_t) + CBA.writeULEB128(NumBlocks);
+      // Write all BBEntries in this BBRange.
+      if (!BBR.BBEntries)
+        continue;
+      for (const ELFYAML::BBAddrMapEntry::BBEntry &BBE : *BBR.BBEntries) {
+        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) +
+                           CBA.writeULEB128(BBE.Size) +
+                           CBA.writeULEB128(BBE.Metadata);
+      }
     }
   }
 }
diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp
index 1da4ea4e3edc919..085812a08ec7365 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -1810,7 +1810,13 @@ void MappingTraits<ELFYAML::BBAddrMapEntry>::mapping(
   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("NumBBRanges", E.NumBBRanges);
+  IO.mapOptional("BBRanges", E.BBRanges);
+}
+
+void MappingTraits<ELFYAML::BBAddrMapEntry::BBRangeEntry>::mapping(
+    IO &IO, ELFYAML::BBAddrMapEntry::BBRangeEntry &E) {
+  IO.mapOptional("BaseAddress", E.BaseAddress, Hex64(0));
   IO.mapOptional("NumBlocks", E.NumBlocks);
   IO.mapOptional("BBEntries", E.BBEntries);
 }
diff --git a/llvm/test/CodeGen/X86/basic-block-sections-labels-functions-sections.ll b/llvm/test/CodeGen/X86/basic-block-address-map-function-sections.ll
similarity index 94%
rename from llvm/test/CodeGen/X86/basic-block-sections-labels-functions-sections.ll
rename to llvm/test/CodeGen/X86/basic-block-address-map-function-sections.ll
index b8217bbc00760f0..cd9e3ad18204e38 100644
--- a/llvm/test/CodeGen/X86/basic-block-sections-labels-functions-sections.ll
+++ b/llvm/test/CodeGen/X86/basic-block-address-map-function-sections.ll
@@ -1,4 +1,5 @@
 ; RUN: llc < %s -mtriple=x86_64 -function-sections -basic-block-sections=labels | FileCheck %s
+; RUN: llc < %s -mtriple=x86_64 -function-sections -basic-block-address-map | FileCheck %s
 
 $_Z4fooTIiET_v = comdat any
 
diff --git a/llvm/test/CodeGen/X86/basic-block-address-map-with-basic-block-sections.ll b/llvm/test/CodeGen/X86/basic-block-address-map-with-basic-block-sections.ll
new file mode 100644
index 000000000000000..8938557518890ec
--- /dev/null
+++ b/llvm/test/CodeGen/X86/basic-block-address-map-with-basic-block-sections.ll
@@ -0,0 +1,71 @@
+;; Check that the -basic-block-address-map option works when used along with -basic-block-sections.
+;; Let a function with 4 basic blocks get split into 2 sections.
+; RUN: echo '!_Z3bazb' > %t
+; RUN: echo '!!0 2' >> %t
+; RUN: llc < %s -mtriple=x86_64 -basic-block-address-map -basic-block-sections=%t | FileCheck %s
+
+define void @_Z3bazb(i1 zeroext) personality i32 (...)* @__gxx_personality_v0 {
+  br i1 %0, label %2, label %7
+
+2:
+  %3 = invoke i32 @_Z3barv()
+          to label %7 unwind label %5
+  br label %9
+
+5:
+  landingpad { i8*, i32 }
+          catch i8* null
+  br label %9
+
+7:
+  %8 = call i32 @_Z3foov()
+  br label %9
+
+9:
+  ret void
+}
+
+declare i32 @_Z3barv() #1
+
+declare i32 @_Z3foov() #1
+
+declare i32 @__gxx_personality_v0(...)
+
+; CHECK:		.text
+; CHECK-LABEL:	_Z3bazb:
+; CHECK-LABEL:	.Lfunc_begin0:
+; CHECK-LABEL:	.LBB_END0_0:
+; CHECK-LABEL:	.LBB0_1:
+; CHECK-LABEL:	.LBB_END0_1:
+; CHECK:		.section .text.split._Z3bazb,"ax", at progbits
+; CHECK-LABEL:	_Z3bazb.cold:
+; CHECK-LABEL:	.LBB_END0_2:
+; CHECK-LABEL:	.LBB0_3:
+; CHECK-LABEL:	.LBB_END0_3:
+; CHECK-LABEL:	.Lfunc_end0:
+
+; CHECK:		.section	.llvm_bb_addr_map,"o", at llvm_bb_addr_map,.text.hot._Z3bazb
+; CHECK-NEXT:   .byte   2               # version
+; CHECK-NEXT:   .byte   128             # feature
+; CHECK-NEXT:   .byte   2               # number of basic block ranges
+; CHECK-NEXT:	.quad	.Lfunc_begin0   # base address
+; CHECK-NEXT:	.byte	2               # number of basic blocks
+; CHECK-NEXT:	.byte	0               # BB id
+; CHECK-NEXT:	.uleb128 .Lfunc_begin0-.Lfunc_begin0
+; CHECK-NEXT:	.uleb128 .LBB_END0_0-.Lfunc_begin0
+; CHECK-NEXT:	.byte	0
+; CHECK-NEXT:	.byte	2               # BB id
+; CHECK-NEXT:	.uleb128 .LBB0_1-.LBB_END0_0
+; CHECK-NEXT:	.uleb128 .LBB_END0_1-.LBB0_1
+; CHECK-NEXT:	.byte	5
+; CHECK-NEXT:	.quad	_Z3bazb.cold    # base address
+; CHECK-NEXT:	.byte	2               # number of basic blocks
+; CHECK-NEXT:	.byte	1               # BB id
+; CHECK-NEXT:	.uleb128 _Z3bazb.cold-_Z3bazb.cold
+; CHECK-NEXT:	.uleb128 .LBB_END0_2-_Z3bazb.cold
+; CHECK-NEXT:	.byte	8
+; CHECK-NEXT:	.byte	3               # BB id
+; CHECK-NEXT:	.uleb128 .LBB0_3-.LBB_END0_2
+; CHECK-NEXT:	.uleb128 .LBB_END0_3-.LBB0_3
+; CHECK-NEXT:	.byte	1
+
diff --git a/llvm/test/CodeGen/X86/basic-block-address-map-with-mfs.ll b/llvm/test/CodeGen/X86/basic-block-address-map-with-mfs.ll
new file mode 100644
index 000000000000000..b8419b8eb8ec9aa
--- /dev/null
+++ b/llvm/test/CodeGen/X86/basic-block-address-map-with-mfs.ll
@@ -0,0 +1,73 @@
+; COM: Emitting basic-block-address-map when machine function splitting is enabled.
+; RUN: llc < %s -mtriple=x86_64 -function-sections -split-machine-functions -basic-block-address-map | FileCheck %s
+
+define void @foo(i1 zeroext %0) nounwind !prof !14 {
+  br i1 %0, label %2, label %4, !prof !15
+
+2:                                                ; preds = %1
+  %3 = call i32 @bar()
+  br label %6
+
+4:                                                ; preds = %1
+  %5 = call i32 @baz()
+  br label %6
+
+6:                                                ; preds = %4, %2
+  %7 = tail call i32 @qux()
+  ret void
+}
+
+declare i32 @bar()
+declare i32 @baz()
+declare i32 @qux()
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"ProfileSummary", !1}
+!1 = !{!2, !3, !4, !5, !6, !7, !8, !9}
+!2 = !{!"ProfileFormat", !"InstrProf"}
+!3 = !{!"TotalCount", i64 10000}
+!4 = !{!"MaxCount", i64 10}
+!5 = !{!"MaxInternalCount", i64 1}
+!6 = !{!"MaxFunctionCount", i64 1000}
+!7 = !{!"NumCounts", i64 3}
+!8 = !{!"NumFunctions", i64 5}
+!9 = !{!"DetailedSummary", !10}
+!10 = !{!11, !12, !13}
+!11 = !{i32 10000, i64 100, i32 1}
+!12 = !{i32 999900, i64 100, i32 1}
+!13 = !{i32 999999, i64 1, i32 2}
+!14 = !{!"function_entry_count", i64 7000}
+!15 = !{!"branch_weights", i32 7000, i32 0}
+
+; CHECK:          .section .text.hot.foo,"ax", at progbits
+; CHECK-LABEL:  foo:
+; CHECK-LABEL:  .Lfunc_begin0:
+; CHECK-LABEL:  .LBB_END0_0:
+; CHECK-LABEL:  .LBB0_1:
+; CHECK-LABEL:  .LBB_END0_1:
+; CHECK:          .section .text.split.foo,"ax", at progbits
+; CHECK-LABEL:  foo.cold:
+; CHECK-LABEL:  .LBB_END0_2:
+; CHECK-LABEL:  .Lfunc_end0:
+
+; CHECK:                .section        .llvm_bb_addr_map,"o", at llvm_bb_addr_map,.text.hot.foo
+; CHECK-NEXT:   .byte   2               # version
+; CHECK-NEXT:   .byte   128             # feature
+; CHECK-NEXT:   .byte   2               # number of basic block ranges
+; CHECK-NEXT:   .quad   .Lfunc_begin0   # base address
+; CHECK-NEXT:   .byte   2               # number of basic blocks
+; CHECK-NEXT:   .byte   0               # BB id
+; CHECK-NEXT:   .uleb128 .Lfunc_begin0-.Lfunc_begin0
+; CHECK-NEXT:   .uleb128 .LBB_END0_0-.Lfunc_begin0
+; CHECK-NEXT:   .byte   8
+; CHECK-NEXT:   .byte   1               # BB id
+; CHECK-NEXT:   .uleb128 .LBB0_1-.LBB_END0_0
+; CHECK-NEXT:   .uleb128 .LBB_END0_1-.LBB0_1
+; CHECK-NEXT:   .byte   3
+; CHECK-NEXT:   .quad   foo.cold    # base address
+; CHECK-NEXT:   .byte   1               # number of basic blocks
+; CHECK-NEXT:   .byte   2               # BB id
+; CHECK-NEXT:   .uleb128 foo.cold-foo.cold
+; CHECK-NEXT:   .uleb128 .LBB_END0_2-foo.cold
+; CHECK-NEXT:   .byte   3
+
diff --git a/llvm/test/CodeGen/X86/basic-block-sections-labels.ll b/llvm/test/CodeGen/X86/basic-block-address-map.ll
similarity index 90%
rename from llvm/test/CodeGen/X86/basic-block-sections-labels.ll
rename to llvm/test/CodeGen/X86/basic-block-address-map.ll
index 0b0b00a0b981486..6ab24b494936ab2 100644
--- a/llvm/test/CodeGen/X86/basic-block-sections-labels.ll
+++ b/llvm/test/CodeGen/X86/basic-block-address-map.ll
@@ -1,5 +1,7 @@
 ; Check the basic block sections labels option
+; RUN: llc < %s -mtriple=x86_64 -function-sections -unique-section-names=true -basic-block-address-map | FileCheck %s --check-prefixes=CHECK,UNIQ
 ; RUN: llc < %s -mtriple=x86_64 -function-sections -unique-section-names=true -basic-block-sections=labels | FileCheck %s --check-prefixes=CHECK,UNIQ
+; RUN: llc < %s -mtriple=x86_64 -function-sections -unique-section-names=false -basic-block-address-map | FileCheck %s --check-prefixes=CHECK,NOUNIQ
 ; RUN: llc < %s -mtriple=x86_64 -function-sections -unique-section-names=false -basic-block-sections=labels | FileCheck %s --check-prefixes=CHECK,NOUNIQ
 ; RUN: llc < %s -mtriple=x86_64 -function-sections -unique-section-names=true -basic-block-sections=labels -split-machine-functions | FileCheck %s --check-prefixes=CHECK,UNIQ
 
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 2e9eb9af35615aa..d9b5e52132bc685 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
@@ -93,40 +93,42 @@ Sections:
     Link:   .text.foo
     Entries:
       - Version: 2
-        Address: [[FOO_ADDR]]
-        BBEntries:
-          - ID:            3
-            AddressOffset: 0x0
-            Size:          0x1
-            Metadata:      0x1
-          - ID:            1
-            AddressOffset: 0x0
-            Size:          0x6
-            Metadata:      0x0
-          - ID:            2
-            AddressOffset: 0x1
-            Size:          0x4
-            Metadata:      0x0
-          - ID:            5
-            AddressOffset: 0x0
-            Size:          0x1
-            Metadata:      0x2
+        BBRanges:
+         - BaseAddress: [[FOO_ADDR]]
+           BBEntries:
+            - ID:            3
+              AddressOffset: 0x0
+              Size:          0x1
+              Metadata:      0x1
+            - ID:            1
+              AddressOffset: 0x0
+              Size:          0x6
+              Metadata:      0x0
+            - ID:            2
+              AddressOffset: 0x1
+              Size:          0x4
+              Metadata:      0x0
+            - ID:            5
+              AddressOffset: 0x0
+              Size:          0x1
+              Metadata:      0x2
   - Name:   .llvm_bb_addr_map.bar
     Type:   SHT_LLVM_BB_ADDR_MAP
     Link:   .text.bar
     Entries:
       - Version: 1
-        Address: [[BAR_ADDR]]
-        BBEntries:
-          - AddressOffset: 0x0
-            Size:          0x1
-            Metadata:      0x1
-          - AddressOffset: 0x4
-            Size:          0x2
-            Metadata:      0x0
-          - AddressOffset: 0x0
-            Size:          0x6
-            Metadata:      0x0
+        BBRanges:
+          - BaseAddress: [[BAR_ADDR]]
+            BBEntries:
+            - AddressOffset: 0x0
+              Size:          0x1
+              Metadata:      0x1
+            - AddressOffset: 0x4
+              Size:          0x2
+              Metadata:      0x0
+            - AddressOffset: 0x0
+              Size:          0x6
+              Metadata:      0x0
 
 Symbols:
   - Name:    foo
@@ -167,36 +169,38 @@ Sections:
     Link:   .text.foo
     Entries:
       - Version: 2
-        Address: 0x4000
-        BBEntries:
-          - ID:            3
-            AddressOffset: 0x0
-            Size:          0x1
-            Metadata:      0x1
-          - ID:            1
-            AddressOffset: 0x0
-            Size:          0x6
-            Metadata:      0x0
-          - ID:            2
-            AddressOffset: 0x1
-            Size:          0x4
-            Metadata:      0x0
-          - ID:            5
-            AddressOffset: 0x0
-            Size:          0x1
-            Metadata:      0x2
+        BBRanges:
+          - BaseAddress: 0x4000
+            BBEntries:
+             - ID:            3
+               AddressOffset: 0x0
+               Size:          0x1
+               Metadata:      0x1
+             - ID:            1
+               AddressOffset: 0x0
+               Size:          0x6
+               Metadata:      0x0
+             - ID:            2
+               AddressOffset: 0x1
+               Size:          0x4
+               Metadata:      0x0
+             - ID:            5
+               AddressOffset: 0x0
+               Size:          0x1
+               Metadata:      0x2
       - Version: 1
-        Address: 0x5000
-        BBEntries:
-          - AddressOffset: 0x0
-            Size:          0x1
-            Metadata:      0x1
-          - AddressOffset: 0x4
-            Size:          0x2
-            Metadata:      0x0
-          - AddressOffset: 0x0
-            Size:          0x6
-            Metadata:      0x0
+        BBRanges:
+          - BaseAddress: 0x5000
+            BBEntries:
+             - AddressOffset: 0x0
+               Size:          0x1
+               Metadata:      0x1
+             - AddressOffset: 0x4
+               Size:          0x2
+               Metadata:      0x0
+             - AddressOffset: 0x0
+               Size:          0x6
+               Metadata:      0x0
 
 Symbols:
   - Name:    foo
diff --git a/llvm/test/tools/llvm-objdump/X86/elf-bbaddrmap-symbolize-relocatable.yaml b/llvm/test/tools/llvm-objdump/X86/elf-bbaddrmap-symbolize-relocatable.yaml
index d5a618467bd2c99..aeef8f5bcd62ed1 100644
--- a/llvm/test/tools/llvm-objdump/X86/elf-bbaddrmap-symbolize-relocatable.yaml
+++ b/llvm/test/tools/llvm-objdump/X86/elf-bbaddrmap-symbolize-relocatable.yaml
@@ -27,17 +27,19 @@ Sections:
     Link:    .text
     Entries:
       - Version: 2
-        BBEntries:
-          - ID:              0
-            AddressOffset:   0x0
-            Size:            0x1
-            Metadata:        0x1
+        BBRanges:
+          - BBEntries:
+             - ID:              0
+               AddressOffset:   0x0
+               Size:            0x1
+               Metadata:        0x1
       - Version: 2
-        BBEntries:
-          - ID:              0
-            AddressOffset:   0x0
-            Size:            0x1
-            Metadata:        0x1
+        BBRanges:
+          - BBEntries:
+            - ID:              0
+              AddressOffset:   0x0
+              Size:            0x1
+              Metadata:        0x1
   - Name:  .rela.llvm_bb_addr_map
     Type:  SHT_RELA
     Flags: [ SHF_INFO_LINK ]
diff --git a/llvm/test/tools/llvm-readobj/ELF/bb-addr-map-relocatable.test b/llvm/test/tools/llvm-readobj/ELF/bb-addr-map-relocatable.test
index 6ac27941853fed6..2d4e5e65a185b92 100644
--- a/llvm/test/tools/llvm-readobj/ELF/bb-addr-map-relocatable.test
+++ b/llvm/test/tools/llvm-readobj/ELF/bb-addr-map-relocatable.test
@@ -11,32 +11,42 @@
 # CHECK-NEXT:   Function {
 # CHECK-NEXT:     At: 0x0
 # CHECK-NEXT:     Name: <?>
-# CHECK-NEXT:     BB entries [
+# CHECK-NEXT:     BB Ranges [
 # CHECK-NEXT:       {
-# CHECK-NEXT:         ID: 0
-# CHECK-NEXT:         Offset: 0x0
-# CHECK-NEXT:         Size: 0xF
-# CHECK-NEXT:         HasReturn: Yes
-# CHECK-NEXT:         HasTailCall: No
-# CHECK-NEXT:         IsEHPad: No
-# CHECK-NEXT:         CanFallThrough: No
-# CHECK-NEXT:         HasIndirectBranch: No
+# CHECK-NEXT:         Base Address: 0x0
+# CHECK-NEXT:         BB Entries [
+# CHECK-NEXT:           {
+# CHECK-NEXT:             ID: 0
+# CHECK-NEXT:             Offset: 0x0
+# CHECK-NEXT:             Size: 0xF
+# CHECK-NEXT:             HasReturn: Yes
+# CHECK-NEXT:             HasTailCall: No
+# CHECK-NEXT:             IsEHPad: No
+# CHECK-NEXT:             CanFallThrough: No
+# CHECK-NEXT:             HasIndirectBranch: No
+# CHECK-NEXT:           }
+# CHECK-NEXT:         ]
 # CHECK-NEXT:       }
 # CHECK-NEXT:     ]
 # CHECK-NEXT:   }
 # CHECK-NEXT:   Function {
 # CHECK-NEXT:     At: 0x10
 # CHECK-NEXT:     Name: <?>
-# CHECK-NEXT:     BB entries [
+# CHECK-NEXT:     BB Ranges [
 # CHECK-NEXT:       {
-# CHECK-NEXT:         ID: 0
-# CHECK-NEXT:         Offset: 0x0
-# CHECK-NEXT:         Size: 0x11
-# CHECK-NEXT:         HasReturn: No
-# CHECK-NEXT:         HasTailCall: No
-# CHECK-NEXT:         IsEHPad: No
-# CHECK-NEXT:         CanFallThrough: Yes
-# CHECK-NEXT:         HasIndirectBranch: No
+# CHECK-NEXT:         Base Address: 0x10
+# CHECK-NEXT:         BB Entries [
+# CHECK-NEXT:           {
+# CHECK-NEXT:             ID: 0
+# CHECK-NEXT:             Offset: 0x0
+# CHECK-NEXT:             Size: 0x11
+# CHECK-NEXT:             HasReturn: No
+# CHECK-NEXT:             HasTailCall: No
+# CHECK-NEXT:             IsEHPad: No
+# CHECK-NEXT:             CanFallThrough: Yes
+# CHECK-NEXT:             HasIndirectBranch: No
+# CHECK-NEXT:           }
+# CHECK-NEXT:         ]
 # CHECK-NEXT:       }
 # CHECK-NEXT:     ]
 # CHECK-NEXT:   }
@@ -57,17 +67,19 @@ Sections:
     Link:    .text
     Entries:
       - Version: 2
-        BBEntries:
-          - ID:              0
-            AddressOffset:   0x0
-            Size:            0xF
-            Metadata:        0x1
+        BBRanges:
+          - BBEntries:
+            - ID:              0
+              AddressOffset:   0x0
+              Size:            0xF
+              Metadata:        0x1
       - Version: 2
-        BBEntries:
-          - ID:              0
-            AddressOffset:   0x0
-            Size:            0x11
-            Metadata:        0x8
+        BBRanges:
+          - BBEntries:
+             - ID:              0
+               AddressOffset:   0x0
+               Size:            0x11
+               Metadata:        0x8
   - Name:  .rela.llvm_bb_addr_map
     Type:  SHT_RELA
     Flags: [ SHF_INFO_LINK ]
@@ -131,7 +143,8 @@ Sections:
     Link:    .text
     Entries:
       - Version: 2
-        BBEntries:
+        BBRanges:
+        - BBEntries:
           - ID:              0
             AddressOffset:   0x0
             Size:            0xF
@@ -184,12 +197,13 @@ Sections:
     Flags:           [ SHF_LINK_ORDER ]
     Entries:
       - Version:         2
-        Address:         0xF
-        BBEntries:
-          - ID:              0
-            AddressOffset:   0x0
-            Size:            0xF
-            Metadata:        0x1
+        BBRanges:
+          - BaseAddress:         0xF
+            BBEntries:
+             - ID:              0
+               AddressOffset:   0x0
+               Size:            0xF
+               Metadata:        0x1
 
 # RUN: yaml2obj %s --docnum=5 -o %t5.o
 # RUN: llvm-readobj %t5.o --bb-addr-map 2>&1 | FileCheck %s --check-prefix=ET-DYN-NO-WARNING -DFILE=%t5.o
@@ -198,16 +212,21 @@ Sections:
 # ET-DYN-NO-WARNING:   Function {
 # ET-DYN-NO-WARNING:     At: 0xF
 # ET-DYN-NO-WARNING:     Name: <?>
-# ET-DYN-NO-WARNING:     BB entries [
+# ET-DYN-NO-WARNING:     BB Ranges [
 # ET-DYN-NO-WARNING:       {
-# ET-DYN-NO-WARNING:         ID: 0
-# ET-DYN-NO-WARNING:         Offset: 0x0
-# ET-DYN-NO-WARNING:         Size: 0xF
-# ET-DYN-NO-WARNING:         HasReturn: Yes
-# ET-DYN-NO-WARNING:         HasTailCall: No
-# ET-DYN-NO-WARNING:         IsEHPad: No
-# ET-DYN-NO-WARNING:         CanFallThrough: No
-# ET-DYN-NO-WARNING:         HasIndirectBranch: No
+# ET-DYN-NO-WARNING:         Base Address: 0xF
+# ET-DYN-NO-WARNING:         BB Entries [
+# ET-DYN-NO-WARNING:           {
+# ET-DYN-NO-WARNING:             ID: 0
+# ET-DYN-NO-WARNING:             Offset: 0x0
+# ET-DYN-NO-WARNING:             Size: 0xF
+# ET-DYN-NO-WARNING:             HasReturn: Yes
+# ET-DYN-NO-WARNING:             HasTailCall: No
+# ET-DYN-NO-WARNING:             IsEHPad: No
+# ET-DYN-NO-WARNING:             CanFallThrough: No
+# ET-DYN-NO-WARNING:             HasIndirectBranch: No
+# ET-DYN-NO-WARNING:           }
+# ET-DYN-NO-WARNING:         ]
 # ET-DYN-NO-WARNING:       }
 # ET-DYN-NO-WARNING:     ]
 # ET-DYN-NO-WARNING:   }
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 92805701751078f..8da1ed08d9fc04f 100644
--- a/llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test
+++ b/llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test
@@ -18,8 +18,8 @@
 # RUN: llvm-readelf %t1.x32.o --bb-addr-map | FileCheck %s --check-prefix=GNU
 
 ## Check that a malformed section can be handled.
-# 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
+# RUN: yaml2obj --docnum=1 %s -DBITS=32 -DSIZE=7 -o %t2.o
+# RUN: llvm-readobj %t2.o --bb-addr-map 2>&1 | FileCheck %s -DOFFSET=0x00000007 -DFILE=%t2.o --check-prefix=TRUNCATED
 
 ## Check that invalid metadata can be handled.
 # RUN: yaml2obj --docnum=1 %s -DBITS=32 -DMETADATA=0xF000002 -o %t3.o
@@ -30,42 +30,57 @@
 # 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:     BB Ranges [
 # CHECK-NEXT:       {
-# CHECK-NEXT:         ID: 0
-# 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:         HasIndirectBranch: No
+# CHECK-NEXT:         Base Address: [[ADDR]]
+# CHECK-NEXT:         BB Entries [
+# CHECK-NEXT:           {
+# CHECK-NEXT:             ID: 0
+# 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:             HasIndirectBranch: No
+# CHECK-NEXT:           }
+# CHECK-NEXT:         ]
 # CHECK-NEXT:       }
 # CHECK-NEXT:       {
-# CHECK-NEXT:         ID: 2
-# 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:         HasIndirectBranch: Yes
+# CHECK-NEXT:         Base Address: 0x44444
+# CHECK-NEXT:         BB Entries [
+# CHECK-NEXT:           {
+# CHECK-NEXT:             ID: 2
+# CHECK-NEXT:             Offset: 0x3
+# CHECK-NEXT:             Size: 0x4
+# CHECK-NEXT:             HasReturn: Yes
+# CHECK-NEXT:             HasTailCall: No
+# CHECK-NEXT:             IsEHPad: Yes
+# CHECK-NEXT:             CanFallThrough: No
+# CHECK-NEXT:             HasIndirectBranch: Yes
+# CHECK-NEXT:           }
+# CHECK-NEXT:         ]
 # CHECK-NEXT:       }
 # CHECK-NEXT:     ]
 # CHECK-NEXT:   }
 # CHECK-NEXT:   Function {
 # CHECK-NEXT:     At: 0x22222
 # CHECK-NEXT:     Name: foo
-# CHECK-NEXT:     BB entries [
+# CHECK-NEXT:     BB Ranges [
 # CHECK-NEXT:       {
-# CHECK-NEXT:         ID: 4
-# 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:         HasIndirectBranch: No
+# CHECK-NEXT:         Base Address: 0x22222
+# CHECK-NEXT:         BB Entries [
+# CHECK-NEXT:           {
+# CHECK-NEXT:             ID: 4
+# 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:            HasIndirectBranch: No
+# CHECK-NEXT:           }
+# CHECK-NEXT:         ]
 # CHECK-NEXT:       }
 # CHECK-NEXT:     ]
 # CHECK-NEXT:   }
@@ -81,26 +96,31 @@
 # TRUNCATED-NEXT:   Function {
 # TRUNCATED-NEXT:     At: 0x33333
 # TRUNCATED-NEXT:     Name: bar
-# TRUNCATED-NEXT:     BB entries [
+# TRUNCATED-NEXT:     BB Ranges [
 # TRUNCATED-NEXT:       {
-# TRUNCATED-NEXT:         ID: 6
-# TRUNCATED-NEXT:         Offset: 0x9
-# TRUNCATED-NEXT:         Size: 0xA
-# TRUNCATED-NEXT:         HasReturn: Yes
-# TRUNCATED-NEXT:         HasTailCall: Yes
-# TRUNCATED-NEXT:         IsEHPad: No
-# TRUNCATED-NEXT:         CanFallThrough: Yes
-# TRUNCATED-NEXT:         HasIndirectBranch: Yes
-# TRUNCATED-NEXT:       }
-# TRUNCATED-NEXT:       {
-# TRUNCATED-NEXT:         ID: 7
-# 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:         HasIndirectBranch: No
+# TRUNCATED-NEXT:         Base Address: 0x33333
+# TRUNCATED-NEXT:         BB Entries [
+# TRUNCATED-NEXT:           {
+# TRUNCATED-NEXT:             ID: 6
+# TRUNCATED-NEXT:             Offset: 0x9
+# TRUNCATED-NEXT:             Size: 0xA
+# TRUNCATED-NEXT:             HasReturn: Yes
+# TRUNCATED-NEXT:             HasTailCall: Yes
+# TRUNCATED-NEXT:             IsEHPad: No
+# TRUNCATED-NEXT:             CanFallThrough: Yes
+# TRUNCATED-NEXT:             HasIndirectBranch: Yes
+# TRUNCATED-NEXT:           }
+# TRUNCATED-NEXT:           {
+# TRUNCATED-NEXT:             ID: 7
+# 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:             HasIndirectBranch: No
+# TRUNCATED-NEXT:           }
+# TRUNCATED-NEXT:         ]
 # TRUNCATED-NEXT:       }
 # TRUNCATED-NEXT:     ]
 # TRUNCATED-NEXT:   }
@@ -127,23 +147,28 @@ Sections:
     Link:   .text
     Entries:
       - Version: 2
-        Address: [[ADDR=0x11111]]
-        BBEntries:
-          - ID:            0
-            AddressOffset: 0x0
-            Size:          0x1
-            Metadata:      [[METADATA=0x2]]
-          - ID:            2
-            AddressOffset: 0x3
-            Size:          0x4
-            Metadata:      0x15
+        Feature: 0x80
+        BBRanges:
+          - BaseAddress: [[ADDR=0x11111]]
+            BBEntries:
+              - ID:            0
+                AddressOffset: 0x0
+                Size:          0x1
+                Metadata:      [[METADATA=0x2]]
+          - BaseAddress: 0x44444
+            BBEntries:
+              - ID:            2
+                AddressOffset: 0x3
+                Size:          0x4
+                Metadata:      0x15
       - Version: 2
-        Address: 0x22222
-        BBEntries:
-          - ID:            4
-            AddressOffset: 0x6
-            Size:          0x7
-            Metadata:      0x8
+        BBRanges:
+          - BaseAddress: 0x22222
+            BBEntries:
+              - ID:            4
+                AddressOffset: 0x6
+                Size:          0x7
+                Metadata:      0x8
   - Name: dummy_section
     Type: SHT_PROGBITS
     Size: 16
@@ -152,16 +177,17 @@ Sections:
     Link: .text.bar
     Entries:
       - Version: 2
-        Address: 0x33333
-        BBEntries:
-          - ID:            6
-            AddressOffset: 0x9
-            Size:          0xa
-            Metadata:      0x1b
-          - ID:            7
-            AddressOffset: 0xc
-            Size:          0xd
-            Metadata:      0xe
+        BBRanges:
+          - BaseAddress: 0x33333
+            BBEntries:
+              - ID:            6
+                AddressOffset: 0x9
+                Size:          0xa
+                Metadata:      0x1b
+              - ID:            7
+                AddressOffset: 0xc
+                Size:          0xd
+                Metadata:      0xe
 Symbols:
   - Name:    foo
     Section: .text
@@ -188,29 +214,35 @@ Symbols:
 # V0-NEXT:   Function {
 # V0-NEXT:     At:   0x11111
 # V0-NEXT:     Name: foo
-# V0-NEXT:     BB entries [
-# V0-NEXT:       {
-# V0-NEXT:         ID: 0
-# V0-NEXT:         Offset: 0x1
-# V0-NEXT:         Size: 0x2
-# V0-NEXT:         HasReturn:
-# V0-NEXT:         HasTailCall:
-# V0-NEXT:         IsEHPad:
-# V0-NEXT:         CanFallThrough:
-# V0-NEXT:         HasIndirectBranch:
-# V0-NEXT:       }
+# V0-NEXT:     BB Ranges [
 # V0-NEXT:       {
-# V0-NEXT:         ID: 1
-# V0-NEXT:         Offset: 0x4
-# V0-NEXT:         Size: 0x5
-# V0-NEXT:         HasReturn:
-# V0-NEXT:         HasTailCall:
-# V0-NEXT:         IsEHPad:
-# V0-NEXT:         CanFallThrough:
-# V0-NEXT:         HasIndirectBranch:
+# V0-NEXT:         Base Address: 0x11111
+# V0-NEXT:         BB Entries [
+# V0-NEXT:           {
+# V0-NEXT:             ID: 0
+# V0-NEXT:             Offset: 0x1
+# V0-NEXT:             Size: 0x2
+# V0-NEXT:             HasReturn:
+# V0-NEXT:             HasTailCall:
+# V0-NEXT:             IsEHPad:
+# V0-NEXT:             CanFallThrough:
+# V0-NEXT:             HasIndirectBranch:
+# V0-NEXT:           }
+# V0-NEXT:           {
+# V0-NEXT:             ID: 1
+# V0-NEXT:             Offset: 0x4
+# V0-NEXT:             Size: 0x5
+# V0-NEXT:             HasReturn:
+# V0-NEXT:             HasTailCall:
+# V0-NEXT:             IsEHPad:
+# V0-NEXT:             CanFallThrough:
+# V0-NEXT:             HasIndirectBranch:
+# V0-NEXT:           }
+# V0-NEXT:         ]
 # V0-NEXT:       }
 # V0-NEXT:     ]
 # V0-NEXT:   }
+# V0-NEXT: ]
 
 ## Check version 1 (without BB IDs).
 # RUN: yaml2obj --docnum=2 %s -DVERSION=1 -DSECTION_TYPE=SHT_LLVM_BB_ADDR_MAP -o %t3
@@ -220,29 +252,35 @@ Symbols:
 # V1-NEXT:   Function {
 # V1-NEXT:     At:   0x11111
 # V1-NEXT:     Name: foo
-# V1-NEXT:     BB entries [
-# V1-NEXT:       {
-# V1-NEXT:         ID: 0
-# V1-NEXT:         Offset: 0x1
-# V1-NEXT:         Size: 0x2
-# V1-NEXT:         HasReturn:
-# V1-NEXT:         HasTailCall:
-# V1-NEXT:         IsEHPad:
-# V1-NEXT:         CanFallThrough:
-# V1-NEXT:         HasIndirectBranch:
-# V1-NEXT:       }
+# V1-NEXT:     BB Ranges [
 # V1-NEXT:       {
-# V1-NEXT:         ID: 1
-# V1-NEXT:         Offset: 0x7
-# V1-NEXT:         Size: 0x5
-# V1-NEXT:         HasReturn:
-# V1-NEXT:         HasTailCall:
-# V1-NEXT:         IsEHPad:
-# V1-NEXT:         CanFallThrough:
-# V1-NEXT:         HasIndirectBranch:
+# V1-NEXT:         Base Address: 0x11111
+# V1-NEXT:         BB Entries [
+# V1-NEXT:           {
+# V1-NEXT:             ID: 0
+# V1-NEXT:             Offset: 0x1
+# V1-NEXT:             Size: 0x2
+# V1-NEXT:             HasReturn:
+# V1-NEXT:             HasTailCall:
+# V1-NEXT:             IsEHPad:
+# V1-NEXT:             CanFallThrough:
+# V1-NEXT:             HasIndirectBranch:
+# V1-NEXT:           }
+# V1-NEXT:           {
+# V1-NEXT:             ID: 1
+# V1-NEXT:             Offset: 0x7
+# V1-NEXT:             Size: 0x5
+# V1-NEXT:             HasReturn:
+# V1-NEXT:             HasTailCall:
+# V1-NEXT:             IsEHPad:
+# V1-NEXT:             CanFallThrough:
+# V1-NEXT:             HasIndirectBranch:
+# V1-NEXT:           }
+# V1-NEXT:         ]
 # V1-NEXT:       }
 # V1-NEXT:     ]
 # V1-NEXT:   }
+# V1-NEXT: ]
 
 --- !ELF
 FileHeader:
@@ -258,14 +296,15 @@ Sections:
     Link:  .text.foo
     Entries:
       - Version: [[VERSION]]
-        Address: 0x11111
-        BBEntries:
-          - AddressOffset: 0x1
-            Size:          0x2
-            Metadata:      0x3
-          - AddressOffset: 0x4
-            Size:          0x5
-            Metadata:      0x6
+        BBRanges:
+          - BaseAddress: 0x11111
+            BBEntries:
+            - AddressOffset: 0x1
+              Size:          0x2
+              Metadata:      0x3
+            - AddressOffset: 0x4
+              Size:          0x5
+              Metadata:      0x6
 Symbols:
   - Name:    foo
     Section: .text.foo
diff --git a/llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml b/llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml
index eceb42f6598f0fd..5701d2bfdbca510 100644
--- a/llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml
+++ b/llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml
@@ -17,30 +17,31 @@
 # 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: 2
-# VALID-NEXT:         Feature: 0xFF
-# VALID-NEXT:         BBEntries:
-# VALID-NEXT:           - ID:            0
-# VALID-NEXT:             AddressOffset: 0x1
-# VALID-NEXT:             Size:          0x2
-# VALID-NEXT:             Metadata:      0x3
-# VALID-NEXT:           - ID:            2
-# VALID-NEXT:             AddressOffset: 0x4
-# VALID-NEXT:             Size:          0x5
-# VALID-NEXT:             Metadata:      0x6
-# VALID-NEXT:           - ID:            4
-# VALID-NEXT:             AddressOffset: 0xFFFFFFFFFFFFFFF7
-# VALID-NEXT:             Size:          0xFFFFFFFFFFFFFFF8
-# VALID-NEXT:             Metadata:      0xFFFFFFFFFFFFFFF9
+# VALID-NEXT:         BBRanges:
+## The 'BaseAddress' field is omitted when it's zero.
+# VALID-NEXT:           - BBEntries:
+# VALID-NEXT:             - ID:            0
+# VALID-NEXT:               AddressOffset: 0x1
+# VALID-NEXT:               Size:          0x2
+# VALID-NEXT:               Metadata:      0x3
+# VALID-NEXT:             - ID:            2
+# VALID-NEXT:               AddressOffset: 0x4
+# VALID-NEXT:               Size:          0x5
+# VALID-NEXT:               Metadata:      0x6
+# VALID-NEXT:             - ID:            4
+# VALID-NEXT:               AddressOffset: 0xFFFFFFFFFFFFFFF7
+# VALID-NEXT:               Size:          0xFFFFFFFFFFFFFFF8
+# VALID-NEXT:               Metadata:      0xFFFFFFFFFFFFFFF9
 # VALID-NEXT:       - Version: 2
-# VALID-NEXT:         Feature: 0xEE
-# VALID-NEXT:         Address: 0xFFFFFFFFFFFFFF20
-# VALID-NEXT:         BBEntries:
-# VALID-NEXT:           - ID:            6
-# VALID-NEXT:             AddressOffset: 0xA
-# VALID-NEXT:             Size:          0xB
-# VALID-NEXT:             Metadata:      0xC
+# VALID-NEXT:         Feature: 0x80
+# 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
 
 --- !ELF
 FileHeader:
@@ -53,30 +54,33 @@ Sections:
     ShSize: [[SIZE=<none>]]
     Entries:
       - Version: 2
-        Feature: 0xFF
-        Address: 0x0
-        BBEntries:
-          - ID:            0
-            AddressOffset: 0x1
-            Size:          0x2
-            Metadata:      0x3
-          - ID:            2
-            AddressOffset: 0x4
-            Size:          0x5
-            Metadata:      0x6
-          - ID:            4
-            AddressOffset: 0xFFFFFFFFFFFFFFF7
-            Size:          0xFFFFFFFFFFFFFFF8
-            Metadata:      0xFFFFFFFFFFFFFFF9
+        Feature: 0x0
+        BBRanges:
+          - BaseAddress: 0x0
+            BBEntries:
+              - ID:            0
+                AddressOffset: 0x1
+                Size:          0x2
+                Metadata:      0x3
+              - ID:            2
+                AddressOffset: 0x4
+                Size:          0x5
+                Metadata:      0x6
+              - ID:            4
+                AddressOffset: 0xFFFFFFFFFFFFFFF7
+                Size:          0xFFFFFFFFFFFFFFF8
+                Metadata:      0xFFFFFFFFFFFFFFF9
       - Version:   2
-        Feature:   0xEE
-        Address:   0xFFFFFFFFFFFFFF20
-        NumBlocks: [[NUMBLOCKS=<none>]]
-        BBEntries:
-          - ID:            6
-            AddressOffset: 0xA
-            Size:          0xB
-            Metadata:      0xC
+        Feature:   0x80
+        NumBBRanges: [[NUMBBRANGES=<none>]]
+        BBRanges:
+          - BaseAddress:   0xFFFFFFFFFFFFFF20
+            NumBlocks: [[NUMBLOCKS=<none>]]
+            BBEntries:
+             - ID:            6
+               AddressOffset: 0xA
+               Size:          0xB
+               Metadata:      0xC
 
 ## Check obj2yaml can dump empty .llvm_bb_addr_map sections.
 
@@ -117,19 +121,21 @@ Sections:
 # MULTI-NEXT:   - Name: .llvm_bb_addr_map
 # MULTI-NEXT:     Type: SHT_LLVM_BB_ADDR_MAP
 # MULTI-NEXT:     Entries:
-## Fields 'Address' and 'Feature' are omitted when they are zero.
+## Fields 'BaseAddress' and 'Feature' are omitted when they are zero.
 # MULTI-NEXT:       - Version: 0
-# MULTI-NEXT:         BBEntries:
-# MULTI-NEXT:           - ID:            0
-# MULTI-NEXT:             AddressOffset: 0x1
-# MULTI-NEXT:             Size:          0x2
-# MULTI-NEXT:             Metadata:      0x3
+# MULTI-NEXT:         BBRanges:
+# MULTI-NEXT:           - BBEntries:
+# MULTI-NEXT:              - ID:            0
+# 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:       - Version:   0
-# MULTI-NEXT:         Address:   0x20
-# MULTI-NEXT:         BBEntries: []
+# MULTI-NEXT:         BBRanges:
+# MULTI-NEXT:           - BaseAddress:   0x20
+# MULTI-NEXT:             BBEntries: []
 
 --- !ELF
 FileHeader:
@@ -144,16 +150,18 @@ Sections:
 ## they are zero.
       - Version: 0
         Feature: 0x0
-        Address: 0x0
-        BBEntries:
-          - AddressOffset: 0x1
-            Size:          0x2
-            Metadata:      0x3
+        BBRanges:
+          - BaseAddress: 0x0
+            BBEntries:
+              - AddressOffset: 0x1
+                Size:          0x2
+                Metadata:      0x3
   - Name: '.llvm_bb_addr_map (1)'
     Type:  SHT_LLVM_BB_ADDR_MAP
     Entries:
       - Version: 0
-        Address: 0x20
+        BBRanges:
+          - BaseAddress: 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
@@ -163,7 +171,10 @@ Sections:
 # RUN: obj2yaml %t4 | FileCheck %s --check-prefixes=TRUNCATED,INVALID
 
 # RUN: yaml2obj --docnum=1 -DNUMBLOCKS=2 %s -o %t5
-# RUN: obj2yaml %t5 | FileCheck %s --check-prefixes=BADNUMBLOCKS,INVALID
+# RUN: obj2yaml %t5 | FileCheck %s --check-prefixes=BADNUM,INVALID
+
+# RUN: yaml2obj --docnum=1 -DNUMBBRANGES=2 %s -o %t6
+# RUN: obj2yaml %t6 | FileCheck %s --check-prefixes=BADNUM,INVALID
 
 # INVALID:           --- !ELF
 # INVALID-NEXT:      FileHeader:
@@ -173,12 +184,12 @@ Sections:
 # INVALID-NEXT:      Sections:
 # INVALID-NEXT:        - Name:    .llvm_bb_addr_map
 # INVALID-NEXT:          Type:    SHT_LLVM_BB_ADDR_MAP
-# BADNUMBLOCKS-NEXT:     Content: {{([[:xdigit:]]+)}}{{$}}
-# TRUNCATED-NEXT:        Content: {{([[:xdigit:]]{16})}}{{$}}
+# BADNUM-NEXT:           Content: {{([[:xdigit:]]+)}}{{$}}
+# 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
+# RUN: yaml2obj --docnum=4 %s -o %t7
+# RUN: obj2yaml %t7 | FileCheck %s --check-prefix=V0
 
 # V0:      --- !ELF
 # V0-NEXT: FileHeader:
@@ -190,12 +201,13 @@ Sections:
 # 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:           - ID:            0
-# V0-NEXT:             AddressOffset: 0x1
-# V0-NEXT:             Size:          0x2
-# V0-NEXT:             Metadata:      0x3
+# V0-NEXT:         BBRanges:
+# V0-NEXT:           - BaseAddress: 0x1111
+# V0-NEXT:             BBEntries:
+# V0-NEXT:               - ID:            0
+# V0-NEXT:                 AddressOffset: 0x1
+# V0-NEXT:                 Size:          0x2
+# V0-NEXT:                 Metadata:      0x3
 
 --- !ELF
 FileHeader:
@@ -207,15 +219,16 @@ Sections:
     Type: SHT_LLVM_BB_ADDR_MAP_V0
     Entries:
       - Version: 0
-        Address: 0x1111
-        BBEntries:
-          - AddressOffset: 0x1
-            Size:          0x2
-            Metadata:      0x3
+        BBRanges:
+          - BaseAddress:  0x1111
+            BBEntries:
+              - AddressOffset: 0x1
+                Size:          0x2
+                Metadata:      0x3
 
 ## Check obj2yaml for version 1.
-# RUN: yaml2obj --docnum=5 %s -o %t7
-# RUN: obj2yaml %t7 | FileCheck %s --check-prefix=V1
+# RUN: yaml2obj --docnum=5 %s -o %t8
+# RUN: obj2yaml %t8 | FileCheck %s --check-prefix=V1
 
 # V1:      --- !ELF
 # V1-NEXT: FileHeader:
@@ -227,16 +240,17 @@ Sections:
 # V1-NEXT:     Type: SHT_LLVM_BB_ADDR_MAP
 # V1-NEXT:     Entries:
 # V1-NEXT:       - Version: 1
-# V1-NEXT:         Address: 0x1111
-# V1-NEXT:         BBEntries:
-# V1-NEXT:           - ID:            0
-# V1-NEXT:             AddressOffset: 0x1
-# V1-NEXT:             Size:          0x2
-# V1-NEXT:             Metadata:      0x3
-# V1-NEXT:           - ID:            1
-# V1-NEXT:             AddressOffset: 0x4
-# V1-NEXT:             Size:          0x5
-# V1-NEXT:             Metadata:      0x6
+# V1-NEXT:         BBRanges:
+# V1-NEXT:           - BaseAddress: 0x1111
+# V1-NEXT:             BBEntries:
+# V1-NEXT:               - ID:            0
+# V1-NEXT:                 AddressOffset: 0x1
+# V1-NEXT:                 Size:          0x2
+# V1-NEXT:                 Metadata:      0x3
+# V1-NEXT:               - ID:            1
+# V1-NEXT:                 AddressOffset: 0x4
+# V1-NEXT:                 Size:          0x5
+# V1-NEXT:                 Metadata:      0x6
 
 --- !ELF
 FileHeader:
@@ -248,11 +262,12 @@ Sections:
     Type: SHT_LLVM_BB_ADDR_MAP
     Entries:
       - Version: 1
-        Address: 0x1111
-        BBEntries:
-          - AddressOffset: 0x1
-            Size:          0x2
-            Metadata:      0x3
-          - AddressOffset: 0x4
-            Size:          0x5
-            Metadata:      0x6
+        BBRanges:
+          - BaseAddress: 0x1111
+            BBEntries:
+              - AddressOffset: 0x1
+                Size:          0x2
+                Metadata:      0x3
+              - AddressOffset: 0x4
+                Size:          0x5
+                Metadata:      0x6
diff --git a/llvm/test/tools/yaml2obj/ELF/bb-addr-map.yaml b/llvm/test/tools/yaml2obj/ELF/bb-addr-map.yaml
index 73c9168084170b5..f279f1c923ffb3b 100644
--- a/llvm/test/tools/yaml2obj/ELF/bb-addr-map.yaml
+++ b/llvm/test/tools/yaml2obj/ELF/bb-addr-map.yaml
@@ -89,12 +89,13 @@ Sections:
     Type: SHT_LLVM_BB_ADDR_MAP
     Entries:
       - Version: 2
-        Address: 0x0000000000000020
-        BBEntries:
-          - ID:            11
-            AddressOffset: 0x00000001
-            Size:          0x00000002
-            Metadata:      0x00000003
+        BBRanges:
+          - BaseAddress: 0x0000000000000020
+            BBEntries:
+              - ID:            11
+                AddressOffset: 0x00000001
+                Size:          0x00000002
+                Metadata:      0x00000003
 
 ## 5) When specifying the description with Entries, the 'Address' field will be
 ##    zero when omitted.
@@ -102,11 +103,12 @@ Sections:
     Type: SHT_LLVM_BB_ADDR_MAP
     Entries:
       - Version: 2
-        BBEntries:
-          - ID:            12
-            AddressOffset: 0x00000001
-            Size:          0x00000002
-            Metadata:      0x00000003
+        BBRanges:
+          - BBEntries:
+            - ID:            12
+              AddressOffset: 0x00000001
+              Size:          0x00000002
+              Metadata:      0x00000003
 
 ## 6) We can override the NumBlocks field with a value different from the
 ##    actual number of BB Entries.
@@ -114,13 +116,14 @@ Sections:
     Type: SHT_LLVM_BB_ADDR_MAP
     Entries:
       - Version:   2
-        Address:   0x0000000000000020
-        NumBlocks: 2
-        BBEntries:
-          - ID:            13
-            AddressOffset: 0x00000001
-            Size:          0x00000002
-            Metadata:      0x00000003
+        BBRanges:
+          - BaseAddress:   0x0000000000000020
+            NumBlocks: 2
+            BBEntries:
+             - ID:            13
+               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
diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp
index 2b7dee7bf46b953..87feaf456e0439e 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -27,6 +27,7 @@
 #include "llvm/ADT/IndexedMap.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SetOperations.h"
+#include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringSet.h"
 #include "llvm/ADT/Twine.h"
@@ -86,7 +87,6 @@
 #include <cctype>
 #include <cstring>
 #include <optional>
-#include <set>
 #include <system_error>
 #include <unordered_map>
 #include <utility>
@@ -1263,20 +1263,20 @@ static SymbolInfoTy createDummySymbolInfo(const ObjectFile &Obj,
     return SymbolInfoTy(Addr, Name, Type);
 }
 
-static void
-collectBBAddrMapLabels(const std::unordered_map<uint64_t, BBAddrMap> &AddrToBBAddrMap,
-                       uint64_t SectionAddr, uint64_t Start, uint64_t End,
-                       std::unordered_map<uint64_t, std::vector<std::string>> &Labels) {
-  if (AddrToBBAddrMap.empty())
+static void collectBBAddrMapLabels(
+    const std::unordered_map<uint64_t, BBAddrMap::BBRangeEntry> &AddrToBBRange,
+    uint64_t SectionAddr, uint64_t Start, uint64_t End,
+    std::unordered_map<uint64_t, std::vector<std::string>> &Labels) {
+  if (AddrToBBRange.empty())
     return;
   Labels.clear();
   uint64_t StartAddress = SectionAddr + Start;
   uint64_t EndAddress = SectionAddr + End;
-  auto Iter = AddrToBBAddrMap.find(StartAddress);
-  if (Iter == AddrToBBAddrMap.end())
+  auto Iter = AddrToBBRange.find(StartAddress);
+  if (Iter == AddrToBBRange.end())
     return;
-  for (const BBAddrMap::BBEntry &BBEntry : Iter->second.getBBEntries()) {
-    uint64_t BBAddress = BBEntry.Offset + Iter->second.getFunctionAddress();
+  for (const BBAddrMap::BBEntry &BBEntry : Iter->second.BBEntries) {
+    uint64_t BBAddress = BBEntry.Offset + Iter->second.BaseAddress;
     if (BBAddress >= EndAddress)
       continue;
     Labels[BBAddress].push_back(("BB" + Twine(BBEntry.ID)).str());
@@ -1631,19 +1631,21 @@ disassembleObject(ObjectFile &Obj, const ObjectFile &DbgObj,
 
   LLVM_DEBUG(LVP.dump());
 
-  std::unordered_map<uint64_t, BBAddrMap> AddrToBBAddrMap;
+  std::unordered_map<uint64_t, BBAddrMap::BBRangeEntry> AddrToBBRange;
   auto ReadBBAddrMap = [&](std::optional<unsigned> SectionIndex =
                                std::nullopt) {
-    AddrToBBAddrMap.clear();
+    AddrToBBRange.clear();
     if (const auto *Elf = dyn_cast<ELFObjectFileBase>(&Obj)) {
       auto BBAddrMapsOrErr = Elf->readBBAddrMap(SectionIndex);
       if (!BBAddrMapsOrErr) {
         reportWarning(toString(BBAddrMapsOrErr.takeError()), Obj.getFileName());
         return;
       }
-      for (auto &FunctionBBAddrMap : *BBAddrMapsOrErr)
-        AddrToBBAddrMap.emplace(FunctionBBAddrMap.Addr,
-                                std::move(FunctionBBAddrMap));
+      for (auto &FunctionBBAddrMap : *BBAddrMapsOrErr) {
+        for (auto &BBRange : FunctionBBAddrMap.BBRanges) {
+          AddrToBBRange.emplace(BBRange.BaseAddress, std::move(BBRange));
+        }
+      }
     }
   };
 
@@ -1780,19 +1782,19 @@ disassembleObject(ObjectFile &Obj, const ObjectFile &DbgObj,
       // inside functions, for which STT_FUNC would be inaccurate.
       //
       // So here, we spot whether there's any non-data symbol present at all,
-      // and only set the DisassembleAsELFData flag if there isn't. Also, we use
+      // and only set the DisassembleAsData flag if there isn't. Also, we use
       // this distinction to inform the decision of which symbol to print at
       // the head of the section, so that if we're printing code, we print a
       // code-related symbol name to go with it.
-      bool DisassembleAsELFData = false;
+      bool DisassembleAsData = false;
       size_t DisplaySymIndex = SymbolsHere.size() - 1;
       if (Obj.isELF() && !DisassembleAll && Section.isText()) {
-        DisassembleAsELFData = true; // unless we find a code symbol below
+        DisassembleAsData = true; // unless we find a code symbol below
 
         for (size_t i = 0; i < SymbolsHere.size(); ++i) {
           uint8_t SymTy = SymbolsHere[i].Type;
           if (SymTy != ELF::STT_OBJECT && SymTy != ELF::STT_COMMON) {
-            DisassembleAsELFData = false;
+            DisassembleAsData = false;
             DisplaySymIndex = i;
           }
         }
@@ -1943,7 +1945,7 @@ disassembleObject(ObjectFile &Obj, const ObjectFile &DbgObj,
       if (SectionAddr < StartAddress)
         Index = std::max<uint64_t>(Index, StartAddress - SectionAddr);
 
-      if (DisassembleAsELFData) {
+      if (DisassembleAsData) {
         dumpELFData(SectionAddr, Index, End, Bytes);
         Index = End;
         continue;
@@ -1971,7 +1973,7 @@ disassembleObject(ObjectFile &Obj, const ObjectFile &DbgObj,
                                   DT->DisAsm.get(), DT->InstPrinter.get(),
                                   PrimaryTarget.SubtargetInfo.get(),
                                   SectionAddr, Index, End, AllLabels);
-        collectBBAddrMapLabels(AddrToBBAddrMap, SectionAddr, Index, End,
+        collectBBAddrMapLabels(AddrToBBRange, SectionAddr, Index, End,
                                BBAddrMapLabels);
       }
 
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index ab26f1369407bf2..8268a3386740c2f 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -7455,30 +7455,37 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printBBAddrMaps() {
       continue;
     }
     for (const BBAddrMap &AM : *BBAddrMapOrErr) {
-      DictScope D(W, "Function");
-      W.printHex("At", AM.Addr);
+      DictScope FD(W, "Function");
+      if (AM.BBRanges.empty())
+        continue;
+      uint64_t FunctionAddress = AM.getFunctionAddress();
+      W.printHex("At", FunctionAddress);
       SmallVector<uint32_t> FuncSymIndex =
-          this->getSymbolIndexesForFunctionAddress(AM.Addr, FunctionSec);
+          this->getSymbolIndexesForFunctionAddress(FunctionAddress, FunctionSec);
       std::string FuncName = "<?>";
       if (FuncSymIndex.empty())
         this->reportUniqueWarning(
             "could not identify function symbol for address (0x" +
-            Twine::utohexstr(AM.Addr) + ") in " + this->describe(*Sec));
+            Twine::utohexstr(FunctionAddress) + ") in " + this->describe(*Sec));
       else
         FuncName = this->getStaticSymbolName(FuncSymIndex.front());
       W.printString("Name", FuncName);
-
-      ListScope L(W, "BB entries");
-      for (const BBAddrMap::BBEntry &BBE : AM.BBEntries) {
-        DictScope L(W);
-        W.printNumber("ID", BBE.ID);
-        W.printHex("Offset", BBE.Offset);
-        W.printHex("Size", BBE.Size);
-        W.printBoolean("HasReturn", BBE.hasReturn());
-        W.printBoolean("HasTailCall", BBE.hasTailCall());
-        W.printBoolean("IsEHPad", BBE.isEHPad());
-        W.printBoolean("CanFallThrough", BBE.canFallThrough());
-        W.printBoolean("HasIndirectBranch", BBE.hasIndirectBranch());
+      ListScope BBRL(W, "BB Ranges");
+      for (const BBAddrMap::BBRangeEntry &BBR : AM.BBRanges) {
+        DictScope BBRD(W);
+        W.printHex("Base Address", BBR.BaseAddress);
+        ListScope BBEL(W, "BB Entries");
+        for (const BBAddrMap::BBEntry &BBE : BBR.BBEntries) {
+          DictScope BBED(W);
+          W.printNumber("ID", BBE.ID);
+          W.printHex("Offset", BBE.Offset);
+          W.printHex("Size", BBE.Size);
+          W.printBoolean("HasReturn", BBE.hasReturn());
+          W.printBoolean("HasTailCall", BBE.hasTailCall());
+          W.printBoolean("IsEHPad", BBE.isEHPad());
+          W.printBoolean("CanFallThrough", BBE.canFallThrough());
+          W.printBoolean("HasIndirectBranch", BBE.hasIndirectBranch());
+        }
       }
     }
   }
diff --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp
index bec4a10a5d35f2a..bcddad5fb9debad 100644
--- a/llvm/tools/obj2yaml/elf2yaml.cpp
+++ b/llvm/tools/obj2yaml/elf2yaml.cpp
@@ -893,6 +893,7 @@ ELFDumper<ELFT>::dumpBBAddrMapSection(const Elf_Shdr *Shdr) {
   DataExtractor::Cursor Cur(0);
   uint8_t Version = 0;
   uint8_t Feature = 0;
+  uint64_t Address = 0;
   while (Cur && Cur.tell() < Content.size()) {
     if (Shdr->sh_type == ELF::SHT_LLVM_BB_ADDR_MAP) {
       Version = Data.getU8(Cur);
@@ -903,19 +904,39 @@ ELFDumper<ELFT>::dumpBBAddrMapSection(const Elf_Shdr *Shdr) {
                 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;
-    // Read the specified number of BB entries, or until decoding fails.
-    for (uint64_t BlockIndex = 0; Cur && BlockIndex < NumBlocks; ++BlockIndex) {
-      uint32_t ID = Version >= 2 ? Data.getULEB128(Cur) : BlockIndex;
-      uint64_t Offset = Data.getULEB128(Cur);
-      uint64_t Size = Data.getULEB128(Cur);
-      uint64_t Metadata = Data.getULEB128(Cur);
-      BBEntries.push_back({ID, Offset, Size, Metadata});
+    uint64_t NumBBRanges = 1;
+    uint64_t NumBlocks = 0;
+    bool MultiBBRangeFeature = Feature & 0x80;
+    if (MultiBBRangeFeature) {
+      NumBBRanges = Data.getULEB128(Cur);
+    } else {
+      Address = Data.getAddress(Cur);
+      NumBlocks = Data.getULEB128(Cur);
+    }
+    std::vector<ELFYAML::BBAddrMapEntry::BBRangeEntry> BBRanges;
+    uint64_t BaseAddress = 0;
+    for (uint64_t BBRangeN = 0; Cur && BBRangeN != NumBBRanges; ++BBRangeN) {
+      if (MultiBBRangeFeature) {
+        BaseAddress = Data.getAddress(Cur);
+        NumBlocks = Data.getULEB128(Cur);
+      } else {
+        BaseAddress = Address;
+      }
+
+      std::vector<ELFYAML::BBAddrMapEntry::BBEntry> BBEntries;
+      // Read the specified number of BB entries, or until decoding fails.
+      for (uint64_t BlockIndex = 0; Cur && BlockIndex < NumBlocks;
+           ++BlockIndex) {
+        uint32_t ID = Version >= 2 ? Data.getULEB128(Cur) : BlockIndex;
+        uint64_t Offset = Data.getULEB128(Cur);
+        uint64_t Size = Data.getULEB128(Cur);
+        uint64_t Metadata = Data.getULEB128(Cur);
+        BBEntries.push_back({ID, Offset, Size, Metadata});
+      }
+      BBRanges.push_back({BaseAddress, /*NumBlocks=*/{}, BBEntries});
     }
     Entries.push_back(
-        {Version, Feature, Address, /*NumBlocks=*/{}, std::move(BBEntries)});
+        {Version, Feature, /*NumBBRanges=*/{}, std::move(BBRanges)});
   }
 
   if (!Cur) {
diff --git a/llvm/unittests/Object/ELFObjectFileTest.cpp b/llvm/unittests/Object/ELFObjectFileTest.cpp
index 17402f39a5df834..157c69edec42b3d 100644
--- a/llvm/unittests/Object/ELFObjectFileTest.cpp
+++ b/llvm/unittests/Object/ELFObjectFileTest.cpp
@@ -486,7 +486,12 @@ TEST(ELFObjectFileTest, InvalidDecodeBBAddrMap) {
   - Type: SHT_LLVM_BB_ADDR_MAP
     Name: .llvm_bb_addr_map
     Entries:
-      - Address: 0x11111
+      - BBRanges:
+          - BaseAddress: 0x11111
+            BBEntries:
+              - AddressOffset: 0x0
+                Size:          0x1
+                Metadata:      0x2
 )");
 
   auto DoCheck = [&](StringRef YamlString, const char *ErrMsg) {
@@ -507,10 +512,11 @@ TEST(ELFObjectFileTest, InvalidDecodeBBAddrMap) {
   SmallString<128> UnsupportedVersionYamlString(CommonYamlString);
   UnsupportedVersionYamlString += R"(
         Version: 3
-        BBEntries:
-          - AddressOffset: 0x0
-            Size:          0x1
-            Metadata:      0x2
+        BBRanges:
+          -  BBEntries:
+            - AddressOffset: 0x0
+              Size:          0x1
+              Metadata:      0x2
 )";
 
   DoCheck(UnsupportedVersionYamlString,
@@ -519,11 +525,12 @@ TEST(ELFObjectFileTest, InvalidDecodeBBAddrMap) {
   SmallString<128> CommonVersionedYamlString(CommonYamlString);
   CommonVersionedYamlString += R"(
         Version: 2
-        BBEntries:
-          - ID:            1
-            AddressOffset: 0x0
-            Size:          0x1
-            Metadata:      0x2
+        BBRanges:
+          - BBEntries:
+              - ID:            1
+                AddressOffset: 0x0
+                Size:          0x1
+                Metadata:      0x2
 )";
 
   // Check that we can detect the malformed encoding when the section is
@@ -540,24 +547,24 @@ TEST(ELFObjectFileTest, InvalidDecodeBBAddrMap) {
   SmallVector<SmallString<128>, 3> OverInt32LimitYamlStrings(
       3, CommonVersionedYamlString);
   OverInt32LimitYamlStrings[0] += R"(
-          - ID:            1
-            AddressOffset: 0x100000000
-            Size:          0xFFFFFFFF
-            Metadata:      0xFFFFFFFF
+              - ID:            1
+                AddressOffset: 0x100000000
+                Size:          0xFFFFFFFF
+                Metadata:      0xFFFFFFFF
 )";
 
   OverInt32LimitYamlStrings[1] += R"(
-          - ID:            2
-            AddressOffset: 0xFFFFFFFF
-            Size:          0x100000000
-            Metadata:      0xFFFFFFFF
+              - ID:            2
+                AddressOffset: 0xFFFFFFFF
+                Size:          0x100000000
+                Metadata:      0xFFFFFFFF
 )";
 
   OverInt32LimitYamlStrings[2] += R"(
-          - ID:            3
-            AddressOffset: 0xFFFFFFFF
-            Size:          0xFFFFFFFF
-            Metadata:      0x100000000
+              - ID:            3
+                AddressOffset: 0xFFFFFFFF
+                Size:          0xFFFFFFFF
+                Metadata:      0x100000000
 )";
 
   DoCheck(OverInt32LimitYamlStrings[0],
@@ -597,11 +604,20 @@ TEST(ELFObjectFileTest, InvalidDecodeBBAddrMap) {
   // with an out-of-range value.
   SmallString<128> OverLimitNumBlocks(CommonVersionedYamlString);
   OverLimitNumBlocks += R"(
-        NumBlocks: 0x100000000
+            NumBlocks: 0x100000000
 )";
-
   DoCheck(OverLimitNumBlocks,
           "ULEB128 value at offset 0xa exceeds UINT32_MAX (0x100000000)");
+
+  // Check for proper error handling when the 'NumBBRanges' field is overridden
+  // with an out-of-range value.
+  SmallString<128> OverLimitNumBBRanges(CommonVersionedYamlString);
+  OverLimitNumBlocks += R"(
+        NumBBRanges: 0x100000000
+)";
+  DoCheck(OverLimitNumBBRanges,
+          "ULEB128 value at offset 0xa exceeds UINT32_MAX (0x100000000)");
+
 }
 
 // Test for the ELFObjectFile::readBBAddrMap API.
@@ -620,51 +636,61 @@ TEST(ELFObjectFileTest, ReadBBAddrMap) {
     Link: 1
     Entries:
       - Version: 2
-        Address: 0x11111
-        BBEntries:
-          - ID:            1
-            AddressOffset: 0x0
-            Size:          0x1
-            Metadata:      0x2
+        BBRanges:
+          - BaseAddress: 0x11111
+            BBEntries:
+              - ID:            1
+                AddressOffset: 0x0
+                Size:          0x1
+                Metadata:      0x2
   - Name: .llvm_bb_addr_map_2
     Type: SHT_LLVM_BB_ADDR_MAP
     Link: 1
     Entries:
       - Version: 2
-        Address: 0x22222
-        BBEntries:
-          - ID:            2
-            AddressOffset: 0x0
-            Size:          0x2
-            Metadata:      0x4
+        BBRanges:
+          - BaseAddress: 0x22222
+            BBEntries:
+              - ID:            2
+                AddressOffset: 0x0
+                Size:          0x2
+                Metadata:      0x4
+          - BaseAddress: 0xFFFFF
+            BBEntries:
+              - ID:            15
+                AddressOffset: 0xF0
+                Size:          0xF1
+                Metadata:      0x1F
   - Name: .llvm_bb_addr_map_3
     Type: SHT_LLVM_BB_ADDR_MAP
     Link: 2
     Entries:
       - Version: 1
-        Address: 0x33333
-        BBEntries:
-          - ID:            0
-            AddressOffset: 0x0
-            Size:          0x3
-            Metadata:      0x6
+        BBRanges:
+          - BaseAddress: 0x33333
+            BBEntries:
+              - ID:            0
+                AddressOffset: 0x0
+                Size:          0x3
+                Metadata:      0x6
   - Name: .llvm_bb_addr_map_4
     Type: SHT_LLVM_BB_ADDR_MAP_V0
   # Link: 0 (by default, can be overriden)
     Entries:
       - Version: 0
-        Address: 0x44444
-        BBEntries:
-          - ID:            0
-            AddressOffset: 0x0
-            Size:          0x4
-            Metadata:      0x18
+        BBRanges:
+          - BaseAddress: 0x44444
+            BBEntries:
+              - ID:            0
+                AddressOffset: 0x0
+                Size:          0x4
+                Metadata:      0x18
 )");
 
-  BBAddrMap E1(0x11111, {{1, 0x0, 0x1, {false, true, false, false, false}}});
-  BBAddrMap E2(0x22222, {{2, 0x0, 0x2, {false, false, true, false, false}}});
-  BBAddrMap E3(0x33333, {{0, 0x0, 0x3, {false, true, true, false, false}}});
-  BBAddrMap E4(0x44444, {{0, 0x0, 0x4, {false, false, false, true, true}}});
+  BBAddrMap E1 = {{{0x11111, {{1, 0x0, 0x1, {false, true, false, false, false}}}}}};
+  BBAddrMap E2 = {{{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}}}}}};
+  BBAddrMap E4 = {{{0x44444, {{0, 0x0, 0x4, {false, false, false, true, true}}}}}};
 
   std::vector<BBAddrMap> Section0BBAddrMaps = {E4};
   std::vector<BBAddrMap> Section1BBAddrMaps = {E3};



More information about the cfe-commits mailing list