| Index: src/compiler/register-allocator.h
|
| diff --git a/src/compiler/register-allocator.h b/src/compiler/register-allocator.h
|
| index b719f327c873ed87fbef5badf89ac098f4fdd368..d968258ce725881be5e3366f253cdd0829a56cb9 100644
|
| --- a/src/compiler/register-allocator.h
|
| +++ b/src/compiler/register-allocator.h
|
| @@ -340,17 +340,18 @@ class LiveRange final : public ZoneObject {
|
| // Shorten the most recently added interval by setting a new start.
|
| void ShortenTo(LifetimePosition start);
|
|
|
| -#ifdef DEBUG
|
| // True if target overlaps an existing interval.
|
| bool HasOverlap(UseInterval* target) const;
|
| void Verify() const;
|
| -#endif
|
| +
|
| + void ConvertUsesToOperand(const InstructionOperand& op,
|
| + InstructionOperand* spill_op);
|
| +
|
| + void set_kind(RegisterKind kind) { kind_ = kind; }
|
|
|
| private:
|
| struct SpillAtDefinitionList;
|
|
|
| - void ConvertUsesToOperand(const InstructionOperand& op,
|
| - InstructionOperand* spill_op);
|
| UseInterval* FirstSearchIntervalForPosition(LifetimePosition position) const;
|
| void AdvanceLastProcessedMarker(UseInterval* to_start_of,
|
| LifetimePosition but_not_past) const;
|
| @@ -381,8 +382,6 @@ class LiveRange final : public ZoneObject {
|
| };
|
| SpillAtDefinitionList* spills_at_definition_;
|
|
|
| - friend class RegisterAllocator; // Assigns to kind_.
|
| -
|
| DISALLOW_COPY_AND_ASSIGN(LiveRange);
|
| };
|
|
|
| @@ -412,81 +411,143 @@ class SpillRange final : public ZoneObject {
|
| };
|
|
|
|
|
| -class RegisterAllocator final : public ZoneObject {
|
| +class RegisterAllocationData final : public ZoneObject {
|
| public:
|
| - explicit RegisterAllocator(const RegisterConfiguration* config,
|
| - Zone* local_zone, Frame* frame,
|
| - InstructionSequence* code,
|
| - const char* debug_name = nullptr);
|
| + class PhiMapValue : public ZoneObject {
|
| + public:
|
| + PhiMapValue(PhiInstruction* phi, const InstructionBlock* block, Zone* zone)
|
| + : phi(phi), block(block), incoming_moves(zone) {
|
| + incoming_moves.reserve(phi->operands().size());
|
| + }
|
| + PhiInstruction* const phi;
|
| + const InstructionBlock* const block;
|
| + ZoneVector<MoveOperands*> incoming_moves;
|
| + };
|
| + typedef ZoneMap<int, PhiMapValue*> PhiMap;
|
| +
|
| + RegisterAllocationData(const RegisterConfiguration* config,
|
| + Zone* allocation_zone, Frame* frame,
|
| + InstructionSequence* code,
|
| + const char* debug_name = nullptr);
|
|
|
| const ZoneVector<LiveRange*>& live_ranges() const { return live_ranges_; }
|
| + ZoneVector<LiveRange*>& live_ranges() { return live_ranges_; }
|
| const ZoneVector<LiveRange*>& fixed_live_ranges() const {
|
| return fixed_live_ranges_;
|
| }
|
| + ZoneVector<LiveRange*>& fixed_live_ranges() { return fixed_live_ranges_; }
|
| + ZoneVector<LiveRange*>& fixed_double_live_ranges() {
|
| + return fixed_double_live_ranges_;
|
| + }
|
| const ZoneVector<LiveRange*>& fixed_double_live_ranges() const {
|
| return fixed_double_live_ranges_;
|
| }
|
| + const ZoneVector<BitVector*>& live_in_sets() const { return live_in_sets_; }
|
| + ZoneVector<BitVector*>& live_in_sets() { return live_in_sets_; }
|
| + ZoneVector<SpillRange*>& spill_ranges() { return spill_ranges_; }
|
| + const ZoneVector<SpillRange*>& spill_ranges() const { return spill_ranges_; }
|
| InstructionSequence* code() const { return code_; }
|
| - // This zone is for datastructures only needed during register allocation.
|
| - Zone* local_zone() const { return local_zone_; }
|
| -
|
| - // Phase 1 : insert moves to account for fixed register operands.
|
| - void MeetRegisterConstraints();
|
| + // This zone is for datastructures only needed during register allocation
|
| + // phases.
|
| + Zone* allocation_zone() const { return allocation_zone_; }
|
| + // This zone is for InstructionOperands and moves that live beyond register
|
| + // allocation.
|
| + Zone* code_zone() const { return code()->zone(); }
|
| + const PhiMap& phi_map() const { return phi_map_; }
|
| + PhiMap& phi_map() { return phi_map_; }
|
| + Frame* frame() const { return frame_; }
|
| + const char* debug_name() const { return debug_name_; }
|
| + const RegisterConfiguration* config() const { return config_; }
|
|
|
| - // Phase 2: deconstruct SSA by inserting moves in successors and the headers
|
| - // of blocks containing phis.
|
| - void ResolvePhis();
|
| + void SetLiveRangeAssignedRegister(LiveRange* range, int reg);
|
| + LiveRange* LiveRangeFor(int index);
|
| + Instruction* InstructionAt(int index) { return code()->InstructionAt(index); }
|
|
|
| - // Phase 3: compute liveness of all virtual register.
|
| - void BuildLiveRanges();
|
| - bool ExistsUseWithoutDefinition();
|
| + void AssignPhiInput(LiveRange* range, const InstructionOperand& assignment);
|
| + SpillRange* AssignSpillRangeToLiveRange(LiveRange* range);
|
|
|
| - // Phase 4: compute register assignments.
|
| - void AllocateGeneralRegisters();
|
| - void AllocateDoubleRegisters();
|
| + MoveOperands* AddGapMove(int index, Instruction::GapPosition position,
|
| + const InstructionOperand& from,
|
| + const InstructionOperand& to);
|
|
|
| - // Phase 5: assign spill splots.
|
| - void AssignSpillSlots();
|
| + bool IsBlockBoundary(LifetimePosition pos) {
|
| + return pos.IsFullStart() &&
|
| + code()
|
| + ->GetInstructionBlock(pos.ToInstructionIndex())
|
| + ->code_start() == pos.ToInstructionIndex();
|
| + }
|
|
|
| - // Phase 6: commit assignment.
|
| - void CommitAssignment();
|
| + const InstructionBlock* GetInstructionBlock(LifetimePosition pos) const {
|
| + return code()->GetInstructionBlock(pos.ToInstructionIndex());
|
| + }
|
|
|
| - // Phase 7: compute values for pointer maps.
|
| - void PopulateReferenceMaps();
|
| + bool IsReference(int virtual_register) const {
|
| + return code()->IsReference(virtual_register);
|
| + }
|
|
|
| - // Phase 8: reconnect split ranges with moves.
|
| - void ConnectRanges();
|
| + bool ExistsUseWithoutDefinition();
|
|
|
| - // Phase 9: insert moves to connect ranges across basic blocks.
|
| - void ResolveControlFlow();
|
| + // Creates a new live range.
|
| + LiveRange* NewLiveRange(int index);
|
|
|
| private:
|
| - int GetVirtualRegister() { return code()->NextVirtualRegister(); }
|
| + Zone* const allocation_zone_;
|
| + Frame* const frame_;
|
| + InstructionSequence* const code_;
|
| + const char* const debug_name_;
|
| + const RegisterConfiguration* const config_;
|
| + PhiMap phi_map_;
|
| + ZoneVector<BitVector*> live_in_sets_;
|
| + ZoneVector<LiveRange*> live_ranges_;
|
| + ZoneVector<LiveRange*> fixed_live_ranges_;
|
| + ZoneVector<LiveRange*> fixed_double_live_ranges_;
|
| + ZoneVector<SpillRange*> spill_ranges_;
|
| + BitVector* assigned_registers_;
|
| + BitVector* assigned_double_registers_;
|
|
|
| - // Checks whether the value of a given virtual register is a reference.
|
| - // TODO(titzer): rename this to IsReference.
|
| - bool HasTaggedValue(int virtual_register) const;
|
| + DISALLOW_COPY_AND_ASSIGN(RegisterAllocationData);
|
| +};
|
|
|
| - // Returns the register kind required by the given virtual register.
|
| - RegisterKind RequiredRegisterKind(int virtual_register) const;
|
|
|
| - // Creates a new live range.
|
| - LiveRange* NewLiveRange(int index);
|
| +class LiveRangeBuilder final : public ZoneObject {
|
| + public:
|
| + explicit LiveRangeBuilder(RegisterAllocationData* data);
|
|
|
| - // This zone is for InstructionOperands and moves that live beyond register
|
| - // allocation.
|
| + // Phase 1 : insert moves to account for fixed register operands.
|
| + void MeetRegisterConstraints();
|
| +
|
| + // Phase 2: deconstruct SSA by inserting moves in successors and the headers
|
| + // of blocks containing phis.
|
| + void ResolvePhis();
|
| +
|
| + // Phase 3: compute liveness of all virtual register.
|
| + void BuildLiveRanges();
|
| +
|
| + private:
|
| + RegisterAllocationData* data() const { return data_; }
|
| + InstructionSequence* code() const { return data()->code(); }
|
| + Zone* allocation_zone() const { return data()->allocation_zone(); }
|
| Zone* code_zone() const { return code()->zone(); }
|
| + const RegisterConfiguration* config() const { return data()->config(); }
|
| + ZoneVector<BitVector*>& live_in_sets() const {
|
| + return data()->live_in_sets();
|
| + }
|
| + ZoneVector<LiveRange*>& live_ranges() { return data()->live_ranges(); }
|
| + ZoneVector<LiveRange*>& fixed_live_ranges() {
|
| + return data()->fixed_live_ranges();
|
| + }
|
| + ZoneVector<LiveRange*>& fixed_double_live_ranges() {
|
| + return data()->fixed_double_live_ranges();
|
| + }
|
| + ZoneVector<SpillRange*>& spill_ranges() { return data()->spill_ranges(); }
|
| + RegisterAllocationData::PhiMap& phi_map() { return data()->phi_map(); }
|
|
|
| - BitVector* assigned_registers() { return assigned_registers_; }
|
| - BitVector* assigned_double_registers() { return assigned_double_registers_; }
|
| + Instruction* InstructionAt(int index) { return code()->InstructionAt(index); }
|
| + bool IsReference(int virtual_register) const {
|
| + return data()->IsReference(virtual_register);
|
| + }
|
|
|
| -#ifdef DEBUG
|
| void Verify() const;
|
| -#endif
|
| -
|
| - void AllocateRegisters();
|
| - bool CanEagerlyResolveControlFlow(const InstructionBlock* block) const;
|
| - bool SafePointsAreInOrder() const;
|
|
|
| // Liveness analysis support.
|
| BitVector* ComputeLiveOut(const InstructionBlock* block);
|
| @@ -501,6 +562,16 @@ class RegisterAllocator final : public ZoneObject {
|
| const InstructionBlock* block);
|
| void ResolvePhis(const InstructionBlock* block);
|
|
|
| + LiveRange* LiveRangeFor(int index) { return data()->LiveRangeFor(index); }
|
| + static int FixedLiveRangeID(int index) { return -index - 1; }
|
| + int FixedDoubleLiveRangeID(int index);
|
| + LiveRange* FixedLiveRangeFor(int index);
|
| + LiveRange* FixedDoubleLiveRangeFor(int index);
|
| + Instruction* GetLastInstruction(const InstructionBlock* block);
|
| +
|
| + // Returns the register kind required by the given virtual register.
|
| + RegisterKind RequiredRegisterKind(int virtual_register) const;
|
| +
|
| // Helper methods for building intervals.
|
| InstructionOperand* AllocateFixed(UnallocatedOperand* operand, int pos,
|
| bool is_tagged);
|
| @@ -509,9 +580,36 @@ class RegisterAllocator final : public ZoneObject {
|
| InstructionOperand* hint);
|
| void Use(LifetimePosition block_start, LifetimePosition position,
|
| InstructionOperand* operand, InstructionOperand* hint);
|
| - MoveOperands* AddGapMove(int index, Instruction::GapPosition position,
|
| - const InstructionOperand& from,
|
| - const InstructionOperand& to);
|
| +
|
| + RegisterAllocationData* const data_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(LiveRangeBuilder);
|
| +};
|
| +
|
| +
|
| +class LinearScanAllocator final : public ZoneObject {
|
| + public:
|
| + explicit LinearScanAllocator(RegisterAllocationData* data, RegisterKind kind);
|
| +
|
| + // Phase 4: compute register assignments.
|
| + void AllocateRegisters();
|
| +
|
| + private:
|
| + RegisterAllocationData* data() const { return data_; }
|
| + InstructionSequence* code() const { return data()->code(); }
|
| + Zone* allocation_zone() const { return data()->allocation_zone(); }
|
| + Zone* code_zone() const { return code()->zone(); }
|
| + const RegisterConfiguration* config() const { return data()->config(); }
|
| +
|
| + Instruction* InstructionAt(int index) { return code()->InstructionAt(index); }
|
| +
|
| + int GetVirtualRegister() { return code()->NextVirtualRegister(); }
|
| +
|
| + bool IsReference(int virtual_register) const {
|
| + return data()->IsReference(virtual_register);
|
| + }
|
| +
|
| + LiveRange* LiveRangeFor(int index) { return data()->LiveRangeFor(index); }
|
|
|
| // Helper methods for updating the life range lists.
|
| void AddToActive(LiveRange* range);
|
| @@ -529,7 +627,6 @@ class RegisterAllocator final : public ZoneObject {
|
| bool TryReuseSpillForPhi(LiveRange* range);
|
| bool TryAllocateFreeReg(LiveRange* range);
|
| void AllocateBlockedReg(LiveRange* range);
|
| - SpillRange* AssignSpillRangeToLiveRange(LiveRange* range);
|
|
|
| // Live range splitting helpers.
|
|
|
| @@ -571,40 +668,26 @@ class RegisterAllocator final : public ZoneObject {
|
| LifetimePosition pos);
|
|
|
| void Spill(LiveRange* range);
|
| - bool IsBlockBoundary(LifetimePosition pos);
|
| -
|
| - // Helper methods for resolving control flow.
|
| - void ResolveControlFlow(const InstructionBlock* block,
|
| - const InstructionOperand& cur_op,
|
| - const InstructionBlock* pred,
|
| - const InstructionOperand& pred_op);
|
| -
|
| - void SetLiveRangeAssignedRegister(LiveRange* range, int reg);
|
|
|
| // Return the block which contains give lifetime position.
|
| - const InstructionBlock* GetInstructionBlock(LifetimePosition pos);
|
| + const InstructionBlock* GetInstructionBlock(LifetimePosition pos) const {
|
| + return data()->GetInstructionBlock(pos);
|
| + }
|
|
|
| - // Helper methods for the fixed registers.
|
| - int RegisterCount() const;
|
| - static int FixedLiveRangeID(int index) { return -index - 1; }
|
| - int FixedDoubleLiveRangeID(int index);
|
| - LiveRange* FixedLiveRangeFor(int index);
|
| - LiveRange* FixedDoubleLiveRangeFor(int index);
|
| - LiveRange* LiveRangeFor(int index);
|
| - Instruction* GetLastInstruction(const InstructionBlock* block);
|
| + void SetLiveRangeAssignedRegister(LiveRange* range, int reg) {
|
| + data()->SetLiveRangeAssignedRegister(range, reg);
|
| + }
|
|
|
| + // Helper methods for the fixed registers.
|
| + int RegisterCount() const { return num_registers_; }
|
| const char* RegisterName(int allocation_index);
|
|
|
| - Instruction* InstructionAt(int index) { return code()->InstructionAt(index); }
|
| - void AssignPhiInput(LiveRange* range, const InstructionOperand& assignment);
|
| -
|
| - Frame* frame() const { return frame_; }
|
| - const char* debug_name() const { return debug_name_; }
|
| - const RegisterConfiguration* config() const { return config_; }
|
| - ZoneVector<LiveRange*>& live_ranges() { return live_ranges_; }
|
| - ZoneVector<LiveRange*>& fixed_live_ranges() { return fixed_live_ranges_; }
|
| + ZoneVector<LiveRange*>& live_ranges() { return data()->live_ranges(); }
|
| + ZoneVector<LiveRange*>& fixed_live_ranges() {
|
| + return data()->fixed_live_ranges();
|
| + }
|
| ZoneVector<LiveRange*>& fixed_double_live_ranges() {
|
| - return fixed_double_live_ranges_;
|
| + return data()->fixed_double_live_ranges();
|
| }
|
| ZoneVector<LiveRange*>& unhandled_live_ranges() {
|
| return unhandled_live_ranges_;
|
| @@ -613,54 +696,92 @@ class RegisterAllocator final : public ZoneObject {
|
| ZoneVector<LiveRange*>& inactive_live_ranges() {
|
| return inactive_live_ranges_;
|
| }
|
| - ZoneVector<SpillRange*>& spill_ranges() { return spill_ranges_; }
|
| + ZoneVector<SpillRange*>& spill_ranges() { return data()->spill_ranges(); }
|
| + RegisterAllocationData::PhiMap& phi_map() { return data()->phi_map(); }
|
|
|
| - class PhiMapValue : public ZoneObject {
|
| - public:
|
| - PhiMapValue(PhiInstruction* phi, const InstructionBlock* block, Zone* zone)
|
| - : phi(phi), block(block), incoming_moves(zone) {
|
| - incoming_moves.reserve(phi->operands().size());
|
| - }
|
| - PhiInstruction* const phi;
|
| - const InstructionBlock* const block;
|
| - ZoneVector<MoveOperands*> incoming_moves;
|
| - };
|
| - typedef ZoneMap<int, PhiMapValue*> PhiMap;
|
| + RegisterAllocationData* const data_;
|
| + const RegisterKind mode_;
|
| + const int num_registers_;
|
|
|
| - Zone* const local_zone_;
|
| - Frame* const frame_;
|
| - InstructionSequence* const code_;
|
| - const char* const debug_name_;
|
| -
|
| - const RegisterConfiguration* config_;
|
| - PhiMap phi_map_;
|
| -
|
| - // During liveness analysis keep a mapping from block id to live_in sets
|
| - // for blocks already analyzed.
|
| - ZoneVector<BitVector*> live_in_sets_;
|
| -
|
| - // Liveness analysis results.
|
| - ZoneVector<LiveRange*> live_ranges_;
|
| -
|
| - // Lists of live ranges
|
| - ZoneVector<LiveRange*> fixed_live_ranges_;
|
| - ZoneVector<LiveRange*> fixed_double_live_ranges_;
|
| ZoneVector<LiveRange*> unhandled_live_ranges_;
|
| ZoneVector<LiveRange*> active_live_ranges_;
|
| ZoneVector<LiveRange*> inactive_live_ranges_;
|
| - ZoneVector<SpillRange*> spill_ranges_;
|
| -
|
| - RegisterKind mode_;
|
| - int num_registers_;
|
| -
|
| - BitVector* assigned_registers_;
|
| - BitVector* assigned_double_registers_;
|
|
|
| #ifdef DEBUG
|
| LifetimePosition allocation_finger_;
|
| #endif
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(RegisterAllocator);
|
| + DISALLOW_COPY_AND_ASSIGN(LinearScanAllocator);
|
| +};
|
| +
|
| +
|
| +class OperandAssigner final : public ZoneObject {
|
| + public:
|
| + explicit OperandAssigner(RegisterAllocationData* data);
|
| +
|
| + // Phase 5: assign spill splots.
|
| + void AssignSpillSlots();
|
| +
|
| + // Phase 6: commit assignment.
|
| + void CommitAssignment();
|
| +
|
| + private:
|
| + RegisterAllocationData* data() const { return data_; }
|
| +
|
| + RegisterAllocationData* const data_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(OperandAssigner);
|
| +};
|
| +
|
| +
|
| +class ReferenceMapPopulator final : public ZoneObject {
|
| + public:
|
| + explicit ReferenceMapPopulator(RegisterAllocationData* data);
|
| +
|
| + // Phase 7: compute values for pointer maps.
|
| + void PopulateReferenceMaps();
|
| +
|
| + private:
|
| + bool SafePointsAreInOrder() const;
|
| +
|
| + bool IsReference(int virtual_register) const {
|
| + return data()->IsReference(virtual_register);
|
| + }
|
| +
|
| + RegisterAllocationData* data() const { return data_; }
|
| +
|
| + RegisterAllocationData* const data_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ReferenceMapPopulator);
|
| +};
|
| +
|
| +
|
| +class LiveRangeConnector final : public ZoneObject {
|
| + public:
|
| + explicit LiveRangeConnector(RegisterAllocationData* data);
|
| +
|
| + // Phase 8: reconnect split ranges with moves.
|
| + void ConnectRanges(Zone* temp_zone);
|
| +
|
| + // Phase 9: insert moves to connect ranges across basic blocks.
|
| + void ResolveControlFlow();
|
| +
|
| + private:
|
| + const InstructionBlock* GetInstructionBlock(LifetimePosition pos) const {
|
| + return data()->GetInstructionBlock(pos);
|
| + }
|
| + bool CanEagerlyResolveControlFlow(const InstructionBlock* block) const;
|
| + void ResolveControlFlow(const InstructionBlock* block,
|
| + const InstructionOperand& cur_op,
|
| + const InstructionBlock* pred,
|
| + const InstructionOperand& pred_op);
|
| + InstructionSequence* code() const { return data()->code(); }
|
| + Zone* code_zone() const { return code()->zone(); }
|
| + RegisterAllocationData* data() const { return data_; }
|
| +
|
| + RegisterAllocationData* const data_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(LiveRangeConnector);
|
| };
|
|
|
| } // namespace compiler
|
|
|