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 |