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