| 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 { |
| (...skipping 690 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 701 DCHECK(result->IsFixed()); | 701 DCHECK(result->IsFixed()); |
| 702 result->kind_ = DOUBLE_REGISTERS; | 702 result->kind_ = DOUBLE_REGISTERS; |
| 703 SetLiveRangeAssignedRegister(result, index); | 703 SetLiveRangeAssignedRegister(result, index); |
| 704 fixed_double_live_ranges()[index] = result; | 704 fixed_double_live_ranges()[index] = result; |
| 705 } | 705 } |
| 706 return result; | 706 return result; |
| 707 } | 707 } |
| 708 | 708 |
| 709 | 709 |
| 710 LiveRange* RegisterAllocator::LiveRangeFor(int index) { | 710 LiveRange* RegisterAllocator::LiveRangeFor(int index) { |
| 711 if (index >= static_cast<int>(live_ranges_.size())) { | 711 if (index >= static_cast<int>(live_ranges().size())) { |
| 712 live_ranges_.resize(index + 1, nullptr); | 712 live_ranges().resize(index + 1, nullptr); |
| 713 } | 713 } |
| 714 auto result = live_ranges()[index]; | 714 auto result = live_ranges()[index]; |
| 715 if (result == nullptr) { | 715 if (result == nullptr) { |
| 716 result = new (local_zone()) LiveRange(index, code_zone()); | 716 result = new (local_zone()) LiveRange(index, code_zone()); |
| 717 live_ranges()[index] = result; | 717 live_ranges()[index] = result; |
| 718 } | 718 } |
| 719 return result; | 719 return result; |
| 720 } | 720 } |
| 721 | 721 |
| 722 | 722 |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 810 if (interval2->end().Value() > interval1->start().Value()) { | 810 if (interval2->end().Value() > interval1->start().Value()) { |
| 811 return true; | 811 return true; |
| 812 } | 812 } |
| 813 interval2 = interval2->next(); | 813 interval2 = interval2->next(); |
| 814 } | 814 } |
| 815 } | 815 } |
| 816 return false; | 816 return false; |
| 817 } | 817 } |
| 818 | 818 |
| 819 | 819 |
| 820 SpillRange::SpillRange(LiveRange* range, int id, Zone* zone) | 820 SpillRange::SpillRange(LiveRange* range, Zone* zone) : live_ranges_(zone) { |
| 821 : id_(id), live_ranges_(1, zone), end_position_(range->End()) { | |
| 822 auto src = range->first_interval(); | 821 auto src = range->first_interval(); |
| 823 UseInterval* result = nullptr; | 822 UseInterval* result = nullptr; |
| 824 UseInterval* node = nullptr; | 823 UseInterval* node = nullptr; |
| 825 // Copy the nodes | 824 // Copy the nodes |
| 826 while (src != nullptr) { | 825 while (src != nullptr) { |
| 827 UseInterval* new_node = new (zone) UseInterval(src->start(), src->end()); | 826 auto new_node = new (zone) UseInterval(src->start(), src->end()); |
| 828 if (result == nullptr) { | 827 if (result == nullptr) { |
| 829 result = new_node; | 828 result = new_node; |
| 830 } else { | 829 } else { |
| 831 node->set_next(new_node); | 830 node->set_next(new_node); |
| 832 } | 831 } |
| 833 node = new_node; | 832 node = new_node; |
| 834 src = src->next(); | 833 src = src->next(); |
| 835 } | 834 } |
| 836 use_interval_ = result; | 835 use_interval_ = result; |
| 837 live_ranges_.Add(range, zone); | 836 live_ranges().push_back(range); |
| 837 end_position_ = node->end(); |
| 838 DCHECK(!range->HasSpillRange()); | 838 DCHECK(!range->HasSpillRange()); |
| 839 range->SetSpillRange(this); | 839 range->SetSpillRange(this); |
| 840 } | 840 } |
| 841 | 841 |
| 842 | 842 |
| 843 bool SpillRange::IsIntersectingWith(SpillRange* other) { | 843 bool SpillRange::IsIntersectingWith(SpillRange* other) const { |
| 844 if (End().Value() <= other->use_interval_->start().Value() || | 844 if (this->use_interval_ == nullptr || other->use_interval_ == nullptr || |
| 845 other->End().Value() <= use_interval_->start().Value()) { | 845 this->End().Value() <= other->use_interval_->start().Value() || |
| 846 other->End().Value() <= this->use_interval_->start().Value()) { |
| 846 return false; | 847 return false; |
| 847 } | 848 } |
| 848 return AreUseIntervalsIntersecting(use_interval_, other->use_interval_); | 849 return AreUseIntervalsIntersecting(use_interval_, other->use_interval_); |
| 849 } | 850 } |
| 850 | 851 |
| 851 | 852 |
| 852 bool SpillRange::TryMerge(SpillRange* other, Zone* zone) { | 853 bool SpillRange::TryMerge(SpillRange* other) { |
| 853 if (Kind() == other->Kind() && | 854 if (Kind() != other->Kind() || IsIntersectingWith(other)) return false; |
| 854 !AreUseIntervalsIntersecting(use_interval_, other->use_interval_)) { | |
| 855 if (End().Value() < other->End().Value()) { | |
| 856 end_position_ = other->End(); | |
| 857 } | |
| 858 | 855 |
| 859 MergeDisjointIntervals(other->use_interval_, zone); | 856 auto max = LifetimePosition::MaxPosition(); |
| 860 other->use_interval_ = nullptr; | 857 if (End().Value() < other->End().Value() && |
| 858 other->End().Value() != max.Value()) { |
| 859 end_position_ = other->End(); |
| 860 } |
| 861 other->end_position_ = max; |
| 861 | 862 |
| 862 for (int i = 0; i < other->live_ranges_.length(); i++) { | 863 MergeDisjointIntervals(other->use_interval_); |
| 863 DCHECK(other->live_ranges_.at(i)->GetSpillRange() == other); | 864 other->use_interval_ = nullptr; |
| 864 other->live_ranges_.at(i)->SetSpillRange(this); | |
| 865 } | |
| 866 | 865 |
| 867 live_ranges_.AddAll(other->live_ranges_, zone); | 866 for (auto range : other->live_ranges()) { |
| 868 other->live_ranges_.Clear(); | 867 DCHECK(range->GetSpillRange() == other); |
| 868 range->SetSpillRange(this); |
| 869 } |
| 869 | 870 |
| 870 return true; | 871 live_ranges().insert(live_ranges().end(), other->live_ranges().begin(), |
| 871 } | 872 other->live_ranges().end()); |
| 872 return false; | 873 other->live_ranges().clear(); |
| 874 |
| 875 return true; |
| 873 } | 876 } |
| 874 | 877 |
| 875 | 878 |
| 876 void SpillRange::SetOperand(InstructionOperand* op) { | 879 void SpillRange::SetOperand(InstructionOperand* op) { |
| 877 for (int i = 0; i < live_ranges_.length(); i++) { | 880 for (auto range : live_ranges()) { |
| 878 DCHECK(live_ranges_.at(i)->GetSpillRange() == this); | 881 DCHECK(range->GetSpillRange() == this); |
| 879 live_ranges_.at(i)->CommitSpillOperand(op); | 882 range->CommitSpillOperand(op); |
| 880 } | 883 } |
| 881 } | 884 } |
| 882 | 885 |
| 883 | 886 |
| 884 void SpillRange::MergeDisjointIntervals(UseInterval* other, Zone* zone) { | 887 void SpillRange::MergeDisjointIntervals(UseInterval* other) { |
| 885 UseInterval* tail = nullptr; | 888 UseInterval* tail = nullptr; |
| 886 auto current = use_interval_; | 889 auto current = use_interval_; |
| 887 while (other != nullptr) { | 890 while (other != nullptr) { |
| 888 // Make sure the 'current' list starts first | 891 // Make sure the 'current' list starts first |
| 889 if (current == nullptr || | 892 if (current == nullptr || |
| 890 current->start().Value() > other->start().Value()) { | 893 current->start().Value() > other->start().Value()) { |
| 891 std::swap(current, other); | 894 std::swap(current, other); |
| 892 } | 895 } |
| 893 | |
| 894 // Check disjointness | 896 // Check disjointness |
| 895 DCHECK(other == nullptr || | 897 DCHECK(other == nullptr || |
| 896 current->end().Value() <= other->start().Value()); | 898 current->end().Value() <= other->start().Value()); |
| 897 | |
| 898 // Append the 'current' node to the result accumulator and move forward | 899 // Append the 'current' node to the result accumulator and move forward |
| 899 if (tail == nullptr) { | 900 if (tail == nullptr) { |
| 900 use_interval_ = current; | 901 use_interval_ = current; |
| 901 } else { | 902 } else { |
| 902 tail->set_next(current); | 903 tail->set_next(current); |
| 903 } | 904 } |
| 904 tail = current; | 905 tail = current; |
| 905 current = current->next(); | 906 current = current->next(); |
| 906 } | 907 } |
| 907 // Other list is empty => we are done | 908 // Other list is empty => we are done |
| 908 } | 909 } |
| 909 | 910 |
| 910 | 911 |
| 911 void RegisterAllocator::ReuseSpillSlots() { | 912 void RegisterAllocator::ReuseSpillSlots() { |
| 912 DCHECK(FLAG_turbo_reuse_spill_slots); | 913 DCHECK(FLAG_turbo_reuse_spill_slots); |
| 913 | 914 |
| 914 // Merge disjoint spill ranges | 915 // Merge disjoint spill ranges |
| 915 for (size_t i = 0; i < spill_ranges().size(); i++) { | 916 for (size_t i = 0; i < spill_ranges().size(); i++) { |
| 916 auto range = spill_ranges()[i]; | 917 auto range = spill_ranges()[i]; |
| 917 if (range->IsEmpty()) continue; | 918 if (range->IsEmpty()) continue; |
| 918 for (size_t j = i + 1; j < spill_ranges().size(); j++) { | 919 for (size_t j = i + 1; j < spill_ranges().size(); j++) { |
| 919 auto other = spill_ranges()[j]; | 920 auto other = spill_ranges()[j]; |
| 920 if (!other->IsEmpty()) { | 921 if (!other->IsEmpty()) { |
| 921 range->TryMerge(other, local_zone()); | 922 range->TryMerge(other); |
| 922 } | 923 } |
| 923 } | 924 } |
| 924 } | 925 } |
| 925 | 926 |
| 926 // Allocate slots for the merged spill ranges. | 927 // Allocate slots for the merged spill ranges. |
| 927 for (auto range : spill_ranges()) { | 928 for (auto range : spill_ranges()) { |
| 928 if (range->IsEmpty()) continue; | 929 if (range->IsEmpty()) continue; |
| 929 // Allocate a new operand referring to the spill slot. | 930 // Allocate a new operand referring to the spill slot. |
| 930 auto kind = range->Kind(); | 931 auto kind = range->Kind(); |
| 931 int index = frame()->AllocateSpillSlot(kind == DOUBLE_REGISTERS); | 932 int index = frame()->AllocateSpillSlot(kind == DOUBLE_REGISTERS); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 945 range->ConvertUsesToOperand(assigned); | 946 range->ConvertUsesToOperand(assigned); |
| 946 if (range->IsSpilled()) { | 947 if (range->IsSpilled()) { |
| 947 range->CommitSpillsAtDefinition(code(), assigned); | 948 range->CommitSpillsAtDefinition(code(), assigned); |
| 948 } | 949 } |
| 949 } | 950 } |
| 950 } | 951 } |
| 951 | 952 |
| 952 | 953 |
| 953 SpillRange* RegisterAllocator::AssignSpillRangeToLiveRange(LiveRange* range) { | 954 SpillRange* RegisterAllocator::AssignSpillRangeToLiveRange(LiveRange* range) { |
| 954 DCHECK(FLAG_turbo_reuse_spill_slots); | 955 DCHECK(FLAG_turbo_reuse_spill_slots); |
| 955 int spill_id = static_cast<int>(spill_ranges().size()); | 956 auto spill_range = new (local_zone()) SpillRange(range, local_zone()); |
| 956 auto spill_range = | |
| 957 new (local_zone()) SpillRange(range, spill_id, local_zone()); | |
| 958 spill_ranges().push_back(spill_range); | 957 spill_ranges().push_back(spill_range); |
| 959 return spill_range; | 958 return spill_range; |
| 960 } | 959 } |
| 961 | 960 |
| 962 | 961 |
| 963 bool RegisterAllocator::TryReuseSpillForPhi(LiveRange* range) { | 962 bool RegisterAllocator::TryReuseSpillForPhi(LiveRange* range) { |
| 964 DCHECK(FLAG_turbo_reuse_spill_slots); | 963 DCHECK(FLAG_turbo_reuse_spill_slots); |
| 965 DCHECK(range->HasNoSpillType()); | 964 DCHECK(range->HasNoSpillType()); |
| 966 if (range->IsChild() || !range->is_phi()) return false; | 965 if (range->IsChild() || !range->is_phi()) return false; |
| 967 | 966 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 997 | 996 |
| 998 // Try to merge the spilled operands and count the number of merged spilled | 997 // Try to merge the spilled operands and count the number of merged spilled |
| 999 // operands. | 998 // operands. |
| 1000 DCHECK(first_op != nullptr); | 999 DCHECK(first_op != nullptr); |
| 1001 auto first_op_spill = first_op->GetSpillRange(); | 1000 auto first_op_spill = first_op->GetSpillRange(); |
| 1002 size_t num_merged = 1; | 1001 size_t num_merged = 1; |
| 1003 for (size_t i = 1; i < phi->operands().size(); i++) { | 1002 for (size_t i = 1; i < phi->operands().size(); i++) { |
| 1004 int op = phi->operands()[i]; | 1003 int op = phi->operands()[i]; |
| 1005 auto op_range = LiveRangeFor(op); | 1004 auto op_range = LiveRangeFor(op); |
| 1006 auto op_spill = op_range->GetSpillRange(); | 1005 auto op_spill = op_range->GetSpillRange(); |
| 1007 if (op_spill != nullptr) { | 1006 if (op_spill != nullptr && |
| 1008 if (op_spill->id() == first_op_spill->id() || | 1007 (op_spill == first_op_spill || first_op_spill->TryMerge(op_spill))) { |
| 1009 first_op_spill->TryMerge(op_spill, local_zone())) { | 1008 num_merged++; |
| 1010 num_merged++; | |
| 1011 } | |
| 1012 } | 1009 } |
| 1013 } | 1010 } |
| 1014 | 1011 |
| 1015 // Only continue if enough operands could be merged to the | 1012 // Only continue if enough operands could be merged to the |
| 1016 // same spill slot. | 1013 // same spill slot. |
| 1017 if (num_merged * 2 <= phi->operands().size() || | 1014 if (num_merged * 2 <= phi->operands().size() || |
| 1018 AreUseIntervalsIntersecting(first_op_spill->interval(), | 1015 AreUseIntervalsIntersecting(first_op_spill->interval(), |
| 1019 range->first_interval())) { | 1016 range->first_interval())) { |
| 1020 return false; | 1017 return false; |
| 1021 } | 1018 } |
| 1022 | 1019 |
| 1023 // If the range does not need register soon, spill it to the merged | 1020 // If the range does not need register soon, spill it to the merged |
| 1024 // spill range. | 1021 // spill range. |
| 1025 auto next_pos = range->Start(); | 1022 auto next_pos = range->Start(); |
| 1026 if (code()->IsGapAt(next_pos.InstructionIndex())) { | 1023 if (code()->IsGapAt(next_pos.InstructionIndex())) { |
| 1027 next_pos = next_pos.NextInstruction(); | 1024 next_pos = next_pos.NextInstruction(); |
| 1028 } | 1025 } |
| 1029 auto pos = range->NextUsePositionRegisterIsBeneficial(next_pos); | 1026 auto pos = range->NextUsePositionRegisterIsBeneficial(next_pos); |
| 1030 if (pos == nullptr) { | 1027 if (pos == nullptr) { |
| 1031 auto spill_range = AssignSpillRangeToLiveRange(range->TopLevel()); | 1028 auto spill_range = AssignSpillRangeToLiveRange(range->TopLevel()); |
| 1032 CHECK(first_op_spill->TryMerge(spill_range, local_zone())); | 1029 CHECK(first_op_spill->TryMerge(spill_range)); |
| 1033 Spill(range); | 1030 Spill(range); |
| 1034 return true; | 1031 return true; |
| 1035 } else if (pos->pos().Value() > range->Start().NextInstruction().Value()) { | 1032 } else if (pos->pos().Value() > range->Start().NextInstruction().Value()) { |
| 1036 auto spill_range = AssignSpillRangeToLiveRange(range->TopLevel()); | 1033 auto spill_range = AssignSpillRangeToLiveRange(range->TopLevel()); |
| 1037 CHECK(first_op_spill->TryMerge(spill_range, local_zone())); | 1034 CHECK(first_op_spill->TryMerge(spill_range)); |
| 1038 SpillBetween(range, range->Start(), pos->pos()); | 1035 SpillBetween(range, range->Start(), pos->pos()); |
| 1039 if (!AllocationOk()) return false; | 1036 if (!AllocationOk()) return false; |
| 1040 DCHECK(UnhandledIsSorted()); | 1037 DCHECK(UnhandledIsSorted()); |
| 1041 return true; | 1038 return true; |
| 1042 } | 1039 } |
| 1043 return false; | 1040 return false; |
| 1044 } | 1041 } |
| 1045 | 1042 |
| 1046 | 1043 |
| 1047 void RegisterAllocator::MeetRegisterConstraints(const InstructionBlock* block) { | 1044 void RegisterAllocator::MeetRegisterConstraints(const InstructionBlock* block) { |
| (...skipping 1498 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2546 } else { | 2543 } else { |
| 2547 DCHECK(range->Kind() == GENERAL_REGISTERS); | 2544 DCHECK(range->Kind() == GENERAL_REGISTERS); |
| 2548 assigned_registers_->Add(reg); | 2545 assigned_registers_->Add(reg); |
| 2549 } | 2546 } |
| 2550 range->set_assigned_register(reg); | 2547 range->set_assigned_register(reg); |
| 2551 } | 2548 } |
| 2552 | 2549 |
| 2553 } // namespace compiler | 2550 } // namespace compiler |
| 2554 } // namespace internal | 2551 } // namespace internal |
| 2555 } // namespace v8 | 2552 } // namespace v8 |
| OLD | NEW |