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/compiler/instruction.h" | 8 #include "src/compiler/instruction.h" |
9 #include "src/zone-containers.h" | 9 #include "src/zone-containers.h" |
10 | 10 |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
53 int ToInstructionIndex() const { | 53 int ToInstructionIndex() const { |
54 DCHECK(IsValid()); | 54 DCHECK(IsValid()); |
55 return value_ / kStep; | 55 return value_ / kStep; |
56 } | 56 } |
57 | 57 |
58 // Returns true if this lifetime position corresponds to a START value | 58 // Returns true if this lifetime position corresponds to a START value |
59 bool IsStart() const { return (value_ & (kHalfStep - 1)) == 0; } | 59 bool IsStart() const { return (value_ & (kHalfStep - 1)) == 0; } |
60 // Returns true if this lifetime position corresponds to a gap START value | 60 // Returns true if this lifetime position corresponds to a gap START value |
61 bool IsFullStart() const { return (value_ & (kStep - 1)) == 0; } | 61 bool IsFullStart() const { return (value_ & (kStep - 1)) == 0; } |
62 | 62 |
63 bool IsGapPosition() { return (value_ & 0x2) == 0; } | 63 bool IsGapPosition() const { return (value_ & 0x2) == 0; } |
64 bool IsInstructionPosition() { return !IsGapPosition(); } | 64 bool IsInstructionPosition() const { return !IsGapPosition(); } |
65 | 65 |
66 // Returns the lifetime position for the current START. | 66 // Returns the lifetime position for the current START. |
67 LifetimePosition Start() const { | 67 LifetimePosition Start() const { |
68 DCHECK(IsValid()); | 68 DCHECK(IsValid()); |
69 return LifetimePosition(value_ & ~(kHalfStep - 1)); | 69 return LifetimePosition(value_ & ~(kHalfStep - 1)); |
70 } | 70 } |
71 | 71 |
72 // Returns the lifetime position for the current gap START. | 72 // Returns the lifetime position for the current gap START. |
73 LifetimePosition FullStart() const { | 73 LifetimePosition FullStart() const { |
74 DCHECK(IsValid()); | 74 DCHECK(IsValid()); |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
280 LiveRange* TopLevel() { return (parent_ == nullptr) ? this : parent_; } | 280 LiveRange* TopLevel() { return (parent_ == nullptr) ? this : parent_; } |
281 const LiveRange* TopLevel() const { | 281 const LiveRange* TopLevel() const { |
282 return (parent_ == nullptr) ? this : parent_; | 282 return (parent_ == nullptr) ? this : parent_; |
283 } | 283 } |
284 LiveRange* next() const { return next_; } | 284 LiveRange* next() const { return next_; } |
285 bool IsChild() const { return parent() != nullptr; } | 285 bool IsChild() const { return parent() != nullptr; } |
286 int id() const { return id_; } | 286 int id() const { return id_; } |
287 bool IsFixed() const { return id_ < 0; } | 287 bool IsFixed() const { return id_ < 0; } |
288 bool IsEmpty() const { return first_interval() == nullptr; } | 288 bool IsEmpty() const { return first_interval() == nullptr; } |
289 InstructionOperand GetAssignedOperand() const; | 289 InstructionOperand GetAssignedOperand() const; |
290 int assigned_register() const { return assigned_register_; } | |
291 int spill_start_index() const { return spill_start_index_; } | 290 int spill_start_index() const { return spill_start_index_; } |
| 291 |
| 292 int assigned_register() const { return AssignedRegisterField::decode(bits_); } |
| 293 bool HasRegisterAssigned() const { |
| 294 return assigned_register() != kUnassignedRegister; |
| 295 } |
292 void set_assigned_register(int reg); | 296 void set_assigned_register(int reg); |
293 void UnsetAssignedRegister(); | 297 void UnsetAssignedRegister(); |
294 void MakeSpilled(); | 298 |
295 bool is_phi() const { return is_phi_; } | 299 bool spilled() const { return SpilledField::decode(bits_); } |
296 void set_is_phi(bool is_phi) { is_phi_ = is_phi; } | 300 void Spill(); |
297 bool is_non_loop_phi() const { return is_non_loop_phi_; } | 301 |
298 void set_is_non_loop_phi(bool is_non_loop_phi) { | 302 RegisterKind kind() const { return RegisterKindField::decode(bits_); } |
299 is_non_loop_phi_ = is_non_loop_phi; | 303 void set_kind(RegisterKind kind) { |
| 304 bits_ = RegisterKindField::update(bits_, kind); |
300 } | 305 } |
301 bool has_slot_use() const { return has_slot_use_; } | 306 |
302 void set_has_slot_use(bool has_slot_use) { has_slot_use_ = has_slot_use; } | 307 // Correct only for parent. |
| 308 bool is_phi() const { return IsPhiField::decode(bits_); } |
| 309 void set_is_phi(bool value) { bits_ = IsPhiField::update(bits_, value); } |
| 310 |
| 311 // Correct only for parent. |
| 312 bool is_non_loop_phi() const { return IsNonLoopPhiField::decode(bits_); } |
| 313 void set_is_non_loop_phi(bool value) { |
| 314 bits_ = IsNonLoopPhiField::update(bits_, value); |
| 315 } |
| 316 |
| 317 // Relevant only for parent. |
| 318 bool has_slot_use() const { return HasSlotUseField::decode(bits_); } |
| 319 void set_has_slot_use(bool value) { |
| 320 bits_ = HasSlotUseField::update(bits_, value); |
| 321 } |
303 | 322 |
304 // Returns use position in this live range that follows both start | 323 // Returns use position in this live range that follows both start |
305 // and last processed use position. | 324 // and last processed use position. |
306 UsePosition* NextUsePosition(LifetimePosition start) const; | 325 UsePosition* NextUsePosition(LifetimePosition start) const; |
307 | 326 |
308 // Returns use position for which register is required in this live | 327 // Returns use position for which register is required in this live |
309 // range and which follows both start and last processed use position | 328 // range and which follows both start and last processed use position |
310 UsePosition* NextRegisterPosition(LifetimePosition start) const; | 329 UsePosition* NextRegisterPosition(LifetimePosition start) const; |
311 | 330 |
312 // Returns use position for which register is beneficial in this live | 331 // Returns use position for which register is beneficial in this live |
313 // range and which follows both start and last processed use position | 332 // range and which follows both start and last processed use position |
314 UsePosition* NextUsePositionRegisterIsBeneficial( | 333 UsePosition* NextUsePositionRegisterIsBeneficial( |
315 LifetimePosition start) const; | 334 LifetimePosition start) const; |
316 | 335 |
317 // Returns use position for which register is beneficial in this live | 336 // Returns use position for which register is beneficial in this live |
318 // range and which precedes start. | 337 // range and which precedes start. |
319 UsePosition* PreviousUsePositionRegisterIsBeneficial( | 338 UsePosition* PreviousUsePositionRegisterIsBeneficial( |
320 LifetimePosition start) const; | 339 LifetimePosition start) const; |
321 | 340 |
322 // Can this live range be spilled at this position. | 341 // Can this live range be spilled at this position. |
323 bool CanBeSpilled(LifetimePosition pos) const; | 342 bool CanBeSpilled(LifetimePosition pos) const; |
324 | 343 |
325 // Split this live range at the given position which must follow the start of | 344 // Split this live range at the given position which must follow the start of |
326 // the range. | 345 // the range. |
327 // All uses following the given position will be moved from this | 346 // All uses following the given position will be moved from this |
328 // live range to the result live range. | 347 // live range to the result live range. |
329 void SplitAt(LifetimePosition position, LiveRange* result, Zone* zone); | 348 void SplitAt(LifetimePosition position, LiveRange* result, Zone* zone); |
330 | 349 |
331 RegisterKind Kind() const { return kind_; } | |
332 bool HasRegisterAssigned() const { | |
333 return assigned_register_ != kUnassignedRegister; | |
334 } | |
335 bool IsSpilled() const { return spilled_; } | |
336 | |
337 // Returns nullptr when no register is hinted, otherwise sets register_index. | 350 // Returns nullptr when no register is hinted, otherwise sets register_index. |
338 UsePosition* FirstHintPosition(int* register_index) const; | 351 UsePosition* FirstHintPosition(int* register_index) const; |
339 UsePosition* FirstHintPosition() const { | 352 UsePosition* FirstHintPosition() const { |
340 int register_index; | 353 int register_index; |
341 return FirstHintPosition(®ister_index); | 354 return FirstHintPosition(®ister_index); |
342 } | 355 } |
343 | 356 |
344 UsePosition* current_hint_position() const { | 357 UsePosition* current_hint_position() const { |
345 DCHECK(current_hint_position_ == FirstHintPosition()); | 358 DCHECK(current_hint_position_ == FirstHintPosition()); |
346 return current_hint_position_; | 359 return current_hint_position_; |
347 } | 360 } |
348 | 361 |
349 LifetimePosition Start() const { | 362 LifetimePosition Start() const { |
350 DCHECK(!IsEmpty()); | 363 DCHECK(!IsEmpty()); |
351 return first_interval()->start(); | 364 return first_interval()->start(); |
352 } | 365 } |
353 | 366 |
354 LifetimePosition End() const { | 367 LifetimePosition End() const { |
355 DCHECK(!IsEmpty()); | 368 DCHECK(!IsEmpty()); |
356 return last_interval_->end(); | 369 return last_interval_->end(); |
357 } | 370 } |
358 | 371 |
359 enum class SpillType { kNoSpillType, kSpillOperand, kSpillRange }; | 372 enum class SpillType { kNoSpillType, kSpillOperand, kSpillRange }; |
360 SpillType spill_type() const { return spill_type_; } | 373 SpillType spill_type() const { return SpillTypeField::decode(bits_); } |
361 InstructionOperand* GetSpillOperand() const { | 374 InstructionOperand* GetSpillOperand() const { |
362 DCHECK(spill_type_ == SpillType::kSpillOperand); | 375 DCHECK(spill_type() == SpillType::kSpillOperand); |
363 return spill_operand_; | 376 return spill_operand_; |
364 } | 377 } |
365 SpillRange* GetSpillRange() const { | 378 SpillRange* GetSpillRange() const { |
366 DCHECK(spill_type_ == SpillType::kSpillRange); | 379 DCHECK(spill_type() == SpillType::kSpillRange); |
367 return spill_range_; | 380 return spill_range_; |
368 } | 381 } |
369 bool HasNoSpillType() const { return spill_type_ == SpillType::kNoSpillType; } | 382 bool HasNoSpillType() const { |
| 383 return spill_type() == SpillType::kNoSpillType; |
| 384 } |
370 bool HasSpillOperand() const { | 385 bool HasSpillOperand() const { |
371 return spill_type_ == SpillType::kSpillOperand; | 386 return spill_type() == SpillType::kSpillOperand; |
372 } | 387 } |
373 bool HasSpillRange() const { return spill_type_ == SpillType::kSpillRange; } | 388 bool HasSpillRange() const { return spill_type() == SpillType::kSpillRange; } |
374 | 389 |
375 void SpillAtDefinition(Zone* zone, int gap_index, | 390 void SpillAtDefinition(Zone* zone, int gap_index, |
376 InstructionOperand* operand); | 391 InstructionOperand* operand); |
377 void SetSpillOperand(InstructionOperand* operand); | 392 void SetSpillOperand(InstructionOperand* operand); |
378 void SetSpillRange(SpillRange* spill_range); | 393 void SetSpillRange(SpillRange* spill_range); |
379 void CommitSpillOperand(AllocatedOperand* operand); | 394 void CommitSpillOperand(AllocatedOperand* operand); |
380 void CommitSpillsAtDefinition(InstructionSequence* sequence, | 395 void CommitSpillsAtDefinition(InstructionSequence* sequence, |
381 InstructionOperand* operand, | 396 InstructionOperand* operand, |
382 bool might_be_duplicated); | 397 bool might_be_duplicated); |
383 | 398 |
(...skipping 14 matching lines...) Expand all Loading... |
398 // Shorten the most recently added interval by setting a new start. | 413 // Shorten the most recently added interval by setting a new start. |
399 void ShortenTo(LifetimePosition start); | 414 void ShortenTo(LifetimePosition start); |
400 | 415 |
401 void Verify() const; | 416 void Verify() const; |
402 | 417 |
403 void ConvertUsesToOperand(const InstructionOperand& op, | 418 void ConvertUsesToOperand(const InstructionOperand& op, |
404 InstructionOperand* spill_op); | 419 InstructionOperand* spill_op); |
405 void SetUseHints(int register_index); | 420 void SetUseHints(int register_index); |
406 void UnsetUseHints() { SetUseHints(kUnassignedRegister); } | 421 void UnsetUseHints() { SetUseHints(kUnassignedRegister); } |
407 | 422 |
408 void set_kind(RegisterKind kind) { kind_ = kind; } | |
409 | |
410 private: | 423 private: |
411 struct SpillAtDefinitionList; | 424 struct SpillAtDefinitionList; |
412 | 425 |
| 426 void set_spill_type(SpillType value) { |
| 427 bits_ = SpillTypeField::update(bits_, value); |
| 428 } |
| 429 |
| 430 void set_spilled(bool value) { bits_ = SpilledField::update(bits_, value); } |
| 431 |
413 UseInterval* FirstSearchIntervalForPosition(LifetimePosition position) const; | 432 UseInterval* FirstSearchIntervalForPosition(LifetimePosition position) const; |
414 void AdvanceLastProcessedMarker(UseInterval* to_start_of, | 433 void AdvanceLastProcessedMarker(UseInterval* to_start_of, |
415 LifetimePosition but_not_past) const; | 434 LifetimePosition but_not_past) const; |
416 | 435 |
417 // TODO(dcarney): pack this structure better. | 436 typedef BitField<bool, 0, 1> SpilledField; |
| 437 typedef BitField<bool, 1, 1> HasSlotUseField; |
| 438 typedef BitField<bool, 2, 1> IsPhiField; |
| 439 typedef BitField<bool, 3, 1> IsNonLoopPhiField; |
| 440 typedef BitField<RegisterKind, 4, 2> RegisterKindField; |
| 441 typedef BitField<SpillType, 6, 2> SpillTypeField; |
| 442 typedef BitField<int32_t, 8, 6> AssignedRegisterField; |
| 443 |
418 int id_; | 444 int id_; |
419 bool spilled_ : 1; | 445 int spill_start_index_; |
420 bool has_slot_use_ : 1; // Relevant only for parent. | 446 uint32_t bits_; |
421 bool is_phi_ : 1; // Correct only for parent. | |
422 bool is_non_loop_phi_ : 1; // Correct only for parent. | |
423 RegisterKind kind_; | |
424 int assigned_register_; | |
425 UseInterval* last_interval_; | 447 UseInterval* last_interval_; |
426 UseInterval* first_interval_; | 448 UseInterval* first_interval_; |
427 UsePosition* first_pos_; | 449 UsePosition* first_pos_; |
428 LiveRange* parent_; | 450 LiveRange* parent_; |
429 LiveRange* next_; | 451 LiveRange* next_; |
| 452 union { |
| 453 // Correct value determined by spill_type() |
| 454 InstructionOperand* spill_operand_; |
| 455 SpillRange* spill_range_; |
| 456 }; |
| 457 SpillAtDefinitionList* spills_at_definition_; |
430 // This is used as a cache, it doesn't affect correctness. | 458 // This is used as a cache, it doesn't affect correctness. |
431 mutable UseInterval* current_interval_; | 459 mutable UseInterval* current_interval_; |
432 // This is used as a cache, it doesn't affect correctness. | 460 // This is used as a cache, it doesn't affect correctness. |
433 mutable UsePosition* last_processed_use_; | 461 mutable UsePosition* last_processed_use_; |
434 // This is used as a cache, it's invalid outside of BuildLiveRanges. | 462 // This is used as a cache, it's invalid outside of BuildLiveRanges. |
435 mutable UsePosition* current_hint_position_; | 463 mutable UsePosition* current_hint_position_; |
436 int spill_start_index_; | |
437 SpillType spill_type_; | |
438 union { | |
439 InstructionOperand* spill_operand_; | |
440 SpillRange* spill_range_; | |
441 }; | |
442 SpillAtDefinitionList* spills_at_definition_; | |
443 | 464 |
444 DISALLOW_COPY_AND_ASSIGN(LiveRange); | 465 DISALLOW_COPY_AND_ASSIGN(LiveRange); |
445 }; | 466 }; |
446 | 467 |
447 | 468 |
448 class SpillRange final : public ZoneObject { | 469 class SpillRange final : public ZoneObject { |
449 public: | 470 public: |
450 SpillRange(LiveRange* range, Zone* zone); | 471 SpillRange(LiveRange* range, Zone* zone); |
451 | 472 |
452 UseInterval* interval() const { return use_interval_; } | 473 UseInterval* interval() const { return use_interval_; } |
453 RegisterKind Kind() const { return live_ranges_[0]->Kind(); } | 474 RegisterKind kind() const { return live_ranges_[0]->kind(); } |
454 bool IsEmpty() const { return live_ranges_.empty(); } | 475 bool IsEmpty() const { return live_ranges_.empty(); } |
455 bool TryMerge(SpillRange* other); | 476 bool TryMerge(SpillRange* other); |
456 void SetOperand(AllocatedOperand* op); | 477 void SetOperand(AllocatedOperand* op); |
457 | 478 |
458 private: | 479 private: |
459 LifetimePosition End() const { return end_position_; } | 480 LifetimePosition End() const { return end_position_; } |
460 ZoneVector<LiveRange*>& live_ranges() { return live_ranges_; } | 481 ZoneVector<LiveRange*>& live_ranges() { return live_ranges_; } |
461 bool IsIntersectingWith(SpillRange* other) const; | 482 bool IsIntersectingWith(SpillRange* other) const; |
462 // Merge intervals, making sure the use intervals are sorted | 483 // Merge intervals, making sure the use intervals are sorted |
463 void MergeDisjointIntervals(UseInterval* other); | 484 void MergeDisjointIntervals(UseInterval* other); |
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
886 RegisterAllocationData* const data_; | 907 RegisterAllocationData* const data_; |
887 | 908 |
888 DISALLOW_COPY_AND_ASSIGN(LiveRangeConnector); | 909 DISALLOW_COPY_AND_ASSIGN(LiveRangeConnector); |
889 }; | 910 }; |
890 | 911 |
891 } // namespace compiler | 912 } // namespace compiler |
892 } // namespace internal | 913 } // namespace internal |
893 } // namespace v8 | 914 } // namespace v8 |
894 | 915 |
895 #endif // V8_REGISTER_ALLOCATOR_H_ | 916 #endif // V8_REGISTER_ALLOCATOR_H_ |
OLD | NEW |