| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/base/adapters.h" | 5 #include "src/base/adapters.h" |
| 6 #include "src/compiler/linkage.h" | 6 #include "src/compiler/linkage.h" |
| 7 #include "src/compiler/register-allocator.h" | 7 #include "src/compiler/register-allocator.h" |
| 8 #include "src/string-stream.h" | 8 #include "src/string-stream.h" |
| 9 | 9 |
| 10 namespace v8 { | 10 namespace v8 { |
| 11 namespace internal { | 11 namespace internal { |
| 12 namespace compiler { | 12 namespace compiler { |
| 13 | 13 |
| 14 #define TRACE(...) \ | 14 #define TRACE(...) \ |
| 15 do { \ | 15 do { \ |
| 16 if (FLAG_trace_alloc) PrintF(__VA_ARGS__); \ | 16 if (FLAG_trace_alloc) PrintF(__VA_ARGS__); \ |
| 17 } while (false) | 17 } while (false) |
| 18 | 18 |
| 19 | |
| 20 namespace { | 19 namespace { |
| 21 | 20 |
| 22 inline LifetimePosition Min(LifetimePosition a, LifetimePosition b) { | 21 inline LifetimePosition Min(LifetimePosition a, LifetimePosition b) { |
| 23 return a.Value() < b.Value() ? a : b; | 22 return a.Value() < b.Value() ? a : b; |
| 24 } | 23 } |
| 25 | 24 |
| 26 | 25 |
| 27 inline LifetimePosition Max(LifetimePosition a, LifetimePosition b) { | 26 inline LifetimePosition Max(LifetimePosition a, LifetimePosition b) { |
| 28 return a.Value() > b.Value() ? a : b; | 27 return a.Value() > b.Value() ? a : b; |
| 29 } | 28 } |
| (...skipping 1428 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1458 } | 1457 } |
| 1459 | 1458 |
| 1460 | 1459 |
| 1461 void LiveRangeBuilder::Verify() const { | 1460 void LiveRangeBuilder::Verify() const { |
| 1462 for (auto current : data()->live_ranges()) { | 1461 for (auto current : data()->live_ranges()) { |
| 1463 if (current != nullptr) current->Verify(); | 1462 if (current != nullptr) current->Verify(); |
| 1464 } | 1463 } |
| 1465 } | 1464 } |
| 1466 | 1465 |
| 1467 | 1466 |
| 1468 RegisterAllocator::RegisterAllocator(RegisterAllocationData* data, | 1467 RegisterAllocator::RegisterAllocator(RegisterAllocationData* data) |
| 1469 RegisterKind kind) | 1468 : data_(data) {} |
| 1470 : data_(data), | |
| 1471 mode_(kind), | |
| 1472 num_registers_(GetRegisterCount(data->config(), kind)) {} | |
| 1473 | 1469 |
| 1474 | 1470 |
| 1475 LiveRange* RegisterAllocator::SplitRangeAt(LiveRange* range, | 1471 LiveRange* RegisterAllocator::SplitRangeAt(LiveRange* range, |
| 1476 LifetimePosition pos) { | 1472 LifetimePosition pos) { |
| 1477 DCHECK(!range->IsFixed()); | 1473 DCHECK(!range->IsFixed()); |
| 1478 TRACE("Splitting live range %d at %d\n", range->id(), pos.Value()); | 1474 TRACE("Splitting live range %d at %d\n", range->id(), pos.Value()); |
| 1479 | 1475 |
| 1480 if (pos.Value() <= range->Start().Value()) return range; | 1476 if (pos.Value() <= range->Start().Value()) return range; |
| 1481 | 1477 |
| 1482 // We can't properly connect liveranges if splitting occurred at the end | 1478 // We can't properly connect liveranges if splitting occurred at the end |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1579 auto first = range->TopLevel(); | 1575 auto first = range->TopLevel(); |
| 1580 if (first->HasNoSpillType()) { | 1576 if (first->HasNoSpillType()) { |
| 1581 data()->AssignSpillRangeToLiveRange(first); | 1577 data()->AssignSpillRangeToLiveRange(first); |
| 1582 } | 1578 } |
| 1583 range->MakeSpilled(); | 1579 range->MakeSpilled(); |
| 1584 } | 1580 } |
| 1585 | 1581 |
| 1586 | 1582 |
| 1587 LinearScanAllocator::LinearScanAllocator(RegisterAllocationData* data, | 1583 LinearScanAllocator::LinearScanAllocator(RegisterAllocationData* data, |
| 1588 RegisterKind kind, Zone* local_zone) | 1584 RegisterKind kind, Zone* local_zone) |
| 1589 : RegisterAllocator(data, kind), | 1585 : RegisterAllocator(data), |
| 1586 mode_(kind), |
| 1587 num_registers_(GetRegisterCount(data->config(), kind)), |
| 1590 unhandled_live_ranges_(local_zone), | 1588 unhandled_live_ranges_(local_zone), |
| 1591 active_live_ranges_(local_zone), | 1589 active_live_ranges_(local_zone), |
| 1592 inactive_live_ranges_(local_zone) { | 1590 inactive_live_ranges_(local_zone) { |
| 1593 unhandled_live_ranges().reserve( | 1591 unhandled_live_ranges().reserve( |
| 1594 static_cast<size_t>(code()->VirtualRegisterCount() * 2)); | 1592 static_cast<size_t>(code()->VirtualRegisterCount() * 2)); |
| 1595 active_live_ranges().reserve(8); | 1593 active_live_ranges().reserve(8); |
| 1596 inactive_live_ranges().reserve(8); | 1594 inactive_live_ranges().reserve(8); |
| 1597 // TryAllocateFreeReg and AllocateBlockedReg assume this | 1595 // TryAllocateFreeReg and AllocateBlockedReg assume this |
| 1598 // when allocating local arrays. | 1596 // when allocating local arrays. |
| 1599 DCHECK(RegisterConfiguration::kMaxDoubleRegisters >= | 1597 DCHECK(RegisterConfiguration::kMaxDoubleRegisters >= |
| 1600 this->data()->config()->num_general_registers()); | 1598 this->data()->config()->num_general_registers()); |
| 1601 } | 1599 } |
| 1602 | 1600 |
| 1603 | 1601 |
| 1604 void LinearScanAllocator::AllocateRegisters() { | 1602 void LinearScanAllocator::AllocateRegisters() { |
| 1605 DCHECK(unhandled_live_ranges().empty()); | 1603 DCHECK(unhandled_live_ranges().empty()); |
| 1606 DCHECK(active_live_ranges().empty()); | 1604 DCHECK(active_live_ranges().empty()); |
| 1607 DCHECK(inactive_live_ranges().empty()); | 1605 DCHECK(inactive_live_ranges().empty()); |
| 1608 | 1606 |
| 1609 for (auto range : data()->live_ranges()) { | 1607 for (auto range : data()->live_ranges()) { |
| 1610 if (range == nullptr) continue; | 1608 if (range == nullptr) continue; |
| 1611 if (range->Kind() == mode()) { | 1609 if (range->Kind() == mode_) { |
| 1612 AddToUnhandledUnsorted(range); | 1610 AddToUnhandledUnsorted(range); |
| 1613 } | 1611 } |
| 1614 } | 1612 } |
| 1615 SortUnhandled(); | 1613 SortUnhandled(); |
| 1616 DCHECK(UnhandledIsSorted()); | 1614 DCHECK(UnhandledIsSorted()); |
| 1617 | 1615 |
| 1618 auto& fixed_ranges = GetFixedRegisters(data(), mode()); | 1616 auto& fixed_ranges = GetFixedRegisters(data(), mode_); |
| 1619 for (auto current : fixed_ranges) { | 1617 for (auto current : fixed_ranges) { |
| 1620 if (current != nullptr) { | 1618 if (current != nullptr) { |
| 1621 DCHECK_EQ(mode(), current->Kind()); | 1619 DCHECK_EQ(mode_, current->Kind()); |
| 1622 AddToInactive(current); | 1620 AddToInactive(current); |
| 1623 } | 1621 } |
| 1624 } | 1622 } |
| 1625 | 1623 |
| 1626 while (!unhandled_live_ranges().empty()) { | 1624 while (!unhandled_live_ranges().empty()) { |
| 1627 DCHECK(UnhandledIsSorted()); | 1625 DCHECK(UnhandledIsSorted()); |
| 1628 auto current = unhandled_live_ranges().back(); | 1626 auto current = unhandled_live_ranges().back(); |
| 1629 unhandled_live_ranges().pop_back(); | 1627 unhandled_live_ranges().pop_back(); |
| 1630 DCHECK(UnhandledIsSorted()); | 1628 DCHECK(UnhandledIsSorted()); |
| 1631 auto position = current->Start(); | 1629 auto position = current->Start(); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1684 bool result = TryAllocateFreeReg(current); | 1682 bool result = TryAllocateFreeReg(current); |
| 1685 if (!result) AllocateBlockedReg(current); | 1683 if (!result) AllocateBlockedReg(current); |
| 1686 if (current->HasRegisterAssigned()) { | 1684 if (current->HasRegisterAssigned()) { |
| 1687 AddToActive(current); | 1685 AddToActive(current); |
| 1688 } | 1686 } |
| 1689 } | 1687 } |
| 1690 } | 1688 } |
| 1691 | 1689 |
| 1692 | 1690 |
| 1693 const char* LinearScanAllocator::RegisterName(int allocation_index) const { | 1691 const char* LinearScanAllocator::RegisterName(int allocation_index) const { |
| 1694 if (mode() == GENERAL_REGISTERS) { | 1692 if (mode_ == GENERAL_REGISTERS) { |
| 1695 return data()->config()->general_register_name(allocation_index); | 1693 return data()->config()->general_register_name(allocation_index); |
| 1696 } else { | 1694 } else { |
| 1697 return data()->config()->double_register_name(allocation_index); | 1695 return data()->config()->double_register_name(allocation_index); |
| 1698 } | 1696 } |
| 1699 } | 1697 } |
| 1700 | 1698 |
| 1701 | 1699 |
| 1702 void LinearScanAllocator::AddToActive(LiveRange* range) { | 1700 void LinearScanAllocator::AddToActive(LiveRange* range) { |
| 1703 TRACE("Add live range %d to active\n", range->id()); | 1701 TRACE("Add live range %d to active\n", range->id()); |
| 1704 active_live_ranges().push_back(range); | 1702 active_live_ranges().push_back(range); |
| (...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2114 Spill(second_part); | 2112 Spill(second_part); |
| 2115 AddToUnhandledSorted(third_part); | 2113 AddToUnhandledSorted(third_part); |
| 2116 } else { | 2114 } else { |
| 2117 // The split result does not intersect with [start, end[. | 2115 // The split result does not intersect with [start, end[. |
| 2118 // Nothing to spill. Just put it to unhandled as whole. | 2116 // Nothing to spill. Just put it to unhandled as whole. |
| 2119 AddToUnhandledSorted(second_part); | 2117 AddToUnhandledSorted(second_part); |
| 2120 } | 2118 } |
| 2121 } | 2119 } |
| 2122 | 2120 |
| 2123 | 2121 |
| 2124 class CoallescedLiveRanges : public ZoneObject { | |
| 2125 public: | |
| 2126 explicit CoallescedLiveRanges(Zone* zone) : storage_(zone) {} | |
| 2127 | |
| 2128 LiveRange* Find(UseInterval* query) { | |
| 2129 ZoneSplayTree<Config>::Locator locator; | |
| 2130 | |
| 2131 if (storage_.Find(GetKey(query), &locator)) { | |
| 2132 return locator.value(); | |
| 2133 } | |
| 2134 return nullptr; | |
| 2135 } | |
| 2136 | |
| 2137 // TODO(mtrofin): Change to void returning if we do not care if the interval | |
| 2138 // was previously added. | |
| 2139 bool Insert(LiveRange* range) { | |
| 2140 auto* interval = range->first_interval(); | |
| 2141 while (interval != nullptr) { | |
| 2142 if (!Insert(interval, range)) return false; | |
| 2143 interval = interval->next(); | |
| 2144 } | |
| 2145 return true; | |
| 2146 } | |
| 2147 | |
| 2148 bool Remove(LiveRange* range) { | |
| 2149 bool ret = false; | |
| 2150 auto* segment = range->first_interval(); | |
| 2151 while (segment != nullptr) { | |
| 2152 ret |= Remove(segment); | |
| 2153 segment = segment->next(); | |
| 2154 } | |
| 2155 return ret; | |
| 2156 } | |
| 2157 | |
| 2158 bool IsEmpty() { return storage_.is_empty(); } | |
| 2159 | |
| 2160 private: | |
| 2161 struct Config { | |
| 2162 typedef std::pair<int, int> Key; | |
| 2163 typedef LiveRange* Value; | |
| 2164 static const Key kNoKey; | |
| 2165 static Value NoValue() { return nullptr; } | |
| 2166 static int Compare(const Key& a, const Key& b) { | |
| 2167 if (a.second <= b.first) return -1; | |
| 2168 if (a.first >= b.second) return 1; | |
| 2169 return 0; | |
| 2170 } | |
| 2171 }; | |
| 2172 | |
| 2173 Config::Key GetKey(UseInterval* interval) { | |
| 2174 if (interval == nullptr) return std::make_pair(0, 0); | |
| 2175 return std::make_pair(interval->start().Value(), interval->end().Value()); | |
| 2176 } | |
| 2177 | |
| 2178 // TODO(mtrofin): Change to void returning if we do not care if the interval | |
| 2179 // was previously added. | |
| 2180 bool Insert(UseInterval* interval, LiveRange* range) { | |
| 2181 ZoneSplayTree<Config>::Locator locator; | |
| 2182 bool ret = storage_.Insert(GetKey(interval), &locator); | |
| 2183 if (ret) locator.set_value(range); | |
| 2184 return ret; | |
| 2185 } | |
| 2186 | |
| 2187 bool Remove(UseInterval* key) { return storage_.Remove(GetKey(key)); } | |
| 2188 | |
| 2189 ZoneSplayTree<Config> storage_; | |
| 2190 DISALLOW_COPY_AND_ASSIGN(CoallescedLiveRanges); | |
| 2191 }; | |
| 2192 | |
| 2193 | |
| 2194 const std::pair<int, int> CoallescedLiveRanges::Config::kNoKey = | |
| 2195 std::make_pair<int, int>(0, 0); | |
| 2196 | |
| 2197 | |
| 2198 GreedyAllocator::GreedyAllocator(RegisterAllocationData* data, | |
| 2199 RegisterKind kind, Zone* local_zone) | |
| 2200 : RegisterAllocator(data, kind), | |
| 2201 allocations_(local_zone), | |
| 2202 queue_(local_zone) {} | |
| 2203 | |
| 2204 | |
| 2205 unsigned GreedyAllocator::GetLiveRangeSize(LiveRange* range) { | |
| 2206 auto interval = range->first_interval(); | |
| 2207 if (interval == nullptr) return 0; | |
| 2208 | |
| 2209 unsigned size = 0; | |
| 2210 while (interval != nullptr) { | |
| 2211 size += (interval->end().Value() - interval->start().Value()); | |
| 2212 interval = interval->next(); | |
| 2213 } | |
| 2214 | |
| 2215 return size; | |
| 2216 } | |
| 2217 | |
| 2218 | |
| 2219 void GreedyAllocator::AssignRangeToRegister(int reg_id, LiveRange* range) { | |
| 2220 allocations_[reg_id]->Insert(range); | |
| 2221 if (range->HasRegisterAssigned()) { | |
| 2222 DCHECK_EQ(reg_id, range->assigned_register()); | |
| 2223 return; | |
| 2224 } | |
| 2225 range->set_assigned_register(reg_id); | |
| 2226 } | |
| 2227 | |
| 2228 | |
| 2229 float GreedyAllocator::CalculateSpillWeight(LiveRange* range) { | |
| 2230 if (range->IsFixed()) return std::numeric_limits<float>::max(); | |
| 2231 | |
| 2232 if (range->FirstHint() != nullptr && range->FirstHint()->IsRegister()) { | |
| 2233 return std::numeric_limits<float>::max(); | |
| 2234 } | |
| 2235 | |
| 2236 unsigned use_count = 0; | |
| 2237 auto* pos = range->first_pos(); | |
| 2238 while (pos != nullptr) { | |
| 2239 use_count++; | |
| 2240 pos = pos->next(); | |
| 2241 } | |
| 2242 | |
| 2243 // GetLiveRangeSize is DCHECK-ed to not be 0 | |
| 2244 unsigned range_size = GetLiveRangeSize(range); | |
| 2245 DCHECK_NE(0, range_size); | |
| 2246 | |
| 2247 return static_cast<float>(use_count) / static_cast<float>(range_size); | |
| 2248 } | |
| 2249 | |
| 2250 | |
| 2251 float GreedyAllocator::CalculateMaxSpillWeight( | |
| 2252 const ZoneSet<LiveRange*>& ranges) { | |
| 2253 float max = 0.0; | |
| 2254 for (auto* r : ranges) { | |
| 2255 max = std::max(max, CalculateSpillWeight(r)); | |
| 2256 } | |
| 2257 return max; | |
| 2258 } | |
| 2259 | |
| 2260 | |
| 2261 void GreedyAllocator::Evict(LiveRange* range) { | |
| 2262 bool removed = allocations_[range->assigned_register()]->Remove(range); | |
| 2263 CHECK(removed); | |
| 2264 } | |
| 2265 | |
| 2266 | |
| 2267 bool GreedyAllocator::TryAllocatePhysicalRegister( | |
| 2268 unsigned reg_id, LiveRange* range, ZoneSet<LiveRange*>* conflicting) { | |
| 2269 auto* segment = range->first_interval(); | |
| 2270 | |
| 2271 auto* alloc_info = allocations_[reg_id]; | |
| 2272 while (segment != nullptr) { | |
| 2273 if (auto* existing = alloc_info->Find(segment)) { | |
| 2274 DCHECK(existing->HasRegisterAssigned()); | |
| 2275 conflicting->insert(existing); | |
| 2276 } | |
| 2277 segment = segment->next(); | |
| 2278 } | |
| 2279 if (!conflicting->empty()) return false; | |
| 2280 // No conflicts means we can safely allocate this register to this range. | |
| 2281 AssignRangeToRegister(reg_id, range); | |
| 2282 return true; | |
| 2283 } | |
| 2284 | |
| 2285 bool GreedyAllocator::TryAllocate(LiveRange* current, | |
| 2286 ZoneSet<LiveRange*>* conflicting) { | |
| 2287 if (current->HasSpillOperand()) { | |
| 2288 Spill(current); | |
| 2289 return true; | |
| 2290 } | |
| 2291 if (current->IsFixed()) { | |
| 2292 return TryAllocatePhysicalRegister(current->assigned_register(), current, | |
| 2293 conflicting); | |
| 2294 } | |
| 2295 | |
| 2296 if (current->HasRegisterAssigned()) { | |
| 2297 int reg_id = current->assigned_register(); | |
| 2298 return TryAllocatePhysicalRegister(reg_id, current, conflicting); | |
| 2299 } | |
| 2300 | |
| 2301 for (unsigned candidate_reg = 0; candidate_reg < allocations_.size(); | |
| 2302 candidate_reg++) { | |
| 2303 if (TryAllocatePhysicalRegister(candidate_reg, current, conflicting)) { | |
| 2304 conflicting->clear(); | |
| 2305 return true; | |
| 2306 } | |
| 2307 } | |
| 2308 return false; | |
| 2309 } | |
| 2310 | |
| 2311 LiveRange* GreedyAllocator::SpillBetweenUntil(LiveRange* range, | |
| 2312 LifetimePosition start, | |
| 2313 LifetimePosition until, | |
| 2314 LifetimePosition end) { | |
| 2315 CHECK(start.Value() < end.Value()); | |
| 2316 auto second_part = SplitRangeAt(range, start); | |
| 2317 | |
| 2318 if (second_part->Start().Value() < end.Value()) { | |
| 2319 // The split result intersects with [start, end[. | |
| 2320 // Split it at position between ]start+1, end[, spill the middle part | |
| 2321 // and put the rest to unhandled. | |
| 2322 auto third_part_end = end.PrevStart().End(); | |
| 2323 if (IsBlockBoundary(code(), end.Start())) { | |
| 2324 third_part_end = end.Start(); | |
| 2325 } | |
| 2326 auto third_part = SplitBetween( | |
| 2327 second_part, Max(second_part->Start().End(), until), third_part_end); | |
| 2328 | |
| 2329 DCHECK(third_part != second_part); | |
| 2330 | |
| 2331 Spill(second_part); | |
| 2332 return third_part; | |
| 2333 } else { | |
| 2334 // The split result does not intersect with [start, end[. | |
| 2335 // Nothing to spill. Just return it for re-processing. | |
| 2336 return second_part; | |
| 2337 } | |
| 2338 } | |
| 2339 | |
| 2340 | |
| 2341 void GreedyAllocator::Enqueue(LiveRange* range) { | |
| 2342 if (range == nullptr || range->IsEmpty()) return; | |
| 2343 unsigned size = GetLiveRangeSize(range); | |
| 2344 queue_.push(std::make_pair(size, range)); | |
| 2345 } | |
| 2346 | |
| 2347 | |
| 2348 // TODO(mtrofin): consolidate with identical code segment in | |
| 2349 // LinearScanAllocator::AllocateRegisters | |
| 2350 bool GreedyAllocator::HandleSpillOperands(LiveRange* range) { | |
| 2351 auto position = range->Start(); | |
| 2352 TRACE("Processing interval %d start=%d\n", range->id(), position.Value()); | |
| 2353 | |
| 2354 if (!range->HasNoSpillType()) { | |
| 2355 TRACE("Live range %d already has a spill operand\n", range->id()); | |
| 2356 auto next_pos = position; | |
| 2357 if (next_pos.IsGapPosition()) { | |
| 2358 next_pos = next_pos.NextStart(); | |
| 2359 } | |
| 2360 auto pos = range->NextUsePositionRegisterIsBeneficial(next_pos); | |
| 2361 // If the range already has a spill operand and it doesn't need a | |
| 2362 // register immediately, split it and spill the first part of the range. | |
| 2363 if (pos == nullptr) { | |
| 2364 Spill(range); | |
| 2365 return true; | |
| 2366 } else if (pos->pos().Value() > range->Start().NextStart().Value()) { | |
| 2367 // Do not spill live range eagerly if use position that can benefit from | |
| 2368 // the register is too close to the start of live range. | |
| 2369 auto* reminder = SpillBetweenUntil(range, position, position, pos->pos()); | |
| 2370 Enqueue(reminder); | |
| 2371 return true; | |
| 2372 } | |
| 2373 } | |
| 2374 return false; | |
| 2375 // TODO(mtrofin): Do we need this? | |
| 2376 // return (TryReuseSpillForPhi(range)); | |
| 2377 } | |
| 2378 | |
| 2379 | |
| 2380 void GreedyAllocator::AllocateRegisters() { | |
| 2381 for (auto range : data()->live_ranges()) { | |
| 2382 if (range == nullptr) continue; | |
| 2383 if (range->Kind() == mode()) { | |
| 2384 DCHECK(!range->HasRegisterAssigned() && !range->IsSpilled()); | |
| 2385 TRACE("Enqueueing live range %d to priority queue \n", range->id()); | |
| 2386 Enqueue(range); | |
| 2387 } | |
| 2388 } | |
| 2389 | |
| 2390 allocations_.resize(num_registers()); | |
| 2391 auto* zone = data()->allocation_zone(); | |
| 2392 for (int i = 0; i < num_registers(); i++) { | |
| 2393 allocations_[i] = new (zone) CoallescedLiveRanges(zone); | |
| 2394 } | |
| 2395 | |
| 2396 for (auto* current : GetFixedRegisters(data(), mode())) { | |
| 2397 if (current != nullptr) { | |
| 2398 DCHECK_EQ(mode(), current->Kind()); | |
| 2399 int reg_nr = current->assigned_register(); | |
| 2400 bool inserted = allocations_[reg_nr]->Insert(current); | |
| 2401 CHECK(inserted); | |
| 2402 } | |
| 2403 } | |
| 2404 | |
| 2405 while (!queue_.empty()) { | |
| 2406 auto current_pair = queue_.top(); | |
| 2407 queue_.pop(); | |
| 2408 auto current = current_pair.second; | |
| 2409 if (HandleSpillOperands(current)) continue; | |
| 2410 ZoneSet<LiveRange*> conflicting(zone); | |
| 2411 if (!TryAllocate(current, &conflicting)) { | |
| 2412 DCHECK(!conflicting.empty()); | |
| 2413 float this_max = CalculateSpillWeight(current); | |
| 2414 float max_conflicting = CalculateMaxSpillWeight(conflicting); | |
| 2415 if (max_conflicting < this_max) { | |
| 2416 for (auto* conflict : conflicting) { | |
| 2417 Evict(conflict); | |
| 2418 Enqueue(conflict); | |
| 2419 } | |
| 2420 conflicting.clear(); | |
| 2421 bool allocated = TryAllocate(current, &conflicting); | |
| 2422 CHECK(allocated); | |
| 2423 DCHECK(conflicting.empty()); | |
| 2424 } else { | |
| 2425 DCHECK(!current->IsFixed() || current->CanBeSpilled(current->Start())); | |
| 2426 bool allocated = AllocateBlockedRange(current, conflicting); | |
| 2427 CHECK(allocated); | |
| 2428 } | |
| 2429 } | |
| 2430 } | |
| 2431 | |
| 2432 BitVector* assigned_registers = new (zone) BitVector(num_registers(), zone); | |
| 2433 for (size_t i = 0; i < allocations_.size(); ++i) { | |
| 2434 if (!allocations_[i]->IsEmpty()) { | |
| 2435 assigned_registers->Add(static_cast<int>(i)); | |
| 2436 } | |
| 2437 } | |
| 2438 data()->frame()->SetAllocatedRegisters(assigned_registers); | |
| 2439 } | |
| 2440 | |
| 2441 | |
| 2442 bool GreedyAllocator::AllocateBlockedRange( | |
| 2443 LiveRange* current, const ZoneSet<LiveRange*>& conflicts) { | |
| 2444 auto register_use = current->NextRegisterPosition(current->Start()); | |
| 2445 if (register_use == nullptr) { | |
| 2446 // There is no use in the current live range that requires a register. | |
| 2447 // We can just spill it. | |
| 2448 Spill(current); | |
| 2449 return true; | |
| 2450 } | |
| 2451 | |
| 2452 auto second_part = SplitRangeAt(current, register_use->pos()); | |
| 2453 Spill(second_part); | |
| 2454 | |
| 2455 return true; | |
| 2456 } | |
| 2457 | |
| 2458 | |
| 2459 OperandAssigner::OperandAssigner(RegisterAllocationData* data) : data_(data) {} | 2122 OperandAssigner::OperandAssigner(RegisterAllocationData* data) : data_(data) {} |
| 2460 | 2123 |
| 2461 | 2124 |
| 2462 void OperandAssigner::AssignSpillSlots() { | 2125 void OperandAssigner::AssignSpillSlots() { |
| 2463 auto& spill_ranges = data()->spill_ranges(); | 2126 auto& spill_ranges = data()->spill_ranges(); |
| 2464 // Merge disjoint spill ranges | 2127 // Merge disjoint spill ranges |
| 2465 for (size_t i = 0; i < spill_ranges.size(); i++) { | 2128 for (size_t i = 0; i < spill_ranges.size(); i++) { |
| 2466 auto range = spill_ranges[i]; | 2129 auto range = spill_ranges[i]; |
| 2467 if (range->IsEmpty()) continue; | 2130 if (range->IsEmpty()) continue; |
| 2468 for (size_t j = i + 1; j < spill_ranges.size(); j++) { | 2131 for (size_t j = i + 1; j < spill_ranges.size(); j++) { |
| (...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2862 moves = it->first.first; | 2525 moves = it->first.first; |
| 2863 } | 2526 } |
| 2864 // Gather all MoveOperands for a single ParallelMove. | 2527 // Gather all MoveOperands for a single ParallelMove. |
| 2865 auto move = new (code_zone()) MoveOperands(it->first.second, it->second); | 2528 auto move = new (code_zone()) MoveOperands(it->first.second, it->second); |
| 2866 auto eliminate = moves->PrepareInsertAfter(move); | 2529 auto eliminate = moves->PrepareInsertAfter(move); |
| 2867 to_insert.push_back(move); | 2530 to_insert.push_back(move); |
| 2868 if (eliminate != nullptr) to_eliminate.push_back(eliminate); | 2531 if (eliminate != nullptr) to_eliminate.push_back(eliminate); |
| 2869 } | 2532 } |
| 2870 } | 2533 } |
| 2871 | 2534 |
| 2872 | |
| 2873 } // namespace compiler | 2535 } // namespace compiler |
| 2874 } // namespace internal | 2536 } // namespace internal |
| 2875 } // namespace v8 | 2537 } // namespace v8 |
| OLD | NEW |