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