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 3 // found in the LICENSE file. 4 5 #ifndef V8_REGISTER_ALLOCATOR_H_ 6 #define V8_REGISTER_ALLOCATOR_H_ 7 8 #include "src/compiler/instruction.h" 9 #include "src/ostreams.h" 10 #include "src/register-configuration.h" 11 #include "src/zone-containers.h" 12 13 namespace v8 { 14 namespace internal { 15 namespace compiler { 16 17 enum RegisterKind { 18 GENERAL_REGISTERS, 19 DOUBLE_REGISTERS 20 }; 21 22 23 // This class represents a single point of a InstructionOperand's lifetime. For 24 // each instruction there are four lifetime positions: 25 // 26 // [[START, END], [START, END]] 27 // 28 // Where the first half position corresponds to 29 // 30 // [GapPosition::START, GapPosition::END] 31 // 32 // and the second half position corresponds to 33 // 34 // [Lifetime::USED_AT_START, Lifetime::USED_AT_END] 35 // 36 class LifetimePosition final { 37 public: 38 // Return the lifetime position that corresponds to the beginning of 39 // the gap with the given index. GapFromInstructionIndex(int index)40 static LifetimePosition GapFromInstructionIndex(int index) { 41 return LifetimePosition(index * kStep); 42 } 43 // Return the lifetime position that corresponds to the beginning of 44 // the instruction with the given index. InstructionFromInstructionIndex(int index)45 static LifetimePosition InstructionFromInstructionIndex(int index) { 46 return LifetimePosition(index * kStep + kHalfStep); 47 } 48 49 // Returns a numeric representation of this lifetime position. value()50 int value() const { return value_; } 51 52 // Returns the index of the instruction to which this lifetime position 53 // corresponds. ToInstructionIndex()54 int ToInstructionIndex() const { 55 DCHECK(IsValid()); 56 return value_ / kStep; 57 } 58 59 // Returns true if this lifetime position corresponds to a START value IsStart()60 bool IsStart() const { return (value_ & (kHalfStep - 1)) == 0; } 61 // Returns true if this lifetime position corresponds to an END value IsEnd()62 bool IsEnd() const { return (value_ & (kHalfStep - 1)) == 1; } 63 // Returns true if this lifetime position corresponds to a gap START value IsFullStart()64 bool IsFullStart() const { return (value_ & (kStep - 1)) == 0; } 65 IsGapPosition()66 bool IsGapPosition() const { return (value_ & 0x2) == 0; } IsInstructionPosition()67 bool IsInstructionPosition() const { return !IsGapPosition(); } 68 69 // Returns the lifetime position for the current START. Start()70 LifetimePosition Start() const { 71 DCHECK(IsValid()); 72 return LifetimePosition(value_ & ~(kHalfStep - 1)); 73 } 74 75 // Returns the lifetime position for the current gap START. FullStart()76 LifetimePosition FullStart() const { 77 DCHECK(IsValid()); 78 return LifetimePosition(value_ & ~(kStep - 1)); 79 } 80 81 // Returns the lifetime position for the current END. End()82 LifetimePosition End() const { 83 DCHECK(IsValid()); 84 return LifetimePosition(Start().value_ + kHalfStep / 2); 85 } 86 87 // Returns the lifetime position for the beginning of the next START. NextStart()88 LifetimePosition NextStart() const { 89 DCHECK(IsValid()); 90 return LifetimePosition(Start().value_ + kHalfStep); 91 } 92 93 // Returns the lifetime position for the beginning of the next gap START. NextFullStart()94 LifetimePosition NextFullStart() const { 95 DCHECK(IsValid()); 96 return LifetimePosition(FullStart().value_ + kStep); 97 } 98 99 // Returns the lifetime position for the beginning of the previous START. PrevStart()100 LifetimePosition PrevStart() const { 101 DCHECK(IsValid()); 102 DCHECK(value_ >= kHalfStep); 103 return LifetimePosition(Start().value_ - kHalfStep); 104 } 105 106 // Constructs the lifetime position which does not correspond to any 107 // instruction. LifetimePosition()108 LifetimePosition() : value_(-1) {} 109 110 // Returns true if this lifetime positions corrensponds to some 111 // instruction. IsValid()112 bool IsValid() const { return value_ != -1; } 113 114 bool operator<(const LifetimePosition& that) const { 115 return this->value_ < that.value_; 116 } 117 118 bool operator<=(const LifetimePosition& that) const { 119 return this->value_ <= that.value_; 120 } 121 122 bool operator==(const LifetimePosition& that) const { 123 return this->value_ == that.value_; 124 } 125 126 bool operator!=(const LifetimePosition& that) const { 127 return this->value_ != that.value_; 128 } 129 130 bool operator>(const LifetimePosition& that) const { 131 return this->value_ > that.value_; 132 } 133 134 bool operator>=(const LifetimePosition& that) const { 135 return this->value_ >= that.value_; 136 } 137 138 void Print() const; 139 Invalid()140 static inline LifetimePosition Invalid() { return LifetimePosition(); } 141 MaxPosition()142 static inline LifetimePosition MaxPosition() { 143 // We have to use this kind of getter instead of static member due to 144 // crash bug in GDB. 145 return LifetimePosition(kMaxInt); 146 } 147 FromInt(int value)148 static inline LifetimePosition FromInt(int value) { 149 return LifetimePosition(value); 150 } 151 152 private: 153 static const int kHalfStep = 2; 154 static const int kStep = 2 * kHalfStep; 155 156 // Code relies on kStep and kHalfStep being a power of two. 157 STATIC_ASSERT(IS_POWER_OF_TWO(kHalfStep)); 158 LifetimePosition(int value)159 explicit LifetimePosition(int value) : value_(value) {} 160 161 int value_; 162 }; 163 164 165 std::ostream& operator<<(std::ostream& os, const LifetimePosition pos); 166 167 168 // Representation of the non-empty interval [start,end[. 169 class UseInterval final : public ZoneObject { 170 public: UseInterval(LifetimePosition start,LifetimePosition end)171 UseInterval(LifetimePosition start, LifetimePosition end) 172 : start_(start), end_(end), next_(nullptr) { 173 DCHECK(start < end); 174 } 175 start()176 LifetimePosition start() const { return start_; } set_start(LifetimePosition start)177 void set_start(LifetimePosition start) { start_ = start; } end()178 LifetimePosition end() const { return end_; } set_end(LifetimePosition end)179 void set_end(LifetimePosition end) { end_ = end; } next()180 UseInterval* next() const { return next_; } set_next(UseInterval * next)181 void set_next(UseInterval* next) { next_ = next; } 182 183 // Split this interval at the given position without effecting the 184 // live range that owns it. The interval must contain the position. 185 UseInterval* SplitAt(LifetimePosition pos, Zone* zone); 186 187 // If this interval intersects with other return smallest position 188 // that belongs to both of them. Intersect(const UseInterval * other)189 LifetimePosition Intersect(const UseInterval* other) const { 190 if (other->start() < start_) return other->Intersect(this); 191 if (other->start() < end_) return other->start(); 192 return LifetimePosition::Invalid(); 193 } 194 Contains(LifetimePosition point)195 bool Contains(LifetimePosition point) const { 196 return start_ <= point && point < end_; 197 } 198 199 // Returns the index of the first gap covered by this interval. FirstGapIndex()200 int FirstGapIndex() const { 201 int ret = start_.ToInstructionIndex(); 202 if (start_.IsInstructionPosition()) { 203 ++ret; 204 } 205 return ret; 206 } 207 208 // Returns the index of the last gap covered by this interval. LastGapIndex()209 int LastGapIndex() const { 210 int ret = end_.ToInstructionIndex(); 211 if (end_.IsGapPosition() && end_.IsStart()) { 212 --ret; 213 } 214 return ret; 215 } 216 217 private: 218 LifetimePosition start_; 219 LifetimePosition end_; 220 UseInterval* next_; 221 222 DISALLOW_COPY_AND_ASSIGN(UseInterval); 223 }; 224 225 226 enum class UsePositionType : uint8_t { kAny, kRequiresRegister, kRequiresSlot }; 227 228 229 enum class UsePositionHintType : uint8_t { 230 kNone, 231 kOperand, 232 kUsePos, 233 kPhi, 234 kUnresolved 235 }; 236 237 238 static const int32_t kUnassignedRegister = 239 RegisterConfiguration::kMaxGeneralRegisters; 240 241 242 static_assert(kUnassignedRegister <= RegisterConfiguration::kMaxDoubleRegisters, 243 "kUnassignedRegister too small"); 244 245 246 // Representation of a use position. 247 class UsePosition final : public ZoneObject { 248 public: 249 UsePosition(LifetimePosition pos, InstructionOperand* operand, void* hint, 250 UsePositionHintType hint_type); 251 operand()252 InstructionOperand* operand() const { return operand_; } HasOperand()253 bool HasOperand() const { return operand_ != nullptr; } 254 RegisterIsBeneficial()255 bool RegisterIsBeneficial() const { 256 return RegisterBeneficialField::decode(flags_); 257 } type()258 UsePositionType type() const { return TypeField::decode(flags_); } 259 void set_type(UsePositionType type, bool register_beneficial); 260 pos()261 LifetimePosition pos() const { return pos_; } 262 next()263 UsePosition* next() const { return next_; } set_next(UsePosition * next)264 void set_next(UsePosition* next) { next_ = next; } 265 266 // For hinting only. set_assigned_register(int register_code)267 void set_assigned_register(int register_code) { 268 flags_ = AssignedRegisterField::update(flags_, register_code); 269 } 270 hint_type()271 UsePositionHintType hint_type() const { 272 return HintTypeField::decode(flags_); 273 } 274 bool HasHint() const; 275 bool HintRegister(int* register_code) const; 276 void ResolveHint(UsePosition* use_pos); IsResolved()277 bool IsResolved() const { 278 return hint_type() != UsePositionHintType::kUnresolved; 279 } 280 static UsePositionHintType HintTypeForOperand(const InstructionOperand& op); 281 282 private: 283 typedef BitField<UsePositionType, 0, 2> TypeField; 284 typedef BitField<UsePositionHintType, 2, 3> HintTypeField; 285 typedef BitField<bool, 5, 1> RegisterBeneficialField; 286 typedef BitField<int32_t, 6, 6> AssignedRegisterField; 287 288 InstructionOperand* const operand_; 289 void* hint_; 290 UsePosition* next_; 291 LifetimePosition const pos_; 292 uint32_t flags_; 293 294 DISALLOW_COPY_AND_ASSIGN(UsePosition); 295 }; 296 297 298 class SpillRange; 299 class RegisterAllocationData; 300 class TopLevelLiveRange; 301 class LiveRangeGroup; 302 303 // Representation of SSA values' live ranges as a collection of (continuous) 304 // intervals over the instruction ordering. 305 class LiveRange : public ZoneObject { 306 public: first_interval()307 UseInterval* first_interval() const { return first_interval_; } first_pos()308 UsePosition* first_pos() const { return first_pos_; } TopLevel()309 TopLevelLiveRange* TopLevel() { return top_level_; } TopLevel()310 const TopLevelLiveRange* TopLevel() const { return top_level_; } 311 312 bool IsTopLevel() const; 313 next()314 LiveRange* next() const { return next_; } 315 relative_id()316 int relative_id() const { return relative_id_; } 317 IsEmpty()318 bool IsEmpty() const { return first_interval() == nullptr; } 319 320 InstructionOperand GetAssignedOperand() const; 321 representation()322 MachineRepresentation representation() const { 323 return RepresentationField::decode(bits_); 324 } 325 assigned_register()326 int assigned_register() const { return AssignedRegisterField::decode(bits_); } HasRegisterAssigned()327 bool HasRegisterAssigned() const { 328 return assigned_register() != kUnassignedRegister; 329 } 330 void set_assigned_register(int reg); 331 void UnsetAssignedRegister(); 332 spilled()333 bool spilled() const { return SpilledField::decode(bits_); } 334 void Spill(); 335 336 RegisterKind kind() const; 337 338 // Returns use position in this live range that follows both start 339 // and last processed use position. 340 UsePosition* NextUsePosition(LifetimePosition start) const; 341 342 // Returns use position for which register is required in this live 343 // range and which follows both start and last processed use position 344 UsePosition* NextRegisterPosition(LifetimePosition start) const; 345 346 // Returns the first use position requiring stack slot, or nullptr. 347 UsePosition* NextSlotPosition(LifetimePosition start) const; 348 349 // Returns use position for which register is beneficial in this live 350 // range and which follows both start and last processed use position 351 UsePosition* NextUsePositionRegisterIsBeneficial( 352 LifetimePosition start) const; 353 354 // Returns use position for which register is beneficial in this live 355 // range and which precedes start. 356 UsePosition* PreviousUsePositionRegisterIsBeneficial( 357 LifetimePosition start) const; 358 359 // Can this live range be spilled at this position. 360 bool CanBeSpilled(LifetimePosition pos) const; 361 362 // Splitting primitive used by both splitting and splintering members. 363 // Performs the split, but does not link the resulting ranges. 364 // The given position must follow the start of the range. 365 // All uses following the given position will be moved from this 366 // live range to the result live range. 367 // The current range will terminate at position, while result will start from 368 // position. 369 UsePosition* DetachAt(LifetimePosition position, LiveRange* result, 370 Zone* zone); 371 372 // Detaches at position, and then links the resulting ranges. Returns the 373 // child, which starts at position. 374 LiveRange* SplitAt(LifetimePosition position, Zone* zone); 375 376 // Returns nullptr when no register is hinted, otherwise sets register_index. 377 UsePosition* FirstHintPosition(int* register_index) const; FirstHintPosition()378 UsePosition* FirstHintPosition() const { 379 int register_index; 380 return FirstHintPosition(®ister_index); 381 } 382 current_hint_position()383 UsePosition* current_hint_position() const { 384 DCHECK(current_hint_position_ == FirstHintPosition()); 385 return current_hint_position_; 386 } 387 Start()388 LifetimePosition Start() const { 389 DCHECK(!IsEmpty()); 390 return first_interval()->start(); 391 } 392 End()393 LifetimePosition End() const { 394 DCHECK(!IsEmpty()); 395 return last_interval_->end(); 396 } 397 398 bool ShouldBeAllocatedBefore(const LiveRange* other) const; 399 bool CanCover(LifetimePosition position) const; 400 bool Covers(LifetimePosition position) const; 401 LifetimePosition FirstIntersection(LiveRange* other) const; 402 VerifyChildStructure()403 void VerifyChildStructure() const { 404 VerifyIntervals(); 405 VerifyPositions(); 406 } 407 408 void ConvertUsesToOperand(const InstructionOperand& op, 409 const InstructionOperand& spill_op); 410 void SetUseHints(int register_index); UnsetUseHints()411 void UnsetUseHints() { SetUseHints(kUnassignedRegister); } 412 413 // Used solely by the Greedy Allocator: 414 unsigned GetSize(); weight()415 float weight() const { return weight_; } set_weight(float weight)416 void set_weight(float weight) { weight_ = weight; } group()417 LiveRangeGroup* group() const { return group_; } set_group(LiveRangeGroup * group)418 void set_group(LiveRangeGroup* group) { group_ = group; } 419 void Print(const RegisterConfiguration* config, bool with_children) const; 420 void Print(bool with_children) const; 421 422 static const int kInvalidSize = -1; 423 static const float kInvalidWeight; 424 static const float kMaxWeight; 425 426 private: 427 friend class TopLevelLiveRange; 428 explicit LiveRange(int relative_id, MachineRepresentation rep, 429 TopLevelLiveRange* top_level); 430 431 void UpdateParentForAllChildren(TopLevelLiveRange* new_top_level); 432 set_spilled(bool value)433 void set_spilled(bool value) { bits_ = SpilledField::update(bits_, value); } 434 435 UseInterval* FirstSearchIntervalForPosition(LifetimePosition position) const; 436 void AdvanceLastProcessedMarker(UseInterval* to_start_of, 437 LifetimePosition but_not_past) const; 438 439 void VerifyPositions() const; 440 void VerifyIntervals() const; 441 442 typedef BitField<bool, 0, 1> SpilledField; 443 typedef BitField<int32_t, 6, 6> AssignedRegisterField; 444 typedef BitField<MachineRepresentation, 12, 8> RepresentationField; 445 446 // Unique among children and splinters of the same virtual register. 447 int relative_id_; 448 uint32_t bits_; 449 UseInterval* last_interval_; 450 UseInterval* first_interval_; 451 UsePosition* first_pos_; 452 TopLevelLiveRange* top_level_; 453 LiveRange* next_; 454 // This is used as a cache, it doesn't affect correctness. 455 mutable UseInterval* current_interval_; 456 // This is used as a cache, it doesn't affect correctness. 457 mutable UsePosition* last_processed_use_; 458 // This is used as a cache, it's invalid outside of BuildLiveRanges. 459 mutable UsePosition* current_hint_position_; 460 // Cache the last position splintering stopped at. 461 mutable UsePosition* splitting_pointer_; 462 // greedy: the number of LifetimePositions covered by this range. Used to 463 // prioritize selecting live ranges for register assignment, as well as 464 // in weight calculations. 465 int size_; 466 467 // greedy: a metric for resolving conflicts between ranges with an assigned 468 // register and ranges that intersect them and need a register. 469 float weight_; 470 471 // greedy: groupping 472 LiveRangeGroup* group_; 473 474 DISALLOW_COPY_AND_ASSIGN(LiveRange); 475 }; 476 477 478 class LiveRangeGroup final : public ZoneObject { 479 public: LiveRangeGroup(Zone * zone)480 explicit LiveRangeGroup(Zone* zone) : ranges_(zone) {} ranges()481 ZoneVector<LiveRange*>& ranges() { return ranges_; } ranges()482 const ZoneVector<LiveRange*>& ranges() const { return ranges_; } 483 484 // TODO(mtrofin): populate assigned register and use in weight calculation. assigned_register()485 int assigned_register() const { return assigned_register_; } set_assigned_register(int reg)486 void set_assigned_register(int reg) { assigned_register_ = reg; } 487 488 private: 489 ZoneVector<LiveRange*> ranges_; 490 int assigned_register_; 491 DISALLOW_COPY_AND_ASSIGN(LiveRangeGroup); 492 }; 493 494 495 class TopLevelLiveRange final : public LiveRange { 496 public: 497 explicit TopLevelLiveRange(int vreg, MachineRepresentation rep); spill_start_index()498 int spill_start_index() const { return spill_start_index_; } 499 IsFixed()500 bool IsFixed() const { return vreg_ < 0; } 501 is_phi()502 bool is_phi() const { return IsPhiField::decode(bits_); } set_is_phi(bool value)503 void set_is_phi(bool value) { bits_ = IsPhiField::update(bits_, value); } 504 is_non_loop_phi()505 bool is_non_loop_phi() const { return IsNonLoopPhiField::decode(bits_); } set_is_non_loop_phi(bool value)506 void set_is_non_loop_phi(bool value) { 507 bits_ = IsNonLoopPhiField::update(bits_, value); 508 } 509 has_slot_use()510 bool has_slot_use() const { return HasSlotUseField::decode(bits_); } set_has_slot_use(bool value)511 void set_has_slot_use(bool value) { 512 bits_ = HasSlotUseField::update(bits_, value); 513 } 514 515 // Add a new interval or a new use position to this live range. 516 void EnsureInterval(LifetimePosition start, LifetimePosition end, Zone* zone); 517 void AddUseInterval(LifetimePosition start, LifetimePosition end, Zone* zone); 518 void AddUsePosition(UsePosition* pos); 519 520 // Shorten the most recently added interval by setting a new start. 521 void ShortenTo(LifetimePosition start); 522 523 // Detaches between start and end, and attributes the resulting range to 524 // result. 525 // The current range is pointed to as "splintered_from". No parent/child 526 // relationship is established between this and result. 527 void Splinter(LifetimePosition start, LifetimePosition end, Zone* zone); 528 529 // Assuming other was splintered from this range, embeds other and its 530 // children as part of the children sequence of this range. 531 void Merge(TopLevelLiveRange* other, Zone* zone); 532 533 // Spill range management. 534 void SetSpillRange(SpillRange* spill_range); 535 enum class SpillType { kNoSpillType, kSpillOperand, kSpillRange }; set_spill_type(SpillType value)536 void set_spill_type(SpillType value) { 537 bits_ = SpillTypeField::update(bits_, value); 538 } spill_type()539 SpillType spill_type() const { return SpillTypeField::decode(bits_); } GetSpillOperand()540 InstructionOperand* GetSpillOperand() const { 541 DCHECK(spill_type() == SpillType::kSpillOperand); 542 return spill_operand_; 543 } 544 GetAllocatedSpillRange()545 SpillRange* GetAllocatedSpillRange() const { 546 DCHECK(spill_type() != SpillType::kSpillOperand); 547 return spill_range_; 548 } 549 GetSpillRange()550 SpillRange* GetSpillRange() const { 551 DCHECK(spill_type() == SpillType::kSpillRange); 552 return spill_range_; 553 } HasNoSpillType()554 bool HasNoSpillType() const { 555 return spill_type() == SpillType::kNoSpillType; 556 } HasSpillOperand()557 bool HasSpillOperand() const { 558 return spill_type() == SpillType::kSpillOperand; 559 } HasSpillRange()560 bool HasSpillRange() const { return spill_type() == SpillType::kSpillRange; } 561 562 AllocatedOperand GetSpillRangeOperand() const; 563 564 void RecordSpillLocation(Zone* zone, int gap_index, 565 InstructionOperand* operand); 566 void SetSpillOperand(InstructionOperand* operand); SetSpillStartIndex(int start)567 void SetSpillStartIndex(int start) { 568 spill_start_index_ = Min(start, spill_start_index_); 569 } 570 571 void CommitSpillMoves(InstructionSequence* sequence, 572 const InstructionOperand& operand, 573 bool might_be_duplicated); 574 575 // If all the children of this range are spilled in deferred blocks, and if 576 // for any non-spilled child with a use position requiring a slot, that range 577 // is contained in a deferred block, mark the range as 578 // IsSpilledOnlyInDeferredBlocks, so that we avoid spilling at definition, 579 // and instead let the LiveRangeConnector perform the spills within the 580 // deferred blocks. If so, we insert here spills for non-spilled ranges 581 // with slot use positions. MarkSpilledInDeferredBlock()582 void MarkSpilledInDeferredBlock() { 583 spill_start_index_ = -1; 584 spilled_in_deferred_blocks_ = true; 585 spill_move_insertion_locations_ = nullptr; 586 } 587 588 bool TryCommitSpillInDeferredBlock(InstructionSequence* code, 589 const InstructionOperand& spill_operand); 590 splintered_from()591 TopLevelLiveRange* splintered_from() const { return splintered_from_; } IsSplinter()592 bool IsSplinter() const { return splintered_from_ != nullptr; } MayRequireSpillRange()593 bool MayRequireSpillRange() const { 594 DCHECK(!IsSplinter()); 595 return !HasSpillOperand() && spill_range_ == nullptr; 596 } 597 void UpdateSpillRangePostMerge(TopLevelLiveRange* merged); vreg()598 int vreg() const { return vreg_; } 599 600 #if DEBUG 601 int debug_virt_reg() const; 602 #endif 603 604 void Verify() const; 605 void VerifyChildrenInOrder() const; 606 GetNextChildId()607 int GetNextChildId() { 608 return IsSplinter() ? splintered_from()->GetNextChildId() 609 : ++last_child_id_; 610 } 611 GetChildCount()612 int GetChildCount() const { return last_child_id_ + 1; } 613 IsSpilledOnlyInDeferredBlocks()614 bool IsSpilledOnlyInDeferredBlocks() const { 615 return spilled_in_deferred_blocks_; 616 } 617 618 struct SpillMoveInsertionList; 619 spill_move_insertion_locations()620 SpillMoveInsertionList* spill_move_insertion_locations() const { 621 return spill_move_insertion_locations_; 622 } splinter()623 TopLevelLiveRange* splinter() const { return splinter_; } SetSplinter(TopLevelLiveRange * splinter)624 void SetSplinter(TopLevelLiveRange* splinter) { 625 DCHECK_NULL(splinter_); 626 DCHECK_NOT_NULL(splinter); 627 628 splinter_ = splinter; 629 splinter->relative_id_ = GetNextChildId(); 630 splinter->set_spill_type(spill_type()); 631 splinter->SetSplinteredFrom(this); 632 } 633 MarkHasPreassignedSlot()634 void MarkHasPreassignedSlot() { has_preassigned_slot_ = true; } has_preassigned_slot()635 bool has_preassigned_slot() const { return has_preassigned_slot_; } 636 637 private: 638 void SetSplinteredFrom(TopLevelLiveRange* splinter_parent); 639 640 typedef BitField<bool, 1, 1> HasSlotUseField; 641 typedef BitField<bool, 2, 1> IsPhiField; 642 typedef BitField<bool, 3, 1> IsNonLoopPhiField; 643 typedef BitField<SpillType, 4, 2> SpillTypeField; 644 645 int vreg_; 646 int last_child_id_; 647 TopLevelLiveRange* splintered_from_; 648 union { 649 // Correct value determined by spill_type() 650 InstructionOperand* spill_operand_; 651 SpillRange* spill_range_; 652 }; 653 SpillMoveInsertionList* spill_move_insertion_locations_; 654 // TODO(mtrofin): generalize spilling after definition, currently specialized 655 // just for spill in a single deferred block. 656 bool spilled_in_deferred_blocks_; 657 int spill_start_index_; 658 UsePosition* last_pos_; 659 TopLevelLiveRange* splinter_; 660 bool has_preassigned_slot_; 661 662 DISALLOW_COPY_AND_ASSIGN(TopLevelLiveRange); 663 }; 664 665 666 struct PrintableLiveRange { 667 const RegisterConfiguration* register_configuration_; 668 const LiveRange* range_; 669 }; 670 671 672 std::ostream& operator<<(std::ostream& os, 673 const PrintableLiveRange& printable_range); 674 675 676 class SpillRange final : public ZoneObject { 677 public: 678 static const int kUnassignedSlot = -1; 679 SpillRange(TopLevelLiveRange* range, Zone* zone); 680 interval()681 UseInterval* interval() const { return use_interval_; } 682 // Currently, only 4 or 8 byte slots are supported. 683 int ByteWidth() const; IsEmpty()684 bool IsEmpty() const { return live_ranges_.empty(); } 685 bool TryMerge(SpillRange* other); HasSlot()686 bool HasSlot() const { return assigned_slot_ != kUnassignedSlot; } 687 set_assigned_slot(int index)688 void set_assigned_slot(int index) { 689 DCHECK_EQ(kUnassignedSlot, assigned_slot_); 690 assigned_slot_ = index; 691 } assigned_slot()692 int assigned_slot() { 693 DCHECK_NE(kUnassignedSlot, assigned_slot_); 694 return assigned_slot_; 695 } live_ranges()696 const ZoneVector<TopLevelLiveRange*>& live_ranges() const { 697 return live_ranges_; 698 } live_ranges()699 ZoneVector<TopLevelLiveRange*>& live_ranges() { return live_ranges_; } byte_width()700 int byte_width() const { return byte_width_; } kind()701 RegisterKind kind() const { return kind_; } 702 void Print() const; 703 704 private: End()705 LifetimePosition End() const { return end_position_; } 706 bool IsIntersectingWith(SpillRange* other) const; 707 // Merge intervals, making sure the use intervals are sorted 708 void MergeDisjointIntervals(UseInterval* other); 709 710 ZoneVector<TopLevelLiveRange*> live_ranges_; 711 UseInterval* use_interval_; 712 LifetimePosition end_position_; 713 int assigned_slot_; 714 int byte_width_; 715 RegisterKind kind_; 716 717 DISALLOW_COPY_AND_ASSIGN(SpillRange); 718 }; 719 720 721 class RegisterAllocationData final : public ZoneObject { 722 public: 723 class PhiMapValue : public ZoneObject { 724 public: 725 PhiMapValue(PhiInstruction* phi, const InstructionBlock* block, Zone* zone); 726 phi()727 const PhiInstruction* phi() const { return phi_; } block()728 const InstructionBlock* block() const { return block_; } 729 730 // For hinting. assigned_register()731 int assigned_register() const { return assigned_register_; } set_assigned_register(int register_code)732 void set_assigned_register(int register_code) { 733 DCHECK_EQ(assigned_register_, kUnassignedRegister); 734 assigned_register_ = register_code; 735 } UnsetAssignedRegister()736 void UnsetAssignedRegister() { assigned_register_ = kUnassignedRegister; } 737 738 void AddOperand(InstructionOperand* operand); 739 void CommitAssignment(const InstructionOperand& operand); 740 741 private: 742 PhiInstruction* const phi_; 743 const InstructionBlock* const block_; 744 ZoneVector<InstructionOperand*> incoming_operands_; 745 int assigned_register_; 746 }; 747 typedef ZoneMap<int, PhiMapValue*> PhiMap; 748 749 struct DelayedReference { 750 ReferenceMap* map; 751 InstructionOperand* operand; 752 }; 753 typedef ZoneVector<DelayedReference> DelayedReferences; 754 typedef ZoneVector<std::pair<TopLevelLiveRange*, int>> 755 RangesWithPreassignedSlots; 756 757 RegisterAllocationData(const RegisterConfiguration* config, 758 Zone* allocation_zone, Frame* frame, 759 InstructionSequence* code, 760 const char* debug_name = nullptr); 761 live_ranges()762 const ZoneVector<TopLevelLiveRange*>& live_ranges() const { 763 return live_ranges_; 764 } live_ranges()765 ZoneVector<TopLevelLiveRange*>& live_ranges() { return live_ranges_; } fixed_live_ranges()766 const ZoneVector<TopLevelLiveRange*>& fixed_live_ranges() const { 767 return fixed_live_ranges_; 768 } fixed_live_ranges()769 ZoneVector<TopLevelLiveRange*>& fixed_live_ranges() { 770 return fixed_live_ranges_; 771 } fixed_double_live_ranges()772 ZoneVector<TopLevelLiveRange*>& fixed_double_live_ranges() { 773 return fixed_double_live_ranges_; 774 } fixed_double_live_ranges()775 const ZoneVector<TopLevelLiveRange*>& fixed_double_live_ranges() const { 776 return fixed_double_live_ranges_; 777 } live_in_sets()778 ZoneVector<BitVector*>& live_in_sets() { return live_in_sets_; } live_out_sets()779 ZoneVector<BitVector*>& live_out_sets() { return live_out_sets_; } spill_ranges()780 ZoneVector<SpillRange*>& spill_ranges() { return spill_ranges_; } delayed_references()781 DelayedReferences& delayed_references() { return delayed_references_; } code()782 InstructionSequence* code() const { return code_; } 783 // This zone is for datastructures only needed during register allocation 784 // phases. allocation_zone()785 Zone* allocation_zone() const { return allocation_zone_; } 786 // This zone is for InstructionOperands and moves that live beyond register 787 // allocation. code_zone()788 Zone* code_zone() const { return code()->zone(); } frame()789 Frame* frame() const { return frame_; } debug_name()790 const char* debug_name() const { return debug_name_; } config()791 const RegisterConfiguration* config() const { return config_; } 792 793 MachineRepresentation RepresentationFor(int virtual_register); 794 795 TopLevelLiveRange* GetOrCreateLiveRangeFor(int index); 796 // Creates a new live range. 797 TopLevelLiveRange* NewLiveRange(int index, MachineRepresentation rep); 798 TopLevelLiveRange* NextLiveRange(MachineRepresentation rep); 799 800 SpillRange* AssignSpillRangeToLiveRange(TopLevelLiveRange* range); 801 SpillRange* CreateSpillRangeForLiveRange(TopLevelLiveRange* range); 802 803 MoveOperands* AddGapMove(int index, Instruction::GapPosition position, 804 const InstructionOperand& from, 805 const InstructionOperand& to); 806 IsReference(TopLevelLiveRange * top_range)807 bool IsReference(TopLevelLiveRange* top_range) const { 808 return code()->IsReference(top_range->vreg()); 809 } 810 811 bool ExistsUseWithoutDefinition(); 812 bool RangesDefinedInDeferredStayInDeferred(); 813 814 void MarkAllocated(RegisterKind kind, int index); 815 816 PhiMapValue* InitializePhiMap(const InstructionBlock* block, 817 PhiInstruction* phi); 818 PhiMapValue* GetPhiMapValueFor(TopLevelLiveRange* top_range); 819 PhiMapValue* GetPhiMapValueFor(int virtual_register); 820 bool IsBlockBoundary(LifetimePosition pos) const; 821 preassigned_slot_ranges()822 RangesWithPreassignedSlots& preassigned_slot_ranges() { 823 return preassigned_slot_ranges_; 824 } 825 826 private: 827 int GetNextLiveRangeId(); 828 829 Zone* const allocation_zone_; 830 Frame* const frame_; 831 InstructionSequence* const code_; 832 const char* const debug_name_; 833 const RegisterConfiguration* const config_; 834 PhiMap phi_map_; 835 ZoneVector<int> allocatable_codes_; 836 ZoneVector<int> allocatable_double_codes_; 837 ZoneVector<BitVector*> live_in_sets_; 838 ZoneVector<BitVector*> live_out_sets_; 839 ZoneVector<TopLevelLiveRange*> live_ranges_; 840 ZoneVector<TopLevelLiveRange*> fixed_live_ranges_; 841 ZoneVector<TopLevelLiveRange*> fixed_double_live_ranges_; 842 ZoneVector<SpillRange*> spill_ranges_; 843 DelayedReferences delayed_references_; 844 BitVector* assigned_registers_; 845 BitVector* assigned_double_registers_; 846 int virtual_register_count_; 847 RangesWithPreassignedSlots preassigned_slot_ranges_; 848 849 DISALLOW_COPY_AND_ASSIGN(RegisterAllocationData); 850 }; 851 852 853 class ConstraintBuilder final : public ZoneObject { 854 public: 855 explicit ConstraintBuilder(RegisterAllocationData* data); 856 857 // Phase 1 : insert moves to account for fixed register operands. 858 void MeetRegisterConstraints(); 859 860 // Phase 2: deconstruct SSA by inserting moves in successors and the headers 861 // of blocks containing phis. 862 void ResolvePhis(); 863 864 private: data()865 RegisterAllocationData* data() const { return data_; } code()866 InstructionSequence* code() const { return data()->code(); } allocation_zone()867 Zone* allocation_zone() const { return data()->allocation_zone(); } 868 869 InstructionOperand* AllocateFixed(UnallocatedOperand* operand, int pos, 870 bool is_tagged); 871 void MeetRegisterConstraints(const InstructionBlock* block); 872 void MeetConstraintsBefore(int index); 873 void MeetConstraintsAfter(int index); 874 void MeetRegisterConstraintsForLastInstructionInBlock( 875 const InstructionBlock* block); 876 void ResolvePhis(const InstructionBlock* block); 877 878 RegisterAllocationData* const data_; 879 880 DISALLOW_COPY_AND_ASSIGN(ConstraintBuilder); 881 }; 882 883 884 class LiveRangeBuilder final : public ZoneObject { 885 public: 886 explicit LiveRangeBuilder(RegisterAllocationData* data, Zone* local_zone); 887 888 // Phase 3: compute liveness of all virtual register. 889 void BuildLiveRanges(); 890 static BitVector* ComputeLiveOut(const InstructionBlock* block, 891 RegisterAllocationData* data); 892 893 private: data()894 RegisterAllocationData* data() const { return data_; } code()895 InstructionSequence* code() const { return data()->code(); } allocation_zone()896 Zone* allocation_zone() const { return data()->allocation_zone(); } code_zone()897 Zone* code_zone() const { return code()->zone(); } config()898 const RegisterConfiguration* config() const { return data()->config(); } live_in_sets()899 ZoneVector<BitVector*>& live_in_sets() const { 900 return data()->live_in_sets(); 901 } 902 903 void Verify() const; 904 905 // Liveness analysis support. 906 void AddInitialIntervals(const InstructionBlock* block, BitVector* live_out); 907 void ProcessInstructions(const InstructionBlock* block, BitVector* live); 908 void ProcessPhis(const InstructionBlock* block, BitVector* live); 909 void ProcessLoopHeader(const InstructionBlock* block, BitVector* live); 910 FixedLiveRangeID(int index)911 static int FixedLiveRangeID(int index) { return -index - 1; } 912 int FixedDoubleLiveRangeID(int index); 913 TopLevelLiveRange* FixedLiveRangeFor(int index); 914 TopLevelLiveRange* FixedDoubleLiveRangeFor(int index); 915 916 void MapPhiHint(InstructionOperand* operand, UsePosition* use_pos); 917 void ResolvePhiHint(InstructionOperand* operand, UsePosition* use_pos); 918 919 UsePosition* NewUsePosition(LifetimePosition pos, InstructionOperand* operand, 920 void* hint, UsePositionHintType hint_type); NewUsePosition(LifetimePosition pos)921 UsePosition* NewUsePosition(LifetimePosition pos) { 922 return NewUsePosition(pos, nullptr, nullptr, UsePositionHintType::kNone); 923 } 924 TopLevelLiveRange* LiveRangeFor(InstructionOperand* operand); 925 // Helper methods for building intervals. 926 UsePosition* Define(LifetimePosition position, InstructionOperand* operand, 927 void* hint, UsePositionHintType hint_type); Define(LifetimePosition position,InstructionOperand * operand)928 void Define(LifetimePosition position, InstructionOperand* operand) { 929 Define(position, operand, nullptr, UsePositionHintType::kNone); 930 } 931 UsePosition* Use(LifetimePosition block_start, LifetimePosition position, 932 InstructionOperand* operand, void* hint, 933 UsePositionHintType hint_type); Use(LifetimePosition block_start,LifetimePosition position,InstructionOperand * operand)934 void Use(LifetimePosition block_start, LifetimePosition position, 935 InstructionOperand* operand) { 936 Use(block_start, position, operand, nullptr, UsePositionHintType::kNone); 937 } 938 939 RegisterAllocationData* const data_; 940 ZoneMap<InstructionOperand*, UsePosition*> phi_hints_; 941 942 DISALLOW_COPY_AND_ASSIGN(LiveRangeBuilder); 943 }; 944 945 946 class RegisterAllocator : public ZoneObject { 947 public: 948 explicit RegisterAllocator(RegisterAllocationData* data, RegisterKind kind); 949 950 protected: data()951 RegisterAllocationData* data() const { return data_; } code()952 InstructionSequence* code() const { return data()->code(); } mode()953 RegisterKind mode() const { return mode_; } num_registers()954 int num_registers() const { return num_registers_; } num_allocatable_registers()955 int num_allocatable_registers() const { return num_allocatable_registers_; } allocatable_register_code(int allocatable_index)956 int allocatable_register_code(int allocatable_index) const { 957 return allocatable_register_codes_[allocatable_index]; 958 } 959 960 // TODO(mtrofin): explain why splitting in gap START is always OK. 961 LifetimePosition GetSplitPositionForInstruction(const LiveRange* range, 962 int instruction_index); 963 allocation_zone()964 Zone* allocation_zone() const { return data()->allocation_zone(); } 965 966 // Find the optimal split for ranges defined by a memory operand, e.g. 967 // constants or function parameters passed on the stack. 968 void SplitAndSpillRangesDefinedByMemoryOperand(bool operands_only); 969 970 // Split the given range at the given position. 971 // If range starts at or after the given position then the 972 // original range is returned. 973 // Otherwise returns the live range that starts at pos and contains 974 // all uses from the original range that follow pos. Uses at pos will 975 // still be owned by the original range after splitting. 976 LiveRange* SplitRangeAt(LiveRange* range, LifetimePosition pos); 977 CanProcessRange(LiveRange * range)978 bool CanProcessRange(LiveRange* range) const { 979 return range != nullptr && !range->IsEmpty() && range->kind() == mode(); 980 } 981 982 983 // Split the given range in a position from the interval [start, end]. 984 LiveRange* SplitBetween(LiveRange* range, LifetimePosition start, 985 LifetimePosition end); 986 987 // Find a lifetime position in the interval [start, end] which 988 // is optimal for splitting: it is either header of the outermost 989 // loop covered by this interval or the latest possible position. 990 LifetimePosition FindOptimalSplitPos(LifetimePosition start, 991 LifetimePosition end); 992 993 void Spill(LiveRange* range); 994 995 // If we are trying to spill a range inside the loop try to 996 // hoist spill position out to the point just before the loop. 997 LifetimePosition FindOptimalSpillingPos(LiveRange* range, 998 LifetimePosition pos); 999 1000 const ZoneVector<TopLevelLiveRange*>& GetFixedRegisters() const; 1001 const char* RegisterName(int allocation_index) const; 1002 1003 private: 1004 RegisterAllocationData* const data_; 1005 const RegisterKind mode_; 1006 const int num_registers_; 1007 int num_allocatable_registers_; 1008 const int* allocatable_register_codes_; 1009 1010 DISALLOW_COPY_AND_ASSIGN(RegisterAllocator); 1011 }; 1012 1013 1014 class LinearScanAllocator final : public RegisterAllocator { 1015 public: 1016 LinearScanAllocator(RegisterAllocationData* data, RegisterKind kind, 1017 Zone* local_zone); 1018 1019 // Phase 4: compute register assignments. 1020 void AllocateRegisters(); 1021 1022 private: unhandled_live_ranges()1023 ZoneVector<LiveRange*>& unhandled_live_ranges() { 1024 return unhandled_live_ranges_; 1025 } active_live_ranges()1026 ZoneVector<LiveRange*>& active_live_ranges() { return active_live_ranges_; } inactive_live_ranges()1027 ZoneVector<LiveRange*>& inactive_live_ranges() { 1028 return inactive_live_ranges_; 1029 } 1030 1031 void SetLiveRangeAssignedRegister(LiveRange* range, int reg); 1032 1033 // Helper methods for updating the life range lists. 1034 void AddToActive(LiveRange* range); 1035 void AddToInactive(LiveRange* range); 1036 void AddToUnhandledSorted(LiveRange* range); 1037 void AddToUnhandledUnsorted(LiveRange* range); 1038 void SortUnhandled(); 1039 bool UnhandledIsSorted(); 1040 void ActiveToHandled(LiveRange* range); 1041 void ActiveToInactive(LiveRange* range); 1042 void InactiveToHandled(LiveRange* range); 1043 void InactiveToActive(LiveRange* range); 1044 1045 // Helper methods for allocating registers. 1046 bool TryReuseSpillForPhi(TopLevelLiveRange* range); 1047 bool TryAllocateFreeReg(LiveRange* range); 1048 void AllocateBlockedReg(LiveRange* range); 1049 1050 // Spill the given life range after position pos. 1051 void SpillAfter(LiveRange* range, LifetimePosition pos); 1052 1053 // Spill the given life range after position [start] and up to position [end]. 1054 void SpillBetween(LiveRange* range, LifetimePosition start, 1055 LifetimePosition end); 1056 1057 // Spill the given life range after position [start] and up to position [end]. 1058 // Range is guaranteed to be spilled at least until position [until]. 1059 void SpillBetweenUntil(LiveRange* range, LifetimePosition start, 1060 LifetimePosition until, LifetimePosition end); 1061 1062 void SplitAndSpillIntersecting(LiveRange* range); 1063 1064 ZoneVector<LiveRange*> unhandled_live_ranges_; 1065 ZoneVector<LiveRange*> active_live_ranges_; 1066 ZoneVector<LiveRange*> inactive_live_ranges_; 1067 1068 #ifdef DEBUG 1069 LifetimePosition allocation_finger_; 1070 #endif 1071 1072 DISALLOW_COPY_AND_ASSIGN(LinearScanAllocator); 1073 }; 1074 1075 1076 class SpillSlotLocator final : public ZoneObject { 1077 public: 1078 explicit SpillSlotLocator(RegisterAllocationData* data); 1079 1080 void LocateSpillSlots(); 1081 1082 private: data()1083 RegisterAllocationData* data() const { return data_; } 1084 1085 RegisterAllocationData* const data_; 1086 1087 DISALLOW_COPY_AND_ASSIGN(SpillSlotLocator); 1088 }; 1089 1090 1091 class OperandAssigner final : public ZoneObject { 1092 public: 1093 explicit OperandAssigner(RegisterAllocationData* data); 1094 1095 // Phase 5: assign spill splots. 1096 void AssignSpillSlots(); 1097 1098 // Phase 6: commit assignment. 1099 void CommitAssignment(); 1100 1101 private: data()1102 RegisterAllocationData* data() const { return data_; } 1103 1104 RegisterAllocationData* const data_; 1105 1106 DISALLOW_COPY_AND_ASSIGN(OperandAssigner); 1107 }; 1108 1109 1110 class ReferenceMapPopulator final : public ZoneObject { 1111 public: 1112 explicit ReferenceMapPopulator(RegisterAllocationData* data); 1113 1114 // Phase 7: compute values for pointer maps. 1115 void PopulateReferenceMaps(); 1116 1117 private: data()1118 RegisterAllocationData* data() const { return data_; } 1119 1120 bool SafePointsAreInOrder() const; 1121 1122 RegisterAllocationData* const data_; 1123 1124 DISALLOW_COPY_AND_ASSIGN(ReferenceMapPopulator); 1125 }; 1126 1127 1128 // Insert moves of the form 1129 // 1130 // Operand(child_(k+1)) = Operand(child_k) 1131 // 1132 // where child_k and child_(k+1) are consecutive children of a range (so 1133 // child_k->next() == child_(k+1)), and Operand(...) refers to the 1134 // assigned operand, be it a register or a slot. 1135 class LiveRangeConnector final : public ZoneObject { 1136 public: 1137 explicit LiveRangeConnector(RegisterAllocationData* data); 1138 1139 // Phase 8: reconnect split ranges with moves, when the control flow 1140 // between the ranges is trivial (no branches). 1141 void ConnectRanges(Zone* local_zone); 1142 1143 // Phase 9: insert moves to connect ranges across basic blocks, when the 1144 // control flow between them cannot be trivially resolved, such as joining 1145 // branches. 1146 void ResolveControlFlow(Zone* local_zone); 1147 1148 private: data()1149 RegisterAllocationData* data() const { return data_; } code()1150 InstructionSequence* code() const { return data()->code(); } code_zone()1151 Zone* code_zone() const { return code()->zone(); } 1152 1153 bool CanEagerlyResolveControlFlow(const InstructionBlock* block) const; 1154 1155 int ResolveControlFlow(const InstructionBlock* block, 1156 const InstructionOperand& cur_op, 1157 const InstructionBlock* pred, 1158 const InstructionOperand& pred_op); 1159 1160 RegisterAllocationData* const data_; 1161 1162 DISALLOW_COPY_AND_ASSIGN(LiveRangeConnector); 1163 }; 1164 1165 } // namespace compiler 1166 } // namespace internal 1167 } // namespace v8 1168 1169 #endif // V8_REGISTER_ALLOCATOR_H_ 1170