From ac0b1ded7b23dcda04959ebad09ff81479cb7fb5 Mon Sep 17 00:00:00 2001 From: "fschneider@chromium.org" Date: Wed, 19 Jan 2011 13:55:56 +0000 Subject: [PATCH] Move LOperand class to lithium.h and move implementations out of .h into .cc files. Review URL: http://codereview.chromium.org/6378004 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6400 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/compiler.cc | 2 +- src/ia32/lithium-gap-resolver-ia32.h | 2 +- src/lithium-allocator.cc | 126 ++++++----- src/lithium-allocator.h | 411 +---------------------------------- src/lithium.cc | 72 ++++++ src/lithium.h | 350 ++++++++++++++++++++++++++++- 6 files changed, 494 insertions(+), 469 deletions(-) diff --git a/src/compiler.cc b/src/compiler.cc index bbe7f2f..5c18c3e 100755 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -37,7 +37,7 @@ #include "full-codegen.h" #include "gdb-jit.h" #include "hydrogen.h" -#include "lithium-allocator.h" +#include "lithium.h" #include "liveedit.h" #include "oprofile-agent.h" #include "parser.h" diff --git a/src/ia32/lithium-gap-resolver-ia32.h b/src/ia32/lithium-gap-resolver-ia32.h index f0bd260..0c81d72 100644 --- a/src/ia32/lithium-gap-resolver-ia32.h +++ b/src/ia32/lithium-gap-resolver-ia32.h @@ -30,7 +30,7 @@ #include "v8.h" -#include "lithium-allocator.h" +#include "lithium.h" namespace v8 { namespace internal { diff --git a/src/lithium-allocator.cc b/src/lithium-allocator.cc index 2bbc6b6..66f5a81 100644 --- a/src/lithium-allocator.cc +++ b/src/lithium-allocator.cc @@ -71,73 +71,24 @@ static inline LifetimePosition Max(LifetimePosition a, LifetimePosition b) { } -void LOperand::PrintTo(StringStream* stream) { - LUnallocated* unalloc = NULL; - switch (kind()) { - case INVALID: - break; - case UNALLOCATED: - unalloc = LUnallocated::cast(this); - stream->Add("v%d", unalloc->virtual_register()); - switch (unalloc->policy()) { - case LUnallocated::NONE: - break; - case LUnallocated::FIXED_REGISTER: { - const char* register_name = - Register::AllocationIndexToString(unalloc->fixed_index()); - stream->Add("(=%s)", register_name); - break; - } - case LUnallocated::FIXED_DOUBLE_REGISTER: { - const char* double_register_name = - DoubleRegister::AllocationIndexToString(unalloc->fixed_index()); - stream->Add("(=%s)", double_register_name); - break; - } - case LUnallocated::FIXED_SLOT: - stream->Add("(=%dS)", unalloc->fixed_index()); - break; - case LUnallocated::MUST_HAVE_REGISTER: - stream->Add("(R)"); - break; - case LUnallocated::WRITABLE_REGISTER: - stream->Add("(WR)"); - break; - case LUnallocated::SAME_AS_FIRST_INPUT: - stream->Add("(1)"); - break; - case LUnallocated::ANY: - stream->Add("(-)"); - break; - case LUnallocated::IGNORE: - stream->Add("(0)"); - break; - } - break; - case CONSTANT_OPERAND: - stream->Add("[constant:%d]", index()); - break; - case STACK_SLOT: - stream->Add("[stack:%d]", index()); - break; - case DOUBLE_STACK_SLOT: - stream->Add("[double_stack:%d]", index()); - break; - case REGISTER: - stream->Add("[%s|R]", Register::AllocationIndexToString(index())); - break; - case DOUBLE_REGISTER: - stream->Add("[%s|R]", DoubleRegister::AllocationIndexToString(index())); - break; - case ARGUMENT: - stream->Add("[arg:%d]", index()); - break; +UsePosition::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()); } -int LOperand::VirtualRegister() { - LUnallocated* unalloc = LUnallocated::cast(this); - return unalloc->virtual_register(); + +bool UsePosition::HasHint() const { + return hint_ != NULL && !hint_->IsUnallocated(); } @@ -190,6 +141,53 @@ bool LiveRange::HasOverlap(UseInterval* target) const { #endif +LiveRange::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); +} + + +void LiveRange::set_assigned_register(int reg, RegisterKind register_kind) { + ASSERT(!HasRegisterAssigned() && !IsSpilled()); + assigned_register_ = reg; + assigned_register_kind_ = register_kind; + ConvertOperands(); +} + + +void LiveRange::MakeSpilled() { + ASSERT(!IsSpilled()); + ASSERT(TopLevel()->HasAllocatedSpillOperand()); + spilled_ = true; + assigned_register_ = kInvalidAssignment; + ConvertOperands(); +} + + +bool LiveRange::HasAllocatedSpillOperand() const { + return spill_operand_ != NULL && !spill_operand_->IsUnallocated(); +} + + +void LiveRange::SetSpillOperand(LOperand* operand) { + ASSERT(!operand->IsUnallocated()); + ASSERT(spill_operand_ != NULL); + ASSERT(spill_operand_->IsUnallocated()); + spill_operand_->ConvertTo(operand->kind(), operand->index()); +} + + UsePosition* LiveRange::NextUsePosition(LifetimePosition start) { UsePosition* use_pos = last_processed_use_; if (use_pos == NULL) use_pos = first_pos(); diff --git a/src/lithium-allocator.h b/src/lithium-allocator.h index 48c6563..1a01378 100644 --- a/src/lithium-allocator.h +++ b/src/lithium-allocator.h @@ -48,6 +48,8 @@ class StringStream; class LArgument; class LChunk; +class LOperand; +class LUnallocated; class LConstantOperand; class LGap; class LParallelMove; @@ -149,355 +151,6 @@ enum RegisterKind { }; -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(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 { }; - - 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 { }; - - class LifetimeField - : public BitField { - }; - - class VirtualRegisterField - : public BitField { - }; - - 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(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(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(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(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(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(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(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(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 @@ class UseInterval: public ZoneObject { // 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 @@ class LiveRange: public ZoneObject { 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 @@ class LiveRange: public ZoneObject { 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 @@ class LiveRange: public ZoneObject { 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_); diff --git a/src/lithium.cc b/src/lithium.cc index d6cff25..e829f2f 100644 --- a/src/lithium.cc +++ b/src/lithium.cc @@ -30,6 +30,78 @@ namespace v8 { namespace internal { + +void LOperand::PrintTo(StringStream* stream) { + LUnallocated* unalloc = NULL; + switch (kind()) { + case INVALID: + break; + case UNALLOCATED: + unalloc = LUnallocated::cast(this); + stream->Add("v%d", unalloc->virtual_register()); + switch (unalloc->policy()) { + case LUnallocated::NONE: + break; + case LUnallocated::FIXED_REGISTER: { + const char* register_name = + Register::AllocationIndexToString(unalloc->fixed_index()); + stream->Add("(=%s)", register_name); + break; + } + case LUnallocated::FIXED_DOUBLE_REGISTER: { + const char* double_register_name = + DoubleRegister::AllocationIndexToString(unalloc->fixed_index()); + stream->Add("(=%s)", double_register_name); + break; + } + case LUnallocated::FIXED_SLOT: + stream->Add("(=%dS)", unalloc->fixed_index()); + break; + case LUnallocated::MUST_HAVE_REGISTER: + stream->Add("(R)"); + break; + case LUnallocated::WRITABLE_REGISTER: + stream->Add("(WR)"); + break; + case LUnallocated::SAME_AS_FIRST_INPUT: + stream->Add("(1)"); + break; + case LUnallocated::ANY: + stream->Add("(-)"); + break; + case LUnallocated::IGNORE: + stream->Add("(0)"); + break; + } + break; + case CONSTANT_OPERAND: + stream->Add("[constant:%d]", index()); + break; + case STACK_SLOT: + stream->Add("[stack:%d]", index()); + break; + case DOUBLE_STACK_SLOT: + stream->Add("[double_stack:%d]", index()); + break; + case REGISTER: + stream->Add("[%s|R]", Register::AllocationIndexToString(index())); + break; + case DOUBLE_REGISTER: + stream->Add("[%s|R]", DoubleRegister::AllocationIndexToString(index())); + break; + case ARGUMENT: + stream->Add("[arg:%d]", index()); + break; + } +} + + +int LOperand::VirtualRegister() { + LUnallocated* unalloc = LUnallocated::cast(this); + return unalloc->virtual_register(); +} + + bool LParallelMove::IsRedundant() const { for (int i = 0; i < move_operands_.length(); ++i) { if (!move_operands_[i].IsRedundant()) return false; diff --git a/src/lithium.h b/src/lithium.h index 5f7c92f..e1b6fc0 100644 --- a/src/lithium.h +++ b/src/lithium.h @@ -29,12 +29,360 @@ #define V8_LITHIUM_H_ #include "hydrogen.h" -#include "lithium-allocator.h" #include "safepoint-table.h" namespace v8 { namespace internal { +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(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 { }; + + 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 { }; + + class LifetimeField + : public BitField { + }; + + class VirtualRegisterField + : public BitField { + }; + + 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(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(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(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(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(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(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(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(op); + } + + static void SetupCache(); + + private: + static const int kNumCachedOperands = 16; + static LDoubleRegister cache[]; + + LDoubleRegister() : LOperand() { } + explicit LDoubleRegister(int index) : LOperand(DOUBLE_REGISTER, index) { } +}; + + class LParallelMove : public ZoneObject { public: LParallelMove() : move_operands_(4) { } -- 2.7.4