[llvm] [ObjectYAML][NFC] Hoist BBAddrMap yaml2obj encoder into a shared helper (PR #205991)
Haohai Wen via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 16 18:07:19 PDT 2026
https://github.com/HaohaiWen updated https://github.com/llvm/llvm-project/pull/205991
>From 11e2b2d3c70513d7340548eab5283e5bd4351c7b Mon Sep 17 00:00:00 2001
From: Haohai Wen <haohai.wen at intel.com>
Date: Fri, 26 Jun 2026 13:40:22 +0800
Subject: [PATCH 1/3] [ObjectYAML][NFC] Add BBAddrMap Writer interface for
yaml2obj
Add BBAddrMapYAML::Writer, a CRTP interface abstracting the write
primitives for BBAddrMap payload, so the encode logic can be shared
by the ELF and upcoming COFF yaml2obj emitters.
---
.../llvm/ObjectYAML/BBAddrMapYAMLEmitter.h | 58 +++++++++++++++++++
llvm/lib/ObjectYAML/ELFEmitter.cpp | 57 +++++++++++-------
2 files changed, 95 insertions(+), 20 deletions(-)
create mode 100644 llvm/include/llvm/ObjectYAML/BBAddrMapYAMLEmitter.h
diff --git a/llvm/include/llvm/ObjectYAML/BBAddrMapYAMLEmitter.h b/llvm/include/llvm/ObjectYAML/BBAddrMapYAMLEmitter.h
new file mode 100644
index 0000000000000..c9cc4c848e3e2
--- /dev/null
+++ b/llvm/include/llvm/ObjectYAML/BBAddrMapYAMLEmitter.h
@@ -0,0 +1,58 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Shared yaml2obj BBAddrMap writer, in a standalone header so type-only
+/// includers don't pull in its dependencies.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECTYAML_BBADDRMAPYAMLEMITTER_H
+#define LLVM_OBJECTYAML_BBADDRMAPYAMLEMITTER_H
+
+#include "llvm/ADT/bit.h"
+#include "llvm/ObjectYAML/BBAddrMapYAML.h"
+#include <cassert>
+#include <cstdint>
+
+namespace llvm {
+namespace BBAddrMapYAML {
+
+/// CRTP interface for emitting the BBAddrMap payload to a target-specific
+/// writer, so the encode logic can be shared across formats.
+template <typename Derived> class Writer {
+ llvm::endianness Endian;
+ unsigned AddressSize;
+
+ Derived &derived() { return static_cast<Derived &>(*this); }
+
+public:
+ Writer(llvm::endianness Endian, unsigned AddressSize)
+ : Endian(Endian), AddressSize(AddressSize) {
+ assert((AddressSize == 4 || AddressSize == 8) && "invalid address size");
+ }
+
+ template <typename T> void writeInt(T Val) {
+ derived().template emitInt<T>(Val, Endian);
+ }
+
+ // Pointer-sized: 4 or 8 bytes per AddressSize.
+ void writeAddress(uint64_t Val) {
+ if (AddressSize == 8)
+ writeInt<uint64_t>(Val);
+ else
+ writeInt<uint32_t>(static_cast<uint32_t>(Val));
+ }
+
+ void writeULEB128(uint64_t Val) { derived().emitULEB128(Val); }
+};
+
+} // end namespace BBAddrMapYAML
+} // end namespace llvm
+
+#endif // LLVM_OBJECTYAML_BBADDRMAPYAMLEMITTER_H
diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp
index 6dc162356ab40..2e60132995fa1 100644
--- a/llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -18,6 +18,7 @@
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Object/ELFTypes.h"
+#include "llvm/ObjectYAML/BBAddrMapYAMLEmitter.h"
#include "llvm/ObjectYAML/DWARFEmitter.h"
#include "llvm/ObjectYAML/DWARFYAML.h"
#include "llvm/ObjectYAML/ELFYAML.h"
@@ -137,6 +138,21 @@ class ContiguousBlobAccumulator {
}
};
+// BBAddrMap writer backed by CBA, keeping its size-limit checks.
+class ELFWriter : public BBAddrMapYAML::Writer<ELFWriter> {
+ ContiguousBlobAccumulator &CBA;
+
+public:
+ ELFWriter(ContiguousBlobAccumulator &CBA, llvm::endianness Endian,
+ unsigned AddressSize)
+ : Writer(Endian, AddressSize), CBA(CBA) {}
+
+ template <typename T> void emitInt(T Val, llvm::endianness Endian) {
+ CBA.write<T>(Val, Endian);
+ }
+ void emitULEB128(uint64_t Val) { CBA.writeULEB128(Val); }
+};
+
// Used to keep track of section and symbol names, so that in the YAML file
// sections and symbols can be referenced by name instead of by index.
class NameToIdxMap {
@@ -1462,6 +1478,7 @@ void ELFState<ELFT>::writeSectionContent(
PGOAnalyses = &Section.PGOAnalyses.value();
}
+ ELFWriter W(CBA, ELFT::Endianness, sizeof(uintX_t));
uint64_t CurrentOffset = CBA.getOffset();
for (const auto &[Idx, E] : llvm::enumerate(*Section.Entries)) {
// Write version and feature values.
@@ -1469,11 +1486,11 @@ void ELFState<ELFT>::writeSectionContent(
WithColor::warning() << "unsupported BB address map version: "
<< static_cast<int>(E.Version)
<< "; encoding using the most recent version";
- CBA.write(E.Version);
+ W.writeInt<uint8_t>(E.Version);
if (E.Version < 5)
- CBA.write(static_cast<uint8_t>(E.Feature));
+ W.writeInt<uint8_t>(static_cast<uint8_t>(E.Feature));
else
- CBA.write<uint16_t>(E.Feature, ELFT::Endianness);
+ W.writeInt<uint16_t>(E.Feature);
auto FeatureOrErr = llvm::object::BBAddrMap::Features::decode(E.Feature);
if (!FeatureOrErr) {
// Invalid feature: warn and skip the entry.
@@ -1493,7 +1510,7 @@ void ELFState<ELFT>::writeSectionContent(
// 'NumBBRanges' field when specified.
uint64_t NumBBRanges =
E.NumBBRanges.value_or(E.BBRanges ? E.BBRanges->size() : 0);
- CBA.writeULEB128(NumBBRanges);
+ W.writeULEB128(NumBBRanges);
}
if (!E.BBRanges)
continue;
@@ -1502,36 +1519,36 @@ void ELFState<ELFT>::writeSectionContent(
FeatureOrErr->CallsiteEndOffsets || E.hasAnyCallsiteEndOffsets();
for (const BBAddrMapYAML::BBAddrMapEntry::BBRangeEntry &BBR : *E.BBRanges) {
// Write the base address of the range.
- CBA.write<uintX_t>(BBR.BaseAddress, ELFT::Endianness);
+ W.writeAddress(BBR.BaseAddress);
// 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);
- CBA.writeULEB128(NumBlocks);
+ W.writeULEB128(NumBlocks);
// Write all BBEntries in this BBRange.
if (!BBR.BBEntries || FeatureOrErr->OmitBBEntries)
continue;
for (const BBAddrMapYAML::BBAddrMapEntry::BBEntry &BBE : *BBR.BBEntries) {
++TotalNumBlocks;
if (E.Version > 1)
- CBA.writeULEB128(BBE.ID);
- CBA.writeULEB128(BBE.AddressOffset);
+ W.writeULEB128(BBE.ID);
+ W.writeULEB128(BBE.AddressOffset);
if (EmitCallsiteEndOffsets) {
size_t NumCallsiteEndOffsets =
BBE.CallsiteEndOffsets ? BBE.CallsiteEndOffsets->size() : 0;
- CBA.writeULEB128(NumCallsiteEndOffsets);
+ W.writeULEB128(NumCallsiteEndOffsets);
if (BBE.CallsiteEndOffsets) {
for (uint32_t Offset : *BBE.CallsiteEndOffsets)
- CBA.writeULEB128(Offset);
+ W.writeULEB128(Offset);
}
}
- CBA.writeULEB128(BBE.Size);
- CBA.writeULEB128(BBE.Metadata);
+ W.writeULEB128(BBE.Size);
+ W.writeULEB128(BBE.Metadata);
if (FeatureOrErr->BBHash || BBE.Hash.has_value()) {
uint64_t Hash =
BBE.Hash.has_value() ? BBE.Hash.value() : llvm::yaml::Hex64(0);
- CBA.write<uint64_t>(Hash, ELFT::Endianness);
+ W.writeInt<uint64_t>(Hash);
}
}
}
@@ -1540,7 +1557,7 @@ void ELFState<ELFT>::writeSectionContent(
const BBAddrMapYAML::PGOAnalysisMapEntry &PGOEntry = PGOAnalyses->at(Idx);
if (PGOEntry.FuncEntryCount)
- CBA.writeULEB128(*PGOEntry.FuncEntryCount);
+ W.writeULEB128(*PGOEntry.FuncEntryCount);
if (!PGOEntry.PGOBBEntries)
continue;
@@ -1556,16 +1573,16 @@ void ELFState<ELFT>::writeSectionContent(
for (const auto &PGOBBE : PGOBBEntries) {
if (PGOBBE.BBFreq)
- CBA.writeULEB128(*PGOBBE.BBFreq);
+ W.writeULEB128(*PGOBBE.BBFreq);
if (FeatureOrErr->PostLinkCfg || PGOBBE.PostLinkBBFreq.has_value())
- CBA.writeULEB128(PGOBBE.PostLinkBBFreq.value_or(0));
+ W.writeULEB128(PGOBBE.PostLinkBBFreq.value_or(0));
if (PGOBBE.Successors) {
- CBA.writeULEB128(PGOBBE.Successors->size());
+ W.writeULEB128(PGOBBE.Successors->size());
for (const auto &[ID, BrProb, PostLinkBrFreq] : *PGOBBE.Successors) {
- CBA.writeULEB128(ID);
- CBA.writeULEB128(BrProb);
+ W.writeULEB128(ID);
+ W.writeULEB128(BrProb);
if (FeatureOrErr->PostLinkCfg || PostLinkBrFreq.has_value())
- CBA.writeULEB128(PostLinkBrFreq.value_or(0));
+ W.writeULEB128(PostLinkBrFreq.value_or(0));
}
}
}
>From 588a4e0571a51bf5f7aa956f351f5347f8b1cd50 Mon Sep 17 00:00:00 2001
From: Haohai Wen <haohai.wen at intel.com>
Date: Fri, 26 Jun 2026 14:10:24 +0800
Subject: [PATCH 2/3] [ObjectYAML][NFC] Hoist BBAddrMap yaml2obj encoder into a
shared helper
Move the .llvm_bb_addr_map payload encode loop out of
ELFState::writeSectionContent and into BBAddrMapYAML::encodePayload, a
function template over the Writer interface, so the upcoming COFF
emitter can reuse it. The ELF path becomes a thin wrapper: it keeps the
format-specific pre-loop validation and sh_size accounting and forwards
the entries through an ELFWriter.
---
.../llvm/ObjectYAML/BBAddrMapYAMLEmitter.h | 122 ++++++++++++++++++
llvm/lib/ObjectYAML/ELFEmitter.cpp | 108 +---------------
2 files changed, 123 insertions(+), 107 deletions(-)
diff --git a/llvm/include/llvm/ObjectYAML/BBAddrMapYAMLEmitter.h b/llvm/include/llvm/ObjectYAML/BBAddrMapYAMLEmitter.h
index c9cc4c848e3e2..3b23674b67141 100644
--- a/llvm/include/llvm/ObjectYAML/BBAddrMapYAMLEmitter.h
+++ b/llvm/include/llvm/ObjectYAML/BBAddrMapYAMLEmitter.h
@@ -15,10 +15,16 @@
#ifndef LLVM_OBJECTYAML_BBADDRMAPYAMLEMITTER_H
#define LLVM_OBJECTYAML_BBADDRMAPYAMLEMITTER_H
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/bit.h"
+#include "llvm/Object/BBAddrMap.h"
#include "llvm/ObjectYAML/BBAddrMapYAML.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/WithColor.h"
#include <cassert>
#include <cstdint>
+#include <vector>
namespace llvm {
namespace BBAddrMapYAML {
@@ -52,6 +58,122 @@ template <typename Derived> class Writer {
void writeULEB128(uint64_t Val) { derived().emitULEB128(Val); }
};
+/// Encodes the BBAddrMap section body through \p W, walking \p PGOAnalyses
+/// alongside \p Entries when non-null. Warns and continues on malformed YAML,
+/// so yaml2obj can still emit intentionally-broken test objects.
+template <typename Derived>
+void encodePayload(ArrayRef<BBAddrMapEntry> Entries,
+ const std::vector<PGOAnalysisMapEntry> *PGOAnalyses,
+ Writer<Derived> &W) {
+ for (const auto &[Idx, E] : llvm::enumerate(Entries)) {
+ // Write version and feature values.
+ if (E.Version > 5)
+ WithColor::warning() << "unsupported BB address map version: "
+ << static_cast<int>(E.Version)
+ << "; encoding using the most recent version";
+ W.template writeInt<uint8_t>(E.Version);
+ if (E.Version < 5)
+ W.template writeInt<uint8_t>(static_cast<uint8_t>(E.Feature));
+ else
+ W.template writeInt<uint16_t>(E.Feature);
+ auto FeatureOrErr = llvm::object::BBAddrMap::Features::decode(E.Feature);
+ if (!FeatureOrErr) {
+ // Invalid feature: warn and skip the entry.
+ WithColor::warning() << toString(FeatureOrErr.takeError());
+ continue;
+ }
+ bool MultiBBRangeFeatureEnabled = FeatureOrErr->MultiBBRange;
+ bool MultiBBRange =
+ MultiBBRangeFeatureEnabled ||
+ (E.NumBBRanges.has_value() && E.NumBBRanges.value() != 1) ||
+ (E.BBRanges && E.BBRanges->size() != 1);
+ if (MultiBBRange && !MultiBBRangeFeatureEnabled)
+ WithColor::warning() << "feature value(" << E.Feature
+ << ") does not support multiple BB ranges.";
+ if (MultiBBRange) {
+ // Write the number of basic block ranges, which is overridden by the
+ // 'NumBBRanges' field when specified.
+ uint64_t NumBBRanges =
+ E.NumBBRanges.value_or(E.BBRanges ? E.BBRanges->size() : 0);
+ W.writeULEB128(NumBBRanges);
+ }
+ if (!E.BBRanges)
+ continue;
+ uint64_t TotalNumBlocks = 0;
+ bool EmitCallsiteEndOffsets =
+ FeatureOrErr->CallsiteEndOffsets || E.hasAnyCallsiteEndOffsets();
+ for (const BBAddrMapEntry::BBRangeEntry &BBR : *E.BBRanges) {
+ // Write the base address of the range.
+ W.writeAddress(BBR.BaseAddress);
+ // 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);
+ W.writeULEB128(NumBlocks);
+ // Write all BBEntries in this BBRange.
+ if (!BBR.BBEntries || FeatureOrErr->OmitBBEntries)
+ continue;
+ for (const BBAddrMapEntry::BBEntry &BBE : *BBR.BBEntries) {
+ ++TotalNumBlocks;
+ if (E.Version > 1)
+ W.writeULEB128(BBE.ID);
+ W.writeULEB128(BBE.AddressOffset);
+ if (EmitCallsiteEndOffsets) {
+ size_t NumCallsiteEndOffsets =
+ BBE.CallsiteEndOffsets ? BBE.CallsiteEndOffsets->size() : 0;
+ W.writeULEB128(NumCallsiteEndOffsets);
+ if (BBE.CallsiteEndOffsets) {
+ for (uint32_t Offset : *BBE.CallsiteEndOffsets)
+ W.writeULEB128(Offset);
+ }
+ }
+ W.writeULEB128(BBE.Size);
+ W.writeULEB128(BBE.Metadata);
+ if (FeatureOrErr->BBHash || BBE.Hash.has_value()) {
+ uint64_t Hash =
+ BBE.Hash.has_value() ? BBE.Hash.value() : llvm::yaml::Hex64(0);
+ W.template writeInt<uint64_t>(Hash);
+ }
+ }
+ }
+ if (!PGOAnalyses)
+ continue;
+ const PGOAnalysisMapEntry &PGOEntry = PGOAnalyses->at(Idx);
+
+ if (PGOEntry.FuncEntryCount)
+ W.writeULEB128(*PGOEntry.FuncEntryCount);
+
+ if (!PGOEntry.PGOBBEntries)
+ continue;
+
+ const auto &PGOBBEntries = PGOEntry.PGOBBEntries.value();
+ if (TotalNumBlocks != PGOBBEntries.size()) {
+ WithColor::warning() << "PGOBBEntries must be the same length as "
+ "BBEntries in the BB address map.\n"
+ << "Mismatch on function with address: "
+ << E.getFunctionAddress();
+ continue;
+ }
+
+ for (const auto &PGOBBE : PGOBBEntries) {
+ if (PGOBBE.BBFreq)
+ W.writeULEB128(*PGOBBE.BBFreq);
+ if (FeatureOrErr->PostLinkCfg || PGOBBE.PostLinkBBFreq.has_value())
+ W.writeULEB128(PGOBBE.PostLinkBBFreq.value_or(0));
+ if (PGOBBE.Successors) {
+ W.writeULEB128(PGOBBE.Successors->size());
+ for (const auto &[ID, BrProb, PostLinkBrFreq] : *PGOBBE.Successors) {
+ W.writeULEB128(ID);
+ W.writeULEB128(BrProb);
+ if (FeatureOrErr->PostLinkCfg || PostLinkBrFreq.has_value())
+ W.writeULEB128(PostLinkBrFreq.value_or(0));
+ }
+ }
+ }
+ }
+}
+
} // end namespace BBAddrMapYAML
} // end namespace llvm
diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp
index 2e60132995fa1..0fe1d458e5891 100644
--- a/llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -1480,113 +1480,7 @@ void ELFState<ELFT>::writeSectionContent(
ELFWriter W(CBA, ELFT::Endianness, sizeof(uintX_t));
uint64_t CurrentOffset = CBA.getOffset();
- for (const auto &[Idx, E] : llvm::enumerate(*Section.Entries)) {
- // Write version and feature values.
- if (E.Version > 5)
- WithColor::warning() << "unsupported BB address map version: "
- << static_cast<int>(E.Version)
- << "; encoding using the most recent version";
- W.writeInt<uint8_t>(E.Version);
- if (E.Version < 5)
- W.writeInt<uint8_t>(static_cast<uint8_t>(E.Feature));
- else
- W.writeInt<uint16_t>(E.Feature);
- auto FeatureOrErr = llvm::object::BBAddrMap::Features::decode(E.Feature);
- if (!FeatureOrErr) {
- // Invalid feature: warn and skip the entry.
- WithColor::warning() << toString(FeatureOrErr.takeError());
- continue;
- }
- bool MultiBBRangeFeatureEnabled = FeatureOrErr->MultiBBRange;
- bool MultiBBRange =
- MultiBBRangeFeatureEnabled ||
- (E.NumBBRanges.has_value() && E.NumBBRanges.value() != 1) ||
- (E.BBRanges && E.BBRanges->size() != 1);
- if (MultiBBRange && !MultiBBRangeFeatureEnabled)
- WithColor::warning() << "feature value(" << E.Feature
- << ") does not support multiple BB ranges.";
- if (MultiBBRange) {
- // Write the number of basic block ranges, which is overridden by the
- // 'NumBBRanges' field when specified.
- uint64_t NumBBRanges =
- E.NumBBRanges.value_or(E.BBRanges ? E.BBRanges->size() : 0);
- W.writeULEB128(NumBBRanges);
- }
- if (!E.BBRanges)
- continue;
- uint64_t TotalNumBlocks = 0;
- bool EmitCallsiteEndOffsets =
- FeatureOrErr->CallsiteEndOffsets || E.hasAnyCallsiteEndOffsets();
- for (const BBAddrMapYAML::BBAddrMapEntry::BBRangeEntry &BBR : *E.BBRanges) {
- // Write the base address of the range.
- W.writeAddress(BBR.BaseAddress);
- // 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);
- W.writeULEB128(NumBlocks);
- // Write all BBEntries in this BBRange.
- if (!BBR.BBEntries || FeatureOrErr->OmitBBEntries)
- continue;
- for (const BBAddrMapYAML::BBAddrMapEntry::BBEntry &BBE : *BBR.BBEntries) {
- ++TotalNumBlocks;
- if (E.Version > 1)
- W.writeULEB128(BBE.ID);
- W.writeULEB128(BBE.AddressOffset);
- if (EmitCallsiteEndOffsets) {
- size_t NumCallsiteEndOffsets =
- BBE.CallsiteEndOffsets ? BBE.CallsiteEndOffsets->size() : 0;
- W.writeULEB128(NumCallsiteEndOffsets);
- if (BBE.CallsiteEndOffsets) {
- for (uint32_t Offset : *BBE.CallsiteEndOffsets)
- W.writeULEB128(Offset);
- }
- }
- W.writeULEB128(BBE.Size);
- W.writeULEB128(BBE.Metadata);
- if (FeatureOrErr->BBHash || BBE.Hash.has_value()) {
- uint64_t Hash =
- BBE.Hash.has_value() ? BBE.Hash.value() : llvm::yaml::Hex64(0);
- W.writeInt<uint64_t>(Hash);
- }
- }
- }
- if (!PGOAnalyses)
- continue;
- const BBAddrMapYAML::PGOAnalysisMapEntry &PGOEntry = PGOAnalyses->at(Idx);
-
- if (PGOEntry.FuncEntryCount)
- W.writeULEB128(*PGOEntry.FuncEntryCount);
-
- if (!PGOEntry.PGOBBEntries)
- continue;
-
- const auto &PGOBBEntries = PGOEntry.PGOBBEntries.value();
- if (TotalNumBlocks != PGOBBEntries.size()) {
- WithColor::warning() << "PGOBBEntries must be the same length as "
- "BBEntries in the BB address map.\n"
- << "Mismatch on function with address: "
- << E.getFunctionAddress();
- continue;
- }
-
- for (const auto &PGOBBE : PGOBBEntries) {
- if (PGOBBE.BBFreq)
- W.writeULEB128(*PGOBBE.BBFreq);
- if (FeatureOrErr->PostLinkCfg || PGOBBE.PostLinkBBFreq.has_value())
- W.writeULEB128(PGOBBE.PostLinkBBFreq.value_or(0));
- if (PGOBBE.Successors) {
- W.writeULEB128(PGOBBE.Successors->size());
- for (const auto &[ID, BrProb, PostLinkBrFreq] : *PGOBBE.Successors) {
- W.writeULEB128(ID);
- W.writeULEB128(BrProb);
- if (FeatureOrErr->PostLinkCfg || PostLinkBrFreq.has_value())
- W.writeULEB128(PostLinkBrFreq.value_or(0));
- }
- }
- }
- }
+ BBAddrMapYAML::encodePayload(*Section.Entries, PGOAnalyses, W);
SHeader.sh_size += CBA.getOffset() - CurrentOffset;
}
>From d610979865d1fb9f06def865a4eccb492a512775 Mon Sep 17 00:00:00 2001
From: Haohai Wen <haohai.wen at intel.com>
Date: Thu, 16 Jul 2026 13:10:01 +0800
Subject: [PATCH 3/3] [ObjectYAML][NFC] Move BBAddrMap YAML encoding to source
Define the shared BBAddrMap payload encoder in BBAddrMapYAML.cpp
instead of a template header. Keep ELFEmitter using the helper
and remove now-unused includes.
---
llvm/include/llvm/ObjectYAML/BBAddrMapYAML.h | 15 +-
.../llvm/ObjectYAML/BBAddrMapYAMLEmitter.h | 180 ------------------
llvm/lib/ObjectYAML/BBAddrMapYAML.cpp | 124 ++++++++++++
llvm/lib/ObjectYAML/ELFEmitter.cpp | 112 +----------
4 files changed, 138 insertions(+), 293 deletions(-)
delete mode 100644 llvm/include/llvm/ObjectYAML/BBAddrMapYAMLEmitter.h
diff --git a/llvm/include/llvm/ObjectYAML/BBAddrMapYAML.h b/llvm/include/llvm/ObjectYAML/BBAddrMapYAML.h
index dd672b6b82510..78cb99e2df30e 100644
--- a/llvm/include/llvm/ObjectYAML/BBAddrMapYAML.h
+++ b/llvm/include/llvm/ObjectYAML/BBAddrMapYAML.h
@@ -17,11 +17,13 @@
#define LLVM_OBJECTYAML_BBADDRMAPYAML_H
#include "llvm/Support/YAMLTraits.h"
-#include <cstdint>
-#include <optional>
-#include <vector>
namespace llvm {
+
+namespace yaml {
+class ContiguousBlobAccumulator;
+}
+
namespace BBAddrMapYAML {
struct BBAddrMapEntry {
@@ -81,6 +83,13 @@ struct PGOAnalysisMapEntry {
std::optional<std::vector<PGOBBEntry>> PGOBBEntries;
};
+/// Encodes the BBAddrMap payload into \p CBA. \p AddressSize must be 4 or 8.
+/// If non-null, \p PGOAnalyses must have the same length as \p Entries.
+LLVM_ABI void encodePayload(ArrayRef<BBAddrMapEntry> Entries,
+ const std::vector<PGOAnalysisMapEntry> *PGOAnalyses,
+ yaml::ContiguousBlobAccumulator &CBA,
+ llvm::endianness Endian, unsigned AddressSize);
+
} // end namespace BBAddrMapYAML
} // end namespace llvm
diff --git a/llvm/include/llvm/ObjectYAML/BBAddrMapYAMLEmitter.h b/llvm/include/llvm/ObjectYAML/BBAddrMapYAMLEmitter.h
deleted file mode 100644
index 3b23674b67141..0000000000000
--- a/llvm/include/llvm/ObjectYAML/BBAddrMapYAMLEmitter.h
+++ /dev/null
@@ -1,180 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// Shared yaml2obj BBAddrMap writer, in a standalone header so type-only
-/// includers don't pull in its dependencies.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_OBJECTYAML_BBADDRMAPYAMLEMITTER_H
-#define LLVM_OBJECTYAML_BBADDRMAPYAMLEMITTER_H
-
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/bit.h"
-#include "llvm/Object/BBAddrMap.h"
-#include "llvm/ObjectYAML/BBAddrMapYAML.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/WithColor.h"
-#include <cassert>
-#include <cstdint>
-#include <vector>
-
-namespace llvm {
-namespace BBAddrMapYAML {
-
-/// CRTP interface for emitting the BBAddrMap payload to a target-specific
-/// writer, so the encode logic can be shared across formats.
-template <typename Derived> class Writer {
- llvm::endianness Endian;
- unsigned AddressSize;
-
- Derived &derived() { return static_cast<Derived &>(*this); }
-
-public:
- Writer(llvm::endianness Endian, unsigned AddressSize)
- : Endian(Endian), AddressSize(AddressSize) {
- assert((AddressSize == 4 || AddressSize == 8) && "invalid address size");
- }
-
- template <typename T> void writeInt(T Val) {
- derived().template emitInt<T>(Val, Endian);
- }
-
- // Pointer-sized: 4 or 8 bytes per AddressSize.
- void writeAddress(uint64_t Val) {
- if (AddressSize == 8)
- writeInt<uint64_t>(Val);
- else
- writeInt<uint32_t>(static_cast<uint32_t>(Val));
- }
-
- void writeULEB128(uint64_t Val) { derived().emitULEB128(Val); }
-};
-
-/// Encodes the BBAddrMap section body through \p W, walking \p PGOAnalyses
-/// alongside \p Entries when non-null. Warns and continues on malformed YAML,
-/// so yaml2obj can still emit intentionally-broken test objects.
-template <typename Derived>
-void encodePayload(ArrayRef<BBAddrMapEntry> Entries,
- const std::vector<PGOAnalysisMapEntry> *PGOAnalyses,
- Writer<Derived> &W) {
- for (const auto &[Idx, E] : llvm::enumerate(Entries)) {
- // Write version and feature values.
- if (E.Version > 5)
- WithColor::warning() << "unsupported BB address map version: "
- << static_cast<int>(E.Version)
- << "; encoding using the most recent version";
- W.template writeInt<uint8_t>(E.Version);
- if (E.Version < 5)
- W.template writeInt<uint8_t>(static_cast<uint8_t>(E.Feature));
- else
- W.template writeInt<uint16_t>(E.Feature);
- auto FeatureOrErr = llvm::object::BBAddrMap::Features::decode(E.Feature);
- if (!FeatureOrErr) {
- // Invalid feature: warn and skip the entry.
- WithColor::warning() << toString(FeatureOrErr.takeError());
- continue;
- }
- bool MultiBBRangeFeatureEnabled = FeatureOrErr->MultiBBRange;
- bool MultiBBRange =
- MultiBBRangeFeatureEnabled ||
- (E.NumBBRanges.has_value() && E.NumBBRanges.value() != 1) ||
- (E.BBRanges && E.BBRanges->size() != 1);
- if (MultiBBRange && !MultiBBRangeFeatureEnabled)
- WithColor::warning() << "feature value(" << E.Feature
- << ") does not support multiple BB ranges.";
- if (MultiBBRange) {
- // Write the number of basic block ranges, which is overridden by the
- // 'NumBBRanges' field when specified.
- uint64_t NumBBRanges =
- E.NumBBRanges.value_or(E.BBRanges ? E.BBRanges->size() : 0);
- W.writeULEB128(NumBBRanges);
- }
- if (!E.BBRanges)
- continue;
- uint64_t TotalNumBlocks = 0;
- bool EmitCallsiteEndOffsets =
- FeatureOrErr->CallsiteEndOffsets || E.hasAnyCallsiteEndOffsets();
- for (const BBAddrMapEntry::BBRangeEntry &BBR : *E.BBRanges) {
- // Write the base address of the range.
- W.writeAddress(BBR.BaseAddress);
- // 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);
- W.writeULEB128(NumBlocks);
- // Write all BBEntries in this BBRange.
- if (!BBR.BBEntries || FeatureOrErr->OmitBBEntries)
- continue;
- for (const BBAddrMapEntry::BBEntry &BBE : *BBR.BBEntries) {
- ++TotalNumBlocks;
- if (E.Version > 1)
- W.writeULEB128(BBE.ID);
- W.writeULEB128(BBE.AddressOffset);
- if (EmitCallsiteEndOffsets) {
- size_t NumCallsiteEndOffsets =
- BBE.CallsiteEndOffsets ? BBE.CallsiteEndOffsets->size() : 0;
- W.writeULEB128(NumCallsiteEndOffsets);
- if (BBE.CallsiteEndOffsets) {
- for (uint32_t Offset : *BBE.CallsiteEndOffsets)
- W.writeULEB128(Offset);
- }
- }
- W.writeULEB128(BBE.Size);
- W.writeULEB128(BBE.Metadata);
- if (FeatureOrErr->BBHash || BBE.Hash.has_value()) {
- uint64_t Hash =
- BBE.Hash.has_value() ? BBE.Hash.value() : llvm::yaml::Hex64(0);
- W.template writeInt<uint64_t>(Hash);
- }
- }
- }
- if (!PGOAnalyses)
- continue;
- const PGOAnalysisMapEntry &PGOEntry = PGOAnalyses->at(Idx);
-
- if (PGOEntry.FuncEntryCount)
- W.writeULEB128(*PGOEntry.FuncEntryCount);
-
- if (!PGOEntry.PGOBBEntries)
- continue;
-
- const auto &PGOBBEntries = PGOEntry.PGOBBEntries.value();
- if (TotalNumBlocks != PGOBBEntries.size()) {
- WithColor::warning() << "PGOBBEntries must be the same length as "
- "BBEntries in the BB address map.\n"
- << "Mismatch on function with address: "
- << E.getFunctionAddress();
- continue;
- }
-
- for (const auto &PGOBBE : PGOBBEntries) {
- if (PGOBBE.BBFreq)
- W.writeULEB128(*PGOBBE.BBFreq);
- if (FeatureOrErr->PostLinkCfg || PGOBBE.PostLinkBBFreq.has_value())
- W.writeULEB128(PGOBBE.PostLinkBBFreq.value_or(0));
- if (PGOBBE.Successors) {
- W.writeULEB128(PGOBBE.Successors->size());
- for (const auto &[ID, BrProb, PostLinkBrFreq] : *PGOBBE.Successors) {
- W.writeULEB128(ID);
- W.writeULEB128(BrProb);
- if (FeatureOrErr->PostLinkCfg || PostLinkBrFreq.has_value())
- W.writeULEB128(PostLinkBrFreq.value_or(0));
- }
- }
- }
- }
-}
-
-} // end namespace BBAddrMapYAML
-} // end namespace llvm
-
-#endif // LLVM_OBJECTYAML_BBADDRMAPYAMLEMITTER_H
diff --git a/llvm/lib/ObjectYAML/BBAddrMapYAML.cpp b/llvm/lib/ObjectYAML/BBAddrMapYAML.cpp
index fbeda0d7f4ef5..f3dbefbcc6191 100644
--- a/llvm/lib/ObjectYAML/BBAddrMapYAML.cpp
+++ b/llvm/lib/ObjectYAML/BBAddrMapYAML.cpp
@@ -13,6 +13,9 @@
//===----------------------------------------------------------------------===//
#include "llvm/ObjectYAML/BBAddrMapYAML.h"
+#include "llvm/Object/BBAddrMap.h"
+#include "llvm/ObjectYAML/ContiguousBlobAccumulator.h"
+#include "llvm/Support/WithColor.h"
namespace llvm {
namespace yaml {
@@ -70,4 +73,125 @@ void MappingTraits<
}
} // end namespace yaml
+
+namespace BBAddrMapYAML {
+
+void encodePayload(ArrayRef<BBAddrMapEntry> Entries,
+ const std::vector<PGOAnalysisMapEntry> *PGOAnalyses,
+ yaml::ContiguousBlobAccumulator &CBA,
+ llvm::endianness Endian, unsigned AddressSize) {
+ assert((AddressSize == 4 || AddressSize == 8) && "invalid address size");
+ for (const auto &[Idx, E] : llvm::enumerate(Entries)) {
+ // Write version and feature values.
+ if (E.Version > 5)
+ WithColor::warning() << "unsupported BB address map version: "
+ << static_cast<int>(E.Version)
+ << "; encoding using the most recent version";
+ CBA.write(E.Version);
+ if (E.Version < 5)
+ CBA.write(static_cast<uint8_t>(E.Feature));
+ else
+ CBA.write<uint16_t>(E.Feature, Endian);
+ auto FeatureOrErr = llvm::object::BBAddrMap::Features::decode(E.Feature);
+ if (!FeatureOrErr) {
+ // Invalid feature: warn and skip the entry.
+ WithColor::warning() << toString(FeatureOrErr.takeError());
+ continue;
+ }
+ bool MultiBBRangeFeatureEnabled = FeatureOrErr->MultiBBRange;
+ bool MultiBBRange =
+ MultiBBRangeFeatureEnabled ||
+ (E.NumBBRanges.has_value() && E.NumBBRanges.value() != 1) ||
+ (E.BBRanges && E.BBRanges->size() != 1);
+ if (MultiBBRange && !MultiBBRangeFeatureEnabled)
+ WithColor::warning() << "feature value(" << E.Feature
+ << ") does not support multiple BB ranges.";
+ if (MultiBBRange) {
+ // Write the number of basic block ranges, which is overridden by the
+ // 'NumBBRanges' field when specified.
+ uint64_t NumBBRanges =
+ E.NumBBRanges.value_or(E.BBRanges ? E.BBRanges->size() : 0);
+ CBA.writeULEB128(NumBBRanges);
+ }
+ if (!E.BBRanges)
+ continue;
+ uint64_t TotalNumBlocks = 0;
+ bool EmitCallsiteEndOffsets =
+ FeatureOrErr->CallsiteEndOffsets || E.hasAnyCallsiteEndOffsets();
+ for (const BBAddrMapEntry::BBRangeEntry &BBR : *E.BBRanges) {
+ // Write the pointer-sized base address of the range.
+ if (AddressSize == 8)
+ CBA.write<uint64_t>(BBR.BaseAddress, Endian);
+ else
+ CBA.write<uint32_t>(static_cast<uint32_t>(BBR.BaseAddress), Endian);
+ // 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);
+ CBA.writeULEB128(NumBlocks);
+ // Write all BBEntries in this BBRange.
+ if (!BBR.BBEntries || FeatureOrErr->OmitBBEntries)
+ continue;
+ for (const BBAddrMapEntry::BBEntry &BBE : *BBR.BBEntries) {
+ ++TotalNumBlocks;
+ if (E.Version > 1)
+ CBA.writeULEB128(BBE.ID);
+ CBA.writeULEB128(BBE.AddressOffset);
+ if (EmitCallsiteEndOffsets) {
+ size_t NumCallsiteEndOffsets =
+ BBE.CallsiteEndOffsets ? BBE.CallsiteEndOffsets->size() : 0;
+ CBA.writeULEB128(NumCallsiteEndOffsets);
+ if (BBE.CallsiteEndOffsets) {
+ for (uint32_t Offset : *BBE.CallsiteEndOffsets)
+ CBA.writeULEB128(Offset);
+ }
+ }
+ CBA.writeULEB128(BBE.Size);
+ CBA.writeULEB128(BBE.Metadata);
+ if (FeatureOrErr->BBHash || BBE.Hash.has_value()) {
+ uint64_t Hash =
+ BBE.Hash.has_value() ? BBE.Hash.value() : llvm::yaml::Hex64(0);
+ CBA.write<uint64_t>(Hash, Endian);
+ }
+ }
+ }
+ if (!PGOAnalyses)
+ continue;
+ const PGOAnalysisMapEntry &PGOEntry = PGOAnalyses->at(Idx);
+
+ if (PGOEntry.FuncEntryCount)
+ CBA.writeULEB128(*PGOEntry.FuncEntryCount);
+
+ if (!PGOEntry.PGOBBEntries)
+ continue;
+
+ const auto &PGOBBEntries = PGOEntry.PGOBBEntries.value();
+ if (TotalNumBlocks != PGOBBEntries.size()) {
+ WithColor::warning() << "PGOBBEntries must be the same length as "
+ "BBEntries in the BB address map.\n"
+ << "Mismatch on function with address: "
+ << E.getFunctionAddress();
+ continue;
+ }
+
+ for (const auto &PGOBBE : PGOBBEntries) {
+ if (PGOBBE.BBFreq)
+ CBA.writeULEB128(*PGOBBE.BBFreq);
+ if (FeatureOrErr->PostLinkCfg || PGOBBE.PostLinkBBFreq.has_value())
+ CBA.writeULEB128(PGOBBE.PostLinkBBFreq.value_or(0));
+ if (PGOBBE.Successors) {
+ CBA.writeULEB128(PGOBBE.Successors->size());
+ for (const auto &[ID, BrProb, PostLinkBrFreq] : *PGOBBE.Successors) {
+ CBA.writeULEB128(ID);
+ CBA.writeULEB128(BrProb);
+ if (FeatureOrErr->PostLinkCfg || PostLinkBrFreq.has_value())
+ CBA.writeULEB128(PostLinkBrFreq.value_or(0));
+ }
+ }
+ }
+ }
+}
+
+} // end namespace BBAddrMapYAML
} // end namespace llvm
diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp
index 1b40a54088313..8bbecc82b6a18 100644
--- a/llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -23,10 +23,7 @@
#include "llvm/ObjectYAML/DWARFYAML.h"
#include "llvm/ObjectYAML/ELFYAML.h"
#include "llvm/ObjectYAML/yaml2obj.h"
-#include "llvm/Support/EndianStream.h"
-#include "llvm/Support/Errc.h"
#include "llvm/Support/Error.h"
-#include "llvm/Support/LEB128.h"
#include "llvm/Support/WithColor.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
@@ -1362,113 +1359,8 @@ void ELFState<ELFT>::writeSectionContent(
}
uint64_t CurrentOffset = CBA.getOffset();
- for (const auto &[Idx, E] : llvm::enumerate(*Section.Entries)) {
- // Write version and feature values.
- if (E.Version > 5)
- WithColor::warning() << "unsupported BB address map version: "
- << static_cast<int>(E.Version)
- << "; encoding using the most recent version";
- CBA.write(E.Version);
- if (E.Version < 5)
- CBA.write(static_cast<uint8_t>(E.Feature));
- else
- CBA.write<uint16_t>(E.Feature, ELFT::Endianness);
- auto FeatureOrErr = llvm::object::BBAddrMap::Features::decode(E.Feature);
- if (!FeatureOrErr) {
- // Invalid feature: warn and skip the entry.
- WithColor::warning() << toString(FeatureOrErr.takeError());
- continue;
- }
- bool MultiBBRangeFeatureEnabled = FeatureOrErr->MultiBBRange;
- bool MultiBBRange =
- MultiBBRangeFeatureEnabled ||
- (E.NumBBRanges.has_value() && E.NumBBRanges.value() != 1) ||
- (E.BBRanges && E.BBRanges->size() != 1);
- if (MultiBBRange && !MultiBBRangeFeatureEnabled)
- WithColor::warning() << "feature value(" << E.Feature
- << ") does not support multiple BB ranges.";
- if (MultiBBRange) {
- // Write the number of basic block ranges, which is overridden by the
- // 'NumBBRanges' field when specified.
- uint64_t NumBBRanges =
- E.NumBBRanges.value_or(E.BBRanges ? E.BBRanges->size() : 0);
- CBA.writeULEB128(NumBBRanges);
- }
- if (!E.BBRanges)
- continue;
- uint64_t TotalNumBlocks = 0;
- bool EmitCallsiteEndOffsets =
- FeatureOrErr->CallsiteEndOffsets || E.hasAnyCallsiteEndOffsets();
- for (const BBAddrMapYAML::BBAddrMapEntry::BBRangeEntry &BBR : *E.BBRanges) {
- // Write the base address of the range.
- CBA.write<uintX_t>(BBR.BaseAddress, ELFT::Endianness);
- // 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);
- CBA.writeULEB128(NumBlocks);
- // Write all BBEntries in this BBRange.
- if (!BBR.BBEntries || FeatureOrErr->OmitBBEntries)
- continue;
- for (const BBAddrMapYAML::BBAddrMapEntry::BBEntry &BBE : *BBR.BBEntries) {
- ++TotalNumBlocks;
- if (E.Version > 1)
- CBA.writeULEB128(BBE.ID);
- CBA.writeULEB128(BBE.AddressOffset);
- if (EmitCallsiteEndOffsets) {
- size_t NumCallsiteEndOffsets =
- BBE.CallsiteEndOffsets ? BBE.CallsiteEndOffsets->size() : 0;
- CBA.writeULEB128(NumCallsiteEndOffsets);
- if (BBE.CallsiteEndOffsets) {
- for (uint32_t Offset : *BBE.CallsiteEndOffsets)
- CBA.writeULEB128(Offset);
- }
- }
- CBA.writeULEB128(BBE.Size);
- CBA.writeULEB128(BBE.Metadata);
- if (FeatureOrErr->BBHash || BBE.Hash.has_value()) {
- uint64_t Hash =
- BBE.Hash.has_value() ? BBE.Hash.value() : llvm::yaml::Hex64(0);
- CBA.write<uint64_t>(Hash, ELFT::Endianness);
- }
- }
- }
- if (!PGOAnalyses)
- continue;
- const BBAddrMapYAML::PGOAnalysisMapEntry &PGOEntry = PGOAnalyses->at(Idx);
-
- if (PGOEntry.FuncEntryCount)
- CBA.writeULEB128(*PGOEntry.FuncEntryCount);
-
- if (!PGOEntry.PGOBBEntries)
- continue;
-
- const auto &PGOBBEntries = PGOEntry.PGOBBEntries.value();
- if (TotalNumBlocks != PGOBBEntries.size()) {
- WithColor::warning() << "PGOBBEntries must be the same length as "
- "BBEntries in the BB address map.\n"
- << "Mismatch on function with address: "
- << E.getFunctionAddress();
- continue;
- }
-
- for (const auto &PGOBBE : PGOBBEntries) {
- if (PGOBBE.BBFreq)
- CBA.writeULEB128(*PGOBBE.BBFreq);
- if (FeatureOrErr->PostLinkCfg || PGOBBE.PostLinkBBFreq.has_value())
- CBA.writeULEB128(PGOBBE.PostLinkBBFreq.value_or(0));
- if (PGOBBE.Successors) {
- CBA.writeULEB128(PGOBBE.Successors->size());
- for (const auto &[ID, BrProb, PostLinkBrFreq] : *PGOBBE.Successors) {
- CBA.writeULEB128(ID);
- CBA.writeULEB128(BrProb);
- if (FeatureOrErr->PostLinkCfg || PostLinkBrFreq.has_value())
- CBA.writeULEB128(PostLinkBrFreq.value_or(0));
- }
- }
- }
- }
+ BBAddrMapYAML::encodePayload(*Section.Entries, PGOAnalyses, CBA,
+ ELFT::Endianness, sizeof(uintX_t));
SHeader.sh_size += CBA.getOffset() - CurrentOffset;
}
More information about the llvm-commits
mailing list