diff --git a/bolt/include/bolt/Core/DebugData.h b/bolt/include/bolt/Core/DebugData.h
--- a/bolt/include/bolt/Core/DebugData.h
+++ b/bolt/include/bolt/Core/DebugData.h
@@ -155,7 +155,7 @@
   uint64_t getSectionOffset();
 
   /// Returns a buffer containing Ranges.
-  virtual std::unique_ptr<DebugBufferVector> finalize() {
+  virtual std::unique_ptr<DebugBufferVector> releaseBuffer() {
     return std::move(RangesBuffer);
   }
 
@@ -165,6 +165,12 @@
     return Writer->getKind() == RangesWriterKind::DebugRangesWriter;
   }
 
+  /// Writes out range lists for a current CU being processed.
+  void virtual finalizeSection(){};
+
+  /// Needs to be invoked before each \p CU is processed.
+  void virtual initSection(DWARFUnit &CU){};
+
 protected:
   std::unique_ptr<DebugBufferVector> RangesBuffer;
 
@@ -203,16 +209,18 @@
   /// Add ranges and return offset into section.
   virtual uint64_t addRanges(const DebugAddressRangesVector &Ranges) override;
 
-  virtual std::unique_ptr<DebugBufferVector> finalize() override {
+  virtual std::unique_ptr<DebugBufferVector> releaseBuffer() override {
     return std::move(RangesBuffer);
   }
 
-  /// Needs to be invoked before each CU is processed.
-  /// \p CUID is a unique ID of each CU.
-  void initSection(uint64_t CUID);
+  /// Needs to be invoked before each \p CU is processed.
+  void virtual initSection(DWARFUnit &CU) override;
 
   /// Writes out range lists for a current CU being processed.
-  void finalizeSection();
+  void virtual finalizeSection() override;
+
+  // Returns true if section is empty.
+  bool empty() { return RangesBuffer->empty(); }
 
   static bool classof(const DebugRangesSectionWriter *Writer) {
     return Writer->getKind() == RangesWriterKind::DebugRangeListsWriter;
@@ -220,8 +228,8 @@
 
 private:
   static DebugAddrWriter *AddrWriter;
-  /// Unique ID of CU being processed.
-  uint64_t CUID{0};
+  /// Used to find unique CU ID.
+  DWARFUnit *CU;
   /// Current relative offset of range list entry within this CUs rangelist
   /// body.
   uint32_t CurrentOffset{0};
@@ -275,10 +283,10 @@
   virtual ~DebugAddrWriter(){};
   /// Given an address returns an index in .debug_addr.
   /// Adds Address to map.
-  uint32_t getIndexFromAddress(uint64_t Address, uint64_t CUID);
+  uint32_t getIndexFromAddress(uint64_t Address, DWARFUnit &CU);
 
-  /// Adds {Address, Index} to DWO ID CU.
-  void addIndexAddress(uint64_t Address, uint32_t Index, uint64_t CUID);
+  /// Adds {\p Address, \p Index} to \p CU.
+  void addIndexAddress(uint64_t Address, uint32_t Index, DWARFUnit &CU);
 
   /// Creates consolidated .debug_addr section, and builds DWOID to offset map.
   virtual AddressSectionBuffer finalize();
@@ -338,6 +346,12 @@
     IndexToAddressMap IndexToAddress;
     uint32_t CurrentIndex{0};
   };
+
+  virtual uint64_t getCUID(DWARFUnit &Unit) {
+    assert(Unit.getDWOId() && "Unit is not Skeleton CU.");
+    return *Unit.getDWOId();
+  }
+
   BinaryContext *BC;
   /// Maps DWOID to AddressForDWOCU.
   std::unordered_map<uint64_t, AddressForDWOCU> AddressMaps;
@@ -357,14 +371,60 @@
   /// Given DWARFUnit \p Unit returns offset of this CU in to .debug_addr
   /// section.
   virtual uint64_t getOffset(DWARFUnit &Unit) override;
+
+protected:
+  /// Given DWARFUnit \p Unit returns either DWO ID or it's offset within
+  /// .debug_info.
+  virtual uint64_t getCUID(DWARFUnit &Unit) override {
+    if (Unit.isDWOUnit()) {
+      DWARFUnit *SkeletonCU = Unit.getLinkedUnit();
+      return SkeletonCU->getOffset();
+    }
+    return Unit.getOffset();
+  }
+};
+
+/// This class is NOT thread safe.
+using DebugStrOffsetsBufferVector = SmallVector<char, 16>;
+class DebugStrOffsetsWriter {
+public:
+  DebugStrOffsetsWriter() {
+    StrOffsetsBuffer = std::make_unique<DebugStrOffsetsBufferVector>();
+    StrOffsetsStream = std::make_unique<raw_svector_ostream>(*StrOffsetsBuffer);
+  }
+
+  /// Initializes Buffer and Stream.
+  void initialize(const DWARFSection &StrOffsetsSection,
+                  const Optional<StrOffsetsContributionDescriptor> Contr);
+
+  /// Update Str offset in .debug_str in .debug_str_offsets.
+  void updateAddressMap(uint32_t Index, uint32_t Address);
+
+  /// Writes out current sections entry into .debug_str_offsets.
+  void finalizeSection();
+
+  /// Returns False if no strings were added to .debug_str.
+  bool isFinalized() const { return !StrOffsetsBuffer->empty(); }
+
+  /// Returns buffer containing .debug_str_offsets.
+  std::unique_ptr<DebugStrOffsetsBufferVector> releaseBuffer() {
+    return std::move(StrOffsetsBuffer);
+  }
+
+private:
+  std::unique_ptr<DebugStrOffsetsBufferVector> StrOffsetsBuffer;
+  std::unique_ptr<raw_svector_ostream> StrOffsetsStream;
+  std::map<uint32_t, uint32_t> IndexToAddressMap;
+  // Section size not including header.
+  uint32_t CurrentSectionSize{0};
 };
 
 using DebugStrBufferVector = SmallVector<char, 16>;
 class DebugStrWriter {
 public:
   DebugStrWriter() = delete;
-  DebugStrWriter(BinaryContext *Bc) : BC(Bc) { create(); }
-  std::unique_ptr<DebugStrBufferVector> finalize() {
+  DebugStrWriter(BinaryContext &BC) : BC(BC) { create(); }
+  std::unique_ptr<DebugStrBufferVector> releaseBuffer() {
     return std::move(StrBuffer);
   }
 
@@ -384,7 +444,7 @@
   void create();
   std::unique_ptr<DebugStrBufferVector> StrBuffer;
   std::unique_ptr<raw_svector_ostream> StrStream;
-  BinaryContext *BC;
+  BinaryContext &BC;
 };
 
 enum class LocWriterKind { DebugLocWriter, DebugLoclistWriter };
@@ -451,9 +511,9 @@
 public:
   ~DebugLoclistWriter() {}
   DebugLoclistWriter() = delete;
-  DebugLoclistWriter(BinaryContext *BC, uint64_t CID,
+  DebugLoclistWriter(BinaryContext *BC, DWARFUnit &Unit,
                      uint32_t LocListsBaseAttrOffset, uint8_t DV, bool SD)
-      : DebugLocWriter(BC), CUID(CID),
+      : DebugLocWriter(BC), CU(Unit),
         LocListsBaseAttrOffset(LocListsBaseAttrOffset), IsSplitDwarf(SD) {
     Kind = LocWriterKind::DebugLoclistWriter;
     DwarfVersion = DV;
@@ -472,8 +532,12 @@
   void finalize(uint64_t SectionOffset,
                 SimpleBinaryPatcher &DebugInfoPatcher) override;
 
-  /// Returns DWO ID.
-  uint64_t getCUID() const { return CUID; }
+  /// Returns CU ID.
+  /// For Skelton CU it is a CU Offset.
+  /// For DWO CU it is a DWO ID.
+  uint64_t getCUID() const {
+    return CU.isDWOUnit() ? *CU.getDWOId() : CU.getOffset();
+  }
 
   LocWriterKind getKind() const { return DebugLocWriter::getKind(); }
 
@@ -511,7 +575,7 @@
     uint64_t Address{0};
   };
   static DebugAddrWriter *AddrWriter;
-  uint64_t CUID{0};
+  DWARFUnit &CU;
   uint32_t LocListsBaseAttrOffset{InvalidLocListsBaseAttrOffset};
   bool IsSplitDwarf{false};
 };
diff --git a/bolt/include/bolt/Rewrite/DWARFRewriter.h b/bolt/include/bolt/Rewrite/DWARFRewriter.h
--- a/bolt/include/bolt/Rewrite/DWARFRewriter.h
+++ b/bolt/include/bolt/Rewrite/DWARFRewriter.h
@@ -48,6 +48,10 @@
   /// Does not do de-duplication.
   std::unique_ptr<DebugStrWriter> StrWriter;
 
+  /// Stores and serializes information that will be put in to the
+  /// .debug_str_offsets DWARF section.
+  std::unique_ptr<DebugStrOffsetsWriter> StrOffstsWriter;
+
   /// .debug_abbrev section writer for the main binary.
   std::unique_ptr<DebugAbbrevWriter> AbbrevWriter;
 
@@ -55,6 +59,12 @@
   /// Use a separate location list writer for each compilation unit
   LocWriters LocListWritersByCU;
 
+  using RangeListsDWOWriers =
+      std::unordered_map<uint64_t,
+                         std::unique_ptr<DebugRangeListsSectionWriter>>;
+  /// Store Rangelists writer for each DWO CU.
+  RangeListsDWOWriers RangeListsWritersByCU;
+
   using DebugAbbrevDWOWriters =
       std::unordered_map<uint64_t, std::unique_ptr<DebugAbbrevWriter>>;
   /// Abbrev section writers for DWOs.
@@ -167,6 +177,14 @@
     return static_cast<Patcher *>(Iter->second.get());
   }
 
+  /// 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
+  /// for this contribution of \p Unit.
+  void addStringHelper(DebugInfoBinaryPatcher &DebugInfoPatcher,
+                       const DWARFUnit &Unit, const AttrInfo &AttrInfoVal,
+                       StringRef Str);
+
 public:
   DWARFRewriter(BinaryContext &BC) : BC(BC) {}
 
diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp
--- a/bolt/lib/Core/BinaryContext.cpp
+++ b/bolt/lib/Core/BinaryContext.cpp
@@ -1500,6 +1500,8 @@
            << DwCtx->getNumCompileUnits() << " CUs will be updated\n";
   }
 
+  preprocessDWODebugInfo();
+
   // Populate MCContext with DWARF files from all units.
   StringRef GlobalPrefix = AsmInfo->getPrivateGlobalPrefix();
   for (const std::unique_ptr<DWARFUnit> &CU : DwCtx->compile_units()) {
@@ -1521,10 +1523,16 @@
       Optional<MD5::MD5Result> Checksum = None;
       if (LineTable->Prologue.ContentTypes.HasMD5)
         Checksum = LineTable->Prologue.FileNames[0].Checksum;
-      BinaryLineTable.setRootFile(
-          CU->getCompilationDir(),
-          dwarf::toString(CU->getUnitDIE().find(dwarf::DW_AT_name), nullptr),
-          Checksum, None);
+      Optional<const char *> Name =
+          dwarf::toString(CU->getUnitDIE().find(dwarf::DW_AT_name), nullptr);
+      if (Optional<uint64_t> DWOID = CU->getDWOId()) {
+        auto Iter = DWOCUs.find(*DWOID);
+        assert(Iter != DWOCUs.end() && "DWO CU was not found.");
+        Name = dwarf::toString(
+            Iter->second->getUnitDIE().find(dwarf::DW_AT_name), nullptr);
+      }
+      BinaryLineTable.setRootFile(CU->getCompilationDir(), *Name, Checksum,
+                                  None);
     }
 
     BinaryLineTable.setDwarfVersion(DwarfVersion);
@@ -1557,8 +1565,6 @@
           getDwarfFile(Dir, FileName, 0, Checksum, None, CUID, DwarfVersion));
     }
   }
-
-  preprocessDWODebugInfo();
 }
 
 bool BinaryContext::shouldEmit(const BinaryFunction &Function) const {
diff --git a/bolt/lib/Core/DebugData.cpp b/bolt/lib/Core/DebugData.cpp
--- a/bolt/lib/Core/DebugData.cpp
+++ b/bolt/lib/Core/DebugData.cpp
@@ -29,6 +29,7 @@
 #include <cstdint>
 #include <limits>
 #include <unordered_map>
+#include <vector>
 
 #define DEBUG_TYPE "bolt-debug-info"
 
@@ -207,7 +208,7 @@
     support::endian::write(*CUBodyStream,
                            static_cast<uint8_t>(dwarf::DW_RLE_startx_length),
                            support::little);
-    const uint32_t Index = AddrWriter->getIndexFromAddress(Range.LowPC, CUID);
+    uint32_t Index = AddrWriter->getIndexFromAddress(Range.LowPC, *CU);
     encodeULEB128(Index, *CUBodyStream);
     encodeULEB128(Range.HighPC - Range.LowPC, *CUBodyStream);
   }
@@ -238,12 +239,12 @@
   SectionOffset = RangesBuffer->size();
 }
 
