[llvm] [RFC][BOLT] Add a new parallel DWARF processing(2/2) (PR #197859)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 11 04:49:27 PDT 2026
https://github.com/Thrrreeee updated https://github.com/llvm/llvm-project/pull/197859
>From 484f2c16c37c9c3100aa421852a9cac2647f3060 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Tue, 26 May 2026 12:35:55 +0800
Subject: [PATCH 01/11] [RFC][BOLT] A New Parallel DWARF Processing Approach in
BOLT (2/2)
---
bolt/include/bolt/Core/DIEBuilder.h | 8 +-
bolt/include/bolt/Core/DebugData.h | 26 +-
bolt/include/bolt/Rewrite/DWARFRewriter.h | 60 +-
bolt/lib/Core/DIEBuilder.cpp | 19 +
bolt/lib/Core/DebugData.cpp | 45 +-
bolt/lib/Rewrite/DWARFRewriter.cpp | 692 +++++++++++++-----
...f4-cross-cu-backward-different-abbrev.test | 2 +-
bolt/test/X86/dwarf4-cross-cu-ranges.test | 55 ++
8 files changed, 680 insertions(+), 227 deletions(-)
create mode 100644 bolt/test/X86/dwarf4-cross-cu-ranges.test
diff --git a/bolt/include/bolt/Core/DIEBuilder.h b/bolt/include/bolt/Core/DIEBuilder.h
index 628edfc12fdaf..72404e6816e11 100644
--- a/bolt/include/bolt/Core/DIEBuilder.h
+++ b/bolt/include/bolt/Core/DIEBuilder.h
@@ -341,7 +341,13 @@ class DIEBuilder {
void generateAbbrevs();
void generateUnitAbbrevs(DIE *Die);
void assignAbbrev(DIEAbbrev &Abbrev);
-
+ void syncAbbrevTableFrom(const DIEBuilder &SrcBuilder);
+ /// Set the base offset for CU emission, used by the incremental merge
+ /// pipeline
+ void setUnitOffsetBases(uint64_t Base) {
+ DebugNamesUnitSize = Base;
+ UnitSize = Base;
+ }
/// Finish current DIE construction.
void finish();
diff --git a/bolt/include/bolt/Core/DebugData.h b/bolt/include/bolt/Core/DebugData.h
index faf7bb62c6bee..f1120c17fee9f 100644
--- a/bolt/include/bolt/Core/DebugData.h
+++ b/bolt/include/bolt/Core/DebugData.h
@@ -571,6 +571,13 @@ class DebugLocWriter {
/// Offset of an empty location list.
static constexpr uint32_t EmptyListOffset = 0;
+ /// Returns the current size (in bytes) of the serialized location buffer.
+ uint64_t getLocBufferSize() const { return LocBuffer->size(); }
+
+ /// Applies an additional base offset to all non-empty location list offsets
+ /// recorded for this CU.
+ void applyBase(DIEBuilder &DIEBldr, uint64_t Base);
+
LocWriterKind getKind() const { return Kind; }
static bool classof(const DebugLocWriter *Writer) {
@@ -580,11 +587,6 @@ class DebugLocWriter {
protected:
std::unique_ptr<DebugBufferVector> LocBuffer;
std::unique_ptr<raw_svector_ostream> LocStream;
- /// Current offset in the section (updated as new entries are written).
- /// Starts with 0 here since this only writes part of a full location lists
- /// section. In the final section, for DWARF4, the first 16 bytes are reserved
- /// for an empty list.
- static uint32_t LocSectionOffset;
uint8_t DwarfVersion{4};
LocWriterKind Kind{LocWriterKind::DebugLocWriter};
@@ -600,6 +602,14 @@ class DebugLocWriter {
/// The list of debug info patches to be made once individual
/// location list writers have been filled
VectorLocListDebugInfoPatchType LocListDebugInfoPatches;
+ /// Location list attribute patches pending base-address relocation.
+ struct LocListPatch {
+ DIE *Die;
+ dwarf::Attribute Attr;
+ dwarf::Form Form;
+ };
+ /// Accumulated location list patches awaiting base-address adjustment.
+ std::vector<LocListPatch> LocListPatches;
};
class DebugLoclistWriter : public DebugLocWriter {
@@ -613,11 +623,6 @@ class DebugLoclistWriter : public DebugLocWriter {
if (DwarfVersion >= 5) {
LocBodyBuffer = std::make_unique<DebugBufferVector>();
LocBodyStream = std::make_unique<raw_svector_ostream>(*LocBodyBuffer);
- } else {
- // Writing out empty location list to which all references to empty
- // location lists will point.
- const char Zeroes[16] = {0};
- *LocStream << StringRef(Zeroes, 16);
}
}
@@ -657,7 +662,6 @@ class DebugLoclistWriter : public DebugLocWriter {
std::unique_ptr<raw_svector_ostream> LocBodyStream;
std::vector<uint32_t> RelativeLocListOffsets;
uint32_t NumberOfEntries{0};
- static uint32_t LoclistBaseOffset;
};
/// Abstract interface for classes that apply modifications to a binary string.
diff --git a/bolt/include/bolt/Rewrite/DWARFRewriter.h b/bolt/include/bolt/Rewrite/DWARFRewriter.h
index cab346b5aebc5..87cdca0ab7ad9 100644
--- a/bolt/include/bolt/Rewrite/DWARFRewriter.h
+++ b/bolt/include/bolt/Rewrite/DWARFRewriter.h
@@ -16,6 +16,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/CodeGen/DIE.h"
#include "llvm/MC/MCContext.h"
+#include "llvm/Support/ThreadPool.h"
#include "llvm/Support/ToolOutputFile.h"
#include <cstdint>
#include <memory>
@@ -40,12 +41,31 @@ class DWARFRewriter {
uint64_t TypeHash;
uint64_t TypeDIERelativeOffset;
};
+ struct BucketLocAccumOffset {
+ uint64_t LoclistsOffset = 0;
+ uint64_t LegacyLocOffset = 0;
+ std::vector<uint64_t> LocListCUOrder;
+ };
+ struct BucketLocalWriter {
+ std::unique_ptr<DebugRangeListsSectionWriter> RngListsWriter;
+ std::unique_ptr<DebugRangesSectionWriter> LegacyRangesWriter;
+
+ /// Release whichever writer was initialized.
+ void clear() {
+ if (RngListsWriter)
+ RngListsWriter.reset();
+ if (LegacyRangesWriter)
+ LegacyRangesWriter.reset();
+ }
+ };
private:
BinaryContext &BC;
std::mutex DWARFRewriterMutex;
+ std::unique_ptr<llvm::ThreadPoolInterface> DebugInfoThreadPool;
+
/// Stores and serializes information that will be put into the
/// .debug_ranges DWARF section.
std::unique_ptr<DebugRangesSectionWriter> LegacyRangesSectionWriter;
@@ -86,6 +106,7 @@ class DWARFRewriter {
AddressWritersByCU;
std::mutex LocListDebugInfoPatchesMutex;
+ std::mutex DebugNamesUpdateMutex;
std::unordered_map<DWARFUnit *, uint64_t> LineTablePatchMap;
std::unordered_map<const DWARFUnit *, uint64_t> TypeUnitRelocMap;
@@ -100,6 +121,8 @@ class DWARFRewriter {
/// Used to track last CU offset for GDB Index.
uint32_t CUOffset{0};
+ llvm::ThreadPoolInterface &
+ getOrCreateDebugInfoThreadPool(unsigned ThreadCount);
/// Update debug info for all DIEs in \p Unit.
void updateUnitDebugInfo(DWARFUnit &Unit, DIEBuilder &DIEBldr,
DebugLocWriter &DebugLocWriter,
@@ -118,19 +141,30 @@ class DWARFRewriter {
/// attribute.
void updateDWARFObjectAddressRanges(
DWARFUnit &Unit, DIEBuilder &DIEBldr, DIE &Die,
- uint64_t DebugRangesOffset,
+ uint64_t DebugRangesOffset, DebugAddrWriter &AddressWriter,
std::optional<uint64_t> RangesBase = std::nullopt);
std::unique_ptr<DebugBufferVector>
- makeFinalLocListsSection(DWARFVersion Version);
-
+ makeFinalLocListsSection(DWARFVersion Version, ArrayRef<uint64_t> CUOrder);
+ void createRangeLocListAndAddressWriters();
/// Finalize type sections in the main binary.
CUOffsetMap finalizeTypeSections(DIEBuilder &DIEBlder, DIEStreamer &Streamer,
GDBIndex &GDBIndexSection);
+ /// Finalize str section in the dwo
+ void finalizeSkeletonAndStrSection(
+ DIEBuilder &PartDIEBlder, DWARFUnit &CU,
+ const std::unordered_map<uint64_t, std::string> &DWOToNameMap);
+
+ /// Merge Bucket locs section and ranges section result
+ void mergePerBucketLocsAndRanges(
+ DIEBuilder &PartDIEBlder, BucketLocalWriter &LocalWriters,
+ const std::unordered_map<uint64_t, std::string> &DWOToNameMap,
+ BucketLocAccumOffset &Accum);
+
/// Process and write out CUs that are passed in.
- void finalizeCompileUnits(DIEBuilder &DIEBlder, DIEStreamer &Streamer,
- CUOffsetMap &CUMap,
+ void finalizeCompileUnits(DIEBuilder &DIEBlder, DIEBuilder &MainDIEBlder,
+ DIEStreamer &Streamer, CUOffsetMap &CUMap,
const std::list<DWARFUnit *> &CUs,
DebugAddrWriter &FinalAddrWriter);
@@ -139,7 +173,19 @@ class DWARFRewriter {
DWARF5AcceleratorTable &DebugNamesTable,
DIEStreamer &Streamer, raw_svector_ostream &ObjOS,
CUOffsetMap &CUMap,
- DebugAddrWriter &FinalAddrWriter);
+ DebugAddrWriter &FinalAddrWriter,
+ std::vector<uint64_t> SortedCU);
+
+ /// Process CUs in main binary.
+ void processMainBinaryCU(DWARFUnit &Unit, DIEBuilder &DIEBlder,
+ BucketLocalWriter &LocalWriter);
+
+ void processBucket(size_t Idx, std::vector<std::vector<DWARFUnit *>> &PartVec,
+ std::vector<std::unique_ptr<DIEBuilder>> &BucketDIEBlders,
+ std::vector<BucketLocalWriter> &LocalWriters,
+ DWARF5AcceleratorTable &DebugNamesTable,
+ std::unordered_map<uint64_t, std::string> &DWOToNameMap,
+ GDBIndex &GDBIndexSection);
/// Patches the binary for DWARF address ranges (e.g. in functions and lexical
/// blocks) to be updated.
@@ -168,7 +214,7 @@ class DWARFRewriter {
void convertToRangesPatchDebugInfo(
DWARFUnit &Unit, DIEBuilder &DIEBldr, DIE &Die,
uint64_t RangesSectionOffset, DIEValue &LowPCAttrInfo,
- DIEValue &HighPCAttrInfo,
+ DIEValue &HighPCAttrInfo, DebugAddrWriter &AddressWriter,
std::optional<uint64_t> RangesBase = std::nullopt);
public:
diff --git a/bolt/lib/Core/DIEBuilder.cpp b/bolt/lib/Core/DIEBuilder.cpp
index 0957071cb117f..4a2b668236a9f 100644
--- a/bolt/lib/Core/DIEBuilder.cpp
+++ b/bolt/lib/Core/DIEBuilder.cpp
@@ -1040,6 +1040,25 @@ void DIEBuilder::generateUnitAbbrevs(DIE *Die) {
}
}
+void DIEBuilder::syncAbbrevTableFrom(const DIEBuilder &SrcBuilder) {
+ Abbreviations.clear();
+ AbbreviationsSet.clear();
+ Abbreviations.reserve(SrcBuilder.Abbreviations.size());
+ for (const auto &SrcAbbrev : SrcBuilder.Abbreviations) {
+ auto Copy = std::make_unique<DIEAbbrev>(SrcAbbrev->getTag(),
+ SrcAbbrev->hasChildren());
+ for (const auto &Attr : SrcAbbrev->getData())
+ Copy->AddAttribute(Attr.getAttribute(), Attr.getForm());
+ Copy->setNumber(SrcAbbrev->getNumber());
+ FoldingSetNodeID ID;
+ Copy->Profile(ID);
+ void *InsertToken;
+ if (!AbbreviationsSet.FindNodeOrInsertPos(ID, InsertToken))
+ AbbreviationsSet.InsertNode(Copy.get(), InsertToken);
+ Abbreviations.push_back(std::move(Copy));
+ }
+}
+
static uint64_t getHash(const DWARFUnit &DU) {
// Before DWARF5 TU units are in their own section, so at least one offset,
// first one, will be the same as CUs in .debug_info.dwo section
diff --git a/bolt/lib/Core/DebugData.cpp b/bolt/lib/Core/DebugData.cpp
index 971720c918687..db51343908717 100644
--- a/bolt/lib/Core/DebugData.cpp
+++ b/bolt/lib/Core/DebugData.cpp
@@ -564,14 +564,12 @@ void DebugLocWriter::init() {
LocStream = std::make_unique<raw_svector_ostream>(*LocBuffer);
// Writing out empty location list to which all references to empty location
// lists will point.
- if (!LocSectionOffset && DwarfVersion < 5) {
+ if (DwarfVersion < 5) {
const char Zeroes[16] = {0};
*LocStream << StringRef(Zeroes, 16);
- LocSectionOffset += 16;
}
}
-uint32_t DebugLocWriter::LocSectionOffset = 0;
void DebugLocWriter::addList(DIEBuilder &DIEBldr, DIE &Die, DIEValue &AttrInfo,
DebugLocationsVector &LocList) {
if (LocList.empty()) {
@@ -581,7 +579,7 @@ void DebugLocWriter::addList(DIEBuilder &DIEBldr, DIE &Die, DIEValue &AttrInfo,
}
// Since there is a separate DebugLocWriter for each thread,
// we don't need a lock to read the SectionOffset and update it.
- const uint32_t EntryOffset = LocSectionOffset;
+ const uint32_t EntryOffset = LocBuffer->size();
for (const DebugLocationEntry &Entry : LocList) {
support::endian::write(*LocStream, static_cast<uint64_t>(Entry.LowPC),
@@ -592,13 +590,11 @@ void DebugLocWriter::addList(DIEBuilder &DIEBldr, DIE &Die, DIEValue &AttrInfo,
llvm::endianness::little);
*LocStream << StringRef(reinterpret_cast<const char *>(Entry.Expr.data()),
Entry.Expr.size());
- LocSectionOffset += 2 * 8 + 2 + Entry.Expr.size();
}
LocStream->write_zeros(16);
- LocSectionOffset += 16;
- LocListDebugInfoPatches.push_back({0xdeadbeee, EntryOffset}); // never seen
- // use
+ LocListDebugInfoPatches.push_back({0xdeadbeee, EntryOffset});
replaceLocValbyForm(DIEBldr, Die, AttrInfo, AttrInfo.getForm(), EntryOffset);
+ LocListPatches.push_back({&Die, AttrInfo.getAttribute(), AttrInfo.getForm()});
}
std::unique_ptr<DebugBufferVector> DebugLocWriter::getBuffer() {
@@ -608,6 +604,27 @@ std::unique_ptr<DebugBufferVector> DebugLocWriter::getBuffer() {
// DWARF 4: 2.6.2
void DebugLocWriter::finalize(DIEBuilder &DIEBldr, DIE &Die) {}
+/// Rebases all pending location list offsets by adding \p Base,
+/// updating the corresponding attributes in each patched DIE.
+void DebugLocWriter::applyBase(DIEBuilder &DIEBldr, uint64_t Base) {
+ if (Base == 0) {
+ LocListPatches.clear();
+ return;
+ }
+ for (const LocListPatch &LP : LocListPatches) {
+ if (!LP.Die)
+ continue;
+ DIEValue Cur = LP.Die->findAttribute(LP.Attr);
+ if (!Cur.getType())
+ continue;
+ uint64_t OldVal = Cur.getDIEInteger().getValue();
+ if (OldVal == DebugLocWriter::EmptyListOffset)
+ continue;
+ DIEBldr.replaceValue(LP.Die, LP.Attr, LP.Form, DIEInteger(OldVal + Base));
+ }
+ LocListPatches.clear();
+}
+
static void writeEmptyListDwarf5(raw_svector_ostream &Stream) {
support::endian::write(Stream, static_cast<uint32_t>(4),
llvm::endianness::little);
@@ -716,7 +733,6 @@ void DebugLoclistWriter::addList(DIEBuilder &DIEBldr, DIE &Die,
*LocBodyStream);
}
-uint32_t DebugLoclistWriter::LoclistBaseOffset = 0;
void DebugLoclistWriter::finalizeDWARF5(DIEBuilder &DIEBldr, DIE &Die) {
if (LocBodyBuffer->empty()) {
DIEValue LocListBaseAttrInfo =
@@ -751,18 +767,17 @@ void DebugLoclistWriter::finalizeDWARF5(DIEBuilder &DIEBldr, DIE &Die) {
*LocStream << *LocBodyBuffer;
if (!isSplitDwarf()) {
+ const uint64_t LocalBase = getDWARF5RngListLocListHeaderSize();
DIEValue LocListBaseAttrInfo =
Die.findAttribute(dwarf::DW_AT_loclists_base);
if (LocListBaseAttrInfo.getType()) {
- DIEBldr.replaceValue(
- &Die, dwarf::DW_AT_loclists_base, LocListBaseAttrInfo.getForm(),
- DIEInteger(LoclistBaseOffset + getDWARF5RngListLocListHeaderSize()));
+ DIEBldr.replaceValue(&Die, dwarf::DW_AT_loclists_base,
+ LocListBaseAttrInfo.getForm(),
+ DIEInteger(LocalBase));
} else {
DIEBldr.addValue(&Die, dwarf::DW_AT_loclists_base,
- dwarf::DW_FORM_sec_offset,
- DIEInteger(LoclistBaseOffset + Header->size()));
+ dwarf::DW_FORM_sec_offset, DIEInteger(LocalBase));
}
- LoclistBaseOffset += LocBuffer->size();
}
clearList(RelativeLocListOffsets);
clearList(*LocArrayBuffer);
diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp
index 076d2e3d29cce..1b8327b624444 100644
--- a/bolt/lib/Rewrite/DWARFRewriter.cpp
+++ b/bolt/lib/Rewrite/DWARFRewriter.cpp
@@ -14,6 +14,8 @@
#include "bolt/Core/DynoStats.h"
#include "bolt/Core/ParallelUtilities.h"
#include "bolt/Rewrite/RewriteInstance.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/EquivalenceClasses.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
@@ -44,11 +46,17 @@
#include "llvm/Support/ThreadPool.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
+#include <cassert>
+#include <condition_variable>
+#include <cstddef>
#include <cstdint>
#include <functional>
#include <iterator>
+#include <limits>
#include <memory>
+#include <mutex>
#include <optional>
+#include <queue>
#include <string>
#include <unordered_map>
#include <utility>
@@ -91,6 +99,19 @@ static void printDie(DWARFUnit &DU, uint64_t DIEOffset) {
using namespace bolt;
+llvm::ThreadPoolInterface &
+DWARFRewriter::getOrCreateDebugInfoThreadPool(unsigned ThreadsCount) {
+ if (opts::NoThreads || ThreadsCount == 0)
+ ThreadsCount = 1;
+
+ if (DebugInfoThreadPool)
+ return *DebugInfoThreadPool;
+
+ DebugInfoThreadPool = std::make_unique<DefaultThreadPool>(
+ llvm::hardware_concurrency(ThreadsCount));
+ return *DebugInfoThreadPool;
+}
+
/// Take a set of DWARF address ranges corresponding to the input binary and
/// translate them to a set of address ranges in the output binary.
static DebugAddressRangesVector
@@ -332,9 +353,14 @@ static cl::opt<bool> KeepARanges(
static cl::opt<unsigned>
DebugThreadCount("debug-thread-count",
cl::desc("specifies thread count for the multithreading "
- "for updating DWO debug info"),
+ "for updating DWARF debug info"),
cl::init(1), cl::cat(BoltCategory));
+static cl::opt<bool>
+ PreserveOrder("dwarf-preserve-order",
+ cl::desc("Update debug information in deterministic order"),
+ cl::init(true), cl::cat(BoltCategory));
+
static cl::opt<std::string> DwarfOutputPath(
"dwarf-output-path",
cl::desc("Path to where .dwo files will be written out to."), cl::init(""),
@@ -429,6 +455,45 @@ static bool getLowAndHighPC(const DIE &Die, const DWARFUnit &DU,
return false;
}
+static void fixupDWARFRanges(DIEBuilder &DIEBlder, DWARFUnit &Unit,
+ uint64_t Offset) {
+ if (Offset == 0)
+ return;
+
+ const uint16_t Version = Unit.getVersion();
+ if (Version >= 5) {
+ DIE *CUDie = DIEBlder.getUnitDIEbyUnit(Unit);
+ DIEValue RngBaseVal = CUDie->findAttribute(dwarf::DW_AT_rnglists_base);
+ if (RngBaseVal) {
+ uint64_t OldVal = RngBaseVal.getDIEInteger().getValue();
+ DIEBlder.replaceValue(CUDie, dwarf::DW_AT_rnglists_base,
+ RngBaseVal.getForm(), DIEInteger(OldVal + Offset));
+ }
+ }
+
+ const auto &DIs = DIEBlder.getDIEsByUnit(Unit);
+ for (const auto &DI : DIs) {
+ DIE *Die = DI->Die;
+ DIEValue RangesVal = Die->findAttribute(dwarf::DW_AT_ranges);
+ if (RangesVal &&
+ (Version < 5 || RangesVal.getForm() == dwarf::DW_FORM_sec_offset)) {
+ uint64_t OldVal = RangesVal.getDIEInteger().getValue();
+ DIEBlder.replaceValue(Die, dwarf::DW_AT_ranges, RangesVal.getForm(),
+ DIEInteger(OldVal + Offset));
+ }
+
+ if (Version < 5) {
+ DIEValue GnuBaseVal = Die->findAttribute(dwarf::DW_AT_GNU_ranges_base);
+ if (GnuBaseVal) {
+ uint64_t OldVal = GnuBaseVal.getDIEInteger().getValue();
+ DIEBlder.replaceValue(Die, dwarf::DW_AT_GNU_ranges_base,
+ GnuBaseVal.getForm(),
+ DIEInteger(OldVal + Offset));
+ }
+ }
+ }
+}
+
static Expected<llvm::DWARFAddressRangesVector>
getDIEAddressRanges(const DIE &Die, DWARFUnit &DU) {
uint64_t LowPC, HighPC, Index;
@@ -535,43 +600,92 @@ static void emitDWOBuilder(const std::string &DWOName,
StrOffstsWriter, StrWriter, TempRangesSectionWriter);
}
-using DWARFUnitVec = std::vector<DWARFUnit *>;
-using CUPartitionVector = std::vector<DWARFUnitVec>;
-/// Partitions CUs in to buckets. Bucket size is controlled by
-/// cu-processing-batch-size. All the CUs that have cross CU reference reference
-/// as a source are put in to the same initial bucket.
-static CUPartitionVector partitionCUs(DWARFContext &DwCtx) {
- CUPartitionVector Vec(2);
- unsigned Counter = 0;
- const DWARFDebugAbbrev *Abbr = DwCtx.getDebugAbbrev();
- for (std::unique_ptr<DWARFUnit> &CU : DwCtx.compile_units()) {
- Expected<const DWARFAbbreviationDeclarationSet *> AbbrDeclSet =
- Abbr->getAbbreviationDeclarationSet(CU->getAbbreviationsOffset());
- if (!AbbrDeclSet) {
- consumeError(AbbrDeclSet.takeError());
- return Vec;
- }
- bool CrossCURefFound = false;
- for (const DWARFAbbreviationDeclaration &Decl : *AbbrDeclSet.get()) {
- for (const DWARFAbbreviationDeclaration::AttributeSpec &Attr :
- Decl.attributes()) {
- if (Attr.Form == dwarf::DW_FORM_ref_addr) {
- CrossCURefFound = true;
+static std::vector<std::vector<DWARFUnit *>> partitionCUs(DWARFContext &DwCtx) {
+ SmallVector<DWARFUnit *, 0> AllCUs;
+ for (auto &CU : DwCtx.compile_units())
+ AllCUs.push_back(CU.get());
+ if (AllCUs.empty())
+ return {};
+ auto FindCuForOffset = [&](uint64_t Offset) -> DWARFUnit * {
+ auto *It =
+ llvm::upper_bound(AllCUs, Offset, [](uint64_t Off, DWARFUnit *U) {
+ return Off < U->getOffset();
+ });
+ if (It == AllCUs.begin())
+ return nullptr;
+ DWARFUnit *TargetCU = *--It;
+ // Ensure offset falls within TargetCU's range.
+ if (Offset >= TargetCU->getNextUnitOffset())
+ return nullptr;
+ return TargetCU;
+ };
+
+ DenseSet<DWARFUnit *> CrossRefSet;
+ EquivalenceClasses<DWARFUnit *> EC;
+ for (DWARFUnit *CU : AllCUs) {
+ const DWARFAbbreviationDeclarationSet *AbbrevSet = CU->getAbbreviations();
+ if (!AbbrevSet)
+ continue;
+ SmallDenseSet<const DWARFAbbreviationDeclaration *, 4> RefAddrAbbrevs;
+ for (const auto &Decl : *AbbrevSet)
+ for (const auto &Spec : Decl.attributes())
+ if (Spec.Form == dwarf::DW_FORM_ref_addr) {
+ RefAddrAbbrevs.insert(&Decl);
break;
}
+ if (RefAddrAbbrevs.empty())
+ continue;
+ // Track CUs involved in cross-CU references via DW_FORM_ref_addr.
+ for (const DWARFDebugInfoEntry &Entry : CU->dies()) {
+ DWARFDie Die(CU, &Entry);
+ const DWARFAbbreviationDeclaration *Abbrev =
+ Die.getAbbreviationDeclarationPtr();
+ if (!Abbrev || !RefAddrAbbrevs.count(Abbrev))
+ continue;
+ for (const DWARFAttribute &Attr : Die.attributes()) {
+ if (Attr.Value.getForm() != dwarf::DW_FORM_ref_addr)
+ continue;
+ auto OptRef = Attr.Value.getAsDebugInfoReference();
+ if (!OptRef)
+ continue;
+ DWARFUnit *TargetCU = FindCuForOffset(*OptRef);
+ if (!TargetCU)
+ continue;
+ if (CrossRefSet.insert(CU).second)
+ EC.insert(CU);
+ if (CrossRefSet.insert(TargetCU).second)
+ EC.insert(TargetCU);
+ EC.unionSets(CU, TargetCU);
}
- if (CrossCURefFound)
- break;
}
- if (CrossCURefFound) {
- Vec[0].push_back(CU.get());
- } else {
- ++Counter;
- Vec.back().push_back(CU.get());
+ }
+
+ DenseMap<DWARFUnit *, std::vector<DWARFUnit *>> MembersByLeader;
+ for (DWARFUnit *CU : AllCUs) {
+ if (!CrossRefSet.count(CU))
+ continue;
+ MembersByLeader[EC.getLeaderValue(CU)].push_back(CU);
+ }
+
+ std::vector<DWARFUnit *> Leaders;
+ Leaders.reserve(MembersByLeader.size());
+ for (auto &[Leader, Members] : MembersByLeader)
+ Leaders.push_back(Leader);
+ llvm::sort(Leaders, [&](DWARFUnit *A, DWARFUnit *B) {
+ return MembersByLeader[A].front()->getOffset() <
+ MembersByLeader[B].front()->getOffset();
+ });
+
+ // Emit cross-ref buckets, then singleton non-cross-ref CUs.
+ std::vector<std::vector<DWARFUnit *>> Vec;
+ for (DWARFUnit *Leader : Leaders)
+ Vec.push_back(std::move(MembersByLeader[Leader]));
+ for (DWARFUnit *CU : AllCUs) {
+ if (!CrossRefSet.count(CU)) {
+ Vec.push_back({CU});
}
- if (Counter % opts::BatchSize == 0 && !Vec.back().empty())
- Vec.push_back({});
}
+
return Vec;
}
@@ -610,45 +724,137 @@ getDWONameMap(DWARFContext &DwCtx) {
}
return DWOIDToNameMap;
}
-void DWARFRewriter::updateDebugInfo() {
- ErrorOr<BinarySection &> DebugInfo = BC.getUniqueSectionByName(".debug_info");
- if (!DebugInfo)
+
+void DWARFRewriter::finalizeSkeletonAndStrSection(
+ DIEBuilder &PartDIEBlder, DWARFUnit &CU,
+ const std::unordered_map<uint64_t, std::string> &DWOToNameMap) {
+ const std::optional<uint64_t> DWOId = CU.getDWOId();
+ std::optional<DWARFUnit *> DWOCU = DWOId ? BC.getDWOCU(*DWOId) : std::nullopt;
+ const bool HasSplitCU = DWOCU && *DWOCU != nullptr;
+ const unsigned Version = CU.getVersion();
+
+ if (HasSplitCU) {
+ auto It = DWOToNameMap.find(*DWOId);
+ if (It != DWOToNameMap.end()) {
+ PartDIEBlder.updateDWONameCompDir(*StrOffstsWriter, *StrWriter, CU,
+ opts::DwarfOutputPath,
+ StringRef(It->second));
+ if (Version >= 5 && StrOffstsWriter->isStrOffsetsSectionModified())
+ StrOffstsWriter->finalizeSection(CU, PartDIEBlder);
+ }
+ // split CU were just finalized above when the
+ // .debug_str_offsets section was modified;
return;
+ }
- ARangesSectionWriter = std::make_unique<DebugARangesSectionWriter>();
- StrWriter = std::make_unique<DebugStrWriter>(*BC.DwCtx, false);
- StrOffstsWriter = std::make_unique<DebugStrOffsetsWriter>(BC);
+ if (Version >= 5)
+ StrOffstsWriter->finalizeSection(CU, PartDIEBlder);
+}
- /// Stores and serializes information that will be put into the
- /// .debug_addr DWARF section.
- std::unique_ptr<DebugAddrWriter> FinalAddrWriter;
+/// Merge: compute per-CU loclist/legacy-loc bases and in the
+/// same loop apply DWARF5 rnglists/loclists base fixups and legacy
+/// .debug_loc base fixups.
+void DWARFRewriter::mergePerBucketLocsAndRanges(
+ DIEBuilder &PartDIEBlder, BucketLocalWriter &LocalWriters,
+ const std::unordered_map<uint64_t, std::string> &DWOToNameMap,
+ BucketLocAccumOffset &Accum) {
+ const auto &Processed = PartDIEBlder.getProcessedCUs();
+ std::vector<DWARFUnit *> SortedCUs;
+ SortedCUs.assign(Processed.begin(), Processed.end());
+ // Ensure deterministic output by sorting CUs in section offset order.
+ llvm::sort(SortedCUs, [](const DWARFUnit *A, const DWARFUnit *B) {
+ return A->getOffset() < B->getOffset();
+ });
+
+ for (DWARFUnit *CU : SortedCUs) {
+ // record CUs order to make loc/loclist order correct
+ Accum.LocListCUOrder.push_back(CU->getOffset());
+ finalizeSkeletonAndStrSection(PartDIEBlder, *CU, DWOToNameMap);
+ }
+ for (DWARFUnit *CU : SortedCUs) {
+
+ const uint64_t CUOffset = CU->getOffset();
+ // Compute this CU's base and adjust loclists / legacy loc fixups inline.
+ uint64_t LoclistsBase = 0;
+ uint64_t LegacyLocBase = 0;
+
+ auto LocIt = LocListWritersByCU.find(CUOffset);
+ if (LocIt != LocListWritersByCU.end()) {
+ DebugLocWriter *LocWriter = LocIt->second.get();
+ auto *LocListWriter = dyn_cast<DebugLoclistWriter>(LocWriter);
+ const uint64_t BufferSize = LocWriter->getLocBufferSize();
+
+ if (LocListWriter && LocListWriter->getDwarfVersion() >= 5 &&
+ !LocListWriter->isSplitDwarf() && BufferSize != 0) {
+ LoclistsBase = Accum.LoclistsOffset;
+ Accum.LoclistsOffset += BufferSize;
+ } else if (!LocListWriter) {
+ LegacyLocBase = Accum.LegacyLocOffset;
+ // DWARF4 .debug_loc buffers carry a trailing 16-byte terminator
+ // which is written only once at the global level; discount it here
+ // so the next CU's base offset is computed correctly.
+ if (BufferSize > 16)
+ Accum.LegacyLocOffset += BufferSize - 16;
+ }
+ }
- if (BC.isDWARF5Used()) {
- FinalAddrWriter = std::make_unique<DebugAddrWriterDwarf5>(&BC);
- RangeListsSectionWriter = std::make_unique<DebugRangeListsSectionWriter>();
- } else {
- FinalAddrWriter = std::make_unique<DebugAddrWriter>(&BC);
+ if (CU->getVersion() >= 5) {
+ uint64_t RangsOffset = RangeListsSectionWriter->getSectionOffset();
+ fixupDWARFRanges(PartDIEBlder, *CU, RangsOffset);
+
+ if (LoclistsBase) {
+ DIE *UnitDIE = PartDIEBlder.getUnitDIEbyUnit(*CU);
+ if (UnitDIE) {
+ DIEValue LocBase = UnitDIE->findAttribute(dwarf::DW_AT_loclists_base);
+ if (LocBase.getType()) {
+ const uint64_t OldVal = LocBase.getDIEInteger().getValue();
+ PartDIEBlder.replaceValue(UnitDIE, dwarf::DW_AT_loclists_base,
+ LocBase.getForm(),
+ DIEInteger(OldVal + LoclistsBase));
+ }
+ }
+ }
+ continue;
+ }
+
+ if (LegacyLocBase && LocIt != LocListWritersByCU.end())
+ LocIt->second->applyBase(PartDIEBlder, LegacyLocBase);
}
- if (BC.isDWARFLegacyUsed()) {
- LegacyRangesSectionWriter = std::make_unique<DebugRangesSectionWriter>();
- LegacyRangesSectionWriter->initSection();
+ /// Append this bucket's .debug_rnglists and .debug_ranges local buffers to
+ /// the global writers.
+ if (LocalWriters.RngListsWriter && RangeListsSectionWriter) {
+ std::unique_ptr<DebugBufferVector> LocalBuf =
+ LocalWriters.RngListsWriter->releaseBuffer();
+ RangeListsSectionWriter->appendToRangeBuffer(*LocalBuf);
}
- uint32_t CUIndex = 0;
- std::mutex AccessMutex;
- // Needs to be invoked in the same order as CUs are processed.
- llvm::DenseMap<uint64_t, uint64_t> LocListWritersIndexByCU;
- auto createRangeLocListAddressWriters = [&](DWARFUnit &CU) {
- std::lock_guard<std::mutex> Lock(AccessMutex);
+ if (!LocalWriters.LegacyRangesWriter || !LegacyRangesSectionWriter)
+ return;
+
+ std::unique_ptr<DebugBufferVector> LegacyBuf =
+ LocalWriters.LegacyRangesWriter->releaseBuffer();
+ // emission order is established later by emitBucketCompileUnits
+ for (DWARFUnit *CU : SortedCUs)
+ if (CU->getVersion() <= 4)
+ fixupDWARFRanges(PartDIEBlder, *CU,
+ LegacyRangesSectionWriter->getSectionOffset());
+ LegacyRangesSectionWriter->appendToRangeBuffer(*LegacyBuf);
+}
+
+void DWARFRewriter::createRangeLocListAndAddressWriters() {
+ for (auto &DWCU : BC.DwCtx->compile_units()) {
+ DWARFUnit &CU = *DWCU;
+ if (LocListWritersByCU.count(CU.getOffset()))
+ continue;
+
const uint16_t DwarfVersion = CU.getVersion();
if (DwarfVersion >= 5) {
auto AddrW = std::make_unique<DebugAddrWriterDwarf5>(
&BC, CU.getAddressByteSize(), CU.getAddrOffsetSectionBase());
RangeListsSectionWriter->setAddressWriter(AddrW.get());
- LocListWritersByCU[CUIndex] =
+ LocListWritersByCU[CU.getOffset()] =
std::make_unique<DebugLoclistWriter>(CU, DwarfVersion, false, *AddrW);
-
if (std::optional<uint64_t> DWOId = CU.getDWOId()) {
assert(RangeListsWritersByCU.count(*DWOId) == 0 &&
"RangeLists writer for DWO unit already exists.");
@@ -663,7 +869,7 @@ void DWARFRewriter::updateDebugInfo() {
auto AddrW =
std::make_unique<DebugAddrWriter>(&BC, CU.getAddressByteSize());
AddressWritersByCU[CU.getOffset()] = std::move(AddrW);
- LocListWritersByCU[CUIndex] = std::make_unique<DebugLocWriter>();
+ LocListWritersByCU[CU.getOffset()] = std::make_unique<DebugLocWriter>();
if (std::optional<uint64_t> DWOId = CU.getDWOId()) {
assert(LegacyRangesWritersByCU.count(*DWOId) == 0 &&
"LegacyRangeLists writer for DWO unit already exists.");
@@ -674,86 +880,161 @@ void DWARFRewriter::updateDebugInfo() {
std::move(LegacyRangesSectionWriterByCU);
}
}
- LocListWritersIndexByCU[CU.getOffset()] = CUIndex++;
- };
+ }
+}
- DWARF5AcceleratorTable DebugNamesTable(opts::CreateDebugNames, BC,
- *StrWriter);
- if (DebugNamesTable.isCreated())
- DebugNamesTable.preAllocateUnits(*BC.DwCtx);
- std::unordered_map<uint64_t, std::string> DWOToNameMap =
- getDWONameMap(*BC.DwCtx);
- GDBIndex GDBIndexSection(BC);
- if (!opts::DwarfOutputPath.empty()) {
- if (std::error_code EC =
- sys::fs::create_directories(opts::DwarfOutputPath)) {
- BC.errs() << "BOLT-ERROR: could not create directory '"
- << opts::DwarfOutputPath << "': " << EC.message() << '\n';
- return;
- }
+void DWARFRewriter::processMainBinaryCU(DWARFUnit &Unit, DIEBuilder &DIEBlder,
+ BucketLocalWriter &LocalWriter) {
+ std::optional<DWARFUnit *> SplitCU;
+ std::optional<uint64_t> RangesBase;
+ std::optional<uint64_t> DWOId = Unit.getDWOId();
+ uint8_t DWARFVersion = Unit.getVersion();
+ if (DWOId)
+ SplitCU = BC.getDWOCU(*DWOId);
+ auto LocIt = LocListWritersByCU.find(Unit.getOffset());
+ assert(LocIt != LocListWritersByCU.end() &&
+ "LocListWriter does not exist for CU");
+ DebugLocWriter &DebugLocWriter = *LocIt->second.get();
+ auto AddrIt = AddressWritersByCU.find(Unit.getOffset());
+ assert(AddrIt != AddressWritersByCU.end() &&
+ "AddressWriter does not exist for CU");
+ DebugAddrWriter &AddressWriter = *AddrIt->second.get();
+ if (DWARFVersion >= 5) {
+ if (!LocalWriter.RngListsWriter)
+ LocalWriter.RngListsWriter =
+ std::make_unique<DebugRangeListsSectionWriter>();
+ } else {
+ if (!LocalWriter.LegacyRangesWriter)
+ LocalWriter.LegacyRangesWriter =
+ std::make_unique<DebugRangesSectionWriter>();
+ }
+
+ DebugRangesSectionWriter &RangesSectionWriter =
+ DWARFVersion >= 5 ? *LocalWriter.RngListsWriter
+ : *LocalWriter.LegacyRangesWriter;
+
+ if (DWARFVersion >= 5) {
+ LocalWriter.RngListsWriter->setAddressWriter(&AddressWriter);
+ RangesBase = RangesSectionWriter.getSectionOffset() +
+ getDWARF5RngListLocListHeaderSize();
+ RangesSectionWriter.initSection(Unit);
+ } else if (SplitCU) {
+ // DWARF4: only split-dwarf CUs need a ranges base
+ RangesBase = LocalWriter.LegacyRangesWriter->getSectionOffset();
}
- auto processSplitCU = [&](DWARFUnit &Unit, DWARFUnit &SplitCU,
+ updateUnitDebugInfo(Unit, DIEBlder, DebugLocWriter, RangesSectionWriter,
+ AddressWriter, RangesBase);
+ DebugLocWriter.finalize(DIEBlder, *DIEBlder.getUnitDIEbyUnit(Unit));
+ if (DWARFVersion >= 5)
+ RangesSectionWriter.finalizeSection();
+}
+
+void DWARFRewriter::processBucket(
+ size_t Idx, std::vector<std::vector<DWARFUnit *>> &PartVec,
+ std::vector<std::unique_ptr<DIEBuilder>> &BucketDIEBlders,
+ std::vector<BucketLocalWriter> &LocalWriters,
+ DWARF5AcceleratorTable &DebugNamesTable,
+ std::unordered_map<uint64_t, std::string> &DWOToNameMap,
+ GDBIndex &GDBIndexSection) {
+ std::vector<DWARFUnit *> &Vec = PartVec[Idx];
+ std::unique_ptr<DIEBuilder> &BucketDIEBlder = BucketDIEBlders[Idx];
+ BucketDIEBlder =
+ std::make_unique<DIEBuilder>(BC, BC.DwCtx.get(), DebugNamesTable);
+ DIEBuilder &PartDIEBlder = *BucketDIEBlder;
+ PartDIEBlder.buildCompileUnits(Vec);
+ auto ProcessSplitCU = [&](DWARFUnit &Unit, DWARFUnit &SplitCU,
DebugRangesSectionWriter &TempRangesSectionWriter,
DebugAddrWriter &AddressWriter,
- const std::string DWOName,
+ const std::string &DWOName,
DIEBuilder &DWODIEBuilder) {
DWODIEBuilder.buildDWOUnit(SplitCU);
DebugStrOffsetsWriter DWOStrOffstsWriter(BC);
- DebugStrWriter DWOStrWriter((SplitCU).getContext(), true);
+ DebugStrWriter DWOStrWriter(SplitCU.getContext(), true);
DWODIEBuilder.updateDWONameCompDirForTypes(DWOStrOffstsWriter, DWOStrWriter,
SplitCU, opts::DwarfOutputPath,
DWOName);
DebugLoclistWriter DebugLocDWoWriter(Unit, Unit.getVersion(), true,
AddressWriter);
-
updateUnitDebugInfo(SplitCU, DWODIEBuilder, DebugLocDWoWriter,
TempRangesSectionWriter, AddressWriter);
- DIE *UnitDIE = DWODIEBuilder.getUnitDIEbyUnit(SplitCU);
- if (!UnitDIE) {
- errs() << "BOLT-WARNING: failed to construct DIE for split CU "
- << Twine::utohexstr(*Unit.getDWOId()) << "\n";
- return;
- }
- DebugLocDWoWriter.finalize(DWODIEBuilder, *UnitDIE);
+ DebugLocDWoWriter.finalize(DWODIEBuilder,
+ *DWODIEBuilder.getUnitDIEbyUnit(SplitCU));
if (Unit.getVersion() >= 5)
TempRangesSectionWriter.finalizeSection();
-
emitDWOBuilder(DWOName, DWODIEBuilder, *this, SplitCU, Unit,
DebugLocDWoWriter, DWOStrOffstsWriter, DWOStrWriter,
GDBIndexSection, TempRangesSectionWriter);
+ {
+ std::lock_guard<std::mutex> Lock(DebugNamesUpdateMutex);
+ DWODIEBuilder.updateDebugNamesTable();
+ }
};
- auto processMainBinaryCU = [&](DWARFUnit &Unit, DIEBuilder &DIEBlder) {
+
+ for (DWARFUnit *CU : PartDIEBlder.getProcessedCUs()) {
std::optional<DWARFUnit *> SplitCU;
- std::optional<uint64_t> RangesBase;
- std::optional<uint64_t> DWOId = Unit.getDWOId();
+ std::optional<uint64_t> DWOId = CU->getDWOId();
if (DWOId)
SplitCU = BC.getDWOCU(*DWOId);
- DebugLocWriter &DebugLocWriter =
- *LocListWritersByCU[LocListWritersIndexByCU[Unit.getOffset()]].get();
- DebugRangesSectionWriter &RangesSectionWriter =
- Unit.getVersion() >= 5 ? *RangeListsSectionWriter
- : *LegacyRangesSectionWriter;
- DebugAddrWriter &AddressWriter =
- *AddressWritersByCU[Unit.getOffset()].get();
- if (Unit.getVersion() >= 5)
- RangeListsSectionWriter->setAddressWriter(&AddressWriter);
- if (Unit.getVersion() >= 5) {
- RangesBase = RangesSectionWriter.getSectionOffset() +
- getDWARF5RngListLocListHeaderSize();
- RangesSectionWriter.initSection(Unit);
- if (!SplitCU)
- StrOffstsWriter->finalizeSection(Unit, DIEBlder);
- } else if (SplitCU) {
- RangesBase = LegacyRangesSectionWriter->getSectionOffset();
+ if (SplitCU) {
+ DebugAddrWriter &AddressWriter = *AddressWritersByCU.at(CU->getOffset());
+ DebugRangesSectionWriter &TempRangesSectionWriter =
+ CU->getVersion() >= 5 ? *RangeListsWritersByCU.at(*DWOId)
+ : *LegacyRangesWritersByCU.at(*DWOId);
+ auto NameIt = DWOToNameMap.find(*DWOId);
+ if (NameIt == DWOToNameMap.end()) {
+ BC.errs() << "BOLT-WARNING: [internal-dwarf-warning]: Could not find "
+ "DWO name for DWO ID "
+ << Twine::utohexstr(*DWOId) << ".\n";
+ continue;
+ }
+ auto DWOName = NameIt->second;
+ auto DWODIEBuilderPtr = std::make_unique<DIEBuilder>(
+ BC, &(**SplitCU).getContext(), DebugNamesTable, CU);
+ DIEBuilder &DWODIEBuilder = *DWODIEBuilderPtr;
+ ProcessSplitCU(*CU, **SplitCU, TempRangesSectionWriter, AddressWriter,
+ DWOName, DWODIEBuilder);
}
+ processMainBinaryCU(*CU, PartDIEBlder, LocalWriters[Idx]);
+ }
+}
- updateUnitDebugInfo(Unit, DIEBlder, DebugLocWriter, RangesSectionWriter,
- AddressWriter, RangesBase);
- DebugLocWriter.finalize(DIEBlder, *DIEBlder.getUnitDIEbyUnit(Unit));
- if (Unit.getVersion() >= 5)
- RangesSectionWriter.finalizeSection();
- };
+void DWARFRewriter::updateDebugInfo() {
+ ErrorOr<BinarySection &> DebugInfo = BC.getUniqueSectionByName(".debug_info");
+ if (!DebugInfo)
+ return;
+ ARangesSectionWriter = std::make_unique<DebugARangesSectionWriter>();
+ StrWriter = std::make_unique<DebugStrWriter>(*BC.DwCtx, false);
+ StrOffstsWriter = std::make_unique<DebugStrOffsetsWriter>(BC);
+ /// Stores and serializes information that will be put into the
+ /// .debug_addr DWARF section.
+ std::unique_ptr<DebugAddrWriter> FinalAddrWriter;
+ if (BC.isDWARF5Used()) {
+ FinalAddrWriter = std::make_unique<DebugAddrWriterDwarf5>(&BC);
+ RangeListsSectionWriter = std::make_unique<DebugRangeListsSectionWriter>();
+ } else {
+ FinalAddrWriter = std::make_unique<DebugAddrWriter>(&BC);
+ }
+ if (BC.isDWARFLegacyUsed()) {
+ LegacyRangesSectionWriter = std::make_unique<DebugRangesSectionWriter>();
+ LegacyRangesSectionWriter->initSection();
+ }
+ uint32_t CUSize = std::distance(BC.DwCtx->compile_units().begin(),
+ BC.DwCtx->compile_units().end());
+ // Pre-create per-CU writers in a single thread.
+ // Worker threads should only read from these maps.
+ createRangeLocListAndAddressWriters();
+ // If the user requested an output directory for rewritten .dwo files, make
+ // sure it exists before any worker attempt to create the files.
+ if (!opts::DwarfOutputPath.empty() && !sys::fs::exists(opts::DwarfOutputPath))
+ (void)sys::fs::create_directories(opts::DwarfOutputPath);
+ std::unordered_map<uint64_t, std::string> DWOToNameMap =
+ getDWONameMap(*BC.DwCtx);
+ DWARF5AcceleratorTable DebugNamesTable(opts::CreateDebugNames, BC,
+ *StrWriter);
+ if (DebugNamesTable.isCreated())
+ DebugNamesTable.preAllocateUnits(*BC.DwCtx);
+ GDBIndex GDBIndexSection(BC);
DIEBuilder DIEBlder(BC, BC.DwCtx.get(), DebugNamesTable);
DIEBlder.buildTypeUnits(StrOffstsWriter.get());
SmallVector<char, 20> OutBuffer;
@@ -765,68 +1046,71 @@ void DWARFRewriter::updateDebugInfo() {
*TheTriple, *ObjOS, "TypeStreamer", DIEBlder, GDBIndexSection);
CUOffsetMap OffsetMap =
finalizeTypeSections(DIEBlder, *Streamer, GDBIndexSection);
-
- CUPartitionVector PartVec = partitionCUs(*BC.DwCtx);
+ std::vector<std::vector<DWARFUnit *>> PartVec = partitionCUs(*BC.DwCtx);
const unsigned int ThreadCount =
std::min(opts::DebugThreadCount, opts::ThreadCount);
- for (std::vector<DWARFUnit *> &Vec : PartVec) {
- DIEBlder.buildCompileUnits(Vec);
- llvm::SmallVector<std::unique_ptr<DIEBuilder>, 72> DWODIEBuildersByCU;
- ThreadPoolInterface &ThreadPool =
- ParallelUtilities::getThreadPool(ThreadCount);
- for (DWARFUnit *CU : DIEBlder.getProcessedCUs()) {
- createRangeLocListAddressWriters(*CU);
- std::optional<DWARFUnit *> SplitCU;
- std::optional<uint64_t> DWOId = CU->getDWOId();
- if (DWOId)
- SplitCU = BC.getDWOCU(*DWOId);
- if (!SplitCU)
- continue;
- DebugAddrWriter &AddressWriter =
- *AddressWritersByCU[CU->getOffset()].get();
- DebugRangesSectionWriter &TempRangesSectionWriter =
- CU->getVersion() >= 5 ? *RangeListsWritersByCU[*DWOId].get()
- : *LegacyRangesWritersByCU[*DWOId].get();
- auto NameIt = DWOToNameMap.find(*DWOId);
- if (NameIt == DWOToNameMap.end()) {
- BC.errs() << "BOLT-WARNING: [internal-dwarf-warning]: Could not find "
- "DWO name for DWO ID "
- << Twine::utohexstr(*DWOId) << ".\n";
- continue;
+ llvm::ThreadPoolInterface &ThreadPool =
+ getOrCreateDebugInfoThreadPool(ThreadCount);
+ std::vector<BucketLocalWriter> LocalWriters(PartVec.size());
+ std::vector<std::unique_ptr<DIEBuilder>> BucketDIEBlders(PartVec.size());
+ std::mutex MergeQueueMutex;
+ std::condition_variable MergeQueueCV;
+ std::queue<size_t> MergeQueue;
+ const size_t TotalTasks = PartVec.size();
+ std::vector<char> BucketDone(TotalTasks, 0);
+
+ BucketLocAccumOffset Accum;
+ auto MergeBucket = [&](size_t Idx) -> void {
+ std::unique_ptr<DIEBuilder> &BucketDIEBlder = BucketDIEBlders[Idx];
+ assert(BucketDIEBlder && "Bucket DIEBuilder is null.");
+
+ mergePerBucketLocsAndRanges(*BucketDIEBlder, LocalWriters[Idx],
+ DWOToNameMap, Accum);
+ finalizeCompileUnits(*BucketDIEBlder, DIEBlder, *Streamer, OffsetMap,
+ BucketDIEBlder->getProcessedCUs(), *FinalAddrWriter);
+ BucketDIEBlders[Idx].reset();
+ LocalWriters[Idx].clear();
+ };
+
+ for (size_t I = 0; I < TotalTasks; ++I) {
+ ThreadPool.async([&, I] {
+ processBucket(I, PartVec, BucketDIEBlders, LocalWriters, DebugNamesTable,
+ DWOToNameMap, GDBIndexSection);
+ {
+ std::lock_guard<std::mutex> Lock(MergeQueueMutex);
+ BucketDone[I] = 1;
+ if (!opts::PreserveOrder)
+ MergeQueue.push(I);
+ }
+ // Only the merge thread waits on the CV and it waits on a specific
+ // index. notify_one is sufficient and avoids waking all workers.
+ MergeQueueCV.notify_one();
+ });
+ }
+
+ // Merge completed buckets in-order or as they finish, depending on
+ // PreserveOrder.
+ for (size_t Idx = 0; Idx < TotalTasks; ++Idx) {
+ size_t ProcessIndex;
+ {
+ std::unique_lock<std::mutex> Lock(MergeQueueMutex);
+ if (opts::PreserveOrder) {
+ MergeQueueCV.wait(Lock, [&] { return BucketDone[Idx] != 0; });
+ ProcessIndex = Idx;
+ } else {
+ MergeQueueCV.wait(Lock, [&] { return !MergeQueue.empty(); });
+ ProcessIndex = MergeQueue.front();
+ MergeQueue.pop();
}
- auto DWOName = NameIt->second;
- DIEBlder.updateDWONameCompDir(*StrOffstsWriter, *StrWriter, *CU,
- opts::DwarfOutputPath, DWOName);
- auto DWODIEBuilderPtr = std::make_unique<DIEBuilder>(
- BC, &(**SplitCU).getContext(), DebugNamesTable, CU);
- DIEBuilder &DWODIEBuilder =
- *DWODIEBuildersByCU.emplace_back(std::move(DWODIEBuilderPtr));
- if (CU->getVersion() >= 5)
- StrOffstsWriter->finalizeSection(*CU, DIEBlder);
- // Important to capture CU and SplitCU by value here, otherwise when the
- // thread is executed at some point after the current iteration of the
- // loop, dereferencing CU/SplitCU in the call to processSplitCU means it
- // will dereference a different variable than the one intended, causing a
- // seg fault.
- ThreadPool.async([&, DWOName, CU, SplitCU] {
- processSplitCU(*CU, **SplitCU, TempRangesSectionWriter, AddressWriter,
- DWOName, DWODIEBuilder);
- });
}
- ThreadPool.wait();
- for (std::unique_ptr<DIEBuilder> &DWODIEBuilderPtr : DWODIEBuildersByCU)
- DWODIEBuilderPtr->updateDebugNamesTable();
- for (DWARFUnit *CU : DIEBlder.getProcessedCUs())
- processMainBinaryCU(*CU, DIEBlder);
- finalizeCompileUnits(DIEBlder, *Streamer, OffsetMap,
- DIEBlder.getProcessedCUs(), *FinalAddrWriter);
+ MergeBucket(ProcessIndex);
}
+ ThreadPool.wait();
DebugNamesTable.emitAccelTable();
-
finalizeDebugSections(DIEBlder, DebugNamesTable, *Streamer, *ObjOS, OffsetMap,
- *FinalAddrWriter);
- GDBIndexSection.updateGdbIndexSection(OffsetMap, CUIndex,
+ *FinalAddrWriter, Accum.LocListCUOrder);
+ GDBIndexSection.updateGdbIndexSection(OffsetMap, CUSize,
*ARangesSectionWriter);
}
@@ -916,7 +1200,7 @@ void DWARFRewriter::updateUnitDebugInfo(
ARangesSectionWriter->addCURanges(Unit.getOffset(),
std::move(OutputRanges));
updateDWARFObjectAddressRanges(Unit, DIEBldr, *Die, RangesSectionOffset,
- RangesBase);
+ AddressWriter, RangesBase);
DIEValue StmtListAttrVal = Die->findAttribute(dwarf::DW_AT_stmt_list);
if (LineTablePatchMap.count(&Unit))
DIEBldr.replaceValue(Die, dwarf::DW_AT_stmt_list,
@@ -971,7 +1255,8 @@ void DWARFRewriter::updateUnitDebugInfo(
}
updateDWARFObjectAddressRanges(
- Unit, DIEBldr, *Die, RangesSectionWriter.addRanges(FunctionRanges));
+ Unit, DIEBldr, *Die, RangesSectionWriter.addRanges(FunctionRanges),
+ AddressWriter);
break;
}
@@ -1016,7 +1301,8 @@ void DWARFRewriter::updateUnitDebugInfo(
OutputRanges.back().HighPC);
break;
}
- updateDWARFObjectAddressRanges(Unit, DIEBldr, *Die, RangesSectionOffset);
+ updateDWARFObjectAddressRanges(Unit, DIEBldr, *Die, RangesSectionOffset,
+ AddressWriter);
break;
}
case dwarf::DW_TAG_call_site: {
@@ -1294,7 +1580,6 @@ void DWARFRewriter::updateUnitDebugInfo(
dwarf::Form Form = LowPCAttrInfo.getForm();
assert(Form != dwarf::DW_FORM_LLVM_addrx_offset &&
"DW_FORM_LLVM_addrx_offset is not supported");
- std::lock_guard<std::mutex> Lock(DWARFRewriterMutex);
if (Form == dwarf::DW_FORM_addrx ||
Form == dwarf::DW_FORM_GNU_addr_index) {
const uint32_t Index = AddressWriter.getIndexFromAddress(
@@ -1321,7 +1606,7 @@ void DWARFRewriter::updateUnitDebugInfo(
void DWARFRewriter::updateDWARFObjectAddressRanges(
DWARFUnit &Unit, DIEBuilder &DIEBldr, DIE &Die, uint64_t DebugRangesOffset,
- std::optional<uint64_t> RangesBase) {
+ DebugAddrWriter &AddressWriter, std::optional<uint64_t> RangesBase) {
if (RangesBase) {
// If DW_AT_GNU_ranges_base is present, update it. No further modifications
@@ -1402,9 +1687,9 @@ void DWARFRewriter::updateDWARFObjectAddressRanges(
// to back. Replace with new attributes and patch the DIE.
DIEValue HighPCAttrInfo = Die.findAttribute(dwarf::DW_AT_high_pc);
if (LowPCAttrInfo && HighPCAttrInfo) {
-
convertToRangesPatchDebugInfo(Unit, DIEBldr, Die, DebugRangesOffset,
- LowPCAttrInfo, HighPCAttrInfo, RangesBase);
+ LowPCAttrInfo, HighPCAttrInfo, AddressWriter,
+ RangesBase);
} else if (!(Unit.isDWOUnit() &&
Die.getTag() == dwarf::DW_TAG_compile_unit)) {
if (opts::Verbosity >= 1)
@@ -1454,8 +1739,7 @@ void DWARFRewriter::updateLineTableOffsets(const MCAssembler &Asm) {
if (!StmtOffset)
continue;
- const uint64_t LineTableOffset =
- Asm.getSymbolOffset(*Label);
+ const uint64_t LineTableOffset = Asm.getSymbolOffset(*Label);
DebugLineOffsetMap[*StmtOffset] = LineTableOffset;
assert(DbgInfoSection && ".debug_info section must exist");
LineTablePatchMap[CU.get()] = LineTableOffset;
@@ -1562,7 +1846,7 @@ CUOffsetMap DWARFRewriter::finalizeTypeSections(DIEBuilder &DIEBlder,
void DWARFRewriter::finalizeDebugSections(
DIEBuilder &DIEBlder, DWARF5AcceleratorTable &DebugNamesTable,
DIEStreamer &Streamer, raw_svector_ostream &ObjOS, CUOffsetMap &CUMap,
- DebugAddrWriter &FinalAddrWriter) {
+ DebugAddrWriter &FinalAddrWriter, std::vector<uint64_t> SortedCU) {
if (StrWriter->isInitialized()) {
RewriteInstance::addToDebugSectionsToOverwrite(".debug_str");
std::unique_ptr<DebugStrBufferVector> DebugStrSectionContents =
@@ -1599,7 +1883,7 @@ void DWARFRewriter::finalizeDebugSections(
if (BC.isDWARF5Used()) {
std::unique_ptr<DebugBufferVector> LocationListSectionContents =
- makeFinalLocListsSection(DWARFVersion::DWARF5);
+ makeFinalLocListsSection(DWARFVersion::DWARF5, SortedCU);
if (!LocationListSectionContents->empty())
BC.registerOrUpdateNoteSection(
".debug_loclists", copyByteArray(*LocationListSectionContents),
@@ -1608,7 +1892,7 @@ void DWARFRewriter::finalizeDebugSections(
if (BC.isDWARFLegacyUsed()) {
std::unique_ptr<DebugBufferVector> LocationListSectionContents =
- makeFinalLocListsSection(DWARFVersion::DWARFLegacy);
+ makeFinalLocListsSection(DWARFVersion::DWARFLegacy, SortedCU);
if (!LocationListSectionContents->empty())
BC.registerOrUpdateNoteSection(
".debug_loc", copyByteArray(*LocationListSectionContents),
@@ -1669,8 +1953,8 @@ void DWARFRewriter::finalizeDebugSections(
DebugNamesSectionContents->size());
}
}
-
void DWARFRewriter::finalizeCompileUnits(DIEBuilder &DIEBlder,
+ DIEBuilder &MainDIEBuilder,
DIEStreamer &Streamer,
CUOffsetMap &CUMap,
const std::list<DWARFUnit *> &CUs,
@@ -1715,9 +1999,17 @@ void DWARFRewriter::finalizeCompileUnits(DIEBuilder &DIEBlder,
LegacyRangesWriter->releaseBuffer();
LegacyRangesSectionWriter->appendToRangeBuffer(*RangesWritersContents);
}
- DIEBlder.generateAbbrevs();
+ for (DWARFUnit *DU : CUs) {
+ DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(*DU);
+ MainDIEBuilder.generateUnitAbbrevs(UnitDIE);
+ }
+ DIEBlder.syncAbbrevTableFrom(MainDIEBuilder);
+ DIEBlder.setUnitOffsetBases(CUOffset);
DIEBlder.finish();
- DIEBlder.updateDebugNamesTable();
+ {
+ std::lock_guard<std::mutex> Lock(DebugNamesUpdateMutex);
+ DIEBlder.updateDebugNamesTable();
+ }
// generate debug_info and CUMap
for (DWARFUnit *CU : CUs) {
emitUnit(DIEBlder, Streamer, *CU);
@@ -2073,16 +2365,24 @@ void DWARFRewriter::writeDWOFiles(
}
std::unique_ptr<DebugBufferVector>
-DWARFRewriter::makeFinalLocListsSection(DWARFVersion Version) {
+DWARFRewriter::makeFinalLocListsSection(DWARFVersion Version,
+ ArrayRef<uint64_t> CUOrder) {
auto LocBuffer = std::make_unique<DebugBufferVector>();
auto LocStream = std::make_unique<raw_svector_ostream>(*LocBuffer);
auto Writer =
std::unique_ptr<MCObjectWriter>(BC.createObjectWriter(*LocStream));
- for (std::pair<const uint64_t, std::unique_ptr<DebugLocWriter>> &Loc :
- LocListWritersByCU) {
- DebugLocWriter *LocWriter = Loc.second.get();
- auto *LocListWriter = llvm::dyn_cast<DebugLoclistWriter>(LocWriter);
+ // For DWARF4 .debug_loc, reserve the first 16 bytes for the empty list.
+ if (Version == DWARFVersion::DWARFLegacy)
+ LocStream->write_zeros(16);
+
+ for (uint64_t CUOffset : CUOrder) {
+ auto It = LocListWritersByCU.find(CUOffset);
+ if (It == LocListWritersByCU.end())
+ continue;
+
+ DebugLocWriter *LocWriter = It->second.get();
+ auto *LocListWriter = dyn_cast<DebugLoclistWriter>(LocWriter);
// Filter out DWARF4, writing out DWARF5
if (Version == DWARFVersion::DWARF5 &&
@@ -2097,8 +2397,19 @@ DWARFRewriter::makeFinalLocListsSection(DWARFVersion Version) {
// Skipping DWARF4/5 split dwarf.
if (LocListWriter && LocListWriter->getDwarfVersion() <= 4)
continue;
+
std::unique_ptr<DebugBufferVector> CurrCULocationLists =
LocWriter->getBuffer();
+ // For DWARF4, each per-CU buffer begins with a 16-byte empty list.
+ // Emit the empty list only once globally (reserved above)
+ if (Version == DWARFVersion::DWARFLegacy) {
+ if (CurrCULocationLists->size() > 16)
+ *LocStream << StringRef(
+ reinterpret_cast<const char *>(CurrCULocationLists->data() + 16),
+ CurrCULocationLists->size() - 16);
+ continue;
+ }
+
*LocStream << *CurrCULocationLists;
}
@@ -2108,7 +2419,8 @@ DWARFRewriter::makeFinalLocListsSection(DWARFVersion Version) {
void DWARFRewriter::convertToRangesPatchDebugInfo(
DWARFUnit &Unit, DIEBuilder &DIEBldr, DIE &Die,
uint64_t RangesSectionOffset, DIEValue &LowPCAttrInfo,
- DIEValue &HighPCAttrInfo, std::optional<uint64_t> RangesBase) {
+ DIEValue &HighPCAttrInfo, DebugAddrWriter &AddressWriter,
+ std::optional<uint64_t> RangesBase) {
dwarf::Form LowForm = LowPCAttrInfo.getForm();
dwarf::Attribute RangeBaseAttribute = dwarf::DW_AT_GNU_ranges_base;
dwarf::Form RangesForm = dwarf::DW_FORM_sec_offset;
@@ -2129,11 +2441,7 @@ void DWARFRewriter::convertToRangesPatchDebugInfo(
// when it's absent.
if (IsUnitDie) {
if (LowForm == dwarf::DW_FORM_addrx) {
- auto AddrWriterIterator = AddressWritersByCU.find(Unit.getOffset());
- assert(AddrWriterIterator != AddressWritersByCU.end() &&
- "AddressWriter does not exist for CU");
- DebugAddrWriter *AddrWriter = AddrWriterIterator->second.get();
- const uint32_t Index = AddrWriter->getIndexFromAddress(0, Unit);
+ const uint32_t Index = AddressWriter.getIndexFromAddress(0, Unit);
DIEBldr.replaceValue(&Die, LowPCAttrInfo.getAttribute(),
LowPCAttrInfo.getForm(), DIEInteger(Index));
} else {
diff --git a/bolt/test/X86/dwarf4-cross-cu-backward-different-abbrev.test b/bolt/test/X86/dwarf4-cross-cu-backward-different-abbrev.test
index b06cec6fe6b96..313ea0150a0a2 100644
--- a/bolt/test/X86/dwarf4-cross-cu-backward-different-abbrev.test
+++ b/bolt/test/X86/dwarf4-cross-cu-backward-different-abbrev.test
@@ -17,9 +17,9 @@
# PRECHECK: DW_AT_abstract_origin [DW_FORM_ref_addr]
# PRECHECK-SAME: "var"
+# POSTCHECK: DW_TAG_compile_unit
# POSTCHECK: DW_TAG_compile_unit
# POSTCHECK: DW_AT_abstract_origin [DW_FORM_ref_addr]
# POSTCHECK-SAME: "inlined"
# POSTCHECK: DW_AT_abstract_origin [DW_FORM_ref_addr]
# POSTCHECK-SAME: "var"
-# POSTCHECK: DW_TAG_compile_unit
diff --git a/bolt/test/X86/dwarf4-cross-cu-ranges.test b/bolt/test/X86/dwarf4-cross-cu-ranges.test
new file mode 100644
index 0000000000000..c1f0c8fcfb9ee
--- /dev/null
+++ b/bolt/test/X86/dwarf4-cross-cu-ranges.test
@@ -0,0 +1,55 @@
+; REQUIRES: system-linux
+
+; RUN: llvm-mc -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-cross-cu-with-loclist.s -o %t.o
+; RUN: %clang %cflags -nostdlib -no-pie %t.o -o %t.exe
+; RUN: llvm-bolt %t.exe -o %t.exe.bolt --update-debug-sections --always-convert-to-ranges --debug-thread-count=4
+; RUN: llvm-objdump --disassemble %t.exe.bolt > %t.txt
+; RUN: llvm-dwarfdump --show-form --verbose --debug-info --debug-ranges %t.exe.bolt >> %t.txt
+; RUN: FileCheck %s --input-file=%t.txt
+
+;; Test that two cross-referenced CUs processed in the same bucket keep their own .debug_ranges entries.
+
+; CHECK: <main>:
+; CHECK-NEXT: [[#%.6x,MAIN:]]
+; CHECK: <_Z4foo2i>:
+; CHECK-NEXT: [[#%.6x,FOO2:]]
+
+; CHECK: DW_AT_name [DW_FORM_strp]{{.*}}= "main.cpp"
+; CHECK-NEXT: DW_AT_stmt_list [DW_FORM_sec_offset]
+; CHECK-NEXT: DW_AT_comp_dir [DW_FORM_strp]
+; CHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000)
+; CHECK-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x[[#%.8x,MAIN_CU_RANGES:]]
+; CHECK-NEXT: [0x0000000000[[#%.6x,MAIN]], 0x0000000000[[#%.6x,MAIN_END:]]))
+
+; CHECK: DW_TAG_subprogram [2]
+; CHECK-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x[[#%.8x,MAIN_SUB_RANGES:]]
+; CHECK-NEXT: [0x0000000000[[#MAIN]], 0x0000000000[[#MAIN_END]]))
+; CHECK-NEXT: DW_AT_frame_base [DW_FORM_exprloc]
+; CHECK-NEXT: DW_AT_GNU_all_call_sites [DW_FORM_flag_present]
+; CHECK-NEXT: DW_AT_name [DW_FORM_strp]{{.*}}= "main"
+
+; CHECK: DW_AT_name [DW_FORM_strp]{{.*}}= "helper1.cpp"
+; CHECK-NEXT: DW_AT_stmt_list [DW_FORM_sec_offset]
+; CHECK-NEXT: DW_AT_comp_dir [DW_FORM_strp]
+; CHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000)
+; CHECK-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x[[#%.8x,HELPER_CU_RANGES:]]
+; CHECK-NEXT: [0x0000000000[[#FOO2]], 0x0000000000[[#%.6x,FOO2_END:]]))
+
+; CHECK: DW_TAG_subprogram [14]
+; CHECK-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x[[#%.8x,HELPER_SUB_RANGES:]]
+; CHECK-NEXT: [0x0000000000[[#FOO2]], 0x0000000000[[#FOO2_END]]))
+; CHECK-NEXT: DW_AT_frame_base [DW_FORM_exprloc]
+; CHECK-NEXT: DW_AT_GNU_all_call_sites [DW_FORM_flag_present]
+; CHECK-NEXT: DW_AT_linkage_name [DW_FORM_strp]{{.*}}= "_Z4foo2i"
+; CHECK-NEXT: DW_AT_name [DW_FORM_strp]{{.*}}= "foo2"
+
+; CHECK: DW_TAG_inlined_subroutine
+; CHECK-NEXT: DW_AT_abstract_origin
+; CHECK-NEXT: DW_AT_ranges {{.*}}(0x[[#%.8x,INLINED_RANGES:]]
+
+; CHECK: .debug_ranges contents:
+; CHECK: [[#%.8x,MAIN_CU_RANGES]] 0000000000[[#%.6x,MAIN]] 0000000000[[#%.6x,MAIN + 0x8]]
+; CHECK: [[#%.8x,MAIN_SUB_RANGES]] 0000000000[[#%.6x,MAIN]] 0000000000[[#%.6x,MAIN + 0x8]]
+; CHECK: [[#%.8x,HELPER_CU_RANGES]] 0000000000[[#%.6x,FOO2]] 0000000000[[#%.6x,FOO2 + 0x4]]
+; CHECK: [[#%.8x,HELPER_SUB_RANGES]] 0000000000[[#%.6x,FOO2]] 0000000000[[#%.6x,FOO2 + 0x4]]
+; CHECK: [[#%.8x,INLINED_RANGES]] 0000000000[[#%.6x,FOO2]] 0000000000[[#%.6x,FOO2 + 0x3]]
\ No newline at end of file
>From 8ec10742354f63b39c1d2aa9ff62634383938c56 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Thu, 28 May 2026 12:42:27 +0800
Subject: [PATCH 02/11] fix some bugs
---
bolt/include/bolt/Core/DebugData.h | 2 +-
bolt/lib/Rewrite/DWARFRewriter.cpp | 28 ++++++++++++++++++++--------
2 files changed, 21 insertions(+), 9 deletions(-)
diff --git a/bolt/include/bolt/Core/DebugData.h b/bolt/include/bolt/Core/DebugData.h
index f1120c17fee9f..67a1c5c739c25 100644
--- a/bolt/include/bolt/Core/DebugData.h
+++ b/bolt/include/bolt/Core/DebugData.h
@@ -175,7 +175,7 @@ class DebugRangesSectionWriter {
/// Returns an offset of an empty address ranges list that is always written
/// to .debug_ranges
- uint64_t getEmptyRangesOffset() const { return EmptyRangesOffset; }
+ static uint64_t getEmptyRangesOffset() { return EmptyRangesOffset; }
/// Returns the SectionOffset.
uint64_t getSectionOffset();
diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp
index 1b8327b624444..ba9e59acb54f0 100644
--- a/bolt/lib/Rewrite/DWARFRewriter.cpp
+++ b/bolt/lib/Rewrite/DWARFRewriter.cpp
@@ -354,7 +354,7 @@ static cl::opt<unsigned>
DebugThreadCount("debug-thread-count",
cl::desc("specifies thread count for the multithreading "
"for updating DWARF debug info"),
- cl::init(1), cl::cat(BoltCategory));
+ cl::init(32), cl::cat(BoltCategory));
static cl::opt<bool>
PreserveOrder("dwarf-preserve-order",
@@ -478,8 +478,11 @@ static void fixupDWARFRanges(DIEBuilder &DIEBlder, DWARFUnit &Unit,
if (RangesVal &&
(Version < 5 || RangesVal.getForm() == dwarf::DW_FORM_sec_offset)) {
uint64_t OldVal = RangesVal.getDIEInteger().getValue();
- DIEBlder.replaceValue(Die, dwarf::DW_AT_ranges, RangesVal.getForm(),
- DIEInteger(OldVal + Offset));
+ // Empty ranges are stored at offset 0 in both local and global
+ // buffers, so must not be shifted during merge.
+ if (OldVal != DebugRangesSectionWriter::getEmptyRangesOffset())
+ DIEBlder.replaceValue(Die, dwarf::DW_AT_ranges, RangesVal.getForm(),
+ DIEInteger(OldVal + Offset));
}
if (Version < 5) {
@@ -834,12 +837,19 @@ void DWARFRewriter::mergePerBucketLocsAndRanges(
std::unique_ptr<DebugBufferVector> LegacyBuf =
LocalWriters.LegacyRangesWriter->releaseBuffer();
- // emission order is established later by emitBucketCompileUnits
+ // Local buffers reserve offset 0 for an empty ranges terminator via
+ // initSection(). When appending to the global buffer, skip that local
+ // terminator since the global buffer has its own at offset 0. Adjust
+ // the fixup offset to account for the skipped prefix.
+ const uint64_t LocalTerminatorSize = 16;
+ const uint64_t GlobalOffset =
+ LegacyRangesSectionWriter->getSectionOffset() - LocalTerminatorSize;
for (DWARFUnit *CU : SortedCUs)
if (CU->getVersion() <= 4)
- fixupDWARFRanges(PartDIEBlder, *CU,
- LegacyRangesSectionWriter->getSectionOffset());
- LegacyRangesSectionWriter->appendToRangeBuffer(*LegacyBuf);
+ fixupDWARFRanges(PartDIEBlder, *CU, GlobalOffset);
+ DebugBufferVector TrimmedBuf(LegacyBuf->begin() + LocalTerminatorSize,
+ LegacyBuf->end());
+ LegacyRangesSectionWriter->appendToRangeBuffer(TrimmedBuf);
}
void DWARFRewriter::createRangeLocListAndAddressWriters() {
@@ -904,9 +914,11 @@ void DWARFRewriter::processMainBinaryCU(DWARFUnit &Unit, DIEBuilder &DIEBlder,
LocalWriter.RngListsWriter =
std::make_unique<DebugRangeListsSectionWriter>();
} else {
- if (!LocalWriter.LegacyRangesWriter)
+ if (!LocalWriter.LegacyRangesWriter) {
LocalWriter.LegacyRangesWriter =
std::make_unique<DebugRangesSectionWriter>();
+ LocalWriter.LegacyRangesWriter->initSection();
+ }
}
DebugRangesSectionWriter &RangesSectionWriter =
>From eade198b17d3af896595f42048cf0b6b42976d58 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Tue, 2 Jun 2026 17:56:10 +0800
Subject: [PATCH 03/11] fix up
---
bolt/include/bolt/Core/DIEBuilder.h | 2 +-
bolt/include/bolt/Rewrite/DWARFRewriter.h | 2 +-
bolt/lib/Core/DIEBuilder.cpp | 2 +-
bolt/lib/Rewrite/DWARFRewriter.cpp | 73 ++++++++++++++---------
4 files changed, 48 insertions(+), 31 deletions(-)
diff --git a/bolt/include/bolt/Core/DIEBuilder.h b/bolt/include/bolt/Core/DIEBuilder.h
index 72404e6816e11..f5b5f0a401140 100644
--- a/bolt/include/bolt/Core/DIEBuilder.h
+++ b/bolt/include/bolt/Core/DIEBuilder.h
@@ -290,7 +290,7 @@ class DIEBuilder {
/// Constructs IR for all the CUs.
void buildCompileUnits(const bool Init = true);
/// Constructs IR for CUs in a vector.
- void buildCompileUnits(const std::vector<DWARFUnit *> &CUs);
+ void buildCompileUnits(const SmallVector<DWARFUnit *> &CUs);
/// Preventing implicit conversions.
template <class T> void buildCompileUnits(T) = delete;
/// Builds DWO Unit. For DWARF5 this includes the type units.
diff --git a/bolt/include/bolt/Rewrite/DWARFRewriter.h b/bolt/include/bolt/Rewrite/DWARFRewriter.h
index 87cdca0ab7ad9..c3184e9ebd64d 100644
--- a/bolt/include/bolt/Rewrite/DWARFRewriter.h
+++ b/bolt/include/bolt/Rewrite/DWARFRewriter.h
@@ -180,7 +180,7 @@ class DWARFRewriter {
void processMainBinaryCU(DWARFUnit &Unit, DIEBuilder &DIEBlder,
BucketLocalWriter &LocalWriter);
- void processBucket(size_t Idx, std::vector<std::vector<DWARFUnit *>> &PartVec,
+ void processBucket(size_t Idx, SmallVector<SmallVector<DWARFUnit *>> &PartVec,
std::vector<std::unique_ptr<DIEBuilder>> &BucketDIEBlders,
std::vector<BucketLocalWriter> &LocalWriters,
DWARF5AcceleratorTable &DebugNamesTable,
diff --git a/bolt/lib/Core/DIEBuilder.cpp b/bolt/lib/Core/DIEBuilder.cpp
index 4a2b668236a9f..f068b2c97ce1e 100644
--- a/bolt/lib/Core/DIEBuilder.cpp
+++ b/bolt/lib/Core/DIEBuilder.cpp
@@ -381,7 +381,7 @@ void DIEBuilder::buildCompileUnits(const bool Init) {
constructFromUnit(*DU);
}
}
-void DIEBuilder::buildCompileUnits(const std::vector<DWARFUnit *> &CUs) {
+void DIEBuilder::buildCompileUnits(const SmallVector<DWARFUnit *> &CUs) {
BuilderState.reset(new State());
// Allocating enough for current batch being processed.
// In real use cases we either processing a batch of CUs with no cross
diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp
index ba9e59acb54f0..a26bc1d3433c7 100644
--- a/bolt/lib/Rewrite/DWARFRewriter.cpp
+++ b/bolt/lib/Rewrite/DWARFRewriter.cpp
@@ -603,7 +603,7 @@ static void emitDWOBuilder(const std::string &DWOName,
StrOffstsWriter, StrWriter, TempRangesSectionWriter);
}
-static std::vector<std::vector<DWARFUnit *>> partitionCUs(DWARFContext &DwCtx) {
+static SmallVector<SmallVector<DWARFUnit *>> partitionCUs(DWARFContext &DwCtx) {
SmallVector<DWARFUnit *, 0> AllCUs;
for (auto &CU : DwCtx.compile_units())
AllCUs.push_back(CU.get());
@@ -638,39 +638,56 @@ static std::vector<std::vector<DWARFUnit *>> partitionCUs(DWARFContext &DwCtx) {
}
if (RefAddrAbbrevs.empty())
continue;
- // Track CUs involved in cross-CU references via DW_FORM_ref_addr.
- for (const DWARFDebugInfoEntry &Entry : CU->dies()) {
- DWARFDie Die(CU, &Entry);
+ // Track CUs involved in cross-CU references via DW_FORM_ref_addr. Use the
+ // low-level extractor instead of DWARFUnit::dies() to avoid materializing
+ // every DIE in the unit.
+ uint64_t DIEOffset = CU->getOffset() + CU->getHeaderSize();
+ const uint64_t NextCUOffset = CU->getNextUnitOffset();
+ DWARFDataExtractor DebugInfoData = CU->getDebugInfoExtractor();
+ DWARFDebugInfoEntry DIEEntry;
+ SmallVector<uint32_t, 8> Parents;
+ Parents.push_back(UINT32_MAX);
+ do {
+ if (!DIEEntry.extractFast(*CU, &DIEOffset, DebugInfoData, NextCUOffset,
+ Parents.back()))
+ break;
const DWARFAbbreviationDeclaration *Abbrev =
- Die.getAbbreviationDeclarationPtr();
- if (!Abbrev || !RefAddrAbbrevs.count(Abbrev))
- continue;
- for (const DWARFAttribute &Attr : Die.attributes()) {
- if (Attr.Value.getForm() != dwarf::DW_FORM_ref_addr)
- continue;
- auto OptRef = Attr.Value.getAsDebugInfoReference();
- if (!OptRef)
- continue;
- DWARFUnit *TargetCU = FindCuForOffset(*OptRef);
- if (!TargetCU)
- continue;
- if (CrossRefSet.insert(CU).second)
- EC.insert(CU);
- if (CrossRefSet.insert(TargetCU).second)
- EC.insert(TargetCU);
- EC.unionSets(CU, TargetCU);
+ DIEEntry.getAbbreviationDeclarationPtr();
+ if (Abbrev) {
+ if (RefAddrAbbrevs.count(Abbrev)) {
+ DWARFDie Die(CU, &DIEEntry);
+ for (const DWARFAttribute &Attr : Die.attributes()) {
+ if (Attr.Value.getForm() != dwarf::DW_FORM_ref_addr)
+ continue;
+ auto OptRef = Attr.Value.getAsDebugInfoReference();
+ if (!OptRef)
+ continue;
+ DWARFUnit *TargetCU = FindCuForOffset(*OptRef);
+ if (!TargetCU)
+ continue;
+ if (CrossRefSet.insert(CU).second)
+ EC.insert(CU);
+ if (CrossRefSet.insert(TargetCU).second)
+ EC.insert(TargetCU);
+ EC.unionSets(CU, TargetCU);
+ }
+ }
+ if (Abbrev->hasChildren())
+ Parents.push_back(0);
+ } else {
+ Parents.pop_back();
}
- }
+ } while (!Parents.empty());
}
- DenseMap<DWARFUnit *, std::vector<DWARFUnit *>> MembersByLeader;
+ DenseMap<DWARFUnit *, SmallVector<DWARFUnit *>> MembersByLeader;
for (DWARFUnit *CU : AllCUs) {
if (!CrossRefSet.count(CU))
continue;
MembersByLeader[EC.getLeaderValue(CU)].push_back(CU);
}
- std::vector<DWARFUnit *> Leaders;
+ SmallVector<DWARFUnit *> Leaders;
Leaders.reserve(MembersByLeader.size());
for (auto &[Leader, Members] : MembersByLeader)
Leaders.push_back(Leader);
@@ -680,7 +697,7 @@ static std::vector<std::vector<DWARFUnit *>> partitionCUs(DWARFContext &DwCtx) {
});
// Emit cross-ref buckets, then singleton non-cross-ref CUs.
- std::vector<std::vector<DWARFUnit *>> Vec;
+ SmallVector<SmallVector<DWARFUnit *>> Vec;
for (DWARFUnit *Leader : Leaders)
Vec.push_back(std::move(MembersByLeader[Leader]));
for (DWARFUnit *CU : AllCUs) {
@@ -942,13 +959,13 @@ void DWARFRewriter::processMainBinaryCU(DWARFUnit &Unit, DIEBuilder &DIEBlder,
}
void DWARFRewriter::processBucket(
- size_t Idx, std::vector<std::vector<DWARFUnit *>> &PartVec,
+ size_t Idx, SmallVector<SmallVector<DWARFUnit *>> &PartVec,
std::vector<std::unique_ptr<DIEBuilder>> &BucketDIEBlders,
std::vector<BucketLocalWriter> &LocalWriters,
DWARF5AcceleratorTable &DebugNamesTable,
std::unordered_map<uint64_t, std::string> &DWOToNameMap,
GDBIndex &GDBIndexSection) {
- std::vector<DWARFUnit *> &Vec = PartVec[Idx];
+ SmallVector<DWARFUnit *> &Vec = PartVec[Idx];
std::unique_ptr<DIEBuilder> &BucketDIEBlder = BucketDIEBlders[Idx];
BucketDIEBlder =
std::make_unique<DIEBuilder>(BC, BC.DwCtx.get(), DebugNamesTable);
@@ -1058,7 +1075,7 @@ void DWARFRewriter::updateDebugInfo() {
*TheTriple, *ObjOS, "TypeStreamer", DIEBlder, GDBIndexSection);
CUOffsetMap OffsetMap =
finalizeTypeSections(DIEBlder, *Streamer, GDBIndexSection);
- std::vector<std::vector<DWARFUnit *>> PartVec = partitionCUs(*BC.DwCtx);
+ SmallVector<SmallVector<DWARFUnit *>> PartVec = partitionCUs(*BC.DwCtx);
const unsigned int ThreadCount =
std::min(opts::DebugThreadCount, opts::ThreadCount);
llvm::ThreadPoolInterface &ThreadPool =
>From c17ba018fe82ea789d802e60d12b1b6b37ffb324 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Tue, 2 Jun 2026 19:36:45 +0800
Subject: [PATCH 04/11] fix
---
bolt/lib/Rewrite/DWARFRewriter.cpp | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp
index a26bc1d3433c7..8439a96a76b6b 100644
--- a/bolt/lib/Rewrite/DWARFRewriter.cpp
+++ b/bolt/lib/Rewrite/DWARFRewriter.cpp
@@ -638,18 +638,16 @@ static SmallVector<SmallVector<DWARFUnit *>> partitionCUs(DWARFContext &DwCtx) {
}
if (RefAddrAbbrevs.empty())
continue;
- // Track CUs involved in cross-CU references via DW_FORM_ref_addr. Use the
- // low-level extractor instead of DWARFUnit::dies() to avoid materializing
- // every DIE in the unit.
+ // Track CUs involved in cross-CU references via DW_FORM_ref_addr.
uint64_t DIEOffset = CU->getOffset() + CU->getHeaderSize();
const uint64_t NextCUOffset = CU->getNextUnitOffset();
DWARFDataExtractor DebugInfoData = CU->getDebugInfoExtractor();
DWARFDebugInfoEntry DIEEntry;
- SmallVector<uint32_t, 8> Parents;
- Parents.push_back(UINT32_MAX);
+ SmallVector<uint32_t, 8> ParentIndex;
+ ParentIndex.push_back(UINT32_MAX);
do {
if (!DIEEntry.extractFast(*CU, &DIEOffset, DebugInfoData, NextCUOffset,
- Parents.back()))
+ ParentIndex.back()))
break;
const DWARFAbbreviationDeclaration *Abbrev =
DIEEntry.getAbbreviationDeclarationPtr();
@@ -673,11 +671,11 @@ static SmallVector<SmallVector<DWARFUnit *>> partitionCUs(DWARFContext &DwCtx) {
}
}
if (Abbrev->hasChildren())
- Parents.push_back(0);
+ ParentIndex.push_back(0);
} else {
- Parents.pop_back();
+ ParentIndex.pop_back();
}
- } while (!Parents.empty());
+ } while (!ParentIndex.empty());
}
DenseMap<DWARFUnit *, SmallVector<DWARFUnit *>> MembersByLeader;
>From 24dcdc31634e42cd0c012a6121cf295c11cac727 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Thu, 4 Jun 2026 16:25:29 +0800
Subject: [PATCH 05/11] fix up
---
bolt/include/bolt/Rewrite/DWARFRewriter.h | 1 +
bolt/lib/Rewrite/DWARFRewriter.cpp | 16 +++++++++-------
2 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/bolt/include/bolt/Rewrite/DWARFRewriter.h b/bolt/include/bolt/Rewrite/DWARFRewriter.h
index c3184e9ebd64d..fe2705abfef04 100644
--- a/bolt/include/bolt/Rewrite/DWARFRewriter.h
+++ b/bolt/include/bolt/Rewrite/DWARFRewriter.h
@@ -180,6 +180,7 @@ class DWARFRewriter {
void processMainBinaryCU(DWARFUnit &Unit, DIEBuilder &DIEBlder,
BucketLocalWriter &LocalWriter);
+ /// Process all CUs in the given bucket.
void processBucket(size_t Idx, SmallVector<SmallVector<DWARFUnit *>> &PartVec,
std::vector<std::unique_ptr<DIEBuilder>> &BucketDIEBlders,
std::vector<BucketLocalWriter> &LocalWriters,
diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp
index 8439a96a76b6b..2eb677a242c7c 100644
--- a/bolt/lib/Rewrite/DWARFRewriter.cpp
+++ b/bolt/lib/Rewrite/DWARFRewriter.cpp
@@ -465,7 +465,7 @@ static void fixupDWARFRanges(DIEBuilder &DIEBlder, DWARFUnit &Unit,
DIE *CUDie = DIEBlder.getUnitDIEbyUnit(Unit);
DIEValue RngBaseVal = CUDie->findAttribute(dwarf::DW_AT_rnglists_base);
if (RngBaseVal) {
- uint64_t OldVal = RngBaseVal.getDIEInteger().getValue();
+ const uint64_t OldVal = RngBaseVal.getDIEInteger().getValue();
DIEBlder.replaceValue(CUDie, dwarf::DW_AT_rnglists_base,
RngBaseVal.getForm(), DIEInteger(OldVal + Offset));
}
@@ -477,7 +477,7 @@ static void fixupDWARFRanges(DIEBuilder &DIEBlder, DWARFUnit &Unit,
DIEValue RangesVal = Die->findAttribute(dwarf::DW_AT_ranges);
if (RangesVal &&
(Version < 5 || RangesVal.getForm() == dwarf::DW_FORM_sec_offset)) {
- uint64_t OldVal = RangesVal.getDIEInteger().getValue();
+ const uint64_t OldVal = RangesVal.getDIEInteger().getValue();
// Empty ranges are stored at offset 0 in both local and global
// buffers, so must not be shifted during merge.
if (OldVal != DebugRangesSectionWriter::getEmptyRangesOffset())
@@ -790,7 +790,6 @@ void DWARFRewriter::mergePerBucketLocsAndRanges(
finalizeSkeletonAndStrSection(PartDIEBlder, *CU, DWOToNameMap);
}
for (DWARFUnit *CU : SortedCUs) {
-
const uint64_t CUOffset = CU->getOffset();
// Compute this CU's base and adjust loclists / legacy loc fixups inline.
uint64_t LoclistsBase = 0;
@@ -808,16 +807,19 @@ void DWARFRewriter::mergePerBucketLocsAndRanges(
Accum.LoclistsOffset += BufferSize;
} else if (!LocListWriter) {
LegacyLocBase = Accum.LegacyLocOffset;
- // DWARF4 .debug_loc buffers carry a trailing 16-byte terminator
- // which is written only once at the global level; discount it here
- // so the next CU's base offset is computed correctly.
+ // Each per-CU DWARF4 .debug_loc buffer begins with a 16-byte empty-list
+ // sentinel (offset 0). That sentinel is emitted once for the whole
+ // section in makeFinalLocListsSection, and each CU's leading 16 bytes
+ // are stripped, so a CU contributes BufferSize-16 bytes to the global
+ // section.
+
if (BufferSize > 16)
Accum.LegacyLocOffset += BufferSize - 16;
}
}
if (CU->getVersion() >= 5) {
- uint64_t RangsOffset = RangeListsSectionWriter->getSectionOffset();
+ const uint64_t RangsOffset = RangeListsSectionWriter->getSectionOffset();
fixupDWARFRanges(PartDIEBlder, *CU, RangsOffset);
if (LoclistsBase) {
>From 688c1e9be7abeb0455cf7dd0112eb848c96811c5 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Fri, 5 Jun 2026 11:23:53 +0800
Subject: [PATCH 06/11] fix
---
bolt/include/bolt/Rewrite/DWARFRewriter.h | 6 ++----
bolt/lib/Rewrite/DWARFRewriter.cpp | 8 ++++++--
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/bolt/include/bolt/Rewrite/DWARFRewriter.h b/bolt/include/bolt/Rewrite/DWARFRewriter.h
index fe2705abfef04..aef24e226e74a 100644
--- a/bolt/include/bolt/Rewrite/DWARFRewriter.h
+++ b/bolt/include/bolt/Rewrite/DWARFRewriter.h
@@ -52,10 +52,8 @@ class DWARFRewriter {
/// Release whichever writer was initialized.
void clear() {
- if (RngListsWriter)
- RngListsWriter.reset();
- if (LegacyRangesWriter)
- LegacyRangesWriter.reset();
+ RngListsWriter.reset();
+ LegacyRangesWriter.reset();
}
};
diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp
index 2eb677a242c7c..a2bffd05ab319 100644
--- a/bolt/lib/Rewrite/DWARFRewriter.cpp
+++ b/bolt/lib/Rewrite/DWARFRewriter.cpp
@@ -605,10 +605,15 @@ static void emitDWOBuilder(const std::string &DWOName,
static SmallVector<SmallVector<DWARFUnit *>> partitionCUs(DWARFContext &DwCtx) {
SmallVector<DWARFUnit *, 0> AllCUs;
+ AllCUs.reserve(std::distance(DwCtx.compile_units().begin(),
+ DwCtx.compile_units().end()));
for (auto &CU : DwCtx.compile_units())
AllCUs.push_back(CU.get());
if (AllCUs.empty())
return {};
+ llvm::sort(AllCUs, [](const DWARFUnit *A, const DWARFUnit *B) {
+ return A->getOffset() < B->getOffset();
+ });
auto FindCuForOffset = [&](uint64_t Offset) -> DWARFUnit * {
auto *It =
llvm::upper_bound(AllCUs, Offset, [](uint64_t Off, DWARFUnit *U) {
@@ -699,9 +704,8 @@ static SmallVector<SmallVector<DWARFUnit *>> partitionCUs(DWARFContext &DwCtx) {
for (DWARFUnit *Leader : Leaders)
Vec.push_back(std::move(MembersByLeader[Leader]));
for (DWARFUnit *CU : AllCUs) {
- if (!CrossRefSet.count(CU)) {
+ if (!CrossRefSet.count(CU))
Vec.push_back({CU});
- }
}
return Vec;
>From 2d23260ee198019893295960d263c64143d816e1 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Mon, 8 Jun 2026 11:07:07 +0800
Subject: [PATCH 07/11] fix ranges code duplication
---
bolt/lib/Rewrite/DWARFRewriter.cpp | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp
index a2bffd05ab319..29538b7adda5c 100644
--- a/bolt/lib/Rewrite/DWARFRewriter.cpp
+++ b/bolt/lib/Rewrite/DWARFRewriter.cpp
@@ -484,16 +484,6 @@ static void fixupDWARFRanges(DIEBuilder &DIEBlder, DWARFUnit &Unit,
DIEBlder.replaceValue(Die, dwarf::DW_AT_ranges, RangesVal.getForm(),
DIEInteger(OldVal + Offset));
}
-
- if (Version < 5) {
- DIEValue GnuBaseVal = Die->findAttribute(dwarf::DW_AT_GNU_ranges_base);
- if (GnuBaseVal) {
- uint64_t OldVal = GnuBaseVal.getDIEInteger().getValue();
- DIEBlder.replaceValue(Die, dwarf::DW_AT_GNU_ranges_base,
- GnuBaseVal.getForm(),
- DIEInteger(OldVal + Offset));
- }
- }
}
}
>From 9ee6c08c76dc2ff665d0541e45c0fa26d1df9291 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Tue, 9 Jun 2026 11:32:15 +0800
Subject: [PATCH 08/11] fix syncAbbrevTableFrom duplication
---
bolt/include/bolt/Core/DIEBuilder.h | 1 -
bolt/lib/Core/DIEBuilder.cpp | 19 -------------------
bolt/lib/Rewrite/DWARFRewriter.cpp | 3 ++-
3 files changed, 2 insertions(+), 21 deletions(-)
diff --git a/bolt/include/bolt/Core/DIEBuilder.h b/bolt/include/bolt/Core/DIEBuilder.h
index f5b5f0a401140..8fba755e154d5 100644
--- a/bolt/include/bolt/Core/DIEBuilder.h
+++ b/bolt/include/bolt/Core/DIEBuilder.h
@@ -341,7 +341,6 @@ class DIEBuilder {
void generateAbbrevs();
void generateUnitAbbrevs(DIE *Die);
void assignAbbrev(DIEAbbrev &Abbrev);
- void syncAbbrevTableFrom(const DIEBuilder &SrcBuilder);
/// Set the base offset for CU emission, used by the incremental merge
/// pipeline
void setUnitOffsetBases(uint64_t Base) {
diff --git a/bolt/lib/Core/DIEBuilder.cpp b/bolt/lib/Core/DIEBuilder.cpp
index f068b2c97ce1e..9ee6059a3cc88 100644
--- a/bolt/lib/Core/DIEBuilder.cpp
+++ b/bolt/lib/Core/DIEBuilder.cpp
@@ -1040,25 +1040,6 @@ void DIEBuilder::generateUnitAbbrevs(DIE *Die) {
}
}
-void DIEBuilder::syncAbbrevTableFrom(const DIEBuilder &SrcBuilder) {
- Abbreviations.clear();
- AbbreviationsSet.clear();
- Abbreviations.reserve(SrcBuilder.Abbreviations.size());
- for (const auto &SrcAbbrev : SrcBuilder.Abbreviations) {
- auto Copy = std::make_unique<DIEAbbrev>(SrcAbbrev->getTag(),
- SrcAbbrev->hasChildren());
- for (const auto &Attr : SrcAbbrev->getData())
- Copy->AddAttribute(Attr.getAttribute(), Attr.getForm());
- Copy->setNumber(SrcAbbrev->getNumber());
- FoldingSetNodeID ID;
- Copy->Profile(ID);
- void *InsertToken;
- if (!AbbreviationsSet.FindNodeOrInsertPos(ID, InsertToken))
- AbbreviationsSet.InsertNode(Copy.get(), InsertToken);
- Abbreviations.push_back(std::move(Copy));
- }
-}
-
static uint64_t getHash(const DWARFUnit &DU) {
// Before DWARF5 TU units are in their own section, so at least one offset,
// first one, will be the same as CUs in .debug_info.dwo section
diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp
index 29538b7adda5c..ab15f452d226a 100644
--- a/bolt/lib/Rewrite/DWARFRewriter.cpp
+++ b/bolt/lib/Rewrite/DWARFRewriter.cpp
@@ -2022,11 +2022,12 @@ void DWARFRewriter::finalizeCompileUnits(DIEBuilder &DIEBlder,
LegacyRangesWriter->releaseBuffer();
LegacyRangesSectionWriter->appendToRangeBuffer(*RangesWritersContents);
}
+ // Assign abbreviation numbers from the main DIEBuilder so all bucket DIEs
+ // share a single global .debug_abbrev table.
for (DWARFUnit *DU : CUs) {
DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(*DU);
MainDIEBuilder.generateUnitAbbrevs(UnitDIE);
}
- DIEBlder.syncAbbrevTableFrom(MainDIEBuilder);
DIEBlder.setUnitOffsetBases(CUOffset);
DIEBlder.finish();
{
>From 5532df4b2040ab5f3dfecaee96146f32ad5946a8 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Wed, 10 Jun 2026 14:09:48 +0800
Subject: [PATCH 09/11] fix FindCuForOffset() duplication
---
bolt/include/bolt/Rewrite/DWARFRewriter.h | 6 ----
bolt/lib/Rewrite/DWARFRewriter.cpp | 40 ++++++++---------------
2 files changed, 13 insertions(+), 33 deletions(-)
diff --git a/bolt/include/bolt/Rewrite/DWARFRewriter.h b/bolt/include/bolt/Rewrite/DWARFRewriter.h
index aef24e226e74a..f0f536fc0cbc0 100644
--- a/bolt/include/bolt/Rewrite/DWARFRewriter.h
+++ b/bolt/include/bolt/Rewrite/DWARFRewriter.h
@@ -49,12 +49,6 @@ class DWARFRewriter {
struct BucketLocalWriter {
std::unique_ptr<DebugRangeListsSectionWriter> RngListsWriter;
std::unique_ptr<DebugRangesSectionWriter> LegacyRangesWriter;
-
- /// Release whichever writer was initialized.
- void clear() {
- RngListsWriter.reset();
- LegacyRangesWriter.reset();
- }
};
private:
diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp
index ab15f452d226a..254cb0ab20f9a 100644
--- a/bolt/lib/Rewrite/DWARFRewriter.cpp
+++ b/bolt/lib/Rewrite/DWARFRewriter.cpp
@@ -593,30 +593,14 @@ static void emitDWOBuilder(const std::string &DWOName,
StrOffstsWriter, StrWriter, TempRangesSectionWriter);
}
-static SmallVector<SmallVector<DWARFUnit *>> partitionCUs(DWARFContext &DwCtx) {
+static SmallVector<SmallVector<DWARFUnit *>> partitionCUs(DWARFContext &DwCtx,
+ const size_t Size) {
SmallVector<DWARFUnit *, 0> AllCUs;
- AllCUs.reserve(std::distance(DwCtx.compile_units().begin(),
- DwCtx.compile_units().end()));
+ AllCUs.reserve(Size);
for (auto &CU : DwCtx.compile_units())
AllCUs.push_back(CU.get());
if (AllCUs.empty())
return {};
- llvm::sort(AllCUs, [](const DWARFUnit *A, const DWARFUnit *B) {
- return A->getOffset() < B->getOffset();
- });
- auto FindCuForOffset = [&](uint64_t Offset) -> DWARFUnit * {
- auto *It =
- llvm::upper_bound(AllCUs, Offset, [](uint64_t Off, DWARFUnit *U) {
- return Off < U->getOffset();
- });
- if (It == AllCUs.begin())
- return nullptr;
- DWARFUnit *TargetCU = *--It;
- // Ensure offset falls within TargetCU's range.
- if (Offset >= TargetCU->getNextUnitOffset())
- return nullptr;
- return TargetCU;
- };
DenseSet<DWARFUnit *> CrossRefSet;
EquivalenceClasses<DWARFUnit *> EC;
@@ -655,8 +639,8 @@ static SmallVector<SmallVector<DWARFUnit *>> partitionCUs(DWARFContext &DwCtx) {
auto OptRef = Attr.Value.getAsDebugInfoReference();
if (!OptRef)
continue;
- DWARFUnit *TargetCU = FindCuForOffset(*OptRef);
- if (!TargetCU)
+ DWARFUnit *TargetCU = DwCtx.getUnitForOffset(*OptRef);
+ if (!TargetCU || TargetCU == CU)
continue;
if (CrossRefSet.insert(CU).second)
EC.insert(CU);
@@ -702,9 +686,7 @@ static SmallVector<SmallVector<DWARFUnit *>> partitionCUs(DWARFContext &DwCtx) {
}
static std::unordered_map<uint64_t, std::string>
-getDWONameMap(DWARFContext &DwCtx) {
- const size_t Size =
- std::distance(DwCtx.compile_units().begin(), DwCtx.compile_units().end());
+getDWONameMap(DWARFContext &DwCtx, const size_t Size) {
std::unordered_map<uint64_t, std::string> DWOIDToNameMap(Size);
std::unordered_map<std::string, uint32_t> NameToIndexMap(Size);
for (const std::unique_ptr<DWARFUnit> &CU : DwCtx.compile_units()) {
@@ -1052,7 +1034,7 @@ void DWARFRewriter::updateDebugInfo() {
if (!opts::DwarfOutputPath.empty() && !sys::fs::exists(opts::DwarfOutputPath))
(void)sys::fs::create_directories(opts::DwarfOutputPath);
std::unordered_map<uint64_t, std::string> DWOToNameMap =
- getDWONameMap(*BC.DwCtx);
+ getDWONameMap(*BC.DwCtx, CUSize);
DWARF5AcceleratorTable DebugNamesTable(opts::CreateDebugNames, BC,
*StrWriter);
if (DebugNamesTable.isCreated())
@@ -1069,7 +1051,8 @@ void DWARFRewriter::updateDebugInfo() {
*TheTriple, *ObjOS, "TypeStreamer", DIEBlder, GDBIndexSection);
CUOffsetMap OffsetMap =
finalizeTypeSections(DIEBlder, *Streamer, GDBIndexSection);
- SmallVector<SmallVector<DWARFUnit *>> PartVec = partitionCUs(*BC.DwCtx);
+ SmallVector<SmallVector<DWARFUnit *>> PartVec =
+ partitionCUs(*BC.DwCtx, CUSize);
const unsigned int ThreadCount =
std::min(opts::DebugThreadCount, opts::ThreadCount);
llvm::ThreadPoolInterface &ThreadPool =
@@ -1091,8 +1074,11 @@ void DWARFRewriter::updateDebugInfo() {
DWOToNameMap, Accum);
finalizeCompileUnits(*BucketDIEBlder, DIEBlder, *Streamer, OffsetMap,
BucketDIEBlder->getProcessedCUs(), *FinalAddrWriter);
+
+ // Release memory for this bucket.
BucketDIEBlders[Idx].reset();
- LocalWriters[Idx].clear();
+ LocalWriters[Idx].RngListsWriter.reset();
+ LocalWriters[Idx].LegacyRangesWriter.reset();
};
for (size_t I = 0; I < TotalTasks; ++I) {
>From c2cf9de9445f7a8b2cd94dabd90671098a7740f5 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Thu, 11 Jun 2026 16:55:35 +0800
Subject: [PATCH 10/11] refactor DWARFRewriter bucket merge flow
---
bolt/include/bolt/Rewrite/DWARFRewriter.h | 20 ++-
bolt/lib/Rewrite/DWARFRewriter.cpp | 188 +++++++++++-----------
2 files changed, 102 insertions(+), 106 deletions(-)
diff --git a/bolt/include/bolt/Rewrite/DWARFRewriter.h b/bolt/include/bolt/Rewrite/DWARFRewriter.h
index f0f536fc0cbc0..3c6e90cf27e93 100644
--- a/bolt/include/bolt/Rewrite/DWARFRewriter.h
+++ b/bolt/include/bolt/Rewrite/DWARFRewriter.h
@@ -143,16 +143,20 @@ class DWARFRewriter {
CUOffsetMap finalizeTypeSections(DIEBuilder &DIEBlder, DIEStreamer &Streamer,
GDBIndex &GDBIndexSection);
- /// Finalize str section in the dwo
- void finalizeSkeletonAndStrSection(
- DIEBuilder &PartDIEBlder, DWARFUnit &CU,
+ /// Finalize str section in the dwo.
+ void finalizeMainCUStrOffsets(
+ DIEBuilder &PartDIEBlder, ArrayRef<DWARFUnit *> SortedCUs,
const std::unordered_map<uint64_t, std::string> &DWOToNameMap);
- /// Merge Bucket locs section and ranges section result
- void mergePerBucketLocsAndRanges(
- DIEBuilder &PartDIEBlder, BucketLocalWriter &LocalWriters,
- const std::unordered_map<uint64_t, std::string> &DWOToNameMap,
- BucketLocAccumOffset &Accum);
+ /// Merge Bucket locs section and ranges section result.
+ void mergePerBucketLocs(DIEBuilder &PartDIEBlder,
+ ArrayRef<DWARFUnit *> SortedCUs,
+ BucketLocAccumOffset &Accum);
+
+ /// Merge Bucket ranges section result.
+ void mergePerBucketRanges(DIEBuilder &PartDIEBlder,
+ BucketLocalWriter &LocalWriters,
+ ArrayRef<DWARFUnit *> SortedCUs);
/// Process and write out CUs that are passed in.
void finalizeCompileUnits(DIEBuilder &DIEBlder, DIEBuilder &MainDIEBlder,
diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp
index 254cb0ab20f9a..f352979b88c16 100644
--- a/bolt/lib/Rewrite/DWARFRewriter.cpp
+++ b/bolt/lib/Rewrite/DWARFRewriter.cpp
@@ -455,38 +455,6 @@ static bool getLowAndHighPC(const DIE &Die, const DWARFUnit &DU,
return false;
}
-static void fixupDWARFRanges(DIEBuilder &DIEBlder, DWARFUnit &Unit,
- uint64_t Offset) {
- if (Offset == 0)
- return;
-
- const uint16_t Version = Unit.getVersion();
- if (Version >= 5) {
- DIE *CUDie = DIEBlder.getUnitDIEbyUnit(Unit);
- DIEValue RngBaseVal = CUDie->findAttribute(dwarf::DW_AT_rnglists_base);
- if (RngBaseVal) {
- const uint64_t OldVal = RngBaseVal.getDIEInteger().getValue();
- DIEBlder.replaceValue(CUDie, dwarf::DW_AT_rnglists_base,
- RngBaseVal.getForm(), DIEInteger(OldVal + Offset));
- }
- }
-
- const auto &DIs = DIEBlder.getDIEsByUnit(Unit);
- for (const auto &DI : DIs) {
- DIE *Die = DI->Die;
- DIEValue RangesVal = Die->findAttribute(dwarf::DW_AT_ranges);
- if (RangesVal &&
- (Version < 5 || RangesVal.getForm() == dwarf::DW_FORM_sec_offset)) {
- const uint64_t OldVal = RangesVal.getDIEInteger().getValue();
- // Empty ranges are stored at offset 0 in both local and global
- // buffers, so must not be shifted during merge.
- if (OldVal != DebugRangesSectionWriter::getEmptyRangesOffset())
- DIEBlder.replaceValue(Die, dwarf::DW_AT_ranges, RangesVal.getForm(),
- DIEInteger(OldVal + Offset));
- }
- }
-}
-
static Expected<llvm::DWARFAddressRangesVector>
getDIEAddressRanges(const DIE &Die, DWARFUnit &DU) {
uint64_t LowPC, HighPC, Index;
@@ -719,55 +687,43 @@ getDWONameMap(DWARFContext &DwCtx, const size_t Size) {
return DWOIDToNameMap;
}
-void DWARFRewriter::finalizeSkeletonAndStrSection(
- DIEBuilder &PartDIEBlder, DWARFUnit &CU,
+void DWARFRewriter::finalizeMainCUStrOffsets(
+ DIEBuilder &PartDIEBlder, ArrayRef<DWARFUnit *> SortedCUs,
const std::unordered_map<uint64_t, std::string> &DWOToNameMap) {
- const std::optional<uint64_t> DWOId = CU.getDWOId();
- std::optional<DWARFUnit *> DWOCU = DWOId ? BC.getDWOCU(*DWOId) : std::nullopt;
- const bool HasSplitCU = DWOCU && *DWOCU != nullptr;
- const unsigned Version = CU.getVersion();
-
- if (HasSplitCU) {
- auto It = DWOToNameMap.find(*DWOId);
- if (It != DWOToNameMap.end()) {
- PartDIEBlder.updateDWONameCompDir(*StrOffstsWriter, *StrWriter, CU,
- opts::DwarfOutputPath,
- StringRef(It->second));
- if (Version >= 5 && StrOffstsWriter->isStrOffsetsSectionModified())
- StrOffstsWriter->finalizeSection(CU, PartDIEBlder);
+ for (DWARFUnit *CU : SortedCUs) {
+ const std::optional<uint64_t> DWOId = CU->getDWOId();
+ std::optional<DWARFUnit *> DWOCU =
+ DWOId ? BC.getDWOCU(*DWOId) : std::nullopt;
+ const bool HasSplitCU = DWOCU && *DWOCU != nullptr;
+ const unsigned Version = CU->getVersion();
+
+ if (HasSplitCU) {
+ auto It = DWOToNameMap.find(*DWOId);
+ if (It != DWOToNameMap.end()) {
+ PartDIEBlder.updateDWONameCompDir(*StrOffstsWriter, *StrWriter, *CU,
+ opts::DwarfOutputPath,
+ StringRef(It->second));
+ if (Version >= 5 && StrOffstsWriter->isStrOffsetsSectionModified())
+ StrOffstsWriter->finalizeSection(*CU, PartDIEBlder);
+ }
+ // split CU were just finalized above when the
+ // .debug_str_offsets section was modified;
+ return;
}
- // split CU were just finalized above when the
- // .debug_str_offsets section was modified;
- return;
- }
-
- if (Version >= 5)
- StrOffstsWriter->finalizeSection(CU, PartDIEBlder);
-}
-/// Merge: compute per-CU loclist/legacy-loc bases and in the
-/// same loop apply DWARF5 rnglists/loclists base fixups and legacy
-/// .debug_loc base fixups.
-void DWARFRewriter::mergePerBucketLocsAndRanges(
- DIEBuilder &PartDIEBlder, BucketLocalWriter &LocalWriters,
- const std::unordered_map<uint64_t, std::string> &DWOToNameMap,
- BucketLocAccumOffset &Accum) {
- const auto &Processed = PartDIEBlder.getProcessedCUs();
- std::vector<DWARFUnit *> SortedCUs;
- SortedCUs.assign(Processed.begin(), Processed.end());
- // Ensure deterministic output by sorting CUs in section offset order.
- llvm::sort(SortedCUs, [](const DWARFUnit *A, const DWARFUnit *B) {
- return A->getOffset() < B->getOffset();
- });
-
- for (DWARFUnit *CU : SortedCUs) {
- // record CUs order to make loc/loclist order correct
- Accum.LocListCUOrder.push_back(CU->getOffset());
- finalizeSkeletonAndStrSection(PartDIEBlder, *CU, DWOToNameMap);
+ if (Version >= 5)
+ StrOffstsWriter->finalizeSection(*CU, PartDIEBlder);
}
+}
+void DWARFRewriter::mergePerBucketLocs(DIEBuilder &PartDIEBlder,
+ ArrayRef<DWARFUnit *> SortedCUs,
+ BucketLocAccumOffset &Accum) {
+ // Location lists are emitted later in Accum.LocListCUOrder order. Compute the
+ // global base each CU will have in the final section and update DIEs now.
for (DWARFUnit *CU : SortedCUs) {
const uint64_t CUOffset = CU->getOffset();
- // Compute this CU's base and adjust loclists / legacy loc fixups inline.
+ // Record CUs order to make loc/loclist order correct.
+ Accum.LocListCUOrder.push_back(CUOffset);
uint64_t LoclistsBase = 0;
uint64_t LegacyLocBase = 0;
@@ -794,31 +750,44 @@ void DWARFRewriter::mergePerBucketLocsAndRanges(
}
}
- if (CU->getVersion() >= 5) {
- const uint64_t RangsOffset = RangeListsSectionWriter->getSectionOffset();
- fixupDWARFRanges(PartDIEBlder, *CU, RangsOffset);
-
- if (LoclistsBase) {
- DIE *UnitDIE = PartDIEBlder.getUnitDIEbyUnit(*CU);
- if (UnitDIE) {
- DIEValue LocBase = UnitDIE->findAttribute(dwarf::DW_AT_loclists_base);
- if (LocBase.getType()) {
- const uint64_t OldVal = LocBase.getDIEInteger().getValue();
- PartDIEBlder.replaceValue(UnitDIE, dwarf::DW_AT_loclists_base,
- LocBase.getForm(),
- DIEInteger(OldVal + LoclistsBase));
- }
+ if (LoclistsBase) {
+ DIE *UnitDIE = PartDIEBlder.getUnitDIEbyUnit(*CU);
+ if (UnitDIE) {
+ DIEValue LocBase = UnitDIE->findAttribute(dwarf::DW_AT_loclists_base);
+ if (LocBase.getType()) {
+ const uint64_t OldVal = LocBase.getDIEInteger().getValue();
+ PartDIEBlder.replaceValue(UnitDIE, dwarf::DW_AT_loclists_base,
+ LocBase.getForm(),
+ DIEInteger(OldVal + LoclistsBase));
}
}
- continue;
}
-
- if (LegacyLocBase && LocIt != LocListWritersByCU.end())
+ if (LegacyLocBase)
LocIt->second->applyBase(PartDIEBlder, LegacyLocBase);
}
+}
+
+void DWARFRewriter::mergePerBucketRanges(DIEBuilder &PartDIEBlder,
+ BucketLocalWriter &LocalWriters,
+ ArrayRef<DWARFUnit *> SortedCUs) {
+ // Range lists are stored in bucket-local buffers during parallel processing.
+ // Fix DIE offsets from bucket-local coordinates into the current global
+ // range section coordinates, then append the local buffers.
+ if (RangeListsSectionWriter) {
+ const uint64_t RangesOffset = RangeListsSectionWriter->getSectionOffset();
+ for (DWARFUnit *CU : SortedCUs)
+ if (CU->getVersion() >= 5) {
+ DIE *CUDie = PartDIEBlder.getUnitDIEbyUnit(*CU);
+ DIEValue RngBaseVal = CUDie->findAttribute(dwarf::DW_AT_rnglists_base);
+ if (RngBaseVal) {
+ const uint64_t OldVal = RngBaseVal.getDIEInteger().getValue();
+ PartDIEBlder.replaceValue(CUDie, dwarf::DW_AT_rnglists_base,
+ RngBaseVal.getForm(),
+ DIEInteger(OldVal + RangesOffset));
+ }
+ }
+ }
- /// Append this bucket's .debug_rnglists and .debug_ranges local buffers to
- /// the global writers.
if (LocalWriters.RngListsWriter && RangeListsSectionWriter) {
std::unique_ptr<DebugBufferVector> LocalBuf =
LocalWriters.RngListsWriter->releaseBuffer();
@@ -838,8 +807,23 @@ void DWARFRewriter::mergePerBucketLocsAndRanges(
const uint64_t GlobalOffset =
LegacyRangesSectionWriter->getSectionOffset() - LocalTerminatorSize;
for (DWARFUnit *CU : SortedCUs)
- if (CU->getVersion() <= 4)
- fixupDWARFRanges(PartDIEBlder, *CU, GlobalOffset);
+ if (CU->getVersion() <= 4) {
+ // Fix DWARF v4 DW_AT_ranges attribute.
+ const auto &DIs = PartDIEBlder.getDIEsByUnit(*CU);
+ for (const auto &DI : DIs) {
+ DIE *Die = DI->Die;
+ DIEValue RangesVal = Die->findAttribute(dwarf::DW_AT_ranges);
+ if (RangesVal && RangesVal.getForm() == dwarf::DW_FORM_sec_offset) {
+ const uint64_t OldVal = RangesVal.getDIEInteger().getValue();
+ // Empty ranges are stored at offset 0 in both local and global
+ // buffers, so must not be shifted during merge.
+ if (OldVal != DebugRangesSectionWriter::getEmptyRangesOffset())
+ PartDIEBlder.replaceValue(Die, dwarf::DW_AT_ranges,
+ RangesVal.getForm(),
+ DIEInteger(OldVal + GlobalOffset));
+ }
+ }
+ }
DebugBufferVector TrimmedBuf(LegacyBuf->begin() + LocalTerminatorSize,
LegacyBuf->end());
LegacyRangesSectionWriter->appendToRangeBuffer(TrimmedBuf);
@@ -1069,9 +1053,17 @@ void DWARFRewriter::updateDebugInfo() {
auto MergeBucket = [&](size_t Idx) -> void {
std::unique_ptr<DIEBuilder> &BucketDIEBlder = BucketDIEBlders[Idx];
assert(BucketDIEBlder && "Bucket DIEBuilder is null.");
+ const auto &Processed = BucketDIEBlder->getProcessedCUs();
+ std::vector<DWARFUnit *> SortedCUs;
+ SortedCUs.assign(Processed.begin(), Processed.end());
+ // Ensure deterministic output by sorting CUs in section offset order.
+ llvm::sort(SortedCUs, [](const DWARFUnit *A, const DWARFUnit *B) {
+ return A->getOffset() < B->getOffset();
+ });
- mergePerBucketLocsAndRanges(*BucketDIEBlder, LocalWriters[Idx],
- DWOToNameMap, Accum);
+ finalizeMainCUStrOffsets(*BucketDIEBlder, SortedCUs, DWOToNameMap);
+ mergePerBucketLocs(*BucketDIEBlder, SortedCUs, Accum);
+ mergePerBucketRanges(*BucketDIEBlder, LocalWriters[Idx], SortedCUs);
finalizeCompileUnits(*BucketDIEBlder, DIEBlder, *Streamer, OffsetMap,
BucketDIEBlder->getProcessedCUs(), *FinalAddrWriter);
>From 6f25c053368f840ff502a57b11a7120ca8244a99 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Thu, 11 Jun 2026 19:48:57 +0800
Subject: [PATCH 11/11] Insert blank lines
---
bolt/lib/Rewrite/DWARFRewriter.cpp | 1 +
bolt/test/X86/dwarf4-cross-cu-ranges.test | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp
index f352979b88c16..9e920875b0189 100644
--- a/bolt/lib/Rewrite/DWARFRewriter.cpp
+++ b/bolt/lib/Rewrite/DWARFRewriter.cpp
@@ -715,6 +715,7 @@ void DWARFRewriter::finalizeMainCUStrOffsets(
StrOffstsWriter->finalizeSection(*CU, PartDIEBlder);
}
}
+
void DWARFRewriter::mergePerBucketLocs(DIEBuilder &PartDIEBlder,
ArrayRef<DWARFUnit *> SortedCUs,
BucketLocAccumOffset &Accum) {
diff --git a/bolt/test/X86/dwarf4-cross-cu-ranges.test b/bolt/test/X86/dwarf4-cross-cu-ranges.test
index c1f0c8fcfb9ee..2e784311c2af2 100644
--- a/bolt/test/X86/dwarf4-cross-cu-ranges.test
+++ b/bolt/test/X86/dwarf4-cross-cu-ranges.test
@@ -52,4 +52,4 @@
; CHECK: [[#%.8x,MAIN_SUB_RANGES]] 0000000000[[#%.6x,MAIN]] 0000000000[[#%.6x,MAIN + 0x8]]
; CHECK: [[#%.8x,HELPER_CU_RANGES]] 0000000000[[#%.6x,FOO2]] 0000000000[[#%.6x,FOO2 + 0x4]]
; CHECK: [[#%.8x,HELPER_SUB_RANGES]] 0000000000[[#%.6x,FOO2]] 0000000000[[#%.6x,FOO2 + 0x4]]
-; CHECK: [[#%.8x,INLINED_RANGES]] 0000000000[[#%.6x,FOO2]] 0000000000[[#%.6x,FOO2 + 0x3]]
\ No newline at end of file
+; CHECK: [[#%.8x,INLINED_RANGES]] 0000000000[[#%.6x,FOO2]] 0000000000[[#%.6x,FOO2 + 0x3]]
More information about the llvm-commits
mailing list