| 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(...) \ | 13 #define TRACE(...) \ |
| 14 do { \ | 14 do { \ |
| 15 if (FLAG_trace_alloc) PrintF(__VA_ARGS__); \ | 15 if (FLAG_trace_alloc) PrintF(__VA_ARGS__); \ |
| 16 } while (false) | 16 } while (false) |
| 17 | 17 |
| 18 static inline LifetimePosition Min(LifetimePosition a, LifetimePosition b) { | 18 namespace { |
| 19 |
| 20 inline LifetimePosition Min(LifetimePosition a, LifetimePosition b) { |
| 19 return a.Value() < b.Value() ? a : b; | 21 return a.Value() < b.Value() ? a : b; |
| 20 } | 22 } |
| 21 | 23 |
| 22 | 24 |
| 23 static inline LifetimePosition Max(LifetimePosition a, LifetimePosition b) { | 25 inline LifetimePosition Max(LifetimePosition a, LifetimePosition b) { |
| 24 return a.Value() > b.Value() ? a : b; | 26 return a.Value() > b.Value() ? a : b; |
| 25 } | 27 } |
| 26 | 28 |
| 27 | 29 |
| 28 static void RemoveElement(ZoneVector<LiveRange*>* v, LiveRange* range) { | 30 void RemoveElement(ZoneVector<LiveRange*>* v, LiveRange* range) { |
| 29 auto it = std::find(v->begin(), v->end(), range); | 31 auto it = std::find(v->begin(), v->end(), range); |
| 30 DCHECK(it != v->end()); | 32 DCHECK(it != v->end()); |
| 31 v->erase(it); | 33 v->erase(it); |
| 32 } | 34 } |
| 33 | 35 |
| 36 } // namespace |
| 37 |
| 34 | 38 |
| 35 UsePosition::UsePosition(LifetimePosition pos, InstructionOperand* operand, | 39 UsePosition::UsePosition(LifetimePosition pos, InstructionOperand* operand, |
| 36 InstructionOperand* hint) | 40 InstructionOperand* hint) |
| 37 : operand_(operand), hint_(hint), pos_(pos), next_(nullptr), flags_(0) { | 41 : operand_(operand), hint_(hint), pos_(pos), next_(nullptr), flags_(0) { |
| 38 bool register_beneficial = true; | 42 bool register_beneficial = true; |
| 39 UsePositionType type = UsePositionType::kAny; | 43 UsePositionType type = UsePositionType::kAny; |
| 40 if (operand_ != nullptr && operand_->IsUnallocated()) { | 44 if (operand_ != nullptr && operand_->IsUnallocated()) { |
| 41 const UnallocatedOperand* unalloc = UnallocatedOperand::cast(operand_); | 45 const UnallocatedOperand* unalloc = UnallocatedOperand::cast(operand_); |
| 42 if (unalloc->HasRegisterPolicy()) { | 46 if (unalloc->HasRegisterPolicy()) { |
| 43 type = UsePositionType::kRequiresRegister; | 47 type = UsePositionType::kRequiresRegister; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 78 struct LiveRange::SpillAtDefinitionList : ZoneObject { | 82 struct LiveRange::SpillAtDefinitionList : ZoneObject { |
| 79 SpillAtDefinitionList(int gap_index, InstructionOperand* operand, | 83 SpillAtDefinitionList(int gap_index, InstructionOperand* operand, |
| 80 SpillAtDefinitionList* next) | 84 SpillAtDefinitionList* next) |
| 81 : gap_index(gap_index), operand(operand), next(next) {} | 85 : gap_index(gap_index), operand(operand), next(next) {} |
| 82 const int gap_index; | 86 const int gap_index; |
| 83 InstructionOperand* const operand; | 87 InstructionOperand* const operand; |
| 84 SpillAtDefinitionList* const next; | 88 SpillAtDefinitionList* const next; |
| 85 }; | 89 }; |
| 86 | 90 |
| 87 | 91 |
| 88 #ifdef DEBUG | 92 LiveRange::LiveRange(int id, Zone* zone) |
| 93 : id_(id), |
| 94 spilled_(false), |
| 95 has_slot_use_(false), |
| 96 is_phi_(false), |
| 97 is_non_loop_phi_(false), |
| 98 kind_(UNALLOCATED_REGISTERS), |
| 99 assigned_register_(kInvalidAssignment), |
| 100 last_interval_(nullptr), |
| 101 first_interval_(nullptr), |
| 102 first_pos_(nullptr), |
| 103 parent_(nullptr), |
| 104 next_(nullptr), |
| 105 current_interval_(nullptr), |
| 106 last_processed_use_(nullptr), |
| 107 current_hint_operand_(nullptr), |
| 108 spill_start_index_(kMaxInt), |
| 109 spill_type_(SpillType::kNoSpillType), |
| 110 spill_operand_(nullptr), |
| 111 spills_at_definition_(nullptr) {} |
| 89 | 112 |
| 90 | 113 |
| 91 void LiveRange::Verify() const { | 114 void LiveRange::Verify() const { |
| 92 UsePosition* cur = first_pos_; | 115 UsePosition* cur = first_pos_; |
| 93 while (cur != nullptr) { | 116 while (cur != nullptr) { |
| 94 DCHECK(Start().Value() <= cur->pos().Value() && | 117 CHECK(Start().Value() <= cur->pos().Value() && |
| 95 cur->pos().Value() <= End().Value()); | 118 cur->pos().Value() <= End().Value()); |
| 96 cur = cur->next(); | 119 cur = cur->next(); |
| 97 } | 120 } |
| 98 } | 121 } |
| 99 | 122 |
| 100 | 123 |
| 101 bool LiveRange::HasOverlap(UseInterval* target) const { | 124 bool LiveRange::HasOverlap(UseInterval* target) const { |
| 102 UseInterval* current_interval = first_interval_; | 125 UseInterval* current_interval = first_interval_; |
| 103 while (current_interval != nullptr) { | 126 while (current_interval != nullptr) { |
| 104 // Intervals overlap if the start of one is contained in the other. | 127 // Intervals overlap if the start of one is contained in the other. |
| 105 if (current_interval->Contains(target->start()) || | 128 if (current_interval->Contains(target->start()) || |
| 106 target->Contains(current_interval->start())) { | 129 target->Contains(current_interval->start())) { |
| 107 return true; | 130 return true; |
| 108 } | 131 } |
| 109 current_interval = current_interval->next(); | 132 current_interval = current_interval->next(); |
| 110 } | 133 } |
| 111 return false; | 134 return false; |
| 112 } | 135 } |
| 113 | 136 |
| 114 | 137 |
| 115 #endif | |
| 116 | |
| 117 | |
| 118 LiveRange::LiveRange(int id, Zone* zone) | |
| 119 : id_(id), | |
| 120 spilled_(false), | |
| 121 has_slot_use_(false), | |
| 122 is_phi_(false), | |
| 123 is_non_loop_phi_(false), | |
| 124 kind_(UNALLOCATED_REGISTERS), | |
| 125 assigned_register_(kInvalidAssignment), | |
| 126 last_interval_(nullptr), | |
| 127 first_interval_(nullptr), | |
| 128 first_pos_(nullptr), | |
| 129 parent_(nullptr), | |
| 130 next_(nullptr), | |
| 131 current_interval_(nullptr), | |
| 132 last_processed_use_(nullptr), | |
| 133 current_hint_operand_(nullptr), | |
| 134 spill_start_index_(kMaxInt), | |
| 135 spill_type_(SpillType::kNoSpillType), | |
| 136 spill_operand_(nullptr), | |
| 137 spills_at_definition_(nullptr) {} | |
| 138 | |
| 139 | |
| 140 void LiveRange::set_assigned_register(int reg) { | 138 void LiveRange::set_assigned_register(int reg) { |
| 141 DCHECK(!HasRegisterAssigned() && !IsSpilled()); | 139 DCHECK(!HasRegisterAssigned() && !IsSpilled()); |
| 142 assigned_register_ = reg; | 140 assigned_register_ = reg; |
| 143 } | 141 } |
| 144 | 142 |
| 145 | 143 |
| 146 void LiveRange::MakeSpilled() { | 144 void LiveRange::MakeSpilled() { |
| 147 DCHECK(!IsSpilled()); | 145 DCHECK(!IsSpilled()); |
| 148 DCHECK(!TopLevel()->HasNoSpillType()); | 146 DCHECK(!TopLevel()->HasNoSpillType()); |
| 149 spilled_ = true; | 147 spilled_ = true; |
| (...skipping 414 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 564 if (a == nullptr || a->start().Value() > other->End().Value()) break; | 562 if (a == nullptr || a->start().Value() > other->End().Value()) break; |
| 565 AdvanceLastProcessedMarker(a, advance_last_processed_up_to); | 563 AdvanceLastProcessedMarker(a, advance_last_processed_up_to); |
| 566 } else { | 564 } else { |
| 567 b = b->next(); | 565 b = b->next(); |
| 568 } | 566 } |
| 569 } | 567 } |
| 570 return LifetimePosition::Invalid(); | 568 return LifetimePosition::Invalid(); |
| 571 } | 569 } |
| 572 | 570 |
| 573 | 571 |
| 574 RegisterAllocator::RegisterAllocator(const RegisterConfiguration* config, | |
| 575 Zone* zone, Frame* frame, | |
| 576 InstructionSequence* code, | |
| 577 const char* debug_name) | |
| 578 : local_zone_(zone), | |
| 579 frame_(frame), | |
| 580 code_(code), | |
| 581 debug_name_(debug_name), | |
| 582 config_(config), | |
| 583 phi_map_(local_zone()), | |
| 584 live_in_sets_(code->InstructionBlockCount(), nullptr, local_zone()), | |
| 585 live_ranges_(code->VirtualRegisterCount() * 2, nullptr, local_zone()), | |
| 586 fixed_live_ranges_(this->config()->num_general_registers(), nullptr, | |
| 587 local_zone()), | |
| 588 fixed_double_live_ranges_(this->config()->num_double_registers(), nullptr, | |
| 589 local_zone()), | |
| 590 unhandled_live_ranges_(local_zone()), | |
| 591 active_live_ranges_(local_zone()), | |
| 592 inactive_live_ranges_(local_zone()), | |
| 593 spill_ranges_(local_zone()), | |
| 594 mode_(UNALLOCATED_REGISTERS), | |
| 595 num_registers_(-1) { | |
| 596 DCHECK(this->config()->num_general_registers() <= | |
| 597 RegisterConfiguration::kMaxGeneralRegisters); | |
| 598 DCHECK(this->config()->num_double_registers() <= | |
| 599 RegisterConfiguration::kMaxDoubleRegisters); | |
| 600 // TryAllocateFreeReg and AllocateBlockedReg assume this | |
| 601 // when allocating local arrays. | |
| 602 DCHECK(RegisterConfiguration::kMaxDoubleRegisters >= | |
| 603 this->config()->num_general_registers()); | |
| 604 unhandled_live_ranges().reserve( | |
| 605 static_cast<size_t>(code->VirtualRegisterCount() * 2)); | |
| 606 active_live_ranges().reserve(8); | |
| 607 inactive_live_ranges().reserve(8); | |
| 608 spill_ranges().reserve(8); | |
| 609 assigned_registers_ = | |
| 610 new (code_zone()) BitVector(config->num_general_registers(), code_zone()); | |
| 611 assigned_double_registers_ = new (code_zone()) | |
| 612 BitVector(config->num_aliased_double_registers(), code_zone()); | |
| 613 frame->SetAllocatedRegisters(assigned_registers_); | |
| 614 frame->SetAllocatedDoubleRegisters(assigned_double_registers_); | |
| 615 } | |
| 616 | |
| 617 | |
| 618 BitVector* RegisterAllocator::ComputeLiveOut(const InstructionBlock* block) { | |
| 619 // Compute live out for the given block, except not including backward | |
| 620 // successor edges. | |
| 621 auto live_out = new (local_zone()) | |
| 622 BitVector(code()->VirtualRegisterCount(), local_zone()); | |
| 623 | |
| 624 // Process all successor blocks. | |
| 625 for (auto succ : block->successors()) { | |
| 626 // Add values live on entry to the successor. Note the successor's | |
| 627 // live_in will not be computed yet for backwards edges. | |
| 628 auto live_in = live_in_sets_[succ.ToSize()]; | |
| 629 if (live_in != nullptr) live_out->Union(*live_in); | |
| 630 | |
| 631 // All phi input operands corresponding to this successor edge are live | |
| 632 // out from this block. | |
| 633 auto successor = code()->InstructionBlockAt(succ); | |
| 634 size_t index = successor->PredecessorIndexOf(block->rpo_number()); | |
| 635 DCHECK(index < successor->PredecessorCount()); | |
| 636 for (auto phi : successor->phis()) { | |
| 637 live_out->Add(phi->operands()[index]); | |
| 638 } | |
| 639 } | |
| 640 return live_out; | |
| 641 } | |
| 642 | |
| 643 | |
| 644 void RegisterAllocator::AddInitialIntervals(const InstructionBlock* block, | |
| 645 BitVector* live_out) { | |
| 646 // Add an interval that includes the entire block to the live range for | |
| 647 // each live_out value. | |
| 648 auto start = LifetimePosition::GapFromInstructionIndex( | |
| 649 block->first_instruction_index()); | |
| 650 auto end = LifetimePosition::InstructionFromInstructionIndex( | |
| 651 block->last_instruction_index()).NextStart(); | |
| 652 BitVector::Iterator iterator(live_out); | |
| 653 while (!iterator.Done()) { | |
| 654 int operand_index = iterator.Current(); | |
| 655 auto range = LiveRangeFor(operand_index); | |
| 656 range->AddUseInterval(start, end, local_zone()); | |
| 657 iterator.Advance(); | |
| 658 } | |
| 659 } | |
| 660 | |
| 661 | |
| 662 int RegisterAllocator::FixedDoubleLiveRangeID(int index) { | |
| 663 return -index - 1 - config()->num_general_registers(); | |
| 664 } | |
| 665 | |
| 666 | |
| 667 InstructionOperand* RegisterAllocator::AllocateFixed( | |
| 668 UnallocatedOperand* operand, int pos, bool is_tagged) { | |
| 669 TRACE("Allocating fixed reg for op %d\n", operand->virtual_register()); | |
| 670 DCHECK(operand->HasFixedPolicy()); | |
| 671 InstructionOperand allocated; | |
| 672 if (operand->HasFixedSlotPolicy()) { | |
| 673 allocated = AllocatedOperand(AllocatedOperand::STACK_SLOT, | |
| 674 operand->fixed_slot_index()); | |
| 675 } else if (operand->HasFixedRegisterPolicy()) { | |
| 676 allocated = AllocatedOperand(AllocatedOperand::REGISTER, | |
| 677 operand->fixed_register_index()); | |
| 678 } else if (operand->HasFixedDoubleRegisterPolicy()) { | |
| 679 allocated = AllocatedOperand(AllocatedOperand::DOUBLE_REGISTER, | |
| 680 operand->fixed_register_index()); | |
| 681 } else { | |
| 682 UNREACHABLE(); | |
| 683 } | |
| 684 InstructionOperand::ReplaceWith(operand, &allocated); | |
| 685 if (is_tagged) { | |
| 686 TRACE("Fixed reg is tagged at %d\n", pos); | |
| 687 auto instr = InstructionAt(pos); | |
| 688 if (instr->HasReferenceMap()) { | |
| 689 instr->reference_map()->RecordReference(*operand); | |
| 690 } | |
| 691 } | |
| 692 return operand; | |
| 693 } | |
| 694 | |
| 695 | |
| 696 LiveRange* RegisterAllocator::NewLiveRange(int index) { | |
| 697 // The LiveRange object itself can go in the local zone, but the | |
| 698 // InstructionOperand needs to go in the code zone, since it may survive | |
| 699 // register allocation. | |
| 700 return new (local_zone()) LiveRange(index, code_zone()); | |
| 701 } | |
| 702 | |
| 703 | |
| 704 LiveRange* RegisterAllocator::FixedLiveRangeFor(int index) { | |
| 705 DCHECK(index < config()->num_general_registers()); | |
| 706 auto result = fixed_live_ranges()[index]; | |
| 707 if (result == nullptr) { | |
| 708 result = NewLiveRange(FixedLiveRangeID(index)); | |
| 709 DCHECK(result->IsFixed()); | |
| 710 result->kind_ = GENERAL_REGISTERS; | |
| 711 SetLiveRangeAssignedRegister(result, index); | |
| 712 fixed_live_ranges()[index] = result; | |
| 713 } | |
| 714 return result; | |
| 715 } | |
| 716 | |
| 717 | |
| 718 LiveRange* RegisterAllocator::FixedDoubleLiveRangeFor(int index) { | |
| 719 DCHECK(index < config()->num_aliased_double_registers()); | |
| 720 auto result = fixed_double_live_ranges()[index]; | |
| 721 if (result == nullptr) { | |
| 722 result = NewLiveRange(FixedDoubleLiveRangeID(index)); | |
| 723 DCHECK(result->IsFixed()); | |
| 724 result->kind_ = DOUBLE_REGISTERS; | |
| 725 SetLiveRangeAssignedRegister(result, index); | |
| 726 fixed_double_live_ranges()[index] = result; | |
| 727 } | |
| 728 return result; | |
| 729 } | |
| 730 | |
| 731 | |
| 732 LiveRange* RegisterAllocator::LiveRangeFor(int index) { | |
| 733 if (index >= static_cast<int>(live_ranges().size())) { | |
| 734 live_ranges().resize(index + 1, nullptr); | |
| 735 } | |
| 736 auto result = live_ranges()[index]; | |
| 737 if (result == nullptr) { | |
| 738 result = NewLiveRange(index); | |
| 739 live_ranges()[index] = result; | |
| 740 } | |
| 741 return result; | |
| 742 } | |
| 743 | |
| 744 | |
| 745 Instruction* RegisterAllocator::GetLastInstruction( | |
| 746 const InstructionBlock* block) { | |
| 747 return code()->InstructionAt(block->last_instruction_index()); | |
| 748 } | |
| 749 | |
| 750 | |
| 751 LiveRange* RegisterAllocator::LiveRangeFor(InstructionOperand* operand) { | |
| 752 if (operand->IsUnallocated()) { | |
| 753 return LiveRangeFor(UnallocatedOperand::cast(operand)->virtual_register()); | |
| 754 } else if (operand->IsConstant()) { | |
| 755 return LiveRangeFor(ConstantOperand::cast(operand)->virtual_register()); | |
| 756 } else if (operand->IsRegister()) { | |
| 757 return FixedLiveRangeFor(RegisterOperand::cast(operand)->index()); | |
| 758 } else if (operand->IsDoubleRegister()) { | |
| 759 return FixedDoubleLiveRangeFor( | |
| 760 DoubleRegisterOperand::cast(operand)->index()); | |
| 761 } else { | |
| 762 return nullptr; | |
| 763 } | |
| 764 } | |
| 765 | |
| 766 | |
| 767 void RegisterAllocator::Define(LifetimePosition position, | |
| 768 InstructionOperand* operand, | |
| 769 InstructionOperand* hint) { | |
| 770 auto range = LiveRangeFor(operand); | |
| 771 if (range == nullptr) return; | |
| 772 | |
| 773 if (range->IsEmpty() || range->Start().Value() > position.Value()) { | |
| 774 // Can happen if there is a definition without use. | |
| 775 range->AddUseInterval(position, position.NextStart(), local_zone()); | |
| 776 range->AddUsePosition(position.NextStart(), nullptr, nullptr, local_zone()); | |
| 777 } else { | |
| 778 range->ShortenTo(position); | |
| 779 } | |
| 780 | |
| 781 if (operand->IsUnallocated()) { | |
| 782 auto unalloc_operand = UnallocatedOperand::cast(operand); | |
| 783 range->AddUsePosition(position, unalloc_operand, hint, local_zone()); | |
| 784 } | |
| 785 } | |
| 786 | |
| 787 | |
| 788 void RegisterAllocator::Use(LifetimePosition block_start, | |
| 789 LifetimePosition position, | |
| 790 InstructionOperand* operand, | |
| 791 InstructionOperand* hint) { | |
| 792 auto range = LiveRangeFor(operand); | |
| 793 if (range == nullptr) return; | |
| 794 if (operand->IsUnallocated()) { | |
| 795 UnallocatedOperand* unalloc_operand = UnallocatedOperand::cast(operand); | |
| 796 range->AddUsePosition(position, unalloc_operand, hint, local_zone()); | |
| 797 } | |
| 798 range->AddUseInterval(block_start, position, local_zone()); | |
| 799 } | |
| 800 | |
| 801 | |
| 802 MoveOperands* RegisterAllocator::AddGapMove(int index, | |
| 803 Instruction::GapPosition position, | |
| 804 const InstructionOperand& from, | |
| 805 const InstructionOperand& to) { | |
| 806 auto instr = code()->InstructionAt(index); | |
| 807 auto moves = instr->GetOrCreateParallelMove(position, code_zone()); | |
| 808 return moves->AddMove(from, to); | |
| 809 } | |
| 810 | |
| 811 | |
| 812 static bool AreUseIntervalsIntersecting(UseInterval* interval1, | 572 static bool AreUseIntervalsIntersecting(UseInterval* interval1, |
| 813 UseInterval* interval2) { | 573 UseInterval* interval2) { |
| 814 while (interval1 != nullptr && interval2 != nullptr) { | 574 while (interval1 != nullptr && interval2 != nullptr) { |
| 815 if (interval1->start().Value() < interval2->start().Value()) { | 575 if (interval1->start().Value() < interval2->start().Value()) { |
| 816 if (interval1->end().Value() > interval2->start().Value()) { | 576 if (interval1->end().Value() > interval2->start().Value()) { |
| 817 return true; | 577 return true; |
| 818 } | 578 } |
| 819 interval1 = interval1->next(); | 579 interval1 = interval1->next(); |
| 820 } else { | 580 } else { |
| 821 if (interval2->end().Value() > interval1->start().Value()) { | 581 if (interval2->end().Value() > interval1->start().Value()) { |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 913 } else { | 673 } else { |
| 914 tail->set_next(current); | 674 tail->set_next(current); |
| 915 } | 675 } |
| 916 tail = current; | 676 tail = current; |
| 917 current = current->next(); | 677 current = current->next(); |
| 918 } | 678 } |
| 919 // Other list is empty => we are done | 679 // Other list is empty => we are done |
| 920 } | 680 } |
| 921 | 681 |
| 922 | 682 |
| 923 void RegisterAllocator::AssignSpillSlots() { | 683 RegisterAllocationData::RegisterAllocationData( |
| 924 // Merge disjoint spill ranges | 684 const RegisterConfiguration* config, Zone* zone, Frame* frame, |
| 925 for (size_t i = 0; i < spill_ranges().size(); i++) { | 685 InstructionSequence* code, const char* debug_name) |
| 926 auto range = spill_ranges()[i]; | 686 : allocation_zone_(zone), |
| 927 if (range->IsEmpty()) continue; | 687 frame_(frame), |
| 928 for (size_t j = i + 1; j < spill_ranges().size(); j++) { | 688 code_(code), |
| 929 auto other = spill_ranges()[j]; | 689 debug_name_(debug_name), |
| 930 if (!other->IsEmpty()) { | 690 config_(config), |
| 931 range->TryMerge(other); | 691 phi_map_(allocation_zone()), |
| 932 } | 692 live_in_sets_(code->InstructionBlockCount(), nullptr, allocation_zone()), |
| 693 live_ranges_(code->VirtualRegisterCount() * 2, nullptr, |
| 694 allocation_zone()), |
| 695 fixed_live_ranges_(this->config()->num_general_registers(), nullptr, |
| 696 allocation_zone()), |
| 697 fixed_double_live_ranges_(this->config()->num_double_registers(), nullptr, |
| 698 allocation_zone()), |
| 699 spill_ranges_(allocation_zone()), |
| 700 assigned_registers_(nullptr), |
| 701 assigned_double_registers_(nullptr) { |
| 702 DCHECK(this->config()->num_general_registers() <= |
| 703 RegisterConfiguration::kMaxGeneralRegisters); |
| 704 DCHECK(this->config()->num_double_registers() <= |
| 705 RegisterConfiguration::kMaxDoubleRegisters); |
| 706 spill_ranges().reserve(8); |
| 707 assigned_registers_ = new (code_zone()) |
| 708 BitVector(this->config()->num_general_registers(), code_zone()); |
| 709 assigned_double_registers_ = new (code_zone()) |
| 710 BitVector(this->config()->num_aliased_double_registers(), code_zone()); |
| 711 this->frame()->SetAllocatedRegisters(assigned_registers_); |
| 712 this->frame()->SetAllocatedDoubleRegisters(assigned_double_registers_); |
| 713 } |
| 714 |
| 715 |
| 716 LiveRange* RegisterAllocationData::LiveRangeFor(int index) { |
| 717 if (index >= static_cast<int>(live_ranges().size())) { |
| 718 live_ranges().resize(index + 1, nullptr); |
| 719 } |
| 720 auto result = live_ranges()[index]; |
| 721 if (result == nullptr) { |
| 722 result = NewLiveRange(index); |
| 723 live_ranges()[index] = result; |
| 724 } |
| 725 return result; |
| 726 } |
| 727 |
| 728 |
| 729 MoveOperands* RegisterAllocationData::AddGapMove( |
| 730 int index, Instruction::GapPosition position, |
| 731 const InstructionOperand& from, const InstructionOperand& to) { |
| 732 auto instr = code()->InstructionAt(index); |
| 733 auto moves = instr->GetOrCreateParallelMove(position, code_zone()); |
| 734 return moves->AddMove(from, to); |
| 735 } |
| 736 |
| 737 |
| 738 void RegisterAllocationData::AssignPhiInput( |
| 739 LiveRange* range, const InstructionOperand& assignment) { |
| 740 DCHECK(range->is_phi()); |
| 741 auto it = phi_map().find(range->id()); |
| 742 DCHECK(it != phi_map().end()); |
| 743 for (auto move : it->second->incoming_moves) { |
| 744 move->set_destination(assignment); |
| 745 } |
| 746 } |
| 747 |
| 748 |
| 749 LiveRange* RegisterAllocationData::NewLiveRange(int index) { |
| 750 // The LiveRange object itself can go in the local zone, but the |
| 751 // InstructionOperand needs to go in the code zone, since it may survive |
| 752 // register allocation. |
| 753 return new (allocation_zone()) LiveRange(index, code_zone()); |
| 754 } |
| 755 |
| 756 |
| 757 bool RegisterAllocationData::ExistsUseWithoutDefinition() { |
| 758 bool found = false; |
| 759 BitVector::Iterator iterator(live_in_sets()[0]); |
| 760 while (!iterator.Done()) { |
| 761 found = true; |
| 762 int operand_index = iterator.Current(); |
| 763 PrintF("Register allocator error: live v%d reached first block.\n", |
| 764 operand_index); |
| 765 LiveRange* range = LiveRangeFor(operand_index); |
| 766 PrintF(" (first use is at %d)\n", range->first_pos()->pos().Value()); |
| 767 if (debug_name() == nullptr) { |
| 768 PrintF("\n"); |
| 769 } else { |
| 770 PrintF(" (function: %s)\n", debug_name()); |
| 933 } | 771 } |
| 934 } | 772 iterator.Advance(); |
| 935 | 773 } |
| 936 // Allocate slots for the merged spill ranges. | 774 return found; |
| 937 for (auto range : spill_ranges()) { | 775 } |
| 938 if (range->IsEmpty()) continue; | 776 |
| 939 // Allocate a new operand referring to the spill slot. | 777 |
| 940 auto kind = range->Kind(); | 778 SpillRange* RegisterAllocationData::AssignSpillRangeToLiveRange( |
| 941 int index = frame()->AllocateSpillSlot(kind == DOUBLE_REGISTERS); | 779 LiveRange* range) { |
| 942 auto op_kind = kind == DOUBLE_REGISTERS | 780 auto spill_range = |
| 943 ? AllocatedOperand::DOUBLE_STACK_SLOT | 781 new (allocation_zone()) SpillRange(range, allocation_zone()); |
| 944 : AllocatedOperand::STACK_SLOT; | |
| 945 auto op = AllocatedOperand::New(code_zone(), op_kind, index); | |
| 946 range->SetOperand(op); | |
| 947 } | |
| 948 } | |
| 949 | |
| 950 | |
| 951 void RegisterAllocator::CommitAssignment() { | |
| 952 for (auto range : live_ranges()) { | |
| 953 if (range == nullptr || range->IsEmpty()) continue; | |
| 954 InstructionOperand* spill_operand = nullptr; | |
| 955 if (!range->TopLevel()->HasNoSpillType()) { | |
| 956 spill_operand = range->TopLevel()->GetSpillOperand(); | |
| 957 } | |
| 958 auto assigned = range->GetAssignedOperand(); | |
| 959 range->ConvertUsesToOperand(assigned, spill_operand); | |
| 960 if (range->is_phi()) AssignPhiInput(range, assigned); | |
| 961 if (!range->IsChild() && spill_operand != nullptr) { | |
| 962 range->CommitSpillsAtDefinition(code(), spill_operand, | |
| 963 range->has_slot_use()); | |
| 964 } | |
| 965 } | |
| 966 } | |
| 967 | |
| 968 | |
| 969 SpillRange* RegisterAllocator::AssignSpillRangeToLiveRange(LiveRange* range) { | |
| 970 auto spill_range = new (local_zone()) SpillRange(range, local_zone()); | |
| 971 spill_ranges().push_back(spill_range); | 782 spill_ranges().push_back(spill_range); |
| 972 return spill_range; | 783 return spill_range; |
| 973 } | 784 } |
| 974 | 785 |
| 975 | 786 |
| 976 bool RegisterAllocator::TryReuseSpillForPhi(LiveRange* range) { | 787 void RegisterAllocationData::SetLiveRangeAssignedRegister(LiveRange* range, |
| 977 if (range->IsChild() || !range->is_phi()) return false; | 788 int reg) { |
| 978 DCHECK(!range->HasSpillOperand()); | 789 if (range->Kind() == DOUBLE_REGISTERS) { |
| 979 | 790 assigned_double_registers_->Add(reg); |
| 980 auto lookup = phi_map_.find(range->id()); | 791 } else { |
| 981 DCHECK(lookup != phi_map_.end()); | 792 DCHECK(range->Kind() == GENERAL_REGISTERS); |
| 982 auto phi = lookup->second->phi; | 793 assigned_registers_->Add(reg); |
| 983 auto block = lookup->second->block; | 794 } |
| 984 // Count the number of spilled operands. | 795 range->set_assigned_register(reg); |
| 985 size_t spilled_count = 0; | 796 auto assignment = range->GetAssignedOperand(); |
| 986 LiveRange* first_op = nullptr; | 797 // TODO(dcarney): stop aliasing hint operands. |
| 987 for (size_t i = 0; i < phi->operands().size(); i++) { | 798 range->ConvertUsesToOperand(assignment, nullptr); |
| 988 int op = phi->operands()[i]; | 799 if (range->is_phi()) AssignPhiInput(range, assignment); |
| 989 LiveRange* op_range = LiveRangeFor(op); | 800 } |
| 990 if (op_range->GetSpillRange() == nullptr) continue; | 801 |
| 991 auto pred = code()->InstructionBlockAt(block->predecessors()[i]); | 802 |
| 992 auto pred_end = LifetimePosition::InstructionFromInstructionIndex( | 803 LiveRangeBuilder::LiveRangeBuilder(RegisterAllocationData* data) |
| 993 pred->last_instruction_index()); | 804 : data_(data) {} |
| 994 while (op_range != nullptr && !op_range->CanCover(pred_end)) { | 805 |
| 995 op_range = op_range->next(); | 806 |
| 807 BitVector* LiveRangeBuilder::ComputeLiveOut(const InstructionBlock* block) { |
| 808 // Compute live out for the given block, except not including backward |
| 809 // successor edges. |
| 810 auto live_out = new (allocation_zone()) |
| 811 BitVector(code()->VirtualRegisterCount(), allocation_zone()); |
| 812 |
| 813 // Process all successor blocks. |
| 814 for (auto succ : block->successors()) { |
| 815 // Add values live on entry to the successor. Note the successor's |
| 816 // live_in will not be computed yet for backwards edges. |
| 817 auto live_in = live_in_sets()[succ.ToSize()]; |
| 818 if (live_in != nullptr) live_out->Union(*live_in); |
| 819 |
| 820 // All phi input operands corresponding to this successor edge are live |
| 821 // out from this block. |
| 822 auto successor = code()->InstructionBlockAt(succ); |
| 823 size_t index = successor->PredecessorIndexOf(block->rpo_number()); |
| 824 DCHECK(index < successor->PredecessorCount()); |
| 825 for (auto phi : successor->phis()) { |
| 826 live_out->Add(phi->operands()[index]); |
| 996 } | 827 } |
| 997 if (op_range != nullptr && op_range->IsSpilled()) { | 828 } |
| 998 spilled_count++; | 829 return live_out; |
| 999 if (first_op == nullptr) { | 830 } |
| 1000 first_op = op_range->TopLevel(); | 831 |
| 1001 } | 832 |
| 833 void LiveRangeBuilder::AddInitialIntervals(const InstructionBlock* block, |
| 834 BitVector* live_out) { |
| 835 // Add an interval that includes the entire block to the live range for |
| 836 // each live_out value. |
| 837 auto start = LifetimePosition::GapFromInstructionIndex( |
| 838 block->first_instruction_index()); |
| 839 auto end = LifetimePosition::InstructionFromInstructionIndex( |
| 840 block->last_instruction_index()).NextStart(); |
| 841 BitVector::Iterator iterator(live_out); |
| 842 while (!iterator.Done()) { |
| 843 int operand_index = iterator.Current(); |
| 844 auto range = LiveRangeFor(operand_index); |
| 845 range->AddUseInterval(start, end, allocation_zone()); |
| 846 iterator.Advance(); |
| 847 } |
| 848 } |
| 849 |
| 850 |
| 851 Instruction* LiveRangeBuilder::GetLastInstruction( |
| 852 const InstructionBlock* block) { |
| 853 return code()->InstructionAt(block->last_instruction_index()); |
| 854 } |
| 855 |
| 856 |
| 857 int LiveRangeBuilder::FixedDoubleLiveRangeID(int index) { |
| 858 return -index - 1 - config()->num_general_registers(); |
| 859 } |
| 860 |
| 861 |
| 862 InstructionOperand* LiveRangeBuilder::AllocateFixed(UnallocatedOperand* operand, |
| 863 int pos, bool is_tagged) { |
| 864 TRACE("Allocating fixed reg for op %d\n", operand->virtual_register()); |
| 865 DCHECK(operand->HasFixedPolicy()); |
| 866 InstructionOperand allocated; |
| 867 if (operand->HasFixedSlotPolicy()) { |
| 868 allocated = AllocatedOperand(AllocatedOperand::STACK_SLOT, |
| 869 operand->fixed_slot_index()); |
| 870 } else if (operand->HasFixedRegisterPolicy()) { |
| 871 allocated = AllocatedOperand(AllocatedOperand::REGISTER, |
| 872 operand->fixed_register_index()); |
| 873 } else if (operand->HasFixedDoubleRegisterPolicy()) { |
| 874 allocated = AllocatedOperand(AllocatedOperand::DOUBLE_REGISTER, |
| 875 operand->fixed_register_index()); |
| 876 } else { |
| 877 UNREACHABLE(); |
| 878 } |
| 879 InstructionOperand::ReplaceWith(operand, &allocated); |
| 880 if (is_tagged) { |
| 881 TRACE("Fixed reg is tagged at %d\n", pos); |
| 882 auto instr = InstructionAt(pos); |
| 883 if (instr->HasReferenceMap()) { |
| 884 instr->reference_map()->RecordReference(*operand); |
| 1002 } | 885 } |
| 1003 } | 886 } |
| 1004 | 887 return operand; |
| 1005 // Only continue if more than half of the operands are spilled. | 888 } |
| 1006 if (spilled_count * 2 <= phi->operands().size()) { | 889 |
| 1007 return false; | 890 |
| 1008 } | 891 LiveRange* LiveRangeBuilder::FixedLiveRangeFor(int index) { |
| 1009 | 892 DCHECK(index < config()->num_general_registers()); |
| 1010 // Try to merge the spilled operands and count the number of merged spilled | 893 auto result = fixed_live_ranges()[index]; |
| 1011 // operands. | 894 if (result == nullptr) { |
| 1012 DCHECK(first_op != nullptr); | 895 result = data()->NewLiveRange(FixedLiveRangeID(index)); |
| 1013 auto first_op_spill = first_op->GetSpillRange(); | 896 DCHECK(result->IsFixed()); |
| 1014 size_t num_merged = 1; | 897 result->set_kind(GENERAL_REGISTERS); |
| 1015 for (size_t i = 1; i < phi->operands().size(); i++) { | 898 data()->SetLiveRangeAssignedRegister(result, index); |
| 1016 int op = phi->operands()[i]; | 899 fixed_live_ranges()[index] = result; |
| 1017 auto op_range = LiveRangeFor(op); | 900 } |
| 1018 auto op_spill = op_range->GetSpillRange(); | 901 return result; |
| 1019 if (op_spill != nullptr && | 902 } |
| 1020 (op_spill == first_op_spill || first_op_spill->TryMerge(op_spill))) { | 903 |
| 1021 num_merged++; | 904 |
| 1022 } | 905 LiveRange* LiveRangeBuilder::FixedDoubleLiveRangeFor(int index) { |
| 1023 } | 906 DCHECK(index < config()->num_aliased_double_registers()); |
| 1024 | 907 auto result = fixed_double_live_ranges()[index]; |
| 1025 // Only continue if enough operands could be merged to the | 908 if (result == nullptr) { |
| 1026 // same spill slot. | 909 result = data()->NewLiveRange(FixedDoubleLiveRangeID(index)); |
| 1027 if (num_merged * 2 <= phi->operands().size() || | 910 DCHECK(result->IsFixed()); |
| 1028 AreUseIntervalsIntersecting(first_op_spill->interval(), | 911 result->set_kind(DOUBLE_REGISTERS); |
| 1029 range->first_interval())) { | 912 data()->SetLiveRangeAssignedRegister(result, index); |
| 1030 return false; | 913 fixed_double_live_ranges()[index] = result; |
| 1031 } | 914 } |
| 1032 | 915 return result; |
| 1033 // If the range does not need register soon, spill it to the merged | 916 } |
| 1034 // spill range. | 917 |
| 1035 auto next_pos = range->Start(); | 918 |
| 1036 if (next_pos.IsGapPosition()) next_pos = next_pos.NextStart(); | 919 LiveRange* LiveRangeBuilder::LiveRangeFor(InstructionOperand* operand) { |
| 1037 auto pos = range->NextUsePositionRegisterIsBeneficial(next_pos); | 920 if (operand->IsUnallocated()) { |
| 1038 if (pos == nullptr) { | 921 return LiveRangeFor(UnallocatedOperand::cast(operand)->virtual_register()); |
| 1039 auto spill_range = range->TopLevel()->HasSpillRange() | 922 } else if (operand->IsConstant()) { |
| 1040 ? range->TopLevel()->GetSpillRange() | 923 return LiveRangeFor(ConstantOperand::cast(operand)->virtual_register()); |
| 1041 : AssignSpillRangeToLiveRange(range->TopLevel()); | 924 } else if (operand->IsRegister()) { |
| 1042 CHECK(first_op_spill->TryMerge(spill_range)); | 925 return FixedLiveRangeFor(RegisterOperand::cast(operand)->index()); |
| 1043 Spill(range); | 926 } else if (operand->IsDoubleRegister()) { |
| 1044 return true; | 927 return FixedDoubleLiveRangeFor( |
| 1045 } else if (pos->pos().Value() > range->Start().NextStart().Value()) { | 928 DoubleRegisterOperand::cast(operand)->index()); |
| 1046 auto spill_range = range->TopLevel()->HasSpillRange() | 929 } else { |
| 1047 ? range->TopLevel()->GetSpillRange() | 930 return nullptr; |
| 1048 : AssignSpillRangeToLiveRange(range->TopLevel()); | 931 } |
| 1049 CHECK(first_op_spill->TryMerge(spill_range)); | 932 } |
| 1050 SpillBetween(range, range->Start(), pos->pos()); | 933 |
| 1051 DCHECK(UnhandledIsSorted()); | 934 |
| 1052 return true; | 935 void LiveRangeBuilder::Define(LifetimePosition position, |
| 1053 } | 936 InstructionOperand* operand, |
| 1054 return false; | 937 InstructionOperand* hint) { |
| 1055 } | 938 auto range = LiveRangeFor(operand); |
| 1056 | 939 if (range == nullptr) return; |
| 1057 | 940 |
| 1058 void RegisterAllocator::MeetRegisterConstraints(const InstructionBlock* block) { | 941 if (range->IsEmpty() || range->Start().Value() > position.Value()) { |
| 942 // Can happen if there is a definition without use. |
| 943 range->AddUseInterval(position, position.NextStart(), allocation_zone()); |
| 944 range->AddUsePosition(position.NextStart(), nullptr, nullptr, |
| 945 allocation_zone()); |
| 946 } else { |
| 947 range->ShortenTo(position); |
| 948 } |
| 949 |
| 950 if (operand->IsUnallocated()) { |
| 951 auto unalloc_operand = UnallocatedOperand::cast(operand); |
| 952 range->AddUsePosition(position, unalloc_operand, hint, allocation_zone()); |
| 953 } |
| 954 } |
| 955 |
| 956 |
| 957 void LiveRangeBuilder::Use(LifetimePosition block_start, |
| 958 LifetimePosition position, |
| 959 InstructionOperand* operand, |
| 960 InstructionOperand* hint) { |
| 961 auto range = LiveRangeFor(operand); |
| 962 if (range == nullptr) return; |
| 963 if (operand->IsUnallocated()) { |
| 964 UnallocatedOperand* unalloc_operand = UnallocatedOperand::cast(operand); |
| 965 range->AddUsePosition(position, unalloc_operand, hint, allocation_zone()); |
| 966 } |
| 967 range->AddUseInterval(block_start, position, allocation_zone()); |
| 968 } |
| 969 |
| 970 |
| 971 void LiveRangeBuilder::MeetRegisterConstraints(const InstructionBlock* block) { |
| 1059 int start = block->first_instruction_index(); | 972 int start = block->first_instruction_index(); |
| 1060 int end = block->last_instruction_index(); | 973 int end = block->last_instruction_index(); |
| 1061 DCHECK_NE(-1, start); | 974 DCHECK_NE(-1, start); |
| 1062 for (int i = start; i <= end; ++i) { | 975 for (int i = start; i <= end; ++i) { |
| 1063 MeetConstraintsBefore(i); | 976 MeetConstraintsBefore(i); |
| 1064 if (i != end) MeetConstraintsAfter(i); | 977 if (i != end) MeetConstraintsAfter(i); |
| 1065 } | 978 } |
| 1066 // Meet register constraints for the instruction in the end. | 979 // Meet register constraints for the instruction in the end. |
| 1067 MeetRegisterConstraintsForLastInstructionInBlock(block); | 980 MeetRegisterConstraintsForLastInstructionInBlock(block); |
| 1068 } | 981 } |
| 1069 | 982 |
| 1070 | 983 |
| 1071 void RegisterAllocator::MeetRegisterConstraintsForLastInstructionInBlock( | 984 void LiveRangeBuilder::MeetRegisterConstraintsForLastInstructionInBlock( |
| 1072 const InstructionBlock* block) { | 985 const InstructionBlock* block) { |
| 1073 int end = block->last_instruction_index(); | 986 int end = block->last_instruction_index(); |
| 1074 auto last_instruction = InstructionAt(end); | 987 auto last_instruction = InstructionAt(end); |
| 1075 for (size_t i = 0; i < last_instruction->OutputCount(); i++) { | 988 for (size_t i = 0; i < last_instruction->OutputCount(); i++) { |
| 1076 auto output_operand = last_instruction->OutputAt(i); | 989 auto output_operand = last_instruction->OutputAt(i); |
| 1077 DCHECK(!output_operand->IsConstant()); | 990 DCHECK(!output_operand->IsConstant()); |
| 1078 auto output = UnallocatedOperand::cast(output_operand); | 991 auto output = UnallocatedOperand::cast(output_operand); |
| 1079 int output_vreg = output->virtual_register(); | 992 int output_vreg = output->virtual_register(); |
| 1080 auto range = LiveRangeFor(output_vreg); | 993 auto range = LiveRangeFor(output_vreg); |
| 1081 bool assigned = false; | 994 bool assigned = false; |
| 1082 if (output->HasFixedPolicy()) { | 995 if (output->HasFixedPolicy()) { |
| 1083 AllocateFixed(output, -1, false); | 996 AllocateFixed(output, -1, false); |
| 1084 // This value is produced on the stack, we never need to spill it. | 997 // This value is produced on the stack, we never need to spill it. |
| 1085 if (output->IsStackSlot()) { | 998 if (output->IsStackSlot()) { |
| 1086 DCHECK(StackSlotOperand::cast(output)->index() < | 999 DCHECK(StackSlotOperand::cast(output)->index() < |
| 1087 frame_->GetSpillSlotCount()); | 1000 data()->frame()->GetSpillSlotCount()); |
| 1088 range->SetSpillOperand(StackSlotOperand::cast(output)); | 1001 range->SetSpillOperand(StackSlotOperand::cast(output)); |
| 1089 range->SetSpillStartIndex(end); | 1002 range->SetSpillStartIndex(end); |
| 1090 assigned = true; | 1003 assigned = true; |
| 1091 } | 1004 } |
| 1092 | 1005 |
| 1093 for (auto succ : block->successors()) { | 1006 for (auto succ : block->successors()) { |
| 1094 const InstructionBlock* successor = code()->InstructionBlockAt(succ); | 1007 const InstructionBlock* successor = code()->InstructionBlockAt(succ); |
| 1095 DCHECK(successor->PredecessorCount() == 1); | 1008 DCHECK(successor->PredecessorCount() == 1); |
| 1096 int gap_index = successor->first_instruction_index(); | 1009 int gap_index = successor->first_instruction_index(); |
| 1097 // Create an unconstrained operand for the same virtual register | 1010 // Create an unconstrained operand for the same virtual register |
| 1098 // and insert a gap move from the fixed output to the operand. | 1011 // and insert a gap move from the fixed output to the operand. |
| 1099 UnallocatedOperand output_copy(UnallocatedOperand::ANY, output_vreg); | 1012 UnallocatedOperand output_copy(UnallocatedOperand::ANY, output_vreg); |
| 1100 AddGapMove(gap_index, Instruction::START, *output, output_copy); | 1013 data()->AddGapMove(gap_index, Instruction::START, *output, output_copy); |
| 1101 } | 1014 } |
| 1102 } | 1015 } |
| 1103 | 1016 |
| 1104 if (!assigned) { | 1017 if (!assigned) { |
| 1105 for (auto succ : block->successors()) { | 1018 for (auto succ : block->successors()) { |
| 1106 const InstructionBlock* successor = code()->InstructionBlockAt(succ); | 1019 const InstructionBlock* successor = code()->InstructionBlockAt(succ); |
| 1107 DCHECK(successor->PredecessorCount() == 1); | 1020 DCHECK(successor->PredecessorCount() == 1); |
| 1108 int gap_index = successor->first_instruction_index(); | 1021 int gap_index = successor->first_instruction_index(); |
| 1109 range->SpillAtDefinition(local_zone(), gap_index, output); | 1022 range->SpillAtDefinition(allocation_zone(), gap_index, output); |
| 1110 range->SetSpillStartIndex(gap_index); | 1023 range->SetSpillStartIndex(gap_index); |
| 1111 } | 1024 } |
| 1112 } | 1025 } |
| 1113 } | 1026 } |
| 1114 } | 1027 } |
| 1115 | 1028 |
| 1116 | 1029 |
| 1117 void RegisterAllocator::MeetConstraintsAfter(int instr_index) { | 1030 void LiveRangeBuilder::MeetConstraintsAfter(int instr_index) { |
| 1118 auto first = InstructionAt(instr_index); | 1031 auto first = InstructionAt(instr_index); |
| 1119 // Handle fixed temporaries. | 1032 // Handle fixed temporaries. |
| 1120 for (size_t i = 0; i < first->TempCount(); i++) { | 1033 for (size_t i = 0; i < first->TempCount(); i++) { |
| 1121 auto temp = UnallocatedOperand::cast(first->TempAt(i)); | 1034 auto temp = UnallocatedOperand::cast(first->TempAt(i)); |
| 1122 if (temp->HasFixedPolicy()) AllocateFixed(temp, instr_index, false); | 1035 if (temp->HasFixedPolicy()) AllocateFixed(temp, instr_index, false); |
| 1123 } | 1036 } |
| 1124 // Handle constant/fixed output operands. | 1037 // Handle constant/fixed output operands. |
| 1125 for (size_t i = 0; i < first->OutputCount(); i++) { | 1038 for (size_t i = 0; i < first->OutputCount(); i++) { |
| 1126 InstructionOperand* output = first->OutputAt(i); | 1039 InstructionOperand* output = first->OutputAt(i); |
| 1127 if (output->IsConstant()) { | 1040 if (output->IsConstant()) { |
| 1128 int output_vreg = ConstantOperand::cast(output)->virtual_register(); | 1041 int output_vreg = ConstantOperand::cast(output)->virtual_register(); |
| 1129 auto range = LiveRangeFor(output_vreg); | 1042 auto range = LiveRangeFor(output_vreg); |
| 1130 range->SetSpillStartIndex(instr_index + 1); | 1043 range->SetSpillStartIndex(instr_index + 1); |
| 1131 range->SetSpillOperand(output); | 1044 range->SetSpillOperand(output); |
| 1132 continue; | 1045 continue; |
| 1133 } | 1046 } |
| 1134 auto first_output = UnallocatedOperand::cast(output); | 1047 auto first_output = UnallocatedOperand::cast(output); |
| 1135 auto range = LiveRangeFor(first_output->virtual_register()); | 1048 auto range = LiveRangeFor(first_output->virtual_register()); |
| 1136 bool assigned = false; | 1049 bool assigned = false; |
| 1137 if (first_output->HasFixedPolicy()) { | 1050 if (first_output->HasFixedPolicy()) { |
| 1138 int output_vreg = first_output->virtual_register(); | 1051 int output_vreg = first_output->virtual_register(); |
| 1139 UnallocatedOperand output_copy(UnallocatedOperand::ANY, output_vreg); | 1052 UnallocatedOperand output_copy(UnallocatedOperand::ANY, output_vreg); |
| 1140 bool is_tagged = HasTaggedValue(output_vreg); | 1053 bool is_tagged = IsReference(output_vreg); |
| 1141 AllocateFixed(first_output, instr_index, is_tagged); | 1054 AllocateFixed(first_output, instr_index, is_tagged); |
| 1142 | 1055 |
| 1143 // This value is produced on the stack, we never need to spill it. | 1056 // This value is produced on the stack, we never need to spill it. |
| 1144 if (first_output->IsStackSlot()) { | 1057 if (first_output->IsStackSlot()) { |
| 1145 DCHECK(StackSlotOperand::cast(first_output)->index() < | 1058 DCHECK(StackSlotOperand::cast(first_output)->index() < |
| 1146 frame_->GetSpillSlotCount()); | 1059 data()->frame()->GetSpillSlotCount()); |
| 1147 range->SetSpillOperand(StackSlotOperand::cast(first_output)); | 1060 range->SetSpillOperand(StackSlotOperand::cast(first_output)); |
| 1148 range->SetSpillStartIndex(instr_index + 1); | 1061 range->SetSpillStartIndex(instr_index + 1); |
| 1149 assigned = true; | 1062 assigned = true; |
| 1150 } | 1063 } |
| 1151 AddGapMove(instr_index + 1, Instruction::START, *first_output, | 1064 data()->AddGapMove(instr_index + 1, Instruction::START, *first_output, |
| 1152 output_copy); | 1065 output_copy); |
| 1153 } | 1066 } |
| 1154 // Make sure we add a gap move for spilling (if we have not done | 1067 // Make sure we add a gap move for spilling (if we have not done |
| 1155 // so already). | 1068 // so already). |
| 1156 if (!assigned) { | 1069 if (!assigned) { |
| 1157 range->SpillAtDefinition(local_zone(), instr_index + 1, first_output); | 1070 range->SpillAtDefinition(allocation_zone(), instr_index + 1, |
| 1071 first_output); |
| 1158 range->SetSpillStartIndex(instr_index + 1); | 1072 range->SetSpillStartIndex(instr_index + 1); |
| 1159 } | 1073 } |
| 1160 } | 1074 } |
| 1161 } | 1075 } |
| 1162 | 1076 |
| 1163 | 1077 |
| 1164 void RegisterAllocator::MeetConstraintsBefore(int instr_index) { | 1078 void LiveRangeBuilder::MeetConstraintsBefore(int instr_index) { |
| 1165 auto second = InstructionAt(instr_index); | 1079 auto second = InstructionAt(instr_index); |
| 1166 // Handle fixed input operands of second instruction. | 1080 // Handle fixed input operands of second instruction. |
| 1167 for (size_t i = 0; i < second->InputCount(); i++) { | 1081 for (size_t i = 0; i < second->InputCount(); i++) { |
| 1168 auto input = second->InputAt(i); | 1082 auto input = second->InputAt(i); |
| 1169 if (input->IsImmediate()) continue; // Ignore immediates. | 1083 if (input->IsImmediate()) continue; // Ignore immediates. |
| 1170 auto cur_input = UnallocatedOperand::cast(input); | 1084 auto cur_input = UnallocatedOperand::cast(input); |
| 1171 if (cur_input->HasFixedPolicy()) { | 1085 if (cur_input->HasFixedPolicy()) { |
| 1172 int input_vreg = cur_input->virtual_register(); | 1086 int input_vreg = cur_input->virtual_register(); |
| 1173 UnallocatedOperand input_copy(UnallocatedOperand::ANY, input_vreg); | 1087 UnallocatedOperand input_copy(UnallocatedOperand::ANY, input_vreg); |
| 1174 bool is_tagged = HasTaggedValue(input_vreg); | 1088 bool is_tagged = IsReference(input_vreg); |
| 1175 AllocateFixed(cur_input, instr_index, is_tagged); | 1089 AllocateFixed(cur_input, instr_index, is_tagged); |
| 1176 AddGapMove(instr_index, Instruction::END, input_copy, *cur_input); | 1090 data()->AddGapMove(instr_index, Instruction::END, input_copy, *cur_input); |
| 1177 } | 1091 } |
| 1178 } | 1092 } |
| 1179 // Handle "output same as input" for second instruction. | 1093 // Handle "output same as input" for second instruction. |
| 1180 for (size_t i = 0; i < second->OutputCount(); i++) { | 1094 for (size_t i = 0; i < second->OutputCount(); i++) { |
| 1181 auto output = second->OutputAt(i); | 1095 auto output = second->OutputAt(i); |
| 1182 if (!output->IsUnallocated()) continue; | 1096 if (!output->IsUnallocated()) continue; |
| 1183 auto second_output = UnallocatedOperand::cast(output); | 1097 auto second_output = UnallocatedOperand::cast(output); |
| 1184 if (!second_output->HasSameAsInputPolicy()) continue; | 1098 if (!second_output->HasSameAsInputPolicy()) continue; |
| 1185 DCHECK(i == 0); // Only valid for first output. | 1099 DCHECK(i == 0); // Only valid for first output. |
| 1186 UnallocatedOperand* cur_input = | 1100 UnallocatedOperand* cur_input = |
| 1187 UnallocatedOperand::cast(second->InputAt(0)); | 1101 UnallocatedOperand::cast(second->InputAt(0)); |
| 1188 int output_vreg = second_output->virtual_register(); | 1102 int output_vreg = second_output->virtual_register(); |
| 1189 int input_vreg = cur_input->virtual_register(); | 1103 int input_vreg = cur_input->virtual_register(); |
| 1190 UnallocatedOperand input_copy(UnallocatedOperand::ANY, input_vreg); | 1104 UnallocatedOperand input_copy(UnallocatedOperand::ANY, input_vreg); |
| 1191 cur_input->set_virtual_register(second_output->virtual_register()); | 1105 cur_input->set_virtual_register(second_output->virtual_register()); |
| 1192 AddGapMove(instr_index, Instruction::END, input_copy, *cur_input); | 1106 data()->AddGapMove(instr_index, Instruction::END, input_copy, *cur_input); |
| 1193 if (HasTaggedValue(input_vreg) && !HasTaggedValue(output_vreg)) { | 1107 if (IsReference(input_vreg) && !IsReference(output_vreg)) { |
| 1194 if (second->HasReferenceMap()) { | 1108 if (second->HasReferenceMap()) { |
| 1195 second->reference_map()->RecordReference(input_copy); | 1109 second->reference_map()->RecordReference(input_copy); |
| 1196 } | 1110 } |
| 1197 } else if (!HasTaggedValue(input_vreg) && HasTaggedValue(output_vreg)) { | 1111 } else if (!IsReference(input_vreg) && IsReference(output_vreg)) { |
| 1198 // The input is assumed to immediately have a tagged representation, | 1112 // The input is assumed to immediately have a tagged representation, |
| 1199 // before the pointer map can be used. I.e. the pointer map at the | 1113 // before the pointer map can be used. I.e. the pointer map at the |
| 1200 // instruction will include the output operand (whose value at the | 1114 // instruction will include the output operand (whose value at the |
| 1201 // beginning of the instruction is equal to the input operand). If | 1115 // beginning of the instruction is equal to the input operand). If |
| 1202 // this is not desired, then the pointer map at this instruction needs | 1116 // this is not desired, then the pointer map at this instruction needs |
| 1203 // to be adjusted manually. | 1117 // to be adjusted manually. |
| 1204 } | 1118 } |
| 1205 } | 1119 } |
| 1206 } | 1120 } |
| 1207 | 1121 |
| 1208 | 1122 |
| 1209 bool RegisterAllocator::IsOutputRegisterOf(Instruction* instr, int index) { | 1123 bool LiveRangeBuilder::IsOutputRegisterOf(Instruction* instr, int index) { |
| 1210 for (size_t i = 0; i < instr->OutputCount(); i++) { | 1124 for (size_t i = 0; i < instr->OutputCount(); i++) { |
| 1211 auto output = instr->OutputAt(i); | 1125 auto output = instr->OutputAt(i); |
| 1212 if (output->IsRegister() && RegisterOperand::cast(output)->index() == index) | 1126 if (output->IsRegister() && RegisterOperand::cast(output)->index() == index) |
| 1213 return true; | 1127 return true; |
| 1214 } | 1128 } |
| 1215 return false; | 1129 return false; |
| 1216 } | 1130 } |
| 1217 | 1131 |
| 1218 | 1132 |
| 1219 bool RegisterAllocator::IsOutputDoubleRegisterOf(Instruction* instr, | 1133 bool LiveRangeBuilder::IsOutputDoubleRegisterOf(Instruction* instr, int index) { |
| 1220 int index) { | |
| 1221 for (size_t i = 0; i < instr->OutputCount(); i++) { | 1134 for (size_t i = 0; i < instr->OutputCount(); i++) { |
| 1222 auto output = instr->OutputAt(i); | 1135 auto output = instr->OutputAt(i); |
| 1223 if (output->IsDoubleRegister() && | 1136 if (output->IsDoubleRegister() && |
| 1224 DoubleRegisterOperand::cast(output)->index() == index) | 1137 DoubleRegisterOperand::cast(output)->index() == index) |
| 1225 return true; | 1138 return true; |
| 1226 } | 1139 } |
| 1227 return false; | 1140 return false; |
| 1228 } | 1141 } |
| 1229 | 1142 |
| 1230 | 1143 |
| 1231 void RegisterAllocator::ProcessInstructions(const InstructionBlock* block, | 1144 void LiveRangeBuilder::ProcessInstructions(const InstructionBlock* block, |
| 1232 BitVector* live) { | 1145 BitVector* live) { |
| 1233 int block_start = block->first_instruction_index(); | 1146 int block_start = block->first_instruction_index(); |
| 1234 auto block_start_position = | 1147 auto block_start_position = |
| 1235 LifetimePosition::GapFromInstructionIndex(block_start); | 1148 LifetimePosition::GapFromInstructionIndex(block_start); |
| 1236 | 1149 |
| 1237 for (int index = block->last_instruction_index(); index >= block_start; | 1150 for (int index = block->last_instruction_index(); index >= block_start; |
| 1238 index--) { | 1151 index--) { |
| 1239 auto curr_position = | 1152 auto curr_position = |
| 1240 LifetimePosition::InstructionFromInstructionIndex(index); | 1153 LifetimePosition::InstructionFromInstructionIndex(index); |
| 1241 auto instr = InstructionAt(index); | 1154 auto instr = InstructionAt(index); |
| 1242 DCHECK(instr != nullptr); | 1155 DCHECK(instr != nullptr); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1254 live->Remove(out_vreg); | 1167 live->Remove(out_vreg); |
| 1255 } | 1168 } |
| 1256 Define(curr_position, output, nullptr); | 1169 Define(curr_position, output, nullptr); |
| 1257 } | 1170 } |
| 1258 | 1171 |
| 1259 if (instr->ClobbersRegisters()) { | 1172 if (instr->ClobbersRegisters()) { |
| 1260 for (int i = 0; i < config()->num_general_registers(); ++i) { | 1173 for (int i = 0; i < config()->num_general_registers(); ++i) { |
| 1261 if (!IsOutputRegisterOf(instr, i)) { | 1174 if (!IsOutputRegisterOf(instr, i)) { |
| 1262 auto range = FixedLiveRangeFor(i); | 1175 auto range = FixedLiveRangeFor(i); |
| 1263 range->AddUseInterval(curr_position, curr_position.End(), | 1176 range->AddUseInterval(curr_position, curr_position.End(), |
| 1264 local_zone()); | 1177 allocation_zone()); |
| 1265 } | 1178 } |
| 1266 } | 1179 } |
| 1267 } | 1180 } |
| 1268 | 1181 |
| 1269 if (instr->ClobbersDoubleRegisters()) { | 1182 if (instr->ClobbersDoubleRegisters()) { |
| 1270 for (int i = 0; i < config()->num_aliased_double_registers(); ++i) { | 1183 for (int i = 0; i < config()->num_aliased_double_registers(); ++i) { |
| 1271 if (!IsOutputDoubleRegisterOf(instr, i)) { | 1184 if (!IsOutputDoubleRegisterOf(instr, i)) { |
| 1272 auto range = FixedDoubleLiveRangeFor(i); | 1185 auto range = FixedDoubleLiveRangeFor(i); |
| 1273 range->AddUseInterval(curr_position, curr_position.End(), | 1186 range->AddUseInterval(curr_position, curr_position.End(), |
| 1274 local_zone()); | 1187 allocation_zone()); |
| 1275 } | 1188 } |
| 1276 } | 1189 } |
| 1277 } | 1190 } |
| 1278 | 1191 |
| 1279 for (size_t i = 0; i < instr->InputCount(); i++) { | 1192 for (size_t i = 0; i < instr->InputCount(); i++) { |
| 1280 auto input = instr->InputAt(i); | 1193 auto input = instr->InputAt(i); |
| 1281 if (input->IsImmediate()) continue; // Ignore immediates. | 1194 if (input->IsImmediate()) continue; // Ignore immediates. |
| 1282 LifetimePosition use_pos; | 1195 LifetimePosition use_pos; |
| 1283 if (input->IsUnallocated() && | 1196 if (input->IsUnallocated() && |
| 1284 UnallocatedOperand::cast(input)->IsUsedAtStart()) { | 1197 UnallocatedOperand::cast(input)->IsUsedAtStart()) { |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1355 Use(block_start_position, curr_position, &from, hint); | 1268 Use(block_start_position, curr_position, &from, hint); |
| 1356 if (from.IsUnallocated()) { | 1269 if (from.IsUnallocated()) { |
| 1357 live->Add(UnallocatedOperand::cast(from).virtual_register()); | 1270 live->Add(UnallocatedOperand::cast(from).virtual_register()); |
| 1358 } | 1271 } |
| 1359 } | 1272 } |
| 1360 } | 1273 } |
| 1361 } | 1274 } |
| 1362 } | 1275 } |
| 1363 | 1276 |
| 1364 | 1277 |
| 1365 void RegisterAllocator::ResolvePhis(const InstructionBlock* block) { | 1278 void LiveRangeBuilder::ResolvePhis(const InstructionBlock* block) { |
| 1366 for (auto phi : block->phis()) { | 1279 for (auto phi : block->phis()) { |
| 1367 int phi_vreg = phi->virtual_register(); | 1280 int phi_vreg = phi->virtual_register(); |
| 1368 auto map_value = new (local_zone()) PhiMapValue(phi, block, local_zone()); | 1281 auto map_value = new (allocation_zone()) |
| 1369 auto res = phi_map_.insert(std::make_pair(phi_vreg, map_value)); | 1282 RegisterAllocationData::PhiMapValue(phi, block, allocation_zone()); |
| 1283 auto res = phi_map().insert(std::make_pair(phi_vreg, map_value)); |
| 1370 DCHECK(res.second); | 1284 DCHECK(res.second); |
| 1371 USE(res); | 1285 USE(res); |
| 1372 auto& output = phi->output(); | 1286 auto& output = phi->output(); |
| 1373 for (size_t i = 0; i < phi->operands().size(); ++i) { | 1287 for (size_t i = 0; i < phi->operands().size(); ++i) { |
| 1374 InstructionBlock* cur_block = | 1288 InstructionBlock* cur_block = |
| 1375 code()->InstructionBlockAt(block->predecessors()[i]); | 1289 code()->InstructionBlockAt(block->predecessors()[i]); |
| 1376 UnallocatedOperand input(UnallocatedOperand::ANY, phi->operands()[i]); | 1290 UnallocatedOperand input(UnallocatedOperand::ANY, phi->operands()[i]); |
| 1377 auto move = AddGapMove(cur_block->last_instruction_index(), | 1291 auto move = data()->AddGapMove(cur_block->last_instruction_index(), |
| 1378 Instruction::END, input, output); | 1292 Instruction::END, input, output); |
| 1379 map_value->incoming_moves.push_back(move); | 1293 map_value->incoming_moves.push_back(move); |
| 1380 DCHECK(!InstructionAt(cur_block->last_instruction_index()) | 1294 DCHECK(!InstructionAt(cur_block->last_instruction_index()) |
| 1381 ->HasReferenceMap()); | 1295 ->HasReferenceMap()); |
| 1382 } | 1296 } |
| 1383 auto live_range = LiveRangeFor(phi_vreg); | 1297 auto live_range = LiveRangeFor(phi_vreg); |
| 1384 int gap_index = block->first_instruction_index(); | 1298 int gap_index = block->first_instruction_index(); |
| 1385 live_range->SpillAtDefinition(local_zone(), gap_index, &output); | 1299 live_range->SpillAtDefinition(allocation_zone(), gap_index, &output); |
| 1386 live_range->SetSpillStartIndex(gap_index); | 1300 live_range->SetSpillStartIndex(gap_index); |
| 1387 // We use the phi-ness of some nodes in some later heuristics. | 1301 // We use the phi-ness of some nodes in some later heuristics. |
| 1388 live_range->set_is_phi(true); | 1302 live_range->set_is_phi(true); |
| 1389 live_range->set_is_non_loop_phi(!block->IsLoopHeader()); | 1303 live_range->set_is_non_loop_phi(!block->IsLoopHeader()); |
| 1390 } | 1304 } |
| 1391 } | 1305 } |
| 1392 | 1306 |
| 1393 | 1307 |
| 1394 void RegisterAllocator::AssignPhiInput(LiveRange* range, | 1308 void LiveRangeBuilder::MeetRegisterConstraints() { |
| 1395 const InstructionOperand& assignment) { | |
| 1396 DCHECK(range->is_phi()); | |
| 1397 auto it = phi_map_.find(range->id()); | |
| 1398 DCHECK(it != phi_map_.end()); | |
| 1399 for (auto move : it->second->incoming_moves) { | |
| 1400 move->set_destination(assignment); | |
| 1401 } | |
| 1402 } | |
| 1403 | |
| 1404 | |
| 1405 void RegisterAllocator::MeetRegisterConstraints() { | |
| 1406 for (auto block : code()->instruction_blocks()) { | 1309 for (auto block : code()->instruction_blocks()) { |
| 1407 MeetRegisterConstraints(block); | 1310 MeetRegisterConstraints(block); |
| 1408 } | 1311 } |
| 1409 } | 1312 } |
| 1410 | 1313 |
| 1411 | 1314 |
| 1412 void RegisterAllocator::ResolvePhis() { | 1315 void LiveRangeBuilder::ResolvePhis() { |
| 1413 // Process the blocks in reverse order. | 1316 // Process the blocks in reverse order. |
| 1414 for (auto i = code()->instruction_blocks().rbegin(); | 1317 for (auto i = code()->instruction_blocks().rbegin(); |
| 1415 i != code()->instruction_blocks().rend(); ++i) { | 1318 i != code()->instruction_blocks().rend(); ++i) { |
| 1416 ResolvePhis(*i); | 1319 ResolvePhis(*i); |
| 1417 } | 1320 } |
| 1418 } | 1321 } |
| 1419 | 1322 |
| 1420 | 1323 |
| 1421 const InstructionBlock* RegisterAllocator::GetInstructionBlock( | 1324 void LiveRangeBuilder::BuildLiveRanges() { |
| 1422 LifetimePosition pos) { | |
| 1423 return code()->GetInstructionBlock(pos.ToInstructionIndex()); | |
| 1424 } | |
| 1425 | |
| 1426 | |
| 1427 void RegisterAllocator::ConnectRanges() { | |
| 1428 ZoneMap<std::pair<ParallelMove*, InstructionOperand>, InstructionOperand> | |
| 1429 delayed_insertion_map(local_zone()); | |
| 1430 for (auto first_range : live_ranges()) { | |
| 1431 if (first_range == nullptr || first_range->IsChild()) continue; | |
| 1432 for (auto second_range = first_range->next(); second_range != nullptr; | |
| 1433 first_range = second_range, second_range = second_range->next()) { | |
| 1434 auto pos = second_range->Start(); | |
| 1435 // Add gap move if the two live ranges touch and there is no block | |
| 1436 // boundary. | |
| 1437 if (second_range->IsSpilled()) continue; | |
| 1438 if (first_range->End().Value() != pos.Value()) continue; | |
| 1439 if (IsBlockBoundary(pos) && | |
| 1440 !CanEagerlyResolveControlFlow(GetInstructionBlock(pos))) { | |
| 1441 continue; | |
| 1442 } | |
| 1443 auto prev_operand = first_range->GetAssignedOperand(); | |
| 1444 auto cur_operand = second_range->GetAssignedOperand(); | |
| 1445 if (prev_operand == cur_operand) continue; | |
| 1446 bool delay_insertion = false; | |
| 1447 Instruction::GapPosition gap_pos; | |
| 1448 int gap_index = pos.ToInstructionIndex(); | |
| 1449 if (pos.IsGapPosition()) { | |
| 1450 gap_pos = pos.IsStart() ? Instruction::START : Instruction::END; | |
| 1451 } else { | |
| 1452 if (pos.IsStart()) { | |
| 1453 delay_insertion = true; | |
| 1454 } else { | |
| 1455 gap_index++; | |
| 1456 } | |
| 1457 gap_pos = delay_insertion ? Instruction::END : Instruction::START; | |
| 1458 } | |
| 1459 auto move = code()->InstructionAt(gap_index)->GetOrCreateParallelMove( | |
| 1460 gap_pos, code_zone()); | |
| 1461 if (!delay_insertion) { | |
| 1462 move->AddMove(prev_operand, cur_operand); | |
| 1463 } else { | |
| 1464 delayed_insertion_map.insert( | |
| 1465 std::make_pair(std::make_pair(move, prev_operand), cur_operand)); | |
| 1466 } | |
| 1467 } | |
| 1468 } | |
| 1469 if (delayed_insertion_map.empty()) return; | |
| 1470 // Insert all the moves which should occur after the stored move. | |
| 1471 ZoneVector<MoveOperands*> to_insert(local_zone()); | |
| 1472 ZoneVector<MoveOperands*> to_eliminate(local_zone()); | |
| 1473 to_insert.reserve(4); | |
| 1474 to_eliminate.reserve(4); | |
| 1475 auto moves = delayed_insertion_map.begin()->first.first; | |
| 1476 for (auto it = delayed_insertion_map.begin();; ++it) { | |
| 1477 bool done = it == delayed_insertion_map.end(); | |
| 1478 if (done || it->first.first != moves) { | |
| 1479 // Commit the MoveOperands for current ParallelMove. | |
| 1480 for (auto move : to_eliminate) { | |
| 1481 move->Eliminate(); | |
| 1482 } | |
| 1483 for (auto move : to_insert) { | |
| 1484 moves->push_back(move); | |
| 1485 } | |
| 1486 if (done) break; | |
| 1487 // Reset state. | |
| 1488 to_eliminate.clear(); | |
| 1489 to_insert.clear(); | |
| 1490 moves = it->first.first; | |
| 1491 } | |
| 1492 // Gather all MoveOperands for a single ParallelMove. | |
| 1493 auto move = new (code_zone()) MoveOperands(it->first.second, it->second); | |
| 1494 auto eliminate = moves->PrepareInsertAfter(move); | |
| 1495 to_insert.push_back(move); | |
| 1496 if (eliminate != nullptr) to_eliminate.push_back(eliminate); | |
| 1497 } | |
| 1498 } | |
| 1499 | |
| 1500 | |
| 1501 bool RegisterAllocator::CanEagerlyResolveControlFlow( | |
| 1502 const InstructionBlock* block) const { | |
| 1503 if (block->PredecessorCount() != 1) return false; | |
| 1504 return block->predecessors()[0].IsNext(block->rpo_number()); | |
| 1505 } | |
| 1506 | |
| 1507 | |
| 1508 namespace { | |
| 1509 | |
| 1510 class LiveRangeBound { | |
| 1511 public: | |
| 1512 explicit LiveRangeBound(const LiveRange* range) | |
| 1513 : range_(range), start_(range->Start()), end_(range->End()) { | |
| 1514 DCHECK(!range->IsEmpty()); | |
| 1515 } | |
| 1516 | |
| 1517 bool CanCover(LifetimePosition position) { | |
| 1518 return start_.Value() <= position.Value() && | |
| 1519 position.Value() < end_.Value(); | |
| 1520 } | |
| 1521 | |
| 1522 const LiveRange* const range_; | |
| 1523 const LifetimePosition start_; | |
| 1524 const LifetimePosition end_; | |
| 1525 | |
| 1526 private: | |
| 1527 DISALLOW_COPY_AND_ASSIGN(LiveRangeBound); | |
| 1528 }; | |
| 1529 | |
| 1530 | |
| 1531 struct FindResult { | |
| 1532 const LiveRange* cur_cover_; | |
| 1533 const LiveRange* pred_cover_; | |
| 1534 }; | |
| 1535 | |
| 1536 | |
| 1537 class LiveRangeBoundArray { | |
| 1538 public: | |
| 1539 LiveRangeBoundArray() : length_(0), start_(nullptr) {} | |
| 1540 | |
| 1541 bool ShouldInitialize() { return start_ == nullptr; } | |
| 1542 | |
| 1543 void Initialize(Zone* zone, const LiveRange* const range) { | |
| 1544 size_t length = 0; | |
| 1545 for (auto i = range; i != nullptr; i = i->next()) length++; | |
| 1546 start_ = zone->NewArray<LiveRangeBound>(length); | |
| 1547 length_ = length; | |
| 1548 auto curr = start_; | |
| 1549 for (auto i = range; i != nullptr; i = i->next(), ++curr) { | |
| 1550 new (curr) LiveRangeBound(i); | |
| 1551 } | |
| 1552 } | |
| 1553 | |
| 1554 LiveRangeBound* Find(const LifetimePosition position) const { | |
| 1555 size_t left_index = 0; | |
| 1556 size_t right_index = length_; | |
| 1557 while (true) { | |
| 1558 size_t current_index = left_index + (right_index - left_index) / 2; | |
| 1559 DCHECK(right_index > current_index); | |
| 1560 auto bound = &start_[current_index]; | |
| 1561 if (bound->start_.Value() <= position.Value()) { | |
| 1562 if (position.Value() < bound->end_.Value()) return bound; | |
| 1563 DCHECK(left_index < current_index); | |
| 1564 left_index = current_index; | |
| 1565 } else { | |
| 1566 right_index = current_index; | |
| 1567 } | |
| 1568 } | |
| 1569 } | |
| 1570 | |
| 1571 LiveRangeBound* FindPred(const InstructionBlock* pred) { | |
| 1572 auto pred_end = LifetimePosition::InstructionFromInstructionIndex( | |
| 1573 pred->last_instruction_index()); | |
| 1574 return Find(pred_end); | |
| 1575 } | |
| 1576 | |
| 1577 LiveRangeBound* FindSucc(const InstructionBlock* succ) { | |
| 1578 auto succ_start = LifetimePosition::GapFromInstructionIndex( | |
| 1579 succ->first_instruction_index()); | |
| 1580 return Find(succ_start); | |
| 1581 } | |
| 1582 | |
| 1583 void Find(const InstructionBlock* block, const InstructionBlock* pred, | |
| 1584 FindResult* result) const { | |
| 1585 auto pred_end = LifetimePosition::InstructionFromInstructionIndex( | |
| 1586 pred->last_instruction_index()); | |
| 1587 auto bound = Find(pred_end); | |
| 1588 result->pred_cover_ = bound->range_; | |
| 1589 auto cur_start = LifetimePosition::GapFromInstructionIndex( | |
| 1590 block->first_instruction_index()); | |
| 1591 // Common case. | |
| 1592 if (bound->CanCover(cur_start)) { | |
| 1593 result->cur_cover_ = bound->range_; | |
| 1594 return; | |
| 1595 } | |
| 1596 result->cur_cover_ = Find(cur_start)->range_; | |
| 1597 DCHECK(result->pred_cover_ != nullptr && result->cur_cover_ != nullptr); | |
| 1598 } | |
| 1599 | |
| 1600 private: | |
| 1601 size_t length_; | |
| 1602 LiveRangeBound* start_; | |
| 1603 | |
| 1604 DISALLOW_COPY_AND_ASSIGN(LiveRangeBoundArray); | |
| 1605 }; | |
| 1606 | |
| 1607 | |
| 1608 class LiveRangeFinder { | |
| 1609 public: | |
| 1610 explicit LiveRangeFinder(const RegisterAllocator& allocator) | |
| 1611 : allocator_(allocator), | |
| 1612 bounds_length_(static_cast<int>(allocator.live_ranges().size())), | |
| 1613 bounds_(allocator.local_zone()->NewArray<LiveRangeBoundArray>( | |
| 1614 bounds_length_)) { | |
| 1615 for (int i = 0; i < bounds_length_; ++i) { | |
| 1616 new (&bounds_[i]) LiveRangeBoundArray(); | |
| 1617 } | |
| 1618 } | |
| 1619 | |
| 1620 LiveRangeBoundArray* ArrayFor(int operand_index) { | |
| 1621 DCHECK(operand_index < bounds_length_); | |
| 1622 auto range = allocator_.live_ranges()[operand_index]; | |
| 1623 DCHECK(range != nullptr && !range->IsEmpty()); | |
| 1624 auto array = &bounds_[operand_index]; | |
| 1625 if (array->ShouldInitialize()) { | |
| 1626 array->Initialize(allocator_.local_zone(), range); | |
| 1627 } | |
| 1628 return array; | |
| 1629 } | |
| 1630 | |
| 1631 private: | |
| 1632 const RegisterAllocator& allocator_; | |
| 1633 const int bounds_length_; | |
| 1634 LiveRangeBoundArray* const bounds_; | |
| 1635 | |
| 1636 DISALLOW_COPY_AND_ASSIGN(LiveRangeFinder); | |
| 1637 }; | |
| 1638 | |
| 1639 } // namespace | |
| 1640 | |
| 1641 | |
| 1642 void RegisterAllocator::ResolveControlFlow() { | |
| 1643 // Lazily linearize live ranges in memory for fast lookup. | |
| 1644 LiveRangeFinder finder(*this); | |
| 1645 for (auto block : code()->instruction_blocks()) { | |
| 1646 if (CanEagerlyResolveControlFlow(block)) continue; | |
| 1647 auto live = live_in_sets_[block->rpo_number().ToInt()]; | |
| 1648 BitVector::Iterator iterator(live); | |
| 1649 while (!iterator.Done()) { | |
| 1650 auto* array = finder.ArrayFor(iterator.Current()); | |
| 1651 for (auto pred : block->predecessors()) { | |
| 1652 FindResult result; | |
| 1653 const auto* pred_block = code()->InstructionBlockAt(pred); | |
| 1654 array->Find(block, pred_block, &result); | |
| 1655 if (result.cur_cover_ == result.pred_cover_ || | |
| 1656 result.cur_cover_->IsSpilled()) | |
| 1657 continue; | |
| 1658 auto pred_op = result.pred_cover_->GetAssignedOperand(); | |
| 1659 auto cur_op = result.cur_cover_->GetAssignedOperand(); | |
| 1660 if (pred_op == cur_op) continue; | |
| 1661 ResolveControlFlow(block, cur_op, pred_block, pred_op); | |
| 1662 } | |
| 1663 iterator.Advance(); | |
| 1664 } | |
| 1665 } | |
| 1666 } | |
| 1667 | |
| 1668 | |
| 1669 void RegisterAllocator::ResolveControlFlow(const InstructionBlock* block, | |
| 1670 const InstructionOperand& cur_op, | |
| 1671 const InstructionBlock* pred, | |
| 1672 const InstructionOperand& pred_op) { | |
| 1673 DCHECK(pred_op != cur_op); | |
| 1674 int gap_index; | |
| 1675 Instruction::GapPosition position; | |
| 1676 if (block->PredecessorCount() == 1) { | |
| 1677 gap_index = block->first_instruction_index(); | |
| 1678 position = Instruction::START; | |
| 1679 } else { | |
| 1680 DCHECK(pred->SuccessorCount() == 1); | |
| 1681 DCHECK(!InstructionAt(pred->last_instruction_index())->HasReferenceMap()); | |
| 1682 gap_index = pred->last_instruction_index(); | |
| 1683 position = Instruction::END; | |
| 1684 } | |
| 1685 AddGapMove(gap_index, position, pred_op, cur_op); | |
| 1686 } | |
| 1687 | |
| 1688 | |
| 1689 void RegisterAllocator::BuildLiveRanges() { | |
| 1690 // Process the blocks in reverse order. | 1325 // Process the blocks in reverse order. |
| 1691 for (int block_id = code()->InstructionBlockCount() - 1; block_id >= 0; | 1326 for (int block_id = code()->InstructionBlockCount() - 1; block_id >= 0; |
| 1692 --block_id) { | 1327 --block_id) { |
| 1693 auto block = code()->InstructionBlockAt(RpoNumber::FromInt(block_id)); | 1328 auto block = code()->InstructionBlockAt(RpoNumber::FromInt(block_id)); |
| 1694 auto live = ComputeLiveOut(block); | 1329 auto live = ComputeLiveOut(block); |
| 1695 // Initially consider all live_out values live for the entire block. We | 1330 // Initially consider all live_out values live for the entire block. We |
| 1696 // will shorten these intervals if necessary. | 1331 // will shorten these intervals if necessary. |
| 1697 AddInitialIntervals(block, live); | 1332 AddInitialIntervals(block, live); |
| 1698 | 1333 |
| 1699 // Process the instructions in reverse order, generating and killing | 1334 // Process the instructions in reverse order, generating and killing |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1717 } | 1352 } |
| 1718 } | 1353 } |
| 1719 DCHECK(hint != nullptr); | 1354 DCHECK(hint != nullptr); |
| 1720 auto block_start = LifetimePosition::GapFromInstructionIndex( | 1355 auto block_start = LifetimePosition::GapFromInstructionIndex( |
| 1721 block->first_instruction_index()); | 1356 block->first_instruction_index()); |
| 1722 Define(block_start, &phi->output(), hint); | 1357 Define(block_start, &phi->output(), hint); |
| 1723 } | 1358 } |
| 1724 | 1359 |
| 1725 // Now live is live_in for this block except not including values live | 1360 // Now live is live_in for this block except not including values live |
| 1726 // out on backward successor edges. | 1361 // out on backward successor edges. |
| 1727 live_in_sets_[block_id] = live; | 1362 live_in_sets()[block_id] = live; |
| 1728 | 1363 |
| 1729 if (block->IsLoopHeader()) { | 1364 if (block->IsLoopHeader()) { |
| 1730 // Add a live range stretching from the first loop instruction to the last | 1365 // Add a live range stretching from the first loop instruction to the last |
| 1731 // for each value live on entry to the header. | 1366 // for each value live on entry to the header. |
| 1732 BitVector::Iterator iterator(live); | 1367 BitVector::Iterator iterator(live); |
| 1733 auto start = LifetimePosition::GapFromInstructionIndex( | 1368 auto start = LifetimePosition::GapFromInstructionIndex( |
| 1734 block->first_instruction_index()); | 1369 block->first_instruction_index()); |
| 1735 auto end = LifetimePosition::GapFromInstructionIndex( | 1370 auto end = LifetimePosition::GapFromInstructionIndex( |
| 1736 code()->LastLoopInstructionIndex(block)).NextFullStart(); | 1371 code()->LastLoopInstructionIndex(block)).NextFullStart(); |
| 1737 while (!iterator.Done()) { | 1372 while (!iterator.Done()) { |
| 1738 int operand_index = iterator.Current(); | 1373 int operand_index = iterator.Current(); |
| 1739 auto range = LiveRangeFor(operand_index); | 1374 auto range = LiveRangeFor(operand_index); |
| 1740 range->EnsureInterval(start, end, local_zone()); | 1375 range->EnsureInterval(start, end, allocation_zone()); |
| 1741 iterator.Advance(); | 1376 iterator.Advance(); |
| 1742 } | 1377 } |
| 1743 // Insert all values into the live in sets of all blocks in the loop. | 1378 // Insert all values into the live in sets of all blocks in the loop. |
| 1744 for (int i = block->rpo_number().ToInt() + 1; | 1379 for (int i = block->rpo_number().ToInt() + 1; |
| 1745 i < block->loop_end().ToInt(); ++i) { | 1380 i < block->loop_end().ToInt(); ++i) { |
| 1746 live_in_sets_[i]->Union(*live); | 1381 live_in_sets()[i]->Union(*live); |
| 1747 } | 1382 } |
| 1748 } | 1383 } |
| 1749 } | 1384 } |
| 1750 | 1385 |
| 1751 for (auto range : live_ranges()) { | 1386 for (auto range : live_ranges()) { |
| 1752 if (range == nullptr) continue; | 1387 if (range == nullptr) continue; |
| 1753 range->kind_ = RequiredRegisterKind(range->id()); | 1388 range->set_kind(RequiredRegisterKind(range->id())); |
| 1754 // Give slots to all ranges with a non fixed slot use. | 1389 // Give slots to all ranges with a non fixed slot use. |
| 1755 if (range->has_slot_use() && range->HasNoSpillType()) { | 1390 if (range->has_slot_use() && range->HasNoSpillType()) { |
| 1756 AssignSpillRangeToLiveRange(range); | 1391 data()->AssignSpillRangeToLiveRange(range); |
| 1757 } | 1392 } |
| 1758 // TODO(bmeurer): This is a horrible hack to make sure that for constant | 1393 // TODO(bmeurer): This is a horrible hack to make sure that for constant |
| 1759 // live ranges, every use requires the constant to be in a register. | 1394 // live ranges, every use requires the constant to be in a register. |
| 1760 // Without this hack, all uses with "any" policy would get the constant | 1395 // Without this hack, all uses with "any" policy would get the constant |
| 1761 // operand assigned. | 1396 // operand assigned. |
| 1762 if (range->HasSpillOperand() && range->GetSpillOperand()->IsConstant()) { | 1397 if (range->HasSpillOperand() && range->GetSpillOperand()->IsConstant()) { |
| 1763 for (auto pos = range->first_pos(); pos != nullptr; pos = pos->next_) { | 1398 for (auto pos = range->first_pos(); pos != nullptr; pos = pos->next_) { |
| 1764 if (pos->type() == UsePositionType::kRequiresSlot) continue; | 1399 if (pos->type() == UsePositionType::kRequiresSlot) continue; |
| 1765 UsePositionType new_type = UsePositionType::kAny; | 1400 UsePositionType new_type = UsePositionType::kAny; |
| 1766 // Can't mark phis as needing a register. | 1401 // Can't mark phis as needing a register. |
| 1767 if (!pos->pos().IsGapPosition()) { | 1402 if (!pos->pos().IsGapPosition()) { |
| 1768 new_type = UsePositionType::kRequiresRegister; | 1403 new_type = UsePositionType::kRequiresRegister; |
| 1769 } | 1404 } |
| 1770 pos->set_type(new_type, true); | 1405 pos->set_type(new_type, true); |
| 1771 } | 1406 } |
| 1772 } | 1407 } |
| 1773 } | 1408 } |
| 1409 |
| 1410 #ifdef DEBUG |
| 1411 Verify(); |
| 1412 #endif |
| 1413 } |
| 1414 |
| 1415 |
| 1416 RegisterKind LiveRangeBuilder::RequiredRegisterKind( |
| 1417 int virtual_register) const { |
| 1418 return (code()->IsDouble(virtual_register)) ? DOUBLE_REGISTERS |
| 1419 : GENERAL_REGISTERS; |
| 1420 } |
| 1421 |
| 1422 |
| 1423 void LiveRangeBuilder::Verify() const { |
| 1424 for (auto current : data()->live_ranges()) { |
| 1425 if (current != nullptr) current->Verify(); |
| 1426 } |
| 1774 } | 1427 } |
| 1775 | 1428 |
| 1776 | 1429 |
| 1777 bool RegisterAllocator::ExistsUseWithoutDefinition() { | 1430 LinearScanAllocator::LinearScanAllocator(RegisterAllocationData* data, |
| 1778 bool found = false; | 1431 RegisterKind kind) |
| 1779 BitVector::Iterator iterator(live_in_sets_[0]); | 1432 : data_(data), |
| 1780 while (!iterator.Done()) { | 1433 mode_(kind), |
| 1781 found = true; | 1434 num_registers_(kind == DOUBLE_REGISTERS |
| 1782 int operand_index = iterator.Current(); | 1435 ? config()->num_aliased_double_registers() |
| 1783 PrintF("Register allocator error: live v%d reached first block.\n", | 1436 : config()->num_general_registers()), |
| 1784 operand_index); | 1437 unhandled_live_ranges_(allocation_zone()), |
| 1785 LiveRange* range = LiveRangeFor(operand_index); | 1438 active_live_ranges_(allocation_zone()), |
| 1786 PrintF(" (first use is at %d)\n", range->first_pos()->pos().Value()); | 1439 inactive_live_ranges_(allocation_zone()) { |
| 1787 if (debug_name() == nullptr) { | 1440 unhandled_live_ranges().reserve( |
| 1788 PrintF("\n"); | 1441 static_cast<size_t>(code()->VirtualRegisterCount() * 2)); |
| 1789 } else { | 1442 active_live_ranges().reserve(8); |
| 1790 PrintF(" (function: %s)\n", debug_name()); | 1443 inactive_live_ranges().reserve(8); |
| 1791 } | 1444 // TryAllocateFreeReg and AllocateBlockedReg assume this |
| 1792 iterator.Advance(); | 1445 // when allocating local arrays. |
| 1793 } | 1446 DCHECK(RegisterConfiguration::kMaxDoubleRegisters >= |
| 1794 return found; | 1447 config()->num_general_registers()); |
| 1795 } | 1448 } |
| 1796 | 1449 |
| 1797 | 1450 |
| 1798 bool RegisterAllocator::SafePointsAreInOrder() const { | 1451 void LinearScanAllocator::AllocateRegisters() { |
| 1799 int safe_point = 0; | |
| 1800 for (auto map : *code()->reference_maps()) { | |
| 1801 if (safe_point > map->instruction_position()) return false; | |
| 1802 safe_point = map->instruction_position(); | |
| 1803 } | |
| 1804 return true; | |
| 1805 } | |
| 1806 | |
| 1807 | |
| 1808 void RegisterAllocator::PopulateReferenceMaps() { | |
| 1809 DCHECK(SafePointsAreInOrder()); | |
| 1810 | |
| 1811 // Iterate over all safe point positions and record a pointer | |
| 1812 // for all spilled live ranges at this point. | |
| 1813 int last_range_start = 0; | |
| 1814 auto reference_maps = code()->reference_maps(); | |
| 1815 ReferenceMapDeque::const_iterator first_it = reference_maps->begin(); | |
| 1816 for (LiveRange* range : live_ranges()) { | |
| 1817 if (range == nullptr) continue; | |
| 1818 // Iterate over the first parts of multi-part live ranges. | |
| 1819 if (range->IsChild()) continue; | |
| 1820 // Skip non-reference values. | |
| 1821 if (!HasTaggedValue(range->id())) continue; | |
| 1822 // Skip empty live ranges. | |
| 1823 if (range->IsEmpty()) continue; | |
| 1824 | |
| 1825 // Find the extent of the range and its children. | |
| 1826 int start = range->Start().ToInstructionIndex(); | |
| 1827 int end = 0; | |
| 1828 for (auto cur = range; cur != nullptr; cur = cur->next()) { | |
| 1829 auto this_end = cur->End(); | |
| 1830 if (this_end.ToInstructionIndex() > end) | |
| 1831 end = this_end.ToInstructionIndex(); | |
| 1832 DCHECK(cur->Start().ToInstructionIndex() >= start); | |
| 1833 } | |
| 1834 | |
| 1835 // Most of the ranges are in order, but not all. Keep an eye on when they | |
| 1836 // step backwards and reset the first_it so we don't miss any safe points. | |
| 1837 if (start < last_range_start) first_it = reference_maps->begin(); | |
| 1838 last_range_start = start; | |
| 1839 | |
| 1840 // Step across all the safe points that are before the start of this range, | |
| 1841 // recording how far we step in order to save doing this for the next range. | |
| 1842 for (; first_it != reference_maps->end(); ++first_it) { | |
| 1843 auto map = *first_it; | |
| 1844 if (map->instruction_position() >= start) break; | |
| 1845 } | |
| 1846 | |
| 1847 // Step through the safe points to see whether they are in the range. | |
| 1848 for (auto it = first_it; it != reference_maps->end(); ++it) { | |
| 1849 auto map = *it; | |
| 1850 int safe_point = map->instruction_position(); | |
| 1851 | |
| 1852 // The safe points are sorted so we can stop searching here. | |
| 1853 if (safe_point - 1 > end) break; | |
| 1854 | |
| 1855 // Advance to the next active range that covers the current | |
| 1856 // safe point position. | |
| 1857 auto safe_point_pos = | |
| 1858 LifetimePosition::InstructionFromInstructionIndex(safe_point); | |
| 1859 auto cur = range; | |
| 1860 while (cur != nullptr && !cur->Covers(safe_point_pos)) { | |
| 1861 cur = cur->next(); | |
| 1862 } | |
| 1863 if (cur == nullptr) continue; | |
| 1864 | |
| 1865 // Check if the live range is spilled and the safe point is after | |
| 1866 // the spill position. | |
| 1867 if (range->HasSpillOperand() && | |
| 1868 safe_point >= range->spill_start_index() && | |
| 1869 !range->GetSpillOperand()->IsConstant()) { | |
| 1870 TRACE("Pointer for range %d (spilled at %d) at safe point %d\n", | |
| 1871 range->id(), range->spill_start_index(), safe_point); | |
| 1872 map->RecordReference(*range->GetSpillOperand()); | |
| 1873 } | |
| 1874 | |
| 1875 if (!cur->IsSpilled()) { | |
| 1876 TRACE( | |
| 1877 "Pointer in register for range %d (start at %d) " | |
| 1878 "at safe point %d\n", | |
| 1879 cur->id(), cur->Start().Value(), safe_point); | |
| 1880 auto operand = cur->GetAssignedOperand(); | |
| 1881 DCHECK(!operand.IsStackSlot()); | |
| 1882 map->RecordReference(operand); | |
| 1883 } | |
| 1884 } | |
| 1885 } | |
| 1886 } | |
| 1887 | |
| 1888 | |
| 1889 void RegisterAllocator::AllocateGeneralRegisters() { | |
| 1890 num_registers_ = config()->num_general_registers(); | |
| 1891 mode_ = GENERAL_REGISTERS; | |
| 1892 AllocateRegisters(); | |
| 1893 } | |
| 1894 | |
| 1895 | |
| 1896 void RegisterAllocator::AllocateDoubleRegisters() { | |
| 1897 num_registers_ = config()->num_aliased_double_registers(); | |
| 1898 mode_ = DOUBLE_REGISTERS; | |
| 1899 AllocateRegisters(); | |
| 1900 } | |
| 1901 | |
| 1902 | |
| 1903 void RegisterAllocator::AllocateRegisters() { | |
| 1904 DCHECK(unhandled_live_ranges().empty()); | 1452 DCHECK(unhandled_live_ranges().empty()); |
| 1905 | 1453 |
| 1906 for (auto range : live_ranges()) { | 1454 for (auto range : live_ranges()) { |
| 1907 if (range == nullptr) continue; | 1455 if (range == nullptr) continue; |
| 1908 if (range->Kind() == mode_) { | 1456 if (range->Kind() == mode_) { |
| 1909 AddToUnhandledUnsorted(range); | 1457 AddToUnhandledUnsorted(range); |
| 1910 } | 1458 } |
| 1911 } | 1459 } |
| 1912 SortUnhandled(); | 1460 SortUnhandled(); |
| 1913 DCHECK(UnhandledIsSorted()); | 1461 DCHECK(UnhandledIsSorted()); |
| 1914 | 1462 |
| 1915 DCHECK(active_live_ranges().empty()); | 1463 DCHECK(active_live_ranges().empty()); |
| 1916 DCHECK(inactive_live_ranges().empty()); | 1464 DCHECK(inactive_live_ranges().empty()); |
| 1917 | 1465 |
| 1918 if (mode_ == DOUBLE_REGISTERS) { | 1466 if (mode_ == DOUBLE_REGISTERS) { |
| 1919 for (int i = 0; i < config()->num_aliased_double_registers(); ++i) { | 1467 for (auto current : fixed_double_live_ranges()) { |
| 1920 auto current = fixed_double_live_ranges()[i]; | 1468 if (current != nullptr) AddToInactive(current); |
| 1921 if (current != nullptr) { | |
| 1922 AddToInactive(current); | |
| 1923 } | |
| 1924 } | 1469 } |
| 1925 } else { | 1470 } else { |
| 1926 DCHECK(mode_ == GENERAL_REGISTERS); | 1471 DCHECK(mode_ == GENERAL_REGISTERS); |
| 1927 for (auto current : fixed_live_ranges()) { | 1472 for (auto current : fixed_live_ranges()) { |
| 1928 if (current != nullptr) { | 1473 if (current != nullptr) AddToInactive(current); |
| 1929 AddToInactive(current); | |
| 1930 } | |
| 1931 } | 1474 } |
| 1932 } | 1475 } |
| 1933 | 1476 |
| 1934 while (!unhandled_live_ranges().empty()) { | 1477 while (!unhandled_live_ranges().empty()) { |
| 1935 DCHECK(UnhandledIsSorted()); | 1478 DCHECK(UnhandledIsSorted()); |
| 1936 auto current = unhandled_live_ranges().back(); | 1479 auto current = unhandled_live_ranges().back(); |
| 1937 unhandled_live_ranges().pop_back(); | 1480 unhandled_live_ranges().pop_back(); |
| 1938 DCHECK(UnhandledIsSorted()); | 1481 DCHECK(UnhandledIsSorted()); |
| 1939 auto position = current->Start(); | 1482 auto position = current->Start(); |
| 1940 #ifdef DEBUG | 1483 #ifdef DEBUG |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1994 if (current->HasRegisterAssigned()) { | 1537 if (current->HasRegisterAssigned()) { |
| 1995 AddToActive(current); | 1538 AddToActive(current); |
| 1996 } | 1539 } |
| 1997 } | 1540 } |
| 1998 | 1541 |
| 1999 active_live_ranges().clear(); | 1542 active_live_ranges().clear(); |
| 2000 inactive_live_ranges().clear(); | 1543 inactive_live_ranges().clear(); |
| 2001 } | 1544 } |
| 2002 | 1545 |
| 2003 | 1546 |
| 2004 const char* RegisterAllocator::RegisterName(int allocation_index) { | 1547 const char* LinearScanAllocator::RegisterName(int allocation_index) { |
| 2005 if (mode_ == GENERAL_REGISTERS) { | 1548 if (mode_ == GENERAL_REGISTERS) { |
| 2006 return config()->general_register_name(allocation_index); | 1549 return config()->general_register_name(allocation_index); |
| 2007 } else { | 1550 } else { |
| 2008 return config()->double_register_name(allocation_index); | 1551 return config()->double_register_name(allocation_index); |
| 2009 } | 1552 } |
| 2010 } | 1553 } |
| 2011 | 1554 |
| 2012 | 1555 |
| 2013 bool RegisterAllocator::HasTaggedValue(int virtual_register) const { | 1556 void LinearScanAllocator::AddToActive(LiveRange* range) { |
| 2014 return code()->IsReference(virtual_register); | |
| 2015 } | |
| 2016 | |
| 2017 | |
| 2018 RegisterKind RegisterAllocator::RequiredRegisterKind( | |
| 2019 int virtual_register) const { | |
| 2020 return (code()->IsDouble(virtual_register)) ? DOUBLE_REGISTERS | |
| 2021 : GENERAL_REGISTERS; | |
| 2022 } | |
| 2023 | |
| 2024 | |
| 2025 void RegisterAllocator::AddToActive(LiveRange* range) { | |
| 2026 TRACE("Add live range %d to active\n", range->id()); | 1557 TRACE("Add live range %d to active\n", range->id()); |
| 2027 active_live_ranges().push_back(range); | 1558 active_live_ranges().push_back(range); |
| 2028 } | 1559 } |
| 2029 | 1560 |
| 2030 | 1561 |
| 2031 void RegisterAllocator::AddToInactive(LiveRange* range) { | 1562 void LinearScanAllocator::AddToInactive(LiveRange* range) { |
| 2032 TRACE("Add live range %d to inactive\n", range->id()); | 1563 TRACE("Add live range %d to inactive\n", range->id()); |
| 2033 inactive_live_ranges().push_back(range); | 1564 inactive_live_ranges().push_back(range); |
| 2034 } | 1565 } |
| 2035 | 1566 |
| 2036 | 1567 |
| 2037 void RegisterAllocator::AddToUnhandledSorted(LiveRange* range) { | 1568 void LinearScanAllocator::AddToUnhandledSorted(LiveRange* range) { |
| 2038 if (range == nullptr || range->IsEmpty()) return; | 1569 if (range == nullptr || range->IsEmpty()) return; |
| 2039 DCHECK(!range->HasRegisterAssigned() && !range->IsSpilled()); | 1570 DCHECK(!range->HasRegisterAssigned() && !range->IsSpilled()); |
| 2040 DCHECK(allocation_finger_.Value() <= range->Start().Value()); | 1571 DCHECK(allocation_finger_.Value() <= range->Start().Value()); |
| 2041 for (int i = static_cast<int>(unhandled_live_ranges().size() - 1); i >= 0; | 1572 for (int i = static_cast<int>(unhandled_live_ranges().size() - 1); i >= 0; |
| 2042 --i) { | 1573 --i) { |
| 2043 auto cur_range = unhandled_live_ranges().at(i); | 1574 auto cur_range = unhandled_live_ranges().at(i); |
| 2044 if (!range->ShouldBeAllocatedBefore(cur_range)) continue; | 1575 if (!range->ShouldBeAllocatedBefore(cur_range)) continue; |
| 2045 TRACE("Add live range %d to unhandled at %d\n", range->id(), i + 1); | 1576 TRACE("Add live range %d to unhandled at %d\n", range->id(), i + 1); |
| 2046 auto it = unhandled_live_ranges().begin() + (i + 1); | 1577 auto it = unhandled_live_ranges().begin() + (i + 1); |
| 2047 unhandled_live_ranges().insert(it, range); | 1578 unhandled_live_ranges().insert(it, range); |
| 2048 DCHECK(UnhandledIsSorted()); | 1579 DCHECK(UnhandledIsSorted()); |
| 2049 return; | 1580 return; |
| 2050 } | 1581 } |
| 2051 TRACE("Add live range %d to unhandled at start\n", range->id()); | 1582 TRACE("Add live range %d to unhandled at start\n", range->id()); |
| 2052 unhandled_live_ranges().insert(unhandled_live_ranges().begin(), range); | 1583 unhandled_live_ranges().insert(unhandled_live_ranges().begin(), range); |
| 2053 DCHECK(UnhandledIsSorted()); | 1584 DCHECK(UnhandledIsSorted()); |
| 2054 } | 1585 } |
| 2055 | 1586 |
| 2056 | 1587 |
| 2057 void RegisterAllocator::AddToUnhandledUnsorted(LiveRange* range) { | 1588 void LinearScanAllocator::AddToUnhandledUnsorted(LiveRange* range) { |
| 2058 if (range == nullptr || range->IsEmpty()) return; | 1589 if (range == nullptr || range->IsEmpty()) return; |
| 2059 DCHECK(!range->HasRegisterAssigned() && !range->IsSpilled()); | 1590 DCHECK(!range->HasRegisterAssigned() && !range->IsSpilled()); |
| 2060 TRACE("Add live range %d to unhandled unsorted at end\n", range->id()); | 1591 TRACE("Add live range %d to unhandled unsorted at end\n", range->id()); |
| 2061 unhandled_live_ranges().push_back(range); | 1592 unhandled_live_ranges().push_back(range); |
| 2062 } | 1593 } |
| 2063 | 1594 |
| 2064 | 1595 |
| 2065 static bool UnhandledSortHelper(LiveRange* a, LiveRange* b) { | 1596 static bool UnhandledSortHelper(LiveRange* a, LiveRange* b) { |
| 2066 DCHECK(!a->ShouldBeAllocatedBefore(b) || !b->ShouldBeAllocatedBefore(a)); | 1597 DCHECK(!a->ShouldBeAllocatedBefore(b) || !b->ShouldBeAllocatedBefore(a)); |
| 2067 if (a->ShouldBeAllocatedBefore(b)) return false; | 1598 if (a->ShouldBeAllocatedBefore(b)) return false; |
| 2068 if (b->ShouldBeAllocatedBefore(a)) return true; | 1599 if (b->ShouldBeAllocatedBefore(a)) return true; |
| 2069 return a->id() < b->id(); | 1600 return a->id() < b->id(); |
| 2070 } | 1601 } |
| 2071 | 1602 |
| 2072 | 1603 |
| 2073 // Sort the unhandled live ranges so that the ranges to be processed first are | 1604 // Sort the unhandled live ranges so that the ranges to be processed first are |
| 2074 // at the end of the array list. This is convenient for the register allocation | 1605 // at the end of the array list. This is convenient for the register allocation |
| 2075 // algorithm because it is efficient to remove elements from the end. | 1606 // algorithm because it is efficient to remove elements from the end. |
| 2076 void RegisterAllocator::SortUnhandled() { | 1607 void LinearScanAllocator::SortUnhandled() { |
| 2077 TRACE("Sort unhandled\n"); | 1608 TRACE("Sort unhandled\n"); |
| 2078 std::sort(unhandled_live_ranges().begin(), unhandled_live_ranges().end(), | 1609 std::sort(unhandled_live_ranges().begin(), unhandled_live_ranges().end(), |
| 2079 &UnhandledSortHelper); | 1610 &UnhandledSortHelper); |
| 2080 } | 1611 } |
| 2081 | 1612 |
| 2082 | 1613 |
| 2083 bool RegisterAllocator::UnhandledIsSorted() { | 1614 bool LinearScanAllocator::UnhandledIsSorted() { |
| 2084 size_t len = unhandled_live_ranges().size(); | 1615 size_t len = unhandled_live_ranges().size(); |
| 2085 for (size_t i = 1; i < len; i++) { | 1616 for (size_t i = 1; i < len; i++) { |
| 2086 auto a = unhandled_live_ranges().at(i - 1); | 1617 auto a = unhandled_live_ranges().at(i - 1); |
| 2087 auto b = unhandled_live_ranges().at(i); | 1618 auto b = unhandled_live_ranges().at(i); |
| 2088 if (a->Start().Value() < b->Start().Value()) return false; | 1619 if (a->Start().Value() < b->Start().Value()) return false; |
| 2089 } | 1620 } |
| 2090 return true; | 1621 return true; |
| 2091 } | 1622 } |
| 2092 | 1623 |
| 2093 | 1624 |
| 2094 void RegisterAllocator::ActiveToHandled(LiveRange* range) { | 1625 void LinearScanAllocator::ActiveToHandled(LiveRange* range) { |
| 2095 RemoveElement(&active_live_ranges(), range); | 1626 RemoveElement(&active_live_ranges(), range); |
| 2096 TRACE("Moving live range %d from active to handled\n", range->id()); | 1627 TRACE("Moving live range %d from active to handled\n", range->id()); |
| 2097 } | 1628 } |
| 2098 | 1629 |
| 2099 | 1630 |
| 2100 void RegisterAllocator::ActiveToInactive(LiveRange* range) { | 1631 void LinearScanAllocator::ActiveToInactive(LiveRange* range) { |
| 2101 RemoveElement(&active_live_ranges(), range); | 1632 RemoveElement(&active_live_ranges(), range); |
| 2102 inactive_live_ranges().push_back(range); | 1633 inactive_live_ranges().push_back(range); |
| 2103 TRACE("Moving live range %d from active to inactive\n", range->id()); | 1634 TRACE("Moving live range %d from active to inactive\n", range->id()); |
| 2104 } | 1635 } |
| 2105 | 1636 |
| 2106 | 1637 |
| 2107 void RegisterAllocator::InactiveToHandled(LiveRange* range) { | 1638 void LinearScanAllocator::InactiveToHandled(LiveRange* range) { |
| 2108 RemoveElement(&inactive_live_ranges(), range); | 1639 RemoveElement(&inactive_live_ranges(), range); |
| 2109 TRACE("Moving live range %d from inactive to handled\n", range->id()); | 1640 TRACE("Moving live range %d from inactive to handled\n", range->id()); |
| 2110 } | 1641 } |
| 2111 | 1642 |
| 2112 | 1643 |
| 2113 void RegisterAllocator::InactiveToActive(LiveRange* range) { | 1644 void LinearScanAllocator::InactiveToActive(LiveRange* range) { |
| 2114 RemoveElement(&inactive_live_ranges(), range); | 1645 RemoveElement(&inactive_live_ranges(), range); |
| 2115 active_live_ranges().push_back(range); | 1646 active_live_ranges().push_back(range); |
| 2116 TRACE("Moving live range %d from inactive to active\n", range->id()); | 1647 TRACE("Moving live range %d from inactive to active\n", range->id()); |
| 2117 } | 1648 } |
| 2118 | 1649 |
| 2119 | 1650 |
| 2120 bool RegisterAllocator::TryAllocateFreeReg(LiveRange* current) { | 1651 bool LinearScanAllocator::TryAllocateFreeReg(LiveRange* current) { |
| 2121 LifetimePosition free_until_pos[RegisterConfiguration::kMaxDoubleRegisters]; | 1652 LifetimePosition free_until_pos[RegisterConfiguration::kMaxDoubleRegisters]; |
| 2122 | 1653 |
| 2123 for (int i = 0; i < num_registers_; i++) { | 1654 for (int i = 0; i < num_registers_; i++) { |
| 2124 free_until_pos[i] = LifetimePosition::MaxPosition(); | 1655 free_until_pos[i] = LifetimePosition::MaxPosition(); |
| 2125 } | 1656 } |
| 2126 | 1657 |
| 2127 for (auto cur_active : active_live_ranges()) { | 1658 for (auto cur_active : active_live_ranges()) { |
| 2128 free_until_pos[cur_active->assigned_register()] = | 1659 free_until_pos[cur_active->assigned_register()] = |
| 2129 LifetimePosition::GapFromInstructionIndex(0); | 1660 LifetimePosition::GapFromInstructionIndex(0); |
| 2130 } | 1661 } |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2179 // the range end. | 1710 // the range end. |
| 2180 DCHECK(pos.Value() >= current->End().Value()); | 1711 DCHECK(pos.Value() >= current->End().Value()); |
| 2181 TRACE("Assigning free reg %s to live range %d\n", RegisterName(reg), | 1712 TRACE("Assigning free reg %s to live range %d\n", RegisterName(reg), |
| 2182 current->id()); | 1713 current->id()); |
| 2183 SetLiveRangeAssignedRegister(current, reg); | 1714 SetLiveRangeAssignedRegister(current, reg); |
| 2184 | 1715 |
| 2185 return true; | 1716 return true; |
| 2186 } | 1717 } |
| 2187 | 1718 |
| 2188 | 1719 |
| 2189 void RegisterAllocator::AllocateBlockedReg(LiveRange* current) { | 1720 void LinearScanAllocator::AllocateBlockedReg(LiveRange* current) { |
| 2190 auto register_use = current->NextRegisterPosition(current->Start()); | 1721 auto register_use = current->NextRegisterPosition(current->Start()); |
| 2191 if (register_use == nullptr) { | 1722 if (register_use == nullptr) { |
| 2192 // There is no use in the current live range that requires a register. | 1723 // There is no use in the current live range that requires a register. |
| 2193 // We can just spill it. | 1724 // We can just spill it. |
| 2194 Spill(current); | 1725 Spill(current); |
| 2195 return; | 1726 return; |
| 2196 } | 1727 } |
| 2197 | 1728 |
| 2198 LifetimePosition use_pos[RegisterConfiguration::kMaxDoubleRegisters]; | 1729 LifetimePosition use_pos[RegisterConfiguration::kMaxDoubleRegisters]; |
| 2199 LifetimePosition block_pos[RegisterConfiguration::kMaxDoubleRegisters]; | 1730 LifetimePosition block_pos[RegisterConfiguration::kMaxDoubleRegisters]; |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2269 | 1800 |
| 2270 | 1801 |
| 2271 static const InstructionBlock* GetContainingLoop( | 1802 static const InstructionBlock* GetContainingLoop( |
| 2272 const InstructionSequence* sequence, const InstructionBlock* block) { | 1803 const InstructionSequence* sequence, const InstructionBlock* block) { |
| 2273 auto index = block->loop_header(); | 1804 auto index = block->loop_header(); |
| 2274 if (!index.IsValid()) return nullptr; | 1805 if (!index.IsValid()) return nullptr; |
| 2275 return sequence->InstructionBlockAt(index); | 1806 return sequence->InstructionBlockAt(index); |
| 2276 } | 1807 } |
| 2277 | 1808 |
| 2278 | 1809 |
| 2279 LifetimePosition RegisterAllocator::FindOptimalSpillingPos( | 1810 LifetimePosition LinearScanAllocator::FindOptimalSpillingPos( |
| 2280 LiveRange* range, LifetimePosition pos) { | 1811 LiveRange* range, LifetimePosition pos) { |
| 2281 auto block = GetInstructionBlock(pos.Start()); | 1812 auto block = GetInstructionBlock(pos.Start()); |
| 2282 auto loop_header = | 1813 auto loop_header = |
| 2283 block->IsLoopHeader() ? block : GetContainingLoop(code(), block); | 1814 block->IsLoopHeader() ? block : GetContainingLoop(code(), block); |
| 2284 | 1815 |
| 2285 if (loop_header == nullptr) return pos; | 1816 if (loop_header == nullptr) return pos; |
| 2286 | 1817 |
| 2287 auto prev_use = range->PreviousUsePositionRegisterIsBeneficial(pos); | 1818 auto prev_use = range->PreviousUsePositionRegisterIsBeneficial(pos); |
| 2288 | 1819 |
| 2289 while (loop_header != nullptr) { | 1820 while (loop_header != nullptr) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2301 } | 1832 } |
| 2302 | 1833 |
| 2303 // Try hoisting out to an outer loop. | 1834 // Try hoisting out to an outer loop. |
| 2304 loop_header = GetContainingLoop(code(), loop_header); | 1835 loop_header = GetContainingLoop(code(), loop_header); |
| 2305 } | 1836 } |
| 2306 | 1837 |
| 2307 return pos; | 1838 return pos; |
| 2308 } | 1839 } |
| 2309 | 1840 |
| 2310 | 1841 |
| 2311 void RegisterAllocator::SplitAndSpillIntersecting(LiveRange* current) { | 1842 void LinearScanAllocator::SplitAndSpillIntersecting(LiveRange* current) { |
| 2312 DCHECK(current->HasRegisterAssigned()); | 1843 DCHECK(current->HasRegisterAssigned()); |
| 2313 int reg = current->assigned_register(); | 1844 int reg = current->assigned_register(); |
| 2314 auto split_pos = current->Start(); | 1845 auto split_pos = current->Start(); |
| 2315 for (size_t i = 0; i < active_live_ranges().size(); ++i) { | 1846 for (size_t i = 0; i < active_live_ranges().size(); ++i) { |
| 2316 auto range = active_live_ranges()[i]; | 1847 auto range = active_live_ranges()[i]; |
| 2317 if (range->assigned_register() == reg) { | 1848 if (range->assigned_register() == reg) { |
| 2318 auto next_pos = range->NextRegisterPosition(current->Start()); | 1849 auto next_pos = range->NextRegisterPosition(current->Start()); |
| 2319 auto spill_pos = FindOptimalSpillingPos(range, split_pos); | 1850 auto spill_pos = FindOptimalSpillingPos(range, split_pos); |
| 2320 if (next_pos == nullptr) { | 1851 if (next_pos == nullptr) { |
| 2321 SpillAfter(range, spill_pos); | 1852 SpillAfter(range, spill_pos); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 2349 SpillBetween(range, split_pos, next_intersection); | 1880 SpillBetween(range, split_pos, next_intersection); |
| 2350 } | 1881 } |
| 2351 InactiveToHandled(range); | 1882 InactiveToHandled(range); |
| 2352 --i; | 1883 --i; |
| 2353 } | 1884 } |
| 2354 } | 1885 } |
| 2355 } | 1886 } |
| 2356 } | 1887 } |
| 2357 | 1888 |
| 2358 | 1889 |
| 2359 bool RegisterAllocator::IsBlockBoundary(LifetimePosition pos) { | 1890 bool LinearScanAllocator::TryReuseSpillForPhi(LiveRange* range) { |
| 2360 return pos.IsFullStart() && | 1891 if (range->IsChild() || !range->is_phi()) return false; |
| 2361 code()->GetInstructionBlock(pos.ToInstructionIndex())->code_start() == | 1892 DCHECK(!range->HasSpillOperand()); |
| 2362 pos.ToInstructionIndex(); | 1893 |
| 1894 auto lookup = phi_map().find(range->id()); |
| 1895 DCHECK(lookup != phi_map().end()); |
| 1896 auto phi = lookup->second->phi; |
| 1897 auto block = lookup->second->block; |
| 1898 // Count the number of spilled operands. |
| 1899 size_t spilled_count = 0; |
| 1900 LiveRange* first_op = nullptr; |
| 1901 for (size_t i = 0; i < phi->operands().size(); i++) { |
| 1902 int op = phi->operands()[i]; |
| 1903 LiveRange* op_range = LiveRangeFor(op); |
| 1904 if (op_range->GetSpillRange() == nullptr) continue; |
| 1905 auto pred = code()->InstructionBlockAt(block->predecessors()[i]); |
| 1906 auto pred_end = LifetimePosition::InstructionFromInstructionIndex( |
| 1907 pred->last_instruction_index()); |
| 1908 while (op_range != nullptr && !op_range->CanCover(pred_end)) { |
| 1909 op_range = op_range->next(); |
| 1910 } |
| 1911 if (op_range != nullptr && op_range->IsSpilled()) { |
| 1912 spilled_count++; |
| 1913 if (first_op == nullptr) { |
| 1914 first_op = op_range->TopLevel(); |
| 1915 } |
| 1916 } |
| 1917 } |
| 1918 |
| 1919 // Only continue if more than half of the operands are spilled. |
| 1920 if (spilled_count * 2 <= phi->operands().size()) { |
| 1921 return false; |
| 1922 } |
| 1923 |
| 1924 // Try to merge the spilled operands and count the number of merged spilled |
| 1925 // operands. |
| 1926 DCHECK(first_op != nullptr); |
| 1927 auto first_op_spill = first_op->GetSpillRange(); |
| 1928 size_t num_merged = 1; |
| 1929 for (size_t i = 1; i < phi->operands().size(); i++) { |
| 1930 int op = phi->operands()[i]; |
| 1931 auto op_range = LiveRangeFor(op); |
| 1932 auto op_spill = op_range->GetSpillRange(); |
| 1933 if (op_spill != nullptr && |
| 1934 (op_spill == first_op_spill || first_op_spill->TryMerge(op_spill))) { |
| 1935 num_merged++; |
| 1936 } |
| 1937 } |
| 1938 |
| 1939 // Only continue if enough operands could be merged to the |
| 1940 // same spill slot. |
| 1941 if (num_merged * 2 <= phi->operands().size() || |
| 1942 AreUseIntervalsIntersecting(first_op_spill->interval(), |
| 1943 range->first_interval())) { |
| 1944 return false; |
| 1945 } |
| 1946 |
| 1947 // If the range does not need register soon, spill it to the merged |
| 1948 // spill range. |
| 1949 auto next_pos = range->Start(); |
| 1950 if (next_pos.IsGapPosition()) next_pos = next_pos.NextStart(); |
| 1951 auto pos = range->NextUsePositionRegisterIsBeneficial(next_pos); |
| 1952 if (pos == nullptr) { |
| 1953 auto spill_range = |
| 1954 range->TopLevel()->HasSpillRange() |
| 1955 ? range->TopLevel()->GetSpillRange() |
| 1956 : data()->AssignSpillRangeToLiveRange(range->TopLevel()); |
| 1957 bool merged = first_op_spill->TryMerge(spill_range); |
| 1958 CHECK(merged); |
| 1959 Spill(range); |
| 1960 return true; |
| 1961 } else if (pos->pos().Value() > range->Start().NextStart().Value()) { |
| 1962 auto spill_range = |
| 1963 range->TopLevel()->HasSpillRange() |
| 1964 ? range->TopLevel()->GetSpillRange() |
| 1965 : data()->AssignSpillRangeToLiveRange(range->TopLevel()); |
| 1966 bool merged = first_op_spill->TryMerge(spill_range); |
| 1967 CHECK(merged); |
| 1968 SpillBetween(range, range->Start(), pos->pos()); |
| 1969 DCHECK(UnhandledIsSorted()); |
| 1970 return true; |
| 1971 } |
| 1972 return false; |
| 2363 } | 1973 } |
| 2364 | 1974 |
| 2365 | 1975 |
| 2366 LiveRange* RegisterAllocator::SplitRangeAt(LiveRange* range, | 1976 LiveRange* LinearScanAllocator::SplitRangeAt(LiveRange* range, |
| 2367 LifetimePosition pos) { | 1977 LifetimePosition pos) { |
| 2368 DCHECK(!range->IsFixed()); | 1978 DCHECK(!range->IsFixed()); |
| 2369 TRACE("Splitting live range %d at %d\n", range->id(), pos.Value()); | 1979 TRACE("Splitting live range %d at %d\n", range->id(), pos.Value()); |
| 2370 | 1980 |
| 2371 if (pos.Value() <= range->Start().Value()) return range; | 1981 if (pos.Value() <= range->Start().Value()) return range; |
| 2372 | 1982 |
| 2373 // We can't properly connect liveranges if splitting occurred at the end | 1983 // We can't properly connect liveranges if splitting occurred at the end |
| 2374 // a block. | 1984 // a block. |
| 2375 DCHECK(pos.IsStart() || pos.IsGapPosition() || | 1985 DCHECK(pos.IsStart() || pos.IsGapPosition() || |
| 2376 (code()->GetInstructionBlock(pos.ToInstructionIndex())) | 1986 (code()->GetInstructionBlock(pos.ToInstructionIndex())) |
| 2377 ->last_instruction_index() != pos.ToInstructionIndex()); | 1987 ->last_instruction_index() != pos.ToInstructionIndex()); |
| 2378 | 1988 |
| 2379 int vreg = GetVirtualRegister(); | 1989 int vreg = GetVirtualRegister(); |
| 2380 auto result = LiveRangeFor(vreg); | 1990 auto result = LiveRangeFor(vreg); |
| 2381 range->SplitAt(pos, result, local_zone()); | 1991 range->SplitAt(pos, result, allocation_zone()); |
| 2382 return result; | 1992 return result; |
| 2383 } | 1993 } |
| 2384 | 1994 |
| 2385 | 1995 |
| 2386 LiveRange* RegisterAllocator::SplitBetween(LiveRange* range, | 1996 LiveRange* LinearScanAllocator::SplitBetween(LiveRange* range, |
| 2387 LifetimePosition start, | 1997 LifetimePosition start, |
| 2388 LifetimePosition end) { | 1998 LifetimePosition end) { |
| 2389 DCHECK(!range->IsFixed()); | 1999 DCHECK(!range->IsFixed()); |
| 2390 TRACE("Splitting live range %d in position between [%d, %d]\n", range->id(), | 2000 TRACE("Splitting live range %d in position between [%d, %d]\n", range->id(), |
| 2391 start.Value(), end.Value()); | 2001 start.Value(), end.Value()); |
| 2392 | 2002 |
| 2393 auto split_pos = FindOptimalSplitPos(start, end); | 2003 auto split_pos = FindOptimalSplitPos(start, end); |
| 2394 DCHECK(split_pos.Value() >= start.Value()); | 2004 DCHECK(split_pos.Value() >= start.Value()); |
| 2395 return SplitRangeAt(range, split_pos); | 2005 return SplitRangeAt(range, split_pos); |
| 2396 } | 2006 } |
| 2397 | 2007 |
| 2398 | 2008 |
| 2399 LifetimePosition RegisterAllocator::FindOptimalSplitPos(LifetimePosition start, | 2009 LifetimePosition LinearScanAllocator::FindOptimalSplitPos( |
| 2400 LifetimePosition end) { | 2010 LifetimePosition start, LifetimePosition end) { |
| 2401 int start_instr = start.ToInstructionIndex(); | 2011 int start_instr = start.ToInstructionIndex(); |
| 2402 int end_instr = end.ToInstructionIndex(); | 2012 int end_instr = end.ToInstructionIndex(); |
| 2403 DCHECK(start_instr <= end_instr); | 2013 DCHECK(start_instr <= end_instr); |
| 2404 | 2014 |
| 2405 // We have no choice | 2015 // We have no choice |
| 2406 if (start_instr == end_instr) return end; | 2016 if (start_instr == end_instr) return end; |
| 2407 | 2017 |
| 2408 auto start_block = GetInstructionBlock(start); | 2018 auto start_block = GetInstructionBlock(start); |
| 2409 auto end_block = GetInstructionBlock(end); | 2019 auto end_block = GetInstructionBlock(end); |
| 2410 | 2020 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 2425 | 2035 |
| 2426 // We did not find any suitable outer loop. Split at the latest possible | 2036 // We did not find any suitable outer loop. Split at the latest possible |
| 2427 // position unless end_block is a loop header itself. | 2037 // position unless end_block is a loop header itself. |
| 2428 if (block == end_block && !end_block->IsLoopHeader()) return end; | 2038 if (block == end_block && !end_block->IsLoopHeader()) return end; |
| 2429 | 2039 |
| 2430 return LifetimePosition::GapFromInstructionIndex( | 2040 return LifetimePosition::GapFromInstructionIndex( |
| 2431 block->first_instruction_index()); | 2041 block->first_instruction_index()); |
| 2432 } | 2042 } |
| 2433 | 2043 |
| 2434 | 2044 |
| 2435 void RegisterAllocator::SpillAfter(LiveRange* range, LifetimePosition pos) { | 2045 void LinearScanAllocator::SpillAfter(LiveRange* range, LifetimePosition pos) { |
| 2436 auto second_part = SplitRangeAt(range, pos); | 2046 auto second_part = SplitRangeAt(range, pos); |
| 2437 Spill(second_part); | 2047 Spill(second_part); |
| 2438 } | 2048 } |
| 2439 | 2049 |
| 2440 | 2050 |
| 2441 void RegisterAllocator::SpillBetween(LiveRange* range, LifetimePosition start, | 2051 void LinearScanAllocator::SpillBetween(LiveRange* range, LifetimePosition start, |
| 2442 LifetimePosition end) { | 2052 LifetimePosition end) { |
| 2443 SpillBetweenUntil(range, start, start, end); | 2053 SpillBetweenUntil(range, start, start, end); |
| 2444 } | 2054 } |
| 2445 | 2055 |
| 2446 | 2056 |
| 2447 void RegisterAllocator::SpillBetweenUntil(LiveRange* range, | 2057 void LinearScanAllocator::SpillBetweenUntil(LiveRange* range, |
| 2448 LifetimePosition start, | 2058 LifetimePosition start, |
| 2449 LifetimePosition until, | 2059 LifetimePosition until, |
| 2450 LifetimePosition end) { | 2060 LifetimePosition end) { |
| 2451 CHECK(start.Value() < end.Value()); | 2061 CHECK(start.Value() < end.Value()); |
| 2452 auto second_part = SplitRangeAt(range, start); | 2062 auto second_part = SplitRangeAt(range, start); |
| 2453 | 2063 |
| 2454 if (second_part->Start().Value() < end.Value()) { | 2064 if (second_part->Start().Value() < end.Value()) { |
| 2455 // The split result intersects with [start, end[. | 2065 // The split result intersects with [start, end[. |
| 2456 // Split it at position between ]start+1, end[, spill the middle part | 2066 // Split it at position between ]start+1, end[, spill the middle part |
| 2457 // and put the rest to unhandled. | 2067 // and put the rest to unhandled. |
| 2458 auto third_part_end = end.PrevStart().End(); | 2068 auto third_part_end = end.PrevStart().End(); |
| 2459 if (IsBlockBoundary(end.Start())) { | 2069 if (data()->IsBlockBoundary(end.Start())) { |
| 2460 third_part_end = end.Start(); | 2070 third_part_end = end.Start(); |
| 2461 } | 2071 } |
| 2462 auto third_part = SplitBetween( | 2072 auto third_part = SplitBetween( |
| 2463 second_part, Max(second_part->Start().End(), until), third_part_end); | 2073 second_part, Max(second_part->Start().End(), until), third_part_end); |
| 2464 | 2074 |
| 2465 DCHECK(third_part != second_part); | 2075 DCHECK(third_part != second_part); |
| 2466 | 2076 |
| 2467 Spill(second_part); | 2077 Spill(second_part); |
| 2468 AddToUnhandledSorted(third_part); | 2078 AddToUnhandledSorted(third_part); |
| 2469 } else { | 2079 } else { |
| 2470 // The split result does not intersect with [start, end[. | 2080 // The split result does not intersect with [start, end[. |
| 2471 // Nothing to spill. Just put it to unhandled as whole. | 2081 // Nothing to spill. Just put it to unhandled as whole. |
| 2472 AddToUnhandledSorted(second_part); | 2082 AddToUnhandledSorted(second_part); |
| 2473 } | 2083 } |
| 2474 } | 2084 } |
| 2475 | 2085 |
| 2476 | 2086 |
| 2477 void RegisterAllocator::Spill(LiveRange* range) { | 2087 void LinearScanAllocator::Spill(LiveRange* range) { |
| 2478 DCHECK(!range->IsSpilled()); | 2088 DCHECK(!range->IsSpilled()); |
| 2479 TRACE("Spilling live range %d\n", range->id()); | 2089 TRACE("Spilling live range %d\n", range->id()); |
| 2480 auto first = range->TopLevel(); | 2090 auto first = range->TopLevel(); |
| 2481 if (first->HasNoSpillType()) { | 2091 if (first->HasNoSpillType()) { |
| 2482 AssignSpillRangeToLiveRange(first); | 2092 data()->AssignSpillRangeToLiveRange(first); |
| 2483 } | 2093 } |
| 2484 range->MakeSpilled(); | 2094 range->MakeSpilled(); |
| 2485 } | 2095 } |
| 2486 | 2096 |
| 2487 | 2097 |
| 2488 int RegisterAllocator::RegisterCount() const { return num_registers_; } | 2098 OperandAssigner::OperandAssigner(RegisterAllocationData* data) : data_(data) {} |
| 2489 | 2099 |
| 2490 | 2100 |
| 2491 #ifdef DEBUG | 2101 void OperandAssigner::AssignSpillSlots() { |
| 2492 | 2102 auto& spill_ranges = data()->spill_ranges(); |
| 2493 | 2103 // Merge disjoint spill ranges |
| 2494 void RegisterAllocator::Verify() const { | 2104 for (size_t i = 0; i < spill_ranges.size(); i++) { |
| 2495 for (auto current : live_ranges()) { | 2105 auto range = spill_ranges[i]; |
| 2496 if (current != nullptr) current->Verify(); | 2106 if (range->IsEmpty()) continue; |
| 2497 } | 2107 for (size_t j = i + 1; j < spill_ranges.size(); j++) { |
| 2498 } | 2108 auto other = spill_ranges[j]; |
| 2499 | 2109 if (!other->IsEmpty()) { |
| 2500 | 2110 range->TryMerge(other); |
| 2501 #endif | 2111 } |
| 2502 | 2112 } |
| 2503 | 2113 } |
| 2504 void RegisterAllocator::SetLiveRangeAssignedRegister(LiveRange* range, | 2114 // Allocate slots for the merged spill ranges. |
| 2505 int reg) { | 2115 for (auto range : spill_ranges) { |
| 2506 if (range->Kind() == DOUBLE_REGISTERS) { | 2116 if (range->IsEmpty()) continue; |
| 2507 assigned_double_registers_->Add(reg); | 2117 // Allocate a new operand referring to the spill slot. |
| 2118 auto kind = range->Kind(); |
| 2119 int index = data()->frame()->AllocateSpillSlot(kind == DOUBLE_REGISTERS); |
| 2120 auto op_kind = kind == DOUBLE_REGISTERS |
| 2121 ? AllocatedOperand::DOUBLE_STACK_SLOT |
| 2122 : AllocatedOperand::STACK_SLOT; |
| 2123 auto op = AllocatedOperand::New(data()->code_zone(), op_kind, index); |
| 2124 range->SetOperand(op); |
| 2125 } |
| 2126 } |
| 2127 |
| 2128 |
| 2129 void OperandAssigner::CommitAssignment() { |
| 2130 for (auto range : data()->live_ranges()) { |
| 2131 if (range == nullptr || range->IsEmpty()) continue; |
| 2132 InstructionOperand* spill_operand = nullptr; |
| 2133 if (!range->TopLevel()->HasNoSpillType()) { |
| 2134 spill_operand = range->TopLevel()->GetSpillOperand(); |
| 2135 } |
| 2136 auto assigned = range->GetAssignedOperand(); |
| 2137 range->ConvertUsesToOperand(assigned, spill_operand); |
| 2138 if (range->is_phi()) data()->AssignPhiInput(range, assigned); |
| 2139 if (!range->IsChild() && spill_operand != nullptr) { |
| 2140 range->CommitSpillsAtDefinition(data()->code(), spill_operand, |
| 2141 range->has_slot_use()); |
| 2142 } |
| 2143 } |
| 2144 } |
| 2145 |
| 2146 |
| 2147 ReferenceMapPopulator::ReferenceMapPopulator(RegisterAllocationData* data) |
| 2148 : data_(data) {} |
| 2149 |
| 2150 |
| 2151 bool ReferenceMapPopulator::SafePointsAreInOrder() const { |
| 2152 int safe_point = 0; |
| 2153 for (auto map : *data()->code()->reference_maps()) { |
| 2154 if (safe_point > map->instruction_position()) return false; |
| 2155 safe_point = map->instruction_position(); |
| 2156 } |
| 2157 return true; |
| 2158 } |
| 2159 |
| 2160 |
| 2161 void ReferenceMapPopulator::PopulateReferenceMaps() { |
| 2162 DCHECK(SafePointsAreInOrder()); |
| 2163 |
| 2164 // Iterate over all safe point positions and record a pointer |
| 2165 // for all spilled live ranges at this point. |
| 2166 int last_range_start = 0; |
| 2167 auto reference_maps = data()->code()->reference_maps(); |
| 2168 ReferenceMapDeque::const_iterator first_it = reference_maps->begin(); |
| 2169 for (LiveRange* range : data()->live_ranges()) { |
| 2170 if (range == nullptr) continue; |
| 2171 // Iterate over the first parts of multi-part live ranges. |
| 2172 if (range->IsChild()) continue; |
| 2173 // Skip non-reference values. |
| 2174 if (!IsReference(range->id())) continue; |
| 2175 // Skip empty live ranges. |
| 2176 if (range->IsEmpty()) continue; |
| 2177 |
| 2178 // Find the extent of the range and its children. |
| 2179 int start = range->Start().ToInstructionIndex(); |
| 2180 int end = 0; |
| 2181 for (auto cur = range; cur != nullptr; cur = cur->next()) { |
| 2182 auto this_end = cur->End(); |
| 2183 if (this_end.ToInstructionIndex() > end) |
| 2184 end = this_end.ToInstructionIndex(); |
| 2185 DCHECK(cur->Start().ToInstructionIndex() >= start); |
| 2186 } |
| 2187 |
| 2188 // Most of the ranges are in order, but not all. Keep an eye on when they |
| 2189 // step backwards and reset the first_it so we don't miss any safe points. |
| 2190 if (start < last_range_start) first_it = reference_maps->begin(); |
| 2191 last_range_start = start; |
| 2192 |
| 2193 // Step across all the safe points that are before the start of this range, |
| 2194 // recording how far we step in order to save doing this for the next range. |
| 2195 for (; first_it != reference_maps->end(); ++first_it) { |
| 2196 auto map = *first_it; |
| 2197 if (map->instruction_position() >= start) break; |
| 2198 } |
| 2199 |
| 2200 // Step through the safe points to see whether they are in the range. |
| 2201 for (auto it = first_it; it != reference_maps->end(); ++it) { |
| 2202 auto map = *it; |
| 2203 int safe_point = map->instruction_position(); |
| 2204 |
| 2205 // The safe points are sorted so we can stop searching here. |
| 2206 if (safe_point - 1 > end) break; |
| 2207 |
| 2208 // Advance to the next active range that covers the current |
| 2209 // safe point position. |
| 2210 auto safe_point_pos = |
| 2211 LifetimePosition::InstructionFromInstructionIndex(safe_point); |
| 2212 auto cur = range; |
| 2213 while (cur != nullptr && !cur->Covers(safe_point_pos)) { |
| 2214 cur = cur->next(); |
| 2215 } |
| 2216 if (cur == nullptr) continue; |
| 2217 |
| 2218 // Check if the live range is spilled and the safe point is after |
| 2219 // the spill position. |
| 2220 if (range->HasSpillOperand() && |
| 2221 safe_point >= range->spill_start_index() && |
| 2222 !range->GetSpillOperand()->IsConstant()) { |
| 2223 TRACE("Pointer for range %d (spilled at %d) at safe point %d\n", |
| 2224 range->id(), range->spill_start_index(), safe_point); |
| 2225 map->RecordReference(*range->GetSpillOperand()); |
| 2226 } |
| 2227 |
| 2228 if (!cur->IsSpilled()) { |
| 2229 TRACE( |
| 2230 "Pointer in register for range %d (start at %d) " |
| 2231 "at safe point %d\n", |
| 2232 cur->id(), cur->Start().Value(), safe_point); |
| 2233 auto operand = cur->GetAssignedOperand(); |
| 2234 DCHECK(!operand.IsStackSlot()); |
| 2235 map->RecordReference(operand); |
| 2236 } |
| 2237 } |
| 2238 } |
| 2239 } |
| 2240 |
| 2241 |
| 2242 namespace { |
| 2243 |
| 2244 class LiveRangeBound { |
| 2245 public: |
| 2246 explicit LiveRangeBound(const LiveRange* range) |
| 2247 : range_(range), start_(range->Start()), end_(range->End()) { |
| 2248 DCHECK(!range->IsEmpty()); |
| 2249 } |
| 2250 |
| 2251 bool CanCover(LifetimePosition position) { |
| 2252 return start_.Value() <= position.Value() && |
| 2253 position.Value() < end_.Value(); |
| 2254 } |
| 2255 |
| 2256 const LiveRange* const range_; |
| 2257 const LifetimePosition start_; |
| 2258 const LifetimePosition end_; |
| 2259 |
| 2260 private: |
| 2261 DISALLOW_COPY_AND_ASSIGN(LiveRangeBound); |
| 2262 }; |
| 2263 |
| 2264 |
| 2265 struct FindResult { |
| 2266 const LiveRange* cur_cover_; |
| 2267 const LiveRange* pred_cover_; |
| 2268 }; |
| 2269 |
| 2270 |
| 2271 class LiveRangeBoundArray { |
| 2272 public: |
| 2273 LiveRangeBoundArray() : length_(0), start_(nullptr) {} |
| 2274 |
| 2275 bool ShouldInitialize() { return start_ == nullptr; } |
| 2276 |
| 2277 void Initialize(Zone* zone, const LiveRange* const range) { |
| 2278 size_t length = 0; |
| 2279 for (auto i = range; i != nullptr; i = i->next()) length++; |
| 2280 start_ = zone->NewArray<LiveRangeBound>(length); |
| 2281 length_ = length; |
| 2282 auto curr = start_; |
| 2283 for (auto i = range; i != nullptr; i = i->next(), ++curr) { |
| 2284 new (curr) LiveRangeBound(i); |
| 2285 } |
| 2286 } |
| 2287 |
| 2288 LiveRangeBound* Find(const LifetimePosition position) const { |
| 2289 size_t left_index = 0; |
| 2290 size_t right_index = length_; |
| 2291 while (true) { |
| 2292 size_t current_index = left_index + (right_index - left_index) / 2; |
| 2293 DCHECK(right_index > current_index); |
| 2294 auto bound = &start_[current_index]; |
| 2295 if (bound->start_.Value() <= position.Value()) { |
| 2296 if (position.Value() < bound->end_.Value()) return bound; |
| 2297 DCHECK(left_index < current_index); |
| 2298 left_index = current_index; |
| 2299 } else { |
| 2300 right_index = current_index; |
| 2301 } |
| 2302 } |
| 2303 } |
| 2304 |
| 2305 LiveRangeBound* FindPred(const InstructionBlock* pred) { |
| 2306 auto pred_end = LifetimePosition::InstructionFromInstructionIndex( |
| 2307 pred->last_instruction_index()); |
| 2308 return Find(pred_end); |
| 2309 } |
| 2310 |
| 2311 LiveRangeBound* FindSucc(const InstructionBlock* succ) { |
| 2312 auto succ_start = LifetimePosition::GapFromInstructionIndex( |
| 2313 succ->first_instruction_index()); |
| 2314 return Find(succ_start); |
| 2315 } |
| 2316 |
| 2317 void Find(const InstructionBlock* block, const InstructionBlock* pred, |
| 2318 FindResult* result) const { |
| 2319 auto pred_end = LifetimePosition::InstructionFromInstructionIndex( |
| 2320 pred->last_instruction_index()); |
| 2321 auto bound = Find(pred_end); |
| 2322 result->pred_cover_ = bound->range_; |
| 2323 auto cur_start = LifetimePosition::GapFromInstructionIndex( |
| 2324 block->first_instruction_index()); |
| 2325 // Common case. |
| 2326 if (bound->CanCover(cur_start)) { |
| 2327 result->cur_cover_ = bound->range_; |
| 2328 return; |
| 2329 } |
| 2330 result->cur_cover_ = Find(cur_start)->range_; |
| 2331 DCHECK(result->pred_cover_ != nullptr && result->cur_cover_ != nullptr); |
| 2332 } |
| 2333 |
| 2334 private: |
| 2335 size_t length_; |
| 2336 LiveRangeBound* start_; |
| 2337 |
| 2338 DISALLOW_COPY_AND_ASSIGN(LiveRangeBoundArray); |
| 2339 }; |
| 2340 |
| 2341 |
| 2342 class LiveRangeFinder { |
| 2343 public: |
| 2344 explicit LiveRangeFinder(const RegisterAllocationData* data) |
| 2345 : data_(data), |
| 2346 bounds_length_(static_cast<int>(data_->live_ranges().size())), |
| 2347 bounds_(data_->allocation_zone()->NewArray<LiveRangeBoundArray>( |
| 2348 bounds_length_)) { |
| 2349 for (int i = 0; i < bounds_length_; ++i) { |
| 2350 new (&bounds_[i]) LiveRangeBoundArray(); |
| 2351 } |
| 2352 } |
| 2353 |
| 2354 LiveRangeBoundArray* ArrayFor(int operand_index) { |
| 2355 DCHECK(operand_index < bounds_length_); |
| 2356 auto range = data_->live_ranges()[operand_index]; |
| 2357 DCHECK(range != nullptr && !range->IsEmpty()); |
| 2358 auto array = &bounds_[operand_index]; |
| 2359 if (array->ShouldInitialize()) { |
| 2360 array->Initialize(data_->allocation_zone(), range); |
| 2361 } |
| 2362 return array; |
| 2363 } |
| 2364 |
| 2365 private: |
| 2366 const RegisterAllocationData* const data_; |
| 2367 const int bounds_length_; |
| 2368 LiveRangeBoundArray* const bounds_; |
| 2369 |
| 2370 DISALLOW_COPY_AND_ASSIGN(LiveRangeFinder); |
| 2371 }; |
| 2372 |
| 2373 } // namespace |
| 2374 |
| 2375 |
| 2376 LiveRangeConnector::LiveRangeConnector(RegisterAllocationData* data) |
| 2377 : data_(data) {} |
| 2378 |
| 2379 |
| 2380 bool LiveRangeConnector::CanEagerlyResolveControlFlow( |
| 2381 const InstructionBlock* block) const { |
| 2382 if (block->PredecessorCount() != 1) return false; |
| 2383 return block->predecessors()[0].IsNext(block->rpo_number()); |
| 2384 } |
| 2385 |
| 2386 |
| 2387 void LiveRangeConnector::ResolveControlFlow() { |
| 2388 // Lazily linearize live ranges in memory for fast lookup. |
| 2389 LiveRangeFinder finder(data()); |
| 2390 auto& live_in_sets = data()->live_in_sets(); |
| 2391 for (auto block : code()->instruction_blocks()) { |
| 2392 if (CanEagerlyResolveControlFlow(block)) continue; |
| 2393 auto live = live_in_sets[block->rpo_number().ToInt()]; |
| 2394 BitVector::Iterator iterator(live); |
| 2395 while (!iterator.Done()) { |
| 2396 auto* array = finder.ArrayFor(iterator.Current()); |
| 2397 for (auto pred : block->predecessors()) { |
| 2398 FindResult result; |
| 2399 const auto* pred_block = code()->InstructionBlockAt(pred); |
| 2400 array->Find(block, pred_block, &result); |
| 2401 if (result.cur_cover_ == result.pred_cover_ || |
| 2402 result.cur_cover_->IsSpilled()) |
| 2403 continue; |
| 2404 auto pred_op = result.pred_cover_->GetAssignedOperand(); |
| 2405 auto cur_op = result.cur_cover_->GetAssignedOperand(); |
| 2406 if (pred_op == cur_op) continue; |
| 2407 ResolveControlFlow(block, cur_op, pred_block, pred_op); |
| 2408 } |
| 2409 iterator.Advance(); |
| 2410 } |
| 2411 } |
| 2412 } |
| 2413 |
| 2414 |
| 2415 void LiveRangeConnector::ResolveControlFlow(const InstructionBlock* block, |
| 2416 const InstructionOperand& cur_op, |
| 2417 const InstructionBlock* pred, |
| 2418 const InstructionOperand& pred_op) { |
| 2419 DCHECK(pred_op != cur_op); |
| 2420 int gap_index; |
| 2421 Instruction::GapPosition position; |
| 2422 if (block->PredecessorCount() == 1) { |
| 2423 gap_index = block->first_instruction_index(); |
| 2424 position = Instruction::START; |
| 2508 } else { | 2425 } else { |
| 2509 DCHECK(range->Kind() == GENERAL_REGISTERS); | 2426 DCHECK(pred->SuccessorCount() == 1); |
| 2510 assigned_registers_->Add(reg); | 2427 DCHECK(!data() |
| 2511 } | 2428 ->InstructionAt(pred->last_instruction_index()) |
| 2512 range->set_assigned_register(reg); | 2429 ->HasReferenceMap()); |
| 2513 auto assignment = range->GetAssignedOperand(); | 2430 gap_index = pred->last_instruction_index(); |
| 2514 // TODO(dcarney): stop aliasing hint operands. | 2431 position = Instruction::END; |
| 2515 range->ConvertUsesToOperand(assignment, nullptr); | 2432 } |
| 2516 if (range->is_phi()) AssignPhiInput(range, assignment); | 2433 data()->AddGapMove(gap_index, position, pred_op, cur_op); |
| 2434 } |
| 2435 |
| 2436 |
| 2437 void LiveRangeConnector::ConnectRanges(Zone* temp_zone) { |
| 2438 ZoneMap<std::pair<ParallelMove*, InstructionOperand>, InstructionOperand> |
| 2439 delayed_insertion_map(temp_zone); |
| 2440 for (auto first_range : data()->live_ranges()) { |
| 2441 if (first_range == nullptr || first_range->IsChild()) continue; |
| 2442 for (auto second_range = first_range->next(); second_range != nullptr; |
| 2443 first_range = second_range, second_range = second_range->next()) { |
| 2444 auto pos = second_range->Start(); |
| 2445 // Add gap move if the two live ranges touch and there is no block |
| 2446 // boundary. |
| 2447 if (second_range->IsSpilled()) continue; |
| 2448 if (first_range->End().Value() != pos.Value()) continue; |
| 2449 if (data()->IsBlockBoundary(pos) && |
| 2450 !CanEagerlyResolveControlFlow(GetInstructionBlock(pos))) { |
| 2451 continue; |
| 2452 } |
| 2453 auto prev_operand = first_range->GetAssignedOperand(); |
| 2454 auto cur_operand = second_range->GetAssignedOperand(); |
| 2455 if (prev_operand == cur_operand) continue; |
| 2456 bool delay_insertion = false; |
| 2457 Instruction::GapPosition gap_pos; |
| 2458 int gap_index = pos.ToInstructionIndex(); |
| 2459 if (pos.IsGapPosition()) { |
| 2460 gap_pos = pos.IsStart() ? Instruction::START : Instruction::END; |
| 2461 } else { |
| 2462 if (pos.IsStart()) { |
| 2463 delay_insertion = true; |
| 2464 } else { |
| 2465 gap_index++; |
| 2466 } |
| 2467 gap_pos = delay_insertion ? Instruction::END : Instruction::START; |
| 2468 } |
| 2469 auto move = code()->InstructionAt(gap_index)->GetOrCreateParallelMove( |
| 2470 gap_pos, code_zone()); |
| 2471 if (!delay_insertion) { |
| 2472 move->AddMove(prev_operand, cur_operand); |
| 2473 } else { |
| 2474 delayed_insertion_map.insert( |
| 2475 std::make_pair(std::make_pair(move, prev_operand), cur_operand)); |
| 2476 } |
| 2477 } |
| 2478 } |
| 2479 if (delayed_insertion_map.empty()) return; |
| 2480 // Insert all the moves which should occur after the stored move. |
| 2481 ZoneVector<MoveOperands*> to_insert(temp_zone); |
| 2482 ZoneVector<MoveOperands*> to_eliminate(temp_zone); |
| 2483 to_insert.reserve(4); |
| 2484 to_eliminate.reserve(4); |
| 2485 auto moves = delayed_insertion_map.begin()->first.first; |
| 2486 for (auto it = delayed_insertion_map.begin();; ++it) { |
| 2487 bool done = it == delayed_insertion_map.end(); |
| 2488 if (done || it->first.first != moves) { |
| 2489 // Commit the MoveOperands for current ParallelMove. |
| 2490 for (auto move : to_eliminate) { |
| 2491 move->Eliminate(); |
| 2492 } |
| 2493 for (auto move : to_insert) { |
| 2494 moves->push_back(move); |
| 2495 } |
| 2496 if (done) break; |
| 2497 // Reset state. |
| 2498 to_eliminate.clear(); |
| 2499 to_insert.clear(); |
| 2500 moves = it->first.first; |
| 2501 } |
| 2502 // Gather all MoveOperands for a single ParallelMove. |
| 2503 auto move = new (code_zone()) MoveOperands(it->first.second, it->second); |
| 2504 auto eliminate = moves->PrepareInsertAfter(move); |
| 2505 to_insert.push_back(move); |
| 2506 if (eliminate != nullptr) to_eliminate.push_back(eliminate); |
| 2507 } |
| 2517 } | 2508 } |
| 2518 | 2509 |
| 2519 } // namespace compiler | 2510 } // namespace compiler |
| 2520 } // namespace internal | 2511 } // namespace internal |
| 2521 } // namespace v8 | 2512 } // namespace v8 |
| OLD | NEW |