-void DebugRangeListsSectionWriter::initSection(uint64_t CUId_) {
+void DebugRangeListsSectionWriter::initSection(DWARFUnit &Unit) {
   CUBodyBuffer = std::make_unique<DebugBufferVector>();
   CUBodyStream = std::make_unique<raw_svector_ostream>(*CUBodyBuffer);
   RangeEntries.clear();
   CurrentOffset = 0;
-  CUID = CUId_;
+  CU = &Unit;
 }
 
 void DebugARangesSectionWriter::addCURanges(uint64_t CUOffset,
@@ -311,8 +312,9 @@
   for (auto &Pair : SortedMap)
     dbgs() << Twine::utohexstr(Pair.second) << "\t" << Pair.first << "\n";
 }
-uint32_t DebugAddrWriter::getIndexFromAddress(uint64_t Address, uint64_t CUID) {
+uint32_t DebugAddrWriter::getIndexFromAddress(uint64_t Address, DWARFUnit &CU) {
   std::lock_guard<std::mutex> Lock(WriterMutex);
+  const uint64_t CUID = getCUID(CU);
   if (!AddressMaps.count(CUID))
     AddressMaps[CUID] = AddressForDWOCU();
 
@@ -330,8 +332,9 @@
 // IndexToAddrss. Case3) Address is in the map but Index is lower. Need to
 // update AddressToIndex and IndexToAddress
 void DebugAddrWriter::addIndexAddress(uint64_t Address, uint32_t Index,
-                                      uint64_t CUID) {
+                                      DWARFUnit &CU) {
   std::lock_guard<std::mutex> Lock(WriterMutex);
+  const uint64_t CUID = getCUID(CU);
   AddressForDWOCU &Map = AddressMaps[CUID];
   auto Entry = Map.find(Address);
   if (Entry != Map.end()) {
@@ -349,16 +352,16 @@
   AddressSectionBuffer Buffer;
   raw_svector_ostream AddressStream(Buffer);
   for (std::unique_ptr<DWARFUnit> &CU : BC->DwCtx->compile_units()) {
-    Optional<uint64_t> DWOId = CU->getDWOId();
     // Handling the case wehre debug information is a mix of Debug fission and
     // monolitic.
-    if (!DWOId)
+    if (!CU->getDWOId())
       continue;
-    auto AM = AddressMaps.find(*DWOId);
+    const uint64_t CUID = getCUID(*CU.get());
+    auto AM = AddressMaps.find(CUID);
     assert(AM != AddressMaps.end() && "Address Map not found.");
     // Adding to map even if it did not contribute to .debug_addr.
     // The Skeleton CU will still have DW_AT_GNU_addr_base.
-    DWOIdToOffsetMap[*DWOId] = Buffer.size();
+    DWOIdToOffsetMap[CUID] = Buffer.size();
     // If does not exist this CUs DWO section didn't contribute to .debug_addr.
     if (AM == AddressMaps.end())
       continue;
@@ -410,13 +413,13 @@
   DIDumpOptions DumpOpts;
   constexpr uint32_t HeaderSize = 8;
   for (std::unique_ptr<DWARFUnit> &CU : BC->DwCtx->compile_units()) {
-    const uint64_t CUID = CU->getOffset();
+    const uint64_t CUID = getCUID(*CU.get());
     const uint8_t AddrSize = CU->getAddressByteSize();
-    auto Iter = AddressMaps.find(CUID);
+    auto AMIter = AddressMaps.find(CUID);
     // A case where CU has entry in .debug_addr, but we don't modify addresses
     // for it.
-    if (Iter == AddressMaps.end()) {
-      Iter = AddressMaps.insert({CUID, AddressForDWOCU()}).first;
+    if (AMIter == AddressMaps.end()) {
+      AMIter = AddressMaps.insert({CUID, AddressForDWOCU()}).first;
       Optional<uint64_t> BaseOffset = CU->getAddrOffsetSectionBase();
       if (!BaseOffset)
         continue;
@@ -430,13 +433,14 @@
       }
       uint32_t Index = 0;
       for (uint64_t Addr : AddrTable.getAddressEntries())
-        Iter->second.insert(Addr, Index++);
+        AMIter->second.insert(Addr, Index++);
     }
 
     DWOIdToOffsetMap[CUID] = Buffer.size() + HeaderSize;
 
-    std::vector<IndexAddressPair> SortedMap(Iter->second.indexToAddressBegin(),
-                                            Iter->second.indexToAdddessEnd());
+    std::vector<IndexAddressPair> SortedMap(
+        AMIter->second.indexToAddressBegin(),
+        AMIter->second.indexToAdddessEnd());
     // Sorting address in increasing order of indices.
     std::sort(SortedMap.begin(), SortedMap.end(),
               [](const IndexAddressPair &A, const IndexAddressPair &B) {
@@ -478,16 +482,16 @@
 }
 
 uint64_t DebugAddrWriter::getOffset(DWARFUnit &Unit) {
-  Optional<uint64_t> DWOId = Unit.getDWOId();
-  assert(DWOId && "Can't get offset, not a skeleton CU.");
-  auto Iter = DWOIdToOffsetMap.find(*DWOId);
+  const uint64_t CUID = getCUID(Unit);
+  assert(CUID && "Can't get offset, not a skeleton CU.");
+  auto Iter = DWOIdToOffsetMap.find(CUID);
   assert(Iter != DWOIdToOffsetMap.end() &&
          "Offset in to.debug_addr was not found for DWO ID.");
   return Iter->second;
 }
 
 uint64_t DebugAddrWriterDwarf5::getOffset(DWARFUnit &Unit) {
-  auto Iter = DWOIdToOffsetMap.find(Unit.getOffset());
+  auto Iter = DWOIdToOffsetMap.find(getCUID(Unit));
   assert(Iter != DWOIdToOffsetMap.end() &&
          "Offset in to.debug_addr was not found for DWO ID.");
   return Iter->second;
@@ -601,7 +605,7 @@
       support::endian::write(*LocBodyStream,
                              static_cast<uint8_t>(dwarf::DW_LLE_startx_length),
                              support::little);
-      const uint32_t Index = AddrWriter->getIndexFromAddress(Entry.LowPC, CUID);
+      const uint32_t Index = AddrWriter->getIndexFromAddress(Entry.LowPC, CU);
       encodeULEB128(Index, *LocBodyStream);
       encodeULEB128(Entry.HighPC - Entry.LowPC, *LocBodyStream);
       encodeULEB128(Entry.Expr.size(), *LocBodyStream);
@@ -647,7 +651,7 @@
       support::endian::write(*LocStream,
                              static_cast<uint8_t>(dwarf::DW_LLE_startx_length),
                              support::little);
-      const uint32_t Index = AddrWriter->getIndexFromAddress(Entry.LowPC, CUID);
+      const uint32_t Index = AddrWriter->getIndexFromAddress(Entry.LowPC, CU);
       encodeULEB128(Index, *LocStream);
 
       // TODO: Support DWARF5
@@ -1053,13 +1057,48 @@
   return NewBinaryContents;
 }
 
+void DebugStrOffsetsWriter::initialize(
+    const DWARFSection &StrOffsetsSection,
+    const Optional<StrOffsetsContributionDescriptor> Contr) {
+  if (!Contr)
+    return;
+
+  const uint8_t DwarfOffsetByteSize = Contr->getDwarfOffsetByteSize();
+  assert(DwarfOffsetByteSize == 4 &&
+         "Dwarf String Offsets Byte Size is not supported.");
+  uint32_t Index = 0;
+  for (uint64_t Offset = 0; Offset < Contr->Size; Offset += DwarfOffsetByteSize)
+    IndexToAddressMap[Index++] = *reinterpret_cast<const uint32_t *>(
+        StrOffsetsSection.Data.data() + Contr->Base + Offset);
+}
+
+void DebugStrOffsetsWriter::updateAddressMap(uint32_t Index, uint32_t Address) {
+  assert(IndexToAddressMap.count(Index) > 0 && "Index is not found.");
+  IndexToAddressMap[Index] = Address;
+}
+
+void DebugStrOffsetsWriter::finalizeSection() {
+  if (IndexToAddressMap.empty())
+    return;
+  // Writing out the header for each section.
+  support::endian::write(*StrOffsetsStream, CurrentSectionSize + 4,
+                         support::little);
+  support::endian::write(*StrOffsetsStream, static_cast<uint16_t>(5),
+                         support::little);
+  support::endian::write(*StrOffsetsStream, static_cast<uint16_t>(0),
+                         support::little);
+  for (const auto &Entry : IndexToAddressMap)
+    support::endian::write(*StrOffsetsStream, Entry.second, support::little);
+  IndexToAddressMap.clear();
+}
+
 void DebugStrWriter::create() {
   StrBuffer = std::make_unique<DebugStrBufferVector>();
   StrStream = std::make_unique<raw_svector_ostream>(*StrBuffer);
 }
 
 void DebugStrWriter::initialize() {
-  auto StrSection = BC->DwCtx->getDWARFObj().getStrSection();
+  auto StrSection = BC.DwCtx->getDWARFObj().getStrSection();
   (*StrStream) << StrSection;
 }
 
diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp
--- a/bolt/lib/Rewrite/DWARFRewriter.cpp
+++ b/bolt/lib/Rewrite/DWARFRewriter.cpp
@@ -163,6 +163,19 @@
   return DWOName;
 }
 
+void DWARFRewriter::addStringHelper(DebugInfoBinaryPatcher &DebugInfoPatcher,
+                                    const DWARFUnit &Unit,
+                                    const AttrInfo &AttrInfoVal,
+                                    StringRef Str) {
+  uint32_t NewOffset = StrWriter->addString(Str);
+  if (Unit.getVersion() == 5) {
+    StrOffstsWriter->updateAddressMap(AttrInfoVal.V.getRawUValue(), NewOffset);
+    return;
+  }
+  DebugInfoPatcher.addLE32Patch(AttrInfoVal.Offset, NewOffset,
+                                AttrInfoVal.Size);
+}
+
 void DWARFRewriter::updateDebugInfo() {
   ErrorOr<BinarySection &> DebugInfo = BC.getUniqueSectionByName(".debug_info");
   if (!DebugInfo)
@@ -172,7 +185,10 @@
       static_cast<DebugInfoBinaryPatcher *>(DebugInfo->getPatcher());
 
   ARangesSectionWriter = std::make_unique<DebugARangesSectionWriter>();
-  StrWriter = std::make_unique<DebugStrWriter>(&BC);
+  StrWriter = std::make_unique<DebugStrWriter>(BC);
+
+  StrOffstsWriter = std::make_unique<DebugStrOffsetsWriter>();
+
   AbbrevWriter = std::make_unique<DebugAbbrevWriter>(*BC.DwCtx);
 
   if (BC.isDWARF5Used()) {
@@ -191,19 +207,39 @@
 
   size_t CUIndex = 0;
   for (std::unique_ptr<DWARFUnit> &CU : BC.DwCtx->compile_units()) {
-    if (CU->getVersion() >= 5) {
+    const uint16_t DwarfVersion = CU->getVersion();
+    if (DwarfVersion >= 5) {
       uint32_t AttrInfoOffset =
           DebugLoclistWriter::InvalidLocListsBaseAttrOffset;
       if (Optional<AttrInfo> AttrInfoVal =
-              findAttributeInfo(CU->getUnitDIE(), dwarf::DW_AT_loclists_base))
+              findAttributeInfo(CU->getUnitDIE(), dwarf::DW_AT_loclists_base)) {
         AttrInfoOffset = AttrInfoVal->Offset;
+        LocListWritersByCU[CUIndex] = std::make_unique<DebugLoclistWriter>(
+            &BC, *CU.get(), AttrInfoOffset, DwarfVersion, false);
+      }
+      if (Optional<uint64_t> DWOId = CU->getDWOId()) {
+        assert(LocListWritersByCU.count(*DWOId) == 0 &&
+               "RangeLists writer for DWO unit already exists.");
+        auto RangeListsSectionWriter =
+            std::make_unique<DebugRangeListsSectionWriter>();
+        RangeListsSectionWriter->initSection(*CU.get());
+        RangeListsWritersByCU[*DWOId] = std::move(RangeListsSectionWriter);
+      }
 
-      LocListWritersByCU[CUIndex] = std::make_unique<DebugLoclistWriter>(
-          &BC, CU->isDWOUnit() ? *CU->getDWOId() : CU->getOffset(),
-          AttrInfoOffset, 5, false);
     } else {
       LocListWritersByCU[CUIndex] = std::make_unique<DebugLocWriter>(&BC);
     }
+
+    if (Optional<uint64_t> DWOId = CU->getDWOId()) {
+      assert(LocListWritersByCU.count(*DWOId) == 0 &&
+             "LocList writer for DWO unit already exists.");
+      // Work around some bug in llvm-15. If I pass in directly lld reports
+      // undefined symbol.
+      auto constexpr WorkAround =
+          DebugLoclistWriter::InvalidLocListsBaseAttrOffset;
+      LocListWritersByCU[*DWOId] = std::make_unique<DebugLoclistWriter>(
+          &BC, *CU.get(), WorkAround, DwarfVersion, true);
+    }
     ++CUIndex;
   }
 
@@ -226,19 +262,15 @@
       std::lock_guard<std::mutex> Lock(AccessMutex);
       ObjectName = getDWOName(Unit, &NameToIndexMap, DWOIdToName);
     }
-
-    uint32_t NewOffset = StrWriter->addString(ObjectName.c_str());
-    DebugInfoPatcher->addLE32Patch(AttrInfoVal->Offset, NewOffset,
-                                   AttrInfoVal->Size);
+    addStringHelper(*DebugInfoPatcher, Unit, *AttrInfoVal, ObjectName.c_str());
 
     AttrInfoVal = findAttributeInfo(DIE, dwarf::DW_AT_comp_dir);
     (void)AttrInfoVal;
     assert(AttrInfoVal && "DW_AT_comp_dir is not in Skeleton CU.");
 
     if (!opts::DwarfOutputPath.empty()) {
-      uint32_t NewOffset = StrWriter->addString(opts::DwarfOutputPath.c_str());
-      DebugInfoPatcher->addLE32Patch(AttrInfoVal->Offset, NewOffset,
-                                     AttrInfoVal->Size);
+      addStringHelper(*DebugInfoPatcher, Unit, *AttrInfoVal,
+                      opts::DwarfOutputPath.c_str());
     }
   };
 
@@ -248,6 +280,8 @@
     Optional<DWARFUnit *> SplitCU;
     Optional<uint64_t> RangesBase;
     llvm::Optional<uint64_t> DWOId = Unit->getDWOId();
+    StrOffstsWriter->initialize(Unit->getStringOffsetSection(),
+                                Unit->getStringOffsetsTableContribution());
     if (DWOId)
       SplitCU = BC.getDWOCU(*DWOId);
 
@@ -256,56 +290,59 @@
     if (SplitCU) {
       updateDWONameCompDir(*Unit);
 
-      // Assuming there is unique DWOID per binary. i.e. two or more CUs don't
-      // have same DWO ID.
-      assert(LocListWritersByCU.count(*DWOId) == 0 &&
-             "LocList writer for DWO unit already exists.");
-      {
-        std::lock_guard<std::mutex> Lock(AccessMutex);
-        DebugLocWriter =
-            LocListWritersByCU
-                .insert({*DWOId, std::make_unique<DebugLoclistWriter>(
-                                     &BC, *DWOId, 0, Unit->getVersion(), true)})
-                .first->second.get();
-      }
       DebugInfoBinaryPatcher *DwoDebugInfoPatcher =
           llvm::cast<DebugInfoBinaryPatcher>(
               getBinaryDWODebugInfoPatcher(*DWOId));
-      RangesBase = RangesSectionWriter->getSectionOffset();
       DWARFContext *DWOCtx = BC.getDWOContext();
       // Setting this CU offset with DWP to normalize DIE offsets to uint32_t
       if (DWOCtx && !DWOCtx->getCUIndex().getRows().empty())
         DwoDebugInfoPatcher->setDWPOffset((*SplitCU)->getOffset());
-      DwoDebugInfoPatcher->setRangeBase(*RangesBase);
+
+      {
+        std::lock_guard<std::mutex> Lock(AccessMutex);
+        DebugLocWriter = LocListWritersByCU[*DWOId].get();
+      }
+      DebugRangesSectionWriter *TempRangesSectionWriter =
+          RangesSectionWriter.get();
+      if (Unit->getVersion() >= 5) {
+        TempRangesSectionWriter = RangeListsWritersByCU[*DWOId].get();
+      } else {
+        RangesBase = RangesSectionWriter->getSectionOffset();
+        // For DWARF5 there is now .debug_rnglists.dwo, so don't need to
+        // update rnglists base.
+        DwoDebugInfoPatcher->setRangeBase(*RangesBase);
+      }
+
       DwoDebugInfoPatcher->addUnitBaseOffsetLabel((*SplitCU)->getOffset());
       DebugAbbrevWriter *DWOAbbrevWriter =
           createBinaryDWOAbbrevWriter((*SplitCU)->getContext(), *DWOId);
       updateUnitDebugInfo(*(*SplitCU), *DwoDebugInfoPatcher, *DWOAbbrevWriter,
-                          *DebugLocWriter, *RangesSectionWriter);
+                          *DebugLocWriter, *TempRangesSectionWriter);
       DwoDebugInfoPatcher->clearDestinationLabels();
       if (!DwoDebugInfoPatcher->getWasRangBasedUsed())
         RangesBase = None;
+      if (Unit->getVersion() >= 5)
+        TempRangesSectionWriter->finalizeSection();
     }
 
     {
       std::lock_guard<std::mutex> Lock(AccessMutex);
-      DebugLocWriter = LocListWritersByCU[CUIndex].get();
+      auto LocListWriterIter = LocListWritersByCU.find(CUIndex);
+      if (LocListWriterIter != LocListWritersByCU.end())
+        DebugLocWriter = LocListWriterIter->second.get();
     }
     if (Unit->getVersion() >= 5) {
       RangesBase = RangesSectionWriter->getSectionOffset() +
                    getDWARF5RngListLocListHeaderSize();
-      reinterpret_cast<DebugRangeListsSectionWriter *>(
-          RangesSectionWriter.get())
-          ->initSection(Unit->getOffset());
+      RangesSectionWriter.get()->initSection(*Unit);
+      StrOffstsWriter->finalizeSection();
     }
 
     DebugInfoPatcher->addUnitBaseOffsetLabel(Unit->getOffset());
     updateUnitDebugInfo(*Unit, *DebugInfoPatcher, *AbbrevWriter,
                         *DebugLocWriter, *RangesSectionWriter, RangesBase);
     if (Unit->getVersion() >= 5)
-      reinterpret_cast<DebugRangeListsSectionWriter *>(
-          RangesSectionWriter.get())
-          ->finalizeSection();
+      RangesSectionWriter.get()->finalizeSection();
   };
 
   CUIndex = 0;
@@ -336,14 +373,6 @@
   updateGdbIndexSection(OffsetMap);
 }
 
-static uint64_t getCUId(DWARFUnit &Unit) {
-  if (Unit.getVersion() >= 5)
-    return Unit.getOffset();
-
-  assert(Unit.isDWOUnit() && "Unit is not Skeleton CU.");
-  return *Unit.getDWOId();
-}
-
 void DWARFRewriter::updateUnitDebugInfo(
     DWARFUnit &Unit, DebugInfoBinaryPatcher &DebugInfoPatcher,
     DebugAbbrevWriter &AbbrevWriter, DebugLocWriter &DebugLocWriter,
@@ -376,7 +405,16 @@
     DWARFDie DIE(&Unit, &Die);
 
     switch (DIE.getTag()) {
-    case dwarf::DW_TAG_compile_unit: {
+    case dwarf::DW_TAG_compile_unit:
+    case dwarf::DW_TAG_skeleton_unit: {
+      // For dwarf5 section 3.1.3
+      // The following attributes are not part of a split full compilation unit
+      // entry but instead are inherited (if present) from the corresponding
+      // skeleton compilation unit: DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges,
+      // DW_AT_stmt_list, DW_AT_comp_dir, DW_AT_str_offsets_base,
+      // DW_AT_addr_base and DW_AT_rnglists_base.
+      if (Unit.getVersion() == 5 && Unit.isDWOUnit())
+        continue;
       auto ModuleRangesOrError = DIE.getAddressRanges();
       if (!ModuleRangesOrError) {
         consumeError(ModuleRangesOrError.takeError());
@@ -501,7 +539,7 @@
                 case dwarf::DW_LLE_offset_pair:
                   assert(
                       (Entry.SectionIndex == SectionedAddress::UndefSection &&
-                       !Unit.isDWOUnit()) &&
+                       (!Unit.isDWOUnit() || Unit.getVersion() == 5)) &&
                       "absolute address expected");
                   InputLL.emplace_back(DebugLocationEntry{
                       BaseAddress + Entry.Value0, BaseAddress + Entry.Value1,
@@ -614,7 +652,7 @@
                 const uint32_t EncodingSize =
                     Expr.getOperandEndOffset(0) - PrevOffset - SizeOfOpcode;
                 const uint32_t Index = AddrWriter->getIndexFromAddress(
-                    EntryAddress->Address, getCUId(Unit));
+                    EntryAddress->Address, Unit);
                 // Encoding new size.
                 SmallString<8> Tmp;
                 raw_svector_ostream OSE(Tmp);
@@ -626,8 +664,7 @@
               } else {
                 // TODO: Re-do this as DWARF5.
                 AddrWriter->addIndexAddress(EntryAddress->Address,
-                                            static_cast<uint32_t>(Index),
-                                            getCUId(Unit));
+                                            static_cast<uint32_t>(Index), Unit);
               }
               if (Expr.getDescription().Op[1] ==
                   DWARFExpression::Operation::SizeNA)
@@ -669,10 +706,10 @@
             // TODO: We can now re-write .debug_info. This can be simplified to
             // just getting a new index and creating a patch.
             AddrWriter->addIndexAddress(NewAddress ? NewAddress : Address,
-                                        Index, getCUId(Unit));
+                                        Index, Unit);
           } else if (Form == dwarf::DW_FORM_addrx) {
             const uint32_t Index = AddrWriter->getIndexFromAddress(
-                NewAddress ? NewAddress : Address, getCUId(Unit));
+                NewAddress ? NewAddress : Address, Unit);
             DebugInfoPatcher.addUDataPatch(AttrOffset, Index, AttrVal->Size);
           } else {
             DebugInfoPatcher.addLE64Patch(AttrOffset, NewAddress);
@@ -908,14 +945,23 @@
   if (StrWriter->isInitialized()) {
     RewriteInstance::addToDebugSectionsToOverwrite(".debug_str");
     std::unique_ptr<DebugStrBufferVector> DebugStrSectionContents =
-        StrWriter->finalize();
+        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());
+  }
+
   std::unique_ptr<DebugBufferVector> RangesSectionContents =
-      RangesSectionWriter->finalize();
+      RangesSectionWriter->releaseBuffer();
   BC.registerOrUpdateNoteSection(
       llvm::isa<DebugRangeListsSectionWriter>(*RangesSectionWriter)
           ? ".debug_rnglists"
@@ -1076,7 +1122,11 @@
       {"debug_str.dwo", {MCOFI.getDwarfStrDWOSection(), DW_SECT_EXT_unknown}},
       {"debug_loc.dwo", {MCOFI.getDwarfLocDWOSection(), DW_SECT_EXT_LOC}},
       {"debug_abbrev.dwo", {MCOFI.getDwarfAbbrevDWOSection(), DW_SECT_ABBREV}},
-      {"debug_line.dwo", {MCOFI.getDwarfLineDWOSection(), DW_SECT_LINE}}};
+      {"debug_line.dwo", {MCOFI.getDwarfLineDWOSection(), DW_SECT_LINE}},
+      {"debug_loclists.dwo",
+       {MCOFI.getDwarfLoclistsDWOSection(), DW_SECT_LOCLISTS}},
+      {"debug_rnglists.dwo",
+       {MCOFI.getDwarfRnglistsDWOSection(), DW_SECT_RNGLISTS}}};
   return KnownSectionsTemp;
 }
 
@@ -1090,11 +1140,14 @@
 
 // Exctracts an appropriate slice if input is DWP.
 // Applies patches or overwrites the section.
-Optional<StringRef> updateDebugData(
-    DWARFContext &DWCtx, std::string &Storage, const SectionRef &Section,
-    const StringMap<KnownSectionsEntry> &KnownSections, MCStreamer &Streamer,
-    DWARFRewriter &Writer, const DWARFUnitIndex::Entry *DWOEntry,
-    uint64_t DWOId, std::unique_ptr<DebugBufferVector> &OutputBuffer) {
+Optional<StringRef>
+updateDebugData(DWARFContext &DWCtx, std::string &Storage,
+                StringRef SectionName, StringRef SectionContents,
+                const StringMap<KnownSectionsEntry> &KnownSections,
+                MCStreamer &Streamer, DWARFRewriter &Writer,
+                const DWARFUnitIndex::Entry *DWOEntry, uint64_t DWOId,
+                std::unique_ptr<DebugBufferVector> &OutputBuffer,
+                DebugRangeListsSectionWriter *RangeListsWriter) {
   auto applyPatch = [&](DebugInfoBinaryPatcher *Patcher,
                         StringRef Data) -> StringRef {
     Patcher->computeNewOffsets(DWCtx, true);
@@ -1115,20 +1168,18 @@
     return OutData;
   };
 
-  StringRef Name = getSectionName(Section);
-  auto SectionIter = KnownSections.find(Name);
+  auto SectionIter = KnownSections.find(SectionName);
   if (SectionIter == KnownSections.end())
     return None;
   Streamer.SwitchSection(SectionIter->second.first);
-  Expected<StringRef> Contents = Section.getContents();
-  assert(Contents && "Invalid contents.");
-  StringRef OutData = *Contents;
+  StringRef OutData = SectionContents;
   uint32_t DWPOffset = 0;
 
   switch (SectionIter->second.second) {
   default: {
-    if (!Name.equals("debug_str.dwo"))
-      errs() << "BOLT-WARNING: Unsupported Debug section: " << Name << "\n";
+    if (!SectionName.equals("debug_str.dwo"))
+      errs() << "BOLT-WARNING: unsupported debug section: " << SectionName
+             << "\n";
     return OutData;
   }
   case DWARFSectionKind::DW_SECT_INFO: {
@@ -1155,7 +1206,8 @@
     return StringRef(reinterpret_cast<const char *>(OutputBuffer->data()),
                      OutputBuffer->size());
   }
-  case DWARFSectionKind::DW_SECT_EXT_LOC: {
+  case DWARFSectionKind::DW_SECT_EXT_LOC:
+  case DWARFSectionKind::DW_SECT_LOCLISTS: {
     DebugLocWriter *LocWriter = Writer.getDebugLocWriter(DWOId);
     OutputBuffer = LocWriter->getBuffer();
     // Creating explicit StringRef here, otherwise
@@ -1168,6 +1220,11 @@
     return getSliceData(DWOEntry, OutData, DWARFSectionKind::DW_SECT_LINE,
                         DWPOffset);
   }
+  case DWARFSectionKind::DW_SECT_RNGLISTS: {
+    OutputBuffer = RangeListsWriter->releaseBuffer();
+    return StringRef(reinterpret_cast<const char *>(OutputBuffer->data()),
+                     OutputBuffer->size());
+  }
   }
 }
 
@@ -1255,12 +1312,23 @@
     bool StrSectionWrittenOut = false;
     const object::ObjectFile *DWOFile =
         (*DWOCU)->getContext().getDWARFObj().getFile();
+
+    DebugRangeListsSectionWriter *RangeListssWriter = nullptr;
+    if (CU->getVersion() == 5) {
+      assert(RangeListsWritersByCU.count(*DWOId) != 0 &&
+             "No RangeListsWriter for DWO ID.");
+      RangeListssWriter = RangeListsWritersByCU[*DWOId].get();
+    }
     for (const SectionRef &Section : DWOFile->sections()) {
       std::string Storage = "";
       std::unique_ptr<DebugBufferVector> OutputData;
-      Optional<StringRef> TOutData = updateDebugData(
-          (*DWOCU)->getContext(), Storage, Section, KnownSections, *Streamer,
-          *this, DWOEntry, *DWOId, OutputData);
+      StringRef SectionName = getSectionName(Section);
+      Expected<StringRef> Contents = Section.getContents();
+      assert(Contents && "Invalid contents.");
+      Optional<StringRef> TOutData =
+          updateDebugData((*DWOCU)->getContext(), Storage, SectionName,
+                          *Contents, KnownSections, *Streamer, *this, DWOEntry,
+                          *DWOId, OutputData, RangeListssWriter);
       if (!TOutData)
         continue;
 
@@ -1355,12 +1423,36 @@
     StringMap<KnownSectionsEntry> KnownSections =
         createKnownSectionsMap(*Streamer->getContext().getObjectFileInfo());
 
+    DebugRangeListsSectionWriter *RangeListssWriter = nullptr;
+    if (CU->getVersion() == 5) {
+      assert(RangeListsWritersByCU.count(*DWOId) != 0 &&
+             "No RangeListsWriter for DWO ID.");
+      RangeListssWriter = RangeListsWritersByCU[*DWOId].get();
+
+      // Handling .debug_rnglists.dwo seperatly. The original .o/.dwo might not
+      // have .debug_rnglists so won't be part of the loop below.
+      if (!RangeListssWriter->empty()) {
+        std::string Storage = "";
+        std::unique_ptr<DebugBufferVector> OutputData;
+        if (Optional<StringRef> OutData = updateDebugData(
+                (*DWOCU)->getContext(), Storage, "debug_rnglists.dwo", "",
+                KnownSections, *Streamer, *this, DWOEntry, *DWOId, OutputData,
+                RangeListssWriter))
+          Streamer->emitBytes(*OutData);
+      }
+    }
     for (const SectionRef &Section : File->sections()) {
       std::string Storage = "";
       std::unique_ptr<DebugBufferVector> OutputData;
-      if (Optional<StringRef> OutData = updateDebugData(
-              (*DWOCU)->getContext(), Storage, Section, KnownSections,
-              *Streamer, *this, DWOEntry, *DWOId, OutputData))
+      StringRef SectionName = getSectionName(Section);
+      if (SectionName == "debug_rnglists.dwo")
+        continue;
+      Expected<StringRef> Contents = Section.getContents();
+      assert(Contents && "Invalid contents.");
+      if (Optional<StringRef> OutData =
+              updateDebugData((*DWOCU)->getContext(), Storage, SectionName,
+                              *Contents, KnownSections, *Streamer, *this,
+                              DWOEntry, *DWOId, OutputData, RangeListssWriter))
         Streamer->emitBytes(*OutData);
     }
     Streamer->Finish();
@@ -1630,8 +1722,8 @@
     // DW_FORM_addrx. Former is when DW_AT_rnglists_base is present. Latter is
     // when it's absent.
     if (LowForm == dwarf::DW_FORM_addrx) {
-      uint32_t Index =
-          AddrWriter->getIndexFromAddress(0, DIE.getDwarfUnit()->getOffset());
+      const uint32_t Index =
+          AddrWriter->getIndexFromAddress(0, *DIE.getDwarfUnit());
       DebugInfoPatcher.addUDataPatch(LowPCOffset, Index, LowPCVal->Size);
     } else
       DebugInfoPatcher.addLE64Patch(LowPCOffset, 0);
diff --git a/bolt/test/X86/Inputs/dwarf4-df-dualcu-helper.ll b/bolt/test/X86/Inputs/dwarf4-df-dualcu-helper.ll
new file mode 100644
--- /dev/null
+++ b/bolt/test/X86/Inputs/dwarf4-df-dualcu-helper.ll
@@ -0,0 +1,81 @@
+; clang++ -g -gdwarf-4 -emit-llvm -S helper.cpp
+; int z = 0;
+; int d = 0;
+;
+; int helper(int z_, int d_) {
+;  z += z_;
+;  d += d_;
+;  return z * d;
+; }
+
+; ModuleID = 'helper.cpp'
+source_filename = "helper.cpp"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@z = dso_local global i32 0, align 4, !dbg !0
+@d = dso_local global i32 0, align 4, !dbg !5
+
+; Function Attrs: mustprogress noinline nounwind optnone uwtable
+define dso_local noundef i32 @_Z6helperii(i32 noundef %z_, i32 noundef %d_) #0 !dbg !14 {
+entry:
+  %z_.addr = alloca i32, align 4
+  %d_.addr = alloca i32, align 4
+  store i32 %z_, i32* %z_.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %z_.addr, metadata !18, metadata !DIExpression()), !dbg !19
+  store i32 %d_, i32* %d_.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %d_.addr, metadata !20, metadata !DIExpression()), !dbg !21
+  %0 = load i32, i32* %z_.addr, align 4, !dbg !22
+  %1 = load i32, i32* @z, align 4, !dbg !23
+  %add = add nsw i32 %1, %0, !dbg !23
+  store i32 %add, i32* @z, align 4, !dbg !23
+  %2 = load i32, i32* %d_.addr, align 4, !dbg !24
+  %3 = load i32, i32* @d, align 4, !dbg !25
+  %add1 = add nsw i32 %3, %2, !dbg !25
+  store i32 %add1, i32* @d, align 4, !dbg !25
+  %4 = load i32, i32* @z, align 4, !dbg !26
+  %5 = load i32, i32* @d, align 4, !dbg !27
+  %mul = mul nsw i32 %4, %5, !dbg !28
+  ret i32 %mul, !dbg !29
+}
+
+; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+attributes #0 = { mustprogress noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { nofree nosync nounwind readnone speculatable willreturn }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!8, !9, !10, !11, !12}
+!llvm.ident = !{!13}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "z", scope: !2, file: !3, line: 1, type: !7, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 15.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "helper.cpp", directory: ".")
+!4 = !{!0, !5}
+!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())
+!6 = distinct !DIGlobalVariable(name: "d", scope: !2, file: !3, line: 2, type: !7, isLocal: false, isDefinition: true)
+!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!8 = !{i32 7, !"Dwarf Version", i32 4}
+!9 = !{i32 2, !"Debug Info Version", i32 3}
+!10 = !{i32 1, !"wchar_size", i32 4}
+!11 = !{i32 7, !"uwtable", i32 2}
+!12 = !{i32 7, !"frame-pointer", i32 2}
+!13 = !{!"clang version 15.0.0"}
+!14 = distinct !DISubprogram(name: "helper", linkageName: "_Z6helperii", scope: !3, file: !3, line: 4, type: !15, scopeLine: 4, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !17)
+!15 = !DISubroutineType(types: !16)
+!16 = !{!7, !7, !7}
+!17 = !{}
+!18 = !DILocalVariable(name: "z_", arg: 1, scope: !14, file: !3, line: 4, type: !7)
+!19 = !DILocation(line: 4, column: 16, scope: !14)
+!20 = !DILocalVariable(name: "d_", arg: 2, scope: !14, file: !3, line: 4, type: !7)
+!21 = !DILocation(line: 4, column: 24, scope: !14)
+!22 = !DILocation(line: 5, column: 7, scope: !14)
+!23 = !DILocation(line: 5, column: 4, scope: !14)
+!24 = !DILocation(line: 6, column: 7, scope: !14)
+!25 = !DILocation(line: 6, column: 4, scope: !14)
+!26 = !DILocation(line: 7, column: 9, scope: !14)
+!27 = !DILocation(line: 7, column: 13, scope: !14)
+!28 = !DILocation(line: 7, column: 11, scope: !14)
+!29 = !DILocation(line: 7, column: 2, scope: !14)
diff --git a/bolt/test/X86/Inputs/dwarf4-df-dualcu-loclist-helper.ll b/bolt/test/X86/Inputs/dwarf4-df-dualcu-loclist-helper.ll
new file mode 100644
--- /dev/null
+++ b/bolt/test/X86/Inputs/dwarf4-df-dualcu-loclist-helper.ll
@@ -0,0 +1,61 @@
+; ModuleID = 'helper.cpp'
+source_filename = "helper.cpp"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@z = dso_local local_unnamed_addr global i32 0, align 4, !dbg !0
+@d = dso_local local_unnamed_addr global i32 0, align 4, !dbg !5
+
+; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn uwtable
+define dso_local noundef i32 @_Z6helperii(i32 noundef %z_, i32 noundef %d_) local_unnamed_addr #0 !dbg !13 {
+entry:
+  call void @llvm.dbg.value(metadata i32 %z_, metadata !17, metadata !DIExpression()), !dbg !19
+  call void @llvm.dbg.value(metadata i32 %d_, metadata !18, metadata !DIExpression()), !dbg !19
+  %0 = load i32, i32* @z, align 4, !dbg !20, !tbaa !21
+  %add = add nsw i32 %0, %z_, !dbg !20
+  store i32 %add, i32* @z, align 4, !dbg !20, !tbaa !21
+  %1 = load i32, i32* @d, align 4, !dbg !25, !tbaa !21
+  %add1 = add nsw i32 %1, %d_, !dbg !25
+  store i32 %add1, i32* @d, align 4, !dbg !25, !tbaa !21
+  %mul = mul nsw i32 %add1, %add, !dbg !26
+  ret i32 %mul, !dbg !27
+}
+
+; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #1
+
+attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { nocallback nofree nosync nounwind readnone speculatable willreturn }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!8, !9, !10, !11}
+!llvm.ident = !{!12}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "z", scope: !2, file: !3, line: 1, type: !7, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 15.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "helper.cpp", directory: ".")
+!4 = !{!0, !5}
+!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())
+!6 = distinct !DIGlobalVariable(name: "d", scope: !2, file: !3, line: 2, type: !7, isLocal: false, isDefinition: true)
+!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!8 = !{i32 7, !"Dwarf Version", i32 4}
+!9 = !{i32 2, !"Debug Info Version", i32 3}
+!10 = !{i32 1, !"wchar_size", i32 4}
+!11 = !{i32 7, !"uwtable", i32 2}
+!12 = !{!"clang version 15.0.0"}
+!13 = distinct !DISubprogram(name: "helper", linkageName: "_Z6helperii", scope: !3, file: !3, line: 4, type: !14, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !16)
+!14 = !DISubroutineType(types: !15)
+!15 = !{!7, !7, !7}
+!16 = !{!17, !18}
+!17 = !DILocalVariable(name: "z_", arg: 1, scope: !13, file: !3, line: 4, type: !7)
+!18 = !DILocalVariable(name: "d_", arg: 2, scope: !13, file: !3, line: 4, type: !7)
+!19 = !DILocation(line: 0, scope: !13)
+!20 = !DILocation(line: 5, column: 4, scope: !13)
+!21 = !{!22, !22, i64 0}
+!22 = !{!"int", !23, i64 0}
+!23 = !{!"omnipotent char", !24, i64 0}
+!24 = !{!"Simple C++ TBAA"}
+!25 = !DILocation(line: 6, column: 4, scope: !13)
+!26 = !DILocation(line: 7, column: 11, scope: !13)
+!27 = !DILocation(line: 7, column: 2, scope: !13)
diff --git a/bolt/test/X86/Inputs/dwarf4-df-dualcu-loclist-main.ll b/bolt/test/X86/Inputs/dwarf4-df-dualcu-loclist-main.ll
new file mode 100644
--- /dev/null
+++ b/bolt/test/X86/Inputs/dwarf4-df-dualcu-loclist-main.ll
@@ -0,0 +1,99 @@
+; ModuleID = 'main.cpp'
+source_filename = "main.cpp"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@x = dso_local local_unnamed_addr global i32 0, align 4, !dbg !0
+@y = dso_local local_unnamed_addr global i32 1, align 4, !dbg !5
+
+; Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind willreturn uwtable
+define dso_local void @_Z3usePiS_(i32* nocapture noundef %x, i32* nocapture noundef %y) local_unnamed_addr #0 !dbg !13 {
+entry:
+  call void @llvm.dbg.value(metadata i32* %x, metadata !18, metadata !DIExpression()), !dbg !20
+  call void @llvm.dbg.value(metadata i32* %y, metadata !19, metadata !DIExpression()), !dbg !20
+  %0 = load i32, i32* %x, align 4, !dbg !21, !tbaa !22
+  %add = add nsw i32 %0, 4, !dbg !21
+  store i32 %add, i32* %x, align 4, !dbg !21, !tbaa !22
+  %1 = load i32, i32* %y, align 4, !dbg !26, !tbaa !22
+  %sub = add nsw i32 %1, -2, !dbg !26
+  store i32 %sub, i32* %y, align 4, !dbg !26, !tbaa !22
+  ret void, !dbg !27
+}
+
+; Function Attrs: mustprogress norecurse uwtable
+define dso_local noundef i32 @main(i32 noundef %argc, i8** nocapture noundef readnone %argv) local_unnamed_addr #1 !dbg !28 {
+entry:
+  call void @llvm.dbg.value(metadata i32 %argc, metadata !35, metadata !DIExpression()), !dbg !37
+  call void @llvm.dbg.value(metadata i8** %argv, metadata !36, metadata !DIExpression()), !dbg !37
+  call void @llvm.dbg.value(metadata i32* @x, metadata !18, metadata !DIExpression()), !dbg !38
+  call void @llvm.dbg.value(metadata i32* @y, metadata !19, metadata !DIExpression()), !dbg !38
+  %add.i = add nsw i32 %argc, 4, !dbg !40
+  store i32 %add.i, i32* @x, align 4, !dbg !40, !tbaa !22
+  %sub.i = add nsw i32 %argc, 1, !dbg !41
+  store i32 %sub.i, i32* @y, align 4, !dbg !41, !tbaa !22
+  %call = tail call noundef i32 @_Z6helperii(i32 noundef %add.i, i32 noundef %sub.i), !dbg !42
+  ret i32 %call, !dbg !43
+}
+
+declare !dbg !44 dso_local noundef i32 @_Z6helperii(i32 noundef, i32 noundef) local_unnamed_addr #2
+
+; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
+
+attributes #0 = { argmemonly mustprogress nofree norecurse nosync nounwind willreturn uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { mustprogress norecurse uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #2 = { "frame-pointer"="none" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #3 = { nocallback nofree nosync nounwind readnone speculatable willreturn }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!8, !9, !10, !11}
+!llvm.ident = !{!12}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "x", scope: !2, file: !3, line: 7, type: !7, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 15.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "main.cpp", directory: ".")
+!4 = !{!0, !5}
+!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())
+!6 = distinct !DIGlobalVariable(name: "y", scope: !2, file: !3, line: 8, type: !7, isLocal: false, isDefinition: true)
+!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!8 = !{i32 7, !"Dwarf Version", i32 4}
+!9 = !{i32 2, !"Debug Info Version", i32 3}
+!10 = !{i32 1, !"wchar_size", i32 4}
+!11 = !{i32 7, !"uwtable", i32 2}
+!12 = !{!"clang version 15.0.0"}
+!13 = distinct !DISubprogram(name: "use", linkageName: "_Z3usePiS_", scope: !3, file: !3, line: 1, type: !14, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !17)
+!14 = !DISubroutineType(types: !15)
+!15 = !{null, !16, !16}
+!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64)
+!17 = !{!18, !19}
+!18 = !DILocalVariable(name: "x", arg: 1, scope: !13, file: !3, line: 1, type: !16)
+!19 = !DILocalVariable(name: "y", arg: 2, scope: !13, file: !3, line: 1, type: !16)
+!20 = !DILocation(line: 0, scope: !13)
+!21 = !DILocation(line: 2, column: 4, scope: !13)
+!22 = !{!23, !23, i64 0}
+!23 = !{!"int", !24, i64 0}
+!24 = !{!"omnipotent char", !25, i64 0}
+!25 = !{!"Simple C++ TBAA"}
+!26 = !DILocation(line: 3, column: 4, scope: !13)
+!27 = !DILocation(line: 4, column: 1, scope: !13)
+!28 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 9, type: !29, scopeLine: 9, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !34)
+!29 = !DISubroutineType(types: !30)
+!30 = !{!7, !7, !31}
+!31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !32, size: 64)
+!32 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !33, size: 64)
+!33 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!34 = !{!35, !36}
+!35 = !DILocalVariable(name: "argc", arg: 1, scope: !28, file: !3, line: 9, type: !7)
+!36 = !DILocalVariable(name: "argv", arg: 2, scope: !28, file: !3, line: 9, type: !31)
+!37 = !DILocation(line: 0, scope: !28)
+!38 = !DILocation(line: 0, scope: !13, inlinedAt: !39)
+!39 = distinct !DILocation(line: 12, column: 4, scope: !28)
+!40 = !DILocation(line: 2, column: 4, scope: !13, inlinedAt: !39)
+!41 = !DILocation(line: 3, column: 4, scope: !13, inlinedAt: !39)
+!42 = !DILocation(line: 13, column: 11, scope: !28)
+!43 = !DILocation(line: 13, column: 4, scope: !28)
+!44 = !DISubprogram(name: "helper", linkageName: "_Z6helperii", scope: !3, file: !3, line: 6, type: !45, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !47)
+!45 = !DISubroutineType(types: !46)
+!46 = !{!7, !7, !7}
+!47 = !{}
diff --git a/bolt/test/X86/Inputs/dwarf4-df-dualcu-main.ll b/bolt/test/X86/Inputs/dwarf4-df-dualcu-main.ll
new file mode 100644
--- /dev/null
+++ b/bolt/test/X86/Inputs/dwarf4-df-dualcu-main.ll
@@ -0,0 +1,129 @@
+; clang++ -g -gdwarf-4 -emit-llvm -S main.cpp
+; void use(int * x, int * y) {
+; *x += 4;
+; *y -= 2;
+; }
+;
+; int helper(int z_, int d_);
+; int x = 0;
+; int y = 1;
+; int  main(int argc, char *argv[]) {
+;    x = argc;
+;    y = argc + 3;
+;    use(&x, &y);
+;    return helper(x, y);
+; }
+
+; ModuleID = 'main.cpp'
+source_filename = "main.cpp"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@x = dso_local global i32 0, align 4, !dbg !0
+@y = dso_local global i32 1, align 4, !dbg !5
+
+; Function Attrs: mustprogress noinline nounwind optnone uwtable
+define dso_local void @_Z3usePiS_(i32* noundef %x, i32* noundef %y) #0 !dbg !14 {
+entry:
+  %x.addr = alloca i32*, align 8
+  %y.addr = alloca i32*, align 8
+  store i32* %x, i32** %x.addr, align 8
+  call void @llvm.dbg.declare(metadata i32** %x.addr, metadata !19, metadata !DIExpression()), !dbg !20
+  store i32* %y, i32** %y.addr, align 8
+  call void @llvm.dbg.declare(metadata i32** %y.addr, metadata !21, metadata !DIExpression()), !dbg !22
+  %0 = load i32*, i32** %x.addr, align 8, !dbg !23
+  %1 = load i32, i32* %0, align 4, !dbg !24
+  %add = add nsw i32 %1, 4, !dbg !24
+  store i32 %add, i32* %0, align 4, !dbg !24
+  %2 = load i32*, i32** %y.addr, align 8, !dbg !25
+  %3 = load i32, i32* %2, align 4, !dbg !26
+  %sub = sub nsw i32 %3, 2, !dbg !26
+  store i32 %sub, i32* %2, align 4, !dbg !26
+  ret void, !dbg !27
+}
+
+; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+; Function Attrs: mustprogress noinline norecurse optnone uwtable
+define dso_local noundef i32 @main(i32 noundef %argc, i8** noundef %argv) #2 !dbg !28 {
+entry:
+  %retval = alloca i32, align 4
+  %argc.addr = alloca i32, align 4
+  %argv.addr = alloca i8**, align 8
+  store i32 0, i32* %retval, align 4
+  store i32 %argc, i32* %argc.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %argc.addr, metadata !34, metadata !DIExpression()), !dbg !35
+  store i8** %argv, i8*** %argv.addr, align 8
+  call void @llvm.dbg.declare(metadata i8*** %argv.addr, metadata !36, metadata !DIExpression()), !dbg !37
+  %0 = load i32, i32* %argc.addr, align 4, !dbg !38
+  store i32 %0, i32* @x, align 4, !dbg !39
+  %1 = load i32, i32* %argc.addr, align 4, !dbg !40
+  %add = add nsw i32 %1, 3, !dbg !41
+  store i32 %add, i32* @y, align 4, !dbg !42
+  call void @_Z3usePiS_(i32* noundef @x, i32* noundef @y), !dbg !43
+  %2 = load i32, i32* @x, align 4, !dbg !44
+  %3 = load i32, i32* @y, align 4, !dbg !45
+  %call = call noundef i32 @_Z6helperii(i32 noundef %2, i32 noundef %3), !dbg !46
+  ret i32 %call, !dbg !47
+}
+
+declare dso_local noundef i32 @_Z6helperii(i32 noundef, i32 noundef) #3
+
+attributes #0 = { mustprogress noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { nofree nosync nounwind readnone speculatable willreturn }
+attributes #2 = { mustprogress noinline norecurse optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #3 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!8, !9, !10, !11, !12}
+!llvm.ident = !{!13}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "x", scope: !2, file: !3, line: 7, type: !7, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 15.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "main.cpp", directory: ".")
+!4 = !{!0, !5}
+!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())
+!6 = distinct !DIGlobalVariable(name: "y", scope: !2, file: !3, line: 8, type: !7, isLocal: false, isDefinition: true)
+!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!8 = !{i32 7, !"Dwarf Version", i32 4}
+!9 = !{i32 2, !"Debug Info Version", i32 3}
+!10 = !{i32 1, !"wchar_size", i32 4}
+!11 = !{i32 7, !"uwtable", i32 2}
+!12 = !{i32 7, !"frame-pointer", i32 2}
+!13 = !{!"clang version 15.0.0"}
+!14 = distinct !DISubprogram(name: "use", linkageName: "_Z3usePiS_", scope: !3, file: !3, line: 1, type: !15, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !18)
+!15 = !DISubroutineType(types: !16)
+!16 = !{null, !17, !17}
+!17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64)
+!18 = !{}
+!19 = !DILocalVariable(name: "x", arg: 1, scope: !14, file: !3, line: 1, type: !17)
+!20 = !DILocation(line: 1, column: 16, scope: !14)
+!21 = !DILocalVariable(name: "y", arg: 2, scope: !14, file: !3, line: 1, type: !17)
+!22 = !DILocation(line: 1, column: 25, scope: !14)
+!23 = !DILocation(line: 2, column: 2, scope: !14)
+!24 = !DILocation(line: 2, column: 4, scope: !14)
+!25 = !DILocation(line: 3, column: 2, scope: !14)
+!26 = !DILocation(line: 3, column: 4, scope: !14)
+!27 = !DILocation(line: 4, column: 1, scope: !14)
+!28 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 9, type: !29, scopeLine: 9, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !18)
+!29 = !DISubroutineType(types: !30)
+!30 = !{!7, !7, !31}
+!31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !32, size: 64)
+!32 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !33, size: 64)
+!33 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!34 = !DILocalVariable(name: "argc", arg: 1, scope: !28, file: !3, line: 9, type: !7)
+!35 = !DILocation(line: 9, column: 15, scope: !28)
+!36 = !DILocalVariable(name: "argv", arg: 2, scope: !28, file: !3, line: 9, type: !31)
+!37 = !DILocation(line: 9, column: 27, scope: !28)
+!38 = !DILocation(line: 10, column: 8, scope: !28)
+!39 = !DILocation(line: 10, column: 6, scope: !28)
+!40 = !DILocation(line: 11, column: 8, scope: !28)
+!41 = !DILocation(line: 11, column: 13, scope: !28)
+!42 = !DILocation(line: 11, column: 6, scope: !28)
+!43 = !DILocation(line: 12, column: 4, scope: !28)
+!44 = !DILocation(line: 13, column: 18, scope: !28)
+!45 = !DILocation(line: 13, column: 21, scope: !28)
+!46 = !DILocation(line: 13, column: 11, scope: !28)
+!47 = !DILocation(line: 13, column: 4, scope: !28)
diff --git a/bolt/test/X86/Inputs/dwarf5-df-dualcu-helper.ll b/bolt/test/X86/Inputs/dwarf5-df-dualcu-helper.ll
new file mode 100644
--- /dev/null
+++ b/bolt/test/X86/Inputs/dwarf5-df-dualcu-helper.ll
@@ -0,0 +1,81 @@
+; clang++ -g -gdwarf-5 -emit-llvm -S helper.cpp
+; int z = 0;
+; int d = 0;
+;
+; int helper(int z_, int d_) {
+;  z += z_;
+;  d += d_;
+;  return z * d;
+; }
+
+; ModuleID = 'helper.cpp'
+source_filename = "helper.cpp"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@z = dso_local global i32 0, align 4, !dbg !0
+@d = dso_local global i32 0, align 4, !dbg !5
+
+; Function Attrs: mustprogress noinline nounwind optnone uwtable
+define dso_local noundef i32 @_Z6helperii(i32 noundef %z_, i32 noundef %d_) #0 !dbg !14 {
+entry:
+  %z_.addr = alloca i32, align 4
+  %d_.addr = alloca i32, align 4
+  store i32 %z_, i32* %z_.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %z_.addr, metadata !18, metadata !DIExpression()), !dbg !19
+  store i32 %d_, i32* %d_.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %d_.addr, metadata !20, metadata !DIExpression()), !dbg !21
+  %0 = load i32, i32* %z_.addr, align 4, !dbg !22
+  %1 = load i32, i32* @z, align 4, !dbg !23
+  %add = add nsw i32 %1, %0, !dbg !23
+  store i32 %add, i32* @z, align 4, !dbg !23
+  %2 = load i32, i32* %d_.addr, align 4, !dbg !24
+  %3 = load i32, i32* @d, align 4, !dbg !25
+  %add1 = add nsw i32 %3, %2, !dbg !25
+  store i32 %add1, i32* @d, align 4, !dbg !25
+  %4 = load i32, i32* @z, align 4, !dbg !26
+  %5 = load i32, i32* @d, align 4, !dbg !27
+  %mul = mul nsw i32 %4, %5, !dbg !28
+  ret i32 %mul, !dbg !29
+}
+
+; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+attributes #0 = { mustprogress noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { nofree nosync nounwind readnone speculatable willreturn }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!8, !9, !10, !11, !12}
+!llvm.ident = !{!13}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "z", scope: !2, file: !3, line: 1, type: !7, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 15.0.0", isOptimized: false, runtimeVersion: 0, splitDebugFilename: "helper.dwo", emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: GNU)
+!3 = !DIFile(filename: "helper.cpp", directory: ".", checksumkind: CSK_MD5, checksum: "e635924a35b65444173d0c76a54b866f")
+!4 = !{!0, !5}
+!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())
+!6 = distinct !DIGlobalVariable(name: "d", scope: !2, file: !3, line: 2, type: !7, isLocal: false, isDefinition: true)
+!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!8 = !{i32 7, !"Dwarf Version", i32 5}
+!9 = !{i32 2, !"Debug Info Version", i32 3}
+!10 = !{i32 1, !"wchar_size", i32 4}
+!11 = !{i32 7, !"uwtable", i32 2}
+!12 = !{i32 7, !"frame-pointer", i32 2}
+!13 = !{!"clang version 15.0.0"}
+!14 = distinct !DISubprogram(name: "helper", linkageName: "_Z6helperii", scope: !3, file: !3, line: 4, type: !15, scopeLine: 4, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !17)
+!15 = !DISubroutineType(types: !16)
+!16 = !{!7, !7, !7}
+!17 = !{}
+!18 = !DILocalVariable(name: "z_", arg: 1, scope: !14, file: !3, line: 4, type: !7)
+!19 = !DILocation(line: 4, column: 16, scope: !14)
+!20 = !DILocalVariable(name: "d_", arg: 2, scope: !14, file: !3, line: 4, type: !7)
+!21 = !DILocation(line: 4, column: 24, scope: !14)
+!22 = !DILocation(line: 5, column: 7, scope: !14)
+!23 = !DILocation(line: 5, column: 4, scope: !14)
+!24 = !DILocation(line: 6, column: 7, scope: !14)
+!25 = !DILocation(line: 6, column: 4, scope: !14)
+!26 = !DILocation(line: 7, column: 9, scope: !14)
+!27 = !DILocation(line: 7, column: 13, scope: !14)
+!28 = !DILocation(line: 7, column: 11, scope: !14)
+!29 = !DILocation(line: 7, column: 2, scope: !14)
diff --git a/bolt/test/X86/Inputs/dwarf5-df-dualcu-loclist-helper.ll b/bolt/test/X86/Inputs/dwarf5-df-dualcu-loclist-helper.ll
new file mode 100644
--- /dev/null
+++ b/bolt/test/X86/Inputs/dwarf5-df-dualcu-loclist-helper.ll
@@ -0,0 +1,61 @@
+; ModuleID = 'helper.cpp'
+source_filename = "helper.cpp"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@z = dso_local local_unnamed_addr global i32 0, align 4, !dbg !0
+@d = dso_local local_unnamed_addr global i32 0, align 4, !dbg !5
+
+; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn uwtable
+define dso_local noundef i32 @_Z6helperii(i32 noundef %z_, i32 noundef %d_) local_unnamed_addr #0 !dbg !13 {
+entry:
+  call void @llvm.dbg.value(metadata i32 %z_, metadata !17, metadata !DIExpression()), !dbg !19
+  call void @llvm.dbg.value(metadata i32 %d_, metadata !18, metadata !DIExpression()), !dbg !19
+  %0 = load i32, i32* @z, align 4, !dbg !20, !tbaa !21
+  %add = add nsw i32 %0, %z_, !dbg !20
+  store i32 %add, i32* @z, align 4, !dbg !20, !tbaa !21
+  %1 = load i32, i32* @d, align 4, !dbg !25, !tbaa !21
+  %add1 = add nsw i32 %1, %d_, !dbg !25
+  store i32 %add1, i32* @d, align 4, !dbg !25, !tbaa !21
+  %mul = mul nsw i32 %add1, %add, !dbg !26
+  ret i32 %mul, !dbg !27
+}
+
+; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #1
+
+attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { nocallback nofree nosync nounwind readnone speculatable willreturn }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!8, !9, !10, !11}
+!llvm.ident = !{!12}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "z", scope: !2, file: !3, line: 1, type: !7, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 15.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "helper.cpp", directory: ".", checksumkind: CSK_MD5, checksum: "e635924a35b65444173d0c76a54b866f")
+!4 = !{!0, !5}
+!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())
+!6 = distinct !DIGlobalVariable(name: "d", scope: !2, file: !3, line: 2, type: !7, isLocal: false, isDefinition: true)
+!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!8 = !{i32 7, !"Dwarf Version", i32 5}
+!9 = !{i32 2, !"Debug Info Version", i32 3}
+!10 = !{i32 1, !"wchar_size", i32 4}
+!11 = !{i32 7, !"uwtable", i32 2}
+!12 = !{!"clang version 15.0.0"}
+!13 = distinct !DISubprogram(name: "helper", linkageName: "_Z6helperii", scope: !3, file: !3, line: 4, type: !14, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !16)
+!14 = !DISubroutineType(types: !15)
+!15 = !{!7, !7, !7}
+!16 = !{!17, !18}
+!17 = !DILocalVariable(name: "z_", arg: 1, scope: !13, file: !3, line: 4, type: !7)
+!18 = !DILocalVariable(name: "d_", arg: 2, scope: !13, file: !3, line: 4, type: !7)
+!19 = !DILocation(line: 0, scope: !13)
+!20 = !DILocation(line: 5, column: 4, scope: !13)
+!21 = !{!22, !22, i64 0}
+!22 = !{!"int", !23, i64 0}
+!23 = !{!"omnipotent char", !24, i64 0}
+!24 = !{!"Simple C++ TBAA"}
+!25 = !DILocation(line: 6, column: 4, scope: !13)
+!26 = !DILocation(line: 7, column: 11, scope: !13)
+!27 = !DILocation(line: 7, column: 2, scope: !13)
diff --git a/bolt/test/X86/Inputs/dwarf5-df-dualcu-loclist-main.ll b/bolt/test/X86/Inputs/dwarf5-df-dualcu-loclist-main.ll
new file mode 100644
--- /dev/null
+++ b/bolt/test/X86/Inputs/dwarf5-df-dualcu-loclist-main.ll
@@ -0,0 +1,99 @@
+; ModuleID = 'main.cpp'
+source_filename = "main.cpp"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@x = dso_local local_unnamed_addr global i32 0, align 4, !dbg !0
+@y = dso_local local_unnamed_addr global i32 1, align 4, !dbg !5
+
+; Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind willreturn uwtable
+define dso_local void @_Z3usePiS_(i32* nocapture noundef %x, i32* nocapture noundef %y) local_unnamed_addr #0 !dbg !13 {
+entry:
+  call void @llvm.dbg.value(metadata i32* %x, metadata !18, metadata !DIExpression()), !dbg !20
+  call void @llvm.dbg.value(metadata i32* %y, metadata !19, metadata !DIExpression()), !dbg !20
+  %0 = load i32, i32* %x, align 4, !dbg !21, !tbaa !22
+  %add = add nsw i32 %0, 4, !dbg !21
+  store i32 %add, i32* %x, align 4, !dbg !21, !tbaa !22
+  %1 = load i32, i32* %y, align 4, !dbg !26, !tbaa !22
+  %sub = add nsw i32 %1, -2, !dbg !26
+  store i32 %sub, i32* %y, align 4, !dbg !26, !tbaa !22
+  ret void, !dbg !27
+}
+
+; Function Attrs: mustprogress norecurse uwtable
+define dso_local noundef i32 @main(i32 noundef %argc, i8** nocapture noundef readnone %argv) local_unnamed_addr #1 !dbg !28 {
+entry:
+  call void @llvm.dbg.value(metadata i32 %argc, metadata !35, metadata !DIExpression()), !dbg !37
+  call void @llvm.dbg.value(metadata i8** %argv, metadata !36, metadata !DIExpression()), !dbg !37
+  call void @llvm.dbg.value(metadata i32* @x, metadata !18, metadata !DIExpression()), !dbg !38
+  call void @llvm.dbg.value(metadata i32* @y, metadata !19, metadata !DIExpression()), !dbg !38
+  %add.i = add nsw i32 %argc, 4, !dbg !40
+  store i32 %add.i, i32* @x, align 4, !dbg !40, !tbaa !22
+  %sub.i = add nsw i32 %argc, 1, !dbg !41
+  store i32 %sub.i, i32* @y, align 4, !dbg !41, !tbaa !22
+  %call = tail call noundef i32 @_Z6helperii(i32 noundef %add.i, i32 noundef %sub.i), !dbg !42
+  ret i32 %call, !dbg !43
+}
+
+declare !dbg !44 dso_local noundef i32 @_Z6helperii(i32 noundef, i32 noundef) local_unnamed_addr #2
+
+; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #3
+
+attributes #0 = { argmemonly mustprogress nofree norecurse nosync nounwind willreturn uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { mustprogress norecurse uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #2 = { "frame-pointer"="none" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #3 = { nocallback nofree nosync nounwind readnone speculatable willreturn }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!8, !9, !10, !11}
+!llvm.ident = !{!12}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "x", scope: !2, file: !3, line: 7, type: !7, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 15.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "main.cpp", directory: ".", checksumkind: CSK_MD5, checksum: "1f627913a0daee879e00a3a51726f0ef")
+!4 = !{!0, !5}
+!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())
+!6 = distinct !DIGlobalVariable(name: "y", scope: !2, file: !3, line: 8, type: !7, isLocal: false, isDefinition: true)
+!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!8 = !{i32 7, !"Dwarf Version", i32 5}
+!9 = !{i32 2, !"Debug Info Version", i32 3}
+!10 = !{i32 1, !"wchar_size", i32 4}
+!11 = !{i32 7, !"uwtable", i32 2}
+!12 = !{!"clang version 15.0.0"}
+!13 = distinct !DISubprogram(name: "use", linkageName: "_Z3usePiS_", scope: !3, file: !3, line: 1, type: !14, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !17)
+!14 = !DISubroutineType(types: !15)
+!15 = !{null, !16, !16}
+!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64)
+!17 = !{!18, !19}
+!18 = !DILocalVariable(name: "x", arg: 1, scope: !13, file: !3, line: 1, type: !16)
+!19 = !DILocalVariable(name: "y", arg: 2, scope: !13, file: !3, line: 1, type: !16)
+!20 = !DILocation(line: 0, scope: !13)
+!21 = !DILocation(line: 2, column: 4, scope: !13)
+!22 = !{!23, !23, i64 0}
+!23 = !{!"int", !24, i64 0}
+!24 = !{!"omnipotent char", !25, i64 0}
+!25 = !{!"Simple C++ TBAA"}
+!26 = !DILocation(line: 3, column: 4, scope: !13)
+!27 = !DILocation(line: 4, column: 1, scope: !13)
+!28 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 9, type: !29, scopeLine: 9, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !34)
+!29 = !DISubroutineType(types: !30)
+!30 = !{!7, !7, !31}
+!31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !32, size: 64)
+!32 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !33, size: 64)
+!33 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!34 = !{!35, !36}
+!35 = !DILocalVariable(name: "argc", arg: 1, scope: !28, file: !3, line: 9, type: !7)
+!36 = !DILocalVariable(name: "argv", arg: 2, scope: !28, file: !3, line: 9, type: !31)
+!37 = !DILocation(line: 0, scope: !28)
+!38 = !DILocation(line: 0, scope: !13, inlinedAt: !39)
+!39 = distinct !DILocation(line: 12, column: 4, scope: !28)
+!40 = !DILocation(line: 2, column: 4, scope: !13, inlinedAt: !39)
+!41 = !DILocation(line: 3, column: 4, scope: !13, inlinedAt: !39)
+!42 = !DILocation(line: 13, column: 11, scope: !28)
+!43 = !DILocation(line: 13, column: 4, scope: !28)
+!44 = !DISubprogram(name: "helper", linkageName: "_Z6helperii", scope: !3, file: !3, line: 6, type: !45, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !47)
+!45 = !DISubroutineType(types: !46)
+!46 = !{!7, !7, !7}
+!47 = !{}
diff --git a/bolt/test/X86/Inputs/dwarf5-df-dualcu-main.ll b/bolt/test/X86/Inputs/dwarf5-df-dualcu-main.ll
new file mode 100644
--- /dev/null
+++ b/bolt/test/X86/Inputs/dwarf5-df-dualcu-main.ll
@@ -0,0 +1,129 @@
+; clang++ -g -gdwarf-5 -emit-llvm -S main.cpp
+; void use(int * x, int * y) {
+; *x += 4;
+; *y -= 2;
+; }
+;
+; int helper(int z_, int d_);
+; int x = 0;
+; int y = 1;
+; int  main(int argc, char *argv[]) {
+;    x = argc;
+;    y = argc + 3;
+;    use(&x, &y);
+;    return helper(x, y);
+; }
+
+; ModuleID = 'main.cpp'
+source_filename = "main.cpp"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@x = dso_local global i32 0, align 4, !dbg !0
+@y = dso_local global i32 1, align 4, !dbg !5
+
+; Function Attrs: mustprogress noinline nounwind optnone uwtable
+define dso_local void @_Z3usePiS_(i32* noundef %x, i32* noundef %y) #0 !dbg !14 {
+entry:
+  %x.addr = alloca i32*, align 8
+  %y.addr = alloca i32*, align 8
+  store i32* %x, i32** %x.addr, align 8
+  call void @llvm.dbg.declare(metadata i32** %x.addr, metadata !19, metadata !DIExpression()), !dbg !20
+  store i32* %y, i32** %y.addr, align 8
+  call void @llvm.dbg.declare(metadata i32** %y.addr, metadata !21, metadata !DIExpression()), !dbg !22
+  %0 = load i32*, i32** %x.addr, align 8, !dbg !23
+  %1 = load i32, i32* %0, align 4, !dbg !24
+  %add = add nsw i32 %1, 4, !dbg !24
+  store i32 %add, i32* %0, align 4, !dbg !24
+  %2 = load i32*, i32** %y.addr, align 8, !dbg !25
+  %3 = load i32, i32* %2, align 4, !dbg !26
+  %sub = sub nsw i32 %3, 2, !dbg !26
+  store i32 %sub, i32* %2, align 4, !dbg !26
+  ret void, !dbg !27
+}
+
+; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+; Function Attrs: mustprogress noinline norecurse optnone uwtable
+define dso_local noundef i32 @main(i32 noundef %argc, i8** noundef %argv) #2 !dbg !28 {
+entry:
+  %retval = alloca i32, align 4
+  %argc.addr = alloca i32, align 4
+  %argv.addr = alloca i8**, align 8
+  store i32 0, i32* %retval, align 4
+  store i32 %argc, i32* %argc.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %argc.addr, metadata !34, metadata !DIExpression()), !dbg !35
+  store i8** %argv, i8*** %argv.addr, align 8
+  call void @llvm.dbg.declare(metadata i8*** %argv.addr, metadata !36, metadata !DIExpression()), !dbg !37
+  %0 = load i32, i32* %argc.addr, align 4, !dbg !38
+  store i32 %0, i32* @x, align 4, !dbg !39
+  %1 = load i32, i32* %argc.addr, align 4, !dbg !40
+  %add = add nsw i32 %1, 3, !dbg !41
+  store i32 %add, i32* @y, align 4, !dbg !42
+  call void @_Z3usePiS_(i32* noundef @x, i32* noundef @y), !dbg !43
+  %2 = load i32, i32* @x, align 4, !dbg !44
+  %3 = load i32, i32* @y, align 4, !dbg !45
+  %call = call noundef i32 @_Z6helperii(i32 noundef %2, i32 noundef %3), !dbg !46
+  ret i32 %call, !dbg !47
+}
+
+declare dso_local noundef i32 @_Z6helperii(i32 noundef, i32 noundef) #3
+
+attributes #0 = { mustprogress noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { nofree nosync nounwind readnone speculatable willreturn }
+attributes #2 = { mustprogress noinline norecurse optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #3 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!8, !9, !10, !11, !12}
+!llvm.ident = !{!13}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "x", scope: !2, file: !3, line: 7, type: !7, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 15.0.0", isOptimized: false, runtimeVersion: 0, splitDebugFilename: "main.dwo", emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: GNU)
+!3 = !DIFile(filename: "main.cpp", directory: ".", checksumkind: CSK_MD5, checksum: "1f627913a0daee879e00a3a51726f0ef")
+!4 = !{!0, !5}
+!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())
+!6 = distinct !DIGlobalVariable(name: "y", scope: !2, file: !3, line: 8, type: !7, isLocal: false, isDefinition: true)
+!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!8 = !{i32 7, !"Dwarf Version", i32 5}
+!9 = !{i32 2, !"Debug Info Version", i32 3}
+!10 = !{i32 1, !"wchar_size", i32 4}
+!11 = !{i32 7, !"uwtable", i32 2}
+!12 = !{i32 7, !"frame-pointer", i32 2}
+!13 = !{!"clang version 15.0.0"}
+!14 = distinct !DISubprogram(name: "use", linkageName: "_Z3usePiS_", scope: !3, file: !3, line: 1, type: !15, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !18)
+!15 = !DISubroutineType(types: !16)
+!16 = !{null, !17, !17}
+!17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64)
+!18 = !{}
+!19 = !DILocalVariable(name: "x", arg: 1, scope: !14, file: !3, line: 1, type: !17)
+!20 = !DILocation(line: 1, column: 16, scope: !14)
+!21 = !DILocalVariable(name: "y", arg: 2, scope: !14, file: !3, line: 1, type: !17)
+!22 = !DILocation(line: 1, column: 25, scope: !14)
+!23 = !DILocation(line: 2, column: 2, scope: !14)
+!24 = !DILocation(line: 2, column: 4, scope: !14)
+!25 = !DILocation(line: 3, column: 2, scope: !14)
+!26 = !DILocation(line: 3, column: 4, scope: !14)
+!27 = !DILocation(line: 4, column: 1, scope: !14)
+!28 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 9, type: !29, scopeLine: 9, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !18)
+!29 = !DISubroutineType(types: !30)
+!30 = !{!7, !7, !31}
+!31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !32, size: 64)
+!32 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !33, size: 64)
+!33 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!34 = !DILocalVariable(name: "argc", arg: 1, scope: !28, file: !3, line: 9, type: !7)
+!35 = !DILocation(line: 9, column: 15, scope: !28)
+!36 = !DILocalVariable(name: "argv", arg: 2, scope: !28, file: !3, line: 9, type: !31)
+!37 = !DILocation(line: 9, column: 27, scope: !28)
+!38 = !DILocation(line: 10, column: 8, scope: !28)
+!39 = !DILocation(line: 10, column: 6, scope: !28)
+!40 = !DILocation(line: 11, column: 8, scope: !28)
+!41 = !DILocation(line: 11, column: 13, scope: !28)
+!42 = !DILocation(line: 11, column: 6, scope: !28)
+!43 = !DILocation(line: 12, column: 4, scope: !28)
+!44 = !DILocation(line: 13, column: 18, scope: !28)
+!45 = !DILocation(line: 13, column: 21, scope: !28)
+!46 = !DILocation(line: 13, column: 11, scope: !28)
+!47 = !DILocation(line: 13, column: 4, scope: !28)
diff --git a/bolt/test/X86/Inputs/dwarf5-df-mono-helper.ll b/bolt/test/X86/Inputs/dwarf5-df-mono-helper.ll
new file mode 100644
--- /dev/null
+++ b/bolt/test/X86/Inputs/dwarf5-df-mono-helper.ll
@@ -0,0 +1,81 @@
+; clang++ -g -gdwarf-5 -emit-llvm -S helper.cpp
+; int z = 0;
+; int d = 0;
+;
+; int helper(int z_, int d_) {
+;  z += z_;
+;  d += d_;
+;  return z * d;
+; }
+
+; ModuleID = 'helper.cpp'
+source_filename = "helper.cpp"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@z = dso_local global i32 0, align 4, !dbg !0
+@d = dso_local global i32 0, align 4, !dbg !5
+
+; Function Attrs: mustprogress noinline nounwind optnone uwtable
+define dso_local noundef i32 @_Z6helperii(i32 noundef %z_, i32 noundef %d_) #0 !dbg !14 {
+entry:
+  %z_.addr = alloca i32, align 4
+  %d_.addr = alloca i32, align 4
+  store i32 %z_, i32* %z_.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %z_.addr, metadata !18, metadata !DIExpression()), !dbg !19
+  store i32 %d_, i32* %d_.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %d_.addr, metadata !20, metadata !DIExpression()), !dbg !21
+  %0 = load i32, i32* %z_.addr, align 4, !dbg !22
+  %1 = load i32, i32* @z, align 4, !dbg !23
+  %add = add nsw i32 %1, %0, !dbg !23
+  store i32 %add, i32* @z, align 4, !dbg !23
+  %2 = load i32, i32* %d_.addr, align 4, !dbg !24
+  %3 = load i32, i32* @d, align 4, !dbg !25
+  %add1 = add nsw i32 %3, %2, !dbg !25
+  store i32 %add1, i32* @d, align 4, !dbg !25
+  %4 = load i32, i32* @z, align 4, !dbg !26
+  %5 = load i32, i32* @d, align 4, !dbg !27
+  %mul = mul nsw i32 %4, %5, !dbg !28
+  ret i32 %mul, !dbg !29
+}
+
+; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+attributes #0 = { mustprogress noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { nocallback nofree nosync nounwind readnone speculatable willreturn }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!8, !9, !10, !11, !12}
+!llvm.ident = !{!13}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "z", scope: !2, file: !3, line: 1, type: !7, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 15.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "helper.cpp", directory: ".", checksumkind: CSK_MD5, checksum: "e635924a35b65444173d0c76a54b866f")
+!4 = !{!0, !5}
+!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())
+!6 = distinct !DIGlobalVariable(name: "d", scope: !2, file: !3, line: 2, type: !7, isLocal: false, isDefinition: true)
+!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!8 = !{i32 7, !"Dwarf Version", i32 5}
+!9 = !{i32 2, !"Debug Info Version", i32 3}
+!10 = !{i32 1, !"wchar_size", i32 4}
+!11 = !{i32 7, !"uwtable", i32 2}
+!12 = !{i32 7, !"frame-pointer", i32 2}
+!13 = !{!"clang version 15.0.0"}
+!14 = distinct !DISubprogram(name: "helper", linkageName: "_Z6helperii", scope: !3, file: !3, line: 4, type: !15, scopeLine: 4, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !17)
+!15 = !DISubroutineType(types: !16)
+!16 = !{!7, !7, !7}
+!17 = !{}
+!18 = !DILocalVariable(name: "z_", arg: 1, scope: !14, file: !3, line: 4, type: !7)
+!19 = !DILocation(line: 4, column: 16, scope: !14)
+!20 = !DILocalVariable(name: "d_", arg: 2, scope: !14, file: !3, line: 4, type: !7)
+!21 = !DILocation(line: 4, column: 24, scope: !14)
+!22 = !DILocation(line: 5, column: 7, scope: !14)
+!23 = !DILocation(line: 5, column: 4, scope: !14)
+!24 = !DILocation(line: 6, column: 7, scope: !14)
+!25 = !DILocation(line: 6, column: 4, scope: !14)
+!26 = !DILocation(line: 7, column: 9, scope: !14)
+!27 = !DILocation(line: 7, column: 13, scope: !14)
+!28 = !DILocation(line: 7, column: 11, scope: !14)
+!29 = !DILocation(line: 7, column: 2, scope: !14)
diff --git a/bolt/test/X86/Inputs/dwarf5-df-mono-main.ll b/bolt/test/X86/Inputs/dwarf5-df-mono-main.ll
new file mode 100644
--- /dev/null
+++ b/bolt/test/X86/Inputs/dwarf5-df-mono-main.ll
@@ -0,0 +1,129 @@
+; clang++ -g -gdwarf-5 -gsplit-dwarf=split -emit-llvm -S  main.cpp
+; void use(int * x, int * y) {
+; *x += 4;
+; *y -= 2;
+; }
+;
+; int helper(int z_, int d_);
+; int x = 0;
+; int y = 1;
+; int  main(int argc, char *argv[]) {
+;    x = argc;
+;    y = argc + 3;
+;    use(&x, &y);
+;    return helper(x, y);
+; }
+
+; ModuleID = 'main.cpp'
+source_filename = "main.cpp"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@x = dso_local global i32 0, align 4, !dbg !0
+@y = dso_local global i32 1, align 4, !dbg !5
+
+; Function Attrs: mustprogress noinline nounwind optnone uwtable
+define dso_local void @_Z3usePiS_(i32* noundef %x, i32* noundef %y) #0 !dbg !14 {
+entry:
+  %x.addr = alloca i32*, align 8
+  %y.addr = alloca i32*, align 8
+  store i32* %x, i32** %x.addr, align 8
+  call void @llvm.dbg.declare(metadata i32** %x.addr, metadata !19, metadata !DIExpression()), !dbg !20
+  store i32* %y, i32** %y.addr, align 8
+  call void @llvm.dbg.declare(metadata i32** %y.addr, metadata !21, metadata !DIExpression()), !dbg !22
+  %0 = load i32*, i32** %x.addr, align 8, !dbg !23
+  %1 = load i32, i32* %0, align 4, !dbg !24
+  %add = add nsw i32 %1, 4, !dbg !24
+  store i32 %add, i32* %0, align 4, !dbg !24
+  %2 = load i32*, i32** %y.addr, align 8, !dbg !25
+  %3 = load i32, i32* %2, align 4, !dbg !26
+  %sub = sub nsw i32 %3, 2, !dbg !26
+  store i32 %sub, i32* %2, align 4, !dbg !26
+  ret void, !dbg !27
+}
+
+; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+; Function Attrs: mustprogress noinline norecurse optnone uwtable
+define dso_local noundef i32 @main(i32 noundef %argc, i8** noundef %argv) #2 !dbg !28 {
+entry:
+  %retval = alloca i32, align 4
+  %argc.addr = alloca i32, align 4
+  %argv.addr = alloca i8**, align 8
+  store i32 0, i32* %retval, align 4
+  store i32 %argc, i32* %argc.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %argc.addr, metadata !34, metadata !DIExpression()), !dbg !35
+  store i8** %argv, i8*** %argv.addr, align 8
+  call void @llvm.dbg.declare(metadata i8*** %argv.addr, metadata !36, metadata !DIExpression()), !dbg !37
+  %0 = load i32, i32* %argc.addr, align 4, !dbg !38
+  store i32 %0, i32* @x, align 4, !dbg !39
+  %1 = load i32, i32* %argc.addr, align 4, !dbg !40
+  %add = add nsw i32 %1, 3, !dbg !41
+  store i32 %add, i32* @y, align 4, !dbg !42
+  call void @_Z3usePiS_(i32* noundef @x, i32* noundef @y), !dbg !43
+  %2 = load i32, i32* @x, align 4, !dbg !44
+  %3 = load i32, i32* @y, align 4, !dbg !45
+  %call = call noundef i32 @_Z6helperii(i32 noundef %2, i32 noundef %3), !dbg !46
+  ret i32 %call, !dbg !47
+}
+
+declare dso_local noundef i32 @_Z6helperii(i32 noundef, i32 noundef) #3
+
+attributes #0 = { mustprogress noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { nocallback nofree nosync nounwind readnone speculatable willreturn }
+attributes #2 = { mustprogress noinline norecurse optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #3 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!8, !9, !10, !11, !12}
+!llvm.ident = !{!13}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "x", scope: !2, file: !3, line: 7, type: !7, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 15.0.0", isOptimized: false, runtimeVersion: 0, splitDebugFilename: "main.dwo", emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: GNU)
+!3 = !DIFile(filename: "main.cpp", directory: ".", checksumkind: CSK_MD5, checksum: "1f627913a0daee879e00a3a51726f0ef")
+!4 = !{!0, !5}
+!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())
+!6 = distinct !DIGlobalVariable(name: "y", scope: !2, file: !3, line: 8, type: !7, isLocal: false, isDefinition: true)
+!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!8 = !{i32 7, !"Dwarf Version", i32 5}
+!9 = !{i32 2, !"Debug Info Version", i32 3}
+!10 = !{i32 1, !"wchar_size", i32 4}
+!11 = !{i32 7, !"uwtable", i32 2}
+!12 = !{i32 7, !"frame-pointer", i32 2}
+!13 = !{!"clang version 15.0.0"}
+!14 = distinct !DISubprogram(name: "use", linkageName: "_Z3usePiS_", scope: !3, file: !3, line: 1, type: !15, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !18)
+!15 = !DISubroutineType(types: !16)
+!16 = !{null, !17, !17}
+!17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64)
+!18 = !{}
+!19 = !DILocalVariable(name: "x", arg: 1, scope: !14, file: !3, line: 1, type: !17)
+!20 = !DILocation(line: 1, column: 16, scope: !14)
+!21 = !DILocalVariable(name: "y", arg: 2, scope: !14, file: !3, line: 1, type: !17)
+!22 = !DILocation(line: 1, column: 25, scope: !14)
+!23 = !DILocation(line: 2, column: 2, scope: !14)
+!24 = !DILocation(line: 2, column: 4, scope: !14)
+!25 = !DILocation(line: 3, column: 2, scope: !14)
+!26 = !DILocation(line: 3, column: 4, scope: !14)
+!27 = !DILocation(line: 4, column: 1, scope: !14)
+!28 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 9, type: !29, scopeLine: 9, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !18)
+!29 = !DISubroutineType(types: !30)
+!30 = !{!7, !7, !31}
+!31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !32, size: 64)
+!32 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !33, size: 64)
+!33 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!34 = !DILocalVariable(name: "argc", arg: 1, scope: !28, file: !3, line: 9, type: !7)
+!35 = !DILocation(line: 9, column: 15, scope: !28)
+!36 = !DILocalVariable(name: "argv", arg: 2, scope: !28, file: !3, line: 9, type: !31)
+!37 = !DILocation(line: 9, column: 27, scope: !28)
+!38 = !DILocation(line: 10, column: 8, scope: !28)
+!39 = !DILocation(line: 10, column: 6, scope: !28)
+!40 = !DILocation(line: 11, column: 8, scope: !28)
+!41 = !DILocation(line: 11, column: 13, scope: !28)
+!42 = !DILocation(line: 11, column: 6, scope: !28)
+!43 = !DILocation(line: 12, column: 4, scope: !28)
+!44 = !DILocation(line: 13, column: 18, scope: !28)
+!45 = !DILocation(line: 13, column: 21, scope: !28)
+!46 = !DILocation(line: 13, column: 11, scope: !28)
+!47 = !DILocation(line: 13, column: 4, scope: !28)
diff --git a/bolt/test/X86/debug-fission-single.s b/bolt/test/X86/debug-fission-single.s
--- a/bolt/test/X86/debug-fission-single.s
+++ b/bolt/test/X86/debug-fission-single.s
@@ -19,22 +19,32 @@
 # RUN:   --update-debug-sections \
 # RUN:   --dwarf-output-path=%T \
 # RUN:   -o %t.bolt.1.exe 2>&1 | FileCheck %s
