| Index: src/lithium-allocator.h
|
| ===================================================================
|
| --- src/lithium-allocator.h (revision 6389)
|
| +++ src/lithium-allocator.h (working copy)
|
| @@ -48,6 +48,8 @@
|
|
|
| class LArgument;
|
| class LChunk;
|
| +class LOperand;
|
| +class LUnallocated;
|
| class LConstantOperand;
|
| class LGap;
|
| class LParallelMove;
|
| @@ -149,355 +151,6 @@
|
| };
|
|
|
|
|
| -class LOperand: public ZoneObject {
|
| - public:
|
| - enum Kind {
|
| - INVALID,
|
| - UNALLOCATED,
|
| - CONSTANT_OPERAND,
|
| - STACK_SLOT,
|
| - DOUBLE_STACK_SLOT,
|
| - REGISTER,
|
| - DOUBLE_REGISTER,
|
| - ARGUMENT
|
| - };
|
| -
|
| - LOperand() : value_(KindField::encode(INVALID)) { }
|
| -
|
| - Kind kind() const { return KindField::decode(value_); }
|
| - int index() const { return static_cast<int>(value_) >> kKindFieldWidth; }
|
| - bool IsConstantOperand() const { return kind() == CONSTANT_OPERAND; }
|
| - bool IsStackSlot() const { return kind() == STACK_SLOT; }
|
| - bool IsDoubleStackSlot() const { return kind() == DOUBLE_STACK_SLOT; }
|
| - bool IsRegister() const { return kind() == REGISTER; }
|
| - bool IsDoubleRegister() const { return kind() == DOUBLE_REGISTER; }
|
| - bool IsArgument() const { return kind() == ARGUMENT; }
|
| - bool IsUnallocated() const { return kind() == UNALLOCATED; }
|
| - bool Equals(LOperand* other) const { return value_ == other->value_; }
|
| - int VirtualRegister();
|
| -
|
| - void PrintTo(StringStream* stream);
|
| - void ConvertTo(Kind kind, int index) {
|
| - value_ = KindField::encode(kind);
|
| - value_ |= index << kKindFieldWidth;
|
| - ASSERT(this->index() == index);
|
| - }
|
| -
|
| - protected:
|
| - static const int kKindFieldWidth = 3;
|
| - class KindField : public BitField<Kind, 0, kKindFieldWidth> { };
|
| -
|
| - LOperand(Kind kind, int index) { ConvertTo(kind, index); }
|
| -
|
| - unsigned value_;
|
| -};
|
| -
|
| -
|
| -class LUnallocated: public LOperand {
|
| - public:
|
| - enum Policy {
|
| - NONE,
|
| - ANY,
|
| - FIXED_REGISTER,
|
| - FIXED_DOUBLE_REGISTER,
|
| - FIXED_SLOT,
|
| - MUST_HAVE_REGISTER,
|
| - WRITABLE_REGISTER,
|
| - SAME_AS_FIRST_INPUT,
|
| - IGNORE
|
| - };
|
| -
|
| - // Lifetime of operand inside the instruction.
|
| - enum Lifetime {
|
| - // USED_AT_START operand is guaranteed to be live only at
|
| - // instruction start. Register allocator is free to assign the same register
|
| - // to some other operand used inside instruction (i.e. temporary or
|
| - // output).
|
| - USED_AT_START,
|
| -
|
| - // USED_AT_END operand is treated as live until the end of
|
| - // instruction. This means that register allocator will not reuse it's
|
| - // register for any other operand inside instruction.
|
| - USED_AT_END
|
| - };
|
| -
|
| - explicit LUnallocated(Policy policy) : LOperand(UNALLOCATED, 0) {
|
| - Initialize(policy, 0, USED_AT_END);
|
| - }
|
| -
|
| - LUnallocated(Policy policy, int fixed_index) : LOperand(UNALLOCATED, 0) {
|
| - Initialize(policy, fixed_index, USED_AT_END);
|
| - }
|
| -
|
| - LUnallocated(Policy policy, Lifetime lifetime) : LOperand(UNALLOCATED, 0) {
|
| - Initialize(policy, 0, lifetime);
|
| - }
|
| -
|
| - // The superclass has a KindField. Some policies have a signed fixed
|
| - // index in the upper bits.
|
| - static const int kPolicyWidth = 4;
|
| - static const int kLifetimeWidth = 1;
|
| - static const int kVirtualRegisterWidth = 17;
|
| -
|
| - static const int kPolicyShift = kKindFieldWidth;
|
| - static const int kLifetimeShift = kPolicyShift + kPolicyWidth;
|
| - static const int kVirtualRegisterShift = kLifetimeShift + kLifetimeWidth;
|
| - static const int kFixedIndexShift =
|
| - kVirtualRegisterShift + kVirtualRegisterWidth;
|
| -
|
| - class PolicyField : public BitField<Policy, kPolicyShift, kPolicyWidth> { };
|
| -
|
| - class LifetimeField
|
| - : public BitField<Lifetime, kLifetimeShift, kLifetimeWidth> {
|
| - };
|
| -
|
| - class VirtualRegisterField
|
| - : public BitField<unsigned,
|
| - kVirtualRegisterShift,
|
| - kVirtualRegisterWidth> {
|
| - };
|
| -
|
| - static const int kMaxVirtualRegisters = 1 << (kVirtualRegisterWidth + 1);
|
| - static const int kMaxFixedIndices = 128;
|
| -
|
| - bool HasIgnorePolicy() const { return policy() == IGNORE; }
|
| - bool HasNoPolicy() const { return policy() == NONE; }
|
| - bool HasAnyPolicy() const {
|
| - return policy() == ANY;
|
| - }
|
| - bool HasFixedPolicy() const {
|
| - return policy() == FIXED_REGISTER ||
|
| - policy() == FIXED_DOUBLE_REGISTER ||
|
| - policy() == FIXED_SLOT;
|
| - }
|
| - bool HasRegisterPolicy() const {
|
| - return policy() == WRITABLE_REGISTER || policy() == MUST_HAVE_REGISTER;
|
| - }
|
| - bool HasSameAsInputPolicy() const {
|
| - return policy() == SAME_AS_FIRST_INPUT;
|
| - }
|
| - Policy policy() const { return PolicyField::decode(value_); }
|
| - void set_policy(Policy policy) {
|
| - value_ &= ~PolicyField::mask();
|
| - value_ |= PolicyField::encode(policy);
|
| - }
|
| - int fixed_index() const {
|
| - return static_cast<int>(value_) >> kFixedIndexShift;
|
| - }
|
| -
|
| - unsigned virtual_register() const {
|
| - return VirtualRegisterField::decode(value_);
|
| - }
|
| -
|
| - void set_virtual_register(unsigned id) {
|
| - value_ &= ~VirtualRegisterField::mask();
|
| - value_ |= VirtualRegisterField::encode(id);
|
| - }
|
| -
|
| - LUnallocated* CopyUnconstrained() {
|
| - LUnallocated* result = new LUnallocated(ANY);
|
| - result->set_virtual_register(virtual_register());
|
| - return result;
|
| - }
|
| -
|
| - static LUnallocated* cast(LOperand* op) {
|
| - ASSERT(op->IsUnallocated());
|
| - return reinterpret_cast<LUnallocated*>(op);
|
| - }
|
| -
|
| - bool IsUsedAtStart() {
|
| - return LifetimeField::decode(value_) == USED_AT_START;
|
| - }
|
| -
|
| - private:
|
| - void Initialize(Policy policy, int fixed_index, Lifetime lifetime) {
|
| - value_ |= PolicyField::encode(policy);
|
| - value_ |= LifetimeField::encode(lifetime);
|
| - value_ |= fixed_index << kFixedIndexShift;
|
| - ASSERT(this->fixed_index() == fixed_index);
|
| - }
|
| -};
|
| -
|
| -
|
| -class LMoveOperands BASE_EMBEDDED {
|
| - public:
|
| - LMoveOperands(LOperand* source, LOperand* destination)
|
| - : source_(source), destination_(destination) {
|
| - }
|
| -
|
| - LOperand* source() const { return source_; }
|
| - void set_source(LOperand* operand) { source_ = operand; }
|
| -
|
| - LOperand* destination() const { return destination_; }
|
| - void set_destination(LOperand* operand) { destination_ = operand; }
|
| -
|
| - // The gap resolver marks moves as "in-progress" by clearing the
|
| - // destination (but not the source).
|
| - bool IsPending() const {
|
| - return destination_ == NULL && source_ != NULL;
|
| - }
|
| -
|
| - // True if this move a move into the given destination operand.
|
| - bool Blocks(LOperand* operand) const {
|
| - return !IsEliminated() && source()->Equals(operand);
|
| - }
|
| -
|
| - // A move is redundant if it's been eliminated, if its source and
|
| - // destination are the same, or if its destination is unneeded.
|
| - bool IsRedundant() const {
|
| - return IsEliminated() || source_->Equals(destination_) || IsIgnored();
|
| - }
|
| -
|
| - bool IsIgnored() const {
|
| - return destination_ != NULL &&
|
| - destination_->IsUnallocated() &&
|
| - LUnallocated::cast(destination_)->HasIgnorePolicy();
|
| - }
|
| -
|
| - // We clear both operands to indicate move that's been eliminated.
|
| - void Eliminate() { source_ = destination_ = NULL; }
|
| - bool IsEliminated() const {
|
| - ASSERT(source_ != NULL || destination_ == NULL);
|
| - return source_ == NULL;
|
| - }
|
| -
|
| - private:
|
| - LOperand* source_;
|
| - LOperand* destination_;
|
| -};
|
| -
|
| -
|
| -class LConstantOperand: public LOperand {
|
| - public:
|
| - static LConstantOperand* Create(int index) {
|
| - ASSERT(index >= 0);
|
| - if (index < kNumCachedOperands) return &cache[index];
|
| - return new LConstantOperand(index);
|
| - }
|
| -
|
| - static LConstantOperand* cast(LOperand* op) {
|
| - ASSERT(op->IsConstantOperand());
|
| - return reinterpret_cast<LConstantOperand*>(op);
|
| - }
|
| -
|
| - static void SetupCache();
|
| -
|
| - private:
|
| - static const int kNumCachedOperands = 128;
|
| - static LConstantOperand cache[];
|
| -
|
| - LConstantOperand() : LOperand() { }
|
| - explicit LConstantOperand(int index) : LOperand(CONSTANT_OPERAND, index) { }
|
| -};
|
| -
|
| -
|
| -class LArgument: public LOperand {
|
| - public:
|
| - explicit LArgument(int index) : LOperand(ARGUMENT, index) { }
|
| -
|
| - static LArgument* cast(LOperand* op) {
|
| - ASSERT(op->IsArgument());
|
| - return reinterpret_cast<LArgument*>(op);
|
| - }
|
| -};
|
| -
|
| -
|
| -class LStackSlot: public LOperand {
|
| - public:
|
| - static LStackSlot* Create(int index) {
|
| - ASSERT(index >= 0);
|
| - if (index < kNumCachedOperands) return &cache[index];
|
| - return new LStackSlot(index);
|
| - }
|
| -
|
| - static LStackSlot* cast(LOperand* op) {
|
| - ASSERT(op->IsStackSlot());
|
| - return reinterpret_cast<LStackSlot*>(op);
|
| - }
|
| -
|
| - static void SetupCache();
|
| -
|
| - private:
|
| - static const int kNumCachedOperands = 128;
|
| - static LStackSlot cache[];
|
| -
|
| - LStackSlot() : LOperand() { }
|
| - explicit LStackSlot(int index) : LOperand(STACK_SLOT, index) { }
|
| -};
|
| -
|
| -
|
| -class LDoubleStackSlot: public LOperand {
|
| - public:
|
| - static LDoubleStackSlot* Create(int index) {
|
| - ASSERT(index >= 0);
|
| - if (index < kNumCachedOperands) return &cache[index];
|
| - return new LDoubleStackSlot(index);
|
| - }
|
| -
|
| - static LDoubleStackSlot* cast(LOperand* op) {
|
| - ASSERT(op->IsStackSlot());
|
| - return reinterpret_cast<LDoubleStackSlot*>(op);
|
| - }
|
| -
|
| - static void SetupCache();
|
| -
|
| - private:
|
| - static const int kNumCachedOperands = 128;
|
| - static LDoubleStackSlot cache[];
|
| -
|
| - LDoubleStackSlot() : LOperand() { }
|
| - explicit LDoubleStackSlot(int index) : LOperand(DOUBLE_STACK_SLOT, index) { }
|
| -};
|
| -
|
| -
|
| -class LRegister: public LOperand {
|
| - public:
|
| - static LRegister* Create(int index) {
|
| - ASSERT(index >= 0);
|
| - if (index < kNumCachedOperands) return &cache[index];
|
| - return new LRegister(index);
|
| - }
|
| -
|
| - static LRegister* cast(LOperand* op) {
|
| - ASSERT(op->IsRegister());
|
| - return reinterpret_cast<LRegister*>(op);
|
| - }
|
| -
|
| - static void SetupCache();
|
| -
|
| - private:
|
| - static const int kNumCachedOperands = 16;
|
| - static LRegister cache[];
|
| -
|
| - LRegister() : LOperand() { }
|
| - explicit LRegister(int index) : LOperand(REGISTER, index) { }
|
| -};
|
| -
|
| -
|
| -class LDoubleRegister: public LOperand {
|
| - public:
|
| - static LDoubleRegister* Create(int index) {
|
| - ASSERT(index >= 0);
|
| - if (index < kNumCachedOperands) return &cache[index];
|
| - return new LDoubleRegister(index);
|
| - }
|
| -
|
| - static LDoubleRegister* cast(LOperand* op) {
|
| - ASSERT(op->IsDoubleRegister());
|
| - return reinterpret_cast<LDoubleRegister*>(op);
|
| - }
|
| -
|
| - static void SetupCache();
|
| -
|
| - private:
|
| - static const int kNumCachedOperands = 16;
|
| - static LDoubleRegister cache[];
|
| -
|
| - LDoubleRegister() : LOperand() { }
|
| - explicit LDoubleRegister(int index) : LOperand(DOUBLE_REGISTER, index) { }
|
| -};
|
| -
|
| -
|
| // A register-allocator view of a Lithium instruction. It contains the id of
|
| // the output operand and a list of input operand uses.
|
| class InstructionSummary: public ZoneObject {
|
| @@ -588,27 +241,14 @@
|
| // Representation of a use position.
|
| class UsePosition: public ZoneObject {
|
| public:
|
| - UsePosition(LifetimePosition pos, LOperand* operand)
|
| - : operand_(operand),
|
| - hint_(NULL),
|
| - pos_(pos),
|
| - next_(NULL),
|
| - requires_reg_(false),
|
| - register_beneficial_(true) {
|
| - if (operand_ != NULL && operand_->IsUnallocated()) {
|
| - LUnallocated* unalloc = LUnallocated::cast(operand_);
|
| - requires_reg_ = unalloc->HasRegisterPolicy();
|
| - register_beneficial_ = !unalloc->HasAnyPolicy();
|
| - }
|
| - ASSERT(pos_.IsValid());
|
| - }
|
| + UsePosition(LifetimePosition pos, LOperand* operand);
|
|
|
| LOperand* operand() const { return operand_; }
|
| bool HasOperand() const { return operand_ != NULL; }
|
|
|
| LOperand* hint() const { return hint_; }
|
| void set_hint(LOperand* hint) { hint_ = hint; }
|
| - bool HasHint() const { return hint_ != NULL && !hint_->IsUnallocated(); }
|
| + bool HasHint() const;
|
| bool RequiresRegister() const;
|
| bool RegisterIsBeneficial() const;
|
|
|
| @@ -634,21 +274,7 @@
|
| public:
|
| static const int kInvalidAssignment = 0x7fffffff;
|
|
|
| - explicit LiveRange(int id)
|
| - : id_(id),
|
| - spilled_(false),
|
| - assigned_register_(kInvalidAssignment),
|
| - assigned_register_kind_(NONE),
|
| - last_interval_(NULL),
|
| - first_interval_(NULL),
|
| - first_pos_(NULL),
|
| - parent_(NULL),
|
| - next_(NULL),
|
| - current_interval_(NULL),
|
| - last_processed_use_(NULL),
|
| - spill_start_index_(kMaxInt) {
|
| - spill_operand_ = new LUnallocated(LUnallocated::IGNORE);
|
| - }
|
| + explicit LiveRange(int id);
|
|
|
| UseInterval* first_interval() const { return first_interval_; }
|
| UsePosition* first_pos() const { return first_pos_; }
|
| @@ -663,19 +289,8 @@
|
| LOperand* CreateAssignedOperand();
|
| int assigned_register() const { return assigned_register_; }
|
| int spill_start_index() const { return spill_start_index_; }
|
| - void set_assigned_register(int reg, RegisterKind register_kind) {
|
| - ASSERT(!HasRegisterAssigned() && !IsSpilled());
|
| - assigned_register_ = reg;
|
| - assigned_register_kind_ = register_kind;
|
| - ConvertOperands();
|
| - }
|
| - void MakeSpilled() {
|
| - ASSERT(!IsSpilled());
|
| - ASSERT(TopLevel()->HasAllocatedSpillOperand());
|
| - spilled_ = true;
|
| - assigned_register_ = kInvalidAssignment;
|
| - ConvertOperands();
|
| - }
|
| + void set_assigned_register(int reg, RegisterKind register_kind);
|
| + void MakeSpilled();
|
|
|
| // Returns use position in this live range that follows both start
|
| // and last processed use position.
|
| @@ -724,17 +339,9 @@
|
| return last_interval_->end();
|
| }
|
|
|
| - bool HasAllocatedSpillOperand() const {
|
| - return spill_operand_ != NULL && !spill_operand_->IsUnallocated();
|
| - }
|
| -
|
| + bool HasAllocatedSpillOperand() const;
|
| LOperand* GetSpillOperand() const { return spill_operand_; }
|
| - void SetSpillOperand(LOperand* operand) {
|
| - ASSERT(!operand->IsUnallocated());
|
| - ASSERT(spill_operand_ != NULL);
|
| - ASSERT(spill_operand_->IsUnallocated());
|
| - spill_operand_->ConvertTo(operand->kind(), operand->index());
|
| - }
|
| + void SetSpillOperand(LOperand* operand);
|
|
|
| void SetSpillStartIndex(int start) {
|
| spill_start_index_ = Min(start, spill_start_index_);
|
|
|