Chromium Code Reviews| 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 322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 333 | 333 |
| 334 // Add a new interval or a new use position to this live range. | 334 // Add a new interval or a new use position to this live range. |
| 335 void EnsureInterval(LifetimePosition start, LifetimePosition end, Zone* zone); | 335 void EnsureInterval(LifetimePosition start, LifetimePosition end, Zone* zone); |
| 336 void AddUseInterval(LifetimePosition start, LifetimePosition end, Zone* zone); | 336 void AddUseInterval(LifetimePosition start, LifetimePosition end, Zone* zone); |
| 337 void AddUsePosition(LifetimePosition pos, InstructionOperand* operand, | 337 void AddUsePosition(LifetimePosition pos, InstructionOperand* operand, |
| 338 InstructionOperand* hint, Zone* zone); | 338 InstructionOperand* hint, Zone* zone); |
| 339 | 339 |
| 340 // Shorten the most recently added interval by setting a new start. | 340 // Shorten the most recently added interval by setting a new start. |
| 341 void ShortenTo(LifetimePosition start); | 341 void ShortenTo(LifetimePosition start); |
| 342 | 342 |
| 343 #ifdef DEBUG | |
| 344 // True if target overlaps an existing interval. | 343 // True if target overlaps an existing interval. |
| 345 bool HasOverlap(UseInterval* target) const; | 344 bool HasOverlap(UseInterval* target) const; |
| 346 void Verify() const; | 345 void Verify() const; |
| 347 #endif | 346 |
| 347 void ConvertUsesToOperand(const InstructionOperand& op, | |
| 348 InstructionOperand* spill_op); | |
| 349 | |
| 350 void set_kind(RegisterKind kind) { kind_ = kind; } | |
| 348 | 351 |
| 349 private: | 352 private: |
| 350 struct SpillAtDefinitionList; | 353 struct SpillAtDefinitionList; |
| 351 | 354 |
| 352 void ConvertUsesToOperand(const InstructionOperand& op, | |
| 353 InstructionOperand* spill_op); | |
| 354 UseInterval* FirstSearchIntervalForPosition(LifetimePosition position) const; | 355 UseInterval* FirstSearchIntervalForPosition(LifetimePosition position) const; |
| 355 void AdvanceLastProcessedMarker(UseInterval* to_start_of, | 356 void AdvanceLastProcessedMarker(UseInterval* to_start_of, |
| 356 LifetimePosition but_not_past) const; | 357 LifetimePosition but_not_past) const; |
| 357 | 358 |
| 358 // TODO(dcarney): pack this structure better. | 359 // TODO(dcarney): pack this structure better. |
| 359 int id_; | 360 int id_; |
| 360 bool spilled_ : 1; | 361 bool spilled_ : 1; |
| 361 bool has_slot_use_ : 1; // Relevant only for parent. | 362 bool has_slot_use_ : 1; // Relevant only for parent. |
| 362 bool is_phi_ : 1; | 363 bool is_phi_ : 1; |
| 363 bool is_non_loop_phi_ : 1; | 364 bool is_non_loop_phi_ : 1; |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 374 // This is used as a cache, it's invalid outside of BuildLiveRanges. | 375 // This is used as a cache, it's invalid outside of BuildLiveRanges. |
| 375 InstructionOperand* current_hint_operand_; | 376 InstructionOperand* current_hint_operand_; |
| 376 int spill_start_index_; | 377 int spill_start_index_; |
| 377 SpillType spill_type_; | 378 SpillType spill_type_; |
| 378 union { | 379 union { |
| 379 InstructionOperand* spill_operand_; | 380 InstructionOperand* spill_operand_; |
| 380 SpillRange* spill_range_; | 381 SpillRange* spill_range_; |
| 381 }; | 382 }; |
| 382 SpillAtDefinitionList* spills_at_definition_; | 383 SpillAtDefinitionList* spills_at_definition_; |
| 383 | 384 |
| 384 friend class RegisterAllocator; // Assigns to kind_. | |
| 385 | |
| 386 DISALLOW_COPY_AND_ASSIGN(LiveRange); | 385 DISALLOW_COPY_AND_ASSIGN(LiveRange); |
| 387 }; | 386 }; |
| 388 | 387 |
| 389 | 388 |
| 390 class SpillRange FINAL : public ZoneObject { | 389 class SpillRange FINAL : public ZoneObject { |
| 391 public: | 390 public: |
| 392 SpillRange(LiveRange* range, Zone* zone); | 391 SpillRange(LiveRange* range, Zone* zone); |
| 393 | 392 |
| 394 UseInterval* interval() const { return use_interval_; } | 393 UseInterval* interval() const { return use_interval_; } |
| 395 RegisterKind Kind() const { return live_ranges_[0]->Kind(); } | 394 RegisterKind Kind() const { return live_ranges_[0]->Kind(); } |
| 396 bool IsEmpty() const { return live_ranges_.empty(); } | 395 bool IsEmpty() const { return live_ranges_.empty(); } |
| 397 bool TryMerge(SpillRange* other); | 396 bool TryMerge(SpillRange* other); |
| 398 void SetOperand(AllocatedOperand* op); | 397 void SetOperand(AllocatedOperand* op); |
| 399 | 398 |
| 400 private: | 399 private: |
| 401 LifetimePosition End() const { return end_position_; } | 400 LifetimePosition End() const { return end_position_; } |
| 402 ZoneVector<LiveRange*>& live_ranges() { return live_ranges_; } | 401 ZoneVector<LiveRange*>& live_ranges() { return live_ranges_; } |
| 403 bool IsIntersectingWith(SpillRange* other) const; | 402 bool IsIntersectingWith(SpillRange* other) const; |
| 404 // Merge intervals, making sure the use intervals are sorted | 403 // Merge intervals, making sure the use intervals are sorted |
| 405 void MergeDisjointIntervals(UseInterval* other); | 404 void MergeDisjointIntervals(UseInterval* other); |
| 406 | 405 |
| 407 ZoneVector<LiveRange*> live_ranges_; | 406 ZoneVector<LiveRange*> live_ranges_; |
| 408 UseInterval* use_interval_; | 407 UseInterval* use_interval_; |
| 409 LifetimePosition end_position_; | 408 LifetimePosition end_position_; |
| 410 | 409 |
| 411 DISALLOW_COPY_AND_ASSIGN(SpillRange); | 410 DISALLOW_COPY_AND_ASSIGN(SpillRange); |
| 412 }; | 411 }; |
| 413 | 412 |
| 414 | 413 |
| 415 class RegisterAllocator FINAL : public ZoneObject { | 414 class LiveRangeBuilder FINAL : public ZoneObject { |
| 416 public: | 415 public: |
| 417 explicit RegisterAllocator(const RegisterConfiguration* config, | 416 class PhiMapValue : public ZoneObject { |
| 418 Zone* local_zone, Frame* frame, | 417 public: |
| 419 InstructionSequence* code, | 418 PhiMapValue(PhiInstruction* phi, const InstructionBlock* block, Zone* zone) |
| 420 const char* debug_name = nullptr); | 419 : phi(phi), block(block), incoming_moves(zone) { |
| 420 incoming_moves.reserve(phi->operands().size()); | |
| 421 } | |
| 422 PhiInstruction* const phi; | |
| 423 const InstructionBlock* const block; | |
| 424 ZoneVector<MoveOperands*> incoming_moves; | |
| 425 }; | |
| 426 typedef ZoneMap<int, PhiMapValue*> PhiMap; | |
| 421 | 427 |
| 422 const ZoneVector<LiveRange*>& live_ranges() const { return live_ranges_; } | 428 LiveRangeBuilder(const RegisterConfiguration* config, Zone* local_zone, |
| 423 const ZoneVector<LiveRange*>& fixed_live_ranges() const { | 429 Frame* frame, InstructionSequence* code, |
| 424 return fixed_live_ranges_; | 430 const char* debug_name = nullptr); |
| 425 } | |
| 426 const ZoneVector<LiveRange*>& fixed_double_live_ranges() const { | |
| 427 return fixed_double_live_ranges_; | |
| 428 } | |
| 429 InstructionSequence* code() const { return code_; } | |
| 430 // This zone is for datastructures only needed during register allocation. | |
| 431 Zone* local_zone() const { return local_zone_; } | |
| 432 | 431 |
| 433 // Phase 1 : insert moves to account for fixed register operands. | 432 // Phase 1 : insert moves to account for fixed register operands. |
| 434 void MeetRegisterConstraints(); | 433 void MeetRegisterConstraints(); |
| 435 | 434 |
| 436 // Phase 2: deconstruct SSA by inserting moves in successors and the headers | 435 // Phase 2: deconstruct SSA by inserting moves in successors and the headers |
| 437 // of blocks containing phis. | 436 // of blocks containing phis. |
| 438 void ResolvePhis(); | 437 void ResolvePhis(); |
| 439 | 438 |
| 440 // Phase 3: compute liveness of all virtual register. | 439 // Phase 3: compute liveness of all virtual register. |
| 441 void BuildLiveRanges(); | 440 void BuildLiveRanges(); |
| 442 bool ExistsUseWithoutDefinition(); | 441 bool ExistsUseWithoutDefinition(); |
| 443 | 442 |
| 444 // Phase 4: compute register assignments. | 443 const ZoneVector<LiveRange*>& live_ranges() const { return live_ranges_; } |
| 445 void AllocateGeneralRegisters(); | 444 ZoneVector<LiveRange*>& live_ranges() { return live_ranges_; } |
| 446 void AllocateDoubleRegisters(); | 445 const ZoneVector<LiveRange*>& fixed_live_ranges() const { |
| 447 | 446 return fixed_live_ranges_; |
| 448 // Phase 5: assign spill splots. | 447 } |
| 449 void AssignSpillSlots(); | 448 ZoneVector<LiveRange*>& fixed_live_ranges() { return fixed_live_ranges_; } |
| 450 | 449 ZoneVector<LiveRange*>& fixed_double_live_ranges() { |
| 451 // Phase 6: commit assignment. | 450 return fixed_double_live_ranges_; |
| 452 void CommitAssignment(); | 451 } |
| 453 | 452 const ZoneVector<LiveRange*>& fixed_double_live_ranges() const { |
| 454 // Phase 7: compute values for pointer maps. | 453 return fixed_double_live_ranges_; |
| 455 void PopulateReferenceMaps(); | 454 } |
| 456 | 455 const ZoneVector<BitVector*>& live_in_sets() const { return live_in_sets_; } |
| 457 // Phase 8: reconnect split ranges with moves. | 456 ZoneVector<SpillRange*>& spill_ranges() { return spill_ranges_; } |
| 458 void ConnectRanges(); | 457 const ZoneVector<SpillRange*>& spill_ranges() const { return spill_ranges_; } |
| 459 | 458 InstructionSequence* code() const { return code_; } |
| 460 // Phase 9: insert moves to connect ranges across basic blocks. | 459 // This zone is for datastructures only needed during register allocation |
| 461 void ResolveControlFlow(); | 460 // phases. |
| 462 | 461 Zone* local_zone() const { return local_zone_; } |
| 463 private: | |
| 464 int GetVirtualRegister() { return code()->NextVirtualRegister(); } | |
| 465 | |
| 466 // Checks whether the value of a given virtual register is a reference. | |
| 467 // TODO(titzer): rename this to IsReference. | |
| 468 bool HasTaggedValue(int virtual_register) const; | |
| 469 | |
| 470 // Returns the register kind required by the given virtual register. | |
| 471 RegisterKind RequiredRegisterKind(int virtual_register) const; | |
| 472 | |
| 473 // Creates a new live range. | |
| 474 LiveRange* NewLiveRange(int index); | |
| 475 | |
| 476 // This zone is for InstructionOperands and moves that live beyond register | 462 // This zone is for InstructionOperands and moves that live beyond register |
| 477 // allocation. | 463 // allocation. |
| 478 Zone* code_zone() const { return code()->zone(); } | 464 Zone* code_zone() const { return code()->zone(); } |
| 465 const PhiMap& phi_map() const { return phi_map_; } | |
| 466 PhiMap& phi_map() { return phi_map_; } | |
| 467 Frame* frame() const { return frame_; } | |
| 468 const char* debug_name() const { return debug_name_; } | |
| 469 const RegisterConfiguration* config() const { return config_; } | |
| 479 | 470 |
| 480 BitVector* assigned_registers() { return assigned_registers_; } | 471 void SetLiveRangeAssignedRegister(LiveRange* range, int reg); |
| 481 BitVector* assigned_double_registers() { return assigned_double_registers_; } | 472 LiveRange* LiveRangeFor(int index); |
| 473 Instruction* InstructionAt(int index) { return code()->InstructionAt(index); } | |
| 482 | 474 |
| 483 #ifdef DEBUG | 475 void AssignPhiInput(LiveRange* range, const InstructionOperand& assignment); |
| 476 SpillRange* AssignSpillRangeToLiveRange(LiveRange* range); | |
| 477 | |
| 478 MoveOperands* AddGapMove(int index, Instruction::GapPosition position, | |
| 479 const InstructionOperand& from, | |
| 480 const InstructionOperand& to); | |
| 481 | |
| 482 bool IsBlockBoundary(LifetimePosition pos); | |
| 483 | |
| 484 const InstructionBlock* GetInstructionBlock(LifetimePosition pos) const { | |
| 485 return code()->GetInstructionBlock(pos.ToInstructionIndex()); | |
| 486 } | |
| 487 | |
| 484 void Verify() const; | 488 void Verify() const; |
| 485 #endif | |
| 486 | 489 |
| 487 void AllocateRegisters(); | 490 bool IsReference(int virtual_register) const { |
| 488 bool CanEagerlyResolveControlFlow(const InstructionBlock* block) const; | 491 return code()->IsReference(virtual_register); |
| 489 bool SafePointsAreInOrder() const; | 492 } |
| 490 | 493 |
| 494 private: | |
| 491 // Liveness analysis support. | 495 // Liveness analysis support. |
| 492 BitVector* ComputeLiveOut(const InstructionBlock* block); | 496 BitVector* ComputeLiveOut(const InstructionBlock* block); |
| 493 void AddInitialIntervals(const InstructionBlock* block, BitVector* live_out); | 497 void AddInitialIntervals(const InstructionBlock* block, BitVector* live_out); |
| 494 bool IsOutputRegisterOf(Instruction* instr, int index); | 498 bool IsOutputRegisterOf(Instruction* instr, int index); |
| 495 bool IsOutputDoubleRegisterOf(Instruction* instr, int index); | 499 bool IsOutputDoubleRegisterOf(Instruction* instr, int index); |
| 496 void ProcessInstructions(const InstructionBlock* block, BitVector* live); | 500 void ProcessInstructions(const InstructionBlock* block, BitVector* live); |
| 497 void MeetRegisterConstraints(const InstructionBlock* block); | 501 void MeetRegisterConstraints(const InstructionBlock* block); |
| 498 void MeetConstraintsBefore(int index); | 502 void MeetConstraintsBefore(int index); |
| 499 void MeetConstraintsAfter(int index); | 503 void MeetConstraintsAfter(int index); |
| 500 void MeetRegisterConstraintsForLastInstructionInBlock( | 504 void MeetRegisterConstraintsForLastInstructionInBlock( |
| 501 const InstructionBlock* block); | 505 const InstructionBlock* block); |
| 502 void ResolvePhis(const InstructionBlock* block); | 506 void ResolvePhis(const InstructionBlock* block); |
| 503 | 507 |
| 508 static int FixedLiveRangeID(int index) { return -index - 1; } | |
| 509 int FixedDoubleLiveRangeID(int index); | |
| 510 LiveRange* FixedLiveRangeFor(int index); | |
| 511 LiveRange* FixedDoubleLiveRangeFor(int index); | |
| 512 Instruction* GetLastInstruction(const InstructionBlock* block); | |
| 513 | |
| 514 // Returns the register kind required by the given virtual register. | |
| 515 RegisterKind RequiredRegisterKind(int virtual_register) const; | |
| 516 | |
| 517 // Creates a new live range. | |
| 518 LiveRange* NewLiveRange(int index); | |
| 519 | |
| 504 // Helper methods for building intervals. | 520 // Helper methods for building intervals. |
| 505 InstructionOperand* AllocateFixed(UnallocatedOperand* operand, int pos, | 521 InstructionOperand* AllocateFixed(UnallocatedOperand* operand, int pos, |
| 506 bool is_tagged); | 522 bool is_tagged); |
| 507 LiveRange* LiveRangeFor(InstructionOperand* operand); | 523 LiveRange* LiveRangeFor(InstructionOperand* operand); |
| 508 void Define(LifetimePosition position, InstructionOperand* operand, | 524 void Define(LifetimePosition position, InstructionOperand* operand, |
| 509 InstructionOperand* hint); | 525 InstructionOperand* hint); |
| 510 void Use(LifetimePosition block_start, LifetimePosition position, | 526 void Use(LifetimePosition block_start, LifetimePosition position, |
| 511 InstructionOperand* operand, InstructionOperand* hint); | 527 InstructionOperand* operand, InstructionOperand* hint); |
| 512 MoveOperands* AddGapMove(int index, Instruction::GapPosition position, | 528 |
| 513 const InstructionOperand& from, | 529 Zone* const local_zone_; |
| 514 const InstructionOperand& to); | 530 Frame* const frame_; |
| 531 InstructionSequence* const code_; | |
| 532 const char* const debug_name_; | |
| 533 const RegisterConfiguration* const config_; | |
|
titzer
2015/04/20 13:33:53
Can we split the output of the LiveRangeBuilder in
| |
| 534 PhiMap phi_map_; | |
| 535 ZoneVector<BitVector*> live_in_sets_; | |
| 536 ZoneVector<LiveRange*> live_ranges_; | |
| 537 ZoneVector<LiveRange*> fixed_live_ranges_; | |
| 538 ZoneVector<LiveRange*> fixed_double_live_ranges_; | |
| 539 ZoneVector<SpillRange*> spill_ranges_; | |
| 540 BitVector* assigned_registers_; | |
| 541 BitVector* assigned_double_registers_; | |
| 542 | |
| 543 DISALLOW_COPY_AND_ASSIGN(LiveRangeBuilder); | |
| 544 }; | |
| 545 | |
| 546 | |
| 547 class LinearScanAllocator FINAL : public ZoneObject { | |
| 548 public: | |
| 549 explicit LinearScanAllocator(LiveRangeBuilder* live_range_builder, | |
| 550 RegisterKind kind); | |
| 551 | |
| 552 // Phase 4: compute register assignments. | |
| 553 void AllocateRegisters(); | |
| 554 | |
| 555 private: | |
| 556 LiveRangeBuilder* live_range_builder() const { return live_range_builder_; } | |
| 557 | |
| 558 InstructionSequence* code() const { return live_range_builder()->code(); } | |
| 559 // This zone is for datastructures only needed during register allocation. | |
| 560 Zone* local_zone() const { return live_range_builder()->local_zone(); } | |
| 561 | |
| 562 // This zone is for InstructionOperands and moves that live beyond register | |
| 563 // allocation. | |
| 564 Zone* code_zone() const { return code()->zone(); } | |
| 565 | |
| 566 Instruction* InstructionAt(int index) { return code()->InstructionAt(index); } | |
| 567 | |
| 568 int GetVirtualRegister() { return code()->NextVirtualRegister(); } | |
| 569 | |
| 570 bool IsReference(int virtual_register) const { | |
| 571 return live_range_builder()->IsReference(virtual_register); | |
| 572 } | |
| 573 | |
| 574 LiveRange* LiveRangeFor(int index) { | |
| 575 return live_range_builder()->LiveRangeFor(index); | |
| 576 } | |
| 515 | 577 |
| 516 // Helper methods for updating the life range lists. | 578 // Helper methods for updating the life range lists. |
| 517 void AddToActive(LiveRange* range); | 579 void AddToActive(LiveRange* range); |
| 518 void AddToInactive(LiveRange* range); | 580 void AddToInactive(LiveRange* range); |
| 519 void AddToUnhandledSorted(LiveRange* range); | 581 void AddToUnhandledSorted(LiveRange* range); |
| 520 void AddToUnhandledUnsorted(LiveRange* range); | 582 void AddToUnhandledUnsorted(LiveRange* range); |
| 521 void SortUnhandled(); | 583 void SortUnhandled(); |
| 522 bool UnhandledIsSorted(); | 584 bool UnhandledIsSorted(); |
| 523 void ActiveToHandled(LiveRange* range); | 585 void ActiveToHandled(LiveRange* range); |
| 524 void ActiveToInactive(LiveRange* range); | 586 void ActiveToInactive(LiveRange* range); |
| 525 void InactiveToHandled(LiveRange* range); | 587 void InactiveToHandled(LiveRange* range); |
| 526 void InactiveToActive(LiveRange* range); | 588 void InactiveToActive(LiveRange* range); |
| 527 | 589 |
| 528 // Helper methods for allocating registers. | 590 // Helper methods for allocating registers. |
| 529 bool TryReuseSpillForPhi(LiveRange* range); | 591 bool TryReuseSpillForPhi(LiveRange* range); |
| 530 bool TryAllocateFreeReg(LiveRange* range); | 592 bool TryAllocateFreeReg(LiveRange* range); |
| 531 void AllocateBlockedReg(LiveRange* range); | 593 void AllocateBlockedReg(LiveRange* range); |
| 532 SpillRange* AssignSpillRangeToLiveRange(LiveRange* range); | |
| 533 | 594 |
| 534 // Live range splitting helpers. | 595 // Live range splitting helpers. |
| 535 | 596 |
| 536 // Split the given range at the given position. | 597 // Split the given range at the given position. |
| 537 // If range starts at or after the given position then the | 598 // If range starts at or after the given position then the |
| 538 // original range is returned. | 599 // original range is returned. |
| 539 // Otherwise returns the live range that starts at pos and contains | 600 // Otherwise returns the live range that starts at pos and contains |
| 540 // all uses from the original range that follow pos. Uses at pos will | 601 // all uses from the original range that follow pos. Uses at pos will |
| 541 // still be owned by the original range after splitting. | 602 // still be owned by the original range after splitting. |
| 542 LiveRange* SplitRangeAt(LiveRange* range, LifetimePosition pos); | 603 LiveRange* SplitRangeAt(LiveRange* range, LifetimePosition pos); |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 564 LifetimePosition until, LifetimePosition end); | 625 LifetimePosition until, LifetimePosition end); |
| 565 | 626 |
| 566 void SplitAndSpillIntersecting(LiveRange* range); | 627 void SplitAndSpillIntersecting(LiveRange* range); |
| 567 | 628 |
| 568 // If we are trying to spill a range inside the loop try to | 629 // If we are trying to spill a range inside the loop try to |
| 569 // hoist spill position out to the point just before the loop. | 630 // hoist spill position out to the point just before the loop. |
| 570 LifetimePosition FindOptimalSpillingPos(LiveRange* range, | 631 LifetimePosition FindOptimalSpillingPos(LiveRange* range, |
| 571 LifetimePosition pos); | 632 LifetimePosition pos); |
| 572 | 633 |
| 573 void Spill(LiveRange* range); | 634 void Spill(LiveRange* range); |
| 574 bool IsBlockBoundary(LifetimePosition pos); | |
| 575 | |
| 576 // Helper methods for resolving control flow. | |
| 577 void ResolveControlFlow(const InstructionBlock* block, | |
| 578 const InstructionOperand& cur_op, | |
| 579 const InstructionBlock* pred, | |
| 580 const InstructionOperand& pred_op); | |
| 581 | |
| 582 void SetLiveRangeAssignedRegister(LiveRange* range, int reg); | |
| 583 | 635 |
| 584 // Return the block which contains give lifetime position. | 636 // Return the block which contains give lifetime position. |
| 585 const InstructionBlock* GetInstructionBlock(LifetimePosition pos); | 637 const InstructionBlock* GetInstructionBlock(LifetimePosition pos) const { |
| 638 return live_range_builder()->GetInstructionBlock(pos); | |
| 639 } | |
| 640 | |
| 641 void SetLiveRangeAssignedRegister(LiveRange* range, int reg) { | |
| 642 live_range_builder()->SetLiveRangeAssignedRegister(range, reg); | |
| 643 } | |
| 586 | 644 |
| 587 // Helper methods for the fixed registers. | 645 // Helper methods for the fixed registers. |
| 588 int RegisterCount() const; | 646 int RegisterCount() const { return num_registers_; } |
| 589 static int FixedLiveRangeID(int index) { return -index - 1; } | |
| 590 int FixedDoubleLiveRangeID(int index); | |
| 591 LiveRange* FixedLiveRangeFor(int index); | |
| 592 LiveRange* FixedDoubleLiveRangeFor(int index); | |
| 593 LiveRange* LiveRangeFor(int index); | |
| 594 Instruction* GetLastInstruction(const InstructionBlock* block); | |
| 595 | |
| 596 const char* RegisterName(int allocation_index); | 647 const char* RegisterName(int allocation_index); |
| 597 | 648 |
| 598 Instruction* InstructionAt(int index) { return code()->InstructionAt(index); } | 649 const RegisterConfiguration* config() const { |
| 599 void AssignPhiInput(LiveRange* range, const InstructionOperand& assignment); | 650 return live_range_builder()->config(); |
| 600 | 651 } |
| 601 Frame* frame() const { return frame_; } | 652 ZoneVector<LiveRange*>& live_ranges() { |
| 602 const char* debug_name() const { return debug_name_; } | 653 return live_range_builder()->live_ranges(); |
| 603 const RegisterConfiguration* config() const { return config_; } | 654 } |
| 604 ZoneVector<LiveRange*>& live_ranges() { return live_ranges_; } | 655 ZoneVector<LiveRange*>& fixed_live_ranges() { |
| 605 ZoneVector<LiveRange*>& fixed_live_ranges() { return fixed_live_ranges_; } | 656 return live_range_builder()->fixed_live_ranges(); |
| 657 } | |
| 606 ZoneVector<LiveRange*>& fixed_double_live_ranges() { | 658 ZoneVector<LiveRange*>& fixed_double_live_ranges() { |
| 607 return fixed_double_live_ranges_; | 659 return live_range_builder()->fixed_double_live_ranges(); |
| 608 } | 660 } |
| 609 ZoneVector<LiveRange*>& unhandled_live_ranges() { | 661 ZoneVector<LiveRange*>& unhandled_live_ranges() { |
| 610 return unhandled_live_ranges_; | 662 return unhandled_live_ranges_; |
| 611 } | 663 } |
| 612 ZoneVector<LiveRange*>& active_live_ranges() { return active_live_ranges_; } | 664 ZoneVector<LiveRange*>& active_live_ranges() { return active_live_ranges_; } |
| 613 ZoneVector<LiveRange*>& inactive_live_ranges() { | 665 ZoneVector<LiveRange*>& inactive_live_ranges() { |
| 614 return inactive_live_ranges_; | 666 return inactive_live_ranges_; |
| 615 } | 667 } |
| 616 ZoneVector<SpillRange*>& spill_ranges() { return spill_ranges_; } | 668 ZoneVector<SpillRange*>& spill_ranges() { |
| 669 return live_range_builder()->spill_ranges(); | |
| 670 } | |
| 671 LiveRangeBuilder::PhiMap& phi_map() { | |
| 672 return live_range_builder()->phi_map(); | |
| 673 } | |
| 617 | 674 |
| 618 class PhiMapValue : public ZoneObject { | 675 LiveRangeBuilder* const live_range_builder_; |
| 619 public: | 676 const RegisterKind mode_; |
| 620 PhiMapValue(PhiInstruction* phi, const InstructionBlock* block, Zone* zone) | 677 const int num_registers_; |
| 621 : phi(phi), block(block), incoming_moves(zone) { | |
| 622 incoming_moves.reserve(phi->operands().size()); | |
| 623 } | |
| 624 PhiInstruction* const phi; | |
| 625 const InstructionBlock* const block; | |
| 626 ZoneVector<MoveOperands*> incoming_moves; | |
| 627 }; | |
| 628 typedef ZoneMap<int, PhiMapValue*> PhiMap; | |
| 629 | 678 |
| 630 Zone* const local_zone_; | |
| 631 Frame* const frame_; | |
| 632 InstructionSequence* const code_; | |
| 633 const char* const debug_name_; | |
| 634 | |
| 635 const RegisterConfiguration* config_; | |
| 636 PhiMap phi_map_; | |
| 637 | |
| 638 // During liveness analysis keep a mapping from block id to live_in sets | |
| 639 // for blocks already analyzed. | |
| 640 ZoneVector<BitVector*> live_in_sets_; | |
| 641 | |
| 642 // Liveness analysis results. | |
| 643 ZoneVector<LiveRange*> live_ranges_; | |
| 644 | |
| 645 // Lists of live ranges | |
| 646 ZoneVector<LiveRange*> fixed_live_ranges_; | |
| 647 ZoneVector<LiveRange*> fixed_double_live_ranges_; | |
| 648 ZoneVector<LiveRange*> unhandled_live_ranges_; | 679 ZoneVector<LiveRange*> unhandled_live_ranges_; |
| 649 ZoneVector<LiveRange*> active_live_ranges_; | 680 ZoneVector<LiveRange*> active_live_ranges_; |
| 650 ZoneVector<LiveRange*> inactive_live_ranges_; | 681 ZoneVector<LiveRange*> inactive_live_ranges_; |
| 651 ZoneVector<SpillRange*> spill_ranges_; | |
| 652 | |
| 653 RegisterKind mode_; | |
| 654 int num_registers_; | |
| 655 | |
| 656 BitVector* assigned_registers_; | |
| 657 BitVector* assigned_double_registers_; | |
| 658 | 682 |
| 659 #ifdef DEBUG | 683 #ifdef DEBUG |
| 660 LifetimePosition allocation_finger_; | 684 LifetimePosition allocation_finger_; |
| 661 #endif | 685 #endif |
| 662 | 686 |
| 663 DISALLOW_COPY_AND_ASSIGN(RegisterAllocator); | 687 DISALLOW_COPY_AND_ASSIGN(LinearScanAllocator); |
| 688 }; | |
| 689 | |
| 690 | |
| 691 class OperandAssigner : public ZoneObject { | |
| 692 public: | |
| 693 explicit OperandAssigner(LiveRangeBuilder* live_range_builder); | |
| 694 | |
| 695 // Phase 5: assign spill splots. | |
| 696 void AssignSpillSlots(); | |
| 697 | |
| 698 // Phase 6: commit assignment. | |
| 699 void CommitAssignment(); | |
| 700 | |
| 701 private: | |
| 702 LiveRangeBuilder* live_range_builder() const { return live_range_builder_; } | |
| 703 | |
| 704 LiveRangeBuilder* const live_range_builder_; | |
| 705 | |
| 706 DISALLOW_COPY_AND_ASSIGN(OperandAssigner); | |
| 707 }; | |
| 708 | |
| 709 | |
| 710 class ReferenceMapPopulator : public ZoneObject { | |
| 711 public: | |
| 712 explicit ReferenceMapPopulator(LiveRangeBuilder* live_range_builder); | |
| 713 | |
| 714 // Phase 7: compute values for pointer maps. | |
| 715 void PopulateReferenceMaps(); | |
| 716 | |
| 717 private: | |
| 718 bool SafePointsAreInOrder() const; | |
| 719 | |
| 720 bool IsReference(int virtual_register) const { | |
| 721 return live_range_builder()->IsReference(virtual_register); | |
| 722 } | |
| 723 | |
| 724 LiveRangeBuilder* live_range_builder() const { return live_range_builder_; } | |
| 725 | |
| 726 LiveRangeBuilder* const live_range_builder_; | |
| 727 | |
| 728 DISALLOW_COPY_AND_ASSIGN(ReferenceMapPopulator); | |
| 729 }; | |
| 730 | |
| 731 | |
| 732 class LiveRangeConnector : public ZoneObject { | |
| 733 public: | |
| 734 explicit LiveRangeConnector(LiveRangeBuilder* live_range_builder); | |
| 735 | |
| 736 // Phase 8: reconnect split ranges with moves. | |
| 737 void ConnectRanges(Zone* temp_zone); | |
| 738 | |
| 739 // Phase 9: insert moves to connect ranges across basic blocks. | |
| 740 void ResolveControlFlow(); | |
| 741 | |
| 742 private: | |
| 743 const InstructionBlock* GetInstructionBlock(LifetimePosition pos) const { | |
| 744 return live_range_builder()->GetInstructionBlock(pos); | |
| 745 } | |
| 746 bool CanEagerlyResolveControlFlow(const InstructionBlock* block) const; | |
| 747 void ResolveControlFlow(const InstructionBlock* block, | |
| 748 const InstructionOperand& cur_op, | |
| 749 const InstructionBlock* pred, | |
| 750 const InstructionOperand& pred_op); | |
| 751 InstructionSequence* code() const { return live_range_builder()->code(); } | |
| 752 Zone* code_zone() const { return code()->zone(); } | |
| 753 LiveRangeBuilder* live_range_builder() const { return live_range_builder_; } | |
| 754 | |
| 755 LiveRangeBuilder* const live_range_builder_; | |
| 756 | |
| 757 DISALLOW_COPY_AND_ASSIGN(LiveRangeConnector); | |
| 664 }; | 758 }; |
| 665 | 759 |
| 666 } // namespace compiler | 760 } // namespace compiler |
| 667 } // namespace internal | 761 } // namespace internal |
| 668 } // namespace v8 | 762 } // namespace v8 |
| 669 | 763 |
| 670 #endif // V8_REGISTER_ALLOCATOR_H_ | 764 #endif // V8_REGISTER_ALLOCATOR_H_ |
| OLD | NEW |