Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/llvm/llvm-project.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/bolt
diff options
context:
space:
mode:
authorAlexander Yermolovich <ayermolo@fb.com>2022-05-06 00:57:14 +0300
committerAlexander Yermolovich <ayermolo@fb.com>2022-05-06 00:59:05 +0300
commitba1ac98c62e847551bd7ed7d48d811228f7f4619 (patch)
tree9411e2edcaa432a8a43ba19818b42c2eb8f730ff /bolt
parentc4f95ef86a224fe730d2219aab90e88a0e7b03d2 (diff)
[BOLT][DWARF] Add version 5 split dwarf support
Added support for DWARF5 Split Dwarf. Reviewed By: maksfb Differential Revision: https://reviews.llvm.org/D122988
Diffstat (limited to 'bolt')
-rw-r--r--bolt/include/bolt/Core/DebugData.h102
-rw-r--r--bolt/include/bolt/Rewrite/DWARFRewriter.h18
-rw-r--r--bolt/lib/Core/BinaryContext.cpp18
-rw-r--r--bolt/lib/Core/DebugData.cpp85
-rw-r--r--bolt/lib/Rewrite/DWARFRewriter.cpp240
-rw-r--r--bolt/test/X86/Inputs/dwarf4-df-dualcu-helper.ll81
-rw-r--r--bolt/test/X86/Inputs/dwarf4-df-dualcu-loclist-helper.ll61
-rw-r--r--bolt/test/X86/Inputs/dwarf4-df-dualcu-loclist-main.ll99
-rw-r--r--bolt/test/X86/Inputs/dwarf4-df-dualcu-main.ll129
-rw-r--r--bolt/test/X86/Inputs/dwarf5-df-dualcu-helper.ll81
-rw-r--r--bolt/test/X86/Inputs/dwarf5-df-dualcu-loclist-helper.ll61
-rw-r--r--bolt/test/X86/Inputs/dwarf5-df-dualcu-loclist-main.ll99
-rw-r--r--bolt/test/X86/Inputs/dwarf5-df-dualcu-main.ll129
-rw-r--r--bolt/test/X86/Inputs/dwarf5-df-mono-helper.ll81
-rw-r--r--bolt/test/X86/Inputs/dwarf5-df-mono-main.ll129
-rw-r--r--bolt/test/X86/debug-fission-single.s22
-rw-r--r--bolt/test/X86/dwarf4-df-dualcu-loclist.test48
-rw-r--r--bolt/test/X86/dwarf4-df-dualcu.test166
-rw-r--r--bolt/test/X86/dwarf5-df-dualcu-loclist.test51
-rw-r--r--bolt/test/X86/dwarf5-df-dualcu.test152
-rw-r--r--bolt/test/X86/dwarf5-df-mono-dualcu.test130
-rw-r--r--bolt/test/X86/dwarf5-locaddrx.test209
22 files changed, 2063 insertions, 128 deletions
diff --git a/bolt/include/bolt/Core/DebugData.h b/bolt/include/bolt/Core/DebugData.h
index 3e60f0ad2dc2..0de5d153bf23 100644
--- a/bolt/include/bolt/Core/DebugData.h
+++ b/bolt/include/bolt/Core/DebugData.h
@@ -155,7 +155,7 @@ public:
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 @@ public:
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 @@ public:
/// 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 @@ public:
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 @@ public:
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 @@ protected:
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 @@ public:
/// 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 @@ private:
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 @@ class DebugLoclistWriter : public DebugLocWriter {
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 @@ public:
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 @@ private:
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
index 1869a7e6ff98..82111d730504 100644
--- a/bolt/include/bolt/Rewrite/DWARFRewriter.h
+++ b/bolt/include/bolt/Rewrite/DWARFRewriter.h
@@ -48,6 +48,10 @@ class DWARFRewriter {
/// 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 @@ class DWARFRewriter {
/// 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 @@ class DWARFRewriter {
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
index 92ddc2603066..6ebed6b68108 100644
--- a/bolt/lib/Core/BinaryContext.cpp
+++ b/bolt/lib/Core/BinaryContext.cpp
@@ -1500,6 +1500,8 @@ void BinaryContext::preprocessDebugInfo() {
<< 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 @@ void BinaryContext::preprocessDebugInfo() {
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 @@ void BinaryContext::preprocessDebugInfo() {
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
index dfb041bb55ae..df3fd2956ee8 100644
--- 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 @@ uint64_t DebugRangeListsSectionWriter::addRanges(
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 @@ void DebugRangeListsSectionWriter::finalizeSection() {
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 @@ void DebugAddrWriter::AddressForDWOCU::dump() {
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 @@ uint32_t DebugAddrWriter::getIndexFromAddress(uint64_t Address, uint64_t CUID) {
// 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 DebugAddrWriter::finalize() {
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 @@ AddressSectionBuffer DebugAddrWriterDwarf5::finalize() {
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 @@ AddressSectionBuffer DebugAddrWriterDwarf5::finalize() {
}
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 @@ AddressSectionBuffer DebugAddrWriterDwarf5::finalize() {
}
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 @@ void DebugLoclistWriter::finalizeDWARF5(uint64_t SectionOffset,
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 @@ void DebugLoclistWriter::finalizeDWARFLegacy(
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 @@ std::string DebugInfoBinaryPatcher::patchBinary(StringRef BinaryContents) {
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
index 1b52bd586f58..4c8231ae02a1 100644
--- a/bolt/lib/Rewrite/DWARFRewriter.cpp
+++ b/bolt/lib/Rewrite/DWARFRewriter.cpp
@@ -163,6 +163,19 @@ getDWOName(llvm::DWARFUnit &CU,
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 @@ void DWARFRewriter::updateDebugInfo() {
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 @@ void DWARFRewriter::updateDebugInfo() {
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 @@ void DWARFRewriter::updateDebugInfo() {
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 @@ void DWARFRewriter::updateDebugInfo() {
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 @@ void DWARFRewriter::updateDebugInfo() {
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 @@ void DWARFRewriter::updateDebugInfo() {
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 @@ void DWARFRewriter::updateUnitDebugInfo(
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 @@ void DWARFRewriter::updateUnitDebugInfo(
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 @@ void DWARFRewriter::updateUnitDebugInfo(
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 @@ void DWARFRewriter::updateUnitDebugInfo(
} 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 @@ void DWARFRewriter::updateUnitDebugInfo(
// 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 @@ DWARFRewriter::finalizeDebugSections(DebugInfoBinaryPatcher &DebugInfoPatcher) {
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 @@ createKnownSectionsMap(const MCObjectFileInfo &MCOFI) {
{"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 @@ StringRef getSectionName(const SectionRef &Section) {
// 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 @@ Optional<StringRef> updateDebugData(
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 @@ Optional<StringRef> updateDebugData(
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 @@ Optional<StringRef> updateDebugData(
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 @@ void DWARFRewriter::writeDWP(
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 @@ void DWARFRewriter::writeDWOFiles(
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 @@ void DWARFRewriter::convertToRangesPatchDebugInfo(
// 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
index 000000000000..3b0ba9c1e0c3
--- /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
index 000000000000..36a3398caf7f
--- /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
index 000000000000..4550b7fa92ff
--- /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
index 000000000000..704f5659b29d
--- /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
index 000000000000..4d53bc4c386e
--- /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
index 000000000000..6848c71a5a7d
--- /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
index 000000000000..bdcb09457278
--- /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
index 000000000000..99651eb65525
--- /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
index 000000000000..c69f64f37ebd
--- /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
index 000000000000..3fa28c0848a9
--- /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
index 7332dc45faac..d1a050491b61 100644
--- 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
index 000000000000..a011488b4eaa
--- /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
index 000000000000..7befeea78bbb
--- /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
index 000000000000..9a0f0481c67b
--- /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
index 000000000000..2902900c6f26
--- /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
index 000000000000..66bab5e5ae3d
--- /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
index 000000000000..1004becdd7ba
--- /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)