Index: src/compiler/register-allocator.h |
diff --git a/src/compiler/register-allocator.h b/src/compiler/register-allocator.h |
index 01f272bbf42d3f14d56f7fbe0062de35af507cb2..ce722325c6ba48e356db28d4894bdc3ae15e215f 100644 |
--- a/src/compiler/register-allocator.h |
+++ b/src/compiler/register-allocator.h |
@@ -196,41 +196,75 @@ class UseInterval final : public ZoneObject { |
enum class UsePositionType : uint8_t { kAny, kRequiresRegister, kRequiresSlot }; |
+enum class UsePositionHintType : uint8_t { |
+ kNone, |
+ kOperand, |
+ kUsePos, |
+ kPhi, |
+ kUnresolved |
+}; |
+ |
+ |
+static const int32_t kUnassignedRegister = |
+ RegisterConfiguration::kMaxGeneralRegisters; |
+ |
+ |
+static_assert(kUnassignedRegister <= RegisterConfiguration::kMaxDoubleRegisters, |
+ "kUnassignedRegister too small"); |
+ |
+ |
// Representation of a use position. |
class UsePosition final : public ZoneObject { |
public: |
- UsePosition(LifetimePosition pos, InstructionOperand* operand, |
- InstructionOperand* hint); |
+ UsePosition(LifetimePosition pos, InstructionOperand* operand, void* hint, |
+ UsePositionHintType hint_type); |
InstructionOperand* operand() const { return operand_; } |
bool HasOperand() const { return operand_ != nullptr; } |
- InstructionOperand* hint() const { return hint_; } |
- bool HasHint() const; |
bool RegisterIsBeneficial() const { |
return RegisterBeneficialField::decode(flags_); |
} |
UsePositionType type() const { return TypeField::decode(flags_); } |
+ void set_type(UsePositionType type, bool register_beneficial); |
LifetimePosition pos() const { return pos_; } |
- UsePosition* next() const { return next_; } |
+ UsePosition* next() const { return next_; } |
void set_next(UsePosition* next) { next_ = next; } |
- void set_type(UsePositionType type, bool register_beneficial); |
+ |
+ // For hinting only. |
+ void set_assigned_register(int register_index) { |
+ flags_ = AssignedRegisterField::update(flags_, register_index); |
+ } |
+ |
+ UsePositionHintType hint_type() const { |
+ return HintTypeField::decode(flags_); |
+ } |
+ bool HasHint() const; |
+ bool HintRegister(int* register_index) const; |
+ void ResolveHint(UsePosition* use_pos); |
+ bool IsResolved() const { |
+ return hint_type() != UsePositionHintType::kUnresolved; |
+ } |
+ static UsePositionHintType HintTypeForOperand(const InstructionOperand& op); |
private: |
- typedef BitField8<UsePositionType, 0, 2> TypeField; |
- typedef BitField8<bool, 2, 1> RegisterBeneficialField; |
+ typedef BitField<UsePositionType, 0, 2> TypeField; |
+ typedef BitField<UsePositionHintType, 2, 3> HintTypeField; |
+ typedef BitField<bool, 5, 1> RegisterBeneficialField; |
+ typedef BitField<int32_t, 6, 6> AssignedRegisterField; |
InstructionOperand* const operand_; |
- InstructionOperand* const hint_; |
- LifetimePosition const pos_; |
+ void* hint_; |
UsePosition* next_; |
- uint8_t flags_; |
+ LifetimePosition const pos_; |
+ uint32_t flags_; |
DISALLOW_COPY_AND_ASSIGN(UsePosition); |
}; |
+ |
class SpillRange; |
@@ -238,8 +272,6 @@ class SpillRange; |
// intervals over the instruction ordering. |
class LiveRange final : public ZoneObject { |
public: |
- static const int kInvalidAssignment = 0x7fffffff; |
- |
explicit LiveRange(int id); |
UseInterval* first_interval() const { return first_interval_; } |
@@ -258,6 +290,7 @@ class LiveRange final : public ZoneObject { |
int assigned_register() const { return assigned_register_; } |
int spill_start_index() const { return spill_start_index_; } |
void set_assigned_register(int reg); |
+ void UnsetAssignedRegister(); |
void MakeSpilled(); |
bool is_phi() const { return is_phi_; } |
void set_is_phi(bool is_phi) { is_phi_ = is_phi; } |
@@ -297,19 +330,20 @@ class LiveRange final : public ZoneObject { |
RegisterKind Kind() const { return kind_; } |
bool HasRegisterAssigned() const { |
- return assigned_register_ != kInvalidAssignment; |
+ return assigned_register_ != kUnassignedRegister; |
} |
bool IsSpilled() const { return spilled_; } |
- InstructionOperand* current_hint_operand() const { |
- DCHECK(current_hint_operand_ == FirstHint()); |
- return current_hint_operand_; |
+ // Returns nullptr when no register is hinted, otherwise sets register_index. |
+ UsePosition* FirstHintPosition(int* register_index) const; |
+ UsePosition* FirstHintPosition() const { |
+ int register_index; |
+ return FirstHintPosition(®ister_index); |
} |
- InstructionOperand* FirstHint() const { |
- UsePosition* pos = first_pos_; |
- while (pos != nullptr && !pos->HasHint()) pos = pos->next(); |
- if (pos != nullptr) return pos->hint(); |
- return nullptr; |
+ |
+ UsePosition* current_hint_position() const { |
+ DCHECK(current_hint_position_ == FirstHintPosition()); |
+ return current_hint_position_; |
} |
LifetimePosition Start() const { |
@@ -359,8 +393,7 @@ class LiveRange final : public ZoneObject { |
// Add a new interval or a new use position to this live range. |
void EnsureInterval(LifetimePosition start, LifetimePosition end, Zone* zone); |
void AddUseInterval(LifetimePosition start, LifetimePosition end, Zone* zone); |
- void AddUsePosition(LifetimePosition pos, InstructionOperand* operand, |
- InstructionOperand* hint, Zone* zone); |
+ void AddUsePosition(UsePosition* pos); |
// Shorten the most recently added interval by setting a new start. |
void ShortenTo(LifetimePosition start); |
@@ -369,6 +402,8 @@ class LiveRange final : public ZoneObject { |
void ConvertUsesToOperand(const InstructionOperand& op, |
InstructionOperand* spill_op); |
+ void SetUseHints(int register_index); |
+ void UnsetUseHints() { SetUseHints(kUnassignedRegister); } |
void set_kind(RegisterKind kind) { kind_ = kind; } |
@@ -383,8 +418,8 @@ class LiveRange final : public ZoneObject { |
int id_; |
bool spilled_ : 1; |
bool has_slot_use_ : 1; // Relevant only for parent. |
- bool is_phi_ : 1; |
- bool is_non_loop_phi_ : 1; |
+ bool is_phi_ : 1; // Correct only for parent. |
+ bool is_non_loop_phi_ : 1; // Correct only for parent. |
RegisterKind kind_; |
int assigned_register_; |
UseInterval* last_interval_; |
@@ -397,7 +432,7 @@ class LiveRange final : public ZoneObject { |
// This is used as a cache, it doesn't affect correctness. |
mutable UsePosition* last_processed_use_; |
// This is used as a cache, it's invalid outside of BuildLiveRanges. |
- mutable InstructionOperand* current_hint_operand_; |
+ mutable UsePosition* current_hint_position_; |
int spill_start_index_; |
SpillType spill_type_; |
union { |
@@ -439,13 +474,27 @@ class RegisterAllocationData final : public ZoneObject { |
public: |
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()); |
+ PhiMapValue(PhiInstruction* phi, const InstructionBlock* block, Zone* zone); |
+ |
+ const PhiInstruction* phi() const { return phi_; } |
+ const InstructionBlock* block() const { return block_; } |
+ |
+ // For hinting. |
+ int assigned_register() const { return assigned_register_; } |
+ void set_assigned_register(int register_index) { |
+ DCHECK_EQ(assigned_register_, kUnassignedRegister); |
+ assigned_register_ = register_index; |
} |
- PhiInstruction* const phi; |
- const InstructionBlock* const block; |
- ZoneVector<MoveOperands*> incoming_moves; |
+ void UnsetAssignedRegister() { assigned_register_ = kUnassignedRegister; } |
+ |
+ void AddOperand(InstructionOperand* operand); |
+ void CommitAssignment(const InstructionOperand& operand); |
+ |
+ private: |
+ PhiInstruction* const phi_; |
+ const InstructionBlock* const block_; |
+ ZoneVector<InstructionOperand*> incoming_operands_; |
+ int assigned_register_; |
}; |
typedef ZoneMap<int, PhiMapValue*> PhiMap; |
@@ -475,16 +524,12 @@ class RegisterAllocationData final : public ZoneObject { |
// 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_; } |
- void SetLiveRangeAssignedRegister(LiveRange* range, int reg); |
LiveRange* LiveRangeFor(int index); |
- void AssignPhiInput(LiveRange* range, const InstructionOperand& assignment); |
SpillRange* AssignSpillRangeToLiveRange(LiveRange* range); |
MoveOperands* AddGapMove(int index, Instruction::GapPosition position, |
@@ -500,6 +545,12 @@ class RegisterAllocationData final : public ZoneObject { |
// Creates a new live range. |
LiveRange* NewLiveRange(int index); |
+ void MarkAllocated(RegisterKind kind, int index); |
+ |
+ PhiMapValue* InitializePhiMap(const InstructionBlock* block, |
+ PhiInstruction* phi); |
+ PhiMapValue* GetPhiMapValueFor(int virtual_register); |
+ |
private: |
Zone* const allocation_zone_; |
Frame* const frame_; |
@@ -558,7 +609,7 @@ class ConstraintBuilder final : public ZoneObject { |
class LiveRangeBuilder final : public ZoneObject { |
public: |
- explicit LiveRangeBuilder(RegisterAllocationData* data); |
+ explicit LiveRangeBuilder(RegisterAllocationData* data, Zone* local_zone); |
// Phase 3: compute liveness of all virtual register. |
void BuildLiveRanges(); |
@@ -580,26 +631,43 @@ class LiveRangeBuilder final : public ZoneObject { |
// Liveness analysis support. |
BitVector* ComputeLiveOut(const InstructionBlock* block); |
void AddInitialIntervals(const InstructionBlock* block, BitVector* live_out); |
- bool IsOutputRegisterOf(Instruction* instr, int index); |
- bool IsOutputDoubleRegisterOf(Instruction* instr, int index); |
void ProcessInstructions(const InstructionBlock* block, BitVector* live); |
+ void ProcessPhis(const InstructionBlock* block, BitVector* live); |
+ void ProcessLoopHeader(const InstructionBlock* block, BitVector* live); |
static int FixedLiveRangeID(int index) { return -index - 1; } |
int FixedDoubleLiveRangeID(int index); |
LiveRange* FixedLiveRangeFor(int index); |
LiveRange* FixedDoubleLiveRangeFor(int index); |
+ void MapPhiHint(InstructionOperand* operand, UsePosition* use_pos); |
+ void ResolvePhiHint(InstructionOperand* operand, UsePosition* use_pos); |
+ |
// Returns the register kind required by the given virtual register. |
RegisterKind RequiredRegisterKind(int virtual_register) const; |
- // Helper methods for building intervals. |
+ UsePosition* NewUsePosition(LifetimePosition pos, InstructionOperand* operand, |
+ void* hint, UsePositionHintType hint_type); |
+ UsePosition* NewUsePosition(LifetimePosition pos) { |
+ return NewUsePosition(pos, nullptr, nullptr, UsePositionHintType::kNone); |
+ } |
LiveRange* LiveRangeFor(InstructionOperand* operand); |
- void Define(LifetimePosition position, InstructionOperand* operand, |
- InstructionOperand* hint); |
+ // Helper methods for building intervals. |
+ UsePosition* Define(LifetimePosition position, InstructionOperand* operand, |
+ void* hint, UsePositionHintType hint_type); |
+ void Define(LifetimePosition position, InstructionOperand* operand) { |
+ Define(position, operand, nullptr, UsePositionHintType::kNone); |
+ } |
+ UsePosition* Use(LifetimePosition block_start, LifetimePosition position, |
+ InstructionOperand* operand, void* hint, |
+ UsePositionHintType hint_type); |
void Use(LifetimePosition block_start, LifetimePosition position, |
- InstructionOperand* operand, InstructionOperand* hint); |
+ InstructionOperand* operand) { |
+ Use(block_start, position, operand, nullptr, UsePositionHintType::kNone); |
+ } |
RegisterAllocationData* const data_; |
+ ZoneMap<InstructionOperand*, UsePosition*> phi_hints_; |
DISALLOW_COPY_AND_ASSIGN(LiveRangeBuilder); |
}; |
@@ -672,6 +740,8 @@ class LinearScanAllocator final : public RegisterAllocator { |
return inactive_live_ranges_; |
} |
+ void SetLiveRangeAssignedRegister(LiveRange* range, int reg); |
+ |
// Helper methods for updating the life range lists. |
void AddToActive(LiveRange* range); |
void AddToInactive(LiveRange* range); |