[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:12:01 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 ee64a9d23bab9016f7a22c4eff31ba8e2f6c43f5 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Wed, 6 May 2026 23:02:53 +0800
Subject: [PATCH 6/6] fix format and build error

---
 bolt/include/bolt/Core/DIEBuilder.h       | 31 ++++++++++++-----------
 bolt/include/bolt/Core/DebugData.h        |  3 ++-
 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, 28 insertions(+), 51 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..197b5f91bee42 100644
--- a/bolt/include/bolt/Core/DebugData.h
+++ b/bolt/include/bolt/Core/DebugData.h
@@ -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