Index: test/unittests/compiler/live-range-unittest.cc |
diff --git a/test/unittests/compiler/live-range-unittest.cc b/test/unittests/compiler/live-range-unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a9ac20ca33e534d3bdb1ddffdf2d366e01e75a24 |
--- /dev/null |
+++ b/test/unittests/compiler/live-range-unittest.cc |
@@ -0,0 +1,412 @@ |
+// Copyright 2015 the V8 project authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+ |
+#include "test/unittests/compiler/live-range-builder.h" |
+#include "test/unittests/test-utils.h" |
+ |
+ |
+// TODO(mtrofin): would we want to centralize this definition? |
+#ifdef DEBUG |
+#define V8_ASSERT_DEBUG_DEATH(statement, regex) \ |
+ ASSERT_DEATH_IF_SUPPORTED(statement, regex) |
+ |
+#else |
+#define V8_ASSERT_DEBUG_DEATH(statement, regex) statement |
+#endif // DEBUG |
+ |
+namespace v8 { |
+namespace internal { |
+namespace compiler { |
+ |
+class LiveRangeUnitTest : public TestWithZone { |
+ public: |
+ // Split helper, to avoid int->LifetimePosition conversion nuisance. |
+ LiveRange* Split(LiveRange* range, int pos) { |
+ return range->SplitAt(LifetimePosition::FromInt(pos), zone()); |
+ } |
+ |
+ |
+ TopLevelLiveRange* Splinter(TopLevelLiveRange* top, int start, int end, |
+ int new_id = 0) { |
+ TopLevelLiveRange* ret = |
+ new (zone()) TopLevelLiveRange(new_id, MachineType::kRepTagged); |
+ top->Splinter(LifetimePosition::FromInt(start), |
+ LifetimePosition::FromInt(end), ret, zone()); |
+ return ret; |
+ } |
+ |
+ // Ranges first and second match structurally. |
+ bool RangesMatch(LiveRange* first, LiveRange* second) { |
+ if (first->Start() != second->Start() || first->End() != second->End()) { |
+ return false; |
+ } |
+ UseInterval* i1 = first->first_interval(); |
+ UseInterval* i2 = second->first_interval(); |
+ |
+ while (i1 != nullptr && i2 != nullptr) { |
+ if (i1->start() != i2->start() || i1->end() != i2->end()) return false; |
+ i1 = i1->next(); |
+ i2 = i2->next(); |
+ } |
+ if (i1 != nullptr || i2 != nullptr) return false; |
+ |
+ UsePosition* p1 = first->first_pos(); |
+ UsePosition* p2 = second->first_pos(); |
+ |
+ while (p1 != nullptr && p2 != nullptr) { |
+ if (p1->pos() != p2->pos()) return false; |
+ p1 = p1->next(); |
+ p2 = p2->next(); |
+ } |
+ if (p1 != nullptr || p2 != nullptr) return false; |
+ return true; |
+ } |
+}; |
+ |
+ |
+TEST_F(LiveRangeUnitTest, InvalidConstruction) { |
+ // Build a range manually, because the builder guards against empty cases. |
+ TopLevelLiveRange* range = |
+ new (zone()) TopLevelLiveRange(1, MachineType::kRepTagged); |
+ V8_ASSERT_DEBUG_DEATH( |
+ range->AddUseInterval(LifetimePosition::FromInt(0), |
+ LifetimePosition::FromInt(0), zone()), |
+ ".*"); |
+} |
+ |
+ |
+TEST_F(LiveRangeUnitTest, SplitInvalidStart) { |
+ TopLevelLiveRange* range = TestRangeBuilder(zone()).Build(0, 1); |
+ V8_ASSERT_DEBUG_DEATH(Split(range, 0), ".*"); |
+} |
+ |
+ |
+TEST_F(LiveRangeUnitTest, InvalidSplitEnd) { |
+ TopLevelLiveRange* range = TestRangeBuilder(zone()).Build(0, 1); |
+ ASSERT_DEATH_IF_SUPPORTED(Split(range, 1), ".*"); |
+} |
+ |
+ |
+TEST_F(LiveRangeUnitTest, SplitInvalidPreStart) { |
+ TopLevelLiveRange* range = TestRangeBuilder(zone()).Build(1, 2); |
+ ASSERT_DEATH_IF_SUPPORTED(Split(range, 0), ".*"); |
+} |
+ |
+ |
+TEST_F(LiveRangeUnitTest, SplitInvalidPostEnd) { |
+ TopLevelLiveRange* range = TestRangeBuilder(zone()).Build(0, 1); |
+ ASSERT_DEATH_IF_SUPPORTED(Split(range, 2), ".*"); |
+} |
+ |
+ |
+TEST_F(LiveRangeUnitTest, SplitSingleIntervalNoUsePositions) { |
+ TopLevelLiveRange* range = TestRangeBuilder(zone()).Build(0, 2); |
+ LiveRange* child = Split(range, 1); |
+ |
+ EXPECT_NE(nullptr, range->next()); |
+ EXPECT_EQ(child, range->next()); |
+ |
+ LiveRange* expected_top = TestRangeBuilder(zone()).Build(0, 1); |
+ LiveRange* expected_bottom = TestRangeBuilder(zone()).Build(1, 2); |
+ EXPECT_TRUE(RangesMatch(expected_top, range)); |
+ EXPECT_TRUE(RangesMatch(expected_bottom, child)); |
+} |
+ |
+ |
+TEST_F(LiveRangeUnitTest, SplitManyIntervalNoUsePositionsBetween) { |
+ TopLevelLiveRange* range = |
+ TestRangeBuilder(zone()).Add(0, 2).Add(4, 6).Build(); |
+ LiveRange* child = Split(range, 3); |
+ |
+ EXPECT_NE(nullptr, range->next()); |
+ EXPECT_EQ(child, range->next()); |
+ |
+ LiveRange* expected_top = TestRangeBuilder(zone()).Build(0, 2); |
+ LiveRange* expected_bottom = TestRangeBuilder(zone()).Build(4, 6); |
+ EXPECT_TRUE(RangesMatch(expected_top, range)); |
+ EXPECT_TRUE(RangesMatch(expected_bottom, child)); |
+} |
+ |
+ |
+TEST_F(LiveRangeUnitTest, SplitManyIntervalNoUsePositionsFront) { |
+ TopLevelLiveRange* range = |
+ TestRangeBuilder(zone()).Add(0, 2).Add(4, 6).Build(); |
+ LiveRange* child = Split(range, 1); |
+ |
+ EXPECT_NE(nullptr, range->next()); |
+ EXPECT_EQ(child, range->next()); |
+ |
+ LiveRange* expected_top = TestRangeBuilder(zone()).Build(0, 1); |
+ LiveRange* expected_bottom = |
+ TestRangeBuilder(zone()).Add(1, 2).Add(4, 6).Build(); |
+ EXPECT_TRUE(RangesMatch(expected_top, range)); |
+ EXPECT_TRUE(RangesMatch(expected_bottom, child)); |
+} |
+ |
+ |
+TEST_F(LiveRangeUnitTest, SplitManyIntervalNoUsePositionsAfter) { |
+ TopLevelLiveRange* range = |
+ TestRangeBuilder(zone()).Add(0, 2).Add(4, 6).Build(); |
+ LiveRange* child = Split(range, 5); |
+ |
+ EXPECT_NE(nullptr, range->next()); |
+ EXPECT_EQ(child, range->next()); |
+ |
+ LiveRange* expected_top = |
+ TestRangeBuilder(zone()).Add(0, 2).Add(4, 5).Build(); |
+ LiveRange* expected_bottom = TestRangeBuilder(zone()).Build(5, 6); |
+ EXPECT_TRUE(RangesMatch(expected_top, range)); |
+ EXPECT_TRUE(RangesMatch(expected_bottom, child)); |
+} |
+ |
+ |
+TEST_F(LiveRangeUnitTest, SplitSingleIntervalUsePositions) { |
+ TopLevelLiveRange* range = |
+ TestRangeBuilder(zone()).Add(0, 3).AddUse(0).AddUse(2).Build(); |
+ |
+ LiveRange* child = Split(range, 1); |
+ |
+ EXPECT_NE(nullptr, range->next()); |
+ EXPECT_EQ(child, range->next()); |
+ |
+ LiveRange* expected_top = |
+ TestRangeBuilder(zone()).Add(0, 1).AddUse(0).Build(); |
+ LiveRange* expected_bottom = |
+ TestRangeBuilder(zone()).Add(1, 3).AddUse(2).Build(); |
+ EXPECT_TRUE(RangesMatch(expected_top, range)); |
+ EXPECT_TRUE(RangesMatch(expected_bottom, child)); |
+} |
+ |
+ |
+TEST_F(LiveRangeUnitTest, SplitSingleIntervalUsePositionsAtPos) { |
+ TopLevelLiveRange* range = |
+ TestRangeBuilder(zone()).Add(0, 3).AddUse(0).AddUse(2).Build(); |
+ |
+ LiveRange* child = Split(range, 2); |
+ |
+ EXPECT_NE(nullptr, range->next()); |
+ EXPECT_EQ(child, range->next()); |
+ |
+ LiveRange* expected_top = |
+ TestRangeBuilder(zone()).Add(0, 2).AddUse(0).AddUse(2).Build(); |
+ LiveRange* expected_bottom = TestRangeBuilder(zone()).Build(2, 3); |
+ EXPECT_TRUE(RangesMatch(expected_top, range)); |
+ EXPECT_TRUE(RangesMatch(expected_bottom, child)); |
+} |
+ |
+ |
+TEST_F(LiveRangeUnitTest, SplitManyIntervalUsePositionsBetween) { |
+ TopLevelLiveRange* range = |
+ TestRangeBuilder(zone()).Add(0, 2).Add(4, 6).AddUse(1).AddUse(5).Build(); |
+ LiveRange* child = Split(range, 3); |
+ |
+ EXPECT_NE(nullptr, range->next()); |
+ EXPECT_EQ(child, range->next()); |
+ |
+ LiveRange* expected_top = |
+ TestRangeBuilder(zone()).Add(0, 2).AddUse(1).Build(); |
+ LiveRange* expected_bottom = |
+ TestRangeBuilder(zone()).Add(4, 6).AddUse(5).Build(); |
+ EXPECT_TRUE(RangesMatch(expected_top, range)); |
+ EXPECT_TRUE(RangesMatch(expected_bottom, child)); |
+} |
+ |
+ |
+TEST_F(LiveRangeUnitTest, SplitManyIntervalUsePositionsAtInterval) { |
+ TopLevelLiveRange* range = |
+ TestRangeBuilder(zone()).Add(0, 2).Add(4, 6).AddUse(1).AddUse(4).Build(); |
+ LiveRange* child = Split(range, 4); |
+ |
+ EXPECT_NE(nullptr, range->next()); |
+ EXPECT_EQ(child, range->next()); |
+ |
+ LiveRange* expected_top = |
+ TestRangeBuilder(zone()).Add(0, 2).AddUse(1).Build(); |
+ LiveRange* expected_bottom = |
+ TestRangeBuilder(zone()).Add(4, 6).AddUse(4).Build(); |
+ EXPECT_TRUE(RangesMatch(expected_top, range)); |
+ EXPECT_TRUE(RangesMatch(expected_bottom, child)); |
+} |
+ |
+ |
+TEST_F(LiveRangeUnitTest, SplitManyIntervalUsePositionsFront) { |
+ TopLevelLiveRange* range = |
+ TestRangeBuilder(zone()).Add(0, 2).Add(4, 6).AddUse(1).AddUse(5).Build(); |
+ LiveRange* child = Split(range, 1); |
+ |
+ EXPECT_NE(nullptr, range->next()); |
+ EXPECT_EQ(child, range->next()); |
+ |
+ LiveRange* expected_top = |
+ TestRangeBuilder(zone()).Add(0, 1).AddUse(1).Build(); |
+ LiveRange* expected_bottom = |
+ TestRangeBuilder(zone()).Add(1, 2).Add(4, 6).AddUse(5).Build(); |
+ EXPECT_TRUE(RangesMatch(expected_top, range)); |
+ EXPECT_TRUE(RangesMatch(expected_bottom, child)); |
+} |
+ |
+ |
+TEST_F(LiveRangeUnitTest, SplitManyIntervalUsePositionsAfter) { |
+ TopLevelLiveRange* range = |
+ TestRangeBuilder(zone()).Add(0, 2).Add(4, 6).AddUse(1).AddUse(5).Build(); |
+ LiveRange* child = Split(range, 5); |
+ |
+ EXPECT_NE(nullptr, range->next()); |
+ EXPECT_EQ(child, range->next()); |
+ |
+ LiveRange* expected_top = |
+ TestRangeBuilder(zone()).Add(0, 2).Add(4, 5).AddUse(1).AddUse(5).Build(); |
+ LiveRange* expected_bottom = TestRangeBuilder(zone()).Build(5, 6); |
+ EXPECT_TRUE(RangesMatch(expected_top, range)); |
+ EXPECT_TRUE(RangesMatch(expected_bottom, child)); |
+} |
+ |
+ |
+TEST_F(LiveRangeUnitTest, SplinterSingleInterval) { |
+ TopLevelLiveRange* range = TestRangeBuilder(zone()).Build(0, 6); |
+ TopLevelLiveRange* splinter = Splinter(range, 3, 5); |
+ EXPECT_EQ(nullptr, range->next()); |
+ EXPECT_EQ(nullptr, splinter->next()); |
+ EXPECT_EQ(range, splinter->splintered_from()); |
+ |
+ TopLevelLiveRange* expected_source = |
+ TestRangeBuilder(zone()).Add(0, 3).Add(5, 6).Build(); |
+ TopLevelLiveRange* expected_splinter = TestRangeBuilder(zone()).Build(3, 5); |
+ EXPECT_TRUE(RangesMatch(expected_source, range)); |
+ EXPECT_TRUE(RangesMatch(expected_splinter, splinter)); |
+} |
+ |
+ |
+TEST_F(LiveRangeUnitTest, MergeSingleInterval) { |
+ TopLevelLiveRange* original = TestRangeBuilder(zone()).Build(0, 6); |
+ TopLevelLiveRange* splinter = Splinter(original, 3, 5); |
+ |
+ original->Merge(splinter, zone()); |
+ TopLevelLiveRange* result = TestRangeBuilder(zone()).Build(0, 6); |
+ LiveRange* child_1 = Split(result, 3); |
+ Split(child_1, 5); |
+ |
+ EXPECT_TRUE(RangesMatch(result, original)); |
+} |
+ |
+ |
+TEST_F(LiveRangeUnitTest, SplinterMultipleIntervalsOutside) { |
+ TopLevelLiveRange* range = |
+ TestRangeBuilder(zone()).Add(0, 3).Add(5, 8).Build(); |
+ TopLevelLiveRange* splinter = Splinter(range, 2, 6); |
+ EXPECT_EQ(nullptr, range->next()); |
+ EXPECT_EQ(nullptr, splinter->next()); |
+ EXPECT_EQ(range, splinter->splintered_from()); |
+ |
+ TopLevelLiveRange* expected_source = |
+ TestRangeBuilder(zone()).Add(0, 2).Add(6, 8).Build(); |
+ TopLevelLiveRange* expected_splinter = |
+ TestRangeBuilder(zone()).Add(2, 3).Add(5, 6).Build(); |
+ EXPECT_TRUE(RangesMatch(expected_source, range)); |
+ EXPECT_TRUE(RangesMatch(expected_splinter, splinter)); |
+} |
+ |
+ |
+TEST_F(LiveRangeUnitTest, MergeMultipleIntervalsOutside) { |
+ TopLevelLiveRange* original = |
+ TestRangeBuilder(zone()).Add(0, 3).Add(5, 8).Build(); |
+ TopLevelLiveRange* splinter = Splinter(original, 2, 6); |
+ original->Merge(splinter, zone()); |
+ |
+ TopLevelLiveRange* result = |
+ TestRangeBuilder(zone()).Add(0, 3).Add(5, 8).Build(); |
+ LiveRange* child_1 = Split(result, 2); |
+ Split(child_1, 6); |
+ EXPECT_TRUE(RangesMatch(result, original)); |
+} |
+ |
+ |
+TEST_F(LiveRangeUnitTest, SplinterMultipleIntervalsInside) { |
+ TopLevelLiveRange* range = |
+ TestRangeBuilder(zone()).Add(0, 3).Add(5, 8).Build(); |
+ V8_ASSERT_DEBUG_DEATH(Splinter(range, 3, 5), ".*"); |
+} |
+ |
+ |
+TEST_F(LiveRangeUnitTest, SplinterMultipleIntervalsLeft) { |
+ TopLevelLiveRange* range = |
+ TestRangeBuilder(zone()).Add(0, 3).Add(5, 8).Build(); |
+ TopLevelLiveRange* splinter = Splinter(range, 2, 4); |
+ EXPECT_EQ(nullptr, range->next()); |
+ EXPECT_EQ(nullptr, splinter->next()); |
+ EXPECT_EQ(range, splinter->splintered_from()); |
+ |
+ TopLevelLiveRange* expected_source = |
+ TestRangeBuilder(zone()).Add(0, 2).Add(5, 8).Build(); |
+ TopLevelLiveRange* expected_splinter = TestRangeBuilder(zone()).Build(2, 3); |
+ EXPECT_TRUE(RangesMatch(expected_source, range)); |
+ EXPECT_TRUE(RangesMatch(expected_splinter, splinter)); |
+} |
+ |
+ |
+TEST_F(LiveRangeUnitTest, MergeMultipleIntervalsLeft) { |
+ TopLevelLiveRange* original = |
+ TestRangeBuilder(zone()).Add(0, 3).Add(5, 8).Build(); |
+ TopLevelLiveRange* splinter = Splinter(original, 2, 4); |
+ original->Merge(splinter, zone()); |
+ |
+ TopLevelLiveRange* result = |
+ TestRangeBuilder(zone()).Add(0, 3).Add(5, 8).Build(); |
+ Split(result, 2); |
+ EXPECT_TRUE(RangesMatch(result, original)); |
+} |
+ |
+ |
+TEST_F(LiveRangeUnitTest, SplinterMultipleIntervalsRight) { |
+ TopLevelLiveRange* range = |
+ TestRangeBuilder(zone()).Add(0, 3).Add(5, 8).Build(); |
+ TopLevelLiveRange* splinter = Splinter(range, 4, 6); |
+ EXPECT_EQ(nullptr, range->next()); |
+ EXPECT_EQ(nullptr, splinter->next()); |
+ EXPECT_EQ(range, splinter->splintered_from()); |
+ |
+ TopLevelLiveRange* expected_source = |
+ TestRangeBuilder(zone()).Add(0, 3).Add(6, 8).Build(); |
+ TopLevelLiveRange* expected_splinter = TestRangeBuilder(zone()).Build(5, 6); |
+ EXPECT_TRUE(RangesMatch(expected_source, range)); |
+ EXPECT_TRUE(RangesMatch(expected_splinter, splinter)); |
+} |
+ |
+ |
+TEST_F(LiveRangeUnitTest, MergeMultipleIntervalsRight) { |
+ TopLevelLiveRange* original = |
+ TestRangeBuilder(zone()).Add(0, 3).Add(5, 8).Build(); |
+ TopLevelLiveRange* splinter = Splinter(original, 4, 6); |
+ original->Merge(splinter, zone()); |
+ |
+ TopLevelLiveRange* result = |
+ TestRangeBuilder(zone()).Add(0, 3).Add(5, 8).Build(); |
+ LiveRange* child_1 = Split(result, 5); |
+ Split(child_1, 6); |
+ |
+ EXPECT_TRUE(RangesMatch(result, original)); |
+} |
+ |
+ |
+TEST_F(LiveRangeUnitTest, MergeAfterSplitting) { |
+ TopLevelLiveRange* original = TestRangeBuilder(zone()).Build(0, 8); |
+ TopLevelLiveRange* splinter = Splinter(original, 4, 6); |
+ LiveRange* original_child = Split(original, 2); |
+ Split(original_child, 7); |
+ original->Merge(splinter, zone()); |
+ |
+ TopLevelLiveRange* result = TestRangeBuilder(zone()).Build(0, 8); |
+ LiveRange* child_1 = Split(result, 2); |
+ LiveRange* child_2 = Split(child_1, 4); |
+ LiveRange* child_3 = Split(child_2, 6); |
+ Split(child_3, 7); |
+ |
+ EXPECT_TRUE(RangesMatch(result, original)); |
+} |
+ |
+ |
+} // namespace compiler |
+} // namespace internal |
+} // namespace v8 |