From 8392d9c43bd2a7d482b7fb03e85f6b449de82087 Mon Sep 17 00:00:00 2001 From: dcarney Date: Thu, 9 Apr 2015 03:40:41 -0700 Subject: [PATCH] [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} --- src/compiler/instruction.cc | 29 ++-- src/compiler/instruction.h | 212 ++++++++++++++---------------- src/compiler/register-allocator.cc | 10 +- test/cctest/compiler/test-gap-resolver.cc | 49 +++++-- 4 files changed, 154 insertions(+), 146 deletions(-) diff --git a/src/compiler/instruction.cc b/src/compiler/instruction.cc index 177de6f..62bd5b7 100644 --- a/src/compiler/instruction.cc +++ b/src/compiler/instruction.cc @@ -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)"; } diff --git a/src/compiler/instruction.h b/src/compiler/instruction.h index 3615e37..4d6538c 100644 --- a/src/compiler/instruction.h +++ b/src/compiler/instruction.h @@ -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(op); \ + } \ + \ + static const OperandType* cast(const InstructionOperand* op) { \ + DCHECK_EQ(OperandKind, op->kind()); \ + return static_cast(op); \ + } \ + \ + static OperandType cast(const InstructionOperand& op) { \ + DCHECK_EQ(OperandKind, op.kind()); \ + return *static_cast(&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(op); - } - - static UnallocatedOperand* cast(InstructionOperand* op) { - DCHECK(op->IsUnallocated()); - return static_cast(op); - } - - static UnallocatedOperand cast(const InstructionOperand& op) { - DCHECK(op.IsUnallocated()); - return *static_cast(&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(op); - } - - static const ConstantOperand* cast(const InstructionOperand* op) { - DCHECK(op->kind() == CONSTANT); - return static_cast(op); - } - - static ConstantOperand cast(const InstructionOperand& op) { - DCHECK(op.kind() == CONSTANT); - return *static_cast(&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(op); - } - - static const ImmediateOperand* cast(const InstructionOperand* op) { - DCHECK(op->kind() == IMMEDIATE); - return static_cast(op); - } - - static ImmediateOperand cast(const InstructionOperand& op) { - DCHECK(op.kind() == IMMEDIATE); - return *static_cast(&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(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(op); - } + INSTRUCTION_OPERAND_CASTS(AllocatedOperand, ALLOCATED); - static const AllocatedOperand* cast(const InstructionOperand* op) { - Kind kind = op->kind(); - CHECK_ALLOCATED_KIND(); - return static_cast(op); - } + private: + typedef BitField64 AllocatedKindField; +}; - static AllocatedOperand cast(const InstructionOperand& op) { - Kind kind = op.kind(); - CHECK_ALLOCATED_KIND(); - return *static_cast(&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(op); \ - } \ - \ - static const SubKind##Operand* cast(const InstructionOperand* op) { \ - DCHECK(op->kind() == kOperandKind); \ - return reinterpret_cast(op); \ - } \ - \ - static SubKind##Operand cast(const InstructionOperand& op) { \ - DCHECK(op.kind() == kOperandKind); \ - return *static_cast(&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(op); \ + } \ + \ + static const SubKind##Operand* cast(const InstructionOperand* op) { \ + DCHECK_EQ(kOperandKind, AllocatedOperand::cast(op)->allocated_kind()); \ + return reinterpret_cast(op); \ + } \ + \ + static SubKind##Operand cast(const InstructionOperand& op) { \ + DCHECK_EQ(kOperandKind, AllocatedOperand::cast(op).allocated_kind()); \ + return *static_cast(&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 { diff --git a/src/compiler/register-allocator.cc b/src/compiler/register-allocator.cc index 33211c9..f3875f7 100644 --- a/src/compiler/register-allocator.cc +++ b/src/compiler/register-allocator.cc @@ -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); } diff --git a/test/cctest/compiler/test-gap-resolver.cc b/test/cctest/compiler/test-gap-resolver.cc index a7664e0..caf9a62 100644 --- a/test/cctest/compiler/test-gap-resolver.cc +++ b/test/cctest/compiler/test-gap-resolver.cc @@ -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 Key; typedef Key Value; typedef std::map 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, -- 2.7.4