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 #ifndef V8_REGISTER_ALLOCATOR_H_ | 5 #ifndef V8_REGISTER_ALLOCATOR_H_ |
6 #define V8_REGISTER_ALLOCATOR_H_ | 6 #define V8_REGISTER_ALLOCATOR_H_ |
7 | 7 |
8 #include "src/compiler/instruction.h" | 8 #include "src/compiler/instruction.h" |
9 #include "src/ostreams.h" | 9 #include "src/ostreams.h" |
10 #include "src/zone-containers.h" | 10 #include "src/zone-containers.h" |
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
244 UsePositionHintType hint_type() const { | 244 UsePositionHintType hint_type() const { |
245 return HintTypeField::decode(flags_); | 245 return HintTypeField::decode(flags_); |
246 } | 246 } |
247 bool HasHint() const; | 247 bool HasHint() const; |
248 bool HintRegister(int* register_index) const; | 248 bool HintRegister(int* register_index) const; |
249 void ResolveHint(UsePosition* use_pos); | 249 void ResolveHint(UsePosition* use_pos); |
250 bool IsResolved() const { | 250 bool IsResolved() const { |
251 return hint_type() != UsePositionHintType::kUnresolved; | 251 return hint_type() != UsePositionHintType::kUnresolved; |
252 } | 252 } |
253 static UsePositionHintType HintTypeForOperand(const InstructionOperand& op); | 253 static UsePositionHintType HintTypeForOperand(const InstructionOperand& op); |
254 void dump_hint(std::ostream& os, const RegisterConfiguration* config); | |
254 | 255 |
255 private: | 256 private: |
256 typedef BitField<UsePositionType, 0, 2> TypeField; | 257 typedef BitField<UsePositionType, 0, 2> TypeField; |
257 typedef BitField<UsePositionHintType, 2, 3> HintTypeField; | 258 typedef BitField<UsePositionHintType, 2, 3> HintTypeField; |
258 typedef BitField<bool, 5, 1> RegisterBeneficialField; | 259 typedef BitField<bool, 5, 1> RegisterBeneficialField; |
259 typedef BitField<int32_t, 6, 6> AssignedRegisterField; | 260 typedef BitField<int32_t, 6, 6> AssignedRegisterField; |
260 | 261 |
261 InstructionOperand* const operand_; | 262 InstructionOperand* const operand_; |
262 void* hint_; | 263 void* hint_; |
263 UsePosition* next_; | 264 UsePosition* next_; |
264 LifetimePosition const pos_; | 265 LifetimePosition const pos_; |
265 uint32_t flags_; | 266 uint32_t flags_; |
266 | 267 |
267 DISALLOW_COPY_AND_ASSIGN(UsePosition); | 268 DISALLOW_COPY_AND_ASSIGN(UsePosition); |
268 }; | 269 }; |
269 | 270 |
270 | 271 |
271 class SpillRange; | 272 class SpillRange; |
273 class LiveRangeGroup; | |
272 | 274 |
273 | 275 |
274 // Representation of SSA values' live ranges as a collection of (continuous) | 276 // Representation of SSA values' live ranges as a collection of (continuous) |
275 // intervals over the instruction ordering. | 277 // intervals over the instruction ordering. |
276 class LiveRange final : public ZoneObject { | 278 class LiveRange final : public ZoneObject { |
277 public: | 279 public: |
278 explicit LiveRange(int id, MachineType machine_type); | 280 explicit LiveRange(int id, MachineType machine_type); |
279 | 281 |
280 UseInterval* first_interval() const { return first_interval_; } | 282 UseInterval* first_interval() const { return first_interval_; } |
281 UsePosition* first_pos() const { return first_pos_; } | 283 UsePosition* first_pos() const { return first_pos_; } |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
334 // range and which follows both start and last processed use position | 336 // range and which follows both start and last processed use position |
335 UsePosition* NextUsePositionRegisterIsBeneficial( | 337 UsePosition* NextUsePositionRegisterIsBeneficial( |
336 LifetimePosition start) const; | 338 LifetimePosition start) const; |
337 | 339 |
338 // Returns use position for which register is beneficial in this live | 340 // Returns use position for which register is beneficial in this live |
339 // range and which precedes start. | 341 // range and which precedes start. |
340 UsePosition* PreviousUsePositionRegisterIsBeneficial( | 342 UsePosition* PreviousUsePositionRegisterIsBeneficial( |
341 LifetimePosition start) const; | 343 LifetimePosition start) const; |
342 | 344 |
343 // Can this live range be spilled at this position. | 345 // Can this live range be spilled at this position. |
344 bool CanBeSpilled(LifetimePosition pos) const; | 346 bool CanBeSpilled(LifetimePosition pos) const { return CanBeSplit(pos); } |
347 | |
348 // Can this live range be split at this position. | |
349 bool CanBeSplit(LifetimePosition pos) const; | |
345 | 350 |
346 // Split this live range at the given position which must follow the start of | 351 // Split this live range at the given position which must follow the start of |
347 // the range. | 352 // the range. |
348 // All uses following the given position will be moved from this | 353 // All uses following the given position will be moved from this |
349 // live range to the result live range. | 354 // live range to the result live range. |
350 void SplitAt(LifetimePosition position, LiveRange* result, Zone* zone); | 355 void SplitAt(LifetimePosition position, LiveRange* result, Zone* zone); |
351 | 356 |
352 // Returns nullptr when no register is hinted, otherwise sets register_index. | 357 // Returns nullptr when no register is hinted, otherwise sets register_index. |
353 UsePosition* FirstHintPosition(int* register_index) const; | 358 UsePosition* FirstHintPosition(int* register_index) const; |
354 UsePosition* FirstHintPosition() const { | 359 UsePosition* FirstHintPosition() const { |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
421 const InstructionOperand& spill_op); | 426 const InstructionOperand& spill_op); |
422 void SetUseHints(int register_index); | 427 void SetUseHints(int register_index); |
423 void UnsetUseHints() { SetUseHints(kUnassignedRegister); } | 428 void UnsetUseHints() { SetUseHints(kUnassignedRegister); } |
424 | 429 |
425 struct SpillAtDefinitionList; | 430 struct SpillAtDefinitionList; |
426 | 431 |
427 SpillAtDefinitionList* spills_at_definition() const { | 432 SpillAtDefinitionList* spills_at_definition() const { |
428 return spills_at_definition_; | 433 return spills_at_definition_; |
429 } | 434 } |
430 | 435 |
436 LiveRangeGroup* group() const { return group_; } | |
437 void SetGroup(LiveRangeGroup* grp) { group_ = grp; } | |
438 | |
439 float GetWeight() const { | |
440 DCHECK(weight_ >= 0.0f); | |
441 return weight_; | |
442 } | |
443 | |
444 unsigned GetSize() { | |
445 if (size_ < 0) RecalculateSize(); | |
446 DCHECK(size_ > 0); | |
447 return static_cast<unsigned>(size_); | |
448 } | |
449 | |
450 void InvalidateWeightAndSize() { | |
451 weight_ = kInvalidWeight; | |
452 size_ = kInvalidSize; | |
453 } | |
454 void RecalculateWeight(InstructionSequence* code); | |
455 LifetimePosition GetFirstSplittablePosition(); | |
456 | |
457 static const float kMaxWeight; | |
458 | |
431 private: | 459 private: |
460 static const float kUseInLoopWeightMultiplier; | |
461 static const float kPreferredRegisterWeightMultiplier; | |
462 static const float kInvalidWeight; | |
463 static const int kInvalidSize = -1; | |
464 | |
465 void RecalculateSize(); | |
432 void set_spill_type(SpillType value) { | 466 void set_spill_type(SpillType value) { |
433 bits_ = SpillTypeField::update(bits_, value); | 467 bits_ = SpillTypeField::update(bits_, value); |
434 } | 468 } |
435 | 469 |
436 void set_spilled(bool value) { bits_ = SpilledField::update(bits_, value); } | 470 void set_spilled(bool value) { bits_ = SpilledField::update(bits_, value); } |
437 | 471 |
438 UseInterval* FirstSearchIntervalForPosition(LifetimePosition position) const; | 472 UseInterval* FirstSearchIntervalForPosition(LifetimePosition position) const; |
439 void AdvanceLastProcessedMarker(UseInterval* to_start_of, | 473 void AdvanceLastProcessedMarker(UseInterval* to_start_of, |
440 LifetimePosition but_not_past) const; | 474 LifetimePosition but_not_past) const; |
441 | 475 |
(...skipping 19 matching lines...) Expand all Loading... | |
461 SpillRange* spill_range_; | 495 SpillRange* spill_range_; |
462 }; | 496 }; |
463 SpillAtDefinitionList* spills_at_definition_; | 497 SpillAtDefinitionList* spills_at_definition_; |
464 // This is used as a cache, it doesn't affect correctness. | 498 // This is used as a cache, it doesn't affect correctness. |
465 mutable UseInterval* current_interval_; | 499 mutable UseInterval* current_interval_; |
466 // This is used as a cache, it doesn't affect correctness. | 500 // This is used as a cache, it doesn't affect correctness. |
467 mutable UsePosition* last_processed_use_; | 501 mutable UsePosition* last_processed_use_; |
468 // This is used as a cache, it's invalid outside of BuildLiveRanges. | 502 // This is used as a cache, it's invalid outside of BuildLiveRanges. |
469 mutable UsePosition* current_hint_position_; | 503 mutable UsePosition* current_hint_position_; |
470 | 504 |
505 // Used only by the greedy allocator. | |
506 float weight_; | |
507 int size_; | |
508 LiveRangeGroup* group_; | |
471 DISALLOW_COPY_AND_ASSIGN(LiveRange); | 509 DISALLOW_COPY_AND_ASSIGN(LiveRange); |
472 }; | 510 }; |
473 | 511 |
474 | 512 |
513 class LiveRangeGroup final : public ZoneObject { | |
514 public: | |
515 explicit LiveRangeGroup(Zone* zone) : ranges_(zone) {} | |
516 ZoneSet<LiveRange*>& ranges() { return ranges_; } | |
517 bool CanAdd(LiveRange* r); | |
518 void TryMerge(LiveRangeGroup* other); | |
519 | |
520 private: | |
521 ZoneSet<LiveRange*> ranges_; | |
522 | |
523 DISALLOW_COPY_AND_ASSIGN(LiveRangeGroup); | |
524 }; | |
525 | |
475 struct PrintableLiveRange { | 526 struct PrintableLiveRange { |
476 const RegisterConfiguration* register_configuration_; | 527 const RegisterConfiguration* register_configuration_; |
477 const LiveRange* range_; | 528 const LiveRange* range_; |
478 }; | 529 }; |
479 | 530 |
480 | 531 |
481 std::ostream& operator<<(std::ostream& os, | 532 std::ostream& operator<<(std::ostream& os, |
482 const PrintableLiveRange& printable_range); | 533 const PrintableLiveRange& printable_range); |
483 | 534 |
484 | 535 |
485 class SpillRange final : public ZoneObject { | 536 class SpillRange final : public ZoneObject { |
486 public: | 537 public: |
487 static const int kUnassignedSlot = -1; | 538 static const int kUnassignedSlot = -1; |
488 SpillRange(LiveRange* range, Zone* zone); | 539 SpillRange(LiveRange* range, Zone* zone); |
489 | 540 |
490 UseInterval* interval() const { return use_interval_; } | 541 UseInterval* interval() const { return use_interval_; } |
491 // Currently, only 4 or 8 byte slots are supported. | 542 // Currently, only 4 or 8 byte slots are supported. |
492 int ByteWidth() const; | 543 int ByteWidth() const; |
493 bool IsEmpty() const { return live_ranges_.empty(); } | 544 bool IsEmpty() const { return live_ranges_.empty(); } |
494 bool TryMerge(SpillRange* other); | 545 bool TryMerge(SpillRange* other); |
495 | 546 |
496 void set_assigned_slot(int index) { | 547 void set_assigned_slot(int index) { |
497 DCHECK_EQ(kUnassignedSlot, assigned_slot_); | 548 DCHECK_EQ(kUnassignedSlot, assigned_slot_); |
498 assigned_slot_ = index; | 549 assigned_slot_ = index; |
499 } | 550 } |
551 bool IsSlotAssigned() const { return assigned_slot_ != kUnassignedSlot; } | |
500 int assigned_slot() { | 552 int assigned_slot() { |
501 DCHECK_NE(kUnassignedSlot, assigned_slot_); | 553 DCHECK_NE(kUnassignedSlot, assigned_slot_); |
502 return assigned_slot_; | 554 return assigned_slot_; |
503 } | 555 } |
504 | 556 |
505 private: | 557 private: |
506 LifetimePosition End() const { return end_position_; } | 558 LifetimePosition End() const { return end_position_; } |
507 ZoneVector<LiveRange*>& live_ranges() { return live_ranges_; } | 559 ZoneVector<LiveRange*>& live_ranges() { return live_ranges_; } |
508 bool IsIntersectingWith(SpillRange* other) const; | 560 bool IsIntersectingWith(SpillRange* other) const; |
509 // Merge intervals, making sure the use intervals are sorted | 561 // Merge intervals, making sure the use intervals are sorted |
510 void MergeDisjointIntervals(UseInterval* other); | 562 void MergeDisjointIntervals(UseInterval* other); |
511 | 563 |
512 ZoneVector<LiveRange*> live_ranges_; | 564 ZoneVector<LiveRange*> live_ranges_; |
513 UseInterval* use_interval_; | 565 UseInterval* use_interval_; |
514 LifetimePosition end_position_; | 566 LifetimePosition end_position_; |
515 int assigned_slot_; | 567 int assigned_slot_; |
516 | 568 |
517 DISALLOW_COPY_AND_ASSIGN(SpillRange); | 569 DISALLOW_COPY_AND_ASSIGN(SpillRange); |
518 }; | 570 }; |
519 | 571 |
520 | 572 |
573 std::ostream& operator<<(std::ostream& os, SpillRange* range); | |
574 | |
575 | |
521 class RegisterAllocationData final : public ZoneObject { | 576 class RegisterAllocationData final : public ZoneObject { |
522 public: | 577 public: |
523 class PhiMapValue : public ZoneObject { | 578 class PhiMapValue : public ZoneObject { |
524 public: | 579 public: |
525 PhiMapValue(PhiInstruction* phi, const InstructionBlock* block, Zone* zone); | 580 PhiMapValue(PhiInstruction* phi, const InstructionBlock* block, Zone* zone); |
526 | 581 |
527 const PhiInstruction* phi() const { return phi_; } | 582 const PhiInstruction* phi() const { return phi_; } |
528 const InstructionBlock* block() const { return block_; } | 583 const InstructionBlock* block() const { return block_; } |
529 | 584 |
530 // For hinting. | 585 // For hinting. |
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
721 InstructionOperand* operand) { | 776 InstructionOperand* operand) { |
722 Use(block_start, position, operand, nullptr, UsePositionHintType::kNone); | 777 Use(block_start, position, operand, nullptr, UsePositionHintType::kNone); |
723 } | 778 } |
724 | 779 |
725 RegisterAllocationData* const data_; | 780 RegisterAllocationData* const data_; |
726 ZoneMap<InstructionOperand*, UsePosition*> phi_hints_; | 781 ZoneMap<InstructionOperand*, UsePosition*> phi_hints_; |
727 | 782 |
728 DISALLOW_COPY_AND_ASSIGN(LiveRangeBuilder); | 783 DISALLOW_COPY_AND_ASSIGN(LiveRangeBuilder); |
729 }; | 784 }; |
730 | 785 |
786 struct AllocatorStats { | |
787 unsigned spills; | |
788 unsigned wins; | |
789 unsigned losses_no_eviction; | |
790 unsigned losses_after_eviction; | |
791 unsigned good_split_attempts; | |
792 unsigned good_split_successes; | |
793 unsigned good_split_smart_above; | |
794 unsigned good_split_smart_below; | |
795 unsigned good_split_above; | |
796 unsigned good_split_below; | |
797 unsigned groups_attempted; | |
798 unsigned groups_succeeded; | |
799 unsigned groups_allocated; | |
800 void reset() { *this = {0}; } | |
801 }; | |
802 | |
803 | |
804 std::ostream& operator<<(std::ostream& os, const AllocatorStats& stats); | |
805 | |
731 | 806 |
732 class RegisterAllocator : public ZoneObject { | 807 class RegisterAllocator : public ZoneObject { |
733 public: | 808 public: |
734 explicit RegisterAllocator(RegisterAllocationData* data, RegisterKind kind); | 809 explicit RegisterAllocator(RegisterAllocationData* data, RegisterKind kind); |
735 | 810 |
736 protected: | 811 protected: |
812 AllocatorStats stats_; | |
737 RegisterAllocationData* data() const { return data_; } | 813 RegisterAllocationData* data() const { return data_; } |
738 InstructionSequence* code() const { return data()->code(); } | 814 InstructionSequence* code() const { return data()->code(); } |
739 RegisterKind mode() const { return mode_; } | 815 RegisterKind mode() const { return mode_; } |
740 int num_registers() const { return num_registers_; } | 816 int num_registers() const { return num_registers_; } |
741 | 817 |
742 Zone* allocation_zone() const { return data()->allocation_zone(); } | 818 Zone* allocation_zone() const { return data()->allocation_zone(); } |
743 | 819 |
744 LiveRange* LiveRangeFor(int index) { return data()->LiveRangeFor(index); } | 820 LiveRange* LiveRangeFor(int index) { return data()->LiveRangeFor(index); } |
745 | 821 |
746 // Split the given range at the given position. | 822 // Split the given range at the given position. |
(...skipping 13 matching lines...) Expand all Loading... | |
760 // loop covered by this interval or the latest possible position. | 836 // loop covered by this interval or the latest possible position. |
761 LifetimePosition FindOptimalSplitPos(LifetimePosition start, | 837 LifetimePosition FindOptimalSplitPos(LifetimePosition start, |
762 LifetimePosition end); | 838 LifetimePosition end); |
763 | 839 |
764 void Spill(LiveRange* range); | 840 void Spill(LiveRange* range); |
765 | 841 |
766 // If we are trying to spill a range inside the loop try to | 842 // If we are trying to spill a range inside the loop try to |
767 // hoist spill position out to the point just before the loop. | 843 // hoist spill position out to the point just before the loop. |
768 LifetimePosition FindOptimalSpillingPos(LiveRange* range, | 844 LifetimePosition FindOptimalSpillingPos(LiveRange* range, |
769 LifetimePosition pos); | 845 LifetimePosition pos); |
846 const char* RegisterName(int allocation_index) const; | |
770 | 847 |
771 private: | 848 private: |
772 RegisterAllocationData* const data_; | 849 RegisterAllocationData* const data_; |
773 const RegisterKind mode_; | 850 const RegisterKind mode_; |
774 const int num_registers_; | 851 const int num_registers_; |
775 | 852 |
776 DISALLOW_COPY_AND_ASSIGN(RegisterAllocator); | 853 DISALLOW_COPY_AND_ASSIGN(RegisterAllocator); |
777 }; | 854 }; |
778 | 855 |
779 | 856 |
780 class LinearScanAllocator final : public RegisterAllocator { | 857 class LinearScanAllocator final : public RegisterAllocator { |
781 public: | 858 public: |
782 LinearScanAllocator(RegisterAllocationData* data, RegisterKind kind, | 859 LinearScanAllocator(RegisterAllocationData* data, RegisterKind kind, |
783 Zone* local_zone); | 860 Zone* local_zone); |
784 | 861 |
785 // Phase 4: compute register assignments. | 862 // Phase 4: compute register assignments. |
786 void AllocateRegisters(); | 863 void AllocateRegisters(); |
787 | 864 |
788 private: | 865 private: |
789 const char* RegisterName(int allocation_index) const; | |
790 | |
791 ZoneVector<LiveRange*>& unhandled_live_ranges() { | 866 ZoneVector<LiveRange*>& unhandled_live_ranges() { |
792 return unhandled_live_ranges_; | 867 return unhandled_live_ranges_; |
793 } | 868 } |
794 ZoneVector<LiveRange*>& active_live_ranges() { return active_live_ranges_; } | 869 ZoneVector<LiveRange*>& active_live_ranges() { return active_live_ranges_; } |
795 ZoneVector<LiveRange*>& inactive_live_ranges() { | 870 ZoneVector<LiveRange*>& inactive_live_ranges() { |
796 return inactive_live_ranges_; | 871 return inactive_live_ranges_; |
797 } | 872 } |
798 | 873 |
799 void SetLiveRangeAssignedRegister(LiveRange* range, int reg); | 874 void SetLiveRangeAssignedRegister(LiveRange* range, int reg); |
800 | 875 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
833 ZoneVector<LiveRange*> active_live_ranges_; | 908 ZoneVector<LiveRange*> active_live_ranges_; |
834 ZoneVector<LiveRange*> inactive_live_ranges_; | 909 ZoneVector<LiveRange*> inactive_live_ranges_; |
835 | 910 |
836 #ifdef DEBUG | 911 #ifdef DEBUG |
837 LifetimePosition allocation_finger_; | 912 LifetimePosition allocation_finger_; |
838 #endif | 913 #endif |
839 | 914 |
840 DISALLOW_COPY_AND_ASSIGN(LinearScanAllocator); | 915 DISALLOW_COPY_AND_ASSIGN(LinearScanAllocator); |
841 }; | 916 }; |
842 | 917 |
918 | |
919 // Storage detail for CoalescedLiveRanges. | |
920 struct AllocatedInterval { | |
921 LifetimePosition start; | |
922 LifetimePosition end; | |
923 LiveRange* range; | |
924 struct Comparer : public std::binary_function<AllocatedInterval, | |
925 AllocatedInterval, bool> { | |
926 bool operator()(const AllocatedInterval& x, | |
927 const AllocatedInterval& y) const { | |
928 return x.start < y.start; | |
929 } | |
930 }; | |
931 }; | |
932 | |
933 | |
843 class CoalescedLiveRanges; | 934 class CoalescedLiveRanges; |
844 | 935 |
845 | 936 |
937 // Iterator over allocated live ranges (CoalescedLiveRanges) that conflict with | |
938 // a given one. See CoalescedLiveRanges::first_conflict. | |
939 // Note that iterating may produce non-consecutively repeating live ranges. | |
940 struct conflict_iterator { | |
941 conflict_iterator() : storage_(nullptr) {} | |
Jarin
2015/06/12 04:09:12
Initialize all fields here.
| |
942 const LiveRange* operator->() const { return pos_->range; } | |
943 | |
944 LiveRange* operator*() const { return pos_->range; } | |
945 | |
946 conflict_iterator& operator++(); | |
947 bool IsEnd() const { | |
948 DCHECK(storage_ != nullptr); | |
949 return pos_ == storage_->end(); | |
950 } | |
951 | |
952 private: | |
953 friend class CoalescedLiveRanges; | |
954 friend bool operator==(const conflict_iterator& first, | |
955 const conflict_iterator& second); | |
956 | |
957 typedef ZoneSet<AllocatedInterval, AllocatedInterval::Comparer> IntervalStore; | |
958 typedef IntervalStore::const_iterator interval_iterator; | |
959 | |
960 void Invalidate() { | |
961 DCHECK(storage_ != nullptr); | |
962 pos_ = storage_->end(); | |
963 query_ = nullptr; | |
964 } | |
965 | |
966 static bool Intersects(LifetimePosition a_start, LifetimePosition a_end, | |
967 LifetimePosition b_start, LifetimePosition b_end) { | |
968 if (a_start == b_start) return true; | |
969 if (a_start < b_start) return a_end > b_start; | |
Jarin
2015/06/12 04:09:12
Out of curiosity, cannot you just leave out the "i
Sven Panne
2015/06/12 07:36:37
Hmmm, this looks still too complicated, normally j
| |
970 return Intersects(b_start, b_end, a_start, a_end); | |
971 } | |
972 | |
973 bool QueryIntersectsAllocatedInterval() { | |
974 DCHECK(query_ != nullptr); | |
975 return Intersects(query_->start(), query_->end(), pos_->start, pos_->end); | |
976 } | |
977 | |
978 bool NextQueryIntersectsAllocatedInterval() { | |
979 DCHECK(query_->next() != nullptr); | |
980 return Intersects(query_->next()->start(), query_->next()->end(), | |
981 pos_->start, pos_->end); | |
982 } | |
983 | |
984 conflict_iterator(UseInterval* query, IntervalStore* storage) | |
985 : query_(query), storage_(storage) { | |
986 InitializeForNewQuery(); | |
987 } | |
988 | |
989 explicit conflict_iterator(IntervalStore* storage) : storage_(storage) { | |
990 Invalidate(); | |
991 } | |
992 | |
993 static conflict_iterator EndIteratorForStorage(IntervalStore* storage) { | |
994 conflict_iterator ret(storage); | |
995 return ret; | |
996 } | |
997 | |
998 void InitializeForNewQuery(); | |
999 void SkipMatchedQueries(); | |
1000 | |
1001 AllocatedInterval AsAllocatedInterval(LifetimePosition pos) { | |
1002 return {pos, LifetimePosition::Invalid(), nullptr}; | |
1003 } | |
1004 | |
1005 UseInterval* query_; | |
1006 IntervalStore* storage_; | |
1007 interval_iterator pos_; | |
1008 }; | |
1009 | |
1010 bool operator==(const conflict_iterator& first, | |
1011 const conflict_iterator& second); | |
1012 bool operator!=(const conflict_iterator& first, | |
1013 const conflict_iterator& second); | |
1014 | |
1015 | |
846 // A variant of the LLVM Greedy Register Allocator. See | 1016 // A variant of the LLVM Greedy Register Allocator. See |
847 // http://blog.llvm.org/2011/09/greedy-register-allocation-in-llvm-30.html | 1017 // http://blog.llvm.org/2011/09/greedy-register-allocation-in-llvm-30.html |
848 class GreedyAllocator final : public RegisterAllocator { | 1018 class GreedyAllocator final : public RegisterAllocator { |
849 public: | 1019 public: |
850 explicit GreedyAllocator(RegisterAllocationData* data, RegisterKind kind, | 1020 explicit GreedyAllocator(RegisterAllocationData* data, RegisterKind kind, |
851 Zone* local_zone); | 1021 Zone* local_zone); |
852 | 1022 |
853 void AllocateRegisters(); | 1023 void AllocateRegisters(); |
854 | 1024 |
855 private: | 1025 private: |
856 LifetimePosition GetSplittablePos(LifetimePosition pos); | 1026 void AllocateRange(LiveRange* current); |
1027 void AllocateGroup(LiveRangeGroup* grp); | |
1028 bool TryAllocateGroup(LiveRangeGroup* grp); | |
1029 bool TryAllocateGroupAtRegister(unsigned reg, LiveRangeGroup* grp); | |
1030 | |
1031 struct PQueueElem { | |
Jarin
2015/06/12 04:09:12
PQueueElem -> QueueElement (or PriorityQueueElemen
| |
1032 bool IsGroup() { return is_grp_; } | |
1033 explicit PQueueElem(LiveRange* range) : is_grp_(false) { | |
1034 storage_.range_ = range; | |
1035 } | |
1036 | |
1037 explicit PQueueElem(LiveRangeGroup* grp) : is_grp_(true) { | |
1038 storage_.grp_ = grp; | |
1039 } | |
1040 | |
1041 | |
1042 LiveRange* get_range() { | |
1043 if (is_grp_) return nullptr; | |
Jarin
2015/06/12 04:09:12
The callers should (and do) always consult IsGroup
| |
1044 return storage_.range_; | |
1045 } | |
1046 | |
1047 | |
1048 LiveRangeGroup* get_group() { | |
1049 if (is_grp_) return storage_.grp_; | |
Jarin
2015/06/12 04:09:12
Similarly, "DCHECK(IsGroup()); return storage_.grp
| |
1050 return nullptr; | |
1051 } | |
1052 | |
1053 private: | |
1054 bool is_grp_; | |
1055 union { | |
1056 LiveRange* range_; | |
1057 LiveRangeGroup* grp_; | |
1058 } storage_; | |
1059 }; | |
1060 | |
1061 void GroupAndEnqueue(); | |
Jarin
2015/06/12 04:09:12
GroupAndEnqueue -> EnqueuePhiGroups?
| |
857 const RegisterConfiguration* config() const { return data()->config(); } | 1062 const RegisterConfiguration* config() const { return data()->config(); } |
858 Zone* local_zone() const { return local_zone_; } | 1063 Zone* local_zone() const { return local_zone_; } |
859 bool TryReuseSpillForPhi(LiveRange* range); | |
860 int GetHintedRegister(LiveRange* range); | |
861 | 1064 |
862 typedef ZonePriorityQueue<std::pair<unsigned, LiveRange*>> PQueue; | 1065 struct PQueueElemComparer |
1066 : public std::binary_function<std::pair<unsigned, PQueueElem>, | |
1067 std::pair<unsigned, PQueueElem>, bool> { | |
1068 bool operator()(const std::pair<unsigned, PQueueElem>& x, | |
1069 const std::pair<unsigned, PQueueElem>& y) const { | |
1070 return x.first < y.first; | |
1071 } | |
1072 }; | |
863 | 1073 |
864 unsigned GetLiveRangeSize(LiveRange* range); | 1074 typedef ZonePriorityQueue<std::pair<unsigned, PQueueElem>, PQueueElemComparer> |
1075 PQueue; | |
Jarin
2015/06/12 04:09:12
PQueue -> PriorityQueue
| |
1076 | |
865 void Enqueue(LiveRange* range); | 1077 void Enqueue(LiveRange* range); |
1078 void Enqueue(LiveRangeGroup* group); | |
866 | 1079 |
867 void Evict(LiveRange* range); | 1080 void Evict(LiveRange* range); |
868 float CalculateSpillWeight(LiveRange* range); | 1081 void EvictAll(int reg, const conflict_iterator& first_conflict); |
869 float CalculateMaxSpillWeight(const ZoneSet<LiveRange*>& ranges); | |
870 | 1082 |
1083 // Find the register with the minimum spill weight. If that is still higher | |
1084 // or equal to competing, return -1. | |
1085 int FindRegisterToEvictForRange( | |
1086 conflict_iterator | |
1087 all_conflicts[RegisterConfiguration::kMaxDoubleRegisters], | |
1088 float competing); | |
871 | 1089 |
872 bool TryAllocate(LiveRange* current, ZoneSet<LiveRange*>* conflicting); | 1090 // Same as above, for all the registers in a group. |
873 bool TryAllocatePhysicalRegister(unsigned reg_id, LiveRange* range, | 1091 int FindRegisterToEvictForGroup(LiveRangeGroup* grp, float competing); |
874 ZoneSet<LiveRange*>* conflicting); | 1092 |
875 bool HandleSpillOperands(LiveRange* range); | 1093 template <typename TIter> |
876 void AllocateBlockedRange(LiveRange* current, LifetimePosition pos, | 1094 float CalculateMaxSpillWeight(const TIter& begin, const TIter& end); |
Jarin
2015/06/12 04:09:12
Static?
| |
877 bool spill); | 1095 |
1096 bool HandleSpillOperands(LiveRange* range, LiveRange** remaining); | |
1097 void HandleBlockedRange(LiveRange* current); | |
1098 bool TrySplitBeforeLoops(LiveRange* current); | |
1099 bool TrySplitAfterLoops(LiveRange* current); | |
1100 bool TrySplitAroundCalls(LiveRange* range); | |
878 | 1101 |
879 LiveRange* SpillBetweenUntil(LiveRange* range, LifetimePosition start, | 1102 LiveRange* SpillBetweenUntil(LiveRange* range, LifetimePosition start, |
880 LifetimePosition until, LifetimePosition end); | 1103 LifetimePosition until, LifetimePosition end); |
881 void AssignRangeToRegister(int reg_id, LiveRange* range); | 1104 void AssignRangeToRegister(int reg_id, LiveRange* range); |
882 | 1105 |
883 LifetimePosition FindProgressingSplitPosition(LiveRange* range, | |
884 bool* is_spill_pos); | |
885 | |
886 Zone* local_zone_; | 1106 Zone* local_zone_; |
887 ZoneVector<CoalescedLiveRanges*> allocations_; | 1107 ZoneVector<CoalescedLiveRanges*> allocations_; |
888 PQueue queue_; | 1108 PQueue queue_; |
889 DISALLOW_COPY_AND_ASSIGN(GreedyAllocator); | 1109 DISALLOW_COPY_AND_ASSIGN(GreedyAllocator); |
890 }; | 1110 }; |
891 | 1111 |
892 | 1112 |
893 class SpillSlotLocator final : public ZoneObject { | 1113 class SpillSlotLocator final : public ZoneObject { |
894 public: | 1114 public: |
895 explicit SpillSlotLocator(RegisterAllocationData* data); | 1115 explicit SpillSlotLocator(RegisterAllocationData* data); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
966 RegisterAllocationData* const data_; | 1186 RegisterAllocationData* const data_; |
967 | 1187 |
968 DISALLOW_COPY_AND_ASSIGN(LiveRangeConnector); | 1188 DISALLOW_COPY_AND_ASSIGN(LiveRangeConnector); |
969 }; | 1189 }; |
970 | 1190 |
971 } // namespace compiler | 1191 } // namespace compiler |
972 } // namespace internal | 1192 } // namespace internal |
973 } // namespace v8 | 1193 } // namespace v8 |
974 | 1194 |
975 #endif // V8_REGISTER_ALLOCATOR_H_ | 1195 #endif // V8_REGISTER_ALLOCATOR_H_ |
OLD | NEW |