Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "src/compiler/coalesced-live-ranges.h" | |
| 6 #include "test/unittests/test-utils.h" | |
| 7 | |
| 8 namespace v8 { | |
| 9 namespace internal { | |
| 10 namespace compiler { | |
| 11 | |
| 12 | |
| 13 // Utility offering shorthand syntax for building up a range by providing its ID | |
| 14 // and pairs (start, end) specifying intervals. Circumvents current incomplete | |
| 15 // support for C++ features such as instantiation lists, on OS X and Android. | |
| 16 class TestRangeBuilder { | |
| 17 public: | |
| 18 explicit TestRangeBuilder(Zone* zone) : id_(-1), pairs_(), zone_(zone) {} | |
| 19 | |
| 20 TestRangeBuilder& Id(int id) { | |
| 21 id_ = id; | |
| 22 return *this; | |
| 23 } | |
| 24 TestRangeBuilder& Add(int start, int end) { | |
| 25 pairs_.push_back({start, end}); | |
| 26 return *this; | |
| 27 } | |
| 28 | |
| 29 LiveRange* Build(int start, int end) { return Add(start, end).Build(); } | |
| 30 | |
| 31 LiveRange* Build() { | |
| 32 LiveRange* range = new (zone_) LiveRange(id_, MachineType::kRepTagged); | |
| 33 // Traverse the provided interval specifications backwards, because that is | |
| 34 // what LiveRange expects. | |
| 35 for (int i = static_cast<int>(pairs_.size()) - 1; i >= 0; --i) { | |
| 36 auto pair = pairs_[i]; | |
| 37 LifetimePosition start = LifetimePosition::FromInt(pair.first); | |
| 38 LifetimePosition end = LifetimePosition::FromInt(pair.second); | |
| 39 CHECK(start < end); | |
| 40 range->AddUseInterval(start, end, zone_); | |
| 41 } | |
| 42 | |
| 43 pairs_.clear(); | |
| 44 return range; | |
| 45 } | |
| 46 | |
| 47 private: | |
| 48 typedef std::pair<int, int> Interval; | |
| 49 typedef std::vector<Interval> IntervalList; | |
| 50 int id_; | |
| 51 IntervalList pairs_; | |
| 52 Zone* zone_; | |
| 53 }; | |
| 54 | |
| 55 | |
| 56 typedef std::set<int> LiveRangeIDs; | |
| 57 | |
| 58 | |
| 59 // Utility offering shorthand building of a set of integers. Circumvents current | |
| 60 // incomplete support for C++ features such as instantiation lists, on OS X and | |
| 61 // Android. | |
| 62 class Conflicts { | |
| 63 public: | |
| 64 Conflicts(int number_of_conflicts, ...) : set_() { | |
|
Benedikt Meurer
2015/07/14 04:35:01
Do we really need to use varargs here? You could a
Mircea Trofin
2015/07/14 16:19:18
Agreed, and even easier, since the purpose was sim
| |
| 65 CHECK(number_of_conflicts > 0); | |
| 66 va_list conflict_list; | |
| 67 va_start(conflict_list, number_of_conflicts); | |
| 68 for (int i = 0; i < number_of_conflicts; ++i) { | |
| 69 int val = va_arg(conflict_list, int); | |
| 70 set_.insert(val); | |
| 71 } | |
| 72 va_end(conflict_list); | |
| 73 } | |
| 74 | |
| 75 operator LiveRangeIDs&() { return set_; } | |
|
Benedikt Meurer
2015/07/14 04:35:01
Same here, there's no need for operator overloadin
Mircea Trofin
2015/07/14 16:19:18
Done.
| |
| 76 static LiveRangeIDs& None() { return empty_set; } | |
| 77 | |
| 78 private: | |
| 79 static LiveRangeIDs empty_set; | |
| 80 LiveRangeIDs set_; | |
| 81 }; | |
| 82 | |
| 83 LiveRangeIDs Conflicts::empty_set; | |
| 84 | |
| 85 class CoalescedLiveRangesTest : public TestWithZone { | |
| 86 public: | |
| 87 CoalescedLiveRangesTest() : TestWithZone(), ranges_(zone()) {} | |
| 88 bool CheckConflictsMatch(const LiveRange* range, const LiveRangeIDs& ids); | |
| 89 | |
| 90 CoalescedLiveRanges& ranges() { return ranges_; } | |
| 91 const CoalescedLiveRanges& ranges() const { return ranges_; } | |
| 92 bool AllocationsAreValid() const; | |
| 93 void RemoveConflicts(LiveRange* range); | |
| 94 | |
| 95 private: | |
| 96 CoalescedLiveRanges ranges_; | |
| 97 }; | |
| 98 | |
| 99 | |
| 100 void CoalescedLiveRangesTest::RemoveConflicts(LiveRange* range) { | |
| 101 ranges().RemoveConflicts(range, [](LiveRange* conflict) {}); | |
| 102 } | |
| 103 | |
| 104 | |
| 105 bool CoalescedLiveRangesTest::AllocationsAreValid() const { | |
| 106 return ranges().TestOnlyVerifyAllocationsAreValid(); | |
| 107 } | |
| 108 | |
| 109 | |
| 110 bool CoalescedLiveRangesTest::CheckConflictsMatch(const LiveRange* range, | |
| 111 const LiveRangeIDs& ids) { | |
| 112 LiveRangeIDs found_ids; | |
| 113 | |
| 114 ranges().VisitConflicts(range, [&](const LiveRange* conflict) { | |
| 115 found_ids.insert(conflict->id()); | |
| 116 return true; | |
| 117 }); | |
| 118 return found_ids == ids; | |
| 119 } | |
| 120 | |
| 121 | |
| 122 TEST_F(CoalescedLiveRangesTest, VisitEmptyAllocations) { | |
| 123 LiveRange* range = TestRangeBuilder(zone()).Id(1).Build(1, 5); | |
| 124 ASSERT_TRUE(ranges().empty()); | |
| 125 ASSERT_TRUE(AllocationsAreValid()); | |
| 126 ASSERT_TRUE(CheckConflictsMatch(range, Conflicts::None())); | |
| 127 } | |
| 128 | |
| 129 | |
| 130 TEST_F(CoalescedLiveRangesTest, CandidateBeforeAfterAllocations) { | |
| 131 LiveRange* range = TestRangeBuilder(zone()).Id(1).Build(5, 6); | |
| 132 ranges().AllocateRange(range); | |
| 133 ASSERT_FALSE(ranges().empty()); | |
| 134 ASSERT_TRUE(AllocationsAreValid()); | |
| 135 LiveRange* query = TestRangeBuilder(zone()).Id(2).Build(1, 2); | |
| 136 ASSERT_TRUE(CheckConflictsMatch(query, Conflicts::None())); | |
| 137 query = TestRangeBuilder(zone()).Id(3).Build(1, 5); | |
| 138 ASSERT_TRUE(CheckConflictsMatch(query, Conflicts::None())); | |
| 139 } | |
| 140 | |
| 141 | |
| 142 TEST_F(CoalescedLiveRangesTest, CandidateBeforeAfterManyAllocations) { | |
| 143 LiveRange* range = | |
| 144 TestRangeBuilder(zone()).Id(1).Add(5, 7).Add(10, 12).Build(); | |
| 145 ranges().AllocateRange(range); | |
| 146 ASSERT_FALSE(ranges().empty()); | |
| 147 ASSERT_TRUE(AllocationsAreValid()); | |
| 148 LiveRange* query = | |
| 149 TestRangeBuilder(zone()).Id(2).Add(1, 2).Add(13, 15).Build(); | |
| 150 ASSERT_TRUE(CheckConflictsMatch(query, Conflicts::None())); | |
| 151 query = TestRangeBuilder(zone()).Id(3).Add(1, 5).Add(12, 15).Build(); | |
| 152 ASSERT_TRUE(CheckConflictsMatch(query, Conflicts::None())); | |
| 153 } | |
| 154 | |
| 155 | |
| 156 TEST_F(CoalescedLiveRangesTest, SelfConflictsWithSelf) { | |
| 157 LiveRange* range = TestRangeBuilder(zone()).Id(1).Build(1, 5); | |
| 158 ranges().AllocateRange(range); | |
| 159 ASSERT_FALSE(ranges().empty()); | |
| 160 ASSERT_TRUE(AllocationsAreValid()); | |
| 161 ASSERT_TRUE(CheckConflictsMatch(range, Conflicts(1, 1))); | |
| 162 range = TestRangeBuilder(zone()).Id(2).Build(8, 10); | |
| 163 ranges().AllocateRange(range); | |
| 164 ASSERT_TRUE(CheckConflictsMatch(range, Conflicts(1, 2))); | |
| 165 } | |
| 166 | |
| 167 | |
| 168 TEST_F(CoalescedLiveRangesTest, QueryStartsBeforeConflict) { | |
| 169 LiveRange* range = TestRangeBuilder(zone()).Id(1).Build(2, 5); | |
| 170 ranges().AllocateRange(range); | |
| 171 LiveRange* query = TestRangeBuilder(zone()).Id(2).Build(1, 3); | |
| 172 ASSERT_TRUE(CheckConflictsMatch(query, Conflicts(1, 1))); | |
| 173 range = TestRangeBuilder(zone()).Id(3).Build(8, 10); | |
| 174 ranges().AllocateRange(range); | |
| 175 query = TestRangeBuilder(zone()).Id(4).Build(6, 9); | |
| 176 ASSERT_TRUE(CheckConflictsMatch(query, Conflicts(1, 3))); | |
| 177 } | |
| 178 | |
| 179 | |
| 180 TEST_F(CoalescedLiveRangesTest, QueryStartsInConflict) { | |
| 181 LiveRange* range = TestRangeBuilder(zone()).Id(1).Build(2, 5); | |
| 182 ranges().AllocateRange(range); | |
| 183 LiveRange* query = TestRangeBuilder(zone()).Id(2).Build(3, 6); | |
| 184 ASSERT_TRUE(CheckConflictsMatch(query, Conflicts(1, 1))); | |
| 185 range = TestRangeBuilder(zone()).Id(3).Build(8, 10); | |
| 186 ranges().AllocateRange(range); | |
| 187 query = TestRangeBuilder(zone()).Id(4).Build(9, 11); | |
| 188 ASSERT_TRUE(CheckConflictsMatch(query, Conflicts(1, 3))); | |
| 189 } | |
| 190 | |
| 191 | |
| 192 TEST_F(CoalescedLiveRangesTest, QueryContainedInConflict) { | |
| 193 LiveRange* range = TestRangeBuilder(zone()).Id(1).Build(1, 5); | |
| 194 ranges().AllocateRange(range); | |
| 195 LiveRange* query = TestRangeBuilder(zone()).Id(2).Build(2, 3); | |
| 196 ASSERT_TRUE(CheckConflictsMatch(query, Conflicts(1, 1))); | |
| 197 } | |
| 198 | |
| 199 | |
| 200 TEST_F(CoalescedLiveRangesTest, QueryContainsConflict) { | |
| 201 LiveRange* range = TestRangeBuilder(zone()).Id(1).Build(2, 3); | |
| 202 ranges().AllocateRange(range); | |
| 203 LiveRange* query = TestRangeBuilder(zone()).Id(2).Build(1, 5); | |
| 204 ASSERT_TRUE(CheckConflictsMatch(query, Conflicts(1, 1))); | |
| 205 } | |
| 206 | |
| 207 | |
| 208 TEST_F(CoalescedLiveRangesTest, QueryCoversManyIntervalsSameRange) { | |
| 209 LiveRange* range = | |
| 210 TestRangeBuilder(zone()).Id(1).Add(1, 5).Add(7, 9).Add(20, 25).Build(); | |
| 211 ranges().AllocateRange(range); | |
| 212 LiveRange* query = TestRangeBuilder(zone()).Id(2).Build(2, 8); | |
| 213 ASSERT_TRUE(CheckConflictsMatch(query, Conflicts(1, 1))); | |
| 214 } | |
| 215 | |
| 216 | |
| 217 TEST_F(CoalescedLiveRangesTest, QueryCoversManyIntervalsDifferentRanges) { | |
| 218 LiveRange* range = | |
| 219 TestRangeBuilder(zone()).Id(1).Add(1, 5).Add(20, 25).Build(); | |
| 220 ranges().AllocateRange(range); | |
| 221 range = TestRangeBuilder(zone()).Id(2).Build(7, 10); | |
| 222 ranges().AllocateRange(range); | |
| 223 LiveRange* query = TestRangeBuilder(zone()).Id(3).Build(2, 22); | |
| 224 ASSERT_TRUE(CheckConflictsMatch(query, Conflicts(2, 1, 2))); | |
| 225 } | |
| 226 | |
| 227 | |
| 228 TEST_F(CoalescedLiveRangesTest, QueryFitsInGaps) { | |
| 229 LiveRange* range = | |
| 230 TestRangeBuilder(zone()).Id(1).Add(1, 5).Add(10, 15).Add(20, 25).Build(); | |
| 231 ranges().AllocateRange(range); | |
| 232 LiveRange* query = | |
| 233 TestRangeBuilder(zone()).Id(3).Add(5, 10).Add(16, 19).Add(27, 30).Build(); | |
| 234 ASSERT_TRUE(CheckConflictsMatch(query, Conflicts::None())); | |
| 235 } | |
| 236 | |
| 237 | |
| 238 TEST_F(CoalescedLiveRangesTest, DeleteConflictBefore) { | |
| 239 LiveRange* range = TestRangeBuilder(zone()).Id(1).Add(1, 4).Add(5, 6).Build(); | |
| 240 ranges().AllocateRange(range); | |
| 241 range = TestRangeBuilder(zone()).Id(2).Build(40, 50); | |
| 242 ranges().AllocateRange(range); | |
| 243 LiveRange* query = TestRangeBuilder(zone()).Id(3).Build(3, 7); | |
| 244 RemoveConflicts(query); | |
| 245 query = TestRangeBuilder(zone()).Id(4).Build(0, 60); | |
| 246 ASSERT_TRUE(CheckConflictsMatch(query, Conflicts(1, 2))); | |
| 247 } | |
| 248 | |
| 249 | |
| 250 TEST_F(CoalescedLiveRangesTest, DeleteConflictAfter) { | |
| 251 LiveRange* range = TestRangeBuilder(zone()).Id(1).Build(1, 5); | |
| 252 ranges().AllocateRange(range); | |
| 253 range = TestRangeBuilder(zone()).Id(2).Add(40, 50).Add(60, 70).Build(); | |
| 254 ranges().AllocateRange(range); | |
| 255 LiveRange* query = TestRangeBuilder(zone()).Id(3).Build(45, 60); | |
| 256 RemoveConflicts(query); | |
| 257 query = TestRangeBuilder(zone()).Id(4).Build(0, 60); | |
| 258 ASSERT_TRUE(CheckConflictsMatch(query, Conflicts(1, 1))); | |
| 259 } | |
| 260 | |
| 261 | |
| 262 TEST_F(CoalescedLiveRangesTest, DeleteConflictStraddle) { | |
| 263 LiveRange* range = | |
| 264 TestRangeBuilder(zone()).Id(1).Add(1, 5).Add(10, 20).Build(); | |
| 265 ranges().AllocateRange(range); | |
| 266 range = TestRangeBuilder(zone()).Id(2).Build(40, 50); | |
| 267 ranges().AllocateRange(range); | |
| 268 LiveRange* query = TestRangeBuilder(zone()).Id(3).Build(4, 15); | |
| 269 RemoveConflicts(query); | |
| 270 query = TestRangeBuilder(zone()).Id(4).Build(0, 60); | |
| 271 ASSERT_TRUE(CheckConflictsMatch(query, Conflicts(1, 2))); | |
| 272 } | |
| 273 | |
| 274 | |
| 275 TEST_F(CoalescedLiveRangesTest, DeleteConflictManyOverlapsBefore) { | |
| 276 LiveRange* range = | |
| 277 TestRangeBuilder(zone()).Id(1).Add(1, 5).Add(6, 10).Add(10, 20).Build(); | |
| 278 ranges().AllocateRange(range); | |
| 279 range = TestRangeBuilder(zone()).Id(2).Build(40, 50); | |
| 280 ranges().AllocateRange(range); | |
| 281 LiveRange* query = TestRangeBuilder(zone()).Id(3).Build(4, 15); | |
| 282 RemoveConflicts(query); | |
| 283 query = TestRangeBuilder(zone()).Id(4).Build(0, 60); | |
| 284 ASSERT_TRUE(CheckConflictsMatch(query, Conflicts(1, 2))); | |
| 285 } | |
| 286 | |
| 287 | |
| 288 } // namespace compiler | |
| 289 } // namespace internal | |
| 290 } // namespace v8 | |
| OLD | NEW |