//===- llvm/unittest/Support/AddresRangeTest.cpp --------------------------===// // // 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/Testing/Support/Error.h" #include "gmock/gmock.h" #include "gtest/gtest.h" using namespace llvm; TEST(AddressRangeTest, TestRanges) { // test llvm::AddressRange. const uint64_t StartAddr = 0x1000; const uint64_t EndAddr = 0x2000; // Verify constructor and API to ensure it takes start and end address. const AddressRange Range(StartAddr, EndAddr); EXPECT_EQ(Range.size(), EndAddr - StartAddr); // Verify llvm::AddressRange::contains(). EXPECT_FALSE(Range.contains(0)); EXPECT_FALSE(Range.contains(StartAddr - 1)); EXPECT_TRUE(Range.contains(StartAddr)); EXPECT_TRUE(Range.contains(EndAddr - 1)); EXPECT_FALSE(Range.contains(EndAddr)); EXPECT_FALSE(Range.contains(UINT64_MAX)); const AddressRange RangeSame(StartAddr, EndAddr); const AddressRange RangeDifferentStart(StartAddr + 1, EndAddr); const AddressRange RangeDifferentEnd(StartAddr, EndAddr + 1); const AddressRange RangeDifferentStartEnd(StartAddr + 1, EndAddr + 1); // Test == and != with values that are the same EXPECT_EQ(Range, RangeSame); EXPECT_FALSE(Range != RangeSame); // Test == and != with values that are the different EXPECT_NE(Range, RangeDifferentStart); EXPECT_NE(Range, RangeDifferentEnd); EXPECT_NE(Range, RangeDifferentStartEnd); EXPECT_FALSE(Range == RangeDifferentStart); EXPECT_FALSE(Range == RangeDifferentEnd); EXPECT_FALSE(Range == RangeDifferentStartEnd); // Test "bool operator<(const AddressRange &, const AddressRange &)". EXPECT_FALSE(Range < RangeSame); EXPECT_FALSE(RangeSame < Range); EXPECT_LT(Range, RangeDifferentStart); EXPECT_LT(Range, RangeDifferentEnd); EXPECT_LT(Range, RangeDifferentStartEnd); // Test "bool operator<(const AddressRange &, uint64_t)" EXPECT_LT(Range.start(), StartAddr + 1); // Test "bool operator<(uint64_t, const AddressRange &)" EXPECT_LT(StartAddr - 1, Range.start()); // Verify llvm::AddressRange::isContiguousWith() and // llvm::AddressRange::intersects(). const AddressRange EndsBeforeRangeStart(0, StartAddr - 1); const AddressRange EndsAtRangeStart(0, StartAddr); const AddressRange OverlapsRangeStart(StartAddr - 1, StartAddr + 1); const AddressRange InsideRange(StartAddr + 1, EndAddr - 1); const AddressRange OverlapsRangeEnd(EndAddr - 1, EndAddr + 1); const AddressRange StartsAtRangeEnd(EndAddr, EndAddr + 0x100); const AddressRange StartsAfterRangeEnd(EndAddr + 1, EndAddr + 0x100); EXPECT_FALSE(Range.intersects(EndsBeforeRangeStart)); EXPECT_FALSE(Range.intersects(EndsAtRangeStart)); EXPECT_TRUE(Range.intersects(OverlapsRangeStart)); EXPECT_TRUE(Range.intersects(InsideRange)); EXPECT_TRUE(Range.intersects(OverlapsRangeEnd)); EXPECT_FALSE(Range.intersects(StartsAtRangeEnd)); EXPECT_FALSE(Range.intersects(StartsAfterRangeEnd)); // Test the functions that maintain address ranges: // "bool AddressRange::contains(uint64_t Addr) const;" // "void AddressRanges::insert(const AddressRange &R);" AddressRanges Ranges; Ranges.insert(AddressRange(0x1000, 0x2000)); Ranges.insert(AddressRange(0x2000, 0x3000)); Ranges.insert(AddressRange(0x4000, 0x5000)); EXPECT_FALSE(Ranges.contains(0)); EXPECT_FALSE(Ranges.contains(0x1000 - 1)); EXPECT_TRUE(Ranges.contains(0x1000)); EXPECT_TRUE(Ranges.contains(0x2000)); EXPECT_TRUE(Ranges.contains(0x4000)); EXPECT_TRUE(Ranges.contains(0x2000 - 1)); EXPECT_TRUE(Ranges.contains(0x3000 - 1)); EXPECT_FALSE(Ranges.contains(0x3000 + 1)); EXPECT_TRUE(Ranges.contains(0x5000 - 1)); EXPECT_FALSE(Ranges.contains(0x5000 + 1)); EXPECT_FALSE(Ranges.contains(UINT64_MAX)); EXPECT_FALSE(Ranges.contains(AddressRange())); EXPECT_FALSE(Ranges.contains(AddressRange(0x1000 - 1, 0x1000))); EXPECT_FALSE(Ranges.contains(AddressRange(0x1000, 0x1000))); EXPECT_TRUE(Ranges.contains(AddressRange(0x1000, 0x1000 + 1))); EXPECT_TRUE(Ranges.contains(AddressRange(0x1000, 0x2000))); EXPECT_TRUE(Ranges.contains(AddressRange(0x1000, 0x2001))); EXPECT_TRUE(Ranges.contains(AddressRange(0x2000, 0x3000))); EXPECT_FALSE(Ranges.contains(AddressRange(0x2000, 0x3001))); EXPECT_FALSE(Ranges.contains(AddressRange(0x3000, 0x3001))); EXPECT_FALSE(Ranges.contains(AddressRange(0x1500, 0x4500))); EXPECT_FALSE(Ranges.contains(AddressRange(0x5000, 0x5001))); // Verify that intersecting ranges get combined Ranges.clear(); Ranges.insert(AddressRange(0x1100, 0x1F00)); // Verify a wholy contained range that is added doesn't do anything. Ranges.insert(AddressRange(0x1500, 0x1F00)); EXPECT_EQ(Ranges.size(), 1u); EXPECT_EQ(Ranges[0], AddressRange(0x1100, 0x1F00)); // Verify a range that starts before and intersects gets combined. Ranges.insert(AddressRange(0x1000, Ranges[0].start() + 1)); EXPECT_EQ(Ranges.size(), 1u); EXPECT_EQ(Ranges[0], AddressRange(0x1000, 0x1F00)); // Verify a range that starts inside and extends ranges gets combined. Ranges.insert(AddressRange(Ranges[0].end() - 1, 0x2000)); EXPECT_EQ(Ranges.size(), 1u); EXPECT_EQ(Ranges[0], AddressRange(0x1000, 0x2000)); // Verify that adjacent ranges get combined Ranges.insert(AddressRange(0x2000, 0x2fff)); EXPECT_EQ(Ranges.size(), 1u); EXPECT_EQ(Ranges[0], AddressRange(0x1000, 0x2fff)); // Verify that ranges having 1 byte gap do not get combined Ranges.insert(AddressRange(0x3000, 0x4000)); EXPECT_EQ(Ranges.size(), 2u); EXPECT_EQ(Ranges[0], AddressRange(0x1000, 0x2fff)); EXPECT_EQ(Ranges[1], AddressRange(0x3000, 0x4000)); // Verify if we add an address range that intersects two ranges // that they get combined Ranges.insert(AddressRange(Ranges[0].end() - 1, Ranges[1].start() + 1)); EXPECT_EQ(Ranges.size(), 1u); EXPECT_EQ(Ranges[0], AddressRange(0x1000, 0x4000)); Ranges.insert(AddressRange(0x3000, 0x4000)); Ranges.insert(AddressRange(0x4000, 0x5000)); Ranges.insert(AddressRange(0x2000, 0x4500)); EXPECT_EQ(Ranges.size(), 1u); 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(std::rand() % 1000); uint64_t End = Start + static_cast(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 Ranges; EXPECT_EQ(Ranges.size(), 0u); EXPECT_TRUE(Ranges.empty()); // Add single range. Ranges.insert(AddressRange(0x1000, 0x2000), 0xfe); EXPECT_EQ(Ranges.size(), 1u); EXPECT_FALSE(Ranges.empty()); 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 mapped value. Ranges.insert(AddressRange(0x1000, 0x2000), 0xfe); EXPECT_EQ(Ranges.size(), 1u); EXPECT_EQ(Ranges.getRangeThatContains(0x1000)->Value, 0xfe); // Add adjacent range and check mapped value. Ranges.insert(AddressRange(0x2000, 0x3000), 0xfc); 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 mapped value. Ranges.insert(AddressRange(0x1000, 0x3000), 0xff); EXPECT_EQ(Ranges.size(), 2u); EXPECT_EQ(Ranges.getRangeThatContains(0x1000)->Value, 0xfe); // Add one more range and check mapped values. Ranges.insert(AddressRange(0x4000, 0x5000), 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 mapped value. Ranges.insert(AddressRange(0x0, 0x6000), 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 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(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(), 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); 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(std::rand() % 1000); uint64_t End = Start + static_cast(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(std::rand() % 1000); uint64_t End = Start + static_cast(std::rand() % 1000); int64_t Value = static_cast(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()); } }