diff options
Diffstat (limited to 'deps/v8/src/compiler/instruction.h')
-rw-r--r-- | deps/v8/src/compiler/instruction.h | 806 |
1 files changed, 452 insertions, 354 deletions
diff --git a/deps/v8/src/compiler/instruction.h b/deps/v8/src/compiler/instruction.h index 38fc433744..39fdb2aab3 100644 --- a/deps/v8/src/compiler/instruction.h +++ b/deps/v8/src/compiler/instruction.h @@ -24,109 +24,97 @@ namespace compiler { class Schedule; -// A couple of reserved opcodes are used for internal use. -const InstructionCode kGapInstruction = -1; -const InstructionCode kSourcePositionInstruction = -2; - -#define INSTRUCTION_OPERAND_LIST(V) \ - V(Constant, CONSTANT) \ - V(Immediate, IMMEDIATE) \ - 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 - }; - - InstructionOperand() { ConvertTo(INVALID, 0, kInvalidVirtualRegister); } + // TODO(dcarney): recover bit. INVALID can be represented as UNALLOCATED with + // kInvalidVirtualRegister and some DCHECKS. + enum Kind { INVALID, UNALLOCATED, CONSTANT, IMMEDIATE, ALLOCATED }; - InstructionOperand(Kind kind, int index) { - DCHECK(kind != UNALLOCATED && kind != INVALID); - ConvertTo(kind, index, kInvalidVirtualRegister); - } - - static InstructionOperand* New(Zone* zone, Kind kind, int index) { - return New(zone, InstructionOperand(kind, index)); - } + InstructionOperand() : InstructionOperand(INVALID) {} Kind kind() const { return KindField::decode(value_); } - // TODO(dcarney): move this to subkind operand. - int index() const { - DCHECK(kind() != UNALLOCATED && kind() != INVALID); - return static_cast<int64_t>(value_) >> IndexField::kShift; - } + #define INSTRUCTION_OPERAND_PREDICATE(name, type) \ bool Is##name() const { return kind() == type; } - INSTRUCTION_OPERAND_LIST(INSTRUCTION_OPERAND_PREDICATE) - INSTRUCTION_OPERAND_PREDICATE(Unallocated, UNALLOCATED) INSTRUCTION_OPERAND_PREDICATE(Invalid, INVALID) + INSTRUCTION_OPERAND_PREDICATE(Unallocated, UNALLOCATED) + INSTRUCTION_OPERAND_PREDICATE(Constant, CONSTANT) + INSTRUCTION_OPERAND_PREDICATE(Immediate, IMMEDIATE) + INSTRUCTION_OPERAND_PREDICATE(Allocated, ALLOCATED) #undef INSTRUCTION_OPERAND_PREDICATE - bool Equals(const InstructionOperand* other) const { - return value_ == other->value_; - } - void ConvertTo(Kind kind, int index) { - DCHECK(kind != UNALLOCATED && kind != INVALID); - ConvertTo(kind, index, kInvalidVirtualRegister); - } + inline bool IsRegister() const; + inline bool IsDoubleRegister() const; + inline bool IsStackSlot() const; + inline bool IsDoubleStackSlot() const; - // Useful for map/set keys. - bool operator<(const InstructionOperand& op) const { - return value_ < op.value_; - } - - protected: template <typename SubKindOperand> static SubKindOperand* New(Zone* zone, const SubKindOperand& op) { void* buffer = zone->New(sizeof(op)); return new (buffer) SubKindOperand(op); } - InstructionOperand(Kind kind, int index, int virtual_register) { - ConvertTo(kind, index, virtual_register); + static void ReplaceWith(InstructionOperand* dest, + const InstructionOperand* src) { + *dest = *src; } - void ConvertTo(Kind kind, int index, int virtual_register) { - if (kind == REGISTER || kind == DOUBLE_REGISTER) DCHECK(index >= 0); - if (kind != UNALLOCATED) { - DCHECK(virtual_register == kInvalidVirtualRegister); - } - value_ = KindField::encode(kind); - value_ |= - VirtualRegisterField::encode(static_cast<uint32_t>(virtual_register)); - value_ |= static_cast<int64_t>(index) << IndexField::kShift; - DCHECK(((kind == UNALLOCATED || kind == INVALID) && index == 0) || - this->index() == index); + bool Equals(const InstructionOperand& that) const { + return this->value_ == that.value_; } - typedef BitField64<Kind, 0, 3> KindField; - typedef BitField64<uint32_t, 3, 32> VirtualRegisterField; - typedef BitField64<int32_t, 35, 29> IndexField; + bool Compare(const InstructionOperand& that) const { + return this->value_ < that.value_; + } + + bool EqualsModuloType(const InstructionOperand& that) const { + return this->GetValueModuloType() == that.GetValueModuloType(); + } + + bool CompareModuloType(const InstructionOperand& that) const { + return this->GetValueModuloType() < that.GetValueModuloType(); + } + + protected: + explicit InstructionOperand(Kind kind) : value_(KindField::encode(kind)) {} + + inline uint64_t GetValueModuloType() const; + + class KindField : public BitField64<Kind, 0, 3> {}; uint64_t value_; }; + struct PrintableInstructionOperand { const RegisterConfiguration* register_configuration_; - const InstructionOperand* op_; + InstructionOperand op_; }; + 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 }; @@ -156,14 +144,14 @@ class UnallocatedOperand : public InstructionOperand { }; UnallocatedOperand(ExtendedPolicy policy, int virtual_register) - : InstructionOperand(UNALLOCATED, 0, virtual_register) { + : UnallocatedOperand(virtual_register) { value_ |= BasicPolicyField::encode(EXTENDED_POLICY); value_ |= ExtendedPolicyField::encode(policy); value_ |= LifetimeField::encode(USED_AT_END); } UnallocatedOperand(BasicPolicy policy, int index, int virtual_register) - : InstructionOperand(UNALLOCATED, 0, virtual_register) { + : UnallocatedOperand(virtual_register) { DCHECK(policy == FIXED_SLOT); value_ |= BasicPolicyField::encode(policy); value_ |= static_cast<int64_t>(index) << FixedSlotIndexField::kShift; @@ -171,7 +159,7 @@ class UnallocatedOperand : public InstructionOperand { } UnallocatedOperand(ExtendedPolicy policy, int index, int virtual_register) - : InstructionOperand(UNALLOCATED, 0, virtual_register) { + : UnallocatedOperand(virtual_register) { DCHECK(policy == FIXED_REGISTER || policy == FIXED_DOUBLE_REGISTER); value_ |= BasicPolicyField::encode(EXTENDED_POLICY); value_ |= ExtendedPolicyField::encode(policy); @@ -181,67 +169,12 @@ class UnallocatedOperand : public InstructionOperand { UnallocatedOperand(ExtendedPolicy policy, Lifetime lifetime, int virtual_register) - : InstructionOperand(UNALLOCATED, 0, virtual_register) { + : UnallocatedOperand(virtual_register) { value_ |= BasicPolicyField::encode(EXTENDED_POLICY); value_ |= ExtendedPolicyField::encode(policy); value_ |= LifetimeField::encode(lifetime); } - UnallocatedOperand* Copy(Zone* zone) { return New(zone, *this); } - - UnallocatedOperand* CopyUnconstrained(Zone* zone) { - 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 - // because it accommodates a larger pay-load. - // - // For FIXED_SLOT policy: - // +------------------------------------------------+ - // | slot_index | 0 | virtual_register | 001 | - // +------------------------------------------------+ - // - // For all other (extended) policies: - // +-----------------------------------------------------+ - // | reg_index | L | PPP | 1 | virtual_register | 001 | - // +-----------------------------------------------------+ - // L ... Lifetime - // P ... Policy - // - // The slot index is a signed value which requires us to decode it manually - // instead of using the BitField utility class. - - // All bits fit into the index field. - STATIC_ASSERT(IndexField::kShift == 35); - - // BitFields for all unallocated operands. - class BasicPolicyField : public BitField64<BasicPolicy, 35, 1> {}; - - // BitFields specific to BasicPolicy::FIXED_SLOT. - class FixedSlotIndexField : public BitField64<int, 36, 28> {}; - - // BitFields specific to BasicPolicy::EXTENDED_POLICY. - class ExtendedPolicyField : public BitField64<ExtendedPolicy, 36, 3> {}; - class LifetimeField : public BitField64<Lifetime, 39, 1> {}; - class FixedRegisterField : public BitField64<int, 40, 6> {}; - // Predicates for the operand policy. bool HasAnyPolicy() const { return basic_policy() == EXTENDED_POLICY && extended_policy() == ANY; @@ -315,46 +248,288 @@ class UnallocatedOperand : public InstructionOperand { DCHECK(basic_policy() == EXTENDED_POLICY); return LifetimeField::decode(value_) == USED_AT_START; } + + INSTRUCTION_OPERAND_CASTS(UnallocatedOperand, UNALLOCATED); + + // The encoding used for UnallocatedOperand operands depends on the policy + // that is + // stored within the operand. The FIXED_SLOT policy uses a compact encoding + // because it accommodates a larger pay-load. + // + // For FIXED_SLOT policy: + // +------------------------------------------------+ + // | slot_index | 0 | virtual_register | 001 | + // +------------------------------------------------+ + // + // For all other (extended) policies: + // +-----------------------------------------------------+ + // | reg_index | L | PPP | 1 | virtual_register | 001 | + // +-----------------------------------------------------+ + // L ... Lifetime + // P ... Policy + // + // The slot index is a signed value which requires us to decode it manually + // instead of using the BitField utility class. + + STATIC_ASSERT(KindField::kSize == 3); + + class VirtualRegisterField : public BitField64<uint32_t, 3, 32> {}; + + // BitFields for all unallocated operands. + class BasicPolicyField : public BitField64<BasicPolicy, 35, 1> {}; + + // BitFields specific to BasicPolicy::FIXED_SLOT. + class FixedSlotIndexField : public BitField64<int, 36, 28> {}; + + // BitFields specific to BasicPolicy::EXTENDED_POLICY. + class ExtendedPolicyField : public BitField64<ExtendedPolicy, 36, 3> {}; + class LifetimeField : public BitField64<Lifetime, 39, 1> {}; + class FixedRegisterField : public BitField64<int, 40, 6> {}; + + private: + explicit UnallocatedOperand(int virtual_register) + : InstructionOperand(UNALLOCATED) { + value_ |= + VirtualRegisterField::encode(static_cast<uint32_t>(virtual_register)); + } +}; + + +class ConstantOperand : public InstructionOperand { + public: + explicit ConstantOperand(int virtual_register) + : InstructionOperand(CONSTANT) { + value_ |= + VirtualRegisterField::encode(static_cast<uint32_t>(virtual_register)); + } + + int32_t virtual_register() const { + return static_cast<int32_t>(VirtualRegisterField::decode(value_)); + } + + static ConstantOperand* New(Zone* zone, int virtual_register) { + return InstructionOperand::New(zone, ConstantOperand(virtual_register)); + } + + INSTRUCTION_OPERAND_CASTS(ConstantOperand, CONSTANT); + + STATIC_ASSERT(KindField::kSize == 3); + class VirtualRegisterField : public BitField64<uint32_t, 3, 32> {}; }; -class MoveOperands FINAL { +class ImmediateOperand : public InstructionOperand { public: - MoveOperands(InstructionOperand* source, InstructionOperand* destination) - : source_(source), destination_(destination) {} + enum ImmediateType { INLINE, INDEXED }; + + explicit ImmediateOperand(ImmediateType type, int32_t value) + : InstructionOperand(IMMEDIATE) { + value_ |= TypeField::encode(type); + value_ |= static_cast<int64_t>(value) << ValueField::kShift; + } - InstructionOperand* source() const { return source_; } - void set_source(InstructionOperand* operand) { source_ = operand; } + ImmediateType type() const { return TypeField::decode(value_); } + + int32_t inline_value() const { + DCHECK_EQ(INLINE, type()); + return static_cast<int64_t>(value_) >> ValueField::kShift; + } + + int32_t indexed_value() const { + DCHECK_EQ(INDEXED, type()); + return static_cast<int64_t>(value_) >> ValueField::kShift; + } + + static ImmediateOperand* New(Zone* zone, ImmediateType type, int32_t value) { + return InstructionOperand::New(zone, ImmediateOperand(type, value)); + } - InstructionOperand* destination() const { return destination_; } - void set_destination(InstructionOperand* operand) { destination_ = operand; } + INSTRUCTION_OPERAND_CASTS(ImmediateOperand, IMMEDIATE); + + STATIC_ASSERT(KindField::kSize == 3); + class TypeField : public BitField64<ImmediateType, 3, 1> {}; + class ValueField : public BitField64<int32_t, 32, 32> {}; +}; + + +class AllocatedOperand : public InstructionOperand { + public: + // TODO(dcarney): machine_type makes this now redundant. Just need to know is + // the operand is a slot or a register. + enum AllocatedKind { + STACK_SLOT, + DOUBLE_STACK_SLOT, + REGISTER, + DOUBLE_REGISTER + }; + + AllocatedOperand(AllocatedKind kind, MachineType machine_type, int index) + : InstructionOperand(ALLOCATED) { + DCHECK_IMPLIES(kind == REGISTER || kind == DOUBLE_REGISTER, index >= 0); + DCHECK(IsSupportedMachineType(machine_type)); + value_ |= AllocatedKindField::encode(kind); + value_ |= MachineTypeField::encode(machine_type); + value_ |= static_cast<int64_t>(index) << IndexField::kShift; + } + + int index() const { + return static_cast<int64_t>(value_) >> IndexField::kShift; + } + + AllocatedKind allocated_kind() const { + return AllocatedKindField::decode(value_); + } + + MachineType machine_type() const { return MachineTypeField::decode(value_); } + + static AllocatedOperand* New(Zone* zone, AllocatedKind kind, + MachineType machine_type, int index) { + return InstructionOperand::New(zone, + AllocatedOperand(kind, machine_type, index)); + } + + static bool IsSupportedMachineType(MachineType machine_type) { + if (RepresentationOf(machine_type) != machine_type) return false; + switch (machine_type) { + case kRepWord32: + case kRepWord64: + case kRepFloat32: + case kRepFloat64: + case kRepTagged: + return true; + default: + return false; + } + } + + INSTRUCTION_OPERAND_CASTS(AllocatedOperand, ALLOCATED); + + STATIC_ASSERT(KindField::kSize == 3); + class AllocatedKindField : public BitField64<AllocatedKind, 3, 2> {}; + class MachineTypeField : public BitField64<MachineType, 5, 16> {}; + class IndexField : public BitField64<int32_t, 35, 29> {}; +}; + + +#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 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 + + +// TODO(dcarney): these subkinds are now pretty useless, nuke. +#define ALLOCATED_OPERAND_CLASS(SubKind, kOperandKind) \ + class SubKind##Operand final : public AllocatedOperand { \ + public: \ + explicit SubKind##Operand(MachineType machine_type, int index) \ + : AllocatedOperand(kOperandKind, machine_type, index) {} \ + \ + static SubKind##Operand* New(Zone* zone, MachineType machine_type, \ + int index) { \ + return InstructionOperand::New(zone, \ + SubKind##Operand(machine_type, 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(ALLOCATED_OPERAND_CLASS) +#undef ALLOCATED_OPERAND_CLASS + + +uint64_t InstructionOperand::GetValueModuloType() const { + if (IsAllocated()) { + // TODO(dcarney): put machine type last and mask. + return AllocatedOperand::MachineTypeField::update(this->value_, kMachNone); + } + return this->value_; +} + + +// Required for maps that don't care about machine type. +struct CompareOperandModuloType { + bool operator()(const InstructionOperand& a, + const InstructionOperand& b) const { + return a.CompareModuloType(b); + } +}; + + +class MoveOperands final : public ZoneObject { + public: + MoveOperands(const InstructionOperand& source, + const InstructionOperand& destination) + : source_(source), destination_(destination) { + DCHECK(!source.IsInvalid() && !destination.IsInvalid()); + } + + const InstructionOperand& source() const { return source_; } + InstructionOperand& source() { return source_; } + void set_source(const InstructionOperand& operand) { source_ = operand; } + + const InstructionOperand& destination() const { return destination_; } + InstructionOperand& destination() { return destination_; } + void set_destination(const InstructionOperand& 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; } + bool IsPending() const { + return destination_.IsInvalid() && !source_.IsInvalid(); + } + void SetPending() { destination_ = InstructionOperand(); } // True if this move a move into the given destination operand. - bool Blocks(InstructionOperand* operand) const { - return !IsEliminated() && source()->Equals(operand); + bool Blocks(const InstructionOperand& operand) const { + return !IsEliminated() && source().EqualsModuloType(operand); } - // A move is redundant if it's been eliminated, if its source and - // destination are the same, or if its destination is constant. + // A move is redundant if it's been eliminated or if its source and + // destination are the same. bool IsRedundant() const { - return IsEliminated() || source_->Equals(destination_) || - (destination_ != NULL && destination_->IsConstant()); + DCHECK_IMPLIES(!destination_.IsInvalid(), !destination_.IsConstant()); + return IsEliminated() || source_.EqualsModuloType(destination_); } // We clear both operands to indicate move that's been eliminated. - void Eliminate() { source_ = destination_ = NULL; } + void Eliminate() { source_ = destination_ = InstructionOperand(); } bool IsEliminated() const { - DCHECK(source_ != NULL || destination_ == NULL); - return source_ == NULL; + DCHECK_IMPLIES(source_.IsInvalid(), destination_.IsInvalid()); + return source_.IsInvalid(); } private: - InstructionOperand* source_; - InstructionOperand* destination_; + InstructionOperand source_; + InstructionOperand destination_; + + DISALLOW_COPY_AND_ASSIGN(MoveOperands); }; @@ -367,58 +542,29 @@ struct PrintableMoveOperands { std::ostream& operator<<(std::ostream& os, const PrintableMoveOperands& mo); -#define INSTRUCTION_SUBKIND_OPERAND_CLASS(SubKind, kOperandKind) \ - class SubKind##Operand FINAL : public InstructionOperand { \ - public: \ - explicit SubKind##Operand(int index) \ - : InstructionOperand(kOperandKind, index) {} \ - \ - static SubKind##Operand* New(int index, Zone* zone) { \ - 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); \ - } \ - }; -INSTRUCTION_OPERAND_LIST(INSTRUCTION_SUBKIND_OPERAND_CLASS) -#undef INSTRUCTION_SUBKIND_OPERAND_CLASS - - -class ParallelMove FINAL : public ZoneObject { +class ParallelMove final : public ZoneVector<MoveOperands*>, public ZoneObject { public: - explicit ParallelMove(Zone* zone) : move_operands_(4, zone) {} + explicit ParallelMove(Zone* zone) : ZoneVector<MoveOperands*>(zone) { + reserve(4); + } - void AddMove(InstructionOperand* from, InstructionOperand* to, Zone* zone) { - move_operands_.Add(MoveOperands(from, to), zone); + MoveOperands* AddMove(const InstructionOperand& from, + const InstructionOperand& to) { + auto zone = get_allocator().zone(); + auto move = new (zone) MoveOperands(from, to); + push_back(move); + return move; } bool IsRedundant() const; - ZoneList<MoveOperands>* move_operands() { return &move_operands_; } - const ZoneList<MoveOperands>* move_operands() const { - return &move_operands_; - } - // Prepare this ParallelMove to insert move as if it happened in a subsequent // ParallelMove. move->source() may be changed. The MoveOperand returned - // must be Eliminated and, as it points directly into move_operands_, it must - // be Eliminated before any further mutation. + // must be Eliminated. MoveOperands* PrepareInsertAfter(MoveOperands* move) const; private: - ZoneList<MoveOperands> move_operands_; + DISALLOW_COPY_AND_ASSIGN(ParallelMove); }; @@ -431,19 +577,13 @@ struct PrintableParallelMove { std::ostream& operator<<(std::ostream& os, const PrintableParallelMove& pm); -class PointerMap FINAL : public ZoneObject { +class ReferenceMap final : public ZoneObject { public: - explicit PointerMap(Zone* zone) - : pointer_operands_(8, zone), - untagged_operands_(0, zone), - instruction_position_(-1) {} - - const ZoneList<InstructionOperand*>* GetNormalizedOperands() { - for (int i = 0; i < untagged_operands_.length(); ++i) { - RemovePointer(untagged_operands_[i]); - } - untagged_operands_.Clear(); - return &pointer_operands_; + explicit ReferenceMap(Zone* zone) + : reference_operands_(8, zone), instruction_position_(-1) {} + + const ZoneVector<InstructionOperand>& reference_operands() const { + return reference_operands_; } int instruction_position() const { return instruction_position_; } @@ -452,22 +592,18 @@ class PointerMap FINAL : public ZoneObject { instruction_position_ = pos; } - void RecordPointer(InstructionOperand* op, Zone* zone); - void RemovePointer(InstructionOperand* op); - void RecordUntagged(InstructionOperand* op, Zone* zone); + void RecordReference(const AllocatedOperand& op); private: - friend std::ostream& operator<<(std::ostream& os, const PointerMap& pm); + friend std::ostream& operator<<(std::ostream& os, const ReferenceMap& pm); - ZoneList<InstructionOperand*> pointer_operands_; - ZoneList<InstructionOperand*> untagged_operands_; + ZoneVector<InstructionOperand> reference_operands_; int instruction_position_; }; -std::ostream& operator<<(std::ostream& os, const PointerMap& pm); +std::ostream& operator<<(std::ostream& os, const ReferenceMap& pm); -// TODO(titzer): s/PointerMap/ReferenceMap/ -class Instruction { +class Instruction final { public: size_t OutputCount() const { return OutputCountField::decode(bit_field_); } const InstructionOperand* OutputAt(size_t i) const { @@ -540,29 +676,24 @@ class Instruction { return this; } bool IsCall() const { return IsCallField::decode(bit_field_); } - bool NeedsPointerMap() const { return IsCall(); } - bool HasPointerMap() const { return pointer_map_ != NULL; } - - bool IsGapMoves() const { return opcode() == kGapInstruction; } - bool IsSourcePosition() const { - return opcode() == kSourcePositionInstruction; - } + bool NeedsReferenceMap() const { return IsCall(); } + bool HasReferenceMap() const { return reference_map_ != NULL; } bool ClobbersRegisters() const { return IsCall(); } bool ClobbersTemps() const { return IsCall(); } bool ClobbersDoubleRegisters() const { return IsCall(); } - PointerMap* pointer_map() const { return pointer_map_; } + ReferenceMap* reference_map() const { return reference_map_; } - void set_pointer_map(PointerMap* map) { - DCHECK(NeedsPointerMap()); - DCHECK(!pointer_map_); - pointer_map_ = map; + void set_reference_map(ReferenceMap* map) { + DCHECK(NeedsReferenceMap()); + DCHECK(!reference_map_); + reference_map_ = map; } void OverwriteWithNop() { opcode_ = ArchOpcodeField::encode(kArchNop); bit_field_ = 0; - pointer_map_ = NULL; + reference_map_ = NULL; } bool IsNop() const { @@ -570,126 +701,64 @@ class Instruction { OutputCount() == 0 && TempCount() == 0; } - protected: - explicit Instruction(InstructionCode opcode); - Instruction(InstructionCode opcode, size_t output_count, - InstructionOperand* outputs, size_t input_count, - InstructionOperand* inputs, size_t temp_count, - InstructionOperand* temps); - - typedef BitField<size_t, 0, 8> OutputCountField; - typedef BitField<size_t, 8, 16> InputCountField; - typedef BitField<size_t, 24, 6> TempCountField; - typedef BitField<bool, 30, 1> IsCallField; - - InstructionCode opcode_; - uint32_t bit_field_; - PointerMap* pointer_map_; - InstructionOperand operands_[1]; - - private: - DISALLOW_COPY_AND_ASSIGN(Instruction); -}; - - -struct PrintableInstruction { - const RegisterConfiguration* register_configuration_; - const Instruction* instr_; -}; -std::ostream& operator<<(std::ostream& os, const PrintableInstruction& instr); - - -// Represents moves inserted before an instruction due to register allocation. -// TODO(titzer): squash GapInstruction back into Instruction, since essentially -// every instruction can possibly have moves inserted before it. -class GapInstruction : public Instruction { - public: - enum InnerPosition { + enum GapPosition { START, END, - FIRST_INNER_POSITION = START, - LAST_INNER_POSITION = END + FIRST_GAP_POSITION = START, + LAST_GAP_POSITION = END }; - ParallelMove* GetOrCreateParallelMove(InnerPosition pos, Zone* zone) { - if (parallel_moves_[pos] == NULL) { + ParallelMove* GetOrCreateParallelMove(GapPosition pos, Zone* zone) { + if (parallel_moves_[pos] == nullptr) { parallel_moves_[pos] = new (zone) ParallelMove(zone); } return parallel_moves_[pos]; } - ParallelMove* GetParallelMove(InnerPosition pos) { + ParallelMove* GetParallelMove(GapPosition pos) { return parallel_moves_[pos]; } - const ParallelMove* GetParallelMove(InnerPosition pos) const { + const ParallelMove* GetParallelMove(GapPosition pos) const { return parallel_moves_[pos]; } - bool IsRedundant() const; - - ParallelMove** parallel_moves() { return parallel_moves_; } - - static GapInstruction* New(Zone* zone) { - void* buffer = zone->New(sizeof(GapInstruction)); - return new (buffer) GapInstruction(kGapInstruction); - } - - static GapInstruction* cast(Instruction* instr) { - DCHECK(instr->IsGapMoves()); - return static_cast<GapInstruction*>(instr); - } - - static const GapInstruction* cast(const Instruction* instr) { - DCHECK(instr->IsGapMoves()); - return static_cast<const GapInstruction*>(instr); - } + bool AreMovesRedundant() const; - protected: - explicit GapInstruction(InstructionCode opcode) : Instruction(opcode) { - parallel_moves_[START] = NULL; - parallel_moves_[END] = NULL; - } + ParallelMove* const* parallel_moves() const { return ¶llel_moves_[0]; } + ParallelMove** parallel_moves() { return ¶llel_moves_[0]; } private: - friend std::ostream& operator<<(std::ostream& os, - const PrintableInstruction& instr); - ParallelMove* parallel_moves_[LAST_INNER_POSITION + 1]; -}; - + explicit Instruction(InstructionCode opcode); -class SourcePositionInstruction FINAL : public Instruction { - public: - static SourcePositionInstruction* New(Zone* zone, SourcePosition position) { - void* buffer = zone->New(sizeof(SourcePositionInstruction)); - return new (buffer) SourcePositionInstruction(position); - } + Instruction(InstructionCode opcode, size_t output_count, + InstructionOperand* outputs, size_t input_count, + InstructionOperand* inputs, size_t temp_count, + InstructionOperand* temps); - SourcePosition source_position() const { return source_position_; } + typedef BitField<size_t, 0, 8> OutputCountField; + typedef BitField<size_t, 8, 16> InputCountField; + typedef BitField<size_t, 24, 6> TempCountField; + typedef BitField<bool, 30, 1> IsCallField; - static SourcePositionInstruction* cast(Instruction* instr) { - DCHECK(instr->IsSourcePosition()); - return static_cast<SourcePositionInstruction*>(instr); - } + InstructionCode opcode_; + uint32_t bit_field_; + ParallelMove* parallel_moves_[2]; + ReferenceMap* reference_map_; + InstructionOperand operands_[1]; - static const SourcePositionInstruction* cast(const Instruction* instr) { - DCHECK(instr->IsSourcePosition()); - return static_cast<const SourcePositionInstruction*>(instr); - } + DISALLOW_COPY_AND_ASSIGN(Instruction); +}; - private: - explicit SourcePositionInstruction(SourcePosition source_position) - : Instruction(kSourcePositionInstruction), - source_position_(source_position) { - DCHECK(!source_position_.IsInvalid()); - DCHECK(!source_position_.IsUnknown()); - } - SourcePosition source_position_; +struct PrintableInstruction { + const RegisterConfiguration* register_configuration_; + const Instruction* instr_; }; +std::ostream& operator<<(std::ostream& os, const PrintableInstruction& instr); -class RpoNumber FINAL { +class RpoNumber final { public: static const int kInvalidRpoNumber = -1; int ToInt() const { @@ -722,7 +791,7 @@ class RpoNumber FINAL { std::ostream& operator<<(std::ostream&, const RpoNumber&); -class Constant FINAL { +class Constant final { public: enum Type { kInt32, @@ -832,7 +901,7 @@ class FrameStateDescriptor : public ZoneObject { std::ostream& operator<<(std::ostream& os, const Constant& constant); -class PhiInstruction FINAL : public ZoneObject { +class PhiInstruction final : public ZoneObject { public: typedef ZoneVector<InstructionOperand> Inputs; @@ -843,23 +912,20 @@ class PhiInstruction FINAL : public ZoneObject { int virtual_register() const { return virtual_register_; } const IntVector& operands() const { return operands_; } + // TODO(dcarney): this has no real business being here, since it's internal to + // the register allocator, but putting it here was convenient. const InstructionOperand& output() const { return output_; } InstructionOperand& output() { return output_; } - const Inputs& inputs() const { return inputs_; } - Inputs& inputs() { return inputs_; } private: - // TODO(dcarney): some of these fields are only for verification, move them to - // verifier. const int virtual_register_; InstructionOperand output_; IntVector operands_; - Inputs inputs_; }; // Analogue of BasicBlock for Instructions instead of Nodes. -class InstructionBlock FINAL : public ZoneObject { +class InstructionBlock final : public ZoneObject { public: InstructionBlock(Zone* zone, RpoNumber rpo_number, RpoNumber loop_header, RpoNumber loop_end, bool deferred); @@ -912,6 +978,15 @@ class InstructionBlock FINAL : public ZoneObject { void set_ao_number(RpoNumber ao_number) { ao_number_ = ao_number; } + bool needs_frame() const { return needs_frame_; } + void mark_needs_frame() { needs_frame_ = true; } + + bool must_construct_frame() const { return must_construct_frame_; } + void mark_must_construct_frame() { must_construct_frame_ = true; } + + bool must_deconstruct_frame() const { return must_deconstruct_frame_; } + void mark_must_deconstruct_frame() { must_deconstruct_frame_ = true; } + private: Successors successors_; Predecessors predecessors_; @@ -923,6 +998,9 @@ class InstructionBlock FINAL : public ZoneObject { int32_t code_start_; // start index of arch-specific code. int32_t code_end_; // end index of arch-specific code. const bool deferred_; // Block contains deferred code. + bool needs_frame_; + bool must_construct_frame_; + bool must_deconstruct_frame_; }; typedef ZoneDeque<Constant> ConstantDeque; @@ -930,7 +1008,7 @@ typedef std::map<int, Constant, std::less<int>, zone_allocator<std::pair<int, Constant> > > ConstantMap; typedef ZoneDeque<Instruction*> InstructionDeque; -typedef ZoneDeque<PointerMap*> PointerMapDeque; +typedef ZoneDeque<ReferenceMap*> ReferenceMapDeque; typedef ZoneVector<FrameStateDescriptor*> DeoptimizationVector; typedef ZoneVector<InstructionBlock*> InstructionBlocks; @@ -940,7 +1018,7 @@ struct PrintableInstructionSequence; // Represents architecture-specific generated code before, during, and after // register allocation. // TODO(titzer): s/IsDouble/IsFloat64/ -class InstructionSequence FINAL : public ZoneObject { +class InstructionSequence final : public ZoneObject { public: static InstructionBlocks* InstructionBlocksFor(Zone* zone, const Schedule* schedule); @@ -974,27 +1052,34 @@ class InstructionSequence FINAL : public ZoneObject { return instruction_blocks_->at(rpo_number.ToSize()); } - const InstructionBlock* GetInstructionBlock(int instruction_index) const; - - bool IsReference(int virtual_register) const; - bool IsDouble(int virtual_register) const; + InstructionBlock* GetInstructionBlock(int instruction_index) const; - void MarkAsReference(int virtual_register); - void MarkAsDouble(int virtual_register); + static MachineType DefaultRepresentation() { + return kPointerSize == 8 ? kRepWord64 : kRepWord32; + } + MachineType GetRepresentation(int virtual_register) const; + void MarkAsRepresentation(MachineType machine_type, int virtual_register); - void AddGapMove(int index, InstructionOperand* from, InstructionOperand* to); + bool IsReference(int virtual_register) const { + return GetRepresentation(virtual_register) == kRepTagged; + } + bool IsFloat(int virtual_register) const { + switch (GetRepresentation(virtual_register)) { + case kRepFloat32: + case kRepFloat64: + return true; + default: + return false; + } + } - GapInstruction* GetBlockStart(RpoNumber rpo) const; + Instruction* GetBlockStart(RpoNumber rpo) const; typedef InstructionDeque::const_iterator const_iterator; const_iterator begin() const { return instructions_.begin(); } const_iterator end() const { return instructions_.end(); } const InstructionDeque& instructions() const { return instructions_; } - GapInstruction* GapAt(int index) const { - return GapInstruction::cast(InstructionAt(index)); - } - bool IsGapAt(int index) const { return InstructionAt(index)->IsGapMoves(); } Instruction* InstructionAt(int index) const { DCHECK(index >= 0); DCHECK(index < static_cast<int>(instructions_.size())); @@ -1002,7 +1087,7 @@ class InstructionSequence FINAL : public ZoneObject { } Isolate* isolate() const { return isolate_; } - const PointerMapDeque* pointer_maps() const { return &pointer_maps_; } + const ReferenceMapDeque* reference_maps() const { return &reference_maps_; } Zone* zone() const { return zone_; } // Used by the instruction selector while adding instructions. @@ -1028,15 +1113,28 @@ class InstructionSequence FINAL : public ZoneObject { typedef ZoneVector<Constant> Immediates; Immediates& immediates() { return immediates_; } - int AddImmediate(Constant constant) { + ImmediateOperand AddImmediate(const Constant& constant) { + if (constant.type() == Constant::kInt32) { + return ImmediateOperand(ImmediateOperand::INLINE, constant.ToInt32()); + } int index = static_cast<int>(immediates_.size()); immediates_.push_back(constant); - return index; - } - Constant GetImmediate(int index) const { - DCHECK(index >= 0); - DCHECK(index < static_cast<int>(immediates_.size())); - return immediates_[index]; + return ImmediateOperand(ImmediateOperand::INDEXED, index); + } + + Constant GetImmediate(const ImmediateOperand* op) const { + switch (op->type()) { + case ImmediateOperand::INLINE: + return Constant(op->inline_value()); + case ImmediateOperand::INDEXED: { + int index = op->indexed_value(); + DCHECK(index >= 0); + DCHECK(index < static_cast<int>(immediates_.size())); + return immediates_[index]; + } + } + UNREACHABLE(); + return Constant(static_cast<int32_t>(0)); } class StateId { @@ -1053,30 +1151,30 @@ class InstructionSequence FINAL : public ZoneObject { FrameStateDescriptor* GetFrameStateDescriptor(StateId deoptimization_id); int GetFrameStateDescriptorCount(); - RpoNumber InputRpo(Instruction* instr, size_t index) { - InstructionOperand* operand = instr->InputAt(index); - Constant constant = operand->IsImmediate() ? GetImmediate(operand->index()) - : GetConstant(operand->index()); - return constant.ToRpoNumber(); - } + RpoNumber InputRpo(Instruction* instr, size_t index); + + bool GetSourcePosition(const Instruction* instr, + SourcePosition* result) const; + void SetSourcePosition(const Instruction* instr, SourcePosition value); private: friend std::ostream& operator<<(std::ostream& os, const PrintableInstructionSequence& code); typedef std::set<int, std::less<int>, ZoneIntAllocator> VirtualRegisterSet; + typedef ZoneMap<const Instruction*, SourcePosition> SourcePositionMap; Isolate* isolate_; Zone* const zone_; InstructionBlocks* const instruction_blocks_; + SourcePositionMap source_positions_; IntVector block_starts_; ConstantMap constants_; Immediates immediates_; InstructionDeque instructions_; int next_virtual_register_; - PointerMapDeque pointer_maps_; - VirtualRegisterSet doubles_; - VirtualRegisterSet references_; + ReferenceMapDeque reference_maps_; + ZoneVector<MachineType> representations_; DeoptimizationVector deoptimization_entries_; DISALLOW_COPY_AND_ASSIGN(InstructionSequence); |