summaryrefslogtreecommitdiffstats
path: root/build/build-clang/llvmorg-17-init-994-g1e72920c8859.patch
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /build/build-clang/llvmorg-17-init-994-g1e72920c8859.patch
parentInitial commit. (diff)
downloadfirefox-esr-upstream.tar.xz
firefox-esr-upstream.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'build/build-clang/llvmorg-17-init-994-g1e72920c8859.patch')
-rw-r--r--build/build-clang/llvmorg-17-init-994-g1e72920c8859.patch842
1 files changed, 842 insertions, 0 deletions
diff --git a/build/build-clang/llvmorg-17-init-994-g1e72920c8859.patch b/build/build-clang/llvmorg-17-init-994-g1e72920c8859.patch
new file mode 100644
index 0000000000..12d817fbe0
--- /dev/null
+++ b/build/build-clang/llvmorg-17-init-994-g1e72920c8859.patch
@@ -0,0 +1,842 @@
+From 4cb60673a0a25a25d171716c5b90e7a3368d434f Mon Sep 17 00:00:00 2001
+From: Alexey Lapshin <a.v.lapshin@mail.ru>
+Date: Mon, 30 Jan 2023 15:05:53 +0100
+Subject: [PATCH] [dsymutil] dsymutil produces broken lines info (probably)
+ with LTO on mac
+
+This patch fixes #60307 issue. The 8bb4451 introduces the possibility
+to unite overlapped or adjacent address ranges to keep address ranges
+in an unambiguous state. The AddressRangesMap is used to normalize
+address ranges. The AddressRangesMap keeps address ranges and the value
+of the relocated address. For intersected range, it creates a united
+range that keeps the last inserted mapping value. The same for adjusted ranges.
+While it is OK to use the last inserted mapping value for intersected ranges
+(as there is no way how to resolve ambiguity) It is not OK to use the
+last inserted value for adjacent address ranges. Currently, two following
+address ranges are united into a single one:
+
+{0,24,17e685c} {24,d8,55afe20} -> {0,d8,55afe20}
+
+To avoid the problem, the AddressRangesMap should not unite adjacent address ranges
+with different relocated addresses. Instead, it should leave adjacent address ranges
+as separate ranges. So, the ranges should look like this:
+
+{0,24,17e685c} {24,d8,55afe20}
+
+Differential Revision: https://reviews.llvm.org/D142936
+---
+ llvm/include/llvm/ADT/AddressRanges.h | 206 ++++++++-----
+ .../llvm/DWARFLinker/DWARFLinkerCompileUnit.h | 2 +-
+ llvm/lib/DWARFLinker/DWARFLinker.cpp | 36 +--
+ llvm/lib/DWARFLinker/DWARFStreamer.cpp | 5 +-
+ llvm/lib/Support/AddressRanges.cpp | 70 -----
+ llvm/lib/Support/CMakeLists.txt | 1 -
+ llvm/unittests/Support/AddressRangeTest.cpp | 285 +++++++++++++++---
+ 7 files changed, 398 insertions(+), 207 deletions(-)
+ delete mode 100644 llvm/lib/Support/AddressRanges.cpp
+
+diff --git a/llvm/include/llvm/ADT/AddressRanges.h b/llvm/include/llvm/ADT/AddressRanges.h
+index f2052d82e7c1..415d30bbb5cf 100644
+--- a/llvm/include/llvm/ADT/AddressRanges.h
++++ b/llvm/include/llvm/ADT/AddressRanges.h
+@@ -28,7 +28,11 @@ public:
+ uint64_t start() const { return Start; }
+ uint64_t end() const { return End; }
+ uint64_t size() const { return End - Start; }
++ uint64_t empty() const { return size() == 0; }
+ bool contains(uint64_t Addr) const { return Start <= Addr && Addr < End; }
++ bool contains(const AddressRange &R) const {
++ return Start <= R.Start && R.End <= End;
++ }
+ bool intersects(const AddressRange &R) const {
+ return Start < R.End && R.Start < End;
+ }
+@@ -45,101 +49,163 @@ private:
+ uint64_t End = 0;
+ };
+
+-/// The AddressRanges class helps normalize address range collections.
+-/// This class keeps a sorted vector of AddressRange objects and can perform
+-/// insertions and searches efficiently. The address ranges are always sorted
+-/// and never contain any invalid or empty address ranges.
+-/// Intersecting([100,200), [150,300)) and adjacent([100,200), [200,300))
+-/// address ranges are combined during insertion.
+-class AddressRanges {
++/// The AddressRangesBase class presents the base functionality for the
++/// normalized address ranges collection. This class keeps a sorted vector
++/// of AddressRange-like objects and can perform searches efficiently.
++/// The address ranges are always sorted and never contain any invalid,
++/// empty or intersected address ranges.
++
++template <typename T> class AddressRangesBase {
+ protected:
+- using Collection = SmallVector<AddressRange>;
++ using Collection = SmallVector<T>;
+ Collection Ranges;
+
+ public:
+ void clear() { Ranges.clear(); }
+ bool empty() const { return Ranges.empty(); }
+- bool contains(uint64_t Addr) const { return find(Addr) != Ranges.end(); }
++ bool contains(uint64_t Addr) const {
++ return find(Addr, Addr + 1) != Ranges.end();
++ }
+ bool contains(AddressRange Range) const {
+- return find(Range) != Ranges.end();
++ return find(Range.start(), Range.end()) != Ranges.end();
+ }
+- std::optional<AddressRange> getRangeThatContains(uint64_t Addr) const {
+- Collection::const_iterator It = find(Addr);
++ void reserve(size_t Capacity) { Ranges.reserve(Capacity); }
++ size_t size() const { return Ranges.size(); }
++
++ std::optional<T> getRangeThatContains(uint64_t Addr) const {
++ typename Collection::const_iterator It = find(Addr, Addr + 1);
+ if (It == Ranges.end())
+ return std::nullopt;
+
+ return *It;
+ }
+- Collection::const_iterator insert(AddressRange Range);
+- void reserve(size_t Capacity) { Ranges.reserve(Capacity); }
+- size_t size() const { return Ranges.size(); }
+- bool operator==(const AddressRanges &RHS) const {
+- return Ranges == RHS.Ranges;
+- }
+- const AddressRange &operator[](size_t i) const {
++
++ typename Collection::const_iterator begin() const { return Ranges.begin(); }
++ typename Collection::const_iterator end() const { return Ranges.end(); }
++
++ const T &operator[](size_t i) const {
+ assert(i < Ranges.size());
+ return Ranges[i];
+ }
+- Collection::const_iterator begin() const { return Ranges.begin(); }
+- Collection::const_iterator end() const { return Ranges.end(); }
++
++ bool operator==(const AddressRangesBase<T> &RHS) const {
++ return Ranges == RHS.Ranges;
++ }
+
+ protected:
+- Collection::const_iterator find(uint64_t Addr) const;
+- Collection::const_iterator find(AddressRange Range) const;
++ typename Collection::const_iterator find(uint64_t Start, uint64_t End) const {
++ if (Start >= End)
++ return Ranges.end();
++
++ auto It =
++ std::partition_point(Ranges.begin(), Ranges.end(), [=](const T &R) {
++ return AddressRange(R).start() <= Start;
++ });
++
++ if (It == Ranges.begin())
++ return Ranges.end();
++
++ --It;
++ if (End > AddressRange(*It).end())
++ return Ranges.end();
++
++ return It;
++ }
+ };
+
+-/// AddressRangesMap class maps values to the address ranges.
+-/// It keeps address ranges and corresponding values. If ranges
+-/// are combined during insertion, then combined range keeps
+-/// newly inserted value.
+-template <typename T> class AddressRangesMap : protected AddressRanges {
++/// The AddressRanges class helps normalize address range collections.
++/// This class keeps a sorted vector of AddressRange objects and can perform
++/// insertions and searches efficiently. Intersecting([100,200), [150,300))
++/// and adjacent([100,200), [200,300)) address ranges are combined during
++/// insertion.
++class AddressRanges : public AddressRangesBase<AddressRange> {
+ public:
+- void clear() {
+- Ranges.clear();
+- Values.clear();
++ Collection::const_iterator insert(AddressRange Range) {
++ if (Range.empty())
++ return Ranges.end();
++
++ auto It = llvm::upper_bound(Ranges, Range);
++ auto It2 = It;
++ while (It2 != Ranges.end() && It2->start() <= Range.end())
++ ++It2;
++ if (It != It2) {
++ Range = {Range.start(), std::max(Range.end(), std::prev(It2)->end())};
++ It = Ranges.erase(It, It2);
++ }
++ if (It != Ranges.begin() && Range.start() <= std::prev(It)->end()) {
++ --It;
++ *It = {It->start(), std::max(It->end(), Range.end())};
++ return It;
++ }
++
++ return Ranges.insert(It, Range);
+ }
+- bool empty() const { return AddressRanges::empty(); }
+- bool contains(uint64_t Addr) const { return AddressRanges::contains(Addr); }
+- bool contains(AddressRange Range) const {
+- return AddressRanges::contains(Range);
+- }
+- void insert(AddressRange Range, T Value) {
+- size_t InputSize = Ranges.size();
+- Collection::const_iterator RangesIt = AddressRanges::insert(Range);
+- if (RangesIt == Ranges.end())
+- return;
++};
+
+- // make Values match to Ranges.
+- size_t Idx = RangesIt - Ranges.begin();
+- typename ValuesCollection::iterator ValuesIt = Values.begin() + Idx;
+- if (InputSize < Ranges.size())
+- Values.insert(ValuesIt, T());
+- else if (InputSize > Ranges.size())
+- Values.erase(ValuesIt, ValuesIt + InputSize - Ranges.size());
+- assert(Ranges.size() == Values.size());
+-
+- // set value to the inserted or combined range.
+- Values[Idx] = Value;
+- }
+- size_t size() const {
+- assert(Ranges.size() == Values.size());
+- return AddressRanges::size();
+- }
+- std::optional<std::pair<AddressRange, T>>
+- getRangeValueThatContains(uint64_t Addr) const {
+- Collection::const_iterator It = find(Addr);
+- if (It == Ranges.end())
+- return std::nullopt;
++class AddressRangeValuePair {
++public:
++ operator AddressRange() const { return Range; }
+
+- return std::make_pair(*It, Values[It - Ranges.begin()]);
+- }
+- std::pair<AddressRange, T> operator[](size_t Idx) const {
+- return std::make_pair(Ranges[Idx], Values[Idx]);
+- }
++ AddressRange Range;
++ int64_t Value = 0;
++};
+
+-protected:
+- using ValuesCollection = SmallVector<T>;
+- ValuesCollection Values;
++inline bool operator==(const AddressRangeValuePair &LHS,
++ const AddressRangeValuePair &RHS) {
++ return LHS.Range == RHS.Range && LHS.Value == RHS.Value;
++}
++
++/// AddressRangesMap class maps values to the address ranges.
++/// It keeps normalized address ranges and corresponding values.
++/// This class keeps a sorted vector of AddressRangeValuePair objects
++/// and can perform insertions and searches efficiently.
++/// Intersecting([100,200), [150,300)) ranges splitted into non-conflicting
++/// parts([100,200), [200,300)). Adjacent([100,200), [200,300)) address
++/// ranges are not combined during insertion.
++class AddressRangesMap : public AddressRangesBase<AddressRangeValuePair> {
++public:
++ void insert(AddressRange Range, int64_t Value) {
++ if (Range.empty())
++ return;
++
++ // Search for range which is less than or equal incoming Range.
++ auto It = std::partition_point(Ranges.begin(), Ranges.end(),
++ [=](const AddressRangeValuePair &R) {
++ return R.Range.start() <= Range.start();
++ });
++
++ if (It != Ranges.begin())
++ It--;
++
++ while (!Range.empty()) {
++ // Inserted range does not overlap with any range.
++ // Store it into the Ranges collection.
++ if (It == Ranges.end() || Range.end() <= It->Range.start()) {
++ Ranges.insert(It, {Range, Value});
++ return;
++ }
++
++ // Inserted range partially overlaps with current range.
++ // Store not overlapped part of inserted range.
++ if (Range.start() < It->Range.start()) {
++ It = Ranges.insert(It, {{Range.start(), It->Range.start()}, Value});
++ It++;
++ Range = {It->Range.start(), Range.end()};
++ continue;
++ }
++
++ // Inserted range fully overlaps with current range.
++ if (Range.end() <= It->Range.end())
++ return;
++
++ // Inserted range partially overlaps with current range.
++ // Remove overlapped part from the inserted range.
++ if (Range.start() < It->Range.end())
++ Range = {It->Range.end(), Range.end()};
++
++ It++;
++ }
++ }
+ };
+
+ } // namespace llvm
+diff --git a/llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h b/llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h
+index 5b0ea339c4d6..9c7f24e69d48 100644
+--- a/llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h
++++ b/llvm/include/llvm/DWARFLinker/DWARFLinkerCompileUnit.h
+@@ -21,7 +21,7 @@ class DeclContext;
+
+ /// Mapped value in the address map is the offset to apply to the
+ /// linked address.
+-using RangesTy = AddressRangesMap<int64_t>;
++using RangesTy = AddressRangesMap;
+
+ // FIXME: Delete this structure.
+ struct PatchLocation {
+diff --git a/llvm/lib/DWARFLinker/DWARFLinker.cpp b/llvm/lib/DWARFLinker/DWARFLinker.cpp
+index 9f6e54377ede..d302d61894fa 100644
+--- a/llvm/lib/DWARFLinker/DWARFLinker.cpp
++++ b/llvm/lib/DWARFLinker/DWARFLinker.cpp
+@@ -1659,7 +1659,7 @@ void DWARFLinker::patchRangesForUnit(const CompileUnit &Unit,
+ DWARFDataExtractor RangeExtractor(OrigDwarf.getDWARFObj(),
+ OrigDwarf.getDWARFObj().getRangesSection(),
+ OrigDwarf.isLittleEndian(), AddressSize);
+- std::optional<std::pair<AddressRange, int64_t>> CachedRange;
++ std::optional<AddressRangeValuePair> CachedRange;
+ DWARFUnit &OrigUnit = Unit.getOrigUnit();
+ auto OrigUnitDie = OrigUnit.getUnitDIE(false);
+ uint64_t UnitBaseAddress =
+@@ -1687,9 +1687,9 @@ void DWARFLinker::patchRangesForUnit(const CompileUnit &Unit,
+ }
+
+ if (!CachedRange ||
+- !CachedRange->first.contains(Range.StartAddress + BaseAddress))
+- CachedRange = FunctionRanges.getRangeValueThatContains(
+- Range.StartAddress + BaseAddress);
++ !CachedRange->Range.contains(Range.StartAddress + BaseAddress))
++ CachedRange = FunctionRanges.getRangeThatContains(Range.StartAddress +
++ BaseAddress);
+
+ // All range entries should lie in the function range.
+ if (!CachedRange) {
+@@ -1698,8 +1698,8 @@ void DWARFLinker::patchRangesForUnit(const CompileUnit &Unit,
+ }
+
+ LinkedRanges.insert(
+- {Range.StartAddress + BaseAddress + CachedRange->second,
+- Range.EndAddress + BaseAddress + CachedRange->second});
++ {Range.StartAddress + BaseAddress + CachedRange->Value,
++ Range.EndAddress + BaseAddress + CachedRange->Value});
+ }
+ }
+
+@@ -1802,7 +1802,7 @@ void DWARFLinker::patchLineTableForUnit(CompileUnit &Unit,
+ // in NewRows.
+ std::vector<DWARFDebugLine::Row> Seq;
+ const auto &FunctionRanges = Unit.getFunctionRanges();
+- std::optional<std::pair<AddressRange, int64_t>> CurrRange;
++ std::optional<AddressRangeValuePair> CurrRange;
+
+ // FIXME: This logic is meant to generate exactly the same output as
+ // Darwin's classic dsymutil. There is a nicer way to implement this
+@@ -1821,13 +1821,13 @@ void DWARFLinker::patchLineTableForUnit(CompileUnit &Unit,
+ // it is marked as end_sequence in the input (because in that
+ // case, the relocation offset is accurate and that entry won't
+ // serve as the start of another function).
+- if (!CurrRange || !CurrRange->first.contains(Row.Address.Address) ||
+- (Row.Address.Address == CurrRange->first.end() && !Row.EndSequence)) {
++ if (!CurrRange || !CurrRange->Range.contains(Row.Address.Address) ||
++ (Row.Address.Address == CurrRange->Range.end() && !Row.EndSequence)) {
+ // We just stepped out of a known range. Insert a end_sequence
+ // corresponding to the end of the range.
+ uint64_t StopAddress =
+- CurrRange ? CurrRange->first.end() + CurrRange->second : -1ULL;
+- CurrRange = FunctionRanges.getRangeValueThatContains(Row.Address.Address);
++ CurrRange ? CurrRange->Range.end() + CurrRange->Value : -1ULL;
++ CurrRange = FunctionRanges.getRangeThatContains(Row.Address.Address);
+ if (!CurrRange) {
+ if (StopAddress != -1ULL) {
+ // Try harder by looking in the Address ranges map.
+@@ -1836,9 +1836,9 @@ void DWARFLinker::patchLineTableForUnit(CompileUnit &Unit,
+ // for now do as dsymutil.
+ // FIXME: Understand exactly what cases this addresses and
+ // potentially remove it along with the Ranges map.
+- if (std::optional<std::pair<AddressRange, int64_t>> Range =
+- Ranges.getRangeValueThatContains(Row.Address.Address))
+- StopAddress = Row.Address.Address + (*Range).second;
++ if (std::optional<AddressRangeValuePair> Range =
++ Ranges.getRangeThatContains(Row.Address.Address))
++ StopAddress = Row.Address.Address + (*Range).Value;
+ }
+ }
+ if (StopAddress != -1ULL && !Seq.empty()) {
+@@ -1863,7 +1863,7 @@ void DWARFLinker::patchLineTableForUnit(CompileUnit &Unit,
+ continue;
+
+ // Relocate row address and add it to the current sequence.
+- Row.Address.Address += CurrRange->second;
++ Row.Address.Address += CurrRange->Value;
+ Seq.emplace_back(Row);
+
+ if (Row.EndSequence)
+@@ -2002,8 +2002,8 @@ void DWARFLinker::patchFrameInfoForObject(const DWARFFile &File,
+ // the function entry point, thus we can't just lookup the address
+ // in the debug map. Use the AddressInfo's range map to see if the FDE
+ // describes something that we can relocate.
+- std::optional<std::pair<AddressRange, int64_t>> Range =
+- Ranges.getRangeValueThatContains(Loc);
++ std::optional<AddressRangeValuePair> Range =
++ Ranges.getRangeThatContains(Loc);
+ if (!Range) {
+ // The +4 is to account for the size of the InitialLength field itself.
+ InputOffset = EntryOffset + InitialLength + 4;
+@@ -2032,7 +2032,7 @@ void DWARFLinker::patchFrameInfoForObject(const DWARFFile &File,
+ // fields that will get reconstructed by emitFDE().
+ unsigned FDERemainingBytes = InitialLength - (4 + AddrSize);
+ TheDwarfEmitter->emitFDE(IteratorInserted.first->getValue(), AddrSize,
+- Loc + Range->second,
++ Loc + Range->Value,
+ FrameData.substr(InputOffset, FDERemainingBytes));
+ InputOffset += FDERemainingBytes;
+ }
+diff --git a/llvm/lib/DWARFLinker/DWARFStreamer.cpp b/llvm/lib/DWARFLinker/DWARFStreamer.cpp
+index 5cad267fd845..ae79e8cb9066 100644
+--- a/llvm/lib/DWARFLinker/DWARFStreamer.cpp
++++ b/llvm/lib/DWARFLinker/DWARFStreamer.cpp
+@@ -402,10 +402,9 @@ void DwarfStreamer::emitUnitRangesEntries(CompileUnit &Unit,
+ // Linked addresses might end up in a different order.
+ // Build linked address ranges.
+ AddressRanges LinkedRanges;
+- for (size_t Idx = 0; Idx < FunctionRanges.size(); Idx++)
++ for (const AddressRangeValuePair &Range : FunctionRanges)
+ LinkedRanges.insert(
+- {FunctionRanges[Idx].first.start() + FunctionRanges[Idx].second,
+- FunctionRanges[Idx].first.end() + FunctionRanges[Idx].second});
++ {Range.Range.start() + Range.Value, Range.Range.end() + Range.Value});
+
+ if (!FunctionRanges.empty())
+ emitDwarfDebugArangesTable(Unit, LinkedRanges);
+diff --git a/llvm/lib/Support/AddressRanges.cpp b/llvm/lib/Support/AddressRanges.cpp
+deleted file mode 100644
+index 187d5be00dae..000000000000
+--- a/llvm/lib/Support/AddressRanges.cpp
++++ /dev/null
+@@ -1,70 +0,0 @@
+-//===- AddressRanges.cpp ----------------------------------------*- C++ -*-===//
+-//
+-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+-// See https://llvm.org/LICENSE.txt for license information.
+-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+-//
+-//===----------------------------------------------------------------------===//
+-
+-#include "llvm/ADT/AddressRanges.h"
+-#include "llvm/ADT/STLExtras.h"
+-#include <inttypes.h>
+-
+-using namespace llvm;
+-
+-AddressRanges::Collection::const_iterator
+-AddressRanges::insert(AddressRange Range) {
+- if (Range.size() == 0)
+- return Ranges.end();
+-
+- auto It = llvm::upper_bound(Ranges, Range);
+- auto It2 = It;
+- while (It2 != Ranges.end() && It2->start() <= Range.end())
+- ++It2;
+- if (It != It2) {
+- Range = {Range.start(), std::max(Range.end(), std::prev(It2)->end())};
+- It = Ranges.erase(It, It2);
+- }
+- if (It != Ranges.begin() && Range.start() <= std::prev(It)->end()) {
+- --It;
+- *It = {It->start(), std::max(It->end(), Range.end())};
+- return It;
+- }
+-
+- return Ranges.insert(It, Range);
+-}
+-
+-AddressRanges::Collection::const_iterator
+-AddressRanges::find(uint64_t Addr) const {
+- auto It = std::partition_point(
+- Ranges.begin(), Ranges.end(),
+- [=](const AddressRange &R) { return R.start() <= Addr; });
+-
+- if (It == Ranges.begin())
+- return Ranges.end();
+-
+- --It;
+- if (Addr >= It->end())
+- return Ranges.end();
+-
+- return It;
+-}
+-
+-AddressRanges::Collection::const_iterator
+-AddressRanges::find(AddressRange Range) const {
+- if (Range.size() == 0)
+- return Ranges.end();
+-
+- auto It = std::partition_point(
+- Ranges.begin(), Ranges.end(),
+- [=](const AddressRange &R) { return R.start() <= Range.start(); });
+-
+- if (It == Ranges.begin())
+- return Ranges.end();
+-
+- --It;
+- if (Range.end() > It->end())
+- return Ranges.end();
+-
+- return It;
+-}
+diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt
+index 4cbc3b79f3bb..8fbb2ca4c164 100644
+--- a/llvm/lib/Support/CMakeLists.txt
++++ b/llvm/lib/Support/CMakeLists.txt
+@@ -117,7 +117,6 @@ endif()
+ add_subdirectory(BLAKE3)
+
+ add_llvm_component_library(LLVMSupport
+- AddressRanges.cpp
+ ABIBreak.cpp
+ AMDGPUMetadata.cpp
+ APFixedPoint.cpp
+diff --git a/llvm/unittests/Support/AddressRangeTest.cpp b/llvm/unittests/Support/AddressRangeTest.cpp
+index 468f1e22ffa8..06b326678402 100644
+--- a/llvm/unittests/Support/AddressRangeTest.cpp
++++ b/llvm/unittests/Support/AddressRangeTest.cpp
+@@ -149,8 +149,31 @@ TEST(AddressRangeTest, TestRanges) {
+ EXPECT_EQ(Ranges[0], AddressRange(0x1000, 0x5000));
+ }
+
++TEST(AddressRangeTest, TestRangesRandom) {
++ AddressRanges Ranges;
++ size_t NumElements = 100;
++
++ std::srand(std::time(nullptr));
++
++ // Fill ranges.
++ for (size_t Idx = 0; Idx < NumElements; Idx++) {
++ uint64_t Start = static_cast<uint64_t>(std::rand() % 1000);
++ uint64_t End = Start + static_cast<uint64_t>(std::rand() % 1000);
++ Ranges.insert({Start, End});
++ }
++
++ // Check ranges.
++ for (size_t Idx = 0; Idx + 1 < Ranges.size(); Idx++) {
++ // Check that ranges are not intersected.
++ EXPECT_FALSE(Ranges[Idx].intersects(Ranges[Idx + 1]));
++
++ // Check that ranges are sorted and not adjusted.
++ EXPECT_TRUE(Ranges[Idx].end() < Ranges[Idx + 1].start());
++ }
++}
++
+ TEST(AddressRangeTest, TestRangesMap) {
+- AddressRangesMap<int> Ranges;
++ AddressRangesMap Ranges;
+
+ EXPECT_EQ(Ranges.size(), 0u);
+ EXPECT_TRUE(Ranges.empty());
+@@ -162,73 +185,247 @@ TEST(AddressRangeTest, TestRangesMap) {
+ EXPECT_TRUE(Ranges.contains(0x1500));
+ EXPECT_TRUE(Ranges.contains(AddressRange(0x1000, 0x2000)));
+
++ ///////////////////////////////////////
++ /// Check ranges with the same mapped value.
++
++ // Clear ranges.
++ Ranges.clear();
++ EXPECT_EQ(Ranges.size(), 0u);
++ EXPECT_TRUE(Ranges.empty());
++
++ // Add range and check mapped value.
++ Ranges.insert(AddressRange(0x1000, 0x2000), 0x11);
++ EXPECT_EQ(Ranges.size(), 1u);
++ EXPECT_EQ(Ranges.getRangeThatContains(0x1000)->Value, 0x11);
++
++ // Add adjacent range and check mapped value.
++ Ranges.insert(AddressRange(0x2000, 0x3000), 0x11);
++ EXPECT_EQ(Ranges.size(), 2u);
++ EXPECT_EQ(Ranges.getRangeThatContains(0x1000)->Value, 0x11);
++ EXPECT_EQ(Ranges.getRangeThatContains(0x2000)->Value, 0x11);
++ EXPECT_EQ(Ranges.getRangeThatContains(0x2900)->Value, 0x11);
++ EXPECT_FALSE(Ranges.getRangeThatContains(0x3000));
++
++ // Add intersecting range and check mapped value.
++ Ranges.insert(AddressRange(0x1000, 0x3000), 0x11);
++ EXPECT_EQ(Ranges.size(), 2u);
++ EXPECT_EQ(Ranges.getRangeThatContains(0x1000)->Value, 0x11);
++
++ // Add second range and check mapped values.
++ Ranges.insert(AddressRange(0x4000, 0x5000), 0x11);
++ EXPECT_EQ(Ranges.size(), 3u);
++ EXPECT_EQ(Ranges[0].Range, AddressRange(0x1000, 0x2000));
++ EXPECT_EQ(Ranges[0].Value, 0x11);
++ EXPECT_EQ(Ranges[1].Range, AddressRange(0x2000, 0x3000));
++ EXPECT_EQ(Ranges[1].Value, 0x11);
++ EXPECT_EQ(Ranges[2].Range, AddressRange(0x4000, 0x5000));
++ EXPECT_EQ(Ranges[2].Value, 0x11);
++ EXPECT_EQ(Ranges.getRangeThatContains(0x1000)->Value, 0x11);
++ EXPECT_EQ(Ranges.getRangeThatContains(0x4000)->Value, 0x11);
++
++ // Add intersecting range and check mapped value.
++ Ranges.insert(AddressRange(0x0, 0x6000), 0x11);
++ EXPECT_EQ(Ranges.size(), 6u);
++ EXPECT_EQ(Ranges.getRangeThatContains(0x1000)->Value, 0x11);
++
++ // Check that mapped values are correctly preserved for combined ranges.
++ Ranges.clear();
++ Ranges.insert(AddressRange(0x0, 0xff), 0x11);
++ Ranges.insert(AddressRange(0x100, 0x1ff), 0x11);
++ Ranges.insert(AddressRange(0x200, 0x2ff), 0x11);
++ Ranges.insert(AddressRange(0x500, 0x5ff), 0x11);
++ Ranges.insert(AddressRange(0x300, 0x3ff), 0x11);
++ Ranges.insert(AddressRange(0x400, 0x4ff), 0x11);
++ Ranges.insert(AddressRange(0x600, 0x6ff), 0x11);
++ EXPECT_EQ(Ranges.size(), 7u);
++
++ Ranges.insert(AddressRange(0x150, 0x350), 0x11);
++ EXPECT_EQ(Ranges.size(), 9u);
++ EXPECT_EQ(Ranges[0].Range, AddressRange(0x0, 0xff));
++ EXPECT_EQ(Ranges[0].Value, 0x11);
++ EXPECT_EQ(Ranges[1].Range, AddressRange(0x100, 0x1ff));
++ EXPECT_EQ(Ranges[1].Value, 0x11);
++ EXPECT_EQ(Ranges[2].Range, AddressRange(0x1ff, 0x200));
++ EXPECT_EQ(Ranges[2].Value, 0x11);
++ EXPECT_EQ(Ranges[3].Range, AddressRange(0x200, 0x2ff));
++ EXPECT_EQ(Ranges[3].Value, 0x11);
++ EXPECT_EQ(Ranges[4].Range, AddressRange(0x2ff, 0x300));
++ EXPECT_EQ(Ranges[4].Value, 0x11);
++ EXPECT_EQ(Ranges[5].Range, AddressRange(0x300, 0x3ff));
++ EXPECT_EQ(Ranges[5].Value, 0x11);
++ EXPECT_EQ(Ranges[6].Range, AddressRange(0x400, 0x4ff));
++ EXPECT_EQ(Ranges[6].Value, 0x11);
++ EXPECT_EQ(Ranges[7].Range, AddressRange(0x500, 0x5ff));
++ EXPECT_EQ(Ranges[7].Value, 0x11);
++ EXPECT_EQ(Ranges[8].Range, AddressRange(0x600, 0x6ff));
++ EXPECT_EQ(Ranges[8].Value, 0x11);
++
++ Ranges.insert(AddressRange(0x3ff, 0x400), 0x11);
++ EXPECT_EQ(Ranges.size(), 10u);
++ EXPECT_EQ(Ranges[0].Range, AddressRange(0x0, 0xff));
++ EXPECT_EQ(Ranges[0].Value, 0x11);
++ EXPECT_EQ(Ranges[1].Range, AddressRange(0x100, 0x1ff));
++ EXPECT_EQ(Ranges[1].Value, 0x11);
++ EXPECT_EQ(Ranges[2].Range, AddressRange(0x1ff, 0x200));
++ EXPECT_EQ(Ranges[2].Value, 0x11);
++ EXPECT_EQ(Ranges[3].Range, AddressRange(0x200, 0x2ff));
++ EXPECT_EQ(Ranges[3].Value, 0x11);
++ EXPECT_EQ(Ranges[4].Range, AddressRange(0x2ff, 0x300));
++ EXPECT_EQ(Ranges[4].Value, 0x11);
++ EXPECT_EQ(Ranges[5].Range, AddressRange(0x300, 0x3ff));
++ EXPECT_EQ(Ranges[5].Value, 0x11);
++ EXPECT_EQ(Ranges[6].Range, AddressRange(0x3ff, 0x400));
++ EXPECT_EQ(Ranges[6].Value, 0x11);
++ EXPECT_EQ(Ranges[7].Range, AddressRange(0x400, 0x4ff));
++ EXPECT_EQ(Ranges[7].Value, 0x11);
++ EXPECT_EQ(Ranges[8].Range, AddressRange(0x500, 0x5ff));
++ EXPECT_EQ(Ranges[8].Value, 0x11);
++ EXPECT_EQ(Ranges[9].Range, AddressRange(0x600, 0x6ff));
++ EXPECT_EQ(Ranges[9].Value, 0x11);
++
++ /////////////////////////////////////////////
++ /// Check ranges with various mapped values.
++
+ // Clear ranges.
+ Ranges.clear();
+ EXPECT_EQ(Ranges.size(), 0u);
+ EXPECT_TRUE(Ranges.empty());
+
+- // Add range and check value.
++ // Add range and check mapped value.
+ Ranges.insert(AddressRange(0x1000, 0x2000), 0xfe);
+ EXPECT_EQ(Ranges.size(), 1u);
+- EXPECT_EQ(Ranges.getRangeValueThatContains(0x1000)->second, 0xfe);
++ EXPECT_EQ(Ranges.getRangeThatContains(0x1000)->Value, 0xfe);
+
+- // Add adjacent range and check value.
++ // Add adjacent range and check mapped value.
+ Ranges.insert(AddressRange(0x2000, 0x3000), 0xfc);
+- EXPECT_EQ(Ranges.size(), 1u);
+- EXPECT_EQ(Ranges.getRangeValueThatContains(0x1000)->second, 0xfc);
+- EXPECT_EQ(Ranges.getRangeValueThatContains(0x2000)->second, 0xfc);
+- EXPECT_EQ(Ranges.getRangeValueThatContains(0x2900)->second, 0xfc);
+- EXPECT_FALSE(Ranges.getRangeValueThatContains(0x3000));
++ EXPECT_EQ(Ranges.size(), 2u);
++ EXPECT_EQ(Ranges.getRangeThatContains(0x1000)->Value, 0xfe);
++ EXPECT_EQ(Ranges.getRangeThatContains(0x2000)->Value, 0xfc);
++ EXPECT_EQ(Ranges.getRangeThatContains(0x2900)->Value, 0xfc);
++ EXPECT_FALSE(Ranges.getRangeThatContains(0x3000));
+
+- // Add intersecting range and check value.
+- Ranges.insert(AddressRange(0x2000, 0x3000), 0xff);
+- EXPECT_EQ(Ranges.size(), 1u);
+- EXPECT_EQ(Ranges.getRangeValueThatContains(0x1000)->second, 0xff);
++ // Add intersecting range and check mapped value.
++ Ranges.insert(AddressRange(0x1000, 0x3000), 0xff);
++ EXPECT_EQ(Ranges.size(), 2u);
++ EXPECT_EQ(Ranges.getRangeThatContains(0x1000)->Value, 0xfe);
+
+- // Add second range and check values.
++ // Add one more range and check mapped values.
+ Ranges.insert(AddressRange(0x4000, 0x5000), 0x0);
+- EXPECT_EQ(Ranges.size(), 2u);
+- EXPECT_EQ(Ranges[0].second, 0xff);
+- EXPECT_EQ(Ranges[1].second, 0x0);
+- EXPECT_EQ(Ranges.getRangeValueThatContains(0x1000)->second, 0xff);
+- EXPECT_EQ(Ranges.getRangeValueThatContains(0x4000)->second, 0x0);
++ EXPECT_EQ(Ranges.size(), 3u);
++ EXPECT_EQ(Ranges[0].Value, 0xfe);
++ EXPECT_EQ(Ranges[1].Value, 0xfc);
++ EXPECT_EQ(Ranges[2].Value, 0x0);
++ EXPECT_EQ(Ranges.getRangeThatContains(0x1000)->Value, 0xfe);
++ EXPECT_EQ(Ranges.getRangeThatContains(0x4000)->Value, 0x0);
+
+- // Add intersecting range and check value.
++ // Add intersecting range and check mapped value.
+ Ranges.insert(AddressRange(0x0, 0x6000), 0x1);
+- EXPECT_EQ(Ranges.size(), 1u);
+- EXPECT_EQ(Ranges.getRangeValueThatContains(0x1000)->second, 0x1);
++ EXPECT_EQ(Ranges.size(), 6u);
++ EXPECT_EQ(Ranges[0].Value, 0x1);
++ EXPECT_EQ(Ranges[1].Value, 0xfe);
++ EXPECT_EQ(Ranges[2].Value, 0xfc);
++ EXPECT_EQ(Ranges[3].Value, 0x1);
++ EXPECT_EQ(Ranges[4].Value, 0x0);
++ EXPECT_EQ(Ranges[5].Value, 0x1);
++ EXPECT_EQ(Ranges.getRangeThatContains(0x1000)->Value, 0xfe);
+
+- // Check that values are correctly preserved for combined ranges.
++ // Check that mapped values are correctly preserved for combined ranges.
+ Ranges.clear();
+ Ranges.insert(AddressRange(0x0, 0xff), 0x1);
+ Ranges.insert(AddressRange(0x100, 0x1ff), 0x2);
+ Ranges.insert(AddressRange(0x200, 0x2ff), 0x3);
+ Ranges.insert(AddressRange(0x300, 0x3ff), 0x4);
+- Ranges.insert(AddressRange(0x400, 0x4ff), 0x5);
+ Ranges.insert(AddressRange(0x500, 0x5ff), 0x6);
++ Ranges.insert(AddressRange(0x400, 0x4ff), 0x5);
+ Ranges.insert(AddressRange(0x600, 0x6ff), 0x7);
++ EXPECT_EQ(Ranges.size(), 7u);
+
+ Ranges.insert(AddressRange(0x150, 0x350), 0xff);
+- EXPECT_EQ(Ranges.size(), 5u);
+- EXPECT_EQ(Ranges[0].first, AddressRange(0x0, 0xff));
+- EXPECT_EQ(Ranges[0].second, 0x1);
+- EXPECT_EQ(Ranges[1].first, AddressRange(0x100, 0x3ff));
+- EXPECT_EQ(Ranges[1].second, 0xff);
+- EXPECT_EQ(Ranges[2].first, AddressRange(0x400, 0x4ff));
+- EXPECT_EQ(Ranges[2].second, 0x5);
+- EXPECT_EQ(Ranges[3].first, AddressRange(0x500, 0x5ff));
+- EXPECT_EQ(Ranges[3].second, 0x6);
+- EXPECT_EQ(Ranges[4].first, AddressRange(0x600, 0x6ff));
+- EXPECT_EQ(Ranges[4].second, 0x7);
++ EXPECT_EQ(Ranges.size(), 9u);
++ EXPECT_EQ(Ranges[0].Range, AddressRange(0x0, 0xff));
++ EXPECT_EQ(Ranges[0].Value, 0x1);
++ EXPECT_EQ(Ranges[1].Range, AddressRange(0x100, 0x1ff));
++ EXPECT_EQ(Ranges[1].Value, 0x2);
++ EXPECT_EQ(Ranges[2].Range, AddressRange(0x1ff, 0x200));
++ EXPECT_EQ(Ranges[2].Value, 0xff);
++ EXPECT_EQ(Ranges[3].Range, AddressRange(0x200, 0x2ff));
++ EXPECT_EQ(Ranges[3].Value, 0x3);
++ EXPECT_EQ(Ranges[4].Range, AddressRange(0x2ff, 0x300));
++ EXPECT_EQ(Ranges[4].Value, 0xff);
++ EXPECT_EQ(Ranges[5].Range, AddressRange(0x300, 0x3ff));
++ EXPECT_EQ(Ranges[5].Value, 0x4);
++ EXPECT_EQ(Ranges[6].Range, AddressRange(0x400, 0x4ff));
++ EXPECT_EQ(Ranges[6].Value, 0x5);
++ EXPECT_EQ(Ranges[7].Range, AddressRange(0x500, 0x5ff));
++ EXPECT_EQ(Ranges[7].Value, 0x6);
++ EXPECT_EQ(Ranges[8].Range, AddressRange(0x600, 0x6ff));
++ EXPECT_EQ(Ranges[8].Value, 0x7);
+
++ Ranges.insert(AddressRange(0x650, 0x700), 0x8);
+ Ranges.insert(AddressRange(0x3ff, 0x400), 0x5);
+- EXPECT_EQ(Ranges.size(), 4u);
+- EXPECT_EQ(Ranges[0].first, AddressRange(0x0, 0xff));
+- EXPECT_EQ(Ranges[0].second, 0x1);
+- EXPECT_EQ(Ranges[1].first, AddressRange(0x100, 0x4ff));
+- EXPECT_EQ(Ranges[1].second, 0x5);
+- EXPECT_EQ(Ranges[2].first, AddressRange(0x500, 0x5ff));
+- EXPECT_EQ(Ranges[2].second, 0x6);
+- EXPECT_EQ(Ranges[3].first, AddressRange(0x600, 0x6ff));
+- EXPECT_EQ(Ranges[3].second, 0x7);
++ Ranges.insert(AddressRange(0x0, 0x40), 0xee);
++ EXPECT_EQ(Ranges.size(), 11u);
++ EXPECT_EQ(Ranges[0].Range, AddressRange(0x0, 0xff));
++ EXPECT_EQ(Ranges[0].Value, 0x1);
++ EXPECT_EQ(Ranges[1].Range, AddressRange(0x100, 0x1ff));
++ EXPECT_EQ(Ranges[1].Value, 0x2);
++ EXPECT_EQ(Ranges[2].Range, AddressRange(0x1ff, 0x200));
++ EXPECT_EQ(Ranges[2].Value, 0xff);
++ EXPECT_EQ(Ranges[3].Range, AddressRange(0x200, 0x2ff));
++ EXPECT_EQ(Ranges[3].Value, 0x3);
++ EXPECT_EQ(Ranges[4].Range, AddressRange(0x2ff, 0x300));
++ EXPECT_EQ(Ranges[4].Value, 0xff);
++ EXPECT_EQ(Ranges[5].Range, AddressRange(0x300, 0x3ff));
++ EXPECT_EQ(Ranges[5].Value, 0x4);
++ EXPECT_EQ(Ranges[6].Range, AddressRange(0x3ff, 0x400));
++ EXPECT_EQ(Ranges[6].Value, 0x5);
++ EXPECT_EQ(Ranges[7].Range, AddressRange(0x400, 0x4ff));
++ EXPECT_EQ(Ranges[7].Value, 0x5);
++ EXPECT_EQ(Ranges[8].Range, AddressRange(0x500, 0x5ff));
++ EXPECT_EQ(Ranges[8].Value, 0x6);
++ EXPECT_EQ(Ranges[9].Range, AddressRange(0x600, 0x6ff));
++ EXPECT_EQ(Ranges[9].Value, 0x7);
++ EXPECT_EQ(Ranges[10].Range, AddressRange(0x6ff, 0x700));
++ EXPECT_EQ(Ranges[10].Value, 0x8);
++}
++
++TEST(AddressRangeTest, TestRangesMapRandom) {
++ AddressRangesMap Ranges;
++ size_t NumElements = 100;
++
++ std::srand(std::time(nullptr));
++
++ // Fill ranges. Use the same mapped value.
++ for (size_t Idx = 0; Idx < NumElements; Idx++) {
++ uint64_t Start = static_cast<uint64_t>(std::rand() % 1000);
++ uint64_t End = Start + static_cast<uint64_t>(std::rand() % 1000);
++ Ranges.insert({Start, End}, 0xffLL);
++ }
++
++ // Check ranges.
++ for (size_t Idx = 0; Idx + 1 < Ranges.size(); Idx++) {
++ // Check that ranges are not intersected.
++ EXPECT_FALSE(Ranges[Idx].Range.intersects(Ranges[Idx + 1].Range));
++
++ // Check that ranges are sorted and not adjusted.
++ EXPECT_TRUE(Ranges[Idx].Range.end() <= Ranges[Idx + 1].Range.start());
++ }
++
++ Ranges.clear();
++ // Fill ranges. Use the various mapped value.
++ for (size_t Idx = 0; Idx < NumElements; Idx++) {
++ uint64_t Start = static_cast<uint64_t>(std::rand() % 1000);
++ uint64_t End = Start + static_cast<uint64_t>(std::rand() % 1000);
++ int64_t Value = static_cast<int64_t>(std::rand() % 10);
++ Ranges.insert({Start, End}, Value);
++ }
++
++ // Check ranges.
++ for (size_t Idx = 0; Idx + 1 < Ranges.size(); Idx++) {
++ // Check that ranges are not intersected.
++ EXPECT_FALSE(Ranges[Idx].Range.intersects(Ranges[Idx + 1].Range));
++
++ // Check that ranges are sorted and not adjusted.
++ EXPECT_TRUE(Ranges[Idx].Range.end() <= Ranges[Idx + 1].Range.start());
++ }
+ }
+--
+2.39.0.1.g6739ec1790
+