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