[llvm] [RFC][BOLT] A New Parallel DWARF Processing Approach in BOLT (PR #195058)
via llvm-commits
llvm-commits at lists.llvm.org
Wed May 6 08:26:19 PDT 2026
https://github.com/Thrrreeee updated https://github.com/llvm/llvm-project/pull/195058
>From 5d599d5b86efb6459653ac22bfeade682c57ccf3 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Thu, 23 Apr 2026 21:30:06 +0800
Subject: [PATCH 1/6] [BOLT][DebugInfo] add new parallel DWARF processing
ordered
---
bolt/include/bolt/Core/DIEBuilder.h | 22 +-
bolt/include/bolt/Core/DebugData.h | 28 +-
bolt/include/bolt/Core/DebugNames.h | 17 +-
bolt/include/bolt/Rewrite/DWARFRewriter.h | 21 +-
bolt/lib/Core/DIEBuilder.cpp | 43 +-
bolt/lib/Core/DebugData.cpp | 39 +-
bolt/lib/Core/DebugNames.cpp | 106 ++-
bolt/lib/Rewrite/DWARFRewriter.cpp | 988 +++++++++++++++++-----
8 files changed, 996 insertions(+), 268 deletions(-)
diff --git a/bolt/include/bolt/Core/DIEBuilder.h b/bolt/include/bolt/Core/DIEBuilder.h
index 95e958f16cffd..7ba196607fee7 100644
--- a/bolt/include/bolt/Core/DIEBuilder.h
+++ b/bolt/include/bolt/Core/DIEBuilder.h
@@ -61,7 +61,7 @@ class DIEBuilder {
bool IsConstructed = false;
// A map of DIE offsets in original DWARF section to DIE ID.
// Which is used to access DieInfoVector.
- std::unordered_map<uint64_t, uint32_t> DIEIDMap;
+ DenseMap<uint64_t, uint32_t> DIEIDMap;
// Some STL implementations don't have a noexcept move constructor for
// unordered_map (e.g. https://github.com/microsoft/STL/issues/165 explains
@@ -105,9 +105,9 @@ class DIEBuilder {
struct State {
/// A map of Units to Unit Index.
- std::unordered_map<uint64_t, uint32_t> UnitIDMap;
+ DenseMap<uint64_t, uint32_t> UnitIDMap;
/// A map of Type Units to Type DIEs.
- std::unordered_map<DWARFUnit *, DIE *> TypeDIEMap;
+ DenseMap<DWARFUnit *, DIE *> TypeDIEMap;
std::list<DWARFUnit *> DUList;
std::vector<DWARFUnitInfo> CloneUnitCtxMap;
std::vector<std::pair<DIEInfo *, AddrReferenceInfo>> AddrReferences;
@@ -132,9 +132,6 @@ class DIEBuilder {
uint64_t DebugNamesUnitSize{0};
llvm::DenseSet<uint64_t> AllProcessed;
DWARF5AcceleratorTable &DebugNamesTable;
- // Unordered map to handle name collision if output DWO directory is
- // specified.
- std::unordered_map<std::string, uint32_t> NameToIndexMap;
/// Returns current state of the DIEBuilder
State &getState() { return *BuilderState; }
@@ -341,6 +338,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();
@@ -393,12 +397,14 @@ class DIEBuilder {
DebugStrWriter &StrWriter,
DWARFUnit &SkeletonCU,
std::optional<StringRef> DwarfOutputPath,
- std::optional<StringRef> DWONameToUse);
+ std::optional<StringRef> DWONameToUse,
+ std::unordered_map<uint64_t, std::string> &DWOIDToName);
/// Updates DWO Name and Compilation directory for Type Units.
void updateDWONameCompDirForTypes(DebugStrOffsetsWriter &StrOffstsWriter,
DebugStrWriter &StrWriter, DWARFUnit &Unit,
std::optional<StringRef> DwarfOutputPath,
- const StringRef DWOName);
+ const StringRef DWOName,
+ std::unordered_map<uint64_t, std::string> &DWOIDToName);
};
} // namespace bolt
} // namespace llvm
diff --git a/bolt/include/bolt/Core/DebugData.h b/bolt/include/bolt/Core/DebugData.h
index faf7bb62c6bee..1c5334b2db562 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,8 @@ 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;
+ /// Current offset in this writer's local buffer (updated as new entries are written).
+ uint32_t LocSectionOffset{0};
uint8_t DwarfVersion{4};
LocWriterKind Kind{LocWriterKind::DebugLocWriter};
@@ -600,6 +604,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 +625,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 +664,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/Core/DebugNames.h b/bolt/include/bolt/Core/DebugNames.h
index 4ec49ca7207b5..6706e9b07f31e 100644
--- a/bolt/include/bolt/Core/DebugNames.h
+++ b/bolt/include/bolt/Core/DebugNames.h
@@ -17,6 +17,7 @@
#include "bolt/Core/DebugData.h"
#include "llvm/CodeGen/AccelTable.h"
+#include <mutex>
namespace llvm {
namespace bolt {
class BOLTDWARF5AccelTableData : public DWARF5AccelTableData {
@@ -72,15 +73,19 @@ class DWARF5AcceleratorTable {
return std::move(FullTableBuffer);
}
/// Adds a DIE that is referenced across CUs.
- void addCrossCUDie(DWARFUnit *Unit, const DIE *Die) {
- CrossCUDies.insert({Die->getOffset(), {Unit, Die}});
- }
+ void addCrossCUDie(DWARFUnit *Unit, const DIE *Die);
+ /// Looks up a DIE that is referenced across CUs.
+ std::optional<std::pair<DWARFUnit *, const DIE *>>
+ getCrossCUDie(uint64_t Offset);
/// Returns true if the DIE can generate an entry for a cross cu reference.
/// This only checks TAGs of a DIE because when this is invoked DIE might not
/// be fully constructed.
bool canGenerateEntryWithCrossCUReference(
const DWARFUnit &Unit, const DIE &Die,
const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec);
+ /// Pre-allocate CU and Foreign TU slots in deterministic order.
+ /// Must be called before any concurrent addAccelTableEntry() calls.
+ void preAllocateUnits(DWARFContext &DwCtx);
private:
BinaryContext &BC;
@@ -90,12 +95,16 @@ class DWARF5AcceleratorTable {
StringRef StrSection;
uint64_t CurrentUnitOffset = 0;
const DWARFUnit *CurrentUnit = nullptr;
+ std::mutex CrossCUDiesMutex;
std::unordered_map<uint32_t, uint32_t> AbbrevTagToIndexMap;
/// Contains a map of TU hashes to a Foreign TU indices.
/// This is used to reduce the size of Foreign TU list since there could be
/// multiple TUs with the same hash.
DenseMap<uint64_t, uint32_t> TUHashToIndexMap;
-
+ /// Track whether AcceleratorTable have been preallocated.
+ bool Preallocated = false;
+ /// Map from DWO ID to preallocated CU index.
+ DenseMap<uint64_t, uint32_t> DWOIdToCUIndex;
/// Represents a group of entries with identical name (and hence, hash value).
struct HashData {
uint64_t StrOffset;
diff --git a/bolt/include/bolt/Rewrite/DWARFRewriter.h b/bolt/include/bolt/Rewrite/DWARFRewriter.h
index cab346b5aebc5..a2e24b15a318b 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>
@@ -46,6 +47,8 @@ class DWARFRewriter {
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;
@@ -100,6 +103,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,11 +123,11 @@ 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, std::vector<uint64_t> CUOrder);
/// Finalize type sections in the main binary.
CUOffsetMap finalizeTypeSections(DIEBuilder &DIEBlder, DIEStreamer &Streamer,
@@ -135,11 +140,11 @@ class DWARFRewriter {
DebugAddrWriter &FinalAddrWriter);
/// Finalize debug sections in the main binary.
- void finalizeDebugSections(DIEBuilder &DIEBlder,
- DWARF5AcceleratorTable &DebugNamesTable,
- DIEStreamer &Streamer, raw_svector_ostream &ObjOS,
- CUOffsetMap &CUMap,
- DebugAddrWriter &FinalAddrWriter);
+ void finalizeDebugSections(DIEBuilder &DIEBlder, DIEStreamer &Streamer,
+ raw_svector_ostream &ObjOS, CUOffsetMap &CUMap);
+ void flushDebugLocAndRangeSections(DebugAddrWriter &FinalAddrWriter,
+ std::vector<uint64_t> CUOrder);
+ void flushDebugStringSections(DWARF5AcceleratorTable &DebugNamesTable);
/// Patches the binary for DWARF address ranges (e.g. in functions and lexical
/// blocks) to be updated.
@@ -168,7 +173,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 ef7ba54ff6ddc..b62f0244bc14e 100644
--- a/bolt/lib/Core/DIEBuilder.cpp
+++ b/bolt/lib/Core/DIEBuilder.cpp
@@ -86,7 +86,8 @@ static void addStringHelper(DebugStrOffsetsWriter &StrOffstsWriter,
std::string DIEBuilder::updateDWONameCompDir(
DebugStrOffsetsWriter &StrOffstsWriter, DebugStrWriter &StrWriter,
DWARFUnit &SkeletonCU, std::optional<StringRef> DwarfOutputPath,
- std::optional<StringRef> DWONameToUse) {
+ std::optional<StringRef> DWONameToUse,
+ std::unordered_map<uint64_t, std::string> &DWOIDToName) {
DIE &UnitDIE = *getUnitDIEbyUnit(SkeletonCU);
DIEValue DWONameAttrInfo = UnitDIE.findAttribute(dwarf::DW_AT_dwo_name);
if (!DWONameAttrInfo)
@@ -96,8 +97,12 @@ std::string DIEBuilder::updateDWONameCompDir(
std::string ObjectName;
if (DWONameToUse)
ObjectName = *DWONameToUse;
- else
- ObjectName = getDWOName(SkeletonCU, NameToIndexMap, DwarfOutputPath);
+ else {
+ std::optional<uint64_t> DWOId = SkeletonCU.getDWOId();
+ auto NameIt = DWOIDToName.find(*DWOId);
+ assert(NameIt != DWOIDToName.end() && "DWO ID not found in name map");
+ ObjectName = NameIt->second;
+ }
addStringHelper(StrOffstsWriter, StrWriter, *this, UnitDIE, SkeletonCU,
DWONameAttrInfo, ObjectName);
@@ -116,10 +121,11 @@ std::string DIEBuilder::updateDWONameCompDir(
void DIEBuilder::updateDWONameCompDirForTypes(
DebugStrOffsetsWriter &StrOffstsWriter, DebugStrWriter &StrWriter,
DWARFUnit &Unit, std::optional<StringRef> DwarfOutputPath,
- const StringRef DWOName) {
+ const StringRef DWOName,
+ std::unordered_map<uint64_t, std::string> &DWOIDToName) {
for (DWARFUnit *DU : getState().DWARF5TUVector)
updateDWONameCompDir(StrOffstsWriter, StrWriter, *DU, DwarfOutputPath,
- DWOName);
+ DWOName, DWOIDToName);
if (StrOffstsWriter.isStrOffsetsSectionModified())
StrOffstsWriter.finalizeSection(Unit, *this);
}
@@ -356,9 +362,8 @@ void DIEBuilder::buildCompileUnits(const std::vector<DWARFUnit *> &CUs) {
}
void DIEBuilder::buildDWOUnit(DWARFUnit &U) {
- BuilderState.release();
- BuilderState = std::make_unique<State>();
- buildTypeUnits(nullptr, false);
+ if (!BuilderState)
+ BuilderState = std::make_unique<State>();
getState().Type = ProcessingType::CUs;
registerUnit(U, false);
constructFromUnit(U);
@@ -514,7 +519,6 @@ void DIEBuilder::finish() {
break;
finalizeCU(*CU, TypeUnitStartOffset);
}
-
for (DWARFUnit *CU : getState().DUList) {
// Skipping DWARF4 types.
if (CU->getVersion() < 5 && CU->isTypeUnit())
@@ -581,7 +585,7 @@ DWARFDie DIEBuilder::resolveDIEReference(
if ((RefCU =
getUnitForOffset(*this, *DwarfContext, TmpRefOffset, AttrSpec))) {
/// Trying to add to current working set in case it's cross CU reference.
- if (!registerUnit(*RefCU, true))
+ if (!registerUnit(*RefCU, false))
return DWARFDie();
DWARFDataExtractor DebugInfoData = RefCU->getDebugInfoExtractor();
if (DwarfDebugInfoEntry.extractFast(*RefCU, &TmpRefOffset, DebugInfoData,
@@ -992,6 +996,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 9bcd4a052bff7..31d7bc99a821b 100644
--- a/bolt/lib/Core/DebugData.cpp
+++ b/bolt/lib/Core/DebugData.cpp
@@ -562,16 +562,16 @@ DebugAddrWriterDwarf5::finalize(const size_t BufferSize) {
void DebugLocWriter::init() {
LocBuffer = std::make_unique<DebugBufferVector>();
LocStream = std::make_unique<raw_svector_ostream>(*LocBuffer);
+ LocSectionOffset = 0;
// 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 +581,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 +592,12 @@ 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
+ LocSectionOffset = LocBuffer->size();
+ 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 +607,25 @@ 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)
+ 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 +734,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 +768,18 @@ 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()));
+ DIEInteger(LocalBase));
} else {
DIEBldr.addValue(&Die, dwarf::DW_AT_loclists_base,
dwarf::DW_FORM_sec_offset,
- DIEInteger(LoclistBaseOffset + Header->size()));
+ DIEInteger(LocalBase));
}
- LoclistBaseOffset += LocBuffer->size();
}
clearList(RelativeLocListOffsets);
clearList(*LocArrayBuffer);
diff --git a/bolt/lib/Core/DebugNames.cpp b/bolt/lib/Core/DebugNames.cpp
index 2db2050a8111d..04e37c38928b7 100644
--- a/bolt/lib/Core/DebugNames.cpp
+++ b/bolt/lib/Core/DebugNames.cpp
@@ -13,7 +13,9 @@
#include "llvm/Support/EndianStream.h"
#include "llvm/Support/LEB128.h"
#include <cstdint>
+#include <climits>
#include <optional>
+#include <tuple>
namespace llvm {
namespace bolt {
@@ -64,6 +66,52 @@ DWARF5AcceleratorTable::DWARF5AcceleratorTable(
}
}
+//
+void DWARF5AcceleratorTable::preAllocateUnits(DWARFContext &DwCtx) {
+ // Collect all DWO IDs in deterministic order (by CU offset in .debug_info).
+ // This is single-threaded, called before parallel process.
+ for (const auto &CU : DwCtx.compile_units()) {
+ if (std::optional<uint64_t> DWOId = CU->getDWOId()) {
+ uint32_t Idx = CUList.size();
+ CUList.push_back(0xBADBAD);
+ CUOffsetsToPatch[*DWOId] = Idx;
+ DWOIdToCUIndex[*DWOId] = Idx;
+ }
+ }
+
+ for (const auto &CU : DwCtx.compile_units()) {
+ std::optional<uint64_t> DWOId = CU->getDWOId();
+ if (!DWOId)
+ continue;
+ std::optional<DWARFUnit *> DWOCU = BC.getDWOCU(*DWOId);
+ if (!DWOCU || !*DWOCU)
+ continue;
+ DWARFContext &DWOCtx = (*DWOCU)->getContext();
+ // check dwo_info_section_units for DWARF5 type units in DWO.
+ for (const auto &TU : DWOCtx.dwo_info_section_units()) {
+ if (!TU->isTypeUnit())
+ continue;
+ const uint64_t TUHash = cast<DWARFTypeUnit>(TU.get())->getTypeHash();
+ // Only insert on first encounter — preserves discovery order.
+ if (!TUHashToIndexMap.count(TUHash)) {
+ TUHashToIndexMap.insert({TUHash, ForeignTUList.size()});
+ ForeignTUList.push_back(TUHash);
+ }
+ }
+ // check dwo_types_section_units for DWARF4 type units in DWO.
+ for (const auto &TU : DWOCtx.dwo_types_section_units()) {
+ if (!TU->isTypeUnit())
+ continue;
+ const uint64_t TUHash = cast<DWARFTypeUnit>(TU.get())->getTypeHash();
+ if (!TUHashToIndexMap.count(TUHash)) {
+ TUHashToIndexMap.insert({TUHash, ForeignTUList.size()});
+ ForeignTUList.push_back(TUHash);
+ }
+ }
+ }
+ Preallocated = true;
+}
+
void DWARF5AcceleratorTable::setCurrentUnit(DWARFUnit &Unit,
const uint64_t UnitStartOffset) {
CurrentUnit = nullptr;
@@ -79,10 +127,35 @@ void DWARF5AcceleratorTable::setCurrentUnit(DWARFUnit &Unit,
}
}
+void DWARF5AcceleratorTable::addCrossCUDie(DWARFUnit *Unit, const DIE *Die) {
+ std::lock_guard<std::mutex> Lock(CrossCUDiesMutex);
+ CrossCUDies.insert({Die->getOffset(), {Unit, Die}});
+}
+
+std::optional<std::pair<DWARFUnit *, const DIE *>>
+DWARF5AcceleratorTable::getCrossCUDie(uint64_t Offset) {
+ std::lock_guard<std::mutex> Lock(CrossCUDiesMutex);
+ auto Iter = CrossCUDies.find(Offset);
+ if (Iter == CrossCUDies.end())
+ return std::nullopt;
+ return Iter->second;
+}
+
void DWARF5AcceleratorTable::addUnit(DWARFUnit &Unit,
const std::optional<uint64_t> &DWOID) {
constexpr uint32_t BADCUOFFSET = 0xBADBAD;
StrSection = Unit.getStringSection();
+
+ if (Preallocated) {
+ if (!Unit.isTypeUnit() && !DWOID) {
+ CUList.push_back(CurrentUnitOffset);
+ }
+ if (Unit.isTypeUnit() && !DWOID) {
+ LocalTUList.push_back(CurrentUnitOffset);
+ }
+ // For DWO CUs and TUs, slots are already preallocated.
+ return;
+ }
if (Unit.isTypeUnit()) {
if (DWOID) {
// We adding an entry for a DWO TU. The DWO CU might not have any entries,
@@ -234,6 +307,11 @@ uint32_t DWARF5AcceleratorTable::getUnitID(const DWARFUnit &Unit,
}
return LocalTUList.size() - 1;
}
+ if (Preallocated && DWOID) {
+ auto Iter = DWOIdToCUIndex.find(*DWOID);
+ assert(Iter != DWOIdToCUIndex.end() && "DWO ID not preallocated");
+ return Iter->second;
+ }
return CUList.size() - 1;
}
@@ -329,15 +407,15 @@ DWARF5AcceleratorTable::processReferencedDie(
if (!Value)
return std::nullopt;
if (Value.getForm() == dwarf::DW_FORM_ref_addr) {
- auto Iter = CrossCUDies.find(Value.getDIEInteger().getValue());
- if (Iter == CrossCUDies.end()) {
+ auto CrossCUEntry = getCrossCUDie(Value.getDIEInteger().getValue());
+ if (!CrossCUEntry) {
BC.errs() << "BOLT-WARNING: [internal-dwarf-warning]: Could not find "
"referenced DIE in CrossCUDies for "
<< Twine::utohexstr(Value.getDIEInteger().getValue())
<< ".\n";
return std::nullopt;
}
- return Iter->second;
+ return CrossCUEntry;
}
const DIEEntry &DIEENtry = Value.getDIEEntry();
return {{&Unit, &DIEENtry.getEntry()}};
@@ -475,7 +553,27 @@ void DWARF5AcceleratorTable::finalize() {
for (HashData *H : Bucket)
llvm::stable_sort(H->Values, [](const BOLTDWARF5AccelTableData *LHS,
const BOLTDWARF5AccelTableData *RHS) {
- return LHS->getDieOffset() < RHS->getDieOffset();
+ const auto GetCompileUnitKey =
+ [](const BOLTDWARF5AccelTableData *Entry) -> unsigned {
+ if (Entry->getSecondUnitID())
+ return *Entry->getSecondUnitID();
+ if (!Entry->isTU())
+ return Entry->getUnitID();
+ return std::numeric_limits<unsigned>::max();
+ };
+ const auto GetTypeUnitKey =
+ [](const BOLTDWARF5AccelTableData *Entry) -> unsigned {
+ return Entry->isTU() ? Entry->getUnitID()
+ : std::numeric_limits<unsigned>::max();
+ };
+ return std::make_tuple(LHS->getDieOffset(), GetCompileUnitKey(LHS),
+ GetTypeUnitKey(LHS), LHS->getDieTag(),
+ LHS->isParentRoot(),
+ LHS->getParentDieOffset()) <
+ std::make_tuple(RHS->getDieOffset(), GetCompileUnitKey(RHS),
+ GetTypeUnitKey(RHS), RHS->getDieTag(),
+ RHS->isParentRoot(),
+ RHS->getParentDieOffset());
});
}
diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp
index ddee5359f5f53..e29e24858a6e3 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"
@@ -42,13 +44,19 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/ThreadPool.h"
+#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
+#include <condition_variable>
#include <cstdint>
#include <functional>
#include <iterator>
+#include <limits>
#include <memory>
+#include <mutex>
+#include <numeric>
#include <optional>
+#include <queue>
#include <string>
#include <unordered_map>
#include <utility>
@@ -91,6 +99,67 @@ static void printDie(DWARFUnit &DU, uint64_t DIEOffset) {
using namespace bolt;
+namespace {
+
+using DWARFUnitVec = std::vector<DWARFUnit *>;
+using CUPartitionVector = std::vector<DWARFUnitVec>;
+
+struct BucketLocalWriters {
+ std::unique_ptr<DebugRangeListsSectionWriter> RngListsWriter;
+ std::unique_ptr<DebugRangesSectionWriter> LegacyRangesWriter;
+
+ /// Release both writers at once. Called when the bucket has been fully
+ /// merged into the global DWARF section writers.
+ void clear() {
+ RngListsWriter.reset();
+ LegacyRangesWriter.reset();
+ }
+};
+
+using BucketDIEBuilder = std::unique_ptr<DIEBuilder>;
+
+/// Inputs shared by every per-bucket merge step. Held once per
+/// updateDebugInfo() invocation so that helpers consume a single const&
+/// reference rather than threading a long parameter list.
+struct BucketMergeInputs {
+ BinaryContext &BC;
+ const std::optional<std::string> &DwarfOutputPath;
+ std::unordered_map<uint64_t, std::string> &DWOToNameMap;
+ DebugStrWriter &StrWriter;
+ DebugStrOffsetsWriter &StrOffstsWriter;
+ const std::map<uint64_t, std::unique_ptr<DebugLocWriter>> &LocListWritersByCU;
+ DebugRangeListsSectionWriter *RangeListsSectionWriter;
+ DebugRangesSectionWriter *LegacyRangesSectionWriter;
+};
+
+/// Running accumulators advanced monotonically by the merge loop. Kept as
+/// plain scalars (not boxed in a struct-of-references) so the compiler can
+/// keep them in registers across helpers.
+struct BucketMergeAccum {
+ uint64_t CumulativeRngListsSize = 0;
+ uint64_t LoclistsRunningOffset = 0;
+ uint64_t LegacyLocRunningOffset = 0;
+ std::vector<uint64_t> LocListCUOrder;
+};
+
+} // namespace
+
+llvm::ThreadPoolInterface &
+DWARFRewriter::getOrCreateDebugInfoThreadPool(unsigned ThreadsCount) {
+ if (opts::NoThreads || ThreadsCount == 0)
+ ThreadsCount = 1;
+
+ if (DebugInfoThreadPool)
+ return *DebugInfoThreadPool;
+
+ if (ThreadsCount > 1)
+ DebugInfoThreadPool = std::make_unique<DefaultThreadPool>(
+ llvm::hardware_concurrency(ThreadsCount));
+ else
+ DebugInfoThreadPool = std::make_unique<SingleThreadExecutor>();
+ 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
@@ -250,8 +319,9 @@ class DIEStreamer : public DwarfStreamer {
const uint64_t TypeSignature = cast<DWARFTypeUnit>(Unit).getTypeHash();
DIE *TypeDIE = DIEBldr->getTypeDIE(Unit);
const DIEBuilder::DWARFUnitInfo &UI = DIEBldr->getUnitInfoByDwarfUnit(Unit);
+ const uint64_t TypeDIEOffset = TypeDIE ? TypeDIE->getOffset() : 0;
GDBIndexSection.addGDBTypeUnitEntry(
- {UI.UnitOffset, TypeSignature, TypeDIE->getOffset()});
+ {UI.UnitOffset, TypeSignature, TypeDIEOffset});
if (Unit.getVersion() < 5) {
// Switch the section to .debug_types section.
std::unique_ptr<MCStreamer> &MS = Asm.OutStreamer;
@@ -265,7 +335,7 @@ class DIEStreamer : public DwarfStreamer {
emitCommonHeader(Unit, UnitDIE, DwarfVersion);
Asm.OutStreamer->emitIntValue(TypeSignature, sizeof(TypeSignature));
- Asm.emitDwarfLengthOrOffset(TypeDIE ? TypeDIE->getOffset() : 0);
+ Asm.emitDwarfLengthOrOffset(TypeDIEOffset);
}
void emitUnitHeader(DWARFUnit &Unit, DIE &UnitDIE) {
@@ -429,6 +499,44 @@ 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;
@@ -539,85 +647,450 @@ 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;
+ 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;
+ return *--It;
+ };
+ // Track CUs that contain DW_FORM_ref_addr (referrers) and all CUs that are
+ // either referrers or ref targets.
+ SmallVector<DWARFUnit *> CrossRefCUs;
+ DenseSet<DWARFUnit *> ReferrerSet;
+ 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;
+ bool HasCrossRef = false;
+ for (const DWARFDebugInfoEntry &Entry : CU->dies()) {
+ DWARFDie Die(CU, &Entry);
+ const DWARFAbbreviationDeclaration *Abbrev =
+ Die.getAbbreviationDeclarationPtr();
+ if (!Abbrev || !RefAddrAbbrevs.count(Abbrev))
+ continue;
+ HasCrossRef = true;
+ 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());
- }
- if (Counter % opts::BatchSize == 0 && !Vec.back().empty())
- Vec.push_back({});
+
+ if (!HasCrossRef)
+ continue;
+
+ // Ensure standalone referrers (e.g. malformed refs) still end up in their
+ // own singleton equivalence class.
+ if (CrossRefSet.insert(CU).second)
+ EC.insert(CU);
+
+ if (ReferrerSet.insert(CU).second)
+ CrossRefCUs.push_back(CU);
+ }
+ CUPartitionVector Vec;
+ // Decide per-equivalence-class ordering policy.
+ // - DWARF4 classes: keep referrers first (needed for backward-ref tests).
+ // - DWARF5+ classes: keep original CU order to preserve stable abbrev/DIE
+ // layout expected by existing tests.
+ DenseMap<DWARFUnit *, bool> LeaderHasDWARF4;
+ for (DWARFUnit *CU : AllCUs) {
+ if (!CrossRefSet.count(CU))
+ continue;
+ DWARFUnit *Leader = EC.getLeaderValue(CU);
+ LeaderHasDWARF4[Leader] |= (CU->getVersion() <= 4);
}
+
+ // Snapshot membership once so we don't need multiple near-identical passes
+ // that keep checking CrossRefSet / Added.
+ DenseMap<DWARFUnit *, SmallVector<DWARFUnit *, 8>> MembersByLeader;
+ DenseMap<DWARFUnit *, SmallVector<DWARFUnit *, 4>> ReferrersByLeader;
+ for (DWARFUnit *CU : AllCUs) {
+ if (!CrossRefSet.count(CU))
+ continue;
+ MembersByLeader[EC.getLeaderValue(CU)].push_back(CU);
+ }
+ for (DWARFUnit *CU : CrossRefCUs)
+ ReferrersByLeader[EC.getLeaderValue(CU)].push_back(CU);
+
+ // Establish bucket order for each policy.
+ SmallVector<DWARFUnit *, 0> DWARF5LeadersInOrder;
+ DenseSet<DWARFUnit *> SeenDWARF5Leaders;
+ for (DWARFUnit *CU : AllCUs) {
+ if (!CrossRefSet.count(CU))
+ continue;
+ DWARFUnit *Leader = EC.getLeaderValue(CU);
+ if (LeaderHasDWARF4.lookup(Leader))
+ continue;
+ if (SeenDWARF5Leaders.insert(Leader).second)
+ DWARF5LeadersInOrder.push_back(Leader);
+ }
+ SmallVector<DWARFUnit *, 0> DWARF4LeadersInOrder;
+ DenseSet<DWARFUnit *> SeenDWARF4Leaders;
+ for (DWARFUnit *CU : CrossRefCUs) {
+ DWARFUnit *Leader = EC.getLeaderValue(CU);
+ if (!LeaderHasDWARF4.lookup(Leader))
+ continue;
+ if (SeenDWARF4Leaders.insert(Leader).second)
+ DWARF4LeadersInOrder.push_back(Leader);
+ }
+
+ // Emit buckets.
+ auto appendBucketForLeader = [&](DWARFUnit *Leader) {
+ auto MemIt = MembersByLeader.find(Leader);
+ assert(MemIt != MembersByLeader.end() &&
+ "Cross-ref leader without members");
+
+ DWARFUnitVec Bucket;
+ const bool HasDWARF4 = LeaderHasDWARF4.lookup(Leader);
+ if (!HasDWARF4) {
+ Bucket.assign(MemIt->second.begin(), MemIt->second.end());
+ Vec.push_back(std::move(Bucket));
+ return;
+ }
+
+ // DWARF4+: referrers first (discovery order), then remaining members
+ // (targets-only) in original CU order.
+ auto RefIt = ReferrersByLeader.find(Leader);
+ Bucket.reserve(MemIt->second.size());
+ if (RefIt != ReferrersByLeader.end())
+ Bucket.insert(Bucket.end(), RefIt->second.begin(), RefIt->second.end());
+ for (DWARFUnit *CU : MemIt->second)
+ if (!ReferrerSet.count(CU))
+ Bucket.push_back(CU);
+ assert(Bucket.size() == MemIt->second.size() &&
+ "Bucket ordering lost or duplicated members");
+ Vec.push_back(std::move(Bucket));
+ };
+
+ // Keep the historical policy split: all DWARF5+ cross-ref buckets first,
+ // then DWARF4 buckets.
+ for (DWARFUnit *Leader : DWARF5LeadersInOrder)
+ appendBucketForLeader(Leader);
+ for (DWARFUnit *Leader : DWARF4LeadersInOrder)
+ appendBucketForLeader(Leader);
+
+ // Finally, append non-cross-ref CUs as singleton buckets in original CU
+ // order.
+ for (DWARFUnit *CU : AllCUs)
+ if (!CrossRefSet.count(CU))
+ Vec.push_back({CU});
return Vec;
}
+
+static std::unordered_map<uint64_t, std::string>
+getDWONameMap(DWARFContext &DwCtx,
+ std::optional<std::string> &DwarfOutputPath) {
+ const size_t Size =
+ std::distance(DwCtx.compile_units().begin(), DwCtx.compile_units().end());
+ 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()) {
+ std::optional<uint64_t> DWOID = CU->getDWOId();
+ if (!DWOID)
+ continue;
+ // Skip invalid (broken) skeleton units that have a DWOId but lack
+ // DW_AT_dwo_name / DW_AT_GNU_dwo_name. These are reported elsewhere via
+ // BinaryContext::isValidDwarfUnit() and should be removed from output.
+ if (!CU->isDWOUnit() && !CU->getUnitDIE().find({dwarf::DW_AT_dwo_name,
+ dwarf::DW_AT_GNU_dwo_name}))
+ continue;
+ std::string DWOName =
+ dwarf::toString(CU->getUnitDIE().find(
+ {dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}),
+ "");
+ if (DWOName.empty())
+ continue;
+ if (DwarfOutputPath) {
+ DWOName = std::string(sys::path::filename(DWOName));
+ uint32_t &Index = NameToIndexMap[DWOName];
+ DWOName.append(std::to_string(Index));
+ ++Index;
+ }
+ DWOName.append(".dwo");
+ DWOIDToNameMap.emplace(*DWOID, std::move(DWOName));
+ }
+ return DWOIDToNameMap;
+}
+
+/// Apply DWO name / comp_dir fixups and finalize .debug_str_offsets for
+/// every CU processed by \p PartDIEBlder. Performs a single pass over
+/// getProcessedCUs(); the intra-bucket order is already deterministic,
+/// so no sort/Pending vector is needed.
+static void finalizeSkeletonAndStrOffsets(DIEBuilder &PartDIEBlder,
+ const BucketMergeInputs &In) {
+ for (DWARFUnit *CU : PartDIEBlder.getProcessedCUs()) {
+ const std::optional<uint64_t> DWOId = CU->getDWOId();
+ const bool HasSplitCU = DWOId && In.BC.getDWOCU(*DWOId) != nullptr;
+ const unsigned Version = CU->getVersion();
+
+ if (HasSplitCU) {
+ auto It = In.DWOToNameMap.find(*DWOId);
+ if (It != In.DWOToNameMap.end()) {
+ PartDIEBlder.updateDWONameCompDir(In.StrOffstsWriter, In.StrWriter, *CU,
+ In.DwarfOutputPath,
+ StringRef(It->second),
+ In.DWOToNameMap);
+ if (Version >= 5 && In.StrOffstsWriter.isStrOffsetsSectionModified())
+ In.StrOffstsWriter.finalizeSection(*CU, PartDIEBlder);
+ }
+ // Skeleton-with-split units were just finalized above when the
+ // .debug_str_offsets section was modified; no second pass needed.
+ continue;
+ }
+
+ if (Version >= 5)
+ In.StrOffstsWriter.finalizeSection(*CU, PartDIEBlder);
+ }
+}
+
+/// Snapshot \p PartDIEBlder.getProcessedCUs() into a SmallVector sorted by
+/// CU offset. The same sorted view is reused by every per-CU helper below
+/// so that the bucket is walked at most twice (once here, once during emit).
+static void snapshotSortedCUs(DIEBuilder &PartDIEBlder,
+ SmallVectorImpl<DWARFUnit *> &Out) {
+ const auto &Processed = PartDIEBlder.getProcessedCUs();
+ Out.clear();
+ Out.reserve(Processed.size());
+ for (DWARFUnit *CU : Processed)
+ Out.push_back(CU);
+ llvm::sort(Out, [](const DWARFUnit *A, const DWARFUnit *B) {
+ return A->getOffset() < B->getOffset();
+ });
+}
+
+/// Single-sweep 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. Doing all per-CU work in one pass keeps the
+/// DWARFUnit* stream in cache and avoids re-walking getProcessedCUs()
+/// three times as the previous split helpers did.
+static void mergePerBucketLocsAndRanges(DIEBuilder &PartDIEBlder,
+ ArrayRef<DWARFUnit *> SortedCUs,
+ const BucketMergeInputs &In,
+ uint64_t DeltaDWARF5,
+ BucketMergeAccum &Accum) {
+ for (DWARFUnit *CU : SortedCUs) {
+ const uint64_t CUOffset = CU->getOffset();
+ Accum.LocListCUOrder.push_back(CUOffset);
+
+ // Compute this CU's contribution base and adjust loclists / legacy loc
+ // fixups inline, avoiding a separate lookup pass.
+ uint64_t LoclistsBase = 0;
+ uint64_t LegacyLocBase = 0;
+ bool HasLoclistsBase = false;
+ bool HasLegacyLocBase = false;
+
+ auto LocIt = In.LocListWritersByCU.find(CUOffset);
+ if (LocIt != In.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.LoclistsRunningOffset;
+ HasLoclistsBase = true;
+ Accum.LoclistsRunningOffset += BufferSize;
+ } else if (!LocListWriter) {
+ LegacyLocBase = Accum.LegacyLocRunningOffset;
+ HasLegacyLocBase = true;
+ // 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.LegacyLocRunningOffset += BufferSize - 16;
+ }
+ }
+
+ const unsigned Version = CU->getVersion();
+ if (Version >= 5) {
+ fixupDWARFRanges(PartDIEBlder, *CU, DeltaDWARF5);
+
+ if (HasLoclistsBase) {
+ 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;
+ }
+
+ // Version <= 4 path.
+ if (HasLegacyLocBase && LocIt != In.LocListWritersByCU.end())
+ LocIt->second->applyBase(PartDIEBlder, LegacyLocBase);
+ }
+}
+
+/// Append this bucket's .debug_rnglists and .debug_ranges local buffers to
+/// the global writers. Reuses \p SortedCUs for the DWARF4 fixup pass so
+/// no extra copy+sort is needed.
+static void appendBucketRangeBuffers(DIEBuilder &PartDIEBlder,
+ ArrayRef<DWARFUnit *> SortedCUs,
+ BucketLocalWriters &LocalWriters,
+ const BucketMergeInputs &In,
+ BucketMergeAccum &Accum) {
+ if (LocalWriters.RngListsWriter && In.RangeListsSectionWriter) {
+ std::unique_ptr<DebugBufferVector> LocalBuf =
+ LocalWriters.RngListsWriter->releaseBuffer();
+ Accum.CumulativeRngListsSize += LocalBuf->size();
+ In.RangeListsSectionWriter->appendToRangeBuffer(*LocalBuf);
+ }
+
+ if (!LocalWriters.LegacyRangesWriter || !In.LegacyRangesSectionWriter)
+ return;
+
+ std::unique_ptr<DebugBufferVector> LegacyBuf =
+ LocalWriters.LegacyRangesWriter->releaseBuffer();
+ const uint64_t DeltaDWARF4 =
+ In.LegacyRangesSectionWriter->getSectionOffset();
+ // Walk the already-sorted snapshot; do not mutate the processed list
+ // (emission order is established later by emitBucketCompileUnits).
+ for (DWARFUnit *CU : SortedCUs)
+ if (CU->getVersion() <= 4)
+ fixupDWARFRanges(PartDIEBlder, *CU, DeltaDWARF4);
+ In.LegacyRangesSectionWriter->appendToRangeBuffer(*LegacyBuf);
+}
+
+static void emitBucketCompileUnits(DIEBuilder &PartDIEBlder,
+ DIEBuilder &MainDIEBuilder,
+ DIEStreamer &Streamer,
+ CUOffsetMap &OffsetMap, uint32_t &CUOffset) {
+ const auto &Processed = PartDIEBlder.getProcessedCUs();
+ for (DWARFUnit *DU : Processed) {
+ DIE *UnitDIE = PartDIEBlder.getUnitDIEbyUnit(*DU);
+ MainDIEBuilder.generateUnitAbbrevs(UnitDIE);
+ }
+
+ PartDIEBlder.syncAbbrevTableFrom(MainDIEBuilder);
+ PartDIEBlder.setUnitOffsetBases(CUOffset);
+ PartDIEBlder.finish();
+ PartDIEBlder.updateDebugNamesTable();
+
+ // Emit units in the same order DIEBuilder assigned offsets.
+ for (DWARFUnit *CU : Processed) {
+ emitUnit(PartDIEBlder, Streamer, *CU);
+ const uint32_t StartOffset = CUOffset;
+ DIE *UnitDIE = PartDIEBlder.getUnitDIEbyUnit(*CU);
+ CUOffset += CU->getHeaderSize();
+ CUOffset += UnitDIE->getSize();
+ OffsetMap[CU->getOffset()] = {StartOffset, CUOffset - StartOffset - 4};
+ }
+}
+
+/// Finalize a single bucket. All per-CU work uses a single sorted snapshot
+/// of getProcessedCUs() to avoid repeated std::list walks and the redundant
+/// sort-passes that the earlier 7-helper split introduced.
+static void mergeOneBucket(size_t Idx, DIEBuilder &MainDIEBuilder,
+ std::vector<BucketDIEBuilder> &BucketDIEBlders,
+ std::vector<BucketLocalWriters> &LocalWriters,
+ BucketMergeInputs &In, BucketMergeAccum &Accum,
+ uint64_t InitialRngListsOffset,
+ DIEStreamer &Streamer, CUOffsetMap &OffsetMap,
+ uint32_t &CUOffset,
+ llvm::function_ref<void(DIEBuilder &)> FinalizeFn) {
+ BucketDIEBuilder &BucketDIEBlder = BucketDIEBlders[Idx];
+ if (!BucketDIEBlder)
+ return;
+
+ DIEBuilder &PartDIEBlder = *BucketDIEBlder;
+
+ finalizeSkeletonAndStrOffsets(PartDIEBlder, In);
+
+ SmallVector<DWARFUnit *, 32> SortedCUs;
+ snapshotSortedCUs(PartDIEBlder, SortedCUs);
+
+ const uint64_t DeltaDWARF5 =
+ InitialRngListsOffset + Accum.CumulativeRngListsSize;
+ mergePerBucketLocsAndRanges(PartDIEBlder, SortedCUs, In, DeltaDWARF5, Accum);
+ appendBucketRangeBuffers(PartDIEBlder, SortedCUs, LocalWriters[Idx], In,
+ Accum);
+ FinalizeFn(PartDIEBlder);
+
+ emitBucketCompileUnits(PartDIEBlder, MainDIEBuilder, Streamer, OffsetMap,
+ CUOffset);
+
+ BucketDIEBlder.reset();
+ LocalWriters[Idx].clear();
+}
+
+
void DWARFRewriter::updateDebugInfo() {
+ TimerGroup allTG("updateDebugInfo", "all time");
+ Timer AllTimer("allTime", "update all time", allTG);
+ TimerGroup threadTG("updateDebugInfothread", "thread time");
+ Timer threadTimer("thread time", "update thread time", threadTG);
+ AllTimer.startTimer();
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();
}
+ // Used for GDB index and for assigning stable per-run CU IDs.
+ // Note: LocListWritersByCU is keyed by CU offset, so CUIndex is not used as
+ // a container key.
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);
+ auto createRangeLocListAndAddressWriters = [&](DWARFUnit &CU) {
+ if (LocListWritersByCU.count(CU.getOffset()))
+ return;
+
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.");
@@ -632,7 +1105,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.");
@@ -643,68 +1116,94 @@ void DWARFRewriter::updateDebugInfo() {
std::move(LegacyRangesSectionWriterByCU);
}
}
- LocListWritersIndexByCU[CU.getOffset()] = CUIndex++;
+ ++CUIndex;
};
-
+ // Pre-create per-CU writers in a single thread.
+ // Worker threads should only read from these maps. This avoids both
+ // non-determinism and potential data races from using
+ // unordered_map::operator[] in parallel code paths.
+ for (const std::unique_ptr<DWARFUnit> &CU : BC.DwCtx->compile_units())
+ createRangeLocListAndAddressWriters(*CU);
+
+ std::optional<std::string> DwarfOutputPath =
+ opts::DwarfOutputPath.empty()
+ ? std::nullopt
+ : std::optional<std::string>(opts::DwarfOutputPath.c_str());
+
+ // If the user requested an output directory for rewritten .dwo files, make
+ // sure it exists before any worker threads attempt to create the files.
+ if (DwarfOutputPath && !sys::fs::exists(*DwarfOutputPath))
+ (void)sys::fs::create_directories(*DwarfOutputPath);
+
+ std::unordered_map<uint64_t, std::string> DWOToNameMap =
+ getDWONameMap(*BC.DwCtx, DwarfOutputPath);
DWARF5AcceleratorTable DebugNamesTable(opts::CreateDebugNames, BC,
*StrWriter);
+ if (DebugNamesTable.isCreated())
+ DebugNamesTable.preAllocateUnits(*BC.DwCtx);
GDBIndex GDBIndexSection(BC);
+ std::mutex BuildTypeMutex;
+ std::mutex DebugNamesUpdateMutex;
+
auto processSplitCU = [&](DWARFUnit &Unit, DWARFUnit &SplitCU,
DebugRangesSectionWriter &TempRangesSectionWriter,
DebugAddrWriter &AddressWriter,
const std::string &DWOName,
- const std::optional<std::string> &DwarfOutputPath,
DIEBuilder &DWODIEBuilder) {
DWODIEBuilder.buildDWOUnit(SplitCU);
DebugStrOffsetsWriter DWOStrOffstsWriter(BC);
DebugStrWriter DWOStrWriter((SplitCU).getContext(), true);
- DWODIEBuilder.updateDWONameCompDirForTypes(
- DWOStrOffstsWriter, DWOStrWriter, SplitCU, DwarfOutputPath, DWOName);
+ DWODIEBuilder.updateDWONameCompDirForTypes(DWOStrOffstsWriter, DWOStrWriter,
+ SplitCU, DwarfOutputPath,
+ DWOName, DWOToNameMap);
DebugLoclistWriter DebugLocDWoWriter(Unit, Unit.getVersion(), true,
AddressWriter);
-
updateUnitDebugInfo(SplitCU, DWODIEBuilder, DebugLocDWoWriter,
TempRangesSectionWriter, AddressWriter);
DebugLocDWoWriter.finalize(DWODIEBuilder,
*DWODIEBuilder.getUnitDIEbyUnit(SplitCU));
if (Unit.getVersion() >= 5)
TempRangesSectionWriter.finalizeSection();
-
emitDWOBuilder(DWOName, DWODIEBuilder, *this, SplitCU, Unit,
DebugLocDWoWriter, DWOStrOffstsWriter, DWOStrWriter,
GDBIndexSection, TempRangesSectionWriter);
};
- auto processMainBinaryCU = [&](DWARFUnit &Unit, DIEBuilder &DIEBlder) {
- std::optional<DWARFUnit *> SplitCU;
- std::optional<uint64_t> RangesBase;
- std::optional<uint64_t> DWOId = Unit.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();
- }
-
- updateUnitDebugInfo(Unit, DIEBlder, DebugLocWriter, RangesSectionWriter,
- AddressWriter, RangesBase);
- DebugLocWriter.finalize(DIEBlder, *DIEBlder.getUnitDIEbyUnit(Unit));
- if (Unit.getVersion() >= 5)
- RangesSectionWriter.finalizeSection();
- };
+ auto processMainBinaryCU =
+ [&](DWARFUnit &Unit, DIEBuilder &DIEBlder,
+ DebugRangesSectionWriter &LocalRangesWriter,
+ DebugRangeListsSectionWriter *LocalRngListsWriter) {
+ std::optional<DWARFUnit *> SplitCU;
+ std::optional<uint64_t> RangesBase;
+ std::optional<uint64_t> DWOId = Unit.getDWOId();
+ 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();
+
+ DebugRangesSectionWriter &RangesSectionWriter =
+ Unit.getVersion() >= 5
+ ? static_cast<DebugRangesSectionWriter &>(*LocalRngListsWriter)
+ : LocalRangesWriter;
+ if (Unit.getVersion() >= 5) {
+ LocalRngListsWriter->setAddressWriter(&AddressWriter);
+ RangesBase = RangesSectionWriter.getSectionOffset() +
+ getDWARF5RngListLocListHeaderSize();
+ RangesSectionWriter.initSection(Unit);
+ } else if (SplitCU) {
+ RangesBase = RangesSectionWriter.getSectionOffset();
+ }
+ updateUnitDebugInfo(Unit, DIEBlder, DebugLocWriter, RangesSectionWriter,
+ AddressWriter, RangesBase);
+ DebugLocWriter.finalize(DIEBlder, *DIEBlder.getUnitDIEbyUnit(Unit));
+ if (Unit.getVersion() >= 5)
+ RangesSectionWriter.finalizeSection();
+ };
DIEBuilder DIEBlder(BC, BC.DwCtx.get(), DebugNamesTable);
DIEBlder.buildTypeUnits(StrOffstsWriter.get());
@@ -717,65 +1216,129 @@ void DWARFRewriter::updateDebugInfo() {
*TheTriple, *ObjOS, "TypeStreamer", DIEBlder, GDBIndexSection);
CUOffsetMap OffsetMap =
finalizeTypeSections(DIEBlder, *Streamer, GDBIndexSection);
-
CUPartitionVector 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();
- std::optional<std::string> DwarfOutputPath =
- opts::DwarfOutputPath.empty()
- ? std::nullopt
- : std::optional<std::string>(opts::DwarfOutputPath.c_str());
- std::string DWOName = DIEBlder.updateDWONameCompDir(
- *StrOffstsWriter, *StrWriter, *CU, DwarfOutputPath, std::nullopt);
- 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([&, DwarfOutputPath, DWOName, CU, SplitCU] {
+ llvm::ThreadPoolInterface &ThreadPool =
+ getOrCreateDebugInfoThreadPool(ThreadCount);
+ std::vector<BucketLocalWriters> LocalWriters(PartVec.size());
+ const uint64_t InitialRngListsOffset =
+ RangeListsSectionWriter ? RangeListsSectionWriter->getSectionOffset() : 0;
+ std::vector<BucketDIEBuilder> BucketDIEBlders(PartVec.size());
+ threadTimer.startTimer();
+ std::mutex MergeQueueMutex;
+ std::condition_variable MergeQueueCV;
+ const size_t TotalTasks = PartVec.size();
+ std::vector<char> BucketDone(TotalTasks, 0);
+
+ // Inputs that every merge step reads but never mutates. Passed by const&
+ // so callees see a stable alias set.
+ BucketMergeInputs MergeIn{BC,
+ DwarfOutputPath,
+ DWOToNameMap,
+ *StrWriter,
+ *StrOffstsWriter,
+ LocListWritersByCU,
+ RangeListsSectionWriter.get(),
+ LegacyRangesSectionWriter.get()};
+ BucketMergeAccum Accum;
+
+ auto FinalizeCompileUnitsForBucket = [&](DIEBuilder &PartDIEBlder) {
+ finalizeCompileUnits(PartDIEBlder, *Streamer, OffsetMap,
+ PartDIEBlder.getProcessedCUs(), *FinalAddrWriter);
+ };
+
+ for (size_t I = 0; I < TotalTasks; ++I) {
+ if (BC.isDWARF5Used())
+ LocalWriters[I].RngListsWriter =
+ std::make_unique<DebugRangeListsSectionWriter>();
+ if (BC.isDWARFLegacyUsed())
+ LocalWriters[I].LegacyRangesWriter =
+ std::make_unique<DebugRangesSectionWriter>();
+ ThreadPool.async([&, I] {
+ std::vector<DWARFUnit *> &Vec = PartVec[I];
+ BucketDIEBuilder &BucketDIEBlder = BucketDIEBlders[I];
+ BucketDIEBlder =
+ std::make_unique<DIEBuilder>(BC, BC.DwCtx.get(), DebugNamesTable);
+ DIEBuilder &PartDIEBlder = *BucketDIEBlder;
+ PartDIEBlder.buildCompileUnits(Vec);
+
+ for (DWARFUnit *CU : PartDIEBlder.getProcessedCUs()) {
+ std::optional<DWARFUnit *> SplitCU;
+ std::optional<uint64_t> DWOId = CU->getDWOId();
+ if (DWOId)
+ SplitCU = BC.getDWOCU(*DWOId);
+ if (!SplitCU)
+ continue;
+ DebugAddrWriter &AddressWriter =
+ *AddressWritersByCU.at(CU->getOffset());
+ DebugRangesSectionWriter &TempRangesSectionWriter =
+ CU->getVersion() >= 5 ? *RangeListsWritersByCU.at(*DWOId)
+ : *LegacyRangesWritersByCU.at(*DWOId);
+ auto DWOName = DWOToNameMap.at(*DWOId);
+ auto DWODIEBuilderPtr = std::make_unique<DIEBuilder>(
+ BC, &(**SplitCU).getContext(), DebugNamesTable, CU);
+ DIEBuilder &DWODIEBuilder = *DWODIEBuilderPtr;
+ {
+ std::lock_guard<std::mutex> Lock(BuildTypeMutex);
+ DWODIEBuilder.buildTypeUnits(nullptr, true);
+ }
processSplitCU(*CU, **SplitCU, TempRangesSectionWriter, AddressWriter,
- DWOName, DwarfOutputPath, DWODIEBuilder);
- });
- }
+ DWOName, DWODIEBuilder);
+ {
+ std::lock_guard<std::mutex> Lock(DebugNamesUpdateMutex);
+ DWODIEBuilder.updateDebugNamesTable();
+ }
+ }
+
+ for (DWARFUnit *CU : PartDIEBlder.getProcessedCUs()) {
+ processMainBinaryCU(*CU, PartDIEBlder,
+ LocalWriters[I].LegacyRangesWriter
+ ? *LocalWriters[I].LegacyRangesWriter
+ : static_cast<DebugRangesSectionWriter &>(
+ *LocalWriters[I].RngListsWriter),
+ LocalWriters[I].RngListsWriter.get());
+ }
+ {
+ std::lock_guard<std::mutex> Lock(MergeQueueMutex);
+ BucketDone[I] = 1;
+ }
+ // 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();
+ });
+ }
+
+ // `SingleThreadExecutor` only runs queued tasks when `wait()` is called.
+ // With max concurrency 1 the merge loop would otherwise deadlock waiting
+ // for BucketDone[Idx] before any worker has run.
+ if (ThreadPool.getMaxConcurrency() == 1)
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);
+
+ // Buckets are merged in their natural order: this preserves the emission
+ // order used by downstream sections (notably .debug_loclists) and lets us
+ // accumulate CumulativeRngListsSize / LoclistsRunningOffset monotonically.
+ for (size_t Idx = 0; Idx < TotalTasks; ++Idx) {
+ {
+ std::unique_lock<std::mutex> Lock(MergeQueueMutex);
+ MergeQueueCV.wait(Lock, [&] { return BucketDone[Idx] != 0; });
+ }
+ mergeOneBucket(Idx, DIEBlder, BucketDIEBlders, LocalWriters, MergeIn, Accum,
+ InitialRngListsOffset, *Streamer, OffsetMap, CUOffset,
+ FinalizeCompileUnitsForBucket);
}
- DebugNamesTable.emitAccelTable();
+ ThreadPool.wait();
+ threadTimer.stopTimer();
- finalizeDebugSections(DIEBlder, DebugNamesTable, *Streamer, *ObjOS, OffsetMap,
- *FinalAddrWriter);
+ flushDebugLocAndRangeSections(*FinalAddrWriter, Accum.LocListCUOrder);
+ flushDebugStringSections(DebugNamesTable);
+ finalizeDebugSections(DIEBlder, *Streamer, *ObjOS, OffsetMap);
GDBIndexSection.updateGdbIndexSection(OffsetMap, CUIndex,
*ARangesSectionWriter);
+ AllTimer.stopTimer();
+ allTG.print(errs());
+ threadTG.print(errs());
}
void DWARFRewriter::updateUnitDebugInfo(
@@ -864,7 +1427,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,
@@ -919,7 +1482,8 @@ void DWARFRewriter::updateUnitDebugInfo(
}
updateDWARFObjectAddressRanges(
- Unit, DIEBldr, *Die, RangesSectionWriter.addRanges(FunctionRanges));
+ Unit, DIEBldr, *Die, RangesSectionWriter.addRanges(FunctionRanges),
+ AddressWriter);
break;
}
@@ -964,7 +1528,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: {
@@ -1242,7 +1807,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(
@@ -1269,7 +1833,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
@@ -1352,7 +1916,7 @@ void DWARFRewriter::updateDWARFObjectAddressRanges(
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)
@@ -1402,8 +1966,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;
@@ -1475,9 +2038,9 @@ CUOffsetMap DWARFRewriter::finalizeTypeSections(DIEBuilder &DIEBlder,
if (!CU->isTypeUnit())
continue;
updateLineTable(*CU);
- emitUnit(DIEBlder, Streamer, *CU);
- uint32_t StartOffset = CUOffset;
DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(*CU);
+ Streamer.emitUnit(*CU, *UnitDIE);
+ uint32_t StartOffset = CUOffset;
CUOffset += CU->getHeaderSize();
CUOffset += UnitDIE->getSize();
CUMap[CU->getOffset()] = {StartOffset, CUOffset - StartOffset - 4};
@@ -1507,28 +2070,8 @@ CUOffsetMap DWARFRewriter::finalizeTypeSections(DIEBuilder &DIEBlder,
return CUMap;
}
-void DWARFRewriter::finalizeDebugSections(
- DIEBuilder &DIEBlder, DWARF5AcceleratorTable &DebugNamesTable,
- DIEStreamer &Streamer, raw_svector_ostream &ObjOS, CUOffsetMap &CUMap,
- DebugAddrWriter &FinalAddrWriter) {
- if (StrWriter->isInitialized()) {
- RewriteInstance::addToDebugSectionsToOverwrite(".debug_str");
- std::unique_ptr<DebugStrBufferVector> DebugStrSectionContents =
- StrWriter->releaseBuffer();
- BC.registerOrUpdateNoteSection(".debug_str",
- copyByteArray(*DebugStrSectionContents),
- DebugStrSectionContents->size());
- }
-
- if (StrOffstsWriter->isFinalized()) {
- RewriteInstance::addToDebugSectionsToOverwrite(".debug_str_offsets");
- std::unique_ptr<DebugStrOffsetsBufferVector>
- DebugStrOffsetsSectionContents = StrOffstsWriter->releaseBuffer();
- BC.registerOrUpdateNoteSection(
- ".debug_str_offsets", copyByteArray(*DebugStrOffsetsSectionContents),
- DebugStrOffsetsSectionContents->size());
- }
-
+void DWARFRewriter::flushDebugLocAndRangeSections(
+ DebugAddrWriter &FinalAddrWriter, std::vector<uint64_t> CUOrder) {
if (BC.isDWARFLegacyUsed()) {
std::unique_ptr<DebugBufferVector> RangesSectionContents =
LegacyRangesSectionWriter->releaseBuffer();
@@ -1536,7 +2079,6 @@ void DWARFRewriter::finalizeDebugSections(
copyByteArray(*RangesSectionContents),
RangesSectionContents->size());
}
-
if (BC.isDWARF5Used()) {
std::unique_ptr<DebugBufferVector> RangesSectionContents =
RangeListsSectionWriter->releaseBuffer();
@@ -1544,25 +2086,22 @@ void DWARFRewriter::finalizeDebugSections(
copyByteArray(*RangesSectionContents),
RangesSectionContents->size());
}
-
if (BC.isDWARF5Used()) {
std::unique_ptr<DebugBufferVector> LocationListSectionContents =
- makeFinalLocListsSection(DWARFVersion::DWARF5);
+ makeFinalLocListsSection(DWARFVersion::DWARF5, CUOrder);
if (!LocationListSectionContents->empty())
BC.registerOrUpdateNoteSection(
".debug_loclists", copyByteArray(*LocationListSectionContents),
LocationListSectionContents->size());
}
-
if (BC.isDWARFLegacyUsed()) {
std::unique_ptr<DebugBufferVector> LocationListSectionContents =
- makeFinalLocListsSection(DWARFVersion::DWARFLegacy);
+ makeFinalLocListsSection(DWARFVersion::DWARFLegacy, CUOrder);
if (!LocationListSectionContents->empty())
BC.registerOrUpdateNoteSection(
".debug_loc", copyByteArray(*LocationListSectionContents),
LocationListSectionContents->size());
}
-
if (FinalAddrWriter.isInitialized()) {
std::unique_ptr<AddressSectionBuffer> AddressSectionContents =
FinalAddrWriter.releaseBuffer();
@@ -1570,16 +2109,52 @@ void DWARFRewriter::finalizeDebugSections(
copyByteArray(*AddressSectionContents),
AddressSectionContents->size());
}
+ LocListWritersByCU.clear();
+ AddressWritersByCU.clear();
+ RangeListsWritersByCU.clear();
+ LegacyRangesWritersByCU.clear();
+}
+
+void DWARFRewriter::flushDebugStringSections(
+ DWARF5AcceleratorTable &DebugNamesTable) {
+ if (StrWriter->isInitialized()) {
+ RewriteInstance::addToDebugSectionsToOverwrite(".debug_str");
+ std::unique_ptr<DebugStrBufferVector> DebugStrSectionContents =
+ StrWriter->releaseBuffer();
+ BC.registerOrUpdateNoteSection(".debug_str",
+ copyByteArray(*DebugStrSectionContents),
+ DebugStrSectionContents->size());
+ }
+ if (StrOffstsWriter->isFinalized()) {
+ RewriteInstance::addToDebugSectionsToOverwrite(".debug_str_offsets");
+ std::unique_ptr<DebugStrOffsetsBufferVector>
+ DebugStrOffsetsSectionContents = StrOffstsWriter->releaseBuffer();
+ BC.registerOrUpdateNoteSection(
+ ".debug_str_offsets", copyByteArray(*DebugStrOffsetsSectionContents),
+ DebugStrOffsetsSectionContents->size());
+ }
+ DebugNamesTable.emitAccelTable();
+ if (DebugNamesTable.isCreated()) {
+ RewriteInstance::addToDebugSectionsToOverwrite(".debug_names");
+ std::unique_ptr<DebugBufferVector> DebugNamesSectionContents =
+ DebugNamesTable.releaseBuffer();
+ BC.registerOrUpdateNoteSection(".debug_names",
+ copyByteArray(*DebugNamesSectionContents),
+ DebugNamesSectionContents->size());
+ }
+}
+void DWARFRewriter::finalizeDebugSections(DIEBuilder &DIEBlder,
+ DIEStreamer &Streamer,
+ raw_svector_ostream &ObjOS,
+ CUOffsetMap &CUMap) {
Streamer.emitAbbrevs(DIEBlder.getAbbrevs(), BC.DwCtx->getMaxVersion());
Streamer.finish();
-
std::unique_ptr<MemoryBuffer> ObjectMemBuffer =
MemoryBuffer::getMemBuffer(ObjOS.str(), "in-memory object file", false);
std::unique_ptr<object::ObjectFile> Obj = cantFail(
object::ObjectFile::createObjectFile(ObjectMemBuffer->getMemBufferRef()),
"error creating in-memory object");
-
for (const SectionRef &Secs : Obj->sections()) {
StringRef Contents = cantFail(Secs.getContents());
StringRef Name = cantFail(Secs.getName());
@@ -1591,33 +2166,19 @@ void DWARFRewriter::finalizeDebugSections(
Contents.size());
}
}
-
// Skip .debug_aranges if we are re-generating .gdb_index.
if (opts::KeepARanges || !BC.getGdbIndexSection()) {
SmallVector<char, 16> ARangesBuffer;
raw_svector_ostream OS(ARangesBuffer);
-
auto MAB = std::unique_ptr<MCAsmBackend>(
BC.TheTarget->createMCAsmBackend(*BC.STI, *BC.MRI, MCTargetOptions()));
-
ARangesSectionWriter->writeARangesSection(OS, CUMap);
const StringRef &ARangesContents = OS.str();
-
BC.registerOrUpdateNoteSection(".debug_aranges",
copyByteArray(ARangesContents),
ARangesContents.size());
}
-
- if (DebugNamesTable.isCreated()) {
- RewriteInstance::addToDebugSectionsToOverwrite(".debug_names");
- std::unique_ptr<DebugBufferVector> DebugNamesSectionContents =
- DebugNamesTable.releaseBuffer();
- BC.registerOrUpdateNoteSection(".debug_names",
- copyByteArray(*DebugNamesSectionContents),
- DebugNamesSectionContents->size());
- }
}
-
void DWARFRewriter::finalizeCompileUnits(DIEBuilder &DIEBlder,
DIEStreamer &Streamer,
CUOffsetMap &CUMap,
@@ -1663,18 +2224,6 @@ void DWARFRewriter::finalizeCompileUnits(DIEBuilder &DIEBlder,
LegacyRangesWriter->releaseBuffer();
LegacyRangesSectionWriter->appendToRangeBuffer(*RangesWritersContents);
}
- DIEBlder.generateAbbrevs();
- DIEBlder.finish();
- DIEBlder.updateDebugNamesTable();
- // generate debug_info and CUMap
- for (DWARFUnit *CU : CUs) {
- emitUnit(DIEBlder, Streamer, *CU);
- const uint32_t StartOffset = CUOffset;
- DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(*CU);
- CUOffset += CU->getHeaderSize();
- CUOffset += UnitDIE->getSize();
- CUMap[CU->getOffset()] = {StartOffset, CUOffset - StartOffset - 4};
- }
}
// Creates all the data structures necessary for creating MCStreamer.
@@ -2019,32 +2568,50 @@ void DWARFRewriter::writeDWOFiles(
}
std::unique_ptr<DebugBufferVector>
-DWARFRewriter::makeFinalLocListsSection(DWARFVersion Version) {
+DWARFRewriter::makeFinalLocListsSection(DWARFVersion Version,
+ std::vector<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 &&
(!LocListWriter || LocListWriter->getDwarfVersion() <= 4))
continue;
- // Filter out DWARF5, writing out DWARF4
if (Version == DWARFVersion::DWARFLegacy &&
(LocListWriter && LocListWriter->getDwarfVersion() >= 5))
continue;
- // 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) and skip
+ // the per-CU prefix so that per-CU offsets rebased via
+ // LocListMergeState::LegacyLocRunningOffset remain valid.
+ if (Version == DWARFVersion::DWARFLegacy) {
+ if (CurrCULocationLists->size() > 16)
+ *LocStream << StringRef(
+ reinterpret_cast<const char *>(CurrCULocationLists->data() + 16),
+ CurrCULocationLists->size() - 16);
+ continue;
+ }
+
*LocStream << *CurrCULocationLists;
}
@@ -2054,7 +2621,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;
@@ -2075,11 +2643,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 {
>From ed6e6c34c7d24b145c825be29e95e7ed78b42491 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Mon, 27 Apr 2026 14:14:48 +0800
Subject: [PATCH 2/6] [BOLT][DebugInfo] fixup partitionCUs() and abbrev test
---
bolt/lib/Rewrite/DWARFRewriter.cpp | 121 +++++-------------
...f4-cross-cu-backward-different-abbrev.test | 2 +-
2 files changed, 34 insertions(+), 89 deletions(-)
diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp
index e29e24858a6e3..0cd31b4fea2f3 100644
--- a/bolt/lib/Rewrite/DWARFRewriter.cpp
+++ b/bolt/lib/Rewrite/DWARFRewriter.cpp
@@ -661,10 +661,7 @@ static CUPartitionVector partitionCUs(DWARFContext &DwCtx) {
return nullptr;
return *--It;
};
- // Track CUs that contain DW_FORM_ref_addr (referrers) and all CUs that are
- // either referrers or ref targets.
- SmallVector<DWARFUnit *> CrossRefCUs;
- DenseSet<DWARFUnit *> ReferrerSet;
+
DenseSet<DWARFUnit *> CrossRefSet;
EquivalenceClasses<DWARFUnit *> EC;
for (DWARFUnit *CU : AllCUs) {
@@ -681,6 +678,7 @@ static CUPartitionVector partitionCUs(DWARFContext &DwCtx) {
if (RefAddrAbbrevs.empty())
continue;
bool HasCrossRef = false;
+ // 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 =
@@ -708,101 +706,50 @@ static CUPartitionVector partitionCUs(DWARFContext &DwCtx) {
if (!HasCrossRef)
continue;
- // Ensure standalone referrers (e.g. malformed refs) still end up in their
- // own singleton equivalence class.
if (CrossRefSet.insert(CU).second)
EC.insert(CU);
-
- if (ReferrerSet.insert(CU).second)
- CrossRefCUs.push_back(CU);
- }
- CUPartitionVector Vec;
- // Decide per-equivalence-class ordering policy.
- // - DWARF4 classes: keep referrers first (needed for backward-ref tests).
- // - DWARF5+ classes: keep original CU order to preserve stable abbrev/DIE
- // layout expected by existing tests.
- DenseMap<DWARFUnit *, bool> LeaderHasDWARF4;
- for (DWARFUnit *CU : AllCUs) {
- if (!CrossRefSet.count(CU))
- continue;
- DWARFUnit *Leader = EC.getLeaderValue(CU);
- LeaderHasDWARF4[Leader] |= (CU->getVersion() <= 4);
}
- // Snapshot membership once so we don't need multiple near-identical passes
- // that keep checking CrossRefSet / Added.
- DenseMap<DWARFUnit *, SmallVector<DWARFUnit *, 8>> MembersByLeader;
- DenseMap<DWARFUnit *, SmallVector<DWARFUnit *, 4>> ReferrersByLeader;
+ DenseMap<DWARFUnit *, std::vector<DWARFUnit *>> MembersByLeader;
for (DWARFUnit *CU : AllCUs) {
if (!CrossRefSet.count(CU))
continue;
MembersByLeader[EC.getLeaderValue(CU)].push_back(CU);
}
- for (DWARFUnit *CU : CrossRefCUs)
- ReferrersByLeader[EC.getLeaderValue(CU)].push_back(CU);
- // Establish bucket order for each policy.
- SmallVector<DWARFUnit *, 0> DWARF5LeadersInOrder;
- DenseSet<DWARFUnit *> SeenDWARF5Leaders;
+ // // Sort members within each bucket by CU offset.
+ // auto SortByOffset = [](DWARFUnit *A, DWARFUnit *B) {
+ // return A->getOffset() < B->getOffset();
+ // };
+ // for (auto &[Leader, Members] : MembersByLeader)
+ // llvm::sort(Members, SortByOffset);
+
+ 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.
+ CUPartitionVector Vec;
+ for (DWARFUnit *Leader : Leaders)
+ Vec.push_back(std::move(MembersByLeader[Leader]));
+ std::vector<DWARFUnit *> PendingSingletons;
for (DWARFUnit *CU : AllCUs) {
- if (!CrossRefSet.count(CU))
- continue;
- DWARFUnit *Leader = EC.getLeaderValue(CU);
- if (LeaderHasDWARF4.lookup(Leader))
- continue;
- if (SeenDWARF5Leaders.insert(Leader).second)
- DWARF5LeadersInOrder.push_back(Leader);
- }
- SmallVector<DWARFUnit *, 0> DWARF4LeadersInOrder;
- DenseSet<DWARFUnit *> SeenDWARF4Leaders;
- for (DWARFUnit *CU : CrossRefCUs) {
- DWARFUnit *Leader = EC.getLeaderValue(CU);
- if (!LeaderHasDWARF4.lookup(Leader))
- continue;
- if (SeenDWARF4Leaders.insert(Leader).second)
- DWARF4LeadersInOrder.push_back(Leader);
+ if (!CrossRefSet.count(CU)) {
+ PendingSingletons.push_back(CU);
+ if (PendingSingletons.size() >= opts::BatchSize) {
+ Vec.push_back(std::move(PendingSingletons));
+ PendingSingletons = {};
+ }
+ }
}
+ if (!PendingSingletons.empty())
+ Vec.push_back(std::move(PendingSingletons));
- // Emit buckets.
- auto appendBucketForLeader = [&](DWARFUnit *Leader) {
- auto MemIt = MembersByLeader.find(Leader);
- assert(MemIt != MembersByLeader.end() &&
- "Cross-ref leader without members");
-
- DWARFUnitVec Bucket;
- const bool HasDWARF4 = LeaderHasDWARF4.lookup(Leader);
- if (!HasDWARF4) {
- Bucket.assign(MemIt->second.begin(), MemIt->second.end());
- Vec.push_back(std::move(Bucket));
- return;
- }
-
- // DWARF4+: referrers first (discovery order), then remaining members
- // (targets-only) in original CU order.
- auto RefIt = ReferrersByLeader.find(Leader);
- Bucket.reserve(MemIt->second.size());
- if (RefIt != ReferrersByLeader.end())
- Bucket.insert(Bucket.end(), RefIt->second.begin(), RefIt->second.end());
- for (DWARFUnit *CU : MemIt->second)
- if (!ReferrerSet.count(CU))
- Bucket.push_back(CU);
- assert(Bucket.size() == MemIt->second.size() &&
- "Bucket ordering lost or duplicated members");
- Vec.push_back(std::move(Bucket));
- };
-
- // Keep the historical policy split: all DWARF5+ cross-ref buckets first,
- // then DWARF4 buckets.
- for (DWARFUnit *Leader : DWARF5LeadersInOrder)
- appendBucketForLeader(Leader);
- for (DWARFUnit *Leader : DWARF4LeadersInOrder)
- appendBucketForLeader(Leader);
-
- // Finally, append non-cross-ref CUs as singleton buckets in original CU
- // order.
- for (DWARFUnit *CU : AllCUs)
- if (!CrossRefSet.count(CU))
- Vec.push_back({CU});
return Vec;
}
@@ -1225,7 +1172,6 @@ void DWARFRewriter::updateDebugInfo() {
const uint64_t InitialRngListsOffset =
RangeListsSectionWriter ? RangeListsSectionWriter->getSectionOffset() : 0;
std::vector<BucketDIEBuilder> BucketDIEBlders(PartVec.size());
- threadTimer.startTimer();
std::mutex MergeQueueMutex;
std::condition_variable MergeQueueCV;
const size_t TotalTasks = PartVec.size();
@@ -1329,7 +1275,6 @@ void DWARFRewriter::updateDebugInfo() {
}
ThreadPool.wait();
- threadTimer.stopTimer();
flushDebugLocAndRangeSections(*FinalAddrWriter, Accum.LocListCUOrder);
flushDebugStringSections(DebugNamesTable);
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
>From 1780a6cd92e9ce717c7b3c87f8a7bc8cc0104325 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Wed, 29 Apr 2026 16:51:58 +0800
Subject: [PATCH 3/6] [BOLT][DebugInfo] reduce additional code
---
bolt/include/bolt/Rewrite/DWARFRewriter.h | 11 +-
bolt/lib/Core/DIEBuilder.cpp | 10 +-
bolt/lib/Core/DebugNames.cpp | 8 +-
bolt/lib/Rewrite/DWARFRewriter.cpp | 183 ++++++++----------
.../X86/dwarf5-df-types-dup-dwp-input.test | 2 +-
5 files changed, 95 insertions(+), 119 deletions(-)
diff --git a/bolt/include/bolt/Rewrite/DWARFRewriter.h b/bolt/include/bolt/Rewrite/DWARFRewriter.h
index a2e24b15a318b..ddf03ee81632c 100644
--- a/bolt/include/bolt/Rewrite/DWARFRewriter.h
+++ b/bolt/include/bolt/Rewrite/DWARFRewriter.h
@@ -140,11 +140,12 @@ class DWARFRewriter {
DebugAddrWriter &FinalAddrWriter);
/// Finalize debug sections in the main binary.
- void finalizeDebugSections(DIEBuilder &DIEBlder, DIEStreamer &Streamer,
- raw_svector_ostream &ObjOS, CUOffsetMap &CUMap);
- void flushDebugLocAndRangeSections(DebugAddrWriter &FinalAddrWriter,
- std::vector<uint64_t> CUOrder);
- void flushDebugStringSections(DWARF5AcceleratorTable &DebugNamesTable);
+ void finalizeDebugSections(DIEBuilder &DIEBlder,
+ DWARF5AcceleratorTable &DebugNamesTable,
+ DIEStreamer &Streamer, raw_svector_ostream &ObjOS,
+ CUOffsetMap &CUMap,
+ DebugAddrWriter &FinalAddrWriter,
+ std::vector<uint64_t> SortedCU);
/// Patches the binary for DWARF address ranges (e.g. in functions and lexical
/// blocks) to be updated.
diff --git a/bolt/lib/Core/DIEBuilder.cpp b/bolt/lib/Core/DIEBuilder.cpp
index b62f0244bc14e..e807011c11bb3 100644
--- a/bolt/lib/Core/DIEBuilder.cpp
+++ b/bolt/lib/Core/DIEBuilder.cpp
@@ -274,6 +274,11 @@ static unsigned int getCUNum(DWARFContext *DwarfContext, bool IsDWO) {
void DIEBuilder::buildTypeUnits(DebugStrOffsetsWriter *StrOffsetWriter,
const bool Init) {
+ static std::mutex DWOTypeUnitsBuildMutex;
+ std::unique_lock<std::mutex> DWOTypeUnitsBuildLock(DWOTypeUnitsBuildMutex,
+ std::defer_lock);
+ if (isDWO())
+ DWOTypeUnitsBuildLock.lock();
if (Init)
BuilderState.reset(new State());
@@ -362,8 +367,9 @@ void DIEBuilder::buildCompileUnits(const std::vector<DWARFUnit *> &CUs) {
}
void DIEBuilder::buildDWOUnit(DWARFUnit &U) {
- if (!BuilderState)
- BuilderState = std::make_unique<State>();
+ BuilderState.release();
+ BuilderState = std::make_unique<State>();
+ buildTypeUnits(nullptr, false);
getState().Type = ProcessingType::CUs;
registerUnit(U, false);
constructFromUnit(U);
diff --git a/bolt/lib/Core/DebugNames.cpp b/bolt/lib/Core/DebugNames.cpp
index 04e37c38928b7..508f264cb4b51 100644
--- a/bolt/lib/Core/DebugNames.cpp
+++ b/bolt/lib/Core/DebugNames.cpp
@@ -567,13 +567,9 @@ void DWARF5AcceleratorTable::finalize() {
: std::numeric_limits<unsigned>::max();
};
return std::make_tuple(LHS->getDieOffset(), GetCompileUnitKey(LHS),
- GetTypeUnitKey(LHS), LHS->getDieTag(),
- LHS->isParentRoot(),
- LHS->getParentDieOffset()) <
+ GetTypeUnitKey(LHS)) <
std::make_tuple(RHS->getDieOffset(), GetCompileUnitKey(RHS),
- GetTypeUnitKey(RHS), RHS->getDieTag(),
- RHS->isParentRoot(),
- RHS->getParentDieOffset());
+ GetTypeUnitKey(RHS));
});
}
diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp
index 0cd31b4fea2f3..1dc3b6580c0e6 100644
--- a/bolt/lib/Rewrite/DWARFRewriter.cpp
+++ b/bolt/lib/Rewrite/DWARFRewriter.cpp
@@ -104,7 +104,7 @@ namespace {
using DWARFUnitVec = std::vector<DWARFUnit *>;
using CUPartitionVector = std::vector<DWARFUnitVec>;
-struct BucketLocalWriters {
+struct BucketLocalWriter {
std::unique_ptr<DebugRangeListsSectionWriter> RngListsWriter;
std::unique_ptr<DebugRangesSectionWriter> LegacyRangesWriter;
@@ -152,11 +152,8 @@ DWARFRewriter::getOrCreateDebugInfoThreadPool(unsigned ThreadsCount) {
if (DebugInfoThreadPool)
return *DebugInfoThreadPool;
- if (ThreadsCount > 1)
- DebugInfoThreadPool = std::make_unique<DefaultThreadPool>(
- llvm::hardware_concurrency(ThreadsCount));
- else
- DebugInfoThreadPool = std::make_unique<SingleThreadExecutor>();
+ DebugInfoThreadPool = std::make_unique<DefaultThreadPool>(
+ llvm::hardware_concurrency(ThreadsCount));
return *DebugInfoThreadPool;
}
@@ -732,23 +729,18 @@ static CUPartitionVector partitionCUs(DWARFContext &DwCtx) {
return MembersByLeader[A].front()->getOffset() <
MembersByLeader[B].front()->getOffset();
});
-
+ // llvm::sort(AllCUs,[&](DWARFUnit *A, DWARFUnit *B){
+ // return A->getLength() < B->getLength();
+ // });
// Emit cross-ref buckets, then singleton non-cross-ref CUs.
CUPartitionVector Vec;
for (DWARFUnit *Leader : Leaders)
Vec.push_back(std::move(MembersByLeader[Leader]));
- std::vector<DWARFUnit *> PendingSingletons;
for (DWARFUnit *CU : AllCUs) {
if (!CrossRefSet.count(CU)) {
- PendingSingletons.push_back(CU);
- if (PendingSingletons.size() >= opts::BatchSize) {
- Vec.push_back(std::move(PendingSingletons));
- PendingSingletons = {};
- }
+ Vec.push_back({CU});
}
}
- if (!PendingSingletons.empty())
- Vec.push_back(std::move(PendingSingletons));
return Vec;
}
@@ -909,7 +901,7 @@ static void mergePerBucketLocsAndRanges(DIEBuilder &PartDIEBlder,
/// no extra copy+sort is needed.
static void appendBucketRangeBuffers(DIEBuilder &PartDIEBlder,
ArrayRef<DWARFUnit *> SortedCUs,
- BucketLocalWriters &LocalWriters,
+ BucketLocalWriter &LocalWriters,
const BucketMergeInputs &In,
BucketMergeAccum &Accum) {
if (LocalWriters.RngListsWriter && In.RangeListsSectionWriter) {
@@ -965,7 +957,7 @@ static void emitBucketCompileUnits(DIEBuilder &PartDIEBlder,
/// sort-passes that the earlier 7-helper split introduced.
static void mergeOneBucket(size_t Idx, DIEBuilder &MainDIEBuilder,
std::vector<BucketDIEBuilder> &BucketDIEBlders,
- std::vector<BucketLocalWriters> &LocalWriters,
+ std::vector<BucketLocalWriter> &LocalWriters,
BucketMergeInputs &In, BucketMergeAccum &Accum,
uint64_t InitialRngListsOffset,
DIEStreamer &Streamer, CUOffsetMap &OffsetMap,
@@ -1114,14 +1106,18 @@ void DWARFRewriter::updateDebugInfo() {
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,
- DebugRangesSectionWriter &LocalRangesWriter,
- DebugRangeListsSectionWriter *LocalRngListsWriter) {
+ [&](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());
@@ -1132,23 +1128,27 @@ void DWARFRewriter::updateDebugInfo() {
assert(AddrIt != AddressWritersByCU.end() &&
"AddressWriter does not exist for CU");
DebugAddrWriter &AddressWriter = *AddrIt->second.get();
+ if (DWARFVersion >= 5)
+ LocalWriter.RngListsWriter = std::make_unique<DebugRangeListsSectionWriter>();
+ else
+ LocalWriter.LegacyRangesWriter = std::make_unique<DebugRangesSectionWriter>();
DebugRangesSectionWriter &RangesSectionWriter =
- Unit.getVersion() >= 5
- ? static_cast<DebugRangesSectionWriter &>(*LocalRngListsWriter)
- : LocalRangesWriter;
- if (Unit.getVersion() >= 5) {
- LocalRngListsWriter->setAddressWriter(&AddressWriter);
+ DWARFVersion >= 5 ? *LocalWriter.RngListsWriter
+ : *LocalWriter.LegacyRangesWriter;
+
+ if (DWARFVersion >= 5) {
+ LocalWriter.RngListsWriter->setAddressWriter(&AddressWriter);
RangesBase = RangesSectionWriter.getSectionOffset() +
getDWARF5RngListLocListHeaderSize();
RangesSectionWriter.initSection(Unit);
} else if (SplitCU) {
- RangesBase = RangesSectionWriter.getSectionOffset();
+ RangesBase = LocalWriter.LegacyRangesWriter->getSectionOffset();
}
updateUnitDebugInfo(Unit, DIEBlder, DebugLocWriter, RangesSectionWriter,
AddressWriter, RangesBase);
DebugLocWriter.finalize(DIEBlder, *DIEBlder.getUnitDIEbyUnit(Unit));
- if (Unit.getVersion() >= 5)
+ if (DWARFVersion >= 5)
RangesSectionWriter.finalizeSection();
};
@@ -1164,11 +1164,12 @@ void DWARFRewriter::updateDebugInfo() {
CUOffsetMap OffsetMap =
finalizeTypeSections(DIEBlder, *Streamer, GDBIndexSection);
CUPartitionVector PartVec = partitionCUs(*BC.DwCtx);
+ errs() << "bucket size :" << PartVec.size() << "\n";
const unsigned int ThreadCount =
std::min(opts::DebugThreadCount, opts::ThreadCount);
llvm::ThreadPoolInterface &ThreadPool =
getOrCreateDebugInfoThreadPool(ThreadCount);
- std::vector<BucketLocalWriters> LocalWriters(PartVec.size());
+ std::vector<BucketLocalWriter> LocalWriters(PartVec.size());
const uint64_t InitialRngListsOffset =
RangeListsSectionWriter ? RangeListsSectionWriter->getSectionOffset() : 0;
std::vector<BucketDIEBuilder> BucketDIEBlders(PartVec.size());
@@ -1193,14 +1194,7 @@ void DWARFRewriter::updateDebugInfo() {
finalizeCompileUnits(PartDIEBlder, *Streamer, OffsetMap,
PartDIEBlder.getProcessedCUs(), *FinalAddrWriter);
};
-
for (size_t I = 0; I < TotalTasks; ++I) {
- if (BC.isDWARF5Used())
- LocalWriters[I].RngListsWriter =
- std::make_unique<DebugRangeListsSectionWriter>();
- if (BC.isDWARFLegacyUsed())
- LocalWriters[I].LegacyRangesWriter =
- std::make_unique<DebugRangesSectionWriter>();
ThreadPool.async([&, I] {
std::vector<DWARFUnit *> &Vec = PartVec[I];
BucketDIEBuilder &BucketDIEBlder = BucketDIEBlders[I];
@@ -1225,26 +1219,11 @@ void DWARFRewriter::updateDebugInfo() {
auto DWODIEBuilderPtr = std::make_unique<DIEBuilder>(
BC, &(**SplitCU).getContext(), DebugNamesTable, CU);
DIEBuilder &DWODIEBuilder = *DWODIEBuilderPtr;
- {
- std::lock_guard<std::mutex> Lock(BuildTypeMutex);
- DWODIEBuilder.buildTypeUnits(nullptr, true);
- }
processSplitCU(*CU, **SplitCU, TempRangesSectionWriter, AddressWriter,
DWOName, DWODIEBuilder);
- {
- std::lock_guard<std::mutex> Lock(DebugNamesUpdateMutex);
- DWODIEBuilder.updateDebugNamesTable();
- }
- }
-
- for (DWARFUnit *CU : PartDIEBlder.getProcessedCUs()) {
- processMainBinaryCU(*CU, PartDIEBlder,
- LocalWriters[I].LegacyRangesWriter
- ? *LocalWriters[I].LegacyRangesWriter
- : static_cast<DebugRangesSectionWriter &>(
- *LocalWriters[I].RngListsWriter),
- LocalWriters[I].RngListsWriter.get());
}
+ for (DWARFUnit *CU : PartDIEBlder.getProcessedCUs())
+ processMainBinaryCU(*CU, PartDIEBlder, LocalWriters[I]);
{
std::lock_guard<std::mutex> Lock(MergeQueueMutex);
BucketDone[I] = 1;
@@ -1254,13 +1233,7 @@ void DWARFRewriter::updateDebugInfo() {
MergeQueueCV.notify_one();
});
}
-
- // `SingleThreadExecutor` only runs queued tasks when `wait()` is called.
- // With max concurrency 1 the merge loop would otherwise deadlock waiting
- // for BucketDone[Idx] before any worker has run.
- if (ThreadPool.getMaxConcurrency() == 1)
- ThreadPool.wait();
-
+
// Buckets are merged in their natural order: this preserves the emission
// order used by downstream sections (notably .debug_loclists) and lets us
// accumulate CumulativeRngListsSize / LoclistsRunningOffset monotonically.
@@ -1275,10 +1248,9 @@ void DWARFRewriter::updateDebugInfo() {
}
ThreadPool.wait();
-
- flushDebugLocAndRangeSections(*FinalAddrWriter, Accum.LocListCUOrder);
- flushDebugStringSections(DebugNamesTable);
- finalizeDebugSections(DIEBlder, *Streamer, *ObjOS, OffsetMap);
+ DebugNamesTable.emitAccelTable();
+ finalizeDebugSections(DIEBlder, DebugNamesTable, *Streamer, *ObjOS, OffsetMap,
+ *FinalAddrWriter, Accum.LocListCUOrder);
GDBIndexSection.updateGdbIndexSection(OffsetMap, CUIndex,
*ARangesSectionWriter);
AllTimer.stopTimer();
@@ -2015,8 +1987,28 @@ CUOffsetMap DWARFRewriter::finalizeTypeSections(DIEBuilder &DIEBlder,
return CUMap;
}
-void DWARFRewriter::flushDebugLocAndRangeSections(
- DebugAddrWriter &FinalAddrWriter, std::vector<uint64_t> CUOrder) {
+void DWARFRewriter::finalizeDebugSections(
+ DIEBuilder &DIEBlder, DWARF5AcceleratorTable &DebugNamesTable,
+ DIEStreamer &Streamer, raw_svector_ostream &ObjOS, CUOffsetMap &CUMap,
+ DebugAddrWriter &FinalAddrWriter, std::vector<uint64_t> SortedCU) {
+ if (StrWriter->isInitialized()) {
+ RewriteInstance::addToDebugSectionsToOverwrite(".debug_str");
+ std::unique_ptr<DebugStrBufferVector> DebugStrSectionContents =
+ StrWriter->releaseBuffer();
+ BC.registerOrUpdateNoteSection(".debug_str",
+ copyByteArray(*DebugStrSectionContents),
+ DebugStrSectionContents->size());
+ }
+
+ if (StrOffstsWriter->isFinalized()) {
+ RewriteInstance::addToDebugSectionsToOverwrite(".debug_str_offsets");
+ std::unique_ptr<DebugStrOffsetsBufferVector>
+ DebugStrOffsetsSectionContents = StrOffstsWriter->releaseBuffer();
+ BC.registerOrUpdateNoteSection(
+ ".debug_str_offsets", copyByteArray(*DebugStrOffsetsSectionContents),
+ DebugStrOffsetsSectionContents->size());
+ }
+
if (BC.isDWARFLegacyUsed()) {
std::unique_ptr<DebugBufferVector> RangesSectionContents =
LegacyRangesSectionWriter->releaseBuffer();
@@ -2024,6 +2016,7 @@ void DWARFRewriter::flushDebugLocAndRangeSections(
copyByteArray(*RangesSectionContents),
RangesSectionContents->size());
}
+
if (BC.isDWARF5Used()) {
std::unique_ptr<DebugBufferVector> RangesSectionContents =
RangeListsSectionWriter->releaseBuffer();
@@ -2031,22 +2024,25 @@ void DWARFRewriter::flushDebugLocAndRangeSections(
copyByteArray(*RangesSectionContents),
RangesSectionContents->size());
}
+
if (BC.isDWARF5Used()) {
std::unique_ptr<DebugBufferVector> LocationListSectionContents =
- makeFinalLocListsSection(DWARFVersion::DWARF5, CUOrder);
+ makeFinalLocListsSection(DWARFVersion::DWARF5,SortedCU);
if (!LocationListSectionContents->empty())
BC.registerOrUpdateNoteSection(
".debug_loclists", copyByteArray(*LocationListSectionContents),
LocationListSectionContents->size());
}
+
if (BC.isDWARFLegacyUsed()) {
std::unique_ptr<DebugBufferVector> LocationListSectionContents =
- makeFinalLocListsSection(DWARFVersion::DWARFLegacy, CUOrder);
+ makeFinalLocListsSection(DWARFVersion::DWARFLegacy, SortedCU);
if (!LocationListSectionContents->empty())
BC.registerOrUpdateNoteSection(
".debug_loc", copyByteArray(*LocationListSectionContents),
LocationListSectionContents->size());
}
+
if (FinalAddrWriter.isInitialized()) {
std::unique_ptr<AddressSectionBuffer> AddressSectionContents =
FinalAddrWriter.releaseBuffer();
@@ -2054,52 +2050,16 @@ void DWARFRewriter::flushDebugLocAndRangeSections(
copyByteArray(*AddressSectionContents),
AddressSectionContents->size());
}
- LocListWritersByCU.clear();
- AddressWritersByCU.clear();
- RangeListsWritersByCU.clear();
- LegacyRangesWritersByCU.clear();
-}
-
-void DWARFRewriter::flushDebugStringSections(
- DWARF5AcceleratorTable &DebugNamesTable) {
- if (StrWriter->isInitialized()) {
- RewriteInstance::addToDebugSectionsToOverwrite(".debug_str");
- std::unique_ptr<DebugStrBufferVector> DebugStrSectionContents =
- StrWriter->releaseBuffer();
- BC.registerOrUpdateNoteSection(".debug_str",
- copyByteArray(*DebugStrSectionContents),
- DebugStrSectionContents->size());
- }
- if (StrOffstsWriter->isFinalized()) {
- RewriteInstance::addToDebugSectionsToOverwrite(".debug_str_offsets");
- std::unique_ptr<DebugStrOffsetsBufferVector>
- DebugStrOffsetsSectionContents = StrOffstsWriter->releaseBuffer();
- BC.registerOrUpdateNoteSection(
- ".debug_str_offsets", copyByteArray(*DebugStrOffsetsSectionContents),
- DebugStrOffsetsSectionContents->size());
- }
- DebugNamesTable.emitAccelTable();
- if (DebugNamesTable.isCreated()) {
- RewriteInstance::addToDebugSectionsToOverwrite(".debug_names");
- std::unique_ptr<DebugBufferVector> DebugNamesSectionContents =
- DebugNamesTable.releaseBuffer();
- BC.registerOrUpdateNoteSection(".debug_names",
- copyByteArray(*DebugNamesSectionContents),
- DebugNamesSectionContents->size());
- }
-}
-void DWARFRewriter::finalizeDebugSections(DIEBuilder &DIEBlder,
- DIEStreamer &Streamer,
- raw_svector_ostream &ObjOS,
- CUOffsetMap &CUMap) {
Streamer.emitAbbrevs(DIEBlder.getAbbrevs(), BC.DwCtx->getMaxVersion());
Streamer.finish();
+
std::unique_ptr<MemoryBuffer> ObjectMemBuffer =
MemoryBuffer::getMemBuffer(ObjOS.str(), "in-memory object file", false);
std::unique_ptr<object::ObjectFile> Obj = cantFail(
object::ObjectFile::createObjectFile(ObjectMemBuffer->getMemBufferRef()),
"error creating in-memory object");
+
for (const SectionRef &Secs : Obj->sections()) {
StringRef Contents = cantFail(Secs.getContents());
StringRef Name = cantFail(Secs.getName());
@@ -2111,18 +2071,31 @@ void DWARFRewriter::finalizeDebugSections(DIEBuilder &DIEBlder,
Contents.size());
}
}
+
// Skip .debug_aranges if we are re-generating .gdb_index.
if (opts::KeepARanges || !BC.getGdbIndexSection()) {
SmallVector<char, 16> ARangesBuffer;
raw_svector_ostream OS(ARangesBuffer);
+
auto MAB = std::unique_ptr<MCAsmBackend>(
BC.TheTarget->createMCAsmBackend(*BC.STI, *BC.MRI, MCTargetOptions()));
+
ARangesSectionWriter->writeARangesSection(OS, CUMap);
const StringRef &ARangesContents = OS.str();
+
BC.registerOrUpdateNoteSection(".debug_aranges",
copyByteArray(ARangesContents),
ARangesContents.size());
}
+
+ if (DebugNamesTable.isCreated()) {
+ RewriteInstance::addToDebugSectionsToOverwrite(".debug_names");
+ std::unique_ptr<DebugBufferVector> DebugNamesSectionContents =
+ DebugNamesTable.releaseBuffer();
+ BC.registerOrUpdateNoteSection(".debug_names",
+ copyByteArray(*DebugNamesSectionContents),
+ DebugNamesSectionContents->size());
+ }
}
void DWARFRewriter::finalizeCompileUnits(DIEBuilder &DIEBlder,
DIEStreamer &Streamer,
diff --git a/bolt/test/X86/dwarf5-df-types-dup-dwp-input.test b/bolt/test/X86/dwarf5-df-types-dup-dwp-input.test
index 754f05dc96328..48209756ac173 100644
--- a/bolt/test/X86/dwarf5-df-types-dup-dwp-input.test
+++ b/bolt/test/X86/dwarf5-df-types-dup-dwp-input.test
@@ -7,7 +7,7 @@
; RUN: -split-dwarf-file=helper.dwo -o helper.o
; RUN: %clang %cflags -gdwarf-5 -gsplit-dwarf=split main.o helper.o -o main.exe
; RUN: llvm-dwp -e main.exe -o main.exe.dwp
-; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections
+; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections --debug-thread-count=4
; RUN: llvm-dwarfdump --debug-info -r 0 main.dwo.dwo | FileCheck -check-prefix=BOLT-DWO-DWO-MAIN %s
; RUN: llvm-dwarfdump --debug-info -r 0 helper.dwo.dwo | FileCheck -check-prefix=BOLT-DWO-DWO-HELPER %s
>From 93edaec0721e54aa3a64cca9ef4be599e3299043 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Wed, 29 Apr 2026 20:50:14 +0800
Subject: [PATCH 4/6] BOLT][DebugInfo] review code
---
bolt/include/bolt/Rewrite/DWARFRewriter.h | 42 +-
bolt/lib/Rewrite/DWARFRewriter.cpp | 482 +++++++++-------------
2 files changed, 226 insertions(+), 298 deletions(-)
diff --git a/bolt/include/bolt/Rewrite/DWARFRewriter.h b/bolt/include/bolt/Rewrite/DWARFRewriter.h
index ddf03ee81632c..a458ea729c1d5 100644
--- a/bolt/include/bolt/Rewrite/DWARFRewriter.h
+++ b/bolt/include/bolt/Rewrite/DWARFRewriter.h
@@ -41,6 +41,23 @@ class DWARFRewriter {
uint64_t TypeHash;
uint64_t TypeDIERelativeOffset;
};
+ struct BucketMergeAccum {
+ uint64_t CumulativeRngListsSize = 0;
+ uint64_t LoclistsRunningOffset = 0;
+ uint64_t LegacyLocRunningOffset = 0;
+ std::vector<uint64_t> LocListCUOrder;
+ };
+ struct BucketLocalWriter {
+ std::unique_ptr<DebugRangeListsSectionWriter> RngListsWriter;
+ std::unique_ptr<DebugRangesSectionWriter> LegacyRangesWriter;
+
+ /// Release both writers at once. Called when the bucket has been fully
+ /// merged into the global DWARF section writers.
+ void clear() {
+ RngListsWriter.reset();
+ LegacyRangesWriter.reset();
+ }
+ };
private:
BinaryContext &BC;
@@ -128,14 +145,33 @@ class DWARFRewriter {
std::unique_ptr<DebugBufferVector>
makeFinalLocListsSection(DWARFVersion Version, std::vector<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 finalizeSkeletonAndStrOffsets(
+ DIEBuilder &PartDIEBlder,
+ const std::optional<std::string> &DwarfOutputPath,
+ std::unordered_map<uint64_t, std::string> DWOToNameMap);
+
+ /// Merge Bucket locs section and ranges section result
+ void mergePerBucketLocsAndRanges(
+ DIEBuilder &PartDIEBlder, ArrayRef<DWARFUnit *> SortedCUs,
+ const std::optional<std::string> &DwarfOutputPath,
+ std::unordered_map<uint64_t, std::string> DWOToNameMap,
+ uint64_t DeltaDWARF5, BucketMergeAccum &Accum);
+
+ /// append buffers to RangeListsSectionWriter/LegacyRangesSectionWriter
+ void appendBucketRangeBuffers(DIEBuilder &PartDIEBlder,
+ ArrayRef<DWARFUnit *> SortedCUs,
+ BucketLocalWriter &LocalWriters,
+ BucketMergeAccum &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);
diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp
index 1dc3b6580c0e6..da0570c18121d 100644
--- a/bolt/lib/Rewrite/DWARFRewriter.cpp
+++ b/bolt/lib/Rewrite/DWARFRewriter.cpp
@@ -99,51 +99,6 @@ static void printDie(DWARFUnit &DU, uint64_t DIEOffset) {
using namespace bolt;
-namespace {
-
-using DWARFUnitVec = std::vector<DWARFUnit *>;
-using CUPartitionVector = std::vector<DWARFUnitVec>;
-
-struct BucketLocalWriter {
- std::unique_ptr<DebugRangeListsSectionWriter> RngListsWriter;
- std::unique_ptr<DebugRangesSectionWriter> LegacyRangesWriter;
-
- /// Release both writers at once. Called when the bucket has been fully
- /// merged into the global DWARF section writers.
- void clear() {
- RngListsWriter.reset();
- LegacyRangesWriter.reset();
- }
-};
-
-using BucketDIEBuilder = std::unique_ptr<DIEBuilder>;
-
-/// Inputs shared by every per-bucket merge step. Held once per
-/// updateDebugInfo() invocation so that helpers consume a single const&
-/// reference rather than threading a long parameter list.
-struct BucketMergeInputs {
- BinaryContext &BC;
- const std::optional<std::string> &DwarfOutputPath;
- std::unordered_map<uint64_t, std::string> &DWOToNameMap;
- DebugStrWriter &StrWriter;
- DebugStrOffsetsWriter &StrOffstsWriter;
- const std::map<uint64_t, std::unique_ptr<DebugLocWriter>> &LocListWritersByCU;
- DebugRangeListsSectionWriter *RangeListsSectionWriter;
- DebugRangesSectionWriter *LegacyRangesSectionWriter;
-};
-
-/// Running accumulators advanced monotonically by the merge loop. Kept as
-/// plain scalars (not boxed in a struct-of-references) so the compiler can
-/// keep them in registers across helpers.
-struct BucketMergeAccum {
- uint64_t CumulativeRngListsSize = 0;
- uint64_t LoclistsRunningOffset = 0;
- uint64_t LegacyLocRunningOffset = 0;
- std::vector<uint64_t> LocListCUOrder;
-};
-
-} // namespace
-
llvm::ThreadPoolInterface &
DWARFRewriter::getOrCreateDebugInfoThreadPool(unsigned ThreadsCount) {
if (opts::NoThreads || ThreadsCount == 0)
@@ -496,9 +451,8 @@ static bool getLowAndHighPC(const DIE &Die, const DWARFUnit &DU,
return false;
}
-
-static void fixupDWARFRanges(DIEBuilder &DIEBlder,
- DWARFUnit &Unit, uint64_t Offset) {
+static void fixupDWARFRanges(DIEBuilder &DIEBlder, DWARFUnit &Unit,
+ uint64_t Offset) {
if (Offset == 0)
return;
@@ -506,10 +460,10 @@ static void fixupDWARFRanges(DIEBuilder &DIEBlder,
if (Version >= 5) {
DIE *CUDie = DIEBlder.getUnitDIEbyUnit(Unit);
DIEValue RngBaseVal = CUDie->findAttribute(dwarf::DW_AT_rnglists_base);
- if(RngBaseVal){
+ if (RngBaseVal) {
uint64_t OldVal = RngBaseVal.getDIEInteger().getValue();
DIEBlder.replaceValue(CUDie, dwarf::DW_AT_rnglists_base,
- RngBaseVal.getForm(), DIEInteger(OldVal + Offset));
+ RngBaseVal.getForm(), DIEInteger(OldVal + Offset));
}
}
@@ -517,7 +471,8 @@ static void fixupDWARFRanges(DIEBuilder &DIEBlder,
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)) {
+ 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));
@@ -525,10 +480,11 @@ static void fixupDWARFRanges(DIEBuilder &DIEBlder,
if (Version < 5) {
DIEValue GnuBaseVal = Die->findAttribute(dwarf::DW_AT_GNU_ranges_base);
- if(GnuBaseVal){
+ if (GnuBaseVal) {
uint64_t OldVal = GnuBaseVal.getDIEInteger().getValue();
DIEBlder.replaceValue(Die, dwarf::DW_AT_GNU_ranges_base,
- GnuBaseVal.getForm(), DIEInteger(OldVal + Offset));
+ GnuBaseVal.getForm(),
+ DIEInteger(OldVal + Offset));
}
}
}
@@ -643,6 +599,8 @@ static void emitDWOBuilder(const std::string &DWOName,
Rewriter.writeDWOFiles(CU, OverriddenSections, DWOName, LocWriter,
StrOffstsWriter, StrWriter, TempRangesSectionWriter);
}
+using DWARFUnitVec = std::vector<DWARFUnit *>;
+using CUPartitionVector = std::vector<DWARFUnitVec>;
static CUPartitionVector partitionCUs(DWARFContext &DwCtx) {
SmallVector<DWARFUnit *, 0> AllCUs;
@@ -721,7 +679,7 @@ static CUPartitionVector partitionCUs(DWARFContext &DwCtx) {
// for (auto &[Leader, Members] : MembersByLeader)
// llvm::sort(Members, SortByOffset);
- std::vector<DWARFUnit *> Leaders;
+ std::vector<DWARFUnit *> Leaders;
Leaders.reserve(MembersByLeader.size());
for (auto &[Leader, Members] : MembersByLeader)
Leaders.push_back(Leader);
@@ -737,15 +695,14 @@ static CUPartitionVector partitionCUs(DWARFContext &DwCtx) {
for (DWARFUnit *Leader : Leaders)
Vec.push_back(std::move(MembersByLeader[Leader]));
for (DWARFUnit *CU : AllCUs) {
- if (!CrossRefSet.count(CU)) {
- Vec.push_back({CU});
- }
+ if (!CrossRefSet.count(CU)) {
+ Vec.push_back({CU});
+ }
}
return Vec;
}
-
static std::unordered_map<uint64_t, std::string>
getDWONameMap(DWARFContext &DwCtx,
std::optional<std::string> &DwarfOutputPath) {
@@ -781,34 +738,30 @@ getDWONameMap(DWARFContext &DwCtx,
return DWOIDToNameMap;
}
-/// Apply DWO name / comp_dir fixups and finalize .debug_str_offsets for
-/// every CU processed by \p PartDIEBlder. Performs a single pass over
-/// getProcessedCUs(); the intra-bucket order is already deterministic,
-/// so no sort/Pending vector is needed.
-static void finalizeSkeletonAndStrOffsets(DIEBuilder &PartDIEBlder,
- const BucketMergeInputs &In) {
+void DWARFRewriter::finalizeSkeletonAndStrOffsets(
+ DIEBuilder &PartDIEBlder, const std::optional<std::string> &DwarfOutputPath,
+ std::unordered_map<uint64_t, std::string> DWOToNameMap) {
for (DWARFUnit *CU : PartDIEBlder.getProcessedCUs()) {
const std::optional<uint64_t> DWOId = CU->getDWOId();
- const bool HasSplitCU = DWOId && In.BC.getDWOCU(*DWOId) != nullptr;
+ const bool HasSplitCU = DWOId && BC.getDWOCU(*DWOId) != nullptr;
const unsigned Version = CU->getVersion();
if (HasSplitCU) {
- auto It = In.DWOToNameMap.find(*DWOId);
- if (It != In.DWOToNameMap.end()) {
- PartDIEBlder.updateDWONameCompDir(In.StrOffstsWriter, In.StrWriter, *CU,
- In.DwarfOutputPath,
- StringRef(It->second),
- In.DWOToNameMap);
- if (Version >= 5 && In.StrOffstsWriter.isStrOffsetsSectionModified())
- In.StrOffstsWriter.finalizeSection(*CU, PartDIEBlder);
+ auto It = DWOToNameMap.find(*DWOId);
+ if (It != DWOToNameMap.end()) {
+ PartDIEBlder.updateDWONameCompDir(*StrOffstsWriter, *StrWriter, *CU,
+ DwarfOutputPath,
+ StringRef(It->second), DWOToNameMap);
+ if (Version >= 5 && StrOffstsWriter->isStrOffsetsSectionModified())
+ StrOffstsWriter->finalizeSection(*CU, PartDIEBlder);
}
// Skeleton-with-split units were just finalized above when the
- // .debug_str_offsets section was modified; no second pass needed.
+ // .debug_str_offsets section was modified;
continue;
}
if (Version >= 5)
- In.StrOffstsWriter.finalizeSection(*CU, PartDIEBlder);
+ StrOffstsWriter->finalizeSection(*CU, PartDIEBlder);
}
}
@@ -832,11 +785,11 @@ static void snapshotSortedCUs(DIEBuilder &PartDIEBlder,
/// .debug_loc base fixups. Doing all per-CU work in one pass keeps the
/// DWARFUnit* stream in cache and avoids re-walking getProcessedCUs()
/// three times as the previous split helpers did.
-static void mergePerBucketLocsAndRanges(DIEBuilder &PartDIEBlder,
- ArrayRef<DWARFUnit *> SortedCUs,
- const BucketMergeInputs &In,
- uint64_t DeltaDWARF5,
- BucketMergeAccum &Accum) {
+void DWARFRewriter::mergePerBucketLocsAndRanges(
+ DIEBuilder &PartDIEBlder, ArrayRef<DWARFUnit *> SortedCUs,
+ const std::optional<std::string> &DwarfOutputPath,
+ std::unordered_map<uint64_t, std::string> DWOToNameMap,
+ uint64_t DeltaDWARF5, BucketMergeAccum &Accum) {
for (DWARFUnit *CU : SortedCUs) {
const uint64_t CUOffset = CU->getOffset();
Accum.LocListCUOrder.push_back(CUOffset);
@@ -848,8 +801,8 @@ static void mergePerBucketLocsAndRanges(DIEBuilder &PartDIEBlder,
bool HasLoclistsBase = false;
bool HasLegacyLocBase = false;
- auto LocIt = In.LocListWritersByCU.find(CUOffset);
- if (LocIt != In.LocListWritersByCU.end()) {
+ 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();
@@ -877,8 +830,7 @@ static void mergePerBucketLocsAndRanges(DIEBuilder &PartDIEBlder,
if (HasLoclistsBase) {
DIE *UnitDIE = PartDIEBlder.getUnitDIEbyUnit(*CU);
if (UnitDIE) {
- DIEValue LocBase =
- UnitDIE->findAttribute(dwarf::DW_AT_loclists_base);
+ 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,
@@ -891,110 +843,81 @@ static void mergePerBucketLocsAndRanges(DIEBuilder &PartDIEBlder,
}
// Version <= 4 path.
- if (HasLegacyLocBase && LocIt != In.LocListWritersByCU.end())
+ if (HasLegacyLocBase && LocIt != LocListWritersByCU.end())
LocIt->second->applyBase(PartDIEBlder, LegacyLocBase);
}
}
+void DWARFRewriter::createRangeLocListAndAddressWriters() {
+ for (auto &DWCU : BC.DwCtx->compile_units()) {
+ DWARFUnit &CU = *DWCU;
+ if (LocListWritersByCU.count(CU.getOffset()))
+ return;
+
+ 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[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.");
+ auto DWORangeListsSectionWriter =
+ std::make_unique<DebugRangeListsSectionWriter>();
+ DWORangeListsSectionWriter->initSection(CU);
+ DWORangeListsSectionWriter->setAddressWriter(AddrW.get());
+ RangeListsWritersByCU[*DWOId] = std::move(DWORangeListsSectionWriter);
+ }
+ AddressWritersByCU[CU.getOffset()] = std::move(AddrW);
+ } else {
+ auto AddrW =
+ std::make_unique<DebugAddrWriter>(&BC, CU.getAddressByteSize());
+ AddressWritersByCU[CU.getOffset()] = std::move(AddrW);
+ 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.");
+ auto LegacyRangesSectionWriterByCU =
+ std::make_unique<DebugRangesSectionWriter>();
+ LegacyRangesSectionWriterByCU->initSection(CU);
+ LegacyRangesWritersByCU[*DWOId] =
+ std::move(LegacyRangesSectionWriterByCU);
+ }
+ }
+ }
+}
+
/// Append this bucket's .debug_rnglists and .debug_ranges local buffers to
/// the global writers. Reuses \p SortedCUs for the DWARF4 fixup pass so
/// no extra copy+sort is needed.
-static void appendBucketRangeBuffers(DIEBuilder &PartDIEBlder,
- ArrayRef<DWARFUnit *> SortedCUs,
- BucketLocalWriter &LocalWriters,
- const BucketMergeInputs &In,
- BucketMergeAccum &Accum) {
- if (LocalWriters.RngListsWriter && In.RangeListsSectionWriter) {
+void DWARFRewriter::appendBucketRangeBuffers(DIEBuilder &PartDIEBlder,
+ ArrayRef<DWARFUnit *> SortedCUs,
+ BucketLocalWriter &LocalWriters,
+ BucketMergeAccum &Accum) {
+ if (LocalWriters.RngListsWriter && RangeListsSectionWriter) {
std::unique_ptr<DebugBufferVector> LocalBuf =
LocalWriters.RngListsWriter->releaseBuffer();
Accum.CumulativeRngListsSize += LocalBuf->size();
- In.RangeListsSectionWriter->appendToRangeBuffer(*LocalBuf);
+ RangeListsSectionWriter->appendToRangeBuffer(*LocalBuf);
}
- if (!LocalWriters.LegacyRangesWriter || !In.LegacyRangesSectionWriter)
+ if (!LocalWriters.LegacyRangesWriter || !LegacyRangesSectionWriter)
return;
std::unique_ptr<DebugBufferVector> LegacyBuf =
LocalWriters.LegacyRangesWriter->releaseBuffer();
- const uint64_t DeltaDWARF4 =
- In.LegacyRangesSectionWriter->getSectionOffset();
+ const uint64_t DeltaDWARF4 = LegacyRangesSectionWriter->getSectionOffset();
// Walk the already-sorted snapshot; do not mutate the processed list
// (emission order is established later by emitBucketCompileUnits).
for (DWARFUnit *CU : SortedCUs)
if (CU->getVersion() <= 4)
fixupDWARFRanges(PartDIEBlder, *CU, DeltaDWARF4);
- In.LegacyRangesSectionWriter->appendToRangeBuffer(*LegacyBuf);
-}
-
-static void emitBucketCompileUnits(DIEBuilder &PartDIEBlder,
- DIEBuilder &MainDIEBuilder,
- DIEStreamer &Streamer,
- CUOffsetMap &OffsetMap, uint32_t &CUOffset) {
- const auto &Processed = PartDIEBlder.getProcessedCUs();
- for (DWARFUnit *DU : Processed) {
- DIE *UnitDIE = PartDIEBlder.getUnitDIEbyUnit(*DU);
- MainDIEBuilder.generateUnitAbbrevs(UnitDIE);
- }
-
- PartDIEBlder.syncAbbrevTableFrom(MainDIEBuilder);
- PartDIEBlder.setUnitOffsetBases(CUOffset);
- PartDIEBlder.finish();
- PartDIEBlder.updateDebugNamesTable();
-
- // Emit units in the same order DIEBuilder assigned offsets.
- for (DWARFUnit *CU : Processed) {
- emitUnit(PartDIEBlder, Streamer, *CU);
- const uint32_t StartOffset = CUOffset;
- DIE *UnitDIE = PartDIEBlder.getUnitDIEbyUnit(*CU);
- CUOffset += CU->getHeaderSize();
- CUOffset += UnitDIE->getSize();
- OffsetMap[CU->getOffset()] = {StartOffset, CUOffset - StartOffset - 4};
- }
-}
-
-/// Finalize a single bucket. All per-CU work uses a single sorted snapshot
-/// of getProcessedCUs() to avoid repeated std::list walks and the redundant
-/// sort-passes that the earlier 7-helper split introduced.
-static void mergeOneBucket(size_t Idx, DIEBuilder &MainDIEBuilder,
- std::vector<BucketDIEBuilder> &BucketDIEBlders,
- std::vector<BucketLocalWriter> &LocalWriters,
- BucketMergeInputs &In, BucketMergeAccum &Accum,
- uint64_t InitialRngListsOffset,
- DIEStreamer &Streamer, CUOffsetMap &OffsetMap,
- uint32_t &CUOffset,
- llvm::function_ref<void(DIEBuilder &)> FinalizeFn) {
- BucketDIEBuilder &BucketDIEBlder = BucketDIEBlders[Idx];
- if (!BucketDIEBlder)
- return;
-
- DIEBuilder &PartDIEBlder = *BucketDIEBlder;
-
- finalizeSkeletonAndStrOffsets(PartDIEBlder, In);
-
- SmallVector<DWARFUnit *, 32> SortedCUs;
- snapshotSortedCUs(PartDIEBlder, SortedCUs);
-
- const uint64_t DeltaDWARF5 =
- InitialRngListsOffset + Accum.CumulativeRngListsSize;
- mergePerBucketLocsAndRanges(PartDIEBlder, SortedCUs, In, DeltaDWARF5, Accum);
- appendBucketRangeBuffers(PartDIEBlder, SortedCUs, LocalWriters[Idx], In,
- Accum);
- FinalizeFn(PartDIEBlder);
-
- emitBucketCompileUnits(PartDIEBlder, MainDIEBuilder, Streamer, OffsetMap,
- CUOffset);
-
- BucketDIEBlder.reset();
- LocalWriters[Idx].clear();
+ LegacyRangesSectionWriter->appendToRangeBuffer(*LegacyBuf);
}
-
void DWARFRewriter::updateDebugInfo() {
- TimerGroup allTG("updateDebugInfo", "all time");
- Timer AllTimer("allTime", "update all time", allTG);
- TimerGroup threadTG("updateDebugInfothread", "thread time");
- Timer threadTimer("thread time", "update thread time", threadTG);
- AllTimer.startTimer();
ErrorOr<BinarySection &> DebugInfo = BC.getUniqueSectionByName(".debug_info");
if (!DebugInfo)
return;
@@ -1015,55 +938,11 @@ void DWARFRewriter::updateDebugInfo() {
LegacyRangesSectionWriter->initSection();
}
- // Used for GDB index and for assigning stable per-run CU IDs.
- // Note: LocListWritersByCU is keyed by CU offset, so CUIndex is not used as
- // a container key.
- uint32_t CUIndex = 0;
- auto createRangeLocListAndAddressWriters = [&](DWARFUnit &CU) {
- if (LocListWritersByCU.count(CU.getOffset()))
- return;
-
- 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[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.");
- auto DWORangeListsSectionWriter =
- std::make_unique<DebugRangeListsSectionWriter>();
- DWORangeListsSectionWriter->initSection(CU);
- DWORangeListsSectionWriter->setAddressWriter(AddrW.get());
- RangeListsWritersByCU[*DWOId] = std::move(DWORangeListsSectionWriter);
- }
- AddressWritersByCU[CU.getOffset()] = std::move(AddrW);
- } else {
- auto AddrW =
- std::make_unique<DebugAddrWriter>(&BC, CU.getAddressByteSize());
- AddressWritersByCU[CU.getOffset()] = std::move(AddrW);
- 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.");
- auto LegacyRangesSectionWriterByCU =
- std::make_unique<DebugRangesSectionWriter>();
- LegacyRangesSectionWriterByCU->initSection(CU);
- LegacyRangesWritersByCU[*DWOId] =
- std::move(LegacyRangesSectionWriterByCU);
- }
- }
- ++CUIndex;
- };
+ 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. This avoids both
- // non-determinism and potential data races from using
- // unordered_map::operator[] in parallel code paths.
- for (const std::unique_ptr<DWARFUnit> &CU : BC.DwCtx->compile_units())
- createRangeLocListAndAddressWriters(*CU);
-
+ // Worker threads should only read from these maps.
+ createRangeLocListAndAddressWriters();
std::optional<std::string> DwarfOutputPath =
opts::DwarfOutputPath.empty()
? std::nullopt
@@ -1081,7 +960,6 @@ void DWARFRewriter::updateDebugInfo() {
if (DebugNamesTable.isCreated())
DebugNamesTable.preAllocateUnits(*BC.DwCtx);
GDBIndex GDBIndexSection(BC);
- std::mutex BuildTypeMutex;
std::mutex DebugNamesUpdateMutex;
auto processSplitCU = [&](DWARFUnit &Unit, DWARFUnit &SplitCU,
@@ -1110,47 +988,48 @@ void DWARFRewriter::updateDebugInfo() {
std::lock_guard<std::mutex> Lock(DebugNamesUpdateMutex);
DWODIEBuilder.updateDebugNamesTable();
}
-
};
- auto 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)
- LocalWriter.RngListsWriter = std::make_unique<DebugRangeListsSectionWriter>();
- else
- 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) {
- RangesBase = LocalWriter.LegacyRangesWriter->getSectionOffset();
- }
- updateUnitDebugInfo(Unit, DIEBlder, DebugLocWriter, RangesSectionWriter,
- AddressWriter, RangesBase);
- DebugLocWriter.finalize(DIEBlder, *DIEBlder.getUnitDIEbyUnit(Unit));
- if (DWARFVersion >= 5)
- RangesSectionWriter.finalizeSection();
- };
+ auto 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)
+ LocalWriter.RngListsWriter =
+ std::make_unique<DebugRangeListsSectionWriter>();
+ else
+ 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) {
+ RangesBase = LocalWriter.LegacyRangesWriter->getSectionOffset();
+ }
+ updateUnitDebugInfo(Unit, DIEBlder, DebugLocWriter, RangesSectionWriter,
+ AddressWriter, RangesBase);
+ DebugLocWriter.finalize(DIEBlder, *DIEBlder.getUnitDIEbyUnit(Unit));
+ if (DWARFVersion >= 5)
+ RangesSectionWriter.finalizeSection();
+ };
DIEBuilder DIEBlder(BC, BC.DwCtx.get(), DebugNamesTable);
DIEBlder.buildTypeUnits(StrOffstsWriter.get());
@@ -1172,32 +1051,18 @@ void DWARFRewriter::updateDebugInfo() {
std::vector<BucketLocalWriter> LocalWriters(PartVec.size());
const uint64_t InitialRngListsOffset =
RangeListsSectionWriter ? RangeListsSectionWriter->getSectionOffset() : 0;
- std::vector<BucketDIEBuilder> BucketDIEBlders(PartVec.size());
+ std::vector<std::unique_ptr<DIEBuilder>> BucketDIEBlders(PartVec.size());
std::mutex MergeQueueMutex;
std::condition_variable MergeQueueCV;
const size_t TotalTasks = PartVec.size();
std::vector<char> BucketDone(TotalTasks, 0);
- // Inputs that every merge step reads but never mutates. Passed by const&
- // so callees see a stable alias set.
- BucketMergeInputs MergeIn{BC,
- DwarfOutputPath,
- DWOToNameMap,
- *StrWriter,
- *StrOffstsWriter,
- LocListWritersByCU,
- RangeListsSectionWriter.get(),
- LegacyRangesSectionWriter.get()};
BucketMergeAccum Accum;
- auto FinalizeCompileUnitsForBucket = [&](DIEBuilder &PartDIEBlder) {
- finalizeCompileUnits(PartDIEBlder, *Streamer, OffsetMap,
- PartDIEBlder.getProcessedCUs(), *FinalAddrWriter);
- };
for (size_t I = 0; I < TotalTasks; ++I) {
ThreadPool.async([&, I] {
std::vector<DWARFUnit *> &Vec = PartVec[I];
- BucketDIEBuilder &BucketDIEBlder = BucketDIEBlders[I];
+ std::unique_ptr<DIEBuilder> &BucketDIEBlder = BucketDIEBlders[I];
BucketDIEBlder =
std::make_unique<DIEBuilder>(BC, BC.DwCtx.get(), DebugNamesTable);
DIEBuilder &PartDIEBlder = *BucketDIEBlder;
@@ -1208,22 +1073,21 @@ void DWARFRewriter::updateDebugInfo() {
std::optional<uint64_t> DWOId = CU->getDWOId();
if (DWOId)
SplitCU = BC.getDWOCU(*DWOId);
- if (!SplitCU)
- continue;
- DebugAddrWriter &AddressWriter =
- *AddressWritersByCU.at(CU->getOffset());
- DebugRangesSectionWriter &TempRangesSectionWriter =
- CU->getVersion() >= 5 ? *RangeListsWritersByCU.at(*DWOId)
- : *LegacyRangesWritersByCU.at(*DWOId);
- auto DWOName = DWOToNameMap.at(*DWOId);
- auto DWODIEBuilderPtr = std::make_unique<DIEBuilder>(
- BC, &(**SplitCU).getContext(), DebugNamesTable, CU);
- DIEBuilder &DWODIEBuilder = *DWODIEBuilderPtr;
- processSplitCU(*CU, **SplitCU, TempRangesSectionWriter, AddressWriter,
- DWOName, DWODIEBuilder);
- }
- for (DWARFUnit *CU : PartDIEBlder.getProcessedCUs())
+ if (SplitCU) {
+ DebugAddrWriter &AddressWriter =
+ *AddressWritersByCU.at(CU->getOffset());
+ DebugRangesSectionWriter &TempRangesSectionWriter =
+ CU->getVersion() >= 5 ? *RangeListsWritersByCU.at(*DWOId)
+ : *LegacyRangesWritersByCU.at(*DWOId);
+ auto DWOName = DWOToNameMap.at(*DWOId);
+ 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[I]);
+ }
{
std::lock_guard<std::mutex> Lock(MergeQueueMutex);
BucketDone[I] = 1;
@@ -1233,7 +1097,7 @@ void DWARFRewriter::updateDebugInfo() {
MergeQueueCV.notify_one();
});
}
-
+
// Buckets are merged in their natural order: this preserves the emission
// order used by downstream sections (notably .debug_loclists) and lets us
// accumulate CumulativeRngListsSize / LoclistsRunningOffset monotonically.
@@ -1242,20 +1106,30 @@ void DWARFRewriter::updateDebugInfo() {
std::unique_lock<std::mutex> Lock(MergeQueueMutex);
MergeQueueCV.wait(Lock, [&] { return BucketDone[Idx] != 0; });
}
- mergeOneBucket(Idx, DIEBlder, BucketDIEBlders, LocalWriters, MergeIn, Accum,
- InitialRngListsOffset, *Streamer, OffsetMap, CUOffset,
- FinalizeCompileUnitsForBucket);
+ std::unique_ptr<DIEBuilder> &BucketDIEBlder = BucketDIEBlders[Idx];
+ if (!BucketDIEBlder)
+ return;
+ finalizeSkeletonAndStrOffsets(*BucketDIEBlder, DwarfOutputPath, DWOToNameMap);
+
+ SmallVector<DWARFUnit *, 32> SortedCUs;
+ snapshotSortedCUs(*BucketDIEBlder, SortedCUs);
+
+ uint64_t DeltaDWARF5 = InitialRngListsOffset + Accum.CumulativeRngListsSize;
+ mergePerBucketLocsAndRanges(*BucketDIEBlder, SortedCUs, DwarfOutputPath,
+ DWOToNameMap, DeltaDWARF5, Accum);
+ appendBucketRangeBuffers(*BucketDIEBlder, SortedCUs, LocalWriters[Idx], Accum);
+
+ finalizeCompileUnits(*BucketDIEBlder, DIEBlder, *Streamer, OffsetMap,
+ BucketDIEBlder->getProcessedCUs(), *FinalAddrWriter);
+ BucketDIEBlders[Idx].reset();
}
ThreadPool.wait();
DebugNamesTable.emitAccelTable();
finalizeDebugSections(DIEBlder, DebugNamesTable, *Streamer, *ObjOS, OffsetMap,
*FinalAddrWriter, Accum.LocListCUOrder);
- GDBIndexSection.updateGdbIndexSection(OffsetMap, CUIndex,
+ GDBIndexSection.updateGdbIndexSection(OffsetMap, CUSize,
*ARangesSectionWriter);
- AllTimer.stopTimer();
- allTG.print(errs());
- threadTG.print(errs());
}
void DWARFRewriter::updateUnitDebugInfo(
@@ -1831,9 +1705,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, AddressWriter, RangesBase);
+ LowPCAttrInfo, HighPCAttrInfo, AddressWriter,
+ RangesBase);
} else if (!(Unit.isDWOUnit() &&
Die.getTag() == dwarf::DW_TAG_compile_unit)) {
if (opts::Verbosity >= 1)
@@ -2027,7 +1901,7 @@ void DWARFRewriter::finalizeDebugSections(
if (BC.isDWARF5Used()) {
std::unique_ptr<DebugBufferVector> LocationListSectionContents =
- makeFinalLocListsSection(DWARFVersion::DWARF5,SortedCU);
+ makeFinalLocListsSection(DWARFVersion::DWARF5, SortedCU);
if (!LocationListSectionContents->empty())
BC.registerOrUpdateNoteSection(
".debug_loclists", copyByteArray(*LocationListSectionContents),
@@ -2098,6 +1972,7 @@ void DWARFRewriter::finalizeDebugSections(
}
}
void DWARFRewriter::finalizeCompileUnits(DIEBuilder &DIEBlder,
+ DIEBuilder &MainDIEBuilder,
DIEStreamer &Streamer,
CUOffsetMap &CUMap,
const std::list<DWARFUnit *> &CUs,
@@ -2142,6 +2017,23 @@ void DWARFRewriter::finalizeCompileUnits(DIEBuilder &DIEBlder,
LegacyRangesWriter->releaseBuffer();
LegacyRangesSectionWriter->appendToRangeBuffer(*RangesWritersContents);
}
+ for (DWARFUnit *DU : CUs) {
+ DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(*DU);
+ MainDIEBuilder.generateUnitAbbrevs(UnitDIE);
+ }
+ DIEBlder.syncAbbrevTableFrom(MainDIEBuilder);
+ DIEBlder.setUnitOffsetBases(CUOffset);
+ DIEBlder.finish();
+ DIEBlder.updateDebugNamesTable();
+ // generate debug_info and CUMap
+ for (DWARFUnit *CU : CUs) {
+ emitUnit(DIEBlder, Streamer, *CU);
+ const uint32_t StartOffset = CUOffset;
+ DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(*CU);
+ CUOffset += CU->getHeaderSize();
+ CUOffset += UnitDIE->getSize();
+ CUMap[CU->getOffset()] = {StartOffset, CUOffset - StartOffset - 4};
+ }
}
// Creates all the data structures necessary for creating MCStreamer.
>From 63e89d3938dc653fe860624046d178ad87813b98 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Thu, 30 Apr 2026 16:32:36 +0800
Subject: [PATCH 5/6] [BOLT][DebugInfo] change range/ranges offset & split
processmainbinary
---
bolt/include/bolt/Rewrite/DWARFRewriter.h | 42 ++---
bolt/lib/Core/DebugNames.cpp | 13 +-
bolt/lib/Rewrite/DWARFRewriter.cpp | 203 +++++++++++-----------
3 files changed, 122 insertions(+), 136 deletions(-)
diff --git a/bolt/include/bolt/Rewrite/DWARFRewriter.h b/bolt/include/bolt/Rewrite/DWARFRewriter.h
index a458ea729c1d5..6a64b3697dbc0 100644
--- a/bolt/include/bolt/Rewrite/DWARFRewriter.h
+++ b/bolt/include/bolt/Rewrite/DWARFRewriter.h
@@ -41,21 +41,21 @@ class DWARFRewriter {
uint64_t TypeHash;
uint64_t TypeDIERelativeOffset;
};
- struct BucketMergeAccum {
- uint64_t CumulativeRngListsSize = 0;
- uint64_t LoclistsRunningOffset = 0;
- uint64_t LegacyLocRunningOffset = 0;
+ struct BucketLocAccum {
+ 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 both writers at once. Called when the bucket has been fully
- /// merged into the global DWARF section writers.
+ /// Release whichever writer was initialized.
void clear() {
- RngListsWriter.reset();
- LegacyRangesWriter.reset();
+ if (RngListsWriter)
+ RngListsWriter.reset();
+ if (LegacyRangesWriter)
+ LegacyRangesWriter.reset();
}
};
@@ -149,25 +149,24 @@ class DWARFRewriter {
/// Finalize type sections in the main binary.
CUOffsetMap finalizeTypeSections(DIEBuilder &DIEBlder, DIEStreamer &Streamer,
GDBIndex &GDBIndexSection);
-
+
/// Finalize str section in the dwo
- void finalizeSkeletonAndStrOffsets(
+ void finalizeSkeletonAndStrSection(
DIEBuilder &PartDIEBlder,
const std::optional<std::string> &DwarfOutputPath,
- std::unordered_map<uint64_t, std::string> DWOToNameMap);
-
+ std::unordered_map<uint64_t, std::string> DWOToNameMap, DWARFUnit &CU);
+
/// Merge Bucket locs section and ranges section result
void mergePerBucketLocsAndRanges(
- DIEBuilder &PartDIEBlder, ArrayRef<DWARFUnit *> SortedCUs,
+ DIEBuilder &PartDIEBlder, std::vector<DWARFUnit *> SortedCUs,
const std::optional<std::string> &DwarfOutputPath,
std::unordered_map<uint64_t, std::string> DWOToNameMap,
- uint64_t DeltaDWARF5, BucketMergeAccum &Accum);
+ BucketLocAccum &Accum);
/// append buffers to RangeListsSectionWriter/LegacyRangesSectionWriter
void appendBucketRangeBuffers(DIEBuilder &PartDIEBlder,
- ArrayRef<DWARFUnit *> SortedCUs,
- BucketLocalWriter &LocalWriters,
- BucketMergeAccum &Accum);
+ std::vector<DWARFUnit *> SortedCUs,
+ BucketLocalWriter &LocalWriters);
/// Process and write out CUs that are passed in.
void finalizeCompileUnits(DIEBuilder &DIEBlder, DIEBuilder &MainDIEBlder,
@@ -182,10 +181,11 @@ class DWARFRewriter {
CUOffsetMap &CUMap,
DebugAddrWriter &FinalAddrWriter,
std::vector<uint64_t> SortedCU);
-
- /// Patches the binary for DWARF address ranges (e.g. in functions and lexical
- /// blocks) to be updated.
- void updateDebugAddressRanges();
+ void processMainBinaryCU(DWARFUnit &Unit, DIEBuilder &DIEBlder,
+ BucketLocalWriter &LocalWriter);
+ /// Patches the binary for DWARF address ranges (e.g. in functions and
+ /// lexical blocks) to be updated.
+ void updateDebugAddressRanges();
/// DWARFDie contains a pointer to a DIE and hence gets invalidated once the
/// embedded DIE is destroyed. This wrapper class stores a DIE internally and
diff --git a/bolt/lib/Core/DebugNames.cpp b/bolt/lib/Core/DebugNames.cpp
index 508f264cb4b51..450e02ed37773 100644
--- a/bolt/lib/Core/DebugNames.cpp
+++ b/bolt/lib/Core/DebugNames.cpp
@@ -87,19 +87,8 @@ void DWARF5AcceleratorTable::preAllocateUnits(DWARFContext &DwCtx) {
if (!DWOCU || !*DWOCU)
continue;
DWARFContext &DWOCtx = (*DWOCU)->getContext();
- // check dwo_info_section_units for DWARF5 type units in DWO.
- for (const auto &TU : DWOCtx.dwo_info_section_units()) {
- if (!TU->isTypeUnit())
- continue;
- const uint64_t TUHash = cast<DWARFTypeUnit>(TU.get())->getTypeHash();
- // Only insert on first encounter — preserves discovery order.
- if (!TUHashToIndexMap.count(TUHash)) {
- TUHashToIndexMap.insert({TUHash, ForeignTUList.size()});
- ForeignTUList.push_back(TUHash);
- }
- }
// check dwo_types_section_units for DWARF4 type units in DWO.
- for (const auto &TU : DWOCtx.dwo_types_section_units()) {
+ for (const auto &TU : DWOCtx.dwo_units()) {
if (!TU->isTypeUnit())
continue;
const uint64_t TUHash = cast<DWARFTypeUnit>(TU.get())->getTypeHash();
diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp
index da0570c18121d..7dfddeac43be8 100644
--- a/bolt/lib/Rewrite/DWARFRewriter.cpp
+++ b/bolt/lib/Rewrite/DWARFRewriter.cpp
@@ -54,9 +54,7 @@
#include <limits>
#include <memory>
#include <mutex>
-#include <numeric>
#include <optional>
-#include <queue>
#include <string>
#include <unordered_map>
#include <utility>
@@ -738,38 +736,35 @@ getDWONameMap(DWARFContext &DwCtx,
return DWOIDToNameMap;
}
-void DWARFRewriter::finalizeSkeletonAndStrOffsets(
+void DWARFRewriter::finalizeSkeletonAndStrSection(
DIEBuilder &PartDIEBlder, const std::optional<std::string> &DwarfOutputPath,
- std::unordered_map<uint64_t, std::string> DWOToNameMap) {
- for (DWARFUnit *CU : PartDIEBlder.getProcessedCUs()) {
- const std::optional<uint64_t> DWOId = CU->getDWOId();
- const bool HasSplitCU = DWOId && BC.getDWOCU(*DWOId) != nullptr;
- const unsigned Version = CU->getVersion();
-
- if (HasSplitCU) {
- auto It = DWOToNameMap.find(*DWOId);
- if (It != DWOToNameMap.end()) {
- PartDIEBlder.updateDWONameCompDir(*StrOffstsWriter, *StrWriter, *CU,
- DwarfOutputPath,
- StringRef(It->second), DWOToNameMap);
- if (Version >= 5 && StrOffstsWriter->isStrOffsetsSectionModified())
- StrOffstsWriter->finalizeSection(*CU, PartDIEBlder);
- }
- // Skeleton-with-split units were just finalized above when the
- // .debug_str_offsets section was modified;
- continue;
+ std::unordered_map<uint64_t, std::string> DWOToNameMap, DWARFUnit &CU) {
+ const std::optional<uint64_t> DWOId = CU.getDWOId();
+ const bool HasSplitCU = DWOId && BC.getDWOCU(*DWOId) != nullptr;
+ const unsigned Version = CU.getVersion();
+
+ if (HasSplitCU) {
+ auto It = DWOToNameMap.find(*DWOId);
+ if (It != DWOToNameMap.end()) {
+ PartDIEBlder.updateDWONameCompDir(*StrOffstsWriter, *StrWriter, CU,
+ DwarfOutputPath, StringRef(It->second),
+ DWOToNameMap);
+ if (Version >= 5 && StrOffstsWriter->isStrOffsetsSectionModified())
+ StrOffstsWriter->finalizeSection(CU, PartDIEBlder);
}
-
- if (Version >= 5)
- StrOffstsWriter->finalizeSection(*CU, PartDIEBlder);
+ // split CU were just finalized above when the
+ // .debug_str_offsets section was modified;
+ return;
}
+
+ if (Version >= 5)
+ StrOffstsWriter->finalizeSection(CU, PartDIEBlder);
}
/// Snapshot \p PartDIEBlder.getProcessedCUs() into a SmallVector sorted by
/// CU offset. The same sorted view is reused by every per-CU helper below
/// so that the bucket is walked at most twice (once here, once during emit).
-static void snapshotSortedCUs(DIEBuilder &PartDIEBlder,
- SmallVectorImpl<DWARFUnit *> &Out) {
+static void sortCU(DIEBuilder &PartDIEBlder, std::vector<DWARFUnit *> &Out) {
const auto &Processed = PartDIEBlder.getProcessedCUs();
Out.clear();
Out.reserve(Processed.size());
@@ -786,13 +781,21 @@ static void snapshotSortedCUs(DIEBuilder &PartDIEBlder,
/// DWARFUnit* stream in cache and avoids re-walking getProcessedCUs()
/// three times as the previous split helpers did.
void DWARFRewriter::mergePerBucketLocsAndRanges(
- DIEBuilder &PartDIEBlder, ArrayRef<DWARFUnit *> SortedCUs,
+ DIEBuilder &PartDIEBlder, std::vector<DWARFUnit *> SortedCUs,
const std::optional<std::string> &DwarfOutputPath,
std::unordered_map<uint64_t, std::string> DWOToNameMap,
- uint64_t DeltaDWARF5, BucketMergeAccum &Accum) {
+ BucketLocAccum &Accum) {
+ for (DWARFUnit *CU : SortedCUs) {
+ // record CUs order to make loc/loclist order correct
+ Accum.LocListCUOrder.push_back(CU->getOffset());
+ finalizeSkeletonAndStrSection(PartDIEBlder, DwarfOutputPath, DWOToNameMap,
+ *CU);
+ }
for (DWARFUnit *CU : SortedCUs) {
+ // finalizeSkeletonAndStrSection(PartDIEBlder, DwarfOutputPath,
+ // DWOToNameMap,
+ // *CU);
const uint64_t CUOffset = CU->getOffset();
- Accum.LocListCUOrder.push_back(CUOffset);
// Compute this CU's contribution base and adjust loclists / legacy loc
// fixups inline, avoiding a separate lookup pass.
@@ -809,23 +812,24 @@ void DWARFRewriter::mergePerBucketLocsAndRanges(
if (LocListWriter && LocListWriter->getDwarfVersion() >= 5 &&
!LocListWriter->isSplitDwarf() && BufferSize != 0) {
- LoclistsBase = Accum.LoclistsRunningOffset;
+ LoclistsBase = Accum.LoclistsOffset;
HasLoclistsBase = true;
- Accum.LoclistsRunningOffset += BufferSize;
+ Accum.LoclistsOffset += BufferSize;
} else if (!LocListWriter) {
- LegacyLocBase = Accum.LegacyLocRunningOffset;
+ LegacyLocBase = Accum.LegacyLocOffset;
HasLegacyLocBase = true;
// 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.LegacyLocRunningOffset += BufferSize - 16;
+ Accum.LegacyLocOffset += BufferSize - 16;
}
}
const unsigned Version = CU->getVersion();
if (Version >= 5) {
- fixupDWARFRanges(PartDIEBlder, *CU, DeltaDWARF5);
+ uint64_t RangsOffset = RangeListsSectionWriter->getSectionOffset();
+ fixupDWARFRanges(PartDIEBlder, *CU, RangsOffset);
if (HasLoclistsBase) {
DIE *UnitDIE = PartDIEBlder.getUnitDIEbyUnit(*CU);
@@ -890,16 +894,13 @@ void DWARFRewriter::createRangeLocListAndAddressWriters() {
}
/// Append this bucket's .debug_rnglists and .debug_ranges local buffers to
-/// the global writers. Reuses \p SortedCUs for the DWARF4 fixup pass so
-/// no extra copy+sort is needed.
+/// the global writers.
void DWARFRewriter::appendBucketRangeBuffers(DIEBuilder &PartDIEBlder,
- ArrayRef<DWARFUnit *> SortedCUs,
- BucketLocalWriter &LocalWriters,
- BucketMergeAccum &Accum) {
+ std::vector<DWARFUnit *> SortedCUs,
+ BucketLocalWriter &LocalWriters) {
if (LocalWriters.RngListsWriter && RangeListsSectionWriter) {
std::unique_ptr<DebugBufferVector> LocalBuf =
LocalWriters.RngListsWriter->releaseBuffer();
- Accum.CumulativeRngListsSize += LocalBuf->size();
RangeListsSectionWriter->appendToRangeBuffer(*LocalBuf);
}
@@ -908,15 +909,56 @@ void DWARFRewriter::appendBucketRangeBuffers(DIEBuilder &PartDIEBlder,
std::unique_ptr<DebugBufferVector> LegacyBuf =
LocalWriters.LegacyRangesWriter->releaseBuffer();
- const uint64_t DeltaDWARF4 = LegacyRangesSectionWriter->getSectionOffset();
- // Walk the already-sorted snapshot; do not mutate the processed list
- // (emission order is established later by emitBucketCompileUnits).
+ // emission order is established later by emitBucketCompileUnits
for (DWARFUnit *CU : SortedCUs)
if (CU->getVersion() <= 4)
- fixupDWARFRanges(PartDIEBlder, *CU, DeltaDWARF4);
+ fixupDWARFRanges(PartDIEBlder, *CU,
+ LegacyRangesSectionWriter->getSectionOffset());
LegacyRangesSectionWriter->appendToRangeBuffer(*LegacyBuf);
}
+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)
+ LocalWriter.RngListsWriter =
+ std::make_unique<DebugRangeListsSectionWriter>();
+ else
+ 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) {
+ RangesBase = LocalWriter.LegacyRangesWriter->getSectionOffset();
+ }
+ updateUnitDebugInfo(Unit, DIEBlder, DebugLocWriter, RangesSectionWriter,
+ AddressWriter, RangesBase);
+ DebugLocWriter.finalize(DIEBlder, *DIEBlder.getUnitDIEbyUnit(Unit));
+ if (DWARFVersion >= 5)
+ RangesSectionWriter.finalizeSection();
+};
+
void DWARFRewriter::updateDebugInfo() {
ErrorOr<BinarySection &> DebugInfo = BC.getUniqueSectionByName(".debug_info");
if (!DebugInfo)
@@ -939,7 +981,7 @@ void DWARFRewriter::updateDebugInfo() {
}
uint32_t CUSize = std::distance(BC.DwCtx->compile_units().begin(),
- BC.DwCtx->compile_units().end());
+ BC.DwCtx->compile_units().end());
// Pre-create per-CU writers in a single thread.
// Worker threads should only read from these maps.
createRangeLocListAndAddressWriters();
@@ -961,7 +1003,6 @@ void DWARFRewriter::updateDebugInfo() {
DebugNamesTable.preAllocateUnits(*BC.DwCtx);
GDBIndex GDBIndexSection(BC);
std::mutex DebugNamesUpdateMutex;
-
auto processSplitCU = [&](DWARFUnit &Unit, DWARFUnit &SplitCU,
DebugRangesSectionWriter &TempRangesSectionWriter,
DebugAddrWriter &AddressWriter,
@@ -989,48 +1030,6 @@ void DWARFRewriter::updateDebugInfo() {
DWODIEBuilder.updateDebugNamesTable();
}
};
- auto 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)
- LocalWriter.RngListsWriter =
- std::make_unique<DebugRangeListsSectionWriter>();
- else
- 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) {
- RangesBase = LocalWriter.LegacyRangesWriter->getSectionOffset();
- }
- updateUnitDebugInfo(Unit, DIEBlder, DebugLocWriter, RangesSectionWriter,
- AddressWriter, RangesBase);
- DebugLocWriter.finalize(DIEBlder, *DIEBlder.getUnitDIEbyUnit(Unit));
- if (DWARFVersion >= 5)
- RangesSectionWriter.finalizeSection();
- };
-
DIEBuilder DIEBlder(BC, BC.DwCtx.get(), DebugNamesTable);
DIEBlder.buildTypeUnits(StrOffstsWriter.get());
SmallVector<char, 20> OutBuffer;
@@ -1043,21 +1042,18 @@ void DWARFRewriter::updateDebugInfo() {
CUOffsetMap OffsetMap =
finalizeTypeSections(DIEBlder, *Streamer, GDBIndexSection);
CUPartitionVector PartVec = partitionCUs(*BC.DwCtx);
- errs() << "bucket size :" << PartVec.size() << "\n";
const unsigned int ThreadCount =
std::min(opts::DebugThreadCount, opts::ThreadCount);
llvm::ThreadPoolInterface &ThreadPool =
getOrCreateDebugInfoThreadPool(ThreadCount);
std::vector<BucketLocalWriter> LocalWriters(PartVec.size());
- const uint64_t InitialRngListsOffset =
- RangeListsSectionWriter ? RangeListsSectionWriter->getSectionOffset() : 0;
std::vector<std::unique_ptr<DIEBuilder>> BucketDIEBlders(PartVec.size());
std::mutex MergeQueueMutex;
std::condition_variable MergeQueueCV;
const size_t TotalTasks = PartVec.size();
std::vector<char> BucketDone(TotalTasks, 0);
- BucketMergeAccum Accum;
+ BucketLocAccum Accum;
for (size_t I = 0; I < TotalTasks; ++I) {
ThreadPool.async([&, I] {
@@ -1099,8 +1095,7 @@ void DWARFRewriter::updateDebugInfo() {
}
// Buckets are merged in their natural order: this preserves the emission
- // order used by downstream sections (notably .debug_loclists) and lets us
- // accumulate CumulativeRngListsSize / LoclistsRunningOffset monotonically.
+ // order used by downstream sections (notably .debug_loclists)
for (size_t Idx = 0; Idx < TotalTasks; ++Idx) {
{
std::unique_lock<std::mutex> Lock(MergeQueueMutex);
@@ -1109,19 +1104,20 @@ void DWARFRewriter::updateDebugInfo() {
std::unique_ptr<DIEBuilder> &BucketDIEBlder = BucketDIEBlders[Idx];
if (!BucketDIEBlder)
return;
- finalizeSkeletonAndStrOffsets(*BucketDIEBlder, DwarfOutputPath, DWOToNameMap);
- SmallVector<DWARFUnit *, 32> SortedCUs;
- snapshotSortedCUs(*BucketDIEBlder, SortedCUs);
+ // Make sure CUs are sorted by offset
+ std::vector<DWARFUnit *> SortedCUs;
+ SortedCUs.reserve(CUSize);
+ sortCU(*BucketDIEBlder, SortedCUs);
- uint64_t DeltaDWARF5 = InitialRngListsOffset + Accum.CumulativeRngListsSize;
mergePerBucketLocsAndRanges(*BucketDIEBlder, SortedCUs, DwarfOutputPath,
- DWOToNameMap, DeltaDWARF5, Accum);
- appendBucketRangeBuffers(*BucketDIEBlder, SortedCUs, LocalWriters[Idx], Accum);
+ DWOToNameMap, Accum);
+ appendBucketRangeBuffers(*BucketDIEBlder, SortedCUs, LocalWriters[Idx]);
finalizeCompileUnits(*BucketDIEBlder, DIEBlder, *Streamer, OffsetMap,
BucketDIEBlder->getProcessedCUs(), *FinalAddrWriter);
BucketDIEBlders[Idx].reset();
+ LocalWriters[Idx].clear();
}
ThreadPool.wait();
@@ -2397,23 +2393,24 @@ DWARFRewriter::makeFinalLocListsSection(DWARFVersion Version,
DebugLocWriter *LocWriter = It->second.get();
auto *LocListWriter = dyn_cast<DebugLoclistWriter>(LocWriter);
+ // Filter out DWARF4, writing out DWARF5
if (Version == DWARFVersion::DWARF5 &&
(!LocListWriter || LocListWriter->getDwarfVersion() <= 4))
continue;
+ // Filter out DWARF5, writing out DWARF4
if (Version == DWARFVersion::DWARFLegacy &&
(LocListWriter && LocListWriter->getDwarfVersion() >= 5))
continue;
+ // 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) and skip
- // the per-CU prefix so that per-CU offsets rebased via
- // LocListMergeState::LegacyLocRunningOffset remain valid.
+ // Emit the empty list only once globally (reserved above)
if (Version == DWARFVersion::DWARFLegacy) {
if (CurrCULocationLists->size() > 16)
*LocStream << StringRef(
>From 98f2ef8049eacb1d143825290e7defa76c401f80 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Wed, 6 May 2026 23:23:06 +0800
Subject: [PATCH 6/6] ix format and build error
---
bolt/include/bolt/Core/DIEBuilder.h | 31 ++++++++++++-----------
bolt/include/bolt/Core/DebugData.h | 5 ++--
bolt/include/bolt/Rewrite/DWARFRewriter.h | 6 ++---
bolt/lib/Core/DIEBuilder.cpp | 23 -----------------
bolt/lib/Core/DebugData.cpp | 11 ++++----
bolt/lib/Core/DebugNames.cpp | 3 +--
bolt/lib/Rewrite/DWARFRewriter.cpp | 2 +-
7 files changed, 29 insertions(+), 52 deletions(-)
diff --git a/bolt/include/bolt/Core/DIEBuilder.h b/bolt/include/bolt/Core/DIEBuilder.h
index 7ba196607fee7..dc36d979a3e30 100644
--- a/bolt/include/bolt/Core/DIEBuilder.h
+++ b/bolt/include/bolt/Core/DIEBuilder.h
@@ -340,10 +340,11 @@ class DIEBuilder {
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;
+ /// 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.
@@ -393,18 +394,18 @@ class DIEBuilder {
return Die->deleteValue(Attribute);
}
/// Updates DWO Name and Compilation directory for Skeleton CU \p Unit.
- std::string updateDWONameCompDir(DebugStrOffsetsWriter &StrOffstsWriter,
- DebugStrWriter &StrWriter,
- DWARFUnit &SkeletonCU,
- std::optional<StringRef> DwarfOutputPath,
- std::optional<StringRef> DWONameToUse,
- std::unordered_map<uint64_t, std::string> &DWOIDToName);
+ std::string
+ updateDWONameCompDir(DebugStrOffsetsWriter &StrOffstsWriter,
+ DebugStrWriter &StrWriter, DWARFUnit &SkeletonCU,
+ std::optional<StringRef> DwarfOutputPath,
+ std::optional<StringRef> DWONameToUse,
+ std::unordered_map<uint64_t, std::string> &DWOIDToName);
/// Updates DWO Name and Compilation directory for Type Units.
- void updateDWONameCompDirForTypes(DebugStrOffsetsWriter &StrOffstsWriter,
- DebugStrWriter &StrWriter, DWARFUnit &Unit,
- std::optional<StringRef> DwarfOutputPath,
- const StringRef DWOName,
- std::unordered_map<uint64_t, std::string> &DWOIDToName);
+ void updateDWONameCompDirForTypes(
+ DebugStrOffsetsWriter &StrOffstsWriter, DebugStrWriter &StrWriter,
+ DWARFUnit &Unit, std::optional<StringRef> DwarfOutputPath,
+ const StringRef DWOName,
+ std::unordered_map<uint64_t, std::string> &DWOIDToName);
};
} // namespace bolt
} // namespace llvm
diff --git a/bolt/include/bolt/Core/DebugData.h b/bolt/include/bolt/Core/DebugData.h
index 1c5334b2db562..ae351c5b7e399 100644
--- a/bolt/include/bolt/Core/DebugData.h
+++ b/bolt/include/bolt/Core/DebugData.h
@@ -573,7 +573,7 @@ class DebugLocWriter {
/// 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);
@@ -587,7 +587,8 @@ class DebugLocWriter {
protected:
std::unique_ptr<DebugBufferVector> LocBuffer;
std::unique_ptr<raw_svector_ostream> LocStream;
- /// Current offset in this writer's local buffer (updated as new entries are written).
+ /// Current offset in this writer's local buffer (updated as new entries are
+ /// written).
uint32_t LocSectionOffset{0};
uint8_t DwarfVersion{4};
LocWriterKind Kind{LocWriterKind::DebugLocWriter};
diff --git a/bolt/include/bolt/Rewrite/DWARFRewriter.h b/bolt/include/bolt/Rewrite/DWARFRewriter.h
index 6a64b3697dbc0..a80d1cd6da5df 100644
--- a/bolt/include/bolt/Rewrite/DWARFRewriter.h
+++ b/bolt/include/bolt/Rewrite/DWARFRewriter.h
@@ -183,9 +183,9 @@ class DWARFRewriter {
std::vector<uint64_t> SortedCU);
void processMainBinaryCU(DWARFUnit &Unit, DIEBuilder &DIEBlder,
BucketLocalWriter &LocalWriter);
- /// Patches the binary for DWARF address ranges (e.g. in functions and
- /// lexical blocks) to be updated.
- void updateDebugAddressRanges();
+ /// Patches the binary for DWARF address ranges (e.g. in functions and
+ /// lexical blocks) to be updated.
+ void updateDebugAddressRanges();
/// DWARFDie contains a pointer to a DIE and hence gets invalidated once the
/// embedded DIE is destroyed. This wrapper class stores a DIE internally and
diff --git a/bolt/lib/Core/DIEBuilder.cpp b/bolt/lib/Core/DIEBuilder.cpp
index e807011c11bb3..2dd255a574de0 100644
--- a/bolt/lib/Core/DIEBuilder.cpp
+++ b/bolt/lib/Core/DIEBuilder.cpp
@@ -42,29 +42,6 @@ extern cl::opt<unsigned> Verbosity;
namespace llvm {
namespace bolt {
-/// Returns DWO Name to be used to update DW_AT_dwo_name/DW_AT_GNU_dwo_name
-/// either in CU or TU unit die. Handles case where user specifies output DWO
-/// directory, and there are duplicate names. Assumes DWO ID is unique.
-static std::string
-getDWOName(llvm::DWARFUnit &CU,
- std::unordered_map<std::string, uint32_t> &NameToIndexMap,
- std::optional<StringRef> &DwarfOutputPath) {
- assert(CU.getDWOId() && "DWO ID not found.");
- std::string DWOName = dwarf::toString(
- CU.getUnitDIE().find({dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}),
- "");
- assert(!DWOName.empty() &&
- "DW_AT_dwo_name/DW_AT_GNU_dwo_name does not exist.");
- if (DwarfOutputPath) {
- DWOName = std::string(sys::path::filename(DWOName));
- uint32_t &Index = NameToIndexMap[DWOName];
- DWOName.append(std::to_string(Index));
- ++Index;
- }
- DWOName.append(".dwo");
- return DWOName;
-}
-
/// Adds a \p Str to .debug_str section.
/// Uses \p AttrInfoVal to either update entry in a DIE for legacy DWARF using
/// \p DebugInfoPatcher, or for DWARF5 update an index in .debug_str_offsets
diff --git a/bolt/lib/Core/DebugData.cpp b/bolt/lib/Core/DebugData.cpp
index 31d7bc99a821b..349f91435ef60 100644
--- a/bolt/lib/Core/DebugData.cpp
+++ b/bolt/lib/Core/DebugData.cpp
@@ -595,7 +595,7 @@ void DebugLocWriter::addList(DIEBuilder &DIEBldr, DIE &Die, DIEValue &AttrInfo,
}
LocStream->write_zeros(16);
LocSectionOffset = LocBuffer->size();
- LocListDebugInfoPatches.push_back({0xdeadbeee, EntryOffset});
+ LocListDebugInfoPatches.push_back({0xdeadbeee, EntryOffset});
replaceLocValbyForm(DIEBldr, Die, AttrInfo, AttrInfo.getForm(), EntryOffset);
LocListPatches.push_back({&Die, AttrInfo.getAttribute(), AttrInfo.getForm()});
}
@@ -772,13 +772,12 @@ void DebugLoclistWriter::finalizeDWARF5(DIEBuilder &DIEBldr, DIE &Die) {
DIEValue LocListBaseAttrInfo =
Die.findAttribute(dwarf::DW_AT_loclists_base);
if (LocListBaseAttrInfo.getType()) {
- DIEBldr.replaceValue(
- &Die, dwarf::DW_AT_loclists_base, LocListBaseAttrInfo.getForm(),
- DIEInteger(LocalBase));
+ 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(LocalBase));
+ dwarf::DW_FORM_sec_offset, DIEInteger(LocalBase));
}
}
clearList(RelativeLocListOffsets);
diff --git a/bolt/lib/Core/DebugNames.cpp b/bolt/lib/Core/DebugNames.cpp
index 450e02ed37773..9eb6df10940da 100644
--- a/bolt/lib/Core/DebugNames.cpp
+++ b/bolt/lib/Core/DebugNames.cpp
@@ -12,8 +12,8 @@
#include "llvm/DebugInfo/DWARF/LowLevel/DWARFExpression.h"
#include "llvm/Support/EndianStream.h"
#include "llvm/Support/LEB128.h"
-#include <cstdint>
#include <climits>
+#include <cstdint>
#include <optional>
#include <tuple>
@@ -66,7 +66,6 @@ DWARF5AcceleratorTable::DWARF5AcceleratorTable(
}
}
-//
void DWARF5AcceleratorTable::preAllocateUnits(DWARFContext &DwCtx) {
// Collect all DWO IDs in deterministic order (by CU offset in .debug_info).
// This is single-threaded, called before parallel process.
diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp
index 7dfddeac43be8..ecdb8f6ad42cd 100644
--- a/bolt/lib/Rewrite/DWARFRewriter.cpp
+++ b/bolt/lib/Rewrite/DWARFRewriter.cpp
@@ -957,7 +957,7 @@ void DWARFRewriter::processMainBinaryCU(DWARFUnit &Unit, DIEBuilder &DIEBlder,
DebugLocWriter.finalize(DIEBlder, *DIEBlder.getUnitDIEbyUnit(Unit));
if (DWARFVersion >= 5)
RangesSectionWriter.finalizeSection();
-};
+}
void DWARFRewriter::updateDebugInfo() {
ErrorOr<BinarySection &> DebugInfo = BC.getUniqueSectionByName(".debug_info");
More information about the llvm-commits
mailing list