-# RUN: not llvm-dwarfdump --show-form --verbose --debug-info %T/debug-fission-simple.dwo0.dwo -o %tAddrIndexTest 2> /dev/null
-# RUN: cat %tAddrIndexTest | grep DW_FORM_GNU_addr_index | FileCheck %s --check-prefix=CHECK-ADDR-INDEX
+# RUN: llvm-dwarfdump --show-form --verbose --debug-ranges %t.bolt.1.exe &> %tAddrIndexTest
+# RUN: not llvm-dwarfdump --show-form --verbose --debug-info %T/debug-fission-simple.dwo0.dwo >> %tAddrIndexTest
+# RUN: cat %tAddrIndexTest | FileCheck %s --check-prefix=CHECK-DWO-DWO
 # RUN: llvm-dwarfdump --show-form --verbose   --debug-addr  %t.bolt.1.exe | FileCheck %s --check-prefix=CHECK-ADDR-SEC
 
 # CHECK-NOT: warning: DWARF unit from offset {{.*}} incl. to offset {{.*}} excl. tries to read DIEs at offset {{.*}}
 
-# CHECK-ADDR-INDEX: DW_AT_low_pc [DW_FORM_GNU_addr_index]	(indexed (00000000)
-# CHECK-ADDR-INDEX: DW_AT_low_pc [DW_FORM_GNU_addr_index]	(indexed (00000000)
-# CHECK-ADDR-INDEX: DW_AT_low_pc [DW_FORM_GNU_addr_index]	(indexed (00000000)
+# CHECK-DWO-DWO: 00000010
+# CHECK-DWO-DWO: 00000010
+# CHECK-DWO-DWO: 00000050
+# CHECK-DWO-DWO: DW_TAG_subprogram
+# CHECK-DWO-DWO-NEXT: DW_AT_low_pc [DW_FORM_GNU_addr_index]	(indexed (00000000)
+# CHECK-DWO-DWO-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000000
+# CHECK-DWO-DWO: DW_TAG_subprogram
+# CHECK-DWO-DWO-NEXT: DW_AT_low_pc [DW_FORM_GNU_addr_index]	(indexed (00000000)
+# CHECK-DWO-DWO-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000020
+# CHECK-DWO-DWO: DW_TAG_subprogram
+# CHECK-DWO-DWO-NEXT: DW_AT_low_pc [DW_FORM_GNU_addr_index]	(indexed (00000000)
+# CHECK-DWO-DWO-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000040
 
 # CHECK-ADDR-SEC: .debug_addr contents:
 # CHECK-ADDR-SEC: 0x00000000: Addrs: [
 # CHECK-ADDR-SEC: 0x0000000000601000
 
 # RUN: llvm-bolt %t.exe --reorder-blocks=reverse -update-debug-sections -dwarf-output-path=%T -o %t.bolt.2.exe --write-dwp=true
-# RUN: not llvm-dwarfdump --show-form --verbose --debug-info %t.bolt.2.exe.dwp -o %tAddrIndexTestDwp 2> /dev/null
+# RUN: not llvm-dwarfdump --show-form --verbose --debug-info %t.bolt.2.exe.dwp &> %tAddrIndexTestDwp
 # RUN: cat %tAddrIndexTestDwp | FileCheck %s --check-prefix=CHECK-DWP-DEBUG
 
 # CHECK-DWP-DEBUG: DW_TAG_compile_unit [1] *
diff --git a/bolt/test/X86/dwarf4-df-dualcu-loclist.test b/bolt/test/X86/dwarf4-df-dualcu-loclist.test
new file mode 100644
--- /dev/null
+++ b/bolt/test/X86/dwarf4-df-dualcu-loclist.test
@@ -0,0 +1,48 @@
+; RUN: rm -rf %t
+; RUN: mkdir %t
+; RUN: cd %t
+; RUN: llc -split-dwarf-file=main.dwo -split-dwarf-output=main.dwo -O2 -mtriple=x86_64-unknown-linux-gnu \
+; RUN: -filetype=obj %p/Inputs/dwarf4-df-dualcu-loclist-main.ll -o=main.o
+; RUN: llc -split-dwarf-file=helper.dwo -split-dwarf-output=helper.dwo -O2 -mtriple=x86_64-unknown-linux-gnu \
+; RUN: -filetype=obj %p/Inputs/dwarf4-df-dualcu-loclist-helper.ll -o=helper.o
+; RUN: %clang %cflags -gdwarf-5 -O2 -gsplit-dwarf=split main.o helper.o -o main.exe
+; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections
+; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.dwo | FileCheck -check-prefix=PRE-BOLT-DWO-MAIN %s
+; RUN: not llvm-dwarfdump --show-form --verbose --debug-info main.dwo.dwo | FileCheck -check-prefix=BOLT-DWO-MAIN %s
+; RUN: llvm-dwarfdump --show-form --verbose --debug-info helper.dwo | FileCheck -check-prefix=PRE-BOLT-DWO-HELPER %s
+; RUN: not llvm-dwarfdump --show-form --verbose --debug-info helper.dwo.dwo | FileCheck -check-prefix=BOLT-DWO-HELPER %s
+
+; Testing dwarf4 split dwarf for two CUs. Making sure DW_AT_location [DW_FORM_sec_offset] is updated correctly.
+
+; PRE-BOLT-DWO-MAIN: version = 0x0004
+; PRE-BOLT-DWO-MAIN: DW_TAG_formal_parameter [10]
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x00000000:
+; PRE-BOLT-DWO-MAIN-NEXT: DW_LLE_startx_length   (0x0000000000000003, 0x0000000000000014)
+; PRE-BOLT-DWO-MAIN-NEXT: DW_LLE_startx_length   (0x0000000000000005, 0x0000000000000005)
+; PRE-BOLT-DWO-MAIN: DW_TAG_formal_parameter [10]
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x00000016:
+; PRE-BOLT-DWO-MAIN-NEXT: DW_LLE_startx_length   (0x0000000000000003, 0x000000000000000c)
+; PRE-BOLT-DWO-MAIN-NEXT: DW_LLE_startx_length   (0x0000000000000006, 0x000000000000000d)
+
+; BOLT-DWO-MAIN: version = 0x0004
+; BOLT-DWO-MAIN: DW_TAG_formal_parameter [10]
+; BOLT-DWO-MAIN-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x00000000:
+; BOLT-DWO-MAIN-NEXT: DW_LLE_startx_length   (0x0000000000000002, 0x0000000000000014)
+; BOLT-DWO-MAIN-NEXT: DW_LLE_startx_length   (0x0000000000000003, 0x0000000000000005)
+; BOLT-DWO-MAIN: DW_TAG_formal_parameter [10]
+; BOLT-DWO-MAIN-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x00000016:
+; BOLT-DWO-MAIN-NEXT: DW_LLE_startx_length   (0x0000000000000002, 0x000000000000000c)
+; BOLT-DWO-MAIN-NEXT: DW_LLE_startx_length   (0x0000000000000005, 0x000000000000000d)
+
+
+; PRE-BOLT-DWO-HELPER: version = 0x0004
+; PRE-BOLT-DWO-HELPER: DW_TAG_formal_parameter [5]
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x00000000:
+; PRE-BOLT-DWO-HELPER-NEXT: DW_LLE_startx_length   (0x0000000000000002, 0x0000000000000008)
+; PRE-BOLT-DWO-HELPER-NEXT: DW_LLE_startx_length   (0x0000000000000003, 0x0000000000000016)
+
+; BOLT-DWO-HELPER: version = 0x0004
+; BOLT-DWO-HELPER: DW_TAG_formal_parameter [5]
+; BOLT-DWO-HELPER-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x00000000:
+; BOLT-DWO-HELPER-NEXT: DW_LLE_startx_length   (0x0000000000000002, 0x0000000000000008): DW_OP_reg5 RDI
+; BOLT-DWO-HELPER-NEXT: DW_LLE_startx_length   (0x0000000000000003, 0x0000000000000016)
diff --git a/bolt/test/X86/dwarf4-df-dualcu.test b/bolt/test/X86/dwarf4-df-dualcu.test
new file mode 100644
--- /dev/null
+++ b/bolt/test/X86/dwarf4-df-dualcu.test
@@ -0,0 +1,166 @@
+; RUN: rm -rf %t
+; RUN: mkdir %t
+; RUN: cd %t
+; RUN: llc -split-dwarf-file=main.dwo -split-dwarf-output=main.dwo -O0 -mtriple=x86_64-unknown-linux-gnu \
+; RUN: -filetype=obj %p/Inputs/dwarf4-df-dualcu-main.ll -o=main.o
+; RUN: llc -split-dwarf-file=helper.dwo -split-dwarf-output=helper.dwo -O0 -mtriple=x86_64-unknown-linux-gnu \
+; RUN: -filetype=obj %p/Inputs/dwarf4-df-dualcu-helper.ll -o=helper.o
+; RUN: %clang %cflags -gdwarf-5 -gsplit-dwarf=split main.o helper.o -o main.exe
+; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections
+; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.exe | FileCheck -check-prefix=PRE-BOLT %s
+; RUN: llvm-dwarfdump --show-form --verbose --debug-ranges main.exe.bolt &> %t/foo.txt
+; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.exe.bolt >> %t/foo.txt
+; RUN: cat %t/foo.txt | FileCheck -check-prefix=BOLT %s
+; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.dwo &> maindwo.txt
+; RUN cat maindwo.txt | FileCheck -check-prefix=PRE-BOLT-DWO-MAIN %s
+; RUN: not llvm-dwarfdump --show-form --verbose --debug-info main.dwo.dwo &> mainddwodwo.txt
+; RUN: cat mainddwodwo.txt | FileCheck -check-prefix=BOLT-DWO-MAIN %s
+; RUN: llvm-dwarfdump --show-form --verbose --debug-info helper.dwo &> helperdwo.txt
+; RUN: cat helperdwo.txt | FileCheck -check-prefix=PRE-BOLT-DWO-HELPER %s
+; RUN: not llvm-dwarfdump --show-form --verbose --debug-info helper.dwo.dwo &> helperdwodwo.txt
+; RUN: cat helperdwodwo.txt | FileCheck -check-prefix=BOLT-DWO-HELPER %s
+
+; Testing dwarf5 split dwarf for two CUs. Making sure DW_AT_low_pc/DW_AT_high_pc are converted correctly in the binary and in dwo.
+; Checking that DW_AT_location [DW_FORM_exprloc]	(DW_OP_addrx ##) are updated correctly.
+
+; PRE-BOLT: version = 0x0004
+; PRE-BOLT: DW_TAG_compile_unit
+; PRE-BOLT: DW_AT_low_pc [DW_FORM_addr]
+; PRE-BOLT-NEXT: DW_AT_high_pc [DW_FORM_data4]
+; PRE-BOLT-NEXT: DW_AT_GNU_addr_base [DW_FORM_sec_offset]  (0x00000000)
+; PRE-BOLT-NEXT: Compile
+; PRE-BOLT: version = 0x0004
+; PRE-BOLT: DW_TAG_compile_unit
+; PRE-BOLT: DW_AT_low_pc [DW_FORM_addr]
+; PRE-BOLT-NEXT: DW_AT_high_pc [DW_FORM_data4]
+; PRE-BOLT: DW_AT_GNU_addr_base [DW_FORM_sec_offset]  (0x00000020)
+
+; BOLT: .debug_ranges
+; BOLT-NEXT: 00000000 <End of list>
+; BOLT-NEXT: 00000010 [[#%.16x,ADDR:]] [[#%.16x,ADDRB:]]
+; BOLT-NEXT: 00000010 <End of list>
+; BOLT-NEXT: 00000030 [[#%.16x,ADDR1:]] [[#%.16x,ADDR1B:]]
+; BOLT-NEXT: 00000030 <End of list>
+; BOLT-NEXT: 00000050 [[#%.16x,ADDR2:]] [[#%.16x,ADDR2B:]]
+; BOLT-NEXT: 00000050 [[#%.16x,ADDR3:]] [[#%.16x,ADDR3B:]]
+; BOLT-NEXT: 00000050 <End of list>
+; BOLT-NEXT: 00000080 [[#%.16x,ADDR4:]] [[#%.16x,ADDR4B:]]
+; BOLT-NEXT: 00000080 <End of list>
+; BOLT-NEXT: 000000a0 [[#%.16x,ADDR5:]] [[#%.16x,ADDR5B:]]
+; BOLT-NEXT: 000000a0 <End of list>
+
+; BOLT: DW_TAG_compile_unit
+; BOLT: DW_AT_GNU_dwo_name [DW_FORM_strp] ( .debug_str[0x00000016] = "main.dwo.dwo")
+; BOLT-NEXT: DW_AT_GNU_dwo_id
+; BOLT-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000)
+; BOLT-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000050
+; BOLT-NEXT: [0x[[#ADDR2]], 0x[[#ADDR2B]])
+; BOLT-NEXT: [0x[[#ADDR3]], 0x[[#ADDR3B]]))
+; BOLT-NEXT: DW_AT_GNU_addr_base [DW_FORM_sec_offset]  (0x00000000)
+; BOLT-NEXT: DW_AT_GNU_ranges_base [DW_FORM_sec_offset]  (0x00000010)
+; BOLT-NEXT: Compile
+; BOLT: DW_TAG_compile_unit
+; BOLT: DW_AT_GNU_dwo_name [DW_FORM_strp] ( .debug_str[0x00000023] = "helper.dwo.dwo")
+; BOLT-NEXT: DW_AT_GNU_dwo_id
+; BOLT-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000)
+; BOLT-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x000000a0
+; BOLT-NEXT: [0x[[#ADDR5]], 0x[[#ADDR5B]])
+; BOLT-NEXT: DW_AT_GNU_addr_base [DW_FORM_sec_offset]  (0x00000010)
+; BOLT-NEXT: DW_AT_GNU_ranges_base [DW_FORM_sec_offset]  (0x00000080)
+
+; PRE-BOLT-DWO-MAIN: version = 0x0004
+; PRE-BOLT-DWO-MAIN: DW_TAG_compile_unit
+; PRE-BOLT-DWO-MAIN: DW_TAG_variable [2]
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_name [DW_FORM_GNU_str_index]	(indexed (00000000) string = "x")
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_type
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_external
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_decl_file
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_decl_line
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_location [DW_FORM_exprloc]	(DW_OP_GNU_addr_index 0x0)
+; PRE-BOLT-DWO-MAIN: DW_TAG_variable [2]
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_name [DW_FORM_GNU_str_index]	(indexed (00000002) string = "y")
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_type
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_external
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_decl_file
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_decl_line
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_location [DW_FORM_exprloc]	(DW_OP_GNU_addr_index 0x1)
+; PRE-BOLT-DWO-MAIN: DW_TAG_subprogram
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_low_pc [DW_FORM_GNU_addr_index]	(indexed (00000002)
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_high_pc [DW_FORM_data4]	(0x00000024)
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_frame_base
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_linkage_name [DW_FORM_GNU_str_index]	(indexed (00000003) string = "_Z3usePiS_")
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_name [DW_FORM_GNU_str_index]	(indexed (00000004) string = "use")
+; PRE-BOLT-DWO-MAIN: DW_TAG_subprogram
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_low_pc [DW_FORM_GNU_addr_index]	(indexed (00000003)
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_high_pc [DW_FORM_data4]	(0x0000005f)
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_frame_base
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_name [DW_FORM_GNU_str_index]	(indexed (00000005) string = "main")
+
+; BOLT-DWO-MAIN: version = 0x0004
+; BOLT-DWO-MAIN: DW_TAG_compile_unit
+; BOLT-DWO-MAIN: DW_TAG_variable [2]
+; BOLT-DWO-MAIN-NEXT: DW_AT_name [DW_FORM_GNU_str_index]	(indexed (00000000) string = "x")
+; BOLT-DWO-MAIN-NEXT: DW_AT_type
+; BOLT-DWO-MAIN-NEXT: DW_AT_external
+; BOLT-DWO-MAIN-NEXT: DW_AT_decl_file
+; BOLT-DWO-MAIN-NEXT: DW_AT_decl_line
+; BOLT-DWO-MAIN-NEXT: DW_AT_location [DW_FORM_exprloc]	(DW_OP_GNU_addr_index 0x0)
+; BOLT-DWO-MAIN: DW_TAG_variable [2]
+; BOLT-DWO-MAIN-NEXT: DW_AT_name [DW_FORM_GNU_str_index]	(indexed (00000002) string = "y")
+; BOLT-DWO-MAIN-NEXT: DW_AT_type
+; BOLT-DWO-MAIN-NEXT: DW_AT_external
+; BOLT-DWO-MAIN-NEXT: DW_AT_decl_file
+; BOLT-DWO-MAIN-NEXT: DW_AT_decl_line
+; BOLT-DWO-MAIN-NEXT: DW_AT_location [DW_FORM_exprloc]	(DW_OP_GNU_addr_index 0x1)
+; BOLT-DWO-MAIN: DW_TAG_subprogram [4]
+; BOLT-DWO-MAIN-NEXT: DW_AT_low_pc [DW_FORM_GNU_addr_index]	(indexed (00000000)
+; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_sec_offset]	(0x00000000
+; BOLT-DWO-MAIN-NEXT: )
+; BOLT-DWO-MAIN-NEXT: DW_AT_frame_base
+; BOLT-DWO-MAIN-NEXT: DW_AT_linkage_name [DW_FORM_GNU_str_index]	(indexed (00000003) string = "_Z3usePiS_")
+; BOLT-DWO-MAIN-NEXT: DW_AT_name [DW_FORM_GNU_str_index]	(indexed (00000004) string = "use")
+; BOLT-DWO-MAIN: DW_TAG_subprogram [6]
+; BOLT-DWO-MAIN-NEXT: DW_AT_low_pc [DW_FORM_GNU_addr_index]	(indexed (00000000)
+; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_sec_offset]	(0x00000020
+; BOLT-DWO-MAIN-NEXT: )
+; BOLT-DWO-MAIN-NEXT: DW_AT_frame_base [DW_FORM_exprloc]	(DW_OP_reg6 RBP)
+; BOLT-DWO-MAIN-NEXT: DW_AT_name [DW_FORM_GNU_str_index]	(indexed (00000005) string = "main")
+
+
+; PRE-BOLT-DWO-HELPER: version = 0x0004
+; PRE-BOLT-DWO-HELPER: DW_TAG_variable [2]
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_name [DW_FORM_GNU_str_index]	(indexed (00000000) string = "z")
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_type
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_external
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_decl_file
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_decl_line
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_location [DW_FORM_exprloc]	(DW_OP_GNU_addr_index 0x0)
+; PRE-BOLT-DWO-HELPER: DW_TAG_variable [2]
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_name [DW_FORM_GNU_str_index]	(indexed (00000002) string = "d")
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_type
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_external
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_decl_file
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_decl_line
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_location [DW_FORM_exprloc]	(DW_OP_GNU_addr_index 0x1)
+; PRE-BOLT-DWO-HELPER: DW_TAG_subprogram [4]
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_low_pc [DW_FORM_GNU_addr_index]	(indexed (00000002)
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_high_pc [DW_FORM_data4]	(0x0000003d)
+
+; BOLT-DWO-HELPER: version = 0x0004
+; BOLT-DWO-HELPER: DW_TAG_variable [2]
+; BOLT-DWO-HELPER-NEXT: DW_AT_name [DW_FORM_GNU_str_index]	(indexed (00000000) string = "z")
+; BOLT-DWO-HELPER-NEXT: DW_AT_type
+; BOLT-DWO-HELPER-NEXT: DW_AT_external
+; BOLT-DWO-HELPER-NEXT: DW_AT_decl_file
+; BOLT-DWO-HELPER-NEXT: DW_AT_decl_line
+; BOLT-DWO-HELPER-NEXT: DW_AT_location [DW_FORM_exprloc]	(DW_OP_GNU_addr_index 0x0)
+; BOLT-DWO-HELPER: DW_TAG_variable [2]
+; BOLT-DWO-HELPER-NEXT: DW_AT_name [DW_FORM_GNU_str_index]	(indexed (00000002) string = "d")
+; BOLT-DWO-HELPER-NEXT: DW_AT_type
+; BOLT-DWO-HELPER-NEXT: DW_AT_external
+; BOLT-DWO-HELPER-NEXT: DW_AT_decl_file
+; BOLT-DWO-HELPER-NEXT: DW_AT_decl_line
+; BOLT-DWO-HELPER-NEXT: DW_AT_location [DW_FORM_exprloc]	(DW_OP_GNU_addr_index 0x1)
+; BOLT-DWO-HELPER: DW_TAG_subprogram [4]
+; BOLT-DWO-HELPER-NEXT: DW_AT_low_pc [DW_FORM_GNU_addr_index]	(indexed (00000000)
+; BOLT-DWO-HELPER-NEXT: DW_AT_ranges [DW_FORM_sec_offset]	(0x00000000
diff --git a/bolt/test/X86/dwarf5-df-dualcu-loclist.test b/bolt/test/X86/dwarf5-df-dualcu-loclist.test
new file mode 100644
--- /dev/null
+++ b/bolt/test/X86/dwarf5-df-dualcu-loclist.test
@@ -0,0 +1,51 @@
+; RUN: rm -rf %t
+; RUN: mkdir %t
+; RUN: cd %t
+; RUN: llc -split-dwarf-file=main.dwo -split-dwarf-output=main.dwo -O2 -mtriple=x86_64-unknown-linux-gnu \
+; RUN: -filetype=obj %p/Inputs/dwarf5-df-dualcu-loclist-main.ll -o=main.o
+; RUN: llc -split-dwarf-file=helper.dwo -split-dwarf-output=helper.dwo -O2 -mtriple=x86_64-unknown-linux-gnu \
+; RUN: -filetype=obj %p/Inputs/dwarf5-df-dualcu-loclist-helper.ll -o=helper.o
+; RUN: %clang %cflags -gdwarf-5 -O2 -gsplit-dwarf=split main.o helper.o -o main.exe
+; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections
+; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.dwo | FileCheck -check-prefix=PRE-BOLT-DWO-MAIN %s
+; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.dwo.dwo | FileCheck -check-prefix=BOLT-DWO-MAIN %s
+; RUN: llvm-dwarfdump --show-form --verbose --debug-info helper.dwo | FileCheck -check-prefix=PRE-BOLT-DWO-HELPER %s
+; RUN: llvm-dwarfdump --show-form --verbose --debug-info helper.dwo.dwo | FileCheck -check-prefix=BOLT-DWO-HELPER %s
+
+; Testing dwarf5 split dwarf for two CUs. Making sure DW_AT_location [DW_FORM_loclistx] is updated correctly.
+
+; PRE-BOLT-DWO-MAIN: version = 0x0005
+; PRE-BOLT-DWO-MAIN: DW_TAG_formal_parameter [10]
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_location [DW_FORM_loclistx] (indexed (0x0) loclist = 0x00000014:
+; PRE-BOLT-DWO-MAIN-NEXT: DW_LLE_base_addressx   (0x0000000000000002)
+; PRE-BOLT-DWO-MAIN-NEXT: DW_LLE_offset_pair     (0x0000000000000010, 0x0000000000000024)
+; PRE-BOLT-DWO-MAIN-NEXT: DW_LLE_offset_pair     (0x0000000000000024, 0x0000000000000029)
+; PRE-BOLT-DWO-MAIN: DW_TAG_formal_parameter [10]
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_location [DW_FORM_loclistx] (indexed (0x1) loclist = 0x00000024:
+; PRE-BOLT-DWO-MAIN-NEXT: DW_LLE_base_addressx   (0x0000000000000002)
+; PRE-BOLT-DWO-MAIN-NEXT: DW_LLE_offset_pair     (0x0000000000000010, 0x000000000000001c)
+; PRE-BOLT-DWO-MAIN-NEXT: DW_LLE_offset_pair     (0x000000000000001c, 0x0000000000000029)
+
+; BOLT-DWO-MAIN: version = 0x0005
+; BOLT-DWO-MAIN: DW_TAG_formal_parameter [10]
+; BOLT-DWO-MAIN-NEXT: DW_AT_location [DW_FORM_loclistx] (indexed (0x0) loclist = 0x00000014:
+; BOLT-DWO-MAIN-NEXT: DW_LLE_startx_length     (0x0000000000000004, 0x0000000000000014)
+; BOLT-DWO-MAIN-NEXT: DW_LLE_startx_length     (0x0000000000000005, 0x0000000000000005)
+; BOLT-DWO-MAIN: DW_TAG_formal_parameter [10]
+; BOLT-DWO-MAIN-NEXT: DW_AT_location [DW_FORM_loclistx] (indexed (0x1) loclist = 0x00000022:
+; BOLT-DWO-MAIN-NEXT: DW_LLE_startx_length     (0x0000000000000004, 0x000000000000000c)
+; BOLT-DWO-MAIN-NEXT: DW_LLE_startx_length     (0x0000000000000006, 0x000000000000000d)
+
+
+; PRE-BOLT-DWO-HELPER: version = 0x0005
+; PRE-BOLT-DWO-HELPER: DW_TAG_formal_parameter [5]
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_location [DW_FORM_loclistx] (indexed (0x0) loclist = 0x00000010:
+; PRE-BOLT-DWO-HELPER-NEXT: DW_LLE_base_addressx   (0x0000000000000002)
+; PRE-BOLT-DWO-HELPER-NEXT: DW_LLE_offset_pair     (0x0000000000000000, 0x0000000000000008)
+; PRE-BOLT-DWO-HELPER-NEXT: DW_LLE_offset_pair     (0x0000000000000008, 0x000000000000001e)
+
+; BOLT-DWO-HELPER: version = 0x0005
+; BOLT-DWO-HELPER: DW_TAG_formal_parameter [5]
+; BOLT-DWO-HELPER-NEXT: DW_AT_location [DW_FORM_loclistx] (indexed (0x0) loclist = 0x00000010:
+; BOLT-DWO-HELPER-NEXT: DW_LLE_startx_length   (0x0000000000000002, 0x0000000000000008)
+; BOLT-DWO-HELPER-NEXT: DW_LLE_startx_length   (0x0000000000000004, 0x0000000000000016)
diff --git a/bolt/test/X86/dwarf5-df-dualcu.test b/bolt/test/X86/dwarf5-df-dualcu.test
new file mode 100644
--- /dev/null
+++ b/bolt/test/X86/dwarf5-df-dualcu.test
@@ -0,0 +1,152 @@
+; RUN: rm -rf %t
+; RUN: mkdir %t
+; RUN: cd %t
+; RUN: llc -split-dwarf-file=main.dwo -split-dwarf-output=main.dwo -O0 -mtriple=x86_64-unknown-linux-gnu \
+; RUN: -filetype=obj %p/Inputs/dwarf5-df-dualcu-main.ll -o=main.o
+; RUN: llc -split-dwarf-file=helper.dwo -split-dwarf-output=helper.dwo -O0 -mtriple=x86_64-unknown-linux-gnu \
+; RUN: -filetype=obj %p/Inputs/dwarf5-df-dualcu-helper.ll -o=helper.o
+; RUN: %clang %cflags -gdwarf-5 -gsplit-dwarf=split main.o helper.o -o main.exe
+; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections
+; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.exe | FileCheck -check-prefix=PRE-BOLT %s
+; RUN: llvm-dwarfdump --show-form --verbose --debug-addr main.exe.bolt &> %t/foo.txt
+; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.exe.bolt >> %t/foo.txt
+; RUN: cat %t/foo.txt | FileCheck -check-prefix=BOLT %s
+; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.dwo | FileCheck -check-prefix=PRE-BOLT-DWO-MAIN %s
+; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.dwo.dwo | FileCheck -check-prefix=BOLT-DWO-MAIN %s
+; RUN: llvm-dwarfdump --show-form --verbose --debug-info helper.dwo | FileCheck -check-prefix=PRE-BOLT-DWO-HELPER %s
+; RUN: llvm-dwarfdump --show-form --verbose --debug-info helper.dwo.dwo | FileCheck -check-prefix=BOLT-DWO-HELPER %s
+
+; Testing dwarf5 split dwarf for two CUs. Making sure DW_AT_low_pc/DW_AT_high_pc are converted correctly in the binary and in dwo.
+; Checking that DW_AT_location [DW_FORM_exprloc]	(DW_OP_addrx ##) are updated correctly.
+
+; PRE-BOLT: version = 0x0005
+; PRE-BOLT: DW_TAG_skeleton_unit
+; PRE-BOLT: DW_AT_low_pc [DW_FORM_addrx]
+; PRE-BOLT-NEXT: DW_AT_high_pc [DW_FORM_data4]
+; PRE-BOLT: DW_AT_addr_base [DW_FORM_sec_offset]  (0x00000008)
+
+; BOLT: Addrs: [
+; BOLT-NEXT: 0x
+; BOLT-NEXT: 0x
+; BOLT-NEXT: 0x[[#%.16x,ADDR:]]
+; BOLT-NEXT: 0x
+; BOLT-NEXT: 0x[[#%.16x,ADDR2:]]
+; BOLT: Addrs: [
+; BOLT-NEXT: 0x
+; BOLT-NEXT: 0x
+; BOLT-NEXT: 0x[[#%.16x,ADDR3:]]
+; BOLT: DW_TAG_skeleton_unit
+; BOLT: DW_AT_dwo_name [DW_FORM_strx1]  (indexed (00000001) string = "main.dwo.dwo")
+; BOLT-NEXT: DW_AT_low_pc [DW_FORM_addrx]	(indexed (00000003) address = 0x0000000000000000)
+; BOLT-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x0) rangelist = 0x00000010
+; BOLT-NEXT: [0x[[#ADDR]]
+; BOLT-SAME: 0x[[#ADDR + 0x24]]
+; BOLT-NEXT: [0x[[#ADDR2]]
+; BOLT-SAME: 0x[[#ADDR2 + 0x59]]
+; BOLT-NEXT: DW_AT_addr_base [DW_FORM_sec_offset]  (0x00000008)
+; BOLT-NEXT: DW_AT_rnglists_base [DW_FORM_sec_offset]  (0x0000000c)
+; BOLT: DW_TAG_skeleton_unit
+; BOLT: DW_AT_dwo_name [DW_FORM_strx1]  (indexed (00000001) string = "helper.dwo.dwo")
+; BOLT-NEXT: DW_AT_low_pc [DW_FORM_addrx]	(indexed (00000003) address = 0x0000000000000000)
+; BOLT-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x0) rangelist = 0x00000027
+; BOLT-NEXT: [0x[[#ADDR3]]
+; BOLT-SAME: 0x[[#ADDR3 + 0x3D]]
+; BOLT-NEXT: DW_AT_addr_base [DW_FORM_sec_offset]  (0x00000038)
+; BOLT-NEXT: DW_AT_rnglists_base [DW_FORM_sec_offset]  (0x00000023)
+
+; PRE-BOLT-DWO-MAIN: version = 0x0005
+; PRE-BOLT-DWO-MAIN: DW_TAG_compile_unit
+; PRE-BOLT-DWO-MAIN: DW_TAG_variable [2]
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_name [DW_FORM_strx1]	(indexed (00000000) string = "x")
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_type
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_external
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_decl_file
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_decl_line
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_location [DW_FORM_exprloc]	(DW_OP_addrx 0x0)
+; PRE-BOLT-DWO-MAIN: DW_TAG_variable [2]
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_name [DW_FORM_strx1]	(indexed (00000002) string = "y")
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_type
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_external
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_decl_file
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_decl_line
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_location [DW_FORM_exprloc]	(DW_OP_addrx 0x1)
+; PRE-BOLT-DWO-MAIN: DW_TAG_subprogram
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_low_pc [DW_FORM_addrx]	(indexed (00000002)
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_high_pc [DW_FORM_data4]	(0x00000024)
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_frame_base
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_linkage_name [DW_FORM_strx1]	(indexed (00000003) string = "_Z3usePiS_")
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_name [DW_FORM_strx1]	(indexed (00000004) string = "use")
+; PRE-BOLT-DWO-MAIN: DW_TAG_subprogram
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_low_pc [DW_FORM_addrx]	(indexed (00000003)
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_high_pc [DW_FORM_data4]	(0x0000005f)
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_frame_base
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_name [DW_FORM_strx1]	(indexed (00000005) string = "main")
+
+; BOLT-DWO-MAIN: DW_TAG_compile_unit
+; BOLT-DWO-MAIN: DW_TAG_variable [2]
+; BOLT-DWO-MAIN-NEXT: DW_AT_name [DW_FORM_strx1]	(indexed (00000000) string = "x")
+; BOLT-DWO-MAIN-NEXT: DW_AT_type
+; BOLT-DWO-MAIN-NEXT: DW_AT_external
+; BOLT-DWO-MAIN-NEXT: DW_AT_decl_file
+; BOLT-DWO-MAIN-NEXT: DW_AT_decl_line
+; BOLT-DWO-MAIN-NEXT: DW_AT_location [DW_FORM_exprloc]	(DW_OP_addrx 0x0)
+; BOLT-DWO-MAIN: DW_TAG_variable [2]
+; BOLT-DWO-MAIN-NEXT: DW_AT_name [DW_FORM_strx1]	(indexed (00000002) string = "y")
+; BOLT-DWO-MAIN-NEXT: DW_AT_type
+; BOLT-DWO-MAIN-NEXT: DW_AT_external
+; BOLT-DWO-MAIN-NEXT: DW_AT_decl_file
+; BOLT-DWO-MAIN-NEXT: DW_AT_decl_line
+; BOLT-DWO-MAIN-NEXT: DW_AT_location [DW_FORM_exprloc]	(DW_OP_addrx 0x1)
+; BOLT-DWO-MAIN: DW_TAG_subprogram [4]
+; BOLT-DWO-MAIN-NEXT: DW_AT_low_pc [DW_FORM_addrx]	(indexed (00000003)
+; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_rnglistx]	(indexed (0x0) rangelist = 0x00000014
+; BOLT-DWO-MAIN-NEXT: [0x0000000000000000, 0x0000000000000024))
+; BOLT-DWO-MAIN-NEXT: DW_AT_frame_base
+; BOLT-DWO-MAIN-NEXT: DW_AT_linkage_name [DW_FORM_strx1]	(indexed (00000003) string = "_Z3usePiS_")
+; BOLT-DWO-MAIN-NEXT: DW_AT_name [DW_FORM_strx1]	(indexed (00000004) string = "use")
+; BOLT-DWO-MAIN: DW_TAG_subprogram [6]
+; BOLT-DWO-MAIN-NEXT: DW_AT_low_pc [DW_FORM_addrx]	(indexed (00000003)
+; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_rnglistx]	(indexed (0x1) rangelist = 0x00000018
+; BOLT-DWO-MAIN-NEXT: [0x0000000000000000, 0x0000000000000059))
+; BOLT-DWO-MAIN-NEXT: DW_AT_frame_base [DW_FORM_exprloc]	(DW_OP_reg6 RBP)
+; BOLT-DWO-MAIN-NEXT: DW_AT_name [DW_FORM_strx1]	(indexed (00000005) string = "main")
+
+
+; PRE-BOLT-DWO-HELPER: version = 0x0005
+; PRE-BOLT-DWO-HELPER: DW_TAG_variable [2]
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_name [DW_FORM_strx1]	(indexed (00000000) string = "z")
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_type
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_external
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_decl_file
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_decl_line
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_location [DW_FORM_exprloc]	(DW_OP_addrx 0x0)
+; PRE-BOLT-DWO-HELPER: DW_TAG_variable [2]
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_name [DW_FORM_strx1]	(indexed (00000002) string = "d")
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_type
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_external
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_decl_file
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_decl_line
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_location [DW_FORM_exprloc]	(DW_OP_addrx 0x1)
+; PRE-BOLT-DWO-HELPER: DW_TAG_subprogram [4]
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_low_pc [DW_FORM_addrx]	(indexed (00000002)
+; PRE-BOLT-DWO-HELPER-NEXT: DW_AT_high_pc [DW_FORM_data4]	(0x0000003d)
+
+; BOLT-DWO-HELPER: version = 0x0005
+; BOLT-DWO-HELPER: DW_TAG_variable [2]
+; BOLT-DWO-HELPER-NEXT: DW_AT_name [DW_FORM_strx1]	(indexed (00000000) string = "z")
+; BOLT-DWO-HELPER-NEXT: DW_AT_type
+; BOLT-DWO-HELPER-NEXT: DW_AT_external
+; BOLT-DWO-HELPER-NEXT: DW_AT_decl_file
+; BOLT-DWO-HELPER-NEXT: DW_AT_decl_line
+; BOLT-DWO-HELPER-NEXT: DW_AT_location [DW_FORM_exprloc]	(DW_OP_addrx 0x0)
+; BOLT-DWO-HELPER: DW_TAG_variable [2]
+; BOLT-DWO-HELPER-NEXT: DW_AT_name [DW_FORM_strx1]	(indexed (00000002) string = "d")
+; BOLT-DWO-HELPER-NEXT: DW_AT_type
+; BOLT-DWO-HELPER-NEXT: DW_AT_external
+; BOLT-DWO-HELPER-NEXT: DW_AT_decl_file
+; BOLT-DWO-HELPER-NEXT: DW_AT_decl_line
+; BOLT-DWO-HELPER-NEXT: DW_AT_location [DW_FORM_exprloc]	(DW_OP_addrx 0x1)
+; BOLT-DWO-HELPER: DW_TAG_subprogram [4]
+; BOLT-DWO-HELPER-NEXT: DW_AT_low_pc [DW_FORM_addrx]	(indexed (00000003)
+; BOLT-DWO-HELPER-NEXT: DW_AT_ranges [DW_FORM_rnglistx]	(indexed (0x0) rangelist = 0x00000010
+; BOLT-DWO-HELPER-NEXT: [0x0000000000000000, 0x000000000000003d))
diff --git a/bolt/test/X86/dwarf5-df-mono-dualcu.test b/bolt/test/X86/dwarf5-df-mono-dualcu.test
new file mode 100644
--- /dev/null
+++ b/bolt/test/X86/dwarf5-df-mono-dualcu.test
@@ -0,0 +1,130 @@
+; RUN: rm -rf %t
+; RUN: mkdir %t
+; RUN: cd %t
+; RUN: llc -split-dwarf-file=main.dwo -split-dwarf-output=main.dwo -O0 -mtriple=x86_64-unknown-linux-gnu \
+; RUN: -filetype=obj %p/Inputs/dwarf5-df-mono-main.ll -o=main.o
+; RUN: llc -O0 -mtriple=x86_64-unknown-linux-gnu -filetype=obj %p/Inputs/dwarf5-df-mono-helper.ll -o=helper.o
+; RUN: %clang %cflags -gdwarf-5 main.o helper.o -o main.exe
+; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections
+; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.exe | FileCheck -check-prefix=PRE-BOLT %s
+; RUN: llvm-dwarfdump --show-form --verbose --debug-addr main.exe.bolt &> %t/foo.txt
+; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.exe.bolt >> %t/foo.txt
+; RUN: cat %t/foo.txt | FileCheck -check-prefix=BOLT %s
+; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.dwo | FileCheck -check-prefix=PRE-BOLT-DWO-MAIN %s
+; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.dwo.dwo | FileCheck -check-prefix=BOLT-DWO-MAIN %s
+
+; Testing dwarf5 mix of split dwarf and monolithic CUs.
+
+; PRE-BOLT: version = 0x0005
+; PRE-BOLT: DW_TAG_skeleton_unit
+; PRE-BOLT: DW_AT_low_pc [DW_FORM_addrx]
+; PRE-BOLT-NEXT: DW_AT_high_pc [DW_FORM_data4]
+; PRE-BOLT: DW_AT_addr_base [DW_FORM_sec_offset]  (0x00000008)
+; PRE-BOLT: version = 0x0005
+; PRE-BOLT: DW_TAG_compile_unit
+; PRE-BOLT: DW_AT_low_pc [DW_FORM_addrx]  (indexed (00000002)
+; PRE-BOLT-NEXT: DW_AT_high_pc [DW_FORM_data4] (0x0000003d)
+; PRE-BOLT-NEXT: DW_AT_addr_base [DW_FORM_sec_offset]  (0x00000030)
+
+; BOLT: Addrs: [
+; BOLT-NEXT: 0x
+; BOLT-NEXT: 0x
+; BOLT-NEXT: 0x[[#%.16x,ADDR:]]
+; BOLT-NEXT: 0x
+; BOLT-NEXT: 0x[[#%.16x,ADDR2:]]
+; BOLT: Addrs: [
+; BOLT-NEXT: 0x[[#%.16x,ADDR3:]]
+; BOLT: DW_TAG_skeleton_unit
+; BOLT: DW_AT_dwo_name [DW_FORM_strx1]  (indexed (00000001) string = "main.dwo.dwo")
+; BOLT-NEXT: DW_AT_low_pc [DW_FORM_addrx]	(indexed (00000003) address = 0x0000000000000000)
+; BOLT-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x0) rangelist = 0x00000010
+; BOLT-NEXT: [0x[[#ADDR]]
+; BOLT-SAME: 0x[[#ADDR + 0x24]]
+; BOLT-NEXT: [0x[[#ADDR2]]
+; BOLT-SAME: 0x[[#ADDR2 + 0x59]]
+; BOLT-NEXT: DW_AT_addr_base [DW_FORM_sec_offset]  (0x00000008)
+; BOLT-NEXT: DW_AT_rnglists_base [DW_FORM_sec_offset]  (0x0000000c)
+; BOLT: DW_TAG_compile_unit
+; BOLT: DW_AT_name [DW_FORM_strx1]  (indexed (00000001) string = "helper.cpp")
+; BOLT: DW_AT_low_pc [DW_FORM_addrx]	(indexed (00000001) address = 0x0000000000000000)
+; BOLT-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x0) rangelist = 0x0000002b
+; BOLT-NEXT: [0x[[#ADDR3]]
+; BOLT-SAME: 0x[[#ADDR3 + 0x3D]]
+; BOLT-NEXT: DW_AT_addr_base [DW_FORM_sec_offset]  (0x00000038)
+; BOLT-NEXT: DW_AT_rnglists_base [DW_FORM_sec_offset]  (0x00000023)
+; BOLT: DW_TAG_variable
+; BOLT-NEXT: DW_AT_name [DW_FORM_strx1]  (indexed (00000003) string = "z")
+; BOLT-NEXT: DW_AT_type
+; BOLT-NEXT: DW_AT_external
+; BOLT-NEXT: DW_AT_decl_file
+; BOLT-NEXT: DW_AT_decl_line
+; BOLT-NEXT: DW_AT_location [DW_FORM_exprloc]  (DW_OP_addrx 0x2)
+; BOLT: DW_TAG_variable
+; BOLT-NEXT: DW_AT_name [DW_FORM_strx1]  (indexed (00000005) string = "d")
+; BOLT-NEXT: DW_AT_type
+; BOLT-NEXT: DW_AT_external
+; BOLT-NEXT: DW_AT_decl_file
+; BOLT-NEXT: DW_AT_decl_line
+; BOLT-NEXT: DW_AT_location [DW_FORM_exprloc]  (DW_OP_addrx 0x3)
+; BOLT: DW_TAG_subprogram
+; BOLT-NEXT: DW_AT_low_pc [DW_FORM_addrx]  (indexed (00000001) address = 0x0000000000000000)
+; BOLT-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x1) rangelist = 0x0000002f
+; BOLT-NEXT: [0x[[#ADDR3]]
+; BOLT-SAME: 0x[[#ADDR3 + 0x3D]]
+
+; PRE-BOLT-DWO-MAIN: version = 0x0005
+; PRE-BOLT-DWO-MAIN: DW_TAG_compile_unit
+; PRE-BOLT-DWO-MAIN: DW_TAG_variable [2]
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_name [DW_FORM_strx1]	(indexed (00000000) string = "x")
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_type
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_external
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_decl_file
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_decl_line
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_location [DW_FORM_exprloc]	(DW_OP_addrx 0x0)
+; PRE-BOLT-DWO-MAIN: DW_TAG_variable [2]
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_name [DW_FORM_strx1]	(indexed (00000002) string = "y")
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_type
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_external
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_decl_file
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_decl_line
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_location [DW_FORM_exprloc]	(DW_OP_addrx 0x1)
+; PRE-BOLT-DWO-MAIN: DW_TAG_subprogram
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_low_pc [DW_FORM_addrx]	(indexed (00000002)
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_high_pc [DW_FORM_data4]	(0x00000024)
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_frame_base
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_linkage_name [DW_FORM_strx1]	(indexed (00000003) string = "_Z3usePiS_")
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_name [DW_FORM_strx1]	(indexed (00000004) string = "use")
+; PRE-BOLT-DWO-MAIN: DW_TAG_subprogram
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_low_pc [DW_FORM_addrx]	(indexed (00000003)
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_high_pc [DW_FORM_data4]	(0x0000005f)
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_frame_base
+; PRE-BOLT-DWO-MAIN-NEXT: DW_AT_name [DW_FORM_strx1]	(indexed (00000005) string = "main")
+
+; BOLT-DWO-MAIN: DW_TAG_compile_unit
+; BOLT-DWO-MAIN: DW_TAG_variable [2]
+; BOLT-DWO-MAIN-NEXT: DW_AT_name [DW_FORM_strx1]	(indexed (00000000) string = "x")
+; BOLT-DWO-MAIN-NEXT: DW_AT_type
+; BOLT-DWO-MAIN-NEXT: DW_AT_external
+; BOLT-DWO-MAIN-NEXT: DW_AT_decl_file
+; BOLT-DWO-MAIN-NEXT: DW_AT_decl_line
+; BOLT-DWO-MAIN-NEXT: DW_AT_location [DW_FORM_exprloc]	(DW_OP_addrx 0x0)
+; BOLT-DWO-MAIN: DW_TAG_variable [2]
+; BOLT-DWO-MAIN-NEXT: DW_AT_name [DW_FORM_strx1]	(indexed (00000002) string = "y")
+; BOLT-DWO-MAIN-NEXT: DW_AT_type
+; BOLT-DWO-MAIN-NEXT: DW_AT_external
+; BOLT-DWO-MAIN-NEXT: DW_AT_decl_file
+; BOLT-DWO-MAIN-NEXT: DW_AT_decl_line
+; BOLT-DWO-MAIN-NEXT: DW_AT_location [DW_FORM_exprloc]	(DW_OP_addrx 0x1)
+; BOLT-DWO-MAIN: DW_TAG_subprogram [4]
+; BOLT-DWO-MAIN-NEXT: DW_AT_low_pc [DW_FORM_addrx]	(indexed (00000003)
+; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_rnglistx]	(indexed (0x0) rangelist = 0x00000014
+; BOLT-DWO-MAIN-NEXT: [0x0000000000000000, 0x0000000000000024))
+; BOLT-DWO-MAIN-NEXT: DW_AT_frame_base
+; BOLT-DWO-MAIN-NEXT: DW_AT_linkage_name [DW_FORM_strx1]	(indexed (00000003) string = "_Z3usePiS_")
+; BOLT-DWO-MAIN-NEXT: DW_AT_name [DW_FORM_strx1]	(indexed (00000004) string = "use")
+; BOLT-DWO-MAIN: DW_TAG_subprogram [6]
+; BOLT-DWO-MAIN-NEXT: DW_AT_low_pc [DW_FORM_addrx]	(indexed (00000003)
+; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_rnglistx]	(indexed (0x1) rangelist = 0x00000018
+; BOLT-DWO-MAIN-NEXT: [0x0000000000000000, 0x0000000000000059))
+; BOLT-DWO-MAIN-NEXT: DW_AT_frame_base [DW_FORM_exprloc]	(DW_OP_reg6 RBP)
+; BOLT-DWO-MAIN-NEXT: DW_AT_name [DW_FORM_strx1]	(indexed (00000005) string = "main")
diff --git a/bolt/test/X86/dwarf5-locaddrx.test b/bolt/test/X86/dwarf5-locaddrx.test
new file mode 100644
--- /dev/null
+++ b/bolt/test/X86/dwarf5-locaddrx.test
@@ -0,0 +1,209 @@
+; RUN: rm -rf %t
+; RUN: mkdir %t
+; RUN: cd %t
+; RUN: llc -split-dwarf-file=mainlocadddrx.dwo -split-dwarf-output=mainlocadddrx.dwo -O0 -mtriple=x86_64-unknown-linux-gnu -filetype=obj %s -o=mainlocadddrx.o
+; RUN: %clang %cflags -gdwarf-5 -gsplit-dwarf=split mainlocadddrx.o -o mainlocadddrx.exe
+; RUN: llvm-bolt mainlocadddrx.exe -o mainlocadddrx.exe.bolt --update-debug-sections
+; RUN: llvm-dwarfdump --show-form --verbose --debug-info mainlocadddrx.exe | FileCheck -check-prefix=PRE-BOLT %s
+; RUN: llvm-dwarfdump --show-form --verbose --debug-addr mainlocadddrx.exe.bolt &> %t/foo.txt
+; RUN: llvm-dwarfdump --show-form --verbose --debug-info mainlocadddrx.exe.bolt >> %t/foo.txt
+; RUN: cat %t/foo.txt | FileCheck -check-prefix=BOLT %s
+; RUN: llvm-dwarfdump --show-form --verbose --debug-info mainlocadddrx.dwo | FileCheck -check-prefix=PRE-BOLT-DWO %s
+; RUN: llvm-dwarfdump --show-form --verbose --debug-info mainlocadddrx.dwo.dwo | FileCheck -check-prefix=BOLT-DWO %s
+
+; Testing dwarf5 split dwarf. Making sure DW_AT_low_pc/DW_AT_high_pc are converted correctly in the binary and in dwo.
+; Checking that DW_AT_location [DW_FORM_exprloc]	(DW_OP_addrx 0x0) is updated correctly.
+
+; PRE-BOLT: version = 0x0005
+; PRE-BOLT: DW_TAG_skeleton_unit
+; PRE-BOLT: DW_AT_low_pc [DW_FORM_addrx]
+; PRE-BOLT-NEXT: DW_AT_high_pc [DW_FORM_data4]
+; PRE-BOLT: DW_AT_addr_base [DW_FORM_sec_offset]  (0x00000008)
+
+; BOLT: Addrs: [
+; BOLT-NEXT: 0x
+; BOLT-NEXT: 0x
+; BOLT-NEXT: 0x[[#%.16x,ADDR:]]
+; BOLT-NEXT: 0x
+; BOLT-NEXT: 0x[[#%.16x,ADDR2:]]
+; BOLT: DW_TAG_skeleton_unit
+; BOLT: DW_AT_low_pc [DW_FORM_addrx]	(indexed (00000003) address = 0x0000000000000000)
+; BOLT-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x0) rangelist = 0x00000010
+; BOLT-NEXT: [0x[[#ADDR]]
+; BOLT-SAME: 0x[[#ADDR + 0x24]]
+; BOLT-NEXT: [0x[[#ADDR2]]
+; BOLT-SAME: 0x[[#ADDR2 + 0x54]]
+; BOLT-NEXT: DW_AT_addr_base [DW_FORM_sec_offset]  (0x00000008)
+; BOLT-NEXT: DW_AT_rnglists_base [DW_FORM_sec_offset]  (0x0000000c)
+
+; PRE-BOLT-DWO: version = 0x0005
+; PRE-BOLT-DWO: DW_TAG_compile_unit
+; PRE-BOLT-DWO: DW_TAG_variable [2]
+; PRE-BOLT-DWO-NEXT: DW_AT_name [DW_FORM_strx1]	(indexed (00000000) string = "x")
+; PRE-BOLT-DWO-NEXT: DW_AT_type
+; PRE-BOLT-DWO-NEXT: DW_AT_external
+; PRE-BOLT-DWO-NEXT: DW_AT_decl_file
+; PRE-BOLT-DWO-NEXT: DW_AT_decl_line
+; PRE-BOLT-DWO-NEXT: DW_AT_location [DW_FORM_exprloc]	(DW_OP_addrx 0x0)
+; PRE-BOLT-DWO: DW_TAG_variable [2]
+; PRE-BOLT-DWO-NEXT: DW_AT_name [DW_FORM_strx1]	(indexed (00000002) string = "y")
+; PRE-BOLT-DWO-NEXT: DW_AT_type
+; PRE-BOLT-DWO-NEXT: DW_AT_external
+; PRE-BOLT-DWO-NEXT: DW_AT_decl_file
+; PRE-BOLT-DWO-NEXT: DW_AT_decl_line
+; PRE-BOLT-DWO-NEXT: DW_AT_location [DW_FORM_exprloc]	(DW_OP_addrx 0x1)
+; PRE-BOLT-DWO: DW_TAG_subprogram
+; PRE-BOLT-DWO-NEXT: DW_AT_low_pc [DW_FORM_addrx]	(indexed (00000002)
+; PRE-BOLT-DWO-NEXT: DW_AT_high_pc [DW_FORM_data4]	(0x00000024)
+; PRE-BOLT-DWO: DW_TAG_subprogram
+; PRE-BOLT-DWO-NEXT: DW_AT_low_pc [DW_FORM_addrx]	(indexed (00000003)
+; PRE-BOLT-DWO-NEXT: DW_AT_high_pc [DW_FORM_data4]	(0x0000005a)
+
+; BOLT-DWO: DW_TAG_compile_unit
+; BOLT-DWO: DW_TAG_variable [2]
+; BOLT-DWO-NEXT: DW_AT_name [DW_FORM_strx1]	(indexed (00000000) string = "x")
+; BOLT-DWO-NEXT: DW_AT_type
+; BOLT-DWO-NEXT: DW_AT_external
+; BOLT-DWO-NEXT: DW_AT_decl_file
+; BOLT-DWO-NEXT: DW_AT_decl_line
+; BOLT-DWO-NEXT: DW_AT_location [DW_FORM_exprloc]	(DW_OP_addrx 0x0)
+; BOLT-DWO: DW_TAG_variable [2]
+; BOLT-DWO-NEXT: DW_AT_name [DW_FORM_strx1]	(indexed (00000002) string = "y")
+; BOLT-DWO-NEXT: DW_AT_type
+; BOLT-DWO-NEXT: DW_AT_external
+; BOLT-DWO-NEXT: DW_AT_decl_file
+; BOLT-DWO-NEXT: DW_AT_decl_line
+; BOLT-DWO-NEXT: DW_AT_location [DW_FORM_exprloc]	(DW_OP_addrx 0x1)
+; BOLT-DWO: DW_TAG_subprogram [4]
+; BOLT-DWO-NEXT: DW_AT_low_pc [DW_FORM_addrx]	(indexed (00000003)
+; BOLT-DWO-NEXT: DW_AT_ranges [DW_FORM_rnglistx]	(indexed (0x0) rangelist = 0x00000014
+; BOLT-DWO-NEXT: [0x0000000000000000, 0x0000000000000024))
+; BOLT-DWO: DW_TAG_subprogram [6]
+; BOLT-DWO-NEXT: DW_AT_low_pc [DW_FORM_addrx]	(indexed (00000003)
+; BOLT-DWO-NEXT: DW_AT_ranges [DW_FORM_rnglistx]	(indexed (0x1) rangelist = 0x00000018
+; BOLT-DWO-NEXT: [0x0000000000000000, 0x0000000000000054))
+
+; void use(int * x, int * y) {
+; *x += 4;
+; *y -= 2;
+; }
+;
+; int x = 0;
+; int y = 1;
+; int  main(int argc, char *argv[]) {
+;    x = argc;
+;    y = argc + 3;
+;    use(&x, &y);
+;    return x + y;
+; }
+
+; ModuleID = 'mainlocadddrx.cpp'
+source_filename = "mainlocadddrx.cpp"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@x = dso_local global i32 0, align 4, !dbg !0
+@y = dso_local global i32 1, align 4, !dbg !5
+
+; Function Attrs: mustprogress noinline nounwind optnone uwtable
+define dso_local void @_Z3usePiS_(i32* noundef %x, i32* noundef %y) #0 !dbg !14 {
+entry:
+  %x.addr = alloca i32*, align 8
+  %y.addr = alloca i32*, align 8
+  store i32* %x, i32** %x.addr, align 8
+  call void @llvm.dbg.declare(metadata i32** %x.addr, metadata !19, metadata !DIExpression()), !dbg !20
+  store i32* %y, i32** %y.addr, align 8
+  call void @llvm.dbg.declare(metadata i32** %y.addr, metadata !21, metadata !DIExpression()), !dbg !22
+  %0 = load i32*, i32** %x.addr, align 8, !dbg !23
+  %1 = load i32, i32* %0, align 4, !dbg !24
+  %add = add nsw i32 %1, 4, !dbg !24
+  store i32 %add, i32* %0, align 4, !dbg !24
+  %2 = load i32*, i32** %y.addr, align 8, !dbg !25
+  %3 = load i32, i32* %2, align 4, !dbg !26
+  %sub = sub nsw i32 %3, 2, !dbg !26
+  store i32 %sub, i32* %2, align 4, !dbg !26
+  ret void, !dbg !27
+}
+
+; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+; Function Attrs: mustprogress noinline norecurse nounwind optnone uwtable
+define dso_local noundef i32 @main(i32 noundef %argc, i8** noundef %argv) #2 !dbg !28 {
+entry:
+  %retval = alloca i32, align 4
+  %argc.addr = alloca i32, align 4
+  %argv.addr = alloca i8**, align 8
+  store i32 0, i32* %retval, align 4
+  store i32 %argc, i32* %argc.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %argc.addr, metadata !34, metadata !DIExpression()), !dbg !35
+  store i8** %argv, i8*** %argv.addr, align 8
+  call void @llvm.dbg.declare(metadata i8*** %argv.addr, metadata !36, metadata !DIExpression()), !dbg !37
+  %0 = load i32, i32* %argc.addr, align 4, !dbg !38
+  store i32 %0, i32* @x, align 4, !dbg !39
+  %1 = load i32, i32* %argc.addr, align 4, !dbg !40
+  %add = add nsw i32 %1, 3, !dbg !41
+  store i32 %add, i32* @y, align 4, !dbg !42
+  call void @_Z3usePiS_(i32* noundef @x, i32* noundef @y), !dbg !43
+  %2 = load i32, i32* @x, align 4, !dbg !44
+  %3 = load i32, i32* @y, align 4, !dbg !45
+  %add1 = add nsw i32 %2, %3, !dbg !46
+  ret i32 %add1, !dbg !47
+}
+
+attributes #0 = { mustprogress noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { nofree nosync nounwind readnone speculatable willreturn }
+attributes #2 = { mustprogress noinline norecurse nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!8, !9, !10, !11, !12}
+!llvm.ident = !{!13}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "x", scope: !2, file: !3, line: 6, type: !7, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 15.0.0", isOptimized: false, runtimeVersion: 0, splitDebugFilename: "mainlocadddrx.dwo", emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: GNU)
+!3 = !DIFile(filename: "mainlocadddrx.cpp", directory: ".", checksumkind: CSK_MD5, checksum: "d4fd79ce0087c4cefd089752bf2182c6")
+!4 = !{!0, !5}
+!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())
+!6 = distinct !DIGlobalVariable(name: "y", scope: !2, file: !3, line: 7, type: !7, isLocal: false, isDefinition: true)
+!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!8 = !{i32 7, !"Dwarf Version", i32 5}
+!9 = !{i32 2, !"Debug Info Version", i32 3}
+!10 = !{i32 1, !"wchar_size", i32 4}
+!11 = !{i32 7, !"uwtable", i32 2}
+!12 = !{i32 7, !"frame-pointer", i32 2}
+!13 = !{!"clang version 15.0.0"}
+!14 = distinct !DISubprogram(name: "use", linkageName: "_Z3usePiS_", scope: !3, file: !3, line: 1, type: !15, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !18)
+!15 = !DISubroutineType(types: !16)
+!16 = !{null, !17, !17}
+!17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64)
+!18 = !{}
+!19 = !DILocalVariable(name: "x", arg: 1, scope: !14, file: !3, line: 1, type: !17)
+!20 = !DILocation(line: 1, column: 16, scope: !14)
+!21 = !DILocalVariable(name: "y", arg: 2, scope: !14, file: !3, line: 1, type: !17)
+!22 = !DILocation(line: 1, column: 25, scope: !14)
+!23 = !DILocation(line: 2, column: 2, scope: !14)
+!24 = !DILocation(line: 2, column: 4, scope: !14)
+!25 = !DILocation(line: 3, column: 2, scope: !14)
+!26 = !DILocation(line: 3, column: 4, scope: !14)
+!27 = !DILocation(line: 4, column: 1, scope: !14)
+!28 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 8, type: !29, scopeLine: 8, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !18)
+!29 = !DISubroutineType(types: !30)
+!30 = !{!7, !7, !31}
+!31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !32, size: 64)
+!32 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !33, size: 64)
+!33 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!34 = !DILocalVariable(name: "argc", arg: 1, scope: !28, file: !3, line: 8, type: !7)
+!35 = !DILocation(line: 8, column: 15, scope: !28)
+!36 = !DILocalVariable(name: "argv", arg: 2, scope: !28, file: !3, line: 8, type: !31)
+!37 = !DILocation(line: 8, column: 27, scope: !28)
+!38 = !DILocation(line: 9, column: 8, scope: !28)
+!39 = !DILocation(line: 9, column: 6, scope: !28)
+!40 = !DILocation(line: 10, column: 8, scope: !28)
+!41 = !DILocation(line: 10, column: 13, scope: !28)
+!42 = !DILocation(line: 10, column: 6, scope: !28)
+!43 = !DILocation(line: 11, column: 4, scope: !28)
+!44 = !DILocation(line: 12, column: 11, scope: !28)
+!45 = !DILocation(line: 12, column: 15, scope: !28)
+!46 = !DILocation(line: 12, column: 13, scope: !28)
+!47 = !DILocation(line: 12, column: 4, scope: !28)