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 |