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/base/adapters.h" | 5 #include "src/base/adapters.h" |
6 #include "src/compiler/linkage.h" | 6 #include "src/compiler/linkage.h" |
7 #include "src/compiler/register-allocator.h" | 7 #include "src/compiler/register-allocator.h" |
8 #include "src/string-stream.h" | 8 #include "src/string-stream.h" |
9 | 9 |
10 namespace v8 { | 10 namespace v8 { |
(...skipping 680 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
691 TopLevelLiveRange::TopLevelLiveRange(int vreg, MachineType machine_type) | 691 TopLevelLiveRange::TopLevelLiveRange(int vreg, MachineType machine_type) |
692 : LiveRange(0, machine_type, this), | 692 : LiveRange(0, machine_type, this), |
693 vreg_(vreg), | 693 vreg_(vreg), |
694 last_child_id_(0), | 694 last_child_id_(0), |
695 splintered_from_(nullptr), | 695 splintered_from_(nullptr), |
696 spill_operand_(nullptr), | 696 spill_operand_(nullptr), |
697 spills_at_definition_(nullptr), | 697 spills_at_definition_(nullptr), |
698 spilled_in_deferred_blocks_(false), | 698 spilled_in_deferred_blocks_(false), |
699 spill_start_index_(kMaxInt), | 699 spill_start_index_(kMaxInt), |
700 last_child_(this), | 700 last_child_(this), |
701 last_pos_(nullptr), | 701 last_insertion_point_(this) { |
702 splinter_(nullptr) { | |
703 bits_ |= SpillTypeField::encode(SpillType::kNoSpillType); | 702 bits_ |= SpillTypeField::encode(SpillType::kNoSpillType); |
704 } | 703 } |
705 | 704 |
706 | 705 |
707 void TopLevelLiveRange::SpillAtDefinition(Zone* zone, int gap_index, | 706 void TopLevelLiveRange::SpillAtDefinition(Zone* zone, int gap_index, |
708 InstructionOperand* operand) { | 707 InstructionOperand* operand) { |
709 DCHECK(HasNoSpillType()); | 708 DCHECK(HasNoSpillType()); |
710 spills_at_definition_ = new (zone) | 709 spills_at_definition_ = new (zone) |
711 SpillAtDefinitionList(gap_index, operand, spills_at_definition_); | 710 SpillAtDefinitionList(gap_index, operand, spills_at_definition_); |
712 } | 711 } |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
839 return StackSlotOperand(machine_type(), index); | 838 return StackSlotOperand(machine_type(), index); |
840 case DOUBLE_REGISTERS: | 839 case DOUBLE_REGISTERS: |
841 return DoubleStackSlotOperand(machine_type(), index); | 840 return DoubleStackSlotOperand(machine_type(), index); |
842 } | 841 } |
843 UNREACHABLE(); | 842 UNREACHABLE(); |
844 return StackSlotOperand(kMachNone, 0); | 843 return StackSlotOperand(kMachNone, 0); |
845 } | 844 } |
846 | 845 |
847 | 846 |
848 void TopLevelLiveRange::Splinter(LifetimePosition start, LifetimePosition end, | 847 void TopLevelLiveRange::Splinter(LifetimePosition start, LifetimePosition end, |
849 Zone* zone) { | 848 TopLevelLiveRange* result, Zone* zone) { |
850 DCHECK(start != Start() || end != End()); | 849 DCHECK(start != Start() || end != End()); |
851 DCHECK(start < end); | 850 DCHECK(start < end); |
852 | 851 |
853 TopLevelLiveRange splinter_temp(-1, machine_type()); | 852 result->set_spill_type(spill_type()); |
854 UsePosition* last_in_splinter = nullptr; | 853 |
855 if (start <= Start()) { | 854 if (start <= Start()) { |
856 // TODO(mtrofin): here, the TopLevel part is in the deferred range, so we | 855 // TODO(mtrofin): here, the TopLevel part is in the deferred range, so we |
857 // may want to continue processing the splinter. However, if the value is | 856 // may want to continue processing the splinter. However, if the value is |
858 // defined in a cold block, and then used in a hot block, it follows that | 857 // defined in a cold block, and then used in a hot block, it follows that |
859 // it should terminate on the RHS of a phi, defined on the hot path. We | 858 // it should terminate on the RHS of a phi, defined on the hot path. We |
860 // should check this, however, this may not be the place, because we don't | 859 // should check this, however, this may not be the place, because we don't |
861 // have access to the instruction sequence. | 860 // have access to the instruction sequence. |
862 DCHECK(end < End()); | 861 DCHECK(end < End()); |
863 DetachAt(end, &splinter_temp, zone); | 862 DetachAt(end, result, zone); |
864 next_ = nullptr; | 863 next_ = nullptr; |
865 } else if (end >= End()) { | 864 } else if (end >= End()) { |
866 DCHECK(start > Start()); | 865 DCHECK(start > Start()); |
867 DetachAt(start, &splinter_temp, zone); | 866 DetachAt(start, result, zone); |
868 next_ = nullptr; | 867 next_ = nullptr; |
869 } else { | 868 } else { |
870 DCHECK(start < End() && Start() < end); | 869 DCHECK(start < End() && Start() < end); |
871 | 870 |
872 const int kInvalidId = std::numeric_limits<int>::max(); | 871 const int kInvalidId = std::numeric_limits<int>::max(); |
873 | 872 |
874 UsePosition* last = DetachAt(start, &splinter_temp, zone); | 873 UsePosition* last = DetachAt(start, result, zone); |
875 | 874 |
876 LiveRange end_part(kInvalidId, this->machine_type(), nullptr); | 875 LiveRange end_part(kInvalidId, this->machine_type(), nullptr); |
877 last_in_splinter = splinter_temp.DetachAt(end, &end_part, zone); | 876 result->DetachAt(end, &end_part, zone); |
878 | 877 |
879 next_ = end_part.next_; | 878 next_ = end_part.next_; |
880 last_interval_->set_next(end_part.first_interval_); | 879 last_interval_->set_next(end_part.first_interval_); |
881 // The next splinter will happen either at or after the current interval. | 880 // The next splinter will happen either at or after the current interval. |
882 // We can optimize DetachAt by setting current_interval_ accordingly, | 881 // We can optimize DetachAt by setting current_interval_ accordingly, |
883 // which will then be picked up by FirstSearchIntervalForPosition. | 882 // which will then be picked up by FirstSearchIntervalForPosition. |
884 current_interval_ = last_interval_; | 883 current_interval_ = last_interval_; |
885 last_interval_ = end_part.last_interval_; | 884 last_interval_ = end_part.last_interval_; |
886 | 885 |
887 if (first_pos_ == nullptr) { | 886 if (first_pos_ == nullptr) { |
888 first_pos_ = end_part.first_pos_; | 887 first_pos_ = end_part.first_pos_; |
889 } else { | 888 } else { |
890 splitting_pointer_ = last; | 889 splitting_pointer_ = last; |
891 if (last != nullptr) last->set_next(end_part.first_pos_); | 890 if (last != nullptr) last->set_next(end_part.first_pos_); |
892 } | 891 } |
893 } | 892 } |
| 893 result->next_ = nullptr; |
| 894 result->top_level_ = result; |
894 | 895 |
895 if (splinter()->IsEmpty()) { | 896 result->SetSplinteredFrom(this); |
896 splinter()->first_interval_ = splinter_temp.first_interval_; | 897 // Ensure the result's relative ID is unique within the IDs used for this |
897 splinter()->last_interval_ = splinter_temp.last_interval_; | 898 // virtual register's children and splinters. |
898 } else { | 899 result->relative_id_ = GetNextChildId(); |
899 splinter()->last_interval_->set_next(splinter_temp.first_interval_); | |
900 splinter()->last_interval_ = splinter_temp.last_interval_; | |
901 } | |
902 if (splinter()->first_pos() == nullptr) { | |
903 splinter()->first_pos_ = splinter_temp.first_pos_; | |
904 } else { | |
905 splinter()->last_pos_->set_next(splinter_temp.first_pos_); | |
906 } | |
907 if (last_in_splinter != nullptr) { | |
908 splinter()->last_pos_ = last_in_splinter; | |
909 } else { | |
910 if (splinter()->first_pos() != nullptr && | |
911 splinter()->last_pos_ == nullptr) { | |
912 splinter()->last_pos_ = splinter()->first_pos(); | |
913 for (UsePosition* pos = splinter()->first_pos(); pos != nullptr; | |
914 pos = pos->next()) { | |
915 splinter()->last_pos_ = pos; | |
916 } | |
917 } | |
918 } | |
919 #if DEBUG | |
920 Verify(); | |
921 splinter()->Verify(); | |
922 #endif | |
923 } | 900 } |
924 | 901 |
925 | 902 |
926 void TopLevelLiveRange::SetSplinteredFrom(TopLevelLiveRange* splinter_parent) { | 903 void TopLevelLiveRange::SetSplinteredFrom(TopLevelLiveRange* splinter_parent) { |
| 904 // The splinter parent is always the original "Top". |
| 905 DCHECK(splinter_parent->Start() < Start()); |
| 906 |
927 splintered_from_ = splinter_parent; | 907 splintered_from_ = splinter_parent; |
928 if (!HasSpillOperand() && splinter_parent->spill_range_ != nullptr) { | 908 if (!HasSpillOperand() && splinter_parent->spill_range_ != nullptr) { |
929 SetSpillRange(splinter_parent->spill_range_); | 909 SetSpillRange(splinter_parent->spill_range_); |
930 } | 910 } |
931 } | 911 } |
932 | 912 |
933 | 913 |
934 void TopLevelLiveRange::UpdateSpillRangePostMerge(TopLevelLiveRange* merged) { | 914 void TopLevelLiveRange::UpdateSpillRangePostMerge(TopLevelLiveRange* merged) { |
935 DCHECK(merged->TopLevel() == this); | 915 DCHECK(merged->TopLevel() == this); |
936 | 916 |
937 if (HasNoSpillType() && merged->HasSpillRange()) { | 917 if (HasNoSpillType() && merged->HasSpillRange()) { |
938 set_spill_type(merged->spill_type()); | 918 set_spill_type(merged->spill_type()); |
939 DCHECK(GetSpillRange()->live_ranges().size() > 0); | 919 DCHECK(GetSpillRange()->live_ranges().size() > 0); |
940 merged->spill_range_ = nullptr; | 920 merged->spill_range_ = nullptr; |
941 merged->bits_ = | 921 merged->bits_ = |
942 SpillTypeField::update(merged->bits_, SpillType::kNoSpillType); | 922 SpillTypeField::update(merged->bits_, SpillType::kNoSpillType); |
943 } | 923 } |
944 } | 924 } |
945 | 925 |
946 | 926 |
947 void TopLevelLiveRange::Merge(TopLevelLiveRange* other, Zone* zone) { | 927 void TopLevelLiveRange::Merge(TopLevelLiveRange* other, Zone* zone) { |
948 DCHECK(Start() < other->Start()); | 928 DCHECK(Start() < other->Start()); |
949 DCHECK(other->splintered_from() == this); | 929 DCHECK(other->splintered_from() == this); |
950 | 930 |
951 LiveRange* first = this; | 931 LiveRange* last_other = other->last_child(); |
952 LiveRange* second = other; | 932 LiveRange* last_me = last_child(); |
953 DCHECK(first->Start() < second->Start()); | |
954 while (first != nullptr && second != nullptr) { | |
955 DCHECK(first != second); | |
956 // Make sure the ranges are in order each time we iterate. | |
957 if (second->Start() < first->Start()) { | |
958 LiveRange* tmp = second; | |
959 second = first; | |
960 first = tmp; | |
961 continue; | |
962 } | |
963 | 933 |
964 if (first->End() <= second->Start()) { | 934 // Simple case: we just append at the end. |
965 if (first->next() == nullptr || | 935 if (last_me->End() <= other->Start()) return last_me->AppendAsChild(other); |
966 first->next()->Start() > second->Start()) { | |
967 // First is in order before second. | |
968 LiveRange* temp = first->next(); | |
969 first->next_ = second; | |
970 first = temp; | |
971 } else { | |
972 // First is in order before its successor (or second), so advance first. | |
973 first = first->next(); | |
974 } | |
975 continue; | |
976 } | |
977 | 936 |
978 DCHECK(first->Start() < second->Start()); | 937 DCHECK(last_me->End() > last_other->End()); |
979 // If first and second intersect, split first. | |
980 if (first->Start() < second->End() && second->Start() < first->End()) { | |
981 LiveRange* temp = first->SplitAt(second->Start(), zone); | |
982 | 938 |
983 temp->set_spilled(first->spilled()); | 939 // In the more general case, we need to find the ranges between which to |
984 if (!temp->spilled()) | 940 // insert. |
985 temp->set_assigned_register(first->assigned_register()); | 941 if (other->Start() < last_insertion_point_->Start()) { |
986 | 942 last_insertion_point_ = this; |
987 first->next_ = second; | |
988 first = temp; | |
989 continue; | |
990 } | |
991 DCHECK(first->End() <= second->Start()); | |
992 } | 943 } |
993 | 944 |
994 TopLevel()->UpdateParentForAllChildren(TopLevel()); | 945 for (; last_insertion_point_->next() != nullptr && |
| 946 last_insertion_point_->next()->Start() <= other->Start(); |
| 947 last_insertion_point_ = last_insertion_point_->next()) { |
| 948 } |
| 949 |
| 950 // When we splintered the original range, we reconstituted the original range |
| 951 // into one range without children, but with discontinuities. To merge the |
| 952 // splinter back in, we need to split the range - or a child obtained after |
| 953 // register allocation splitting. |
| 954 LiveRange* after = last_insertion_point_->next(); |
| 955 if (last_insertion_point_->End() > other->Start()) { |
| 956 LiveRange* new_after = last_insertion_point_->SplitAt(other->Start(), zone); |
| 957 new_after->set_spilled(last_insertion_point_->spilled()); |
| 958 if (!new_after->spilled()) |
| 959 new_after->set_assigned_register( |
| 960 last_insertion_point_->assigned_register()); |
| 961 after = new_after; |
| 962 } |
| 963 |
| 964 last_other->next_ = after; |
| 965 last_insertion_point_->next_ = other; |
| 966 other->UpdateParentForAllChildren(TopLevel()); |
995 TopLevel()->UpdateSpillRangePostMerge(other); | 967 TopLevel()->UpdateSpillRangePostMerge(other); |
996 | |
997 #if DEBUG | |
998 Verify(); | |
999 #endif | |
1000 } | 968 } |
1001 | 969 |
1002 | 970 |
1003 void TopLevelLiveRange::ShortenTo(LifetimePosition start) { | 971 void TopLevelLiveRange::ShortenTo(LifetimePosition start) { |
1004 TRACE("Shorten live range %d to [%d\n", vreg(), start.value()); | 972 TRACE("Shorten live range %d to [%d\n", vreg(), start.value()); |
1005 DCHECK(first_interval_ != nullptr); | 973 DCHECK(first_interval_ != nullptr); |
1006 DCHECK(first_interval_->start() <= start); | 974 DCHECK(first_interval_->start() <= start); |
1007 DCHECK(start < first_interval_->end()); | 975 DCHECK(start < first_interval_->end()); |
1008 first_interval_->set_start(start); | 976 first_interval_->set_start(start); |
1009 } | 977 } |
(...skipping 2383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3393 auto eliminate = moves->PrepareInsertAfter(move); | 3361 auto eliminate = moves->PrepareInsertAfter(move); |
3394 to_insert.push_back(move); | 3362 to_insert.push_back(move); |
3395 if (eliminate != nullptr) to_eliminate.push_back(eliminate); | 3363 if (eliminate != nullptr) to_eliminate.push_back(eliminate); |
3396 } | 3364 } |
3397 } | 3365 } |
3398 | 3366 |
3399 | 3367 |
3400 } // namespace compiler | 3368 } // namespace compiler |
3401 } // namespace internal | 3369 } // namespace internal |
3402 } // namespace v8 | 3370 } // namespace v8 |
OLD | NEW |