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/compiler/linkage.h" | 5 #include "src/compiler/linkage.h" |
6 #include "src/compiler/register-allocator.h" | 6 #include "src/compiler/register-allocator.h" |
7 #include "src/string-stream.h" | 7 #include "src/string-stream.h" |
8 | 8 |
9 namespace v8 { | 9 namespace v8 { |
10 namespace internal { | 10 namespace internal { |
11 namespace compiler { | 11 namespace compiler { |
12 | 12 |
| 13 #define TRACE(...) \ |
| 14 do { \ |
| 15 if (FLAG_trace_alloc) PrintF(__VA_ARGS__); \ |
| 16 } while (false) |
| 17 |
13 static inline LifetimePosition Min(LifetimePosition a, LifetimePosition b) { | 18 static inline LifetimePosition Min(LifetimePosition a, LifetimePosition b) { |
14 return a.Value() < b.Value() ? a : b; | 19 return a.Value() < b.Value() ? a : b; |
15 } | 20 } |
16 | 21 |
17 | 22 |
18 static inline LifetimePosition Max(LifetimePosition a, LifetimePosition b) { | 23 static inline LifetimePosition Max(LifetimePosition a, LifetimePosition b) { |
19 return a.Value() > b.Value() ? a : b; | 24 return a.Value() > b.Value() ? a : b; |
20 } | 25 } |
21 | 26 |
22 | 27 |
23 static void TraceAlloc(const char* msg, ...) { | |
24 if (FLAG_trace_alloc) { | |
25 va_list arguments; | |
26 va_start(arguments, msg); | |
27 base::OS::VPrint(msg, arguments); | |
28 va_end(arguments); | |
29 } | |
30 } | |
31 | |
32 | |
33 static void RemoveElement(ZoneVector<LiveRange*>* v, LiveRange* range) { | 28 static void RemoveElement(ZoneVector<LiveRange*>* v, LiveRange* range) { |
34 auto it = std::find(v->begin(), v->end(), range); | 29 auto it = std::find(v->begin(), v->end(), range); |
35 DCHECK(it != v->end()); | 30 DCHECK(it != v->end()); |
36 v->erase(it); | 31 v->erase(it); |
37 } | 32 } |
38 | 33 |
39 | 34 |
40 UsePosition::UsePosition(LifetimePosition pos, InstructionOperand* operand, | 35 UsePosition::UsePosition(LifetimePosition pos, InstructionOperand* operand, |
41 InstructionOperand* hint) | 36 InstructionOperand* hint) |
42 : operand_(operand), hint_(hint), pos_(pos), next_(nullptr), flags_(0) { | 37 : operand_(operand), hint_(hint), pos_(pos), next_(nullptr), flags_(0) { |
(...skipping 397 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
440 if (pos == nullptr) return false; | 435 if (pos == nullptr) return false; |
441 UsePosition* other_pos = other->first_pos(); | 436 UsePosition* other_pos = other->first_pos(); |
442 if (other_pos == nullptr) return true; | 437 if (other_pos == nullptr) return true; |
443 return pos->pos().Value() < other_pos->pos().Value(); | 438 return pos->pos().Value() < other_pos->pos().Value(); |
444 } | 439 } |
445 return start.Value() < other_start.Value(); | 440 return start.Value() < other_start.Value(); |
446 } | 441 } |
447 | 442 |
448 | 443 |
449 void LiveRange::ShortenTo(LifetimePosition start) { | 444 void LiveRange::ShortenTo(LifetimePosition start) { |
450 TraceAlloc("Shorten live range %d to [%d\n", id_, start.Value()); | 445 TRACE("Shorten live range %d to [%d\n", id_, start.Value()); |
451 DCHECK(first_interval_ != nullptr); | 446 DCHECK(first_interval_ != nullptr); |
452 DCHECK(first_interval_->start().Value() <= start.Value()); | 447 DCHECK(first_interval_->start().Value() <= start.Value()); |
453 DCHECK(start.Value() < first_interval_->end().Value()); | 448 DCHECK(start.Value() < first_interval_->end().Value()); |
454 first_interval_->set_start(start); | 449 first_interval_->set_start(start); |
455 } | 450 } |
456 | 451 |
457 | 452 |
458 void LiveRange::EnsureInterval(LifetimePosition start, LifetimePosition end, | 453 void LiveRange::EnsureInterval(LifetimePosition start, LifetimePosition end, |
459 Zone* zone) { | 454 Zone* zone) { |
460 TraceAlloc("Ensure live range %d in interval [%d %d[\n", id_, start.Value(), | 455 TRACE("Ensure live range %d in interval [%d %d[\n", id_, start.Value(), |
461 end.Value()); | 456 end.Value()); |
462 auto new_end = end; | 457 auto new_end = end; |
463 while (first_interval_ != nullptr && | 458 while (first_interval_ != nullptr && |
464 first_interval_->start().Value() <= end.Value()) { | 459 first_interval_->start().Value() <= end.Value()) { |
465 if (first_interval_->end().Value() > end.Value()) { | 460 if (first_interval_->end().Value() > end.Value()) { |
466 new_end = first_interval_->end(); | 461 new_end = first_interval_->end(); |
467 } | 462 } |
468 first_interval_ = first_interval_->next(); | 463 first_interval_ = first_interval_->next(); |
469 } | 464 } |
470 | 465 |
471 auto new_interval = new (zone) UseInterval(start, new_end); | 466 auto new_interval = new (zone) UseInterval(start, new_end); |
472 new_interval->next_ = first_interval_; | 467 new_interval->next_ = first_interval_; |
473 first_interval_ = new_interval; | 468 first_interval_ = new_interval; |
474 if (new_interval->next() == nullptr) { | 469 if (new_interval->next() == nullptr) { |
475 last_interval_ = new_interval; | 470 last_interval_ = new_interval; |
476 } | 471 } |
477 } | 472 } |
478 | 473 |
479 | 474 |
480 void LiveRange::AddUseInterval(LifetimePosition start, LifetimePosition end, | 475 void LiveRange::AddUseInterval(LifetimePosition start, LifetimePosition end, |
481 Zone* zone) { | 476 Zone* zone) { |
482 TraceAlloc("Add to live range %d interval [%d %d[\n", id_, start.Value(), | 477 TRACE("Add to live range %d interval [%d %d[\n", id_, start.Value(), |
483 end.Value()); | 478 end.Value()); |
484 if (first_interval_ == nullptr) { | 479 if (first_interval_ == nullptr) { |
485 auto interval = new (zone) UseInterval(start, end); | 480 auto interval = new (zone) UseInterval(start, end); |
486 first_interval_ = interval; | 481 first_interval_ = interval; |
487 last_interval_ = interval; | 482 last_interval_ = interval; |
488 } else { | 483 } else { |
489 if (end.Value() == first_interval_->start().Value()) { | 484 if (end.Value() == first_interval_->start().Value()) { |
490 first_interval_->set_start(start); | 485 first_interval_->set_start(start); |
491 } else if (end.Value() < first_interval_->start().Value()) { | 486 } else if (end.Value() < first_interval_->start().Value()) { |
492 auto interval = new (zone) UseInterval(start, end); | 487 auto interval = new (zone) UseInterval(start, end); |
493 interval->set_next(first_interval_); | 488 interval->set_next(first_interval_); |
494 first_interval_ = interval; | 489 first_interval_ = interval; |
495 } else { | 490 } else { |
496 // Order of instruction's processing (see ProcessInstructions) guarantees | 491 // Order of instruction's processing (see ProcessInstructions) guarantees |
497 // that each new use interval either precedes or intersects with | 492 // that each new use interval either precedes or intersects with |
498 // last added interval. | 493 // last added interval. |
499 DCHECK(start.Value() < first_interval_->end().Value()); | 494 DCHECK(start.Value() < first_interval_->end().Value()); |
500 first_interval_->start_ = Min(start, first_interval_->start_); | 495 first_interval_->start_ = Min(start, first_interval_->start_); |
501 first_interval_->end_ = Max(end, first_interval_->end_); | 496 first_interval_->end_ = Max(end, first_interval_->end_); |
502 } | 497 } |
503 } | 498 } |
504 } | 499 } |
505 | 500 |
506 | 501 |
507 void LiveRange::AddUsePosition(LifetimePosition pos, | 502 void LiveRange::AddUsePosition(LifetimePosition pos, |
508 InstructionOperand* operand, | 503 InstructionOperand* operand, |
509 InstructionOperand* hint, Zone* zone) { | 504 InstructionOperand* hint, Zone* zone) { |
510 TraceAlloc("Add to live range %d use position %d\n", id_, pos.Value()); | 505 TRACE("Add to live range %d use position %d\n", id_, pos.Value()); |
511 auto use_pos = new (zone) UsePosition(pos, operand, hint); | 506 auto use_pos = new (zone) UsePosition(pos, operand, hint); |
512 UsePosition* prev_hint = nullptr; | 507 UsePosition* prev_hint = nullptr; |
513 UsePosition* prev = nullptr; | 508 UsePosition* prev = nullptr; |
514 auto current = first_pos_; | 509 auto current = first_pos_; |
515 while (current != nullptr && current->pos().Value() < pos.Value()) { | 510 while (current != nullptr && current->pos().Value() < pos.Value()) { |
516 prev_hint = current->HasHint() ? current : prev_hint; | 511 prev_hint = current->HasHint() ? current : prev_hint; |
517 prev = current; | 512 prev = current; |
518 current = current->next(); | 513 current = current->next(); |
519 } | 514 } |
520 | 515 |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
704 } | 699 } |
705 | 700 |
706 | 701 |
707 int RegisterAllocator::FixedDoubleLiveRangeID(int index) { | 702 int RegisterAllocator::FixedDoubleLiveRangeID(int index) { |
708 return -index - 1 - config()->num_general_registers(); | 703 return -index - 1 - config()->num_general_registers(); |
709 } | 704 } |
710 | 705 |
711 | 706 |
712 InstructionOperand* RegisterAllocator::AllocateFixed( | 707 InstructionOperand* RegisterAllocator::AllocateFixed( |
713 UnallocatedOperand* operand, int pos, bool is_tagged) { | 708 UnallocatedOperand* operand, int pos, bool is_tagged) { |
714 TraceAlloc("Allocating fixed reg for op %d\n", operand->virtual_register()); | 709 TRACE("Allocating fixed reg for op %d\n", operand->virtual_register()); |
715 DCHECK(operand->HasFixedPolicy()); | 710 DCHECK(operand->HasFixedPolicy()); |
716 if (operand->HasFixedSlotPolicy()) { | 711 if (operand->HasFixedSlotPolicy()) { |
717 operand->ConvertTo(InstructionOperand::STACK_SLOT, | 712 operand->ConvertTo(InstructionOperand::STACK_SLOT, |
718 operand->fixed_slot_index()); | 713 operand->fixed_slot_index()); |
719 } else if (operand->HasFixedRegisterPolicy()) { | 714 } else if (operand->HasFixedRegisterPolicy()) { |
720 int reg_index = operand->fixed_register_index(); | 715 int reg_index = operand->fixed_register_index(); |
721 operand->ConvertTo(InstructionOperand::REGISTER, reg_index); | 716 operand->ConvertTo(InstructionOperand::REGISTER, reg_index); |
722 } else if (operand->HasFixedDoubleRegisterPolicy()) { | 717 } else if (operand->HasFixedDoubleRegisterPolicy()) { |
723 int reg_index = operand->fixed_register_index(); | 718 int reg_index = operand->fixed_register_index(); |
724 operand->ConvertTo(InstructionOperand::DOUBLE_REGISTER, reg_index); | 719 operand->ConvertTo(InstructionOperand::DOUBLE_REGISTER, reg_index); |
725 } else { | 720 } else { |
726 UNREACHABLE(); | 721 UNREACHABLE(); |
727 } | 722 } |
728 if (is_tagged) { | 723 if (is_tagged) { |
729 TraceAlloc("Fixed reg is tagged at %d\n", pos); | 724 TRACE("Fixed reg is tagged at %d\n", pos); |
730 auto instr = InstructionAt(pos); | 725 auto instr = InstructionAt(pos); |
731 if (instr->HasPointerMap()) { | 726 if (instr->HasPointerMap()) { |
732 instr->pointer_map()->RecordPointer(operand, code_zone()); | 727 instr->pointer_map()->RecordPointer(operand, code_zone()); |
733 } | 728 } |
734 } | 729 } |
735 return operand; | 730 return operand; |
736 } | 731 } |
737 | 732 |
738 | 733 |
739 LiveRange* RegisterAllocator::NewLiveRange(int index) { | 734 LiveRange* RegisterAllocator::NewLiveRange(int index) { |
(...skipping 1194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1934 while (cur != nullptr && !cur->Covers(safe_point_pos)) { | 1929 while (cur != nullptr && !cur->Covers(safe_point_pos)) { |
1935 cur = cur->next(); | 1930 cur = cur->next(); |
1936 } | 1931 } |
1937 if (cur == nullptr) continue; | 1932 if (cur == nullptr) continue; |
1938 | 1933 |
1939 // Check if the live range is spilled and the safe point is after | 1934 // Check if the live range is spilled and the safe point is after |
1940 // the spill position. | 1935 // the spill position. |
1941 if (range->HasSpillOperand() && | 1936 if (range->HasSpillOperand() && |
1942 safe_point >= range->spill_start_index() && | 1937 safe_point >= range->spill_start_index() && |
1943 !range->GetSpillOperand()->IsConstant()) { | 1938 !range->GetSpillOperand()->IsConstant()) { |
1944 TraceAlloc("Pointer for range %d (spilled at %d) at safe point %d\n", | 1939 TRACE("Pointer for range %d (spilled at %d) at safe point %d\n", |
1945 range->id(), range->spill_start_index(), safe_point); | 1940 range->id(), range->spill_start_index(), safe_point); |
1946 map->RecordPointer(range->GetSpillOperand(), code_zone()); | 1941 map->RecordPointer(range->GetSpillOperand(), code_zone()); |
1947 } | 1942 } |
1948 | 1943 |
1949 if (!cur->IsSpilled()) { | 1944 if (!cur->IsSpilled()) { |
1950 TraceAlloc( | 1945 TRACE( |
1951 "Pointer in register for range %d (start at %d) " | 1946 "Pointer in register for range %d (start at %d) " |
1952 "at safe point %d\n", | 1947 "at safe point %d\n", |
1953 cur->id(), cur->Start().Value(), safe_point); | 1948 cur->id(), cur->Start().Value(), safe_point); |
1954 InstructionOperand* operand = cur->GetAssignedOperand(operand_cache()); | 1949 InstructionOperand* operand = cur->GetAssignedOperand(operand_cache()); |
1955 DCHECK(!operand->IsStackSlot()); | 1950 DCHECK(!operand->IsStackSlot()); |
1956 map->RecordPointer(operand, code_zone()); | 1951 map->RecordPointer(operand, code_zone()); |
1957 } | 1952 } |
1958 } | 1953 } |
1959 } | 1954 } |
1960 } | 1955 } |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2007 | 2002 |
2008 while (!unhandled_live_ranges().empty()) { | 2003 while (!unhandled_live_ranges().empty()) { |
2009 DCHECK(UnhandledIsSorted()); | 2004 DCHECK(UnhandledIsSorted()); |
2010 auto current = unhandled_live_ranges().back(); | 2005 auto current = unhandled_live_ranges().back(); |
2011 unhandled_live_ranges().pop_back(); | 2006 unhandled_live_ranges().pop_back(); |
2012 DCHECK(UnhandledIsSorted()); | 2007 DCHECK(UnhandledIsSorted()); |
2013 auto position = current->Start(); | 2008 auto position = current->Start(); |
2014 #ifdef DEBUG | 2009 #ifdef DEBUG |
2015 allocation_finger_ = position; | 2010 allocation_finger_ = position; |
2016 #endif | 2011 #endif |
2017 TraceAlloc("Processing interval %d start=%d\n", current->id(), | 2012 TRACE("Processing interval %d start=%d\n", current->id(), position.Value()); |
2018 position.Value()); | |
2019 | 2013 |
2020 if (!current->HasNoSpillType()) { | 2014 if (!current->HasNoSpillType()) { |
2021 TraceAlloc("Live range %d already has a spill operand\n", current->id()); | 2015 TRACE("Live range %d already has a spill operand\n", current->id()); |
2022 auto next_pos = position; | 2016 auto next_pos = position; |
2023 if (code()->IsGapAt(next_pos.InstructionIndex())) { | 2017 if (code()->IsGapAt(next_pos.InstructionIndex())) { |
2024 next_pos = next_pos.NextInstruction(); | 2018 next_pos = next_pos.NextInstruction(); |
2025 } | 2019 } |
2026 auto pos = current->NextUsePositionRegisterIsBeneficial(next_pos); | 2020 auto pos = current->NextUsePositionRegisterIsBeneficial(next_pos); |
2027 // If the range already has a spill operand and it doesn't need a | 2021 // If the range already has a spill operand and it doesn't need a |
2028 // register immediately, split it and spill the first part of the range. | 2022 // register immediately, split it and spill the first part of the range. |
2029 if (pos == nullptr) { | 2023 if (pos == nullptr) { |
2030 Spill(current); | 2024 Spill(current); |
2031 continue; | 2025 continue; |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2092 | 2086 |
2093 | 2087 |
2094 RegisterKind RegisterAllocator::RequiredRegisterKind( | 2088 RegisterKind RegisterAllocator::RequiredRegisterKind( |
2095 int virtual_register) const { | 2089 int virtual_register) const { |
2096 return (code()->IsDouble(virtual_register)) ? DOUBLE_REGISTERS | 2090 return (code()->IsDouble(virtual_register)) ? DOUBLE_REGISTERS |
2097 : GENERAL_REGISTERS; | 2091 : GENERAL_REGISTERS; |
2098 } | 2092 } |
2099 | 2093 |
2100 | 2094 |
2101 void RegisterAllocator::AddToActive(LiveRange* range) { | 2095 void RegisterAllocator::AddToActive(LiveRange* range) { |
2102 TraceAlloc("Add live range %d to active\n", range->id()); | 2096 TRACE("Add live range %d to active\n", range->id()); |
2103 active_live_ranges().push_back(range); | 2097 active_live_ranges().push_back(range); |
2104 } | 2098 } |
2105 | 2099 |
2106 | 2100 |
2107 void RegisterAllocator::AddToInactive(LiveRange* range) { | 2101 void RegisterAllocator::AddToInactive(LiveRange* range) { |
2108 TraceAlloc("Add live range %d to inactive\n", range->id()); | 2102 TRACE("Add live range %d to inactive\n", range->id()); |
2109 inactive_live_ranges().push_back(range); | 2103 inactive_live_ranges().push_back(range); |
2110 } | 2104 } |
2111 | 2105 |
2112 | 2106 |
2113 void RegisterAllocator::AddToUnhandledSorted(LiveRange* range) { | 2107 void RegisterAllocator::AddToUnhandledSorted(LiveRange* range) { |
2114 if (range == nullptr || range->IsEmpty()) return; | 2108 if (range == nullptr || range->IsEmpty()) return; |
2115 DCHECK(!range->HasRegisterAssigned() && !range->IsSpilled()); | 2109 DCHECK(!range->HasRegisterAssigned() && !range->IsSpilled()); |
2116 DCHECK(allocation_finger_.Value() <= range->Start().Value()); | 2110 DCHECK(allocation_finger_.Value() <= range->Start().Value()); |
2117 for (int i = static_cast<int>(unhandled_live_ranges().size() - 1); i >= 0; | 2111 for (int i = static_cast<int>(unhandled_live_ranges().size() - 1); i >= 0; |
2118 --i) { | 2112 --i) { |
2119 auto cur_range = unhandled_live_ranges().at(i); | 2113 auto cur_range = unhandled_live_ranges().at(i); |
2120 if (!range->ShouldBeAllocatedBefore(cur_range)) continue; | 2114 if (!range->ShouldBeAllocatedBefore(cur_range)) continue; |
2121 TraceAlloc("Add live range %d to unhandled at %d\n", range->id(), i + 1); | 2115 TRACE("Add live range %d to unhandled at %d\n", range->id(), i + 1); |
2122 auto it = unhandled_live_ranges().begin() + (i + 1); | 2116 auto it = unhandled_live_ranges().begin() + (i + 1); |
2123 unhandled_live_ranges().insert(it, range); | 2117 unhandled_live_ranges().insert(it, range); |
2124 DCHECK(UnhandledIsSorted()); | 2118 DCHECK(UnhandledIsSorted()); |
2125 return; | 2119 return; |
2126 } | 2120 } |
2127 TraceAlloc("Add live range %d to unhandled at start\n", range->id()); | 2121 TRACE("Add live range %d to unhandled at start\n", range->id()); |
2128 unhandled_live_ranges().insert(unhandled_live_ranges().begin(), range); | 2122 unhandled_live_ranges().insert(unhandled_live_ranges().begin(), range); |
2129 DCHECK(UnhandledIsSorted()); | 2123 DCHECK(UnhandledIsSorted()); |
2130 } | 2124 } |
2131 | 2125 |
2132 | 2126 |
2133 void RegisterAllocator::AddToUnhandledUnsorted(LiveRange* range) { | 2127 void RegisterAllocator::AddToUnhandledUnsorted(LiveRange* range) { |
2134 if (range == nullptr || range->IsEmpty()) return; | 2128 if (range == nullptr || range->IsEmpty()) return; |
2135 DCHECK(!range->HasRegisterAssigned() && !range->IsSpilled()); | 2129 DCHECK(!range->HasRegisterAssigned() && !range->IsSpilled()); |
2136 TraceAlloc("Add live range %d to unhandled unsorted at end\n", range->id()); | 2130 TRACE("Add live range %d to unhandled unsorted at end\n", range->id()); |
2137 unhandled_live_ranges().push_back(range); | 2131 unhandled_live_ranges().push_back(range); |
2138 } | 2132 } |
2139 | 2133 |
2140 | 2134 |
2141 static bool UnhandledSortHelper(LiveRange* a, LiveRange* b) { | 2135 static bool UnhandledSortHelper(LiveRange* a, LiveRange* b) { |
2142 DCHECK(!a->ShouldBeAllocatedBefore(b) || !b->ShouldBeAllocatedBefore(a)); | 2136 DCHECK(!a->ShouldBeAllocatedBefore(b) || !b->ShouldBeAllocatedBefore(a)); |
2143 if (a->ShouldBeAllocatedBefore(b)) return false; | 2137 if (a->ShouldBeAllocatedBefore(b)) return false; |
2144 if (b->ShouldBeAllocatedBefore(a)) return true; | 2138 if (b->ShouldBeAllocatedBefore(a)) return true; |
2145 return a->id() < b->id(); | 2139 return a->id() < b->id(); |
2146 } | 2140 } |
2147 | 2141 |
2148 | 2142 |
2149 // Sort the unhandled live ranges so that the ranges to be processed first are | 2143 // Sort the unhandled live ranges so that the ranges to be processed first are |
2150 // at the end of the array list. This is convenient for the register allocation | 2144 // at the end of the array list. This is convenient for the register allocation |
2151 // algorithm because it is efficient to remove elements from the end. | 2145 // algorithm because it is efficient to remove elements from the end. |
2152 void RegisterAllocator::SortUnhandled() { | 2146 void RegisterAllocator::SortUnhandled() { |
2153 TraceAlloc("Sort unhandled\n"); | 2147 TRACE("Sort unhandled\n"); |
2154 std::sort(unhandled_live_ranges().begin(), unhandled_live_ranges().end(), | 2148 std::sort(unhandled_live_ranges().begin(), unhandled_live_ranges().end(), |
2155 &UnhandledSortHelper); | 2149 &UnhandledSortHelper); |
2156 } | 2150 } |
2157 | 2151 |
2158 | 2152 |
2159 bool RegisterAllocator::UnhandledIsSorted() { | 2153 bool RegisterAllocator::UnhandledIsSorted() { |
2160 size_t len = unhandled_live_ranges().size(); | 2154 size_t len = unhandled_live_ranges().size(); |
2161 for (size_t i = 1; i < len; i++) { | 2155 for (size_t i = 1; i < len; i++) { |
2162 auto a = unhandled_live_ranges().at(i - 1); | 2156 auto a = unhandled_live_ranges().at(i - 1); |
2163 auto b = unhandled_live_ranges().at(i); | 2157 auto b = unhandled_live_ranges().at(i); |
2164 if (a->Start().Value() < b->Start().Value()) return false; | 2158 if (a->Start().Value() < b->Start().Value()) return false; |
2165 } | 2159 } |
2166 return true; | 2160 return true; |
2167 } | 2161 } |
2168 | 2162 |
2169 | 2163 |
2170 void RegisterAllocator::ActiveToHandled(LiveRange* range) { | 2164 void RegisterAllocator::ActiveToHandled(LiveRange* range) { |
2171 RemoveElement(&active_live_ranges(), range); | 2165 RemoveElement(&active_live_ranges(), range); |
2172 TraceAlloc("Moving live range %d from active to handled\n", range->id()); | 2166 TRACE("Moving live range %d from active to handled\n", range->id()); |
2173 } | 2167 } |
2174 | 2168 |
2175 | 2169 |
2176 void RegisterAllocator::ActiveToInactive(LiveRange* range) { | 2170 void RegisterAllocator::ActiveToInactive(LiveRange* range) { |
2177 RemoveElement(&active_live_ranges(), range); | 2171 RemoveElement(&active_live_ranges(), range); |
2178 inactive_live_ranges().push_back(range); | 2172 inactive_live_ranges().push_back(range); |
2179 TraceAlloc("Moving live range %d from active to inactive\n", range->id()); | 2173 TRACE("Moving live range %d from active to inactive\n", range->id()); |
2180 } | 2174 } |
2181 | 2175 |
2182 | 2176 |
2183 void RegisterAllocator::InactiveToHandled(LiveRange* range) { | 2177 void RegisterAllocator::InactiveToHandled(LiveRange* range) { |
2184 RemoveElement(&inactive_live_ranges(), range); | 2178 RemoveElement(&inactive_live_ranges(), range); |
2185 TraceAlloc("Moving live range %d from inactive to handled\n", range->id()); | 2179 TRACE("Moving live range %d from inactive to handled\n", range->id()); |
2186 } | 2180 } |
2187 | 2181 |
2188 | 2182 |
2189 void RegisterAllocator::InactiveToActive(LiveRange* range) { | 2183 void RegisterAllocator::InactiveToActive(LiveRange* range) { |
2190 RemoveElement(&inactive_live_ranges(), range); | 2184 RemoveElement(&inactive_live_ranges(), range); |
2191 active_live_ranges().push_back(range); | 2185 active_live_ranges().push_back(range); |
2192 TraceAlloc("Moving live range %d from inactive to active\n", range->id()); | 2186 TRACE("Moving live range %d from inactive to active\n", range->id()); |
2193 } | 2187 } |
2194 | 2188 |
2195 | 2189 |
2196 bool RegisterAllocator::TryAllocateFreeReg(LiveRange* current) { | 2190 bool RegisterAllocator::TryAllocateFreeReg(LiveRange* current) { |
2197 LifetimePosition free_until_pos[RegisterConfiguration::kMaxDoubleRegisters]; | 2191 LifetimePosition free_until_pos[RegisterConfiguration::kMaxDoubleRegisters]; |
2198 | 2192 |
2199 for (int i = 0; i < num_registers_; i++) { | 2193 for (int i = 0; i < num_registers_; i++) { |
2200 free_until_pos[i] = LifetimePosition::MaxPosition(); | 2194 free_until_pos[i] = LifetimePosition::MaxPosition(); |
2201 } | 2195 } |
2202 | 2196 |
2203 for (auto cur_active : active_live_ranges()) { | 2197 for (auto cur_active : active_live_ranges()) { |
2204 free_until_pos[cur_active->assigned_register()] = | 2198 free_until_pos[cur_active->assigned_register()] = |
2205 LifetimePosition::FromInstructionIndex(0); | 2199 LifetimePosition::FromInstructionIndex(0); |
2206 } | 2200 } |
2207 | 2201 |
2208 for (auto cur_inactive : inactive_live_ranges()) { | 2202 for (auto cur_inactive : inactive_live_ranges()) { |
2209 DCHECK(cur_inactive->End().Value() > current->Start().Value()); | 2203 DCHECK(cur_inactive->End().Value() > current->Start().Value()); |
2210 auto next_intersection = cur_inactive->FirstIntersection(current); | 2204 auto next_intersection = cur_inactive->FirstIntersection(current); |
2211 if (!next_intersection.IsValid()) continue; | 2205 if (!next_intersection.IsValid()) continue; |
2212 int cur_reg = cur_inactive->assigned_register(); | 2206 int cur_reg = cur_inactive->assigned_register(); |
2213 free_until_pos[cur_reg] = Min(free_until_pos[cur_reg], next_intersection); | 2207 free_until_pos[cur_reg] = Min(free_until_pos[cur_reg], next_intersection); |
2214 } | 2208 } |
2215 | 2209 |
2216 auto hint = current->FirstHint(); | 2210 auto hint = current->FirstHint(); |
2217 if (hint != nullptr && (hint->IsRegister() || hint->IsDoubleRegister())) { | 2211 if (hint != nullptr && (hint->IsRegister() || hint->IsDoubleRegister())) { |
2218 int register_index = hint->index(); | 2212 int register_index = hint->index(); |
2219 TraceAlloc( | 2213 TRACE("Found reg hint %s (free until [%d) for live range %d (end %d[).\n", |
2220 "Found reg hint %s (free until [%d) for live range %d (end %d[).\n", | 2214 RegisterName(register_index), free_until_pos[register_index].Value(), |
2221 RegisterName(register_index), free_until_pos[register_index].Value(), | 2215 current->id(), current->End().Value()); |
2222 current->id(), current->End().Value()); | |
2223 | 2216 |
2224 // The desired register is free until the end of the current live range. | 2217 // The desired register is free until the end of the current live range. |
2225 if (free_until_pos[register_index].Value() >= current->End().Value()) { | 2218 if (free_until_pos[register_index].Value() >= current->End().Value()) { |
2226 TraceAlloc("Assigning preferred reg %s to live range %d\n", | 2219 TRACE("Assigning preferred reg %s to live range %d\n", |
2227 RegisterName(register_index), current->id()); | 2220 RegisterName(register_index), current->id()); |
2228 SetLiveRangeAssignedRegister(current, register_index); | 2221 SetLiveRangeAssignedRegister(current, register_index); |
2229 return true; | 2222 return true; |
2230 } | 2223 } |
2231 } | 2224 } |
2232 | 2225 |
2233 // Find the register which stays free for the longest time. | 2226 // Find the register which stays free for the longest time. |
2234 int reg = 0; | 2227 int reg = 0; |
2235 for (int i = 1; i < RegisterCount(); ++i) { | 2228 for (int i = 1; i < RegisterCount(); ++i) { |
2236 if (free_until_pos[i].Value() > free_until_pos[reg].Value()) { | 2229 if (free_until_pos[i].Value() > free_until_pos[reg].Value()) { |
2237 reg = i; | 2230 reg = i; |
(...skipping 10 matching lines...) Expand all Loading... |
2248 if (pos.Value() < current->End().Value()) { | 2241 if (pos.Value() < current->End().Value()) { |
2249 // Register reg is available at the range start but becomes blocked before | 2242 // Register reg is available at the range start but becomes blocked before |
2250 // the range end. Split current at position where it becomes blocked. | 2243 // the range end. Split current at position where it becomes blocked. |
2251 auto tail = SplitRangeAt(current, pos); | 2244 auto tail = SplitRangeAt(current, pos); |
2252 AddToUnhandledSorted(tail); | 2245 AddToUnhandledSorted(tail); |
2253 } | 2246 } |
2254 | 2247 |
2255 // Register reg is available at the range start and is free until | 2248 // Register reg is available at the range start and is free until |
2256 // the range end. | 2249 // the range end. |
2257 DCHECK(pos.Value() >= current->End().Value()); | 2250 DCHECK(pos.Value() >= current->End().Value()); |
2258 TraceAlloc("Assigning free reg %s to live range %d\n", RegisterName(reg), | 2251 TRACE("Assigning free reg %s to live range %d\n", RegisterName(reg), |
2259 current->id()); | 2252 current->id()); |
2260 SetLiveRangeAssignedRegister(current, reg); | 2253 SetLiveRangeAssignedRegister(current, reg); |
2261 | 2254 |
2262 return true; | 2255 return true; |
2263 } | 2256 } |
2264 | 2257 |
2265 | 2258 |
2266 void RegisterAllocator::AllocateBlockedReg(LiveRange* current) { | 2259 void RegisterAllocator::AllocateBlockedReg(LiveRange* current) { |
2267 auto register_use = current->NextRegisterPosition(current->Start()); | 2260 auto register_use = current->NextRegisterPosition(current->Start()); |
2268 if (register_use == nullptr) { | 2261 if (register_use == nullptr) { |
2269 // There is no use in the current live range that requires a register. | 2262 // There is no use in the current live range that requires a register. |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2327 if (block_pos[reg].Value() < current->End().Value()) { | 2320 if (block_pos[reg].Value() < current->End().Value()) { |
2328 // Register becomes blocked before the current range end. Split before that | 2321 // Register becomes blocked before the current range end. Split before that |
2329 // position. | 2322 // position. |
2330 LiveRange* tail = SplitBetween(current, current->Start(), | 2323 LiveRange* tail = SplitBetween(current, current->Start(), |
2331 block_pos[reg].InstructionStart()); | 2324 block_pos[reg].InstructionStart()); |
2332 AddToUnhandledSorted(tail); | 2325 AddToUnhandledSorted(tail); |
2333 } | 2326 } |
2334 | 2327 |
2335 // Register reg is not blocked for the whole range. | 2328 // Register reg is not blocked for the whole range. |
2336 DCHECK(block_pos[reg].Value() >= current->End().Value()); | 2329 DCHECK(block_pos[reg].Value() >= current->End().Value()); |
2337 TraceAlloc("Assigning blocked reg %s to live range %d\n", RegisterName(reg), | 2330 TRACE("Assigning blocked reg %s to live range %d\n", RegisterName(reg), |
2338 current->id()); | 2331 current->id()); |
2339 SetLiveRangeAssignedRegister(current, reg); | 2332 SetLiveRangeAssignedRegister(current, reg); |
2340 | 2333 |
2341 // This register was not free. Thus we need to find and spill | 2334 // This register was not free. Thus we need to find and spill |
2342 // parts of active and inactive live regions that use the same register | 2335 // parts of active and inactive live regions that use the same register |
2343 // at the same lifetime positions as current. | 2336 // at the same lifetime positions as current. |
2344 SplitAndSpillIntersecting(current); | 2337 SplitAndSpillIntersecting(current); |
2345 } | 2338 } |
2346 | 2339 |
2347 | 2340 |
2348 static const InstructionBlock* GetContainingLoop( | 2341 static const InstructionBlock* GetContainingLoop( |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2436 bool RegisterAllocator::IsBlockBoundary(LifetimePosition pos) { | 2429 bool RegisterAllocator::IsBlockBoundary(LifetimePosition pos) { |
2437 return pos.IsInstructionStart() && | 2430 return pos.IsInstructionStart() && |
2438 code()->GetInstructionBlock(pos.InstructionIndex())->code_start() == | 2431 code()->GetInstructionBlock(pos.InstructionIndex())->code_start() == |
2439 pos.InstructionIndex(); | 2432 pos.InstructionIndex(); |
2440 } | 2433 } |
2441 | 2434 |
2442 | 2435 |
2443 LiveRange* RegisterAllocator::SplitRangeAt(LiveRange* range, | 2436 LiveRange* RegisterAllocator::SplitRangeAt(LiveRange* range, |
2444 LifetimePosition pos) { | 2437 LifetimePosition pos) { |
2445 DCHECK(!range->IsFixed()); | 2438 DCHECK(!range->IsFixed()); |
2446 TraceAlloc("Splitting live range %d at %d\n", range->id(), pos.Value()); | 2439 TRACE("Splitting live range %d at %d\n", range->id(), pos.Value()); |
2447 | 2440 |
2448 if (pos.Value() <= range->Start().Value()) return range; | 2441 if (pos.Value() <= range->Start().Value()) return range; |
2449 | 2442 |
2450 // We can't properly connect liveranges if splitting occurred at the end | 2443 // We can't properly connect liveranges if splitting occurred at the end |
2451 // a block. | 2444 // a block. |
2452 DCHECK(pos.IsInstructionStart() || | 2445 DCHECK(pos.IsInstructionStart() || |
2453 (code()->GetInstructionBlock(pos.InstructionIndex())) | 2446 (code()->GetInstructionBlock(pos.InstructionIndex())) |
2454 ->last_instruction_index() != pos.InstructionIndex()); | 2447 ->last_instruction_index() != pos.InstructionIndex()); |
2455 | 2448 |
2456 int vreg = GetVirtualRegister(); | 2449 int vreg = GetVirtualRegister(); |
2457 auto result = LiveRangeFor(vreg); | 2450 auto result = LiveRangeFor(vreg); |
2458 range->SplitAt(pos, result, local_zone()); | 2451 range->SplitAt(pos, result, local_zone()); |
2459 return result; | 2452 return result; |
2460 } | 2453 } |
2461 | 2454 |
2462 | 2455 |
2463 LiveRange* RegisterAllocator::SplitBetween(LiveRange* range, | 2456 LiveRange* RegisterAllocator::SplitBetween(LiveRange* range, |
2464 LifetimePosition start, | 2457 LifetimePosition start, |
2465 LifetimePosition end) { | 2458 LifetimePosition end) { |
2466 DCHECK(!range->IsFixed()); | 2459 DCHECK(!range->IsFixed()); |
2467 TraceAlloc("Splitting live range %d in position between [%d, %d]\n", | 2460 TRACE("Splitting live range %d in position between [%d, %d]\n", range->id(), |
2468 range->id(), start.Value(), end.Value()); | 2461 start.Value(), end.Value()); |
2469 | 2462 |
2470 auto split_pos = FindOptimalSplitPos(start, end); | 2463 auto split_pos = FindOptimalSplitPos(start, end); |
2471 DCHECK(split_pos.Value() >= start.Value()); | 2464 DCHECK(split_pos.Value() >= start.Value()); |
2472 return SplitRangeAt(range, split_pos); | 2465 return SplitRangeAt(range, split_pos); |
2473 } | 2466 } |
2474 | 2467 |
2475 | 2468 |
2476 LifetimePosition RegisterAllocator::FindOptimalSplitPos(LifetimePosition start, | 2469 LifetimePosition RegisterAllocator::FindOptimalSplitPos(LifetimePosition start, |
2477 LifetimePosition end) { | 2470 LifetimePosition end) { |
2478 int start_instr = start.InstructionIndex(); | 2471 int start_instr = start.InstructionIndex(); |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2547 } else { | 2540 } else { |
2548 // The split result does not intersect with [start, end[. | 2541 // The split result does not intersect with [start, end[. |
2549 // Nothing to spill. Just put it to unhandled as whole. | 2542 // Nothing to spill. Just put it to unhandled as whole. |
2550 AddToUnhandledSorted(second_part); | 2543 AddToUnhandledSorted(second_part); |
2551 } | 2544 } |
2552 } | 2545 } |
2553 | 2546 |
2554 | 2547 |
2555 void RegisterAllocator::Spill(LiveRange* range) { | 2548 void RegisterAllocator::Spill(LiveRange* range) { |
2556 DCHECK(!range->IsSpilled()); | 2549 DCHECK(!range->IsSpilled()); |
2557 TraceAlloc("Spilling live range %d\n", range->id()); | 2550 TRACE("Spilling live range %d\n", range->id()); |
2558 auto first = range->TopLevel(); | 2551 auto first = range->TopLevel(); |
2559 if (first->HasNoSpillType()) { | 2552 if (first->HasNoSpillType()) { |
2560 AssignSpillRangeToLiveRange(first); | 2553 AssignSpillRangeToLiveRange(first); |
2561 } | 2554 } |
2562 range->MakeSpilled(); | 2555 range->MakeSpilled(); |
2563 } | 2556 } |
2564 | 2557 |
2565 | 2558 |
2566 int RegisterAllocator::RegisterCount() const { return num_registers_; } | 2559 int RegisterAllocator::RegisterCount() const { return num_registers_; } |
2567 | 2560 |
(...skipping 18 matching lines...) Expand all Loading... |
2586 } else { | 2579 } else { |
2587 DCHECK(range->Kind() == GENERAL_REGISTERS); | 2580 DCHECK(range->Kind() == GENERAL_REGISTERS); |
2588 assigned_registers_->Add(reg); | 2581 assigned_registers_->Add(reg); |
2589 } | 2582 } |
2590 range->set_assigned_register(reg, operand_cache()); | 2583 range->set_assigned_register(reg, operand_cache()); |
2591 } | 2584 } |
2592 | 2585 |
2593 } // namespace compiler | 2586 } // namespace compiler |
2594 } // namespace internal | 2587 } // namespace internal |
2595 } // namespace v8 | 2588 } // namespace v8 |
OLD | NEW |