| 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 |