1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #ifndef V8_LITHIUM_ALLOCATOR_H_ 29 #define V8_LITHIUM_ALLOCATOR_H_ 30 31 #include "v8.h" 32 33 #include "allocation.h" 34 #include "lithium.h" 35 #include "zone.h" 36 37 namespace v8 { 38 namespace internal { 39 40 // Forward declarations. 41 class HBasicBlock; 42 class HGraph; 43 class HInstruction; 44 class HPhi; 45 class HTracer; 46 class HValue; 47 class BitVector; 48 class StringStream; 49 50 class LArgument; 51 class LPlatformChunk; 52 class LOperand; 53 class LUnallocated; 54 class LConstantOperand; 55 class LGap; 56 class LParallelMove; 57 class LPointerMap; 58 class LStackSlot; 59 class LRegister; 60 61 62 // This class represents a single point of a LOperand's lifetime. 63 // For each lithium instruction there are exactly two lifetime positions: 64 // the beginning and the end of the instruction. Lifetime positions for 65 // different lithium instructions are disjoint. 66 class LifetimePosition { 67 public: 68 // Return the lifetime position that corresponds to the beginning of 69 // the instruction with the given index. 70 static LifetimePosition FromInstructionIndex(int index) { 71 return LifetimePosition(index * kStep); 72 } 73 74 // Returns a numeric representation of this lifetime position. 75 int Value() const { 76 return value_; 77 } 78 79 // Returns the index of the instruction to which this lifetime position 80 // corresponds. 81 int InstructionIndex() const { 82 ASSERT(IsValid()); 83 return value_ / kStep; 84 } 85 86 // Returns true if this lifetime position corresponds to the instruction 87 // start. 88 bool IsInstructionStart() const { 89 return (value_ & (kStep - 1)) == 0; 90 } 91 92 // Returns the lifetime position for the start of the instruction which 93 // corresponds to this lifetime position. 94 LifetimePosition InstructionStart() const { 95 ASSERT(IsValid()); 96 return LifetimePosition(value_ & ~(kStep - 1)); 97 } 98 99 // Returns the lifetime position for the end of the instruction which 100 // corresponds to this lifetime position. 101 LifetimePosition InstructionEnd() const { 102 ASSERT(IsValid()); 103 return LifetimePosition(InstructionStart().Value() + kStep/2); 104 } 105 106 // Returns the lifetime position for the beginning of the next instruction. 107 LifetimePosition NextInstruction() const { 108 ASSERT(IsValid()); 109 return LifetimePosition(InstructionStart().Value() + kStep); 110 } 111 112 // Returns the lifetime position for the beginning of the previous 113 // instruction. 114 LifetimePosition PrevInstruction() const { 115 ASSERT(IsValid()); 116 ASSERT(value_ > 1); 117 return LifetimePosition(InstructionStart().Value() - kStep); 118 } 119 120 // Constructs the lifetime position which does not correspond to any 121 // instruction. 122 LifetimePosition() : value_(-1) {} 123 124 // Returns true if this lifetime positions corrensponds to some 125 // instruction. 126 bool IsValid() const { return value_ != -1; } 127 128 static inline LifetimePosition Invalid() { return LifetimePosition(); } 129 130 static inline LifetimePosition MaxPosition() { 131 // We have to use this kind of getter instead of static member due to 132 // crash bug in GDB. 133 return LifetimePosition(kMaxInt); 134 } 135 136 private: 137 static const int kStep = 2; 138 139 // Code relies on kStep being a power of two. 140 STATIC_ASSERT(IS_POWER_OF_TWO(kStep)); 141 142 explicit LifetimePosition(int value) : value_(value) { } 143 144 int value_; 145 }; 146 147 148 enum RegisterKind { 149 UNALLOCATED_REGISTERS, 150 GENERAL_REGISTERS, 151 DOUBLE_REGISTERS 152 }; 153 154 155 // A register-allocator view of a Lithium instruction. It contains the id of 156 // the output operand and a list of input operand uses. 157 158 class LInstruction; 159 class LEnvironment; 160 161 // Iterator for non-null temp operands. 162 class TempIterator BASE_EMBEDDED { 163 public: 164 inline explicit TempIterator(LInstruction* instr); 165 inline bool Done(); 166 inline LOperand* Current(); 167 inline void Advance(); 168 169 private: 170 inline void SkipUninteresting(); 171 LInstruction* instr_; 172 int limit_; 173 int current_; 174 }; 175 176 177 // Iterator for non-constant input operands. 178 class InputIterator BASE_EMBEDDED { 179 public: 180 inline explicit InputIterator(LInstruction* instr); 181 inline bool Done(); 182 inline LOperand* Current(); 183 inline void Advance(); 184 185 private: 186 inline void SkipUninteresting(); 187 LInstruction* instr_; 188 int limit_; 189 int current_; 190 }; 191 192 193 class UseIterator BASE_EMBEDDED { 194 public: 195 inline explicit UseIterator(LInstruction* instr); 196 inline bool Done(); 197 inline LOperand* Current(); 198 inline void Advance(); 199 200 private: 201 InputIterator input_iterator_; 202 DeepIterator env_iterator_; 203 }; 204 205 206 // Representation of the non-empty interval [start,end[. 207 class UseInterval: public ZoneObject { 208 public: 209 UseInterval(LifetimePosition start, LifetimePosition end) 210 : start_(start), end_(end), next_(NULL) { 211 ASSERT(start.Value() < end.Value()); 212 } 213 214 LifetimePosition start() const { return start_; } 215 LifetimePosition end() const { return end_; } 216 UseInterval* next() const { return next_; } 217 218 // Split this interval at the given position without effecting the 219 // live range that owns it. The interval must contain the position. 220 void SplitAt(LifetimePosition pos, Zone* zone); 221 222 // If this interval intersects with other return smallest position 223 // that belongs to both of them. 224 LifetimePosition Intersect(const UseInterval* other) const { 225 if (other->start().Value() < start_.Value()) return other->Intersect(this); 226 if (other->start().Value() < end_.Value()) return other->start(); 227 return LifetimePosition::Invalid(); 228 } 229 230 bool Contains(LifetimePosition point) const { 231 return start_.Value() <= point.Value() && point.Value() < end_.Value(); 232 } 233 234 private: 235 void set_start(LifetimePosition start) { start_ = start; } 236 void set_next(UseInterval* next) { next_ = next; } 237 238 LifetimePosition start_; 239 LifetimePosition end_; 240 UseInterval* next_; 241 242 friend class LiveRange; // Assigns to start_. 243 }; 244 245 // Representation of a use position. 246 class UsePosition: public ZoneObject { 247 public: 248 UsePosition(LifetimePosition pos, LOperand* operand, LOperand* hint); 249 250 LOperand* operand() const { return operand_; } 251 bool HasOperand() const { return operand_ != NULL; } 252 253 LOperand* hint() const { return hint_; } 254 bool HasHint() const; 255 bool RequiresRegister() const; 256 bool RegisterIsBeneficial() const; 257 258 LifetimePosition pos() const { return pos_; } 259 UsePosition* next() const { return next_; } 260 261 private: 262 void set_next(UsePosition* next) { next_ = next; } 263 264 LOperand* const operand_; 265 LOperand* const hint_; 266 LifetimePosition const pos_; 267 UsePosition* next_; 268 bool requires_reg_; 269 bool register_beneficial_; 270 271 friend class LiveRange; 272 }; 273 274 // Representation of SSA values' live ranges as a collection of (continuous) 275 // intervals over the instruction ordering. 276 class LiveRange: public ZoneObject { 277 public: 278 static const int kInvalidAssignment = 0x7fffffff; 279 280 LiveRange(int id, Zone* zone); 281 282 UseInterval* first_interval() const { return first_interval_; } 283 UsePosition* first_pos() const { return first_pos_; } 284 LiveRange* parent() const { return parent_; } 285 LiveRange* TopLevel() { return (parent_ == NULL) ? this : parent_; } 286 LiveRange* next() const { return next_; } 287 bool IsChild() const { return parent() != NULL; } 288 int id() const { return id_; } 289 bool IsFixed() const { return id_ < 0; } 290 bool IsEmpty() const { return first_interval() == NULL; } 291 LOperand* CreateAssignedOperand(Zone* zone); 292 int assigned_register() const { return assigned_register_; } 293 int spill_start_index() const { return spill_start_index_; } 294 void set_assigned_register(int reg, Zone* zone); 295 void MakeSpilled(Zone* zone); 296 297 // Returns use position in this live range that follows both start 298 // and last processed use position. 299 // Modifies internal state of live range! 300 UsePosition* NextUsePosition(LifetimePosition start); 301 302 // Returns use position for which register is required in this live 303 // range and which follows both start and last processed use position 304 // Modifies internal state of live range! 305 UsePosition* NextRegisterPosition(LifetimePosition start); 306 307 // Returns use position for which register is beneficial in this live 308 // range and which follows both start and last processed use position 309 // Modifies internal state of live range! 310 UsePosition* NextUsePositionRegisterIsBeneficial(LifetimePosition start); 311 312 // Returns use position for which register is beneficial in this live 313 // range and which precedes start. 314 UsePosition* PreviousUsePositionRegisterIsBeneficial(LifetimePosition start); 315 316 // Can this live range be spilled at this position. 317 bool CanBeSpilled(LifetimePosition pos); 318 319 // Split this live range at the given position which must follow the start of 320 // the range. 321 // All uses following the given position will be moved from this 322 // live range to the result live range. 323 void SplitAt(LifetimePosition position, LiveRange* result, Zone* zone); 324 325 RegisterKind Kind() const { return kind_; } 326 bool HasRegisterAssigned() const { 327 return assigned_register_ != kInvalidAssignment; 328 } 329 bool IsSpilled() const { return spilled_; } 330 331 LOperand* current_hint_operand() const { 332 ASSERT(current_hint_operand_ == FirstHint()); 333 return current_hint_operand_; 334 } 335 LOperand* FirstHint() const { 336 UsePosition* pos = first_pos_; 337 while (pos != NULL && !pos->HasHint()) pos = pos->next(); 338 if (pos != NULL) return pos->hint(); 339 return NULL; 340 } 341 342 LifetimePosition Start() const { 343 ASSERT(!IsEmpty()); 344 return first_interval()->start(); 345 } 346 347 LifetimePosition End() const { 348 ASSERT(!IsEmpty()); 349 return last_interval_->end(); 350 } 351 352 bool HasAllocatedSpillOperand() const; 353 LOperand* GetSpillOperand() const { return spill_operand_; } 354 void SetSpillOperand(LOperand* operand); 355 356 void SetSpillStartIndex(int start) { 357 spill_start_index_ = Min(start, spill_start_index_); 358 } 359 360 bool ShouldBeAllocatedBefore(const LiveRange* other) const; 361 bool CanCover(LifetimePosition position) const; 362 bool Covers(LifetimePosition position); 363 LifetimePosition FirstIntersection(LiveRange* other); 364 365 // Add a new interval or a new use position to this live range. 366 void EnsureInterval(LifetimePosition start, 367 LifetimePosition end, 368 Zone* zone); 369 void AddUseInterval(LifetimePosition start, 370 LifetimePosition end, 371 Zone* zone); 372 void AddUsePosition(LifetimePosition pos, 373 LOperand* operand, 374 LOperand* hint, 375 Zone* zone); 376 377 // Shorten the most recently added interval by setting a new start. 378 void ShortenTo(LifetimePosition start); 379 380 #ifdef DEBUG 381 // True if target overlaps an existing interval. 382 bool HasOverlap(UseInterval* target) const; 383 void Verify() const; 384 #endif 385 386 private: 387 void ConvertOperands(Zone* zone); 388 UseInterval* FirstSearchIntervalForPosition(LifetimePosition position) const; 389 void AdvanceLastProcessedMarker(UseInterval* to_start_of, 390 LifetimePosition but_not_past) const; 391 392 int id_; 393 bool spilled_; 394 RegisterKind kind_; 395 int assigned_register_; 396 UseInterval* last_interval_; 397 UseInterval* first_interval_; 398 UsePosition* first_pos_; 399 LiveRange* parent_; 400 LiveRange* next_; 401 // This is used as a cache, it doesn't affect correctness. 402 mutable UseInterval* current_interval_; 403 UsePosition* last_processed_use_; 404 // This is used as a cache, it's invalid outside of BuildLiveRanges. 405 LOperand* current_hint_operand_; 406 LOperand* spill_operand_; 407 int spill_start_index_; 408 409 friend class LAllocator; // Assigns to kind_. 410 }; 411 412 413 class LAllocator BASE_EMBEDDED { 414 public: 415 LAllocator(int first_virtual_register, HGraph* graph); 416 417 static void TraceAlloc(const char* msg, ...); 418 419 // Checks whether the value of a given virtual register is tagged. 420 bool HasTaggedValue(int virtual_register) const; 421 422 // Returns the register kind required by the given virtual register. 423 RegisterKind RequiredRegisterKind(int virtual_register) const; 424 425 bool Allocate(LChunk* chunk); 426 427 const ZoneList<LiveRange*>* live_ranges() const { return &live_ranges_; } 428 const Vector<LiveRange*>* fixed_live_ranges() const { 429 return &fixed_live_ranges_; 430 } 431 const Vector<LiveRange*>* fixed_double_live_ranges() const { 432 return &fixed_double_live_ranges_; 433 } 434 435 LPlatformChunk* chunk() const { return chunk_; } 436 HGraph* graph() const { return graph_; } 437 Isolate* isolate() const { return graph_->isolate(); } 438 Zone* zone() { return &zone_; } 439 440 int GetVirtualRegister() { 441 if (next_virtual_register_ >= LUnallocated::kMaxVirtualRegisters) { 442 allocation_ok_ = false; 443 // Maintain the invariant that we return something below the maximum. 444 return 0; 445 } 446 return next_virtual_register_++; 447 } 448 449 bool AllocationOk() { return allocation_ok_; } 450 451 void MarkAsOsrEntry() { 452 // There can be only one. 453 ASSERT(!has_osr_entry_); 454 // Simply set a flag to find and process instruction later. 455 has_osr_entry_ = true; 456 } 457 458 #ifdef DEBUG 459 void Verify() const; 460 #endif 461 462 BitVector* assigned_registers() { 463 return assigned_registers_; 464 } 465 BitVector* assigned_double_registers() { 466 return assigned_double_registers_; 467 } 468 469 private: 470 void MeetRegisterConstraints(); 471 void ResolvePhis(); 472 void BuildLiveRanges(); 473 void AllocateGeneralRegisters(); 474 void AllocateDoubleRegisters(); 475 void ConnectRanges(); 476 void ResolveControlFlow(); 477 void PopulatePointerMaps(); 478 void AllocateRegisters(); 479 bool CanEagerlyResolveControlFlow(HBasicBlock* block) const; 480 inline bool SafePointsAreInOrder() const; 481 482 // Liveness analysis support. 483 void InitializeLivenessAnalysis(); 484 BitVector* ComputeLiveOut(HBasicBlock* block); 485 void AddInitialIntervals(HBasicBlock* block, BitVector* live_out); 486 void ProcessInstructions(HBasicBlock* block, BitVector* live); 487 void MeetRegisterConstraints(HBasicBlock* block); 488 void MeetConstraintsBetween(LInstruction* first, 489 LInstruction* second, 490 int gap_index); 491 void ResolvePhis(HBasicBlock* block); 492 493 // Helper methods for building intervals. 494 LOperand* AllocateFixed(LUnallocated* operand, int pos, bool is_tagged); 495 LiveRange* LiveRangeFor(LOperand* operand); 496 void Define(LifetimePosition position, LOperand* operand, LOperand* hint); 497 void Use(LifetimePosition block_start, 498 LifetimePosition position, 499 LOperand* operand, 500 LOperand* hint); 501 void AddConstraintsGapMove(int index, LOperand* from, LOperand* to); 502 503 // Helper methods for updating the life range lists. 504 void AddToActive(LiveRange* range); 505 void AddToInactive(LiveRange* range); 506 void AddToUnhandledSorted(LiveRange* range); 507 void AddToUnhandledUnsorted(LiveRange* range); 508 void SortUnhandled(); 509 bool UnhandledIsSorted(); 510 void ActiveToHandled(LiveRange* range); 511 void ActiveToInactive(LiveRange* range); 512 void InactiveToHandled(LiveRange* range); 513 void InactiveToActive(LiveRange* range); 514 void FreeSpillSlot(LiveRange* range); 515 LOperand* TryReuseSpillSlot(LiveRange* range); 516 517 // Helper methods for allocating registers. 518 bool TryAllocateFreeReg(LiveRange* range); 519 void AllocateBlockedReg(LiveRange* range); 520 521 // Live range splitting helpers. 522 523 // Split the given range at the given position. 524 // If range starts at or after the given position then the 525 // original range is returned. 526 // Otherwise returns the live range that starts at pos and contains 527 // all uses from the original range that follow pos. Uses at pos will 528 // still be owned by the original range after splitting. 529 LiveRange* SplitRangeAt(LiveRange* range, LifetimePosition pos); 530 531 // Split the given range in a position from the interval [start, end]. 532 LiveRange* SplitBetween(LiveRange* range, 533 LifetimePosition start, 534 LifetimePosition end); 535 536 // Find a lifetime position in the interval [start, end] which 537 // is optimal for splitting: it is either header of the outermost 538 // loop covered by this interval or the latest possible position. 539 LifetimePosition FindOptimalSplitPos(LifetimePosition start, 540 LifetimePosition end); 541 542 // Spill the given life range after position pos. 543 void SpillAfter(LiveRange* range, LifetimePosition pos); 544 545 // Spill the given life range after position [start] and up to position [end]. 546 void SpillBetween(LiveRange* range, 547 LifetimePosition start, 548 LifetimePosition end); 549 550 // Spill the given life range after position [start] and up to position [end]. 551 // Range is guaranteed to be spilled at least until position [until]. 552 void SpillBetweenUntil(LiveRange* range, 553 LifetimePosition start, 554 LifetimePosition until, 555 LifetimePosition end); 556 557 void SplitAndSpillIntersecting(LiveRange* range); 558 559 // If we are trying to spill a range inside the loop try to 560 // hoist spill position out to the point just before the loop. 561 LifetimePosition FindOptimalSpillingPos(LiveRange* range, 562 LifetimePosition pos); 563 564 void Spill(LiveRange* range); 565 bool IsBlockBoundary(LifetimePosition pos); 566 567 // Helper methods for resolving control flow. 568 void ResolveControlFlow(LiveRange* range, 569 HBasicBlock* block, 570 HBasicBlock* pred); 571 572 inline void SetLiveRangeAssignedRegister(LiveRange* range, int reg); 573 574 // Return parallel move that should be used to connect ranges split at the 575 // given position. 576 LParallelMove* GetConnectingParallelMove(LifetimePosition pos); 577 578 // Return the block which contains give lifetime position. 579 HBasicBlock* GetBlock(LifetimePosition pos); 580 581 // Helper methods for the fixed registers. 582 int RegisterCount() const; 583 static int FixedLiveRangeID(int index) { return -index - 1; } 584 static int FixedDoubleLiveRangeID(int index); 585 LiveRange* FixedLiveRangeFor(int index); 586 LiveRange* FixedDoubleLiveRangeFor(int index); 587 LiveRange* LiveRangeFor(int index); 588 HPhi* LookupPhi(LOperand* operand) const; 589 LGap* GetLastGap(HBasicBlock* block); 590 591 const char* RegisterName(int allocation_index); 592 593 inline bool IsGapAt(int index); 594 595 inline LInstruction* InstructionAt(int index); 596 597 inline LGap* GapAt(int index); 598 599 Zone zone_; 600 601 LPlatformChunk* chunk_; 602 603 // During liveness analysis keep a mapping from block id to live_in sets 604 // for blocks already analyzed. 605 ZoneList<BitVector*> live_in_sets_; 606 607 // Liveness analysis results. 608 ZoneList<LiveRange*> live_ranges_; 609 610 // Lists of live ranges 611 EmbeddedVector<LiveRange*, Register::kMaxNumAllocatableRegisters> 612 fixed_live_ranges_; 613 EmbeddedVector<LiveRange*, DoubleRegister::kMaxNumAllocatableRegisters> 614 fixed_double_live_ranges_; 615 ZoneList<LiveRange*> unhandled_live_ranges_; 616 ZoneList<LiveRange*> active_live_ranges_; 617 ZoneList<LiveRange*> inactive_live_ranges_; 618 ZoneList<LiveRange*> reusable_slots_; 619 620 // Next virtual register number to be assigned to temporaries. 621 int next_virtual_register_; 622 int first_artificial_register_; 623 GrowableBitVector double_artificial_registers_; 624 625 RegisterKind mode_; 626 int num_registers_; 627 628 BitVector* assigned_registers_; 629 BitVector* assigned_double_registers_; 630 631 HGraph* graph_; 632 633 bool has_osr_entry_; 634 635 // Indicates success or failure during register allocation. 636 bool allocation_ok_; 637 638 #ifdef DEBUG 639 LifetimePosition allocation_finger_; 640 #endif 641 642 DISALLOW_COPY_AND_ASSIGN(LAllocator); 643 }; 644 645 646 class LAllocatorPhase : public CompilationPhase { 647 public: 648 LAllocatorPhase(const char* name, LAllocator* allocator); 649 ~LAllocatorPhase(); 650 651 private: 652 LAllocator* allocator_; 653 unsigned allocator_zone_start_allocation_size_; 654 655 DISALLOW_COPY_AND_ASSIGN(LAllocatorPhase); 656 }; 657 658 659 } } // namespace v8::internal 660 661 #endif // V8_LITHIUM_ALLOCATOR_H_ 662