| 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/allocation.h" | 8 #include "src/allocation.h" |
| 9 #include "src/compiler/instruction.h" | 9 #include "src/compiler/instruction.h" |
| 10 #include "src/compiler/zone-pool.h" | |
| 11 #include "src/macro-assembler.h" | 10 #include "src/macro-assembler.h" |
| 12 #include "src/zone.h" | 11 #include "src/zone.h" |
| 13 | 12 |
| 14 namespace v8 { | 13 namespace v8 { |
| 15 namespace internal { | 14 namespace internal { |
| 16 | |
| 17 // Forward declarations. | |
| 18 class BitVector; | |
| 19 class InstructionOperand; | |
| 20 class UnallocatedOperand; | |
| 21 class ParallelMove; | |
| 22 class PointerMap; | |
| 23 | |
| 24 namespace compiler { | 15 namespace compiler { |
| 25 | 16 |
| 26 class PipelineStatistics; | 17 class PipelineStatistics; |
| 27 | 18 |
| 28 enum RegisterKind { | 19 enum RegisterKind { |
| 29 UNALLOCATED_REGISTERS, | 20 UNALLOCATED_REGISTERS, |
| 30 GENERAL_REGISTERS, | 21 GENERAL_REGISTERS, |
| 31 DOUBLE_REGISTERS | 22 DOUBLE_REGISTERS |
| 32 }; | 23 }; |
| 33 | 24 |
| 34 | 25 |
| 35 // This class represents a single point of a InstructionOperand's lifetime. For | 26 // This class represents a single point of a InstructionOperand's lifetime. For |
| 36 // each instruction there are exactly two lifetime positions: the beginning and | 27 // each instruction there are exactly two lifetime positions: the beginning and |
| 37 // the end of the instruction. Lifetime positions for different instructions are | 28 // the end of the instruction. Lifetime positions for different instructions are |
| 38 // disjoint. | 29 // disjoint. |
| 39 class LifetimePosition { | 30 class LifetimePosition FINAL { |
| 40 public: | 31 public: |
| 41 // Return the lifetime position that corresponds to the beginning of | 32 // Return the lifetime position that corresponds to the beginning of |
| 42 // the instruction with the given index. | 33 // the instruction with the given index. |
| 43 static LifetimePosition FromInstructionIndex(int index) { | 34 static LifetimePosition FromInstructionIndex(int index) { |
| 44 return LifetimePosition(index * kStep); | 35 return LifetimePosition(index * kStep); |
| 45 } | 36 } |
| 46 | 37 |
| 47 // Returns a numeric representation of this lifetime position. | 38 // Returns a numeric representation of this lifetime position. |
| 48 int Value() const { return value_; } | 39 int Value() const { return value_; } |
| 49 | 40 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 108 // Code relies on kStep being a power of two. | 99 // Code relies on kStep being a power of two. |
| 109 STATIC_ASSERT(IS_POWER_OF_TWO(kStep)); | 100 STATIC_ASSERT(IS_POWER_OF_TWO(kStep)); |
| 110 | 101 |
| 111 explicit LifetimePosition(int value) : value_(value) {} | 102 explicit LifetimePosition(int value) : value_(value) {} |
| 112 | 103 |
| 113 int value_; | 104 int value_; |
| 114 }; | 105 }; |
| 115 | 106 |
| 116 | 107 |
| 117 // Representation of the non-empty interval [start,end[. | 108 // Representation of the non-empty interval [start,end[. |
| 118 class UseInterval : public ZoneObject { | 109 class UseInterval FINAL : public ZoneObject { |
| 119 public: | 110 public: |
| 120 UseInterval(LifetimePosition start, LifetimePosition end) | 111 UseInterval(LifetimePosition start, LifetimePosition end) |
| 121 : start_(start), end_(end), next_(NULL) { | 112 : start_(start), end_(end), next_(NULL) { |
| 122 DCHECK(start.Value() < end.Value()); | 113 DCHECK(start.Value() < end.Value()); |
| 123 } | 114 } |
| 124 | 115 |
| 125 LifetimePosition start() const { return start_; } | 116 LifetimePosition start() const { return start_; } |
| 126 LifetimePosition end() const { return end_; } | 117 LifetimePosition end() const { return end_; } |
| 127 UseInterval* next() const { return next_; } | 118 UseInterval* next() const { return next_; } |
| 128 | 119 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 141 bool Contains(LifetimePosition point) const { | 132 bool Contains(LifetimePosition point) const { |
| 142 return start_.Value() <= point.Value() && point.Value() < end_.Value(); | 133 return start_.Value() <= point.Value() && point.Value() < end_.Value(); |
| 143 } | 134 } |
| 144 | 135 |
| 145 void set_start(LifetimePosition start) { start_ = start; } | 136 void set_start(LifetimePosition start) { start_ = start; } |
| 146 void set_next(UseInterval* next) { next_ = next; } | 137 void set_next(UseInterval* next) { next_ = next; } |
| 147 | 138 |
| 148 LifetimePosition start_; | 139 LifetimePosition start_; |
| 149 LifetimePosition end_; | 140 LifetimePosition end_; |
| 150 UseInterval* next_; | 141 UseInterval* next_; |
| 142 |
| 143 private: |
| 144 DISALLOW_COPY_AND_ASSIGN(UseInterval); |
| 151 }; | 145 }; |
| 152 | 146 |
| 147 |
| 153 // Representation of a use position. | 148 // Representation of a use position. |
| 154 class UsePosition : public ZoneObject { | 149 class UsePosition FINAL : public ZoneObject { |
| 155 public: | 150 public: |
| 156 UsePosition(LifetimePosition pos, InstructionOperand* operand, | 151 UsePosition(LifetimePosition pos, InstructionOperand* operand, |
| 157 InstructionOperand* hint); | 152 InstructionOperand* hint); |
| 158 | 153 |
| 159 InstructionOperand* operand() const { return operand_; } | 154 InstructionOperand* operand() const { return operand_; } |
| 160 bool HasOperand() const { return operand_ != NULL; } | 155 bool HasOperand() const { return operand_ != NULL; } |
| 161 | 156 |
| 162 InstructionOperand* hint() const { return hint_; } | 157 InstructionOperand* hint() const { return hint_; } |
| 163 bool HasHint() const; | 158 bool HasHint() const; |
| 164 bool RequiresRegister() const; | 159 bool RequiresRegister() const; |
| 165 bool RegisterIsBeneficial() const; | 160 bool RegisterIsBeneficial() const; |
| 166 | 161 |
| 167 LifetimePosition pos() const { return pos_; } | 162 LifetimePosition pos() const { return pos_; } |
| 168 UsePosition* next() const { return next_; } | 163 UsePosition* next() const { return next_; } |
| 169 | 164 |
| 170 void set_next(UsePosition* next) { next_ = next; } | 165 void set_next(UsePosition* next) { next_ = next; } |
| 171 | 166 |
| 172 InstructionOperand* const operand_; | 167 InstructionOperand* const operand_; |
| 173 InstructionOperand* const hint_; | 168 InstructionOperand* const hint_; |
| 174 LifetimePosition const pos_; | 169 LifetimePosition const pos_; |
| 175 UsePosition* next_; | 170 UsePosition* next_; |
| 176 bool requires_reg_; | 171 bool requires_reg_ : 1; |
| 177 bool register_beneficial_; | 172 bool register_beneficial_ : 1; |
| 173 |
| 174 private: |
| 175 DISALLOW_COPY_AND_ASSIGN(UsePosition); |
| 178 }; | 176 }; |
| 179 | 177 |
| 178 |
| 180 // Representation of SSA values' live ranges as a collection of (continuous) | 179 // Representation of SSA values' live ranges as a collection of (continuous) |
| 181 // intervals over the instruction ordering. | 180 // intervals over the instruction ordering. |
| 182 class LiveRange : public ZoneObject { | 181 class LiveRange FINAL : public ZoneObject { |
| 183 public: | 182 public: |
| 184 static const int kInvalidAssignment = 0x7fffffff; | 183 static const int kInvalidAssignment = 0x7fffffff; |
| 185 | 184 |
| 186 LiveRange(int id, Zone* zone); | 185 LiveRange(int id, Zone* zone); |
| 187 | 186 |
| 188 UseInterval* first_interval() const { return first_interval_; } | 187 UseInterval* first_interval() const { return first_interval_; } |
| 189 UsePosition* first_pos() const { return first_pos_; } | 188 UsePosition* first_pos() const { return first_pos_; } |
| 190 LiveRange* parent() const { return parent_; } | 189 LiveRange* parent() const { return parent_; } |
| 191 LiveRange* TopLevel() { return (parent_ == NULL) ? this : parent_; } | 190 LiveRange* TopLevel() { return (parent_ == NULL) ? this : parent_; } |
| 192 LiveRange* next() const { return next_; } | 191 LiveRange* next() const { return next_; } |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 308 LiveRange* next_; | 307 LiveRange* next_; |
| 309 // This is used as a cache, it doesn't affect correctness. | 308 // This is used as a cache, it doesn't affect correctness. |
| 310 mutable UseInterval* current_interval_; | 309 mutable UseInterval* current_interval_; |
| 311 UsePosition* last_processed_use_; | 310 UsePosition* last_processed_use_; |
| 312 // This is used as a cache, it's invalid outside of BuildLiveRanges. | 311 // This is used as a cache, it's invalid outside of BuildLiveRanges. |
| 313 InstructionOperand* current_hint_operand_; | 312 InstructionOperand* current_hint_operand_; |
| 314 InstructionOperand* spill_operand_; | 313 InstructionOperand* spill_operand_; |
| 315 int spill_start_index_; | 314 int spill_start_index_; |
| 316 | 315 |
| 317 friend class RegisterAllocator; // Assigns to kind_. | 316 friend class RegisterAllocator; // Assigns to kind_. |
| 317 |
| 318 DISALLOW_COPY_AND_ASSIGN(LiveRange); |
| 318 }; | 319 }; |
| 319 | 320 |
| 320 | 321 |
| 321 class RegisterAllocator BASE_EMBEDDED { | 322 class RegisterAllocator BASE_EMBEDDED { |
| 322 public: | 323 public: |
| 323 // TODO(dcarney): remove info | |
| 324 explicit RegisterAllocator(Zone* local_zone, Frame* frame, | 324 explicit RegisterAllocator(Zone* local_zone, Frame* frame, |
| 325 CompilationInfo* info, InstructionSequence* code); | 325 InstructionSequence* code, |
| 326 | 326 const char* debug_name = nullptr); |
| 327 static void TraceAlloc(const char* msg, ...); | |
| 328 | |
| 329 // Checks whether the value of a given virtual register is a reference. | |
| 330 // TODO(titzer): rename this to IsReference. | |
| 331 bool HasTaggedValue(int virtual_register) const; | |
| 332 | |
| 333 // Returns the register kind required by the given virtual register. | |
| 334 RegisterKind RequiredRegisterKind(int virtual_register) const; | |
| 335 | 327 |
| 336 bool Allocate(PipelineStatistics* stats = NULL); | 328 bool Allocate(PipelineStatistics* stats = NULL); |
| 329 bool AllocationOk() { return allocation_ok_; } |
| 330 BitVector* assigned_registers() { return assigned_registers_; } |
| 331 BitVector* assigned_double_registers() { return assigned_double_registers_; } |
| 337 | 332 |
| 338 const ZoneList<LiveRange*>* live_ranges() const { return &live_ranges_; } | 333 const ZoneList<LiveRange*>* live_ranges() const { return &live_ranges_; } |
| 339 const Vector<LiveRange*>* fixed_live_ranges() const { | 334 const Vector<LiveRange*>* fixed_live_ranges() const { |
| 340 return &fixed_live_ranges_; | 335 return &fixed_live_ranges_; |
| 341 } | 336 } |
| 342 const Vector<LiveRange*>* fixed_double_live_ranges() const { | 337 const Vector<LiveRange*>* fixed_double_live_ranges() const { |
| 343 return &fixed_double_live_ranges_; | 338 return &fixed_double_live_ranges_; |
| 344 } | 339 } |
| 340 InstructionSequence* code() const { return code_; } |
| 345 | 341 |
| 346 CompilationInfo* info() const { return info_; } | 342 private: |
| 347 inline InstructionSequence* code() const { return code_; } | |
| 348 | |
| 349 // This zone is for datastructures only needed during register allocation. | |
| 350 inline Zone* zone() const { return zone_; } | |
| 351 | |
| 352 // This zone is for InstructionOperands and moves that live beyond register | |
| 353 // allocation. | |
| 354 inline Zone* code_zone() const { return code()->zone(); } | |
| 355 | |
| 356 int GetVirtualRegister() { | 343 int GetVirtualRegister() { |
| 357 int vreg = code()->NextVirtualRegister(); | 344 int vreg = code()->NextVirtualRegister(); |
| 358 if (vreg >= UnallocatedOperand::kMaxVirtualRegisters) { | 345 if (vreg >= UnallocatedOperand::kMaxVirtualRegisters) { |
| 359 allocation_ok_ = false; | 346 allocation_ok_ = false; |
| 360 // Maintain the invariant that we return something below the maximum. | 347 // Maintain the invariant that we return something below the maximum. |
| 361 return 0; | 348 return 0; |
| 362 } | 349 } |
| 363 return vreg; | 350 return vreg; |
| 364 } | 351 } |
| 365 | 352 |
| 366 bool AllocationOk() { return allocation_ok_; } | 353 // Checks whether the value of a given virtual register is a reference. |
| 354 // TODO(titzer): rename this to IsReference. |
| 355 bool HasTaggedValue(int virtual_register) const; |
| 356 |
| 357 // Returns the register kind required by the given virtual register. |
| 358 RegisterKind RequiredRegisterKind(int virtual_register) const; |
| 359 |
| 360 // This zone is for datastructures only needed during register allocation. |
| 361 Zone* zone() const { return zone_; } |
| 362 |
| 363 // This zone is for InstructionOperands and moves that live beyond register |
| 364 // allocation. |
| 365 Zone* code_zone() const { return code()->zone(); } |
| 367 | 366 |
| 368 #ifdef DEBUG | 367 #ifdef DEBUG |
| 369 void Verify() const; | 368 void Verify() const; |
| 370 #endif | 369 #endif |
| 371 | 370 |
| 372 BitVector* assigned_registers() { return assigned_registers_; } | |
| 373 BitVector* assigned_double_registers() { return assigned_double_registers_; } | |
| 374 | |
| 375 private: | |
| 376 void MeetRegisterConstraints(); | 371 void MeetRegisterConstraints(); |
| 377 void ResolvePhis(); | 372 void ResolvePhis(); |
| 378 void BuildLiveRanges(); | 373 void BuildLiveRanges(); |
| 379 void AllocateGeneralRegisters(); | 374 void AllocateGeneralRegisters(); |
| 380 void AllocateDoubleRegisters(); | 375 void AllocateDoubleRegisters(); |
| 381 void ConnectRanges(); | 376 void ConnectRanges(); |
| 382 void ResolveControlFlow(); | 377 void ResolveControlFlow(); |
| 383 void PopulatePointerMaps(); // TODO(titzer): rename to PopulateReferenceMaps. | 378 void PopulatePointerMaps(); // TODO(titzer): rename to PopulateReferenceMaps. |
| 384 void AllocateRegisters(); | 379 void AllocateRegisters(); |
| 385 bool CanEagerlyResolveControlFlow(const InstructionBlock* block) const; | 380 bool CanEagerlyResolveControlFlow(const InstructionBlock* block) const; |
| 386 inline bool SafePointsAreInOrder() const; | 381 bool SafePointsAreInOrder() const; |
| 387 | 382 |
| 388 // Liveness analysis support. | 383 // Liveness analysis support. |
| 389 void InitializeLivenessAnalysis(); | 384 void InitializeLivenessAnalysis(); |
| 390 BitVector* ComputeLiveOut(const InstructionBlock* block); | 385 BitVector* ComputeLiveOut(const InstructionBlock* block); |
| 391 void AddInitialIntervals(const InstructionBlock* block, BitVector* live_out); | 386 void AddInitialIntervals(const InstructionBlock* block, BitVector* live_out); |
| 392 bool IsOutputRegisterOf(Instruction* instr, int index); | 387 bool IsOutputRegisterOf(Instruction* instr, int index); |
| 393 bool IsOutputDoubleRegisterOf(Instruction* instr, int index); | 388 bool IsOutputDoubleRegisterOf(Instruction* instr, int index); |
| 394 void ProcessInstructions(const InstructionBlock* block, BitVector* live); | 389 void ProcessInstructions(const InstructionBlock* block, BitVector* live); |
| 395 void MeetRegisterConstraints(const InstructionBlock* block); | 390 void MeetRegisterConstraints(const InstructionBlock* block); |
| 396 void MeetConstraintsBetween(Instruction* first, Instruction* second, | 391 void MeetConstraintsBetween(Instruction* first, Instruction* second, |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 467 LifetimePosition FindOptimalSpillingPos(LiveRange* range, | 462 LifetimePosition FindOptimalSpillingPos(LiveRange* range, |
| 468 LifetimePosition pos); | 463 LifetimePosition pos); |
| 469 | 464 |
| 470 void Spill(LiveRange* range); | 465 void Spill(LiveRange* range); |
| 471 bool IsBlockBoundary(LifetimePosition pos); | 466 bool IsBlockBoundary(LifetimePosition pos); |
| 472 | 467 |
| 473 // Helper methods for resolving control flow. | 468 // Helper methods for resolving control flow. |
| 474 void ResolveControlFlow(LiveRange* range, const InstructionBlock* block, | 469 void ResolveControlFlow(LiveRange* range, const InstructionBlock* block, |
| 475 const InstructionBlock* pred); | 470 const InstructionBlock* pred); |
| 476 | 471 |
| 477 inline void SetLiveRangeAssignedRegister(LiveRange* range, int reg); | 472 void SetLiveRangeAssignedRegister(LiveRange* range, int reg); |
| 478 | 473 |
| 479 // Return parallel move that should be used to connect ranges split at the | 474 // Return parallel move that should be used to connect ranges split at the |
| 480 // given position. | 475 // given position. |
| 481 ParallelMove* GetConnectingParallelMove(LifetimePosition pos); | 476 ParallelMove* GetConnectingParallelMove(LifetimePosition pos); |
| 482 | 477 |
| 483 // Return the block which contains give lifetime position. | 478 // Return the block which contains give lifetime position. |
| 484 const InstructionBlock* GetInstructionBlock(LifetimePosition pos); | 479 const InstructionBlock* GetInstructionBlock(LifetimePosition pos); |
| 485 | 480 |
| 486 // Helper methods for the fixed registers. | 481 // Helper methods for the fixed registers. |
| 487 int RegisterCount() const; | 482 int RegisterCount() const; |
| 488 static int FixedLiveRangeID(int index) { return -index - 1; } | 483 static int FixedLiveRangeID(int index) { return -index - 1; } |
| 489 static int FixedDoubleLiveRangeID(int index); | 484 static int FixedDoubleLiveRangeID(int index); |
| 490 LiveRange* FixedLiveRangeFor(int index); | 485 LiveRange* FixedLiveRangeFor(int index); |
| 491 LiveRange* FixedDoubleLiveRangeFor(int index); | 486 LiveRange* FixedDoubleLiveRangeFor(int index); |
| 492 LiveRange* LiveRangeFor(int index); | 487 LiveRange* LiveRangeFor(int index); |
| 493 GapInstruction* GetLastGap(const InstructionBlock* block); | 488 GapInstruction* GetLastGap(const InstructionBlock* block); |
| 494 | 489 |
| 495 const char* RegisterName(int allocation_index); | 490 const char* RegisterName(int allocation_index); |
| 496 | 491 |
| 497 inline Instruction* InstructionAt(int index) { | 492 Instruction* InstructionAt(int index) { return code()->InstructionAt(index); } |
| 498 return code()->InstructionAt(index); | |
| 499 } | |
| 500 | 493 |
| 501 Frame* frame() const { return frame_; } | 494 Frame* frame() const { return frame_; } |
| 495 const char* debug_name() const { return debug_name_; } |
| 502 | 496 |
| 503 Zone* const zone_; | 497 Zone* const zone_; |
| 504 Frame* const frame_; | 498 Frame* const frame_; |
| 505 CompilationInfo* const info_; | |
| 506 InstructionSequence* const code_; | 499 InstructionSequence* const code_; |
| 500 const char* const debug_name_; |
| 507 | 501 |
| 508 // During liveness analysis keep a mapping from block id to live_in sets | 502 // During liveness analysis keep a mapping from block id to live_in sets |
| 509 // for blocks already analyzed. | 503 // for blocks already analyzed. |
| 510 ZoneList<BitVector*> live_in_sets_; | 504 ZoneList<BitVector*> live_in_sets_; |
| 511 | 505 |
| 512 // Liveness analysis results. | 506 // Liveness analysis results. |
| 513 ZoneList<LiveRange*> live_ranges_; | 507 ZoneList<LiveRange*> live_ranges_; |
| 514 | 508 |
| 515 // Lists of live ranges | 509 // Lists of live ranges |
| 516 EmbeddedVector<LiveRange*, Register::kMaxNumAllocatableRegisters> | 510 EmbeddedVector<LiveRange*, Register::kMaxNumAllocatableRegisters> |
| (...skipping 19 matching lines...) Expand all Loading... |
| 536 #endif | 530 #endif |
| 537 | 531 |
| 538 DISALLOW_COPY_AND_ASSIGN(RegisterAllocator); | 532 DISALLOW_COPY_AND_ASSIGN(RegisterAllocator); |
| 539 }; | 533 }; |
| 540 | 534 |
| 541 } | 535 } |
| 542 } | 536 } |
| 543 } // namespace v8::internal::compiler | 537 } // namespace v8::internal::compiler |
| 544 | 538 |
| 545 #endif // V8_REGISTER_ALLOCATOR_H_ | 539 #endif // V8_REGISTER_ALLOCATOR_H_ |
| OLD | NEW |