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
parent 93a0b806
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
#include "full-codegen.h" #include "full-codegen.h"
#include "gdb-jit.h" #include "gdb-jit.h"
#include "hydrogen.h" #include "hydrogen.h"
#include "lithium-allocator.h" #include "lithium.h"
#include "liveedit.h" #include "liveedit.h"
#include "oprofile-agent.h" #include "oprofile-agent.h"
#include "parser.h" #include "parser.h"
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#include "v8.h" #include "v8.h"
#include "lithium-allocator.h" #include "lithium.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
......
...@@ -71,73 +71,24 @@ static inline LifetimePosition Max(LifetimePosition a, LifetimePosition b) { ...@@ -71,73 +71,24 @@ static inline LifetimePosition Max(LifetimePosition a, LifetimePosition b) {
} }
void LOperand::PrintTo(StringStream* stream) { UsePosition::UsePosition(LifetimePosition pos, LOperand* operand)
LUnallocated* unalloc = NULL; : operand_(operand),
switch (kind()) { hint_(NULL),
case INVALID: pos_(pos),
break; next_(NULL),
case UNALLOCATED: requires_reg_(false),
unalloc = LUnallocated::cast(this); register_beneficial_(true) {
stream->Add("v%d", unalloc->virtual_register()); if (operand_ != NULL && operand_->IsUnallocated()) {
switch (unalloc->policy()) { LUnallocated* unalloc = LUnallocated::cast(operand_);
case LUnallocated::NONE: requires_reg_ = unalloc->HasRegisterPolicy();
break; register_beneficial_ = !unalloc->HasAnyPolicy();
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;
} }
ASSERT(pos_.IsValid());
} }
int LOperand::VirtualRegister() {
LUnallocated* unalloc = LUnallocated::cast(this); bool UsePosition::HasHint() const {
return unalloc->virtual_register(); return hint_ != NULL && !hint_->IsUnallocated();
} }
...@@ -190,6 +141,53 @@ bool LiveRange::HasOverlap(UseInterval* target) const { ...@@ -190,6 +141,53 @@ bool LiveRange::HasOverlap(UseInterval* target) const {
#endif #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* LiveRange::NextUsePosition(LifetimePosition start) {
UsePosition* use_pos = last_processed_use_; UsePosition* use_pos = last_processed_use_;
if (use_pos == NULL) use_pos = first_pos(); if (use_pos == NULL) use_pos = first_pos();
......
...@@ -48,6 +48,8 @@ class StringStream; ...@@ -48,6 +48,8 @@ class StringStream;
class LArgument; class LArgument;
class LChunk; class LChunk;
class LOperand;
class LUnallocated;
class LConstantOperand; class LConstantOperand;
class LGap; class LGap;
class LParallelMove; class LParallelMove;
...@@ -149,355 +151,6 @@ enum RegisterKind { ...@@ -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<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 // A register-allocator view of a Lithium instruction. It contains the id of
// the output operand and a list of input operand uses. // the output operand and a list of input operand uses.
class InstructionSummary: public ZoneObject { class InstructionSummary: public ZoneObject {
...@@ -588,27 +241,14 @@ class UseInterval: public ZoneObject { ...@@ -588,27 +241,14 @@ class UseInterval: public ZoneObject {
// Representation of a use position. // Representation of a use position.
class UsePosition: public ZoneObject { class UsePosition: public ZoneObject {
public: public:
UsePosition(LifetimePosition pos, LOperand* operand) 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());
}
LOperand* operand() const { return operand_; } LOperand* operand() const { return operand_; }
bool HasOperand() const { return operand_ != NULL; } bool HasOperand() const { return operand_ != NULL; }
LOperand* hint() const { return hint_; } LOperand* hint() const { return hint_; }
void set_hint(LOperand* hint) { hint_ = hint; } void set_hint(LOperand* hint) { hint_ = hint; }
bool HasHint() const { return hint_ != NULL && !hint_->IsUnallocated(); } bool HasHint() const;
bool RequiresRegister() const; bool RequiresRegister() const;
bool RegisterIsBeneficial() const; bool RegisterIsBeneficial() const;
...@@ -634,21 +274,7 @@ class LiveRange: public ZoneObject { ...@@ -634,21 +274,7 @@ class LiveRange: public ZoneObject {
public: public:
static const int kInvalidAssignment = 0x7fffffff; static const int kInvalidAssignment = 0x7fffffff;
explicit LiveRange(int id) 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);
}
UseInterval* first_interval() const { return first_interval_; } UseInterval* first_interval() const { return first_interval_; }
UsePosition* first_pos() const { return first_pos_; } UsePosition* first_pos() const { return first_pos_; }
...@@ -663,19 +289,8 @@ class LiveRange: public ZoneObject { ...@@ -663,19 +289,8 @@ class LiveRange: public ZoneObject {
LOperand* CreateAssignedOperand(); LOperand* CreateAssignedOperand();
int assigned_register() const { return assigned_register_; } int assigned_register() const { return assigned_register_; }
int spill_start_index() const { return spill_start_index_; } int spill_start_index() const { return spill_start_index_; }
void set_assigned_register(int reg, RegisterKind register_kind) { void set_assigned_register(int reg, RegisterKind register_kind);
ASSERT(!HasRegisterAssigned() && !IsSpilled()); void MakeSpilled();
assigned_register_ = reg;
assigned_register_kind_ = register_kind;
ConvertOperands();
}
void MakeSpilled() {
ASSERT(!IsSpilled());
ASSERT(TopLevel()->HasAllocatedSpillOperand());
spilled_ = true;
assigned_register_ = kInvalidAssignment;
ConvertOperands();
}
// Returns use position in this live range that follows both start // Returns use position in this live range that follows both start
// and last processed use position. // and last processed use position.
...@@ -724,17 +339,9 @@ class LiveRange: public ZoneObject { ...@@ -724,17 +339,9 @@ class LiveRange: public ZoneObject {
return last_interval_->end(); return last_interval_->end();
} }
bool HasAllocatedSpillOperand() const { bool HasAllocatedSpillOperand() const;
return spill_operand_ != NULL && !spill_operand_->IsUnallocated();
}
LOperand* GetSpillOperand() const { return spill_operand_; } LOperand* GetSpillOperand() const { return spill_operand_; }
void SetSpillOperand(LOperand* operand) { void SetSpillOperand(LOperand* operand);
ASSERT(!operand->IsUnallocated());
ASSERT(spill_operand_ != NULL);
ASSERT(spill_operand_->IsUnallocated());
spill_operand_->ConvertTo(operand->kind(), operand->index());
}
void SetSpillStartIndex(int start) { void SetSpillStartIndex(int start) {
spill_start_index_ = Min(start, spill_start_index_); spill_start_index_ = Min(start, spill_start_index_);
......
...@@ -30,6 +30,78 @@ ...@@ -30,6 +30,78 @@
namespace v8 { namespace v8 {
namespace internal { 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 { bool LParallelMove::IsRedundant() const {
for (int i = 0; i < move_operands_.length(); ++i) { for (int i = 0; i < move_operands_.length(); ++i) {
if (!move_operands_[i].IsRedundant()) return false; if (!move_operands_[i].IsRedundant()) return false;
......
...@@ -29,12 +29,360 @@ ...@@ -29,12 +29,360 @@
#define V8_LITHIUM_H_ #define V8_LITHIUM_H_
#include "hydrogen.h" #include "hydrogen.h"
#include "lithium-allocator.h"
#include "safepoint-table.h" #include "safepoint-table.h"
namespace v8 { namespace v8 {
namespace internal { 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<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) { }
};
class LParallelMove : public ZoneObject { class LParallelMove : public ZoneObject {
public: public:
LParallelMove() : move_operands_(4) { } LParallelMove() : move_operands_(4) { }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment