aboutsummaryrefslogtreecommitdiff
path: root/deps/v8/src/compiler/instruction.h
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/compiler/instruction.h')
-rw-r--r--deps/v8/src/compiler/instruction.h806
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 &parallel_moves_[0]; }
+ ParallelMove** parallel_moves() { return &parallel_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);