Commit 8392d9c4 authored by dcarney's avatar dcarney Committed by Commit bot

[turbofan] Make AllocatedOperand an InstructionOperand::Kind.

This is preparatory work to have MachineTypes encoded in AllocatedOperands.

Review URL: https://codereview.chromium.org/1075863002

Cr-Commit-Position: refs/heads/master@{#27698}
parent f190a6d2
......@@ -46,19 +46,22 @@ std::ostream& operator<<(std::ostream& os,
<< "]";
case InstructionOperand::IMMEDIATE:
return os << "[immediate:" << ImmediateOperand::cast(op).index() << "]";
case InstructionOperand::STACK_SLOT:
return os << "[stack:" << StackSlotOperand::cast(op).index() << "]";
case InstructionOperand::DOUBLE_STACK_SLOT:
return os << "[double_stack:" << DoubleStackSlotOperand::cast(op).index()
<< "]";
case InstructionOperand::REGISTER:
return os << "["
<< conf->general_register_name(
RegisterOperand::cast(op).index()) << "|R]";
case InstructionOperand::DOUBLE_REGISTER:
return os << "["
<< conf->double_register_name(
DoubleRegisterOperand::cast(op).index()) << "|R]";
case InstructionOperand::ALLOCATED:
switch (AllocatedOperand::cast(op).allocated_kind()) {
case AllocatedOperand::STACK_SLOT:
return os << "[stack:" << StackSlotOperand::cast(op).index() << "]";
case AllocatedOperand::DOUBLE_STACK_SLOT:
return os << "[double_stack:"
<< DoubleStackSlotOperand::cast(op).index() << "]";
case AllocatedOperand::REGISTER:
return os << "["
<< conf->general_register_name(
RegisterOperand::cast(op).index()) << "|R]";
case AllocatedOperand::DOUBLE_REGISTER:
return os << "["
<< conf->double_register_name(
DoubleRegisterOperand::cast(op).index()) << "|R]";
}
case InstructionOperand::INVALID:
return os << "(x)";
}
......
......@@ -27,26 +27,13 @@ class Schedule;
// A couple of reserved opcodes are used for internal use.
const InstructionCode kSourcePositionInstruction = -1;
#define ALLOCATED_OPERAND_LIST(V) \
V(StackSlot, STACK_SLOT) \
V(DoubleStackSlot, DOUBLE_STACK_SLOT) \
V(Register, REGISTER) \
V(DoubleRegister, DOUBLE_REGISTER)
class InstructionOperand {
public:
static const int kInvalidVirtualRegister = -1;
enum Kind {
INVALID,
UNALLOCATED,
CONSTANT,
IMMEDIATE,
STACK_SLOT,
DOUBLE_STACK_SLOT,
REGISTER,
DOUBLE_REGISTER
};
// TODO(dcarney): recover bit. INVALID can be represented as UNALLOCATED with
// kInvalidVirtualRegister and some DCHECKS.
enum Kind { INVALID, UNALLOCATED, CONSTANT, IMMEDIATE, ALLOCATED };
InstructionOperand()
: InstructionOperand(INVALID, 0, kInvalidVirtualRegister) {}
......@@ -55,13 +42,18 @@ class InstructionOperand {
#define INSTRUCTION_OPERAND_PREDICATE(name, type) \
bool Is##name() const { return kind() == type; }
ALLOCATED_OPERAND_LIST(INSTRUCTION_OPERAND_PREDICATE)
INSTRUCTION_OPERAND_PREDICATE(Invalid, INVALID)
INSTRUCTION_OPERAND_PREDICATE(Unallocated, UNALLOCATED)
INSTRUCTION_OPERAND_PREDICATE(Constant, CONSTANT)
INSTRUCTION_OPERAND_PREDICATE(Immediate, IMMEDIATE)
INSTRUCTION_OPERAND_PREDICATE(Unallocated, UNALLOCATED)
INSTRUCTION_OPERAND_PREDICATE(Invalid, INVALID)
INSTRUCTION_OPERAND_PREDICATE(Allocated, ALLOCATED)
#undef INSTRUCTION_OPERAND_PREDICATE
inline bool IsRegister() const;
inline bool IsDoubleRegister() const;
inline bool IsStackSlot() const;
inline bool IsDoubleStackSlot() const;
bool Equals(const InstructionOperand* other) const {
return value_ == other->value_;
}
......@@ -84,7 +76,6 @@ class InstructionOperand {
protected:
InstructionOperand(Kind kind, int index, int virtual_register) {
if (kind == REGISTER || kind == DOUBLE_REGISTER) DCHECK(index >= 0);
if (kind != UNALLOCATED && kind != CONSTANT) {
DCHECK(virtual_register == kInvalidVirtualRegister);
}
......@@ -109,6 +100,23 @@ struct PrintableInstructionOperand {
std::ostream& operator<<(std::ostream& os,
const PrintableInstructionOperand& op);
#define INSTRUCTION_OPERAND_CASTS(OperandType, OperandKind) \
\
static OperandType* cast(InstructionOperand* op) { \
DCHECK_EQ(OperandKind, op->kind()); \
return static_cast<OperandType*>(op); \
} \
\
static const OperandType* cast(const InstructionOperand* op) { \
DCHECK_EQ(OperandKind, op->kind()); \
return static_cast<const OperandType*>(op); \
} \
\
static OperandType cast(const InstructionOperand& op) { \
DCHECK_EQ(OperandKind, op.kind()); \
return *static_cast<const OperandType*>(&op); \
}
class UnallocatedOperand : public InstructionOperand {
public:
enum BasicPolicy { FIXED_SLOT, EXTENDED_POLICY };
......@@ -175,21 +183,6 @@ class UnallocatedOperand : public InstructionOperand {
return New(zone, UnallocatedOperand(ANY, virtual_register()));
}
static const UnallocatedOperand* cast(const InstructionOperand* op) {
DCHECK(op->IsUnallocated());
return static_cast<const UnallocatedOperand*>(op);
}
static UnallocatedOperand* cast(InstructionOperand* op) {
DCHECK(op->IsUnallocated());
return static_cast<UnallocatedOperand*>(op);
}
static UnallocatedOperand cast(const InstructionOperand& op) {
DCHECK(op.IsUnallocated());
return *static_cast<const UnallocatedOperand*>(&op);
}
// The encoding used for UnallocatedOperand operands depends on the policy
// that is
// stored within the operand. The FIXED_SLOT policy uses a compact encoding
......@@ -297,6 +290,8 @@ class UnallocatedOperand : public InstructionOperand {
DCHECK(basic_policy() == EXTENDED_POLICY);
return LifetimeField::decode(value_) == USED_AT_START;
}
INSTRUCTION_OPERAND_CASTS(UnallocatedOperand, UNALLOCATED);
};
......@@ -313,20 +308,7 @@ class ConstantOperand : public InstructionOperand {
return InstructionOperand::New(zone, ConstantOperand(virtual_register));
}
static ConstantOperand* cast(InstructionOperand* op) {
DCHECK(op->kind() == CONSTANT);
return static_cast<ConstantOperand*>(op);
}
static const ConstantOperand* cast(const InstructionOperand* op) {
DCHECK(op->kind() == CONSTANT);
return static_cast<const ConstantOperand*>(op);
}
static ConstantOperand cast(const InstructionOperand& op) {
DCHECK(op.kind() == CONSTANT);
return *static_cast<const ConstantOperand*>(&op);
}
INSTRUCTION_OPERAND_CASTS(ConstantOperand, CONSTANT);
};
......@@ -343,93 +325,91 @@ class ImmediateOperand : public InstructionOperand {
return InstructionOperand::New(zone, ImmediateOperand(index));
}
static ImmediateOperand* cast(InstructionOperand* op) {
DCHECK(op->kind() == IMMEDIATE);
return static_cast<ImmediateOperand*>(op);
}
static const ImmediateOperand* cast(const InstructionOperand* op) {
DCHECK(op->kind() == IMMEDIATE);
return static_cast<const ImmediateOperand*>(op);
}
static ImmediateOperand cast(const InstructionOperand& op) {
DCHECK(op.kind() == IMMEDIATE);
return *static_cast<const ImmediateOperand*>(&op);
}
INSTRUCTION_OPERAND_CASTS(ImmediateOperand, IMMEDIATE);
};
class AllocatedOperand : public InstructionOperand {
#define ALLOCATED_OPERAND_CHECK(Name, Kind) || kind == Kind
#define CHECK_ALLOCATED_KIND() \
DCHECK(false ALLOCATED_OPERAND_LIST(ALLOCATED_OPERAND_CHECK)); \
USE(kind);
public:
enum AllocatedKind {
STACK_SLOT,
DOUBLE_STACK_SLOT,
REGISTER,
DOUBLE_REGISTER
};
AllocatedOperand(AllocatedKind kind, int index)
: InstructionOperand(ALLOCATED, index, kInvalidVirtualRegister) {
if (kind == REGISTER || kind == DOUBLE_REGISTER) DCHECK(index >= 0);
value_ = AllocatedKindField::update(value_, kind);
}
int index() const {
return static_cast<int64_t>(value_) >> IndexField::kShift;
}
AllocatedOperand(Kind kind, int index)
: InstructionOperand(kind, index, kInvalidVirtualRegister) {
CHECK_ALLOCATED_KIND();
AllocatedKind allocated_kind() const {
return AllocatedKindField::decode(value_);
}
static AllocatedOperand* New(Zone* zone, Kind kind, int index) {
static AllocatedOperand* New(Zone* zone, AllocatedKind kind, int index) {
return InstructionOperand::New(zone, AllocatedOperand(kind, index));
}
static AllocatedOperand* cast(InstructionOperand* op) {
Kind kind = op->kind();
CHECK_ALLOCATED_KIND();
return static_cast<AllocatedOperand*>(op);
}
INSTRUCTION_OPERAND_CASTS(AllocatedOperand, ALLOCATED);
static const AllocatedOperand* cast(const InstructionOperand* op) {
Kind kind = op->kind();
CHECK_ALLOCATED_KIND();
return static_cast<const AllocatedOperand*>(op);
}
private:
typedef BitField64<AllocatedKind, 3, 2> AllocatedKindField;
};
static AllocatedOperand cast(const InstructionOperand& op) {
Kind kind = op.kind();
CHECK_ALLOCATED_KIND();
return *static_cast<const AllocatedOperand*>(&op);
}
#undef CHECK_ALLOCATED_KIND
#undef ALLOCATED_OPERAND_CAST_CHECK
};
#undef INSTRUCTION_OPERAND_CASTS
#define ALLOCATED_OPERAND_LIST(V) \
V(StackSlot, STACK_SLOT) \
V(DoubleStackSlot, DOUBLE_STACK_SLOT) \
V(Register, REGISTER) \
V(DoubleRegister, DOUBLE_REGISTER)
#define INSTRUCTION_SUBKIND_OPERAND_CLASS(SubKind, kOperandKind) \
class SubKind##Operand FINAL : public AllocatedOperand { \
public: \
explicit SubKind##Operand(int index) \
: AllocatedOperand(kOperandKind, index) {} \
\
static SubKind##Operand* New(Zone* zone, int index) { \
return InstructionOperand::New(zone, SubKind##Operand(index)); \
} \
\
static SubKind##Operand* cast(InstructionOperand* op) { \
DCHECK(op->kind() == kOperandKind); \
return reinterpret_cast<SubKind##Operand*>(op); \
} \
\
static const SubKind##Operand* cast(const InstructionOperand* op) { \
DCHECK(op->kind() == kOperandKind); \
return reinterpret_cast<const SubKind##Operand*>(op); \
} \
\
static SubKind##Operand cast(const InstructionOperand& op) { \
DCHECK(op.kind() == kOperandKind); \
return *static_cast<const SubKind##Operand*>(&op); \
} \
#define ALLOCATED_OPERAND_IS(SubKind, kOperandKind) \
bool InstructionOperand::Is##SubKind() const { \
return IsAllocated() && \
AllocatedOperand::cast(this)->allocated_kind() == \
AllocatedOperand::kOperandKind; \
}
ALLOCATED_OPERAND_LIST(ALLOCATED_OPERAND_IS)
#undef ALLOCATED_OPERAND_IS
#define ALLOCATED_OPERAND_CLASS(SubKind, kOperandKind) \
class SubKind##Operand FINAL : public AllocatedOperand { \
public: \
explicit SubKind##Operand(int index) \
: AllocatedOperand(kOperandKind, index) {} \
\
static SubKind##Operand* New(Zone* zone, int index) { \
return InstructionOperand::New(zone, SubKind##Operand(index)); \
} \
\
static SubKind##Operand* cast(InstructionOperand* op) { \
DCHECK_EQ(kOperandKind, AllocatedOperand::cast(op)->allocated_kind()); \
return reinterpret_cast<SubKind##Operand*>(op); \
} \
\
static const SubKind##Operand* cast(const InstructionOperand* op) { \
DCHECK_EQ(kOperandKind, AllocatedOperand::cast(op)->allocated_kind()); \
return reinterpret_cast<const SubKind##Operand*>(op); \
} \
\
static SubKind##Operand cast(const InstructionOperand& op) { \
DCHECK_EQ(kOperandKind, AllocatedOperand::cast(op).allocated_kind()); \
return *static_cast<const SubKind##Operand*>(&op); \
} \
};
ALLOCATED_OPERAND_LIST(INSTRUCTION_SUBKIND_OPERAND_CLASS)
#undef INSTRUCTION_SUBKIND_OPERAND_CLASS
ALLOCATED_OPERAND_LIST(ALLOCATED_OPERAND_CLASS)
#undef ALLOCATED_OPERAND_CLASS
class MoveOperands FINAL {
......
......@@ -707,13 +707,13 @@ InstructionOperand* RegisterAllocator::AllocateFixed(
DCHECK(operand->HasFixedPolicy());
InstructionOperand allocated;
if (operand->HasFixedSlotPolicy()) {
allocated = AllocatedOperand(InstructionOperand::STACK_SLOT,
allocated = AllocatedOperand(AllocatedOperand::STACK_SLOT,
operand->fixed_slot_index());
} else if (operand->HasFixedRegisterPolicy()) {
allocated = AllocatedOperand(InstructionOperand::REGISTER,
allocated = AllocatedOperand(AllocatedOperand::REGISTER,
operand->fixed_register_index());
} else if (operand->HasFixedDoubleRegisterPolicy()) {
allocated = AllocatedOperand(InstructionOperand::DOUBLE_REGISTER,
allocated = AllocatedOperand(AllocatedOperand::DOUBLE_REGISTER,
operand->fixed_register_index());
} else {
UNREACHABLE();
......@@ -976,8 +976,8 @@ void RegisterAllocator::AssignSpillSlots() {
auto kind = range->Kind();
int index = frame()->AllocateSpillSlot(kind == DOUBLE_REGISTERS);
auto op_kind = kind == DOUBLE_REGISTERS
? InstructionOperand::DOUBLE_STACK_SLOT
: InstructionOperand::STACK_SLOT;
? AllocatedOperand::DOUBLE_STACK_SLOT
: AllocatedOperand::STACK_SLOT;
auto op = AllocatedOperand::New(code_zone(), op_kind, index);
range->SetOperand(op);
}
......
......@@ -32,8 +32,28 @@ class InterpreterState {
}
private:
struct Key {
bool is_constant;
AllocatedOperand::AllocatedKind kind;
int index;
bool operator<(const Key& other) const {
if (this->is_constant != other.is_constant) {
return this->is_constant;
}
if (this->kind != other.kind) {
return this->kind < other.kind;
}
return this->index < other.index;
}
bool operator==(const Key& other) const {
return this->is_constant == other.is_constant &&
this->kind == other.kind && this->index == other.index;
}
};
// Internally, the state is a normalized permutation of (kind,index) pairs.
typedef std::pair<InstructionOperand::Kind, int> Key;
typedef Key Value;
typedef std::map<Key, Value> OperandMap;
......@@ -51,22 +71,27 @@ class InterpreterState {
}
static Key KeyFor(const InstructionOperand* op) {
int v = op->IsConstant() ? ConstantOperand::cast(op)->virtual_register()
: AllocatedOperand::cast(op)->index();
return Key(op->kind(), v);
bool is_constant = op->IsConstant();
AllocatedOperand::AllocatedKind kind;
int index;
if (!is_constant) {
index = AllocatedOperand::cast(op)->index();
kind = AllocatedOperand::cast(op)->allocated_kind();
} else {
index = ConstantOperand::cast(op)->virtual_register();
kind = AllocatedOperand::REGISTER;
}
Key key = {is_constant, kind, index};
return key;
}
static Value ValueFor(const InstructionOperand* op) {
int v = op->IsConstant() ? ConstantOperand::cast(op)->virtual_register()
: AllocatedOperand::cast(op)->index();
return Value(op->kind(), v);
}
static Value ValueFor(const InstructionOperand* op) { return KeyFor(op); }
static InstructionOperand FromKey(Key key) {
if (key.first == InstructionOperand::CONSTANT) {
return ConstantOperand(key.second);
if (key.is_constant) {
return ConstantOperand(key.index);
}
return AllocatedOperand(key.first, key.second);
return AllocatedOperand(key.kind, key.index);
}
friend std::ostream& operator<<(std::ostream& os,
......
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