diff --git a/src/compiler/frame.h b/src/compiler/frame.h index a5dd11657b..2850a8c1a1 100644 --- a/src/compiler/frame.h +++ b/src/compiler/frame.h @@ -20,13 +20,11 @@ class Frame : public ZoneObject { Frame() : register_save_area_size_(0), spill_slot_count_(0), - double_spill_slot_count_(0), osr_stack_slot_count_(0), allocated_registers_(NULL), allocated_double_registers_(NULL) {} inline int GetSpillSlotCount() { return spill_slot_count_; } - inline int GetDoubleSpillSlotCount() { return double_spill_slot_count_; } void SetAllocatedRegisters(BitVector* regs) { DCHECK(allocated_registers_ == NULL); @@ -57,15 +55,13 @@ class Frame : public ZoneObject { int GetOsrStackSlotCount() { return osr_stack_slot_count_; } - int AllocateSpillSlot(bool is_double) { - // If 32-bit, skip one if the new slot is a double. - if (is_double) { - if (kDoubleSize > kPointerSize) { - DCHECK(kDoubleSize == kPointerSize * 2); - spill_slot_count_++; - spill_slot_count_ |= 1; - } - double_spill_slot_count_++; + int AllocateSpillSlot(int width) { + DCHECK(width == 4 || width == 8); + // Skip one slot if necessary. + if (width > kPointerSize) { + DCHECK(width == kPointerSize * 2); + spill_slot_count_++; + spill_slot_count_ |= 1; } return spill_slot_count_++; } @@ -78,7 +74,6 @@ class Frame : public ZoneObject { private: int register_save_area_size_; int spill_slot_count_; - int double_spill_slot_count_; int osr_stack_slot_count_; BitVector* allocated_registers_; BitVector* allocated_double_registers_; diff --git a/src/compiler/gap-resolver.cc b/src/compiler/gap-resolver.cc index d9b20b6488..e5de73781b 100644 --- a/src/compiler/gap-resolver.cc +++ b/src/compiler/gap-resolver.cc @@ -75,7 +75,7 @@ void GapResolver::PerformMove(ParallelMove* moves, MoveOperands* move) const { // This move's source may have changed due to swaps to resolve cycles and so // it may now be the last move in the cycle. If so remove it. InstructionOperand source = move->source(); - if (source == destination) { + if (source.EqualsModuloType(destination)) { move->Eliminate(); return; } diff --git a/src/compiler/instruction-selector-impl.h b/src/compiler/instruction-selector-impl.h index f4acfa0ba9..b34a914efc 100644 --- a/src/compiler/instruction-selector-impl.h +++ b/src/compiler/instruction-selector-impl.h @@ -137,7 +137,7 @@ class OperandGenerator { UnallocatedOperand op = UnallocatedOperand( UnallocatedOperand::MUST_HAVE_REGISTER, UnallocatedOperand::USED_AT_START, sequence()->NextVirtualRegister()); - sequence()->MarkAsDouble(op.virtual_register()); + sequence()->MarkAsRepresentation(kRepFloat64, op.virtual_register()); return op; } diff --git a/src/compiler/instruction-selector.cc b/src/compiler/instruction-selector.cc index 1e2ab97485..3d6c1fedf7 100644 --- a/src/compiler/instruction-selector.cc +++ b/src/compiler/instruction-selector.cc @@ -241,70 +241,17 @@ void InstructionSelector::MarkAsUsed(Node* node) { } -bool InstructionSelector::IsDouble(const Node* node) const { - DCHECK_NOT_NULL(node); - int const virtual_register = virtual_registers_[node->id()]; - if (virtual_register == InstructionOperand::kInvalidVirtualRegister) { - return false; - } - return sequence()->IsDouble(virtual_register); -} - - -void InstructionSelector::MarkAsDouble(Node* node) { - DCHECK_NOT_NULL(node); - DCHECK(!IsReference(node)); - sequence()->MarkAsDouble(GetVirtualRegister(node)); -} - - -bool InstructionSelector::IsReference(const Node* node) const { - DCHECK_NOT_NULL(node); - int const virtual_register = virtual_registers_[node->id()]; - if (virtual_register == InstructionOperand::kInvalidVirtualRegister) { - return false; - } - return sequence()->IsReference(virtual_register); -} - - -void InstructionSelector::MarkAsReference(Node* node) { - DCHECK_NOT_NULL(node); - DCHECK(!IsDouble(node)); - sequence()->MarkAsReference(GetVirtualRegister(node)); -} - - void InstructionSelector::MarkAsRepresentation(MachineType rep, const InstructionOperand& op) { UnallocatedOperand unalloc = UnallocatedOperand::cast(op); - switch (RepresentationOf(rep)) { - case kRepFloat32: - case kRepFloat64: - sequence()->MarkAsDouble(unalloc.virtual_register()); - break; - case kRepTagged: - sequence()->MarkAsReference(unalloc.virtual_register()); - break; - default: - break; - } + rep = RepresentationOf(rep); + sequence()->MarkAsRepresentation(rep, unalloc.virtual_register()); } void InstructionSelector::MarkAsRepresentation(MachineType rep, Node* node) { - DCHECK_NOT_NULL(node); - switch (RepresentationOf(rep)) { - case kRepFloat32: - case kRepFloat64: - MarkAsDouble(node); - break; - case kRepTagged: - MarkAsReference(node); - break; - default: - break; - } + rep = RepresentationOf(rep); + sequence()->MarkAsRepresentation(rep, GetVirtualRegister(node)); } @@ -625,9 +572,9 @@ void InstructionSelector::VisitNode(Node* node) { case IrOpcode::kExternalConstant: return VisitConstant(node); case IrOpcode::kFloat32Constant: - return MarkAsDouble(node), VisitConstant(node); + return MarkAsFloat32(node), VisitConstant(node); case IrOpcode::kFloat64Constant: - return MarkAsDouble(node), VisitConstant(node); + return MarkAsFloat64(node), VisitConstant(node); case IrOpcode::kHeapConstant: return MarkAsReference(node), VisitConstant(node); case IrOpcode::kNumberConstant: { @@ -648,125 +595,125 @@ void InstructionSelector::VisitNode(Node* node) { case IrOpcode::kStore: return VisitStore(node); case IrOpcode::kWord32And: - return VisitWord32And(node); + return MarkAsWord32(node), VisitWord32And(node); case IrOpcode::kWord32Or: - return VisitWord32Or(node); + return MarkAsWord32(node), VisitWord32Or(node); case IrOpcode::kWord32Xor: - return VisitWord32Xor(node); + return MarkAsWord32(node), VisitWord32Xor(node); case IrOpcode::kWord32Shl: - return VisitWord32Shl(node); + return MarkAsWord32(node), VisitWord32Shl(node); case IrOpcode::kWord32Shr: - return VisitWord32Shr(node); + return MarkAsWord32(node), VisitWord32Shr(node); case IrOpcode::kWord32Sar: - return VisitWord32Sar(node); + return MarkAsWord32(node), VisitWord32Sar(node); case IrOpcode::kWord32Ror: - return VisitWord32Ror(node); + return MarkAsWord32(node), VisitWord32Ror(node); case IrOpcode::kWord32Equal: return VisitWord32Equal(node); case IrOpcode::kWord32Clz: - return VisitWord32Clz(node); + return MarkAsWord32(node), VisitWord32Clz(node); case IrOpcode::kWord64And: - return VisitWord64And(node); + return MarkAsWord64(node), VisitWord64And(node); case IrOpcode::kWord64Or: - return VisitWord64Or(node); + return MarkAsWord64(node), VisitWord64Or(node); case IrOpcode::kWord64Xor: - return VisitWord64Xor(node); + return MarkAsWord64(node), VisitWord64Xor(node); case IrOpcode::kWord64Shl: - return VisitWord64Shl(node); + return MarkAsWord64(node), VisitWord64Shl(node); case IrOpcode::kWord64Shr: - return VisitWord64Shr(node); + return MarkAsWord64(node), VisitWord64Shr(node); case IrOpcode::kWord64Sar: - return VisitWord64Sar(node); + return MarkAsWord64(node), VisitWord64Sar(node); case IrOpcode::kWord64Ror: - return VisitWord64Ror(node); + return MarkAsWord64(node), VisitWord64Ror(node); case IrOpcode::kWord64Equal: return VisitWord64Equal(node); case IrOpcode::kInt32Add: - return VisitInt32Add(node); + return MarkAsWord32(node), VisitInt32Add(node); case IrOpcode::kInt32AddWithOverflow: - return VisitInt32AddWithOverflow(node); + return MarkAsWord32(node), VisitInt32AddWithOverflow(node); case IrOpcode::kInt32Sub: - return VisitInt32Sub(node); + return MarkAsWord32(node), VisitInt32Sub(node); case IrOpcode::kInt32SubWithOverflow: return VisitInt32SubWithOverflow(node); case IrOpcode::kInt32Mul: - return VisitInt32Mul(node); + return MarkAsWord32(node), VisitInt32Mul(node); case IrOpcode::kInt32MulHigh: return VisitInt32MulHigh(node); case IrOpcode::kInt32Div: - return VisitInt32Div(node); + return MarkAsWord32(node), VisitInt32Div(node); case IrOpcode::kInt32Mod: - return VisitInt32Mod(node); + return MarkAsWord32(node), VisitInt32Mod(node); case IrOpcode::kInt32LessThan: return VisitInt32LessThan(node); case IrOpcode::kInt32LessThanOrEqual: return VisitInt32LessThanOrEqual(node); case IrOpcode::kUint32Div: - return VisitUint32Div(node); + return MarkAsWord32(node), VisitUint32Div(node); case IrOpcode::kUint32LessThan: return VisitUint32LessThan(node); case IrOpcode::kUint32LessThanOrEqual: return VisitUint32LessThanOrEqual(node); case IrOpcode::kUint32Mod: - return VisitUint32Mod(node); + return MarkAsWord32(node), VisitUint32Mod(node); case IrOpcode::kUint32MulHigh: return VisitUint32MulHigh(node); case IrOpcode::kInt64Add: - return VisitInt64Add(node); + return MarkAsWord64(node), VisitInt64Add(node); case IrOpcode::kInt64Sub: - return VisitInt64Sub(node); + return MarkAsWord64(node), VisitInt64Sub(node); case IrOpcode::kInt64Mul: - return VisitInt64Mul(node); + return MarkAsWord64(node), VisitInt64Mul(node); case IrOpcode::kInt64Div: - return VisitInt64Div(node); + return MarkAsWord64(node), VisitInt64Div(node); case IrOpcode::kInt64Mod: - return VisitInt64Mod(node); + return MarkAsWord64(node), VisitInt64Mod(node); case IrOpcode::kInt64LessThan: return VisitInt64LessThan(node); case IrOpcode::kInt64LessThanOrEqual: return VisitInt64LessThanOrEqual(node); case IrOpcode::kUint64Div: - return VisitUint64Div(node); + return MarkAsWord64(node), VisitUint64Div(node); case IrOpcode::kUint64LessThan: return VisitUint64LessThan(node); case IrOpcode::kUint64Mod: - return VisitUint64Mod(node); + return MarkAsWord64(node), VisitUint64Mod(node); case IrOpcode::kChangeFloat32ToFloat64: - return MarkAsDouble(node), VisitChangeFloat32ToFloat64(node); + return MarkAsFloat64(node), VisitChangeFloat32ToFloat64(node); case IrOpcode::kChangeInt32ToFloat64: - return MarkAsDouble(node), VisitChangeInt32ToFloat64(node); + return MarkAsFloat64(node), VisitChangeInt32ToFloat64(node); case IrOpcode::kChangeUint32ToFloat64: - return MarkAsDouble(node), VisitChangeUint32ToFloat64(node); + return MarkAsFloat64(node), VisitChangeUint32ToFloat64(node); case IrOpcode::kChangeFloat64ToInt32: - return VisitChangeFloat64ToInt32(node); + return MarkAsWord32(node), VisitChangeFloat64ToInt32(node); case IrOpcode::kChangeFloat64ToUint32: - return VisitChangeFloat64ToUint32(node); + return MarkAsWord32(node), VisitChangeFloat64ToUint32(node); case IrOpcode::kChangeInt32ToInt64: - return VisitChangeInt32ToInt64(node); + return MarkAsWord64(node), VisitChangeInt32ToInt64(node); case IrOpcode::kChangeUint32ToUint64: - return VisitChangeUint32ToUint64(node); + return MarkAsWord64(node), VisitChangeUint32ToUint64(node); case IrOpcode::kTruncateFloat64ToFloat32: - return MarkAsDouble(node), VisitTruncateFloat64ToFloat32(node); + return MarkAsFloat32(node), VisitTruncateFloat64ToFloat32(node); case IrOpcode::kTruncateFloat64ToInt32: - return VisitTruncateFloat64ToInt32(node); + return MarkAsWord32(node), VisitTruncateFloat64ToInt32(node); case IrOpcode::kTruncateInt64ToInt32: - return VisitTruncateInt64ToInt32(node); + return MarkAsWord32(node), VisitTruncateInt64ToInt32(node); case IrOpcode::kFloat32Add: - return MarkAsDouble(node), VisitFloat32Add(node); + return MarkAsFloat32(node), VisitFloat32Add(node); case IrOpcode::kFloat32Sub: - return MarkAsDouble(node), VisitFloat32Sub(node); + return MarkAsFloat32(node), VisitFloat32Sub(node); case IrOpcode::kFloat32Mul: - return MarkAsDouble(node), VisitFloat32Mul(node); + return MarkAsFloat32(node), VisitFloat32Mul(node); case IrOpcode::kFloat32Div: - return MarkAsDouble(node), VisitFloat32Div(node); + return MarkAsFloat32(node), VisitFloat32Div(node); case IrOpcode::kFloat32Min: - return MarkAsDouble(node), VisitFloat32Min(node); + return MarkAsFloat32(node), VisitFloat32Min(node); case IrOpcode::kFloat32Max: - return MarkAsDouble(node), VisitFloat32Max(node); + return MarkAsFloat32(node), VisitFloat32Max(node); case IrOpcode::kFloat32Abs: - return MarkAsDouble(node), VisitFloat32Abs(node); + return MarkAsFloat32(node), VisitFloat32Abs(node); case IrOpcode::kFloat32Sqrt: - return MarkAsDouble(node), VisitFloat32Sqrt(node); + return MarkAsFloat32(node), VisitFloat32Sqrt(node); case IrOpcode::kFloat32Equal: return VisitFloat32Equal(node); case IrOpcode::kFloat32LessThan: @@ -774,23 +721,23 @@ void InstructionSelector::VisitNode(Node* node) { case IrOpcode::kFloat32LessThanOrEqual: return VisitFloat32LessThanOrEqual(node); case IrOpcode::kFloat64Add: - return MarkAsDouble(node), VisitFloat64Add(node); + return MarkAsFloat64(node), VisitFloat64Add(node); case IrOpcode::kFloat64Sub: - return MarkAsDouble(node), VisitFloat64Sub(node); + return MarkAsFloat64(node), VisitFloat64Sub(node); case IrOpcode::kFloat64Mul: - return MarkAsDouble(node), VisitFloat64Mul(node); + return MarkAsFloat64(node), VisitFloat64Mul(node); case IrOpcode::kFloat64Div: - return MarkAsDouble(node), VisitFloat64Div(node); + return MarkAsFloat64(node), VisitFloat64Div(node); case IrOpcode::kFloat64Mod: - return MarkAsDouble(node), VisitFloat64Mod(node); + return MarkAsFloat64(node), VisitFloat64Mod(node); case IrOpcode::kFloat64Min: - return MarkAsDouble(node), VisitFloat64Min(node); + return MarkAsFloat64(node), VisitFloat64Min(node); case IrOpcode::kFloat64Max: - return MarkAsDouble(node), VisitFloat64Max(node); + return MarkAsFloat64(node), VisitFloat64Max(node); case IrOpcode::kFloat64Abs: - return MarkAsDouble(node), VisitFloat64Abs(node); + return MarkAsFloat64(node), VisitFloat64Abs(node); case IrOpcode::kFloat64Sqrt: - return MarkAsDouble(node), VisitFloat64Sqrt(node); + return MarkAsFloat64(node), VisitFloat64Sqrt(node); case IrOpcode::kFloat64Equal: return VisitFloat64Equal(node); case IrOpcode::kFloat64LessThan: @@ -798,19 +745,19 @@ void InstructionSelector::VisitNode(Node* node) { case IrOpcode::kFloat64LessThanOrEqual: return VisitFloat64LessThanOrEqual(node); case IrOpcode::kFloat64RoundDown: - return MarkAsDouble(node), VisitFloat64RoundDown(node); + return MarkAsFloat64(node), VisitFloat64RoundDown(node); case IrOpcode::kFloat64RoundTruncate: - return MarkAsDouble(node), VisitFloat64RoundTruncate(node); + return MarkAsFloat64(node), VisitFloat64RoundTruncate(node); case IrOpcode::kFloat64RoundTiesAway: - return MarkAsDouble(node), VisitFloat64RoundTiesAway(node); + return MarkAsFloat64(node), VisitFloat64RoundTiesAway(node); case IrOpcode::kFloat64ExtractLowWord32: - return VisitFloat64ExtractLowWord32(node); + return MarkAsWord32(node), VisitFloat64ExtractLowWord32(node); case IrOpcode::kFloat64ExtractHighWord32: - return VisitFloat64ExtractHighWord32(node); + return MarkAsWord32(node), VisitFloat64ExtractHighWord32(node); case IrOpcode::kFloat64InsertLowWord32: - return MarkAsDouble(node), VisitFloat64InsertLowWord32(node); + return MarkAsFloat64(node), VisitFloat64InsertLowWord32(node); case IrOpcode::kFloat64InsertHighWord32: - return MarkAsDouble(node), VisitFloat64InsertHighWord32(node); + return MarkAsFloat64(node), VisitFloat64InsertHighWord32(node); case IrOpcode::kLoadStackPointer: return VisitLoadStackPointer(node); case IrOpcode::kCheckedLoad: { diff --git a/src/compiler/instruction-selector.h b/src/compiler/instruction-selector.h index 6a7b962b0e..b3054084f4 100644 --- a/src/compiler/instruction-selector.h +++ b/src/compiler/instruction-selector.h @@ -146,21 +146,14 @@ class InstructionSelector final { // will need to generate code for it. void MarkAsUsed(Node* node); - // Checks if {node} is marked as double. - bool IsDouble(const Node* node) const; - - // Inform the register allocator of a double result. - void MarkAsDouble(Node* node); - - // Checks if {node} is marked as reference. - bool IsReference(const Node* node) const; - - // Inform the register allocator of a reference result. - void MarkAsReference(Node* node); - // Inform the register allocation of the representation of the value produced // by {node}. void MarkAsRepresentation(MachineType rep, Node* node); + void MarkAsWord32(Node* node) { MarkAsRepresentation(kRepWord32, node); } + void MarkAsWord64(Node* node) { MarkAsRepresentation(kRepWord64, node); } + void MarkAsFloat32(Node* node) { MarkAsRepresentation(kRepFloat32, node); } + void MarkAsFloat64(Node* node) { MarkAsRepresentation(kRepFloat64, node); } + void MarkAsReference(Node* node) { MarkAsRepresentation(kRepTagged, node); } // Inform the register allocation of the representation of the unallocated // operand {op}. diff --git a/src/compiler/instruction.cc b/src/compiler/instruction.cc index df3d345fc5..ed66db2ce1 100644 --- a/src/compiler/instruction.cc +++ b/src/compiler/instruction.cc @@ -53,22 +53,48 @@ std::ostream& operator<<(std::ostream& os, return os << "[immediate:" << imm.indexed_value() << "]"; } } - case InstructionOperand::ALLOCATED: - switch (AllocatedOperand::cast(op).allocated_kind()) { + case InstructionOperand::ALLOCATED: { + auto allocated = AllocatedOperand::cast(op); + switch (allocated.allocated_kind()) { case AllocatedOperand::STACK_SLOT: - return os << "[stack:" << StackSlotOperand::cast(op).index() << "]"; + os << "[stack:" << StackSlotOperand::cast(op).index(); + break; case AllocatedOperand::DOUBLE_STACK_SLOT: - return os << "[double_stack:" - << DoubleStackSlotOperand::cast(op).index() << "]"; + os << "[double_stack:" << DoubleStackSlotOperand::cast(op).index(); + break; case AllocatedOperand::REGISTER: - return os << "[" - << conf->general_register_name( - RegisterOperand::cast(op).index()) << "|R]"; + os << "[" + << conf->general_register_name(RegisterOperand::cast(op).index()) + << "|R"; + break; case AllocatedOperand::DOUBLE_REGISTER: - return os << "[" - << conf->double_register_name( - DoubleRegisterOperand::cast(op).index()) << "|R]"; + os << "[" + << conf->double_register_name( + DoubleRegisterOperand::cast(op).index()) << "|R"; + break; } + switch (allocated.machine_type()) { + case kRepWord32: + os << "|w32"; + break; + case kRepWord64: + os << "|w64"; + break; + case kRepFloat32: + os << "|f32"; + break; + case kRepFloat64: + os << "|f64"; + break; + case kRepTagged: + os << "|t"; + break; + default: + os << "|?"; + break; + } + return os << "]"; + } case InstructionOperand::INVALID: return os << "(x)"; } @@ -83,7 +109,7 @@ std::ostream& operator<<(std::ostream& os, PrintableInstructionOperand printable_op = {printable.register_configuration_, mo.destination()}; os << printable_op; - if (mo.source() != mo.destination()) { + if (!mo.source().Equals(mo.destination())) { printable_op.op_ = mo.source(); os << " = " << printable_op; } @@ -104,11 +130,11 @@ MoveOperands* ParallelMove::PrepareInsertAfter(MoveOperands* move) const { MoveOperands* to_eliminate = nullptr; for (auto curr : *this) { if (curr->IsEliminated()) continue; - if (curr->destination() == move->source()) { + if (curr->destination().EqualsModuloType(move->source())) { DCHECK(!replacement); replacement = curr; if (to_eliminate != nullptr) break; - } else if (curr->destination() == move->destination()) { + } else if (curr->destination().EqualsModuloType(move->destination())) { DCHECK(!to_eliminate); to_eliminate = curr; if (replacement != nullptr) break; @@ -479,8 +505,7 @@ InstructionSequence::InstructionSequence(Isolate* isolate, instructions_(zone()), next_virtual_register_(0), reference_maps_(zone()), - doubles_(std::less(), VirtualRegisterSet::allocator_type(zone())), - references_(std::less(), VirtualRegisterSet::allocator_type(zone())), + representations_(zone()), deoptimization_entries_(zone()) { block_starts_.reserve(instruction_blocks_->size()); } @@ -548,23 +573,48 @@ const InstructionBlock* InstructionSequence::GetInstructionBlock( } -bool InstructionSequence::IsReference(int virtual_register) const { - return references_.find(virtual_register) != references_.end(); +static MachineType FilterRepresentation(MachineType rep) { + DCHECK_EQ(rep, RepresentationOf(rep)); + switch (rep) { + case kRepBit: + case kRepWord8: + case kRepWord16: + return InstructionSequence::DefaultRepresentation(); + case kRepWord32: + case kRepWord64: + case kRepFloat32: + case kRepFloat64: + case kRepTagged: + return rep; + default: + break; + } + UNREACHABLE(); + return kMachNone; } -bool InstructionSequence::IsDouble(int virtual_register) const { - return doubles_.find(virtual_register) != doubles_.end(); +MachineType InstructionSequence::GetRepresentation(int virtual_register) const { + DCHECK_LE(0, virtual_register); + DCHECK_LT(virtual_register, VirtualRegisterCount()); + if (virtual_register >= static_cast(representations_.size())) { + return DefaultRepresentation(); + } + return representations_[virtual_register]; } -void InstructionSequence::MarkAsReference(int virtual_register) { - references_.insert(virtual_register); -} - - -void InstructionSequence::MarkAsDouble(int virtual_register) { - doubles_.insert(virtual_register); +void InstructionSequence::MarkAsRepresentation(MachineType machine_type, + int virtual_register) { + DCHECK_LE(0, virtual_register); + DCHECK_LT(virtual_register, VirtualRegisterCount()); + if (virtual_register >= static_cast(representations_.size())) { + representations_.resize(VirtualRegisterCount(), DefaultRepresentation()); + } + machine_type = FilterRepresentation(machine_type); + DCHECK_IMPLIES(representations_[virtual_register] != machine_type, + representations_[virtual_register] == DefaultRepresentation()); + representations_[virtual_register] = machine_type; } diff --git a/src/compiler/instruction.h b/src/compiler/instruction.h index 9b9728224c..7d5105b93a 100644 --- a/src/compiler/instruction.h +++ b/src/compiler/instruction.h @@ -50,19 +50,6 @@ class InstructionOperand { inline bool IsStackSlot() const; inline bool IsDoubleStackSlot() const; - // Useful for map/set keys. - bool operator<(const InstructionOperand& op) const { - return value_ < op.value_; - } - - bool operator==(const InstructionOperand& op) const { - return value_ == op.value_; - } - - bool operator!=(const InstructionOperand& op) const { - return value_ != op.value_; - } - template static SubKindOperand* New(Zone* zone, const SubKindOperand& op) { void* buffer = zone->New(sizeof(op)); @@ -74,22 +61,43 @@ class InstructionOperand { *dest = *src; } + bool Equals(const InstructionOperand& that) const { + return this->value_ == that.value_; + } + + 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 {}; uint64_t value_; }; + struct PrintableInstructionOperand { const RegisterConfiguration* register_configuration_; InstructionOperand op_; }; + std::ostream& operator<<(std::ostream& os, const PrintableInstructionOperand& op); + #define INSTRUCTION_OPERAND_CASTS(OperandType, OperandKind) \ \ static OperandType* cast(InstructionOperand* op) { \ @@ -346,6 +354,8 @@ class ImmediateOperand : public InstructionOperand { 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, @@ -353,10 +363,12 @@ class AllocatedOperand : public InstructionOperand { DOUBLE_REGISTER }; - AllocatedOperand(AllocatedKind kind, int index) + 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(index) << IndexField::kShift; } @@ -368,14 +380,33 @@ class AllocatedOperand : public InstructionOperand { return AllocatedKindField::decode(value_); } - static AllocatedOperand* New(Zone* zone, AllocatedKind kind, int index) { - return InstructionOperand::New(zone, AllocatedOperand(kind, index)); + 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 {}; + class MachineTypeField : public BitField64 {}; class IndexField : public BitField64 {}; }; @@ -400,14 +431,17 @@ 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(int index) \ - : AllocatedOperand(kOperandKind, index) {} \ + explicit SubKind##Operand(MachineType machine_type, int index) \ + : AllocatedOperand(kOperandKind, machine_type, index) {} \ \ - static SubKind##Operand* New(Zone* zone, int index) { \ - return InstructionOperand::New(zone, SubKind##Operand(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) { \ @@ -429,6 +463,24 @@ 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, @@ -456,14 +508,14 @@ class MoveOperands final : public ZoneObject { // True if this move a move into the given destination operand. bool Blocks(const InstructionOperand& operand) const { - return !IsEliminated() && source() == operand; + return !IsEliminated() && source().EqualsModuloType(operand); } // A move is redundant if it's been eliminated or if its source and // destination are the same. bool IsRedundant() const { DCHECK_IMPLIES(!destination_.IsInvalid(), !destination_.IsConstant()); - return IsEliminated() || source_ == destination_; + return IsEliminated() || source_.EqualsModuloType(destination_); } // We clear both operands to indicate move that's been eliminated. @@ -551,7 +603,7 @@ class ReferenceMap final : public ZoneObject { std::ostream& operator<<(std::ostream& os, const ReferenceMap& pm); -class Instruction { +class Instruction final { public: size_t OutputCount() const { return OutputCountField::decode(bit_field_); } const InstructionOperand* OutputAt(size_t i) const { @@ -676,10 +728,9 @@ class Instruction { ParallelMove* const* parallel_moves() const { return ¶llel_moves_[0]; } ParallelMove** parallel_moves() { return ¶llel_moves_[0]; } - protected: + private: explicit Instruction(InstructionCode opcode); - private: Instruction(InstructionCode opcode, size_t output_count, InstructionOperand* outputs, size_t input_count, InstructionOperand* inputs, size_t temp_count, @@ -696,7 +747,6 @@ class Instruction { ReferenceMap* reference_map_; InstructionOperand operands_[1]; - private: DISALLOW_COPY_AND_ASSIGN(Instruction); }; @@ -1004,11 +1054,24 @@ class InstructionSequence final : public ZoneObject { const InstructionBlock* GetInstructionBlock(int instruction_index) const; - bool IsReference(int virtual_register) const; - bool IsDouble(int virtual_register) const; + static MachineType DefaultRepresentation() { + return kPointerSize == 8 ? kRepWord64 : kRepWord32; + } + MachineType GetRepresentation(int virtual_register) const; + void MarkAsRepresentation(MachineType machine_type, int virtual_register); - void MarkAsReference(int virtual_register); - void MarkAsDouble(int virtual_register); + 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; + } + } Instruction* GetBlockStart(RpoNumber rpo) const; @@ -1111,8 +1174,7 @@ class InstructionSequence final : public ZoneObject { InstructionDeque instructions_; int next_virtual_register_; ReferenceMapDeque reference_maps_; - VirtualRegisterSet doubles_; - VirtualRegisterSet references_; + ZoneVector representations_; DeoptimizationVector deoptimization_entries_; DISALLOW_COPY_AND_ASSIGN(InstructionSequence); diff --git a/src/compiler/move-optimizer.cc b/src/compiler/move-optimizer.cc index ea514aaa13..d55005f768 100644 --- a/src/compiler/move-optimizer.cc +++ b/src/compiler/move-optimizer.cc @@ -11,8 +11,18 @@ namespace compiler { namespace { typedef std::pair MoveKey; -typedef ZoneMap MoveMap; -typedef ZoneSet OperandSet; + +struct MoveKeyCompare { + bool operator()(const MoveKey& a, const MoveKey& b) const { + if (a.first.EqualsModuloType(b.first)) { + return a.second.CompareModuloType(b.second); + } + return a.first.CompareModuloType(b.first); + } +}; + +typedef ZoneMap MoveMap; +typedef ZoneSet OperandSet; bool GapsCanMoveOver(Instruction* instr) { return instr->IsNop(); } @@ -224,10 +234,12 @@ bool IsSlot(const InstructionOperand& op) { bool LoadCompare(const MoveOperands* a, const MoveOperands* b) { - if (a->source() != b->source()) return a->source() < b->source(); + if (!a->source().EqualsModuloType(b->source())) { + return a->source().CompareModuloType(b->source()); + } if (IsSlot(a->destination()) && !IsSlot(b->destination())) return false; if (!IsSlot(a->destination()) && IsSlot(b->destination())) return true; - return a->destination() < b->destination(); + return a->destination().CompareModuloType(b->destination()); } } // namespace @@ -252,7 +264,8 @@ void MoveOptimizer::FinalizeMoves(Instruction* instr) { MoveOperands* group_begin = nullptr; for (auto load : loads) { // New group. - if (group_begin == nullptr || load->source() != group_begin->source()) { + if (group_begin == nullptr || + !load->source().EqualsModuloType(group_begin->source())) { group_begin = load; continue; } diff --git a/src/compiler/register-allocator-verifier.cc b/src/compiler/register-allocator-verifier.cc index 2a749dd5f8..f23d24433f 100644 --- a/src/compiler/register-allocator-verifier.cc +++ b/src/compiler/register-allocator-verifier.cc @@ -163,7 +163,7 @@ void RegisterAllocatorVerifier::BuildConstraint(const InstructionOperand* op, CHECK(false); break; case UnallocatedOperand::NONE: - if (sequence()->IsDouble(vreg)) { + if (sequence()->IsFloat(vreg)) { constraint->type_ = kNoneDouble; } else { constraint->type_ = kNone; @@ -178,14 +178,14 @@ void RegisterAllocatorVerifier::BuildConstraint(const InstructionOperand* op, constraint->value_ = unallocated->fixed_register_index(); break; case UnallocatedOperand::MUST_HAVE_REGISTER: - if (sequence()->IsDouble(vreg)) { + if (sequence()->IsFloat(vreg)) { constraint->type_ = kDoubleRegister; } else { constraint->type_ = kRegister; } break; case UnallocatedOperand::MUST_HAVE_SLOT: - if (sequence()->IsDouble(vreg)) { + if (sequence()->IsFloat(vreg)) { constraint->type_ = kDoubleSlot; } else { constraint->type_ = kSlot; @@ -286,7 +286,7 @@ class PhiMap : public ZoneMap, public ZoneObject { struct OperandLess { bool operator()(const InstructionOperand* a, const InstructionOperand* b) const { - return *a < *b; + return a->CompareModuloType(*b); } }; @@ -320,7 +320,7 @@ class OperandMap : public ZoneObject { this->erase(it++); if (it == this->end()) return; } - if (*it->first == *o.first) { + if (it->first->EqualsModuloType(*o.first)) { ++it; if (it == this->end()) return; } else { @@ -372,13 +372,14 @@ class OperandMap : public ZoneObject { } void DropRegisters(const RegisterConfiguration* config) { - for (int i = 0; i < config->num_general_registers(); ++i) { - RegisterOperand op(i); - Drop(&op); - } - for (int i = 0; i < config->num_double_registers(); ++i) { - DoubleRegisterOperand op(i); - Drop(&op); + // TODO(dcarney): sort map by kind and drop range. + for (auto it = map().begin(); it != map().end();) { + auto op = it->first; + if (op->IsRegister() || op->IsDoubleRegister()) { + map().erase(it++); + } else { + ++it; + } } } diff --git a/src/compiler/register-allocator.cc b/src/compiler/register-allocator.cc index 49229d5872..7b2caff60c 100644 --- a/src/compiler/register-allocator.cc +++ b/src/compiler/register-allocator.cc @@ -89,6 +89,27 @@ bool IsOutputDoubleRegisterOf(Instruction* instr, int index) { return false; } + +// TODO(dcarney): fix frame to allow frame accesses to half size location. +int GetByteWidth(MachineType machine_type) { + DCHECK_EQ(RepresentationOf(machine_type), machine_type); + switch (machine_type) { + case kRepBit: + case kRepWord8: + case kRepWord16: + case kRepWord32: + case kRepTagged: + return kPointerSize; + case kRepFloat32: + case kRepWord64: + case kRepFloat64: + return 8; + default: + UNREACHABLE(); + return 0; + } +} + } // namespace @@ -214,7 +235,7 @@ struct LiveRange::SpillAtDefinitionList : ZoneObject { }; -LiveRange::LiveRange(int id) +LiveRange::LiveRange(int id, MachineType machine_type) : id_(id), spill_start_index_(kMaxInt), bits_(0), @@ -228,8 +249,10 @@ LiveRange::LiveRange(int id) current_interval_(nullptr), last_processed_use_(nullptr), current_hint_position_(nullptr) { + DCHECK(AllocatedOperand::IsSupportedMachineType(machine_type)); bits_ = SpillTypeField::encode(SpillType::kNoSpillType) | - AssignedRegisterField::encode(kUnassignedRegister); + AssignedRegisterField::encode(kUnassignedRegister) | + MachineTypeField::encode(machine_type); } @@ -268,6 +291,18 @@ void LiveRange::Spill() { } +RegisterKind LiveRange::kind() const { + switch (RepresentationOf(machine_type())) { + case kRepFloat32: + case kRepFloat64: + return DOUBLE_REGISTERS; + default: + break; + } + return GENERAL_REGISTERS; +} + + void LiveRange::SpillAtDefinition(Zone* zone, int gap_index, InstructionOperand* operand) { DCHECK(HasNoSpillType()); @@ -277,9 +312,9 @@ void LiveRange::SpillAtDefinition(Zone* zone, int gap_index, void LiveRange::CommitSpillsAtDefinition(InstructionSequence* sequence, - InstructionOperand* op, + const InstructionOperand& op, bool might_be_duplicated) { - DCHECK_IMPLIES(op->IsConstant(), spills_at_definition_ == nullptr); + DCHECK_IMPLIES(op.IsConstant(), spills_at_definition_ == nullptr); DCHECK(!IsChild()); auto zone = sequence->zone(); for (auto to_spill = spills_at_definition_; to_spill != nullptr; @@ -292,15 +327,15 @@ void LiveRange::CommitSpillsAtDefinition(InstructionSequence* sequence, bool found = false; for (auto move_op : *move) { if (move_op->IsEliminated()) continue; - if (move_op->source() == *to_spill->operand && - move_op->destination() == *op) { + if (move_op->source().Equals(*to_spill->operand) && + move_op->destination().Equals(op)) { found = true; break; } } if (found) continue; } - move->AddMove(*to_spill->operand, *op); + move->AddMove(*to_spill->operand, op); } } @@ -329,14 +364,6 @@ void LiveRange::SetSpillRange(SpillRange* spill_range) { } -void LiveRange::CommitSpillOperand(AllocatedOperand* operand) { - DCHECK(HasSpillRange()); - DCHECK(!IsChild()); - set_spill_type(SpillType::kSpillOperand); - spill_operand_ = operand; -} - - UsePosition* LiveRange::NextUsePosition(LifetimePosition start) const { UsePosition* use_pos = last_processed_use_; if (use_pos == nullptr || use_pos->pos() > start) { @@ -395,18 +422,33 @@ InstructionOperand LiveRange::GetAssignedOperand() const { DCHECK(!spilled()); switch (kind()) { case GENERAL_REGISTERS: - return RegisterOperand(assigned_register()); + return RegisterOperand(machine_type(), assigned_register()); case DOUBLE_REGISTERS: - return DoubleRegisterOperand(assigned_register()); - default: - UNREACHABLE(); + return DoubleRegisterOperand(machine_type(), assigned_register()); } } DCHECK(spilled()); DCHECK(!HasRegisterAssigned()); - auto op = TopLevel()->GetSpillOperand(); - DCHECK(!op->IsUnallocated()); - return *op; + if (TopLevel()->HasSpillOperand()) { + auto op = TopLevel()->GetSpillOperand(); + DCHECK(!op->IsUnallocated()); + return *op; + } + return TopLevel()->GetSpillRangeOperand(); +} + + +AllocatedOperand LiveRange::GetSpillRangeOperand() const { + auto spill_range = GetSpillRange(); + int index = spill_range->assigned_slot(); + switch (kind()) { + case GENERAL_REGISTERS: + return StackSlotOperand(machine_type(), index); + case DOUBLE_REGISTERS: + return DoubleStackSlotOperand(machine_type(), index); + } + UNREACHABLE(); + return StackSlotOperand(kMachNone, 0); } @@ -512,7 +554,6 @@ void LiveRange::SplitAt(LifetimePosition position, LiveRange* result, // Link the new live range in the chain before any of the other // ranges linked from the range before the split. result->parent_ = (parent_ == nullptr) ? this : parent_; - result->set_kind(result->parent_->kind()); result->next_ = next_; next_ = result; @@ -626,15 +667,14 @@ void LiveRange::AddUsePosition(UsePosition* use_pos) { void LiveRange::ConvertUsesToOperand(const InstructionOperand& op, - InstructionOperand* spill_op) { + const InstructionOperand& spill_op) { for (auto pos = first_pos(); pos != nullptr; pos = pos->next()) { DCHECK(Start() <= pos->pos() && pos->pos() <= End()); if (!pos->HasOperand()) continue; switch (pos->type()) { case UsePositionType::kRequiresSlot: - if (spill_op != nullptr) { - InstructionOperand::ReplaceWith(pos->operand(), spill_op); - } + DCHECK(spill_op.IsStackSlot() || spill_op.IsDoubleStackSlot()); + InstructionOperand::ReplaceWith(pos->operand(), &spill_op); break; case UsePositionType::kRequiresRegister: DCHECK(op.IsRegister() || op.IsDoubleRegister()); @@ -726,7 +766,8 @@ static bool AreUseIntervalsIntersecting(UseInterval* interval1, } -SpillRange::SpillRange(LiveRange* parent, Zone* zone) : live_ranges_(zone) { +SpillRange::SpillRange(LiveRange* parent, Zone* zone) + : live_ranges_(zone), assigned_slot_(kUnassignedSlot) { DCHECK(!parent->IsChild()); UseInterval* result = nullptr; UseInterval* node = nullptr; @@ -752,6 +793,11 @@ SpillRange::SpillRange(LiveRange* parent, Zone* zone) : live_ranges_(zone) { } +int SpillRange::ByteWidth() const { + return GetByteWidth(live_ranges_[0]->machine_type()); +} + + bool SpillRange::IsIntersectingWith(SpillRange* other) const { if (this->use_interval_ == nullptr || other->use_interval_ == nullptr || this->End() <= other->use_interval_->start() || @@ -763,7 +809,11 @@ bool SpillRange::IsIntersectingWith(SpillRange* other) const { bool SpillRange::TryMerge(SpillRange* other) { - if (kind() != other->kind() || IsIntersectingWith(other)) return false; + // TODO(dcarney): byte widths should be compared here not kinds. + if (live_ranges_[0]->kind() != other->live_ranges_[0]->kind() || + IsIntersectingWith(other)) { + return false; + } auto max = LifetimePosition::MaxPosition(); if (End() < other->End() && other->End() != max) { @@ -787,14 +837,6 @@ bool SpillRange::TryMerge(SpillRange* other) { } -void SpillRange::SetOperand(AllocatedOperand* op) { - for (auto range : live_ranges()) { - DCHECK(range->GetSpillRange() == this); - range->CommitSpillOperand(op); - } -} - - void SpillRange::MergeDisjointIntervals(UseInterval* other) { UseInterval* tail = nullptr; auto current = use_interval_; @@ -861,7 +903,8 @@ RegisterAllocationData::RegisterAllocationData( allocation_zone()), spill_ranges_(allocation_zone()), assigned_registers_(nullptr), - assigned_double_registers_(nullptr) { + assigned_double_registers_(nullptr), + virtual_register_count_(code->VirtualRegisterCount()) { DCHECK(this->config()->num_general_registers() <= RegisterConfiguration::kMaxGeneralRegisters); DCHECK(this->config()->num_double_registers() <= @@ -876,19 +919,6 @@ RegisterAllocationData::RegisterAllocationData( } -LiveRange* RegisterAllocationData::LiveRangeFor(int index) { - if (index >= static_cast(live_ranges().size())) { - live_ranges().resize(index + 1, nullptr); - } - auto result = live_ranges()[index]; - if (result == nullptr) { - result = NewLiveRange(index); - live_ranges()[index] = result; - } - return result; -} - - MoveOperands* RegisterAllocationData::AddGapMove( int index, Instruction::GapPosition position, const InstructionOperand& from, const InstructionOperand& to) { @@ -898,8 +928,40 @@ MoveOperands* RegisterAllocationData::AddGapMove( } -LiveRange* RegisterAllocationData::NewLiveRange(int index) { - return new (allocation_zone()) LiveRange(index); +MachineType RegisterAllocationData::MachineTypeFor(int virtual_register) { + DCHECK_LT(virtual_register, code()->VirtualRegisterCount()); + return code()->GetRepresentation(virtual_register); +} + + +LiveRange* RegisterAllocationData::LiveRangeFor(int index) { + if (index >= static_cast(live_ranges().size())) { + live_ranges().resize(index + 1, nullptr); + } + auto result = live_ranges()[index]; + if (result == nullptr) { + result = NewLiveRange(index, MachineTypeFor(index)); + live_ranges()[index] = result; + } + return result; +} + + +LiveRange* RegisterAllocationData::NewLiveRange(int index, + MachineType machine_type) { + return new (allocation_zone()) LiveRange(index, machine_type); +} + + +LiveRange* RegisterAllocationData::NewChildRangeFor(LiveRange* range) { + int vreg = virtual_register_count_++; + if (vreg >= static_cast(live_ranges().size())) { + live_ranges().resize(vreg + 1, nullptr); + } + auto child = new (allocation_zone()) LiveRange(vreg, range->machine_type()); + DCHECK_NULL(live_ranges()[vreg]); + live_ranges()[vreg] = child; + return child; } @@ -972,15 +1034,21 @@ InstructionOperand* ConstraintBuilder::AllocateFixed( TRACE("Allocating fixed reg for op %d\n", operand->virtual_register()); DCHECK(operand->HasFixedPolicy()); InstructionOperand allocated; + MachineType machine_type = InstructionSequence::DefaultRepresentation(); + int virtual_register = operand->virtual_register(); + if (virtual_register != InstructionOperand::kInvalidVirtualRegister) { + machine_type = data()->MachineTypeFor(virtual_register); + } if (operand->HasFixedSlotPolicy()) { - allocated = AllocatedOperand(AllocatedOperand::STACK_SLOT, + allocated = AllocatedOperand(AllocatedOperand::STACK_SLOT, machine_type, operand->fixed_slot_index()); } else if (operand->HasFixedRegisterPolicy()) { - allocated = AllocatedOperand(AllocatedOperand::REGISTER, + allocated = AllocatedOperand(AllocatedOperand::REGISTER, machine_type, operand->fixed_register_index()); } else if (operand->HasFixedDoubleRegisterPolicy()) { + DCHECK_NE(InstructionOperand::kInvalidVirtualRegister, virtual_register); allocated = AllocatedOperand(AllocatedOperand::DOUBLE_REGISTER, - operand->fixed_register_index()); + machine_type, operand->fixed_register_index()); } else { UNREACHABLE(); } @@ -1248,9 +1316,9 @@ LiveRange* LiveRangeBuilder::FixedLiveRangeFor(int index) { DCHECK(index < config()->num_general_registers()); auto result = data()->fixed_live_ranges()[index]; if (result == nullptr) { - result = data()->NewLiveRange(FixedLiveRangeID(index)); + result = data()->NewLiveRange(FixedLiveRangeID(index), + InstructionSequence::DefaultRepresentation()); DCHECK(result->IsFixed()); - result->set_kind(GENERAL_REGISTERS); result->set_assigned_register(index); data()->MarkAllocated(GENERAL_REGISTERS, index); data()->fixed_live_ranges()[index] = result; @@ -1263,9 +1331,8 @@ LiveRange* LiveRangeBuilder::FixedDoubleLiveRangeFor(int index) { DCHECK(index < config()->num_aliased_double_registers()); auto result = data()->fixed_double_live_ranges()[index]; if (result == nullptr) { - result = data()->NewLiveRange(FixedDoubleLiveRangeID(index)); + result = data()->NewLiveRange(FixedDoubleLiveRangeID(index), kRepFloat64); DCHECK(result->IsFixed()); - result->set_kind(DOUBLE_REGISTERS); result->set_assigned_register(index); data()->MarkAllocated(DOUBLE_REGISTERS, index); data()->fixed_double_live_ranges()[index] = result; @@ -1565,7 +1632,6 @@ void LiveRangeBuilder::BuildLiveRanges() { // Postprocess the ranges. for (auto range : data()->live_ranges()) { if (range == nullptr) continue; - range->set_kind(RequiredRegisterKind(range->id())); // Give slots to all ranges with a non fixed slot use. if (range->has_slot_use() && range->HasNoSpillType()) { data()->AssignSpillRangeToLiveRange(range); @@ -1610,13 +1676,6 @@ void LiveRangeBuilder::ResolvePhiHint(InstructionOperand* operand, } -RegisterKind LiveRangeBuilder::RequiredRegisterKind( - int virtual_register) const { - return (code()->IsDouble(virtual_register)) ? DOUBLE_REGISTERS - : GENERAL_REGISTERS; -} - - void LiveRangeBuilder::Verify() const { for (auto& hint : phi_hints_) { CHECK(hint.second->IsResolved()); @@ -1647,8 +1706,7 @@ LiveRange* RegisterAllocator::SplitRangeAt(LiveRange* range, (GetInstructionBlock(code(), pos)->last_instruction_index() != pos.ToInstructionIndex())); - int vreg = code()->NextVirtualRegister(); - auto result = LiveRangeFor(vreg); + auto result = data()->NewChildRangeFor(range); range->SplitAt(pos, result, allocation_zone()); return result; } @@ -2652,13 +2710,9 @@ void OperandAssigner::AssignSpillSlots() { for (auto range : spill_ranges) { if (range->IsEmpty()) continue; // Allocate a new operand referring to the spill slot. - auto kind = range->kind(); - int index = data()->frame()->AllocateSpillSlot(kind == DOUBLE_REGISTERS); - auto op_kind = kind == DOUBLE_REGISTERS - ? AllocatedOperand::DOUBLE_STACK_SLOT - : AllocatedOperand::STACK_SLOT; - auto op = AllocatedOperand::New(data()->code_zone(), op_kind, index); - range->SetOperand(op); + int byte_width = range->ByteWidth(); + int index = data()->frame()->AllocateSpillSlot(byte_width); + range->set_assigned_slot(index); } } @@ -2666,16 +2720,18 @@ void OperandAssigner::AssignSpillSlots() { void OperandAssigner::CommitAssignment() { for (auto range : data()->live_ranges()) { if (range == nullptr || range->IsEmpty()) continue; - InstructionOperand* spill_operand = nullptr; - if (!range->TopLevel()->HasNoSpillType()) { - spill_operand = range->TopLevel()->GetSpillOperand(); + InstructionOperand spill_operand; + if (range->TopLevel()->HasSpillOperand()) { + spill_operand = *range->TopLevel()->GetSpillOperand(); + } else if (range->TopLevel()->HasSpillRange()) { + spill_operand = range->TopLevel()->GetSpillRangeOperand(); } auto assigned = range->GetAssignedOperand(); range->ConvertUsesToOperand(assigned, spill_operand); if (range->is_phi()) { data()->GetPhiMapValueFor(range->id())->CommitAssignment(assigned); } - if (!range->IsChild() && spill_operand != nullptr) { + if (!range->IsChild() && !spill_operand.IsInvalid()) { range->CommitSpillsAtDefinition(data()->code(), spill_operand, range->has_slot_use()); } @@ -2756,12 +2812,21 @@ void ReferenceMapPopulator::PopulateReferenceMaps() { // Check if the live range is spilled and the safe point is after // the spill position. - if (range->HasSpillOperand() && - safe_point >= range->spill_start_index() && - !range->GetSpillOperand()->IsConstant()) { + if (((range->HasSpillOperand() && + !range->GetSpillOperand()->IsConstant()) || + range->HasSpillRange()) && + safe_point >= range->spill_start_index()) { TRACE("Pointer for range %d (spilled at %d) at safe point %d\n", range->id(), range->spill_start_index(), safe_point); - map->RecordReference(*range->GetSpillOperand()); + InstructionOperand operand; + if (range->HasSpillOperand()) { + operand = *range->GetSpillOperand(); + } else { + operand = range->GetSpillRangeOperand(); + } + DCHECK(operand.IsStackSlot()); + DCHECK_EQ(kRepTagged, AllocatedOperand::cast(operand).machine_type()); + map->RecordReference(operand); } if (!cur->spilled()) { @@ -2771,6 +2836,7 @@ void ReferenceMapPopulator::PopulateReferenceMaps() { cur->id(), cur->Start().value(), safe_point); auto operand = cur->GetAssignedOperand(); DCHECK(!operand.IsStackSlot()); + DCHECK_EQ(kRepTagged, AllocatedOperand::cast(operand).machine_type()); map->RecordReference(operand); } } @@ -2909,6 +2975,24 @@ class LiveRangeFinder { DISALLOW_COPY_AND_ASSIGN(LiveRangeFinder); }; + +typedef std::pair DelayedInsertionMapKey; + + +struct DelayedInsertionMapCompare { + bool operator()(const DelayedInsertionMapKey& a, + const DelayedInsertionMapKey& b) const { + if (a.first == b.first) { + return a.second.Compare(b.second); + } + return a.first < b.first; + } +}; + + +typedef ZoneMap DelayedInsertionMap; + } // namespace @@ -2942,7 +3026,7 @@ void LiveRangeConnector::ResolveControlFlow(Zone* local_zone) { continue; auto pred_op = result.pred_cover_->GetAssignedOperand(); auto cur_op = result.cur_cover_->GetAssignedOperand(); - if (pred_op == cur_op) continue; + if (pred_op.Equals(cur_op)) continue; ResolveControlFlow(block, cur_op, pred_block, pred_op); } iterator.Advance(); @@ -2955,7 +3039,7 @@ void LiveRangeConnector::ResolveControlFlow(const InstructionBlock* block, const InstructionOperand& cur_op, const InstructionBlock* pred, const InstructionOperand& pred_op) { - DCHECK(pred_op != cur_op); + DCHECK(!pred_op.Equals(cur_op)); int gap_index; Instruction::GapPosition position; if (block->PredecessorCount() == 1) { @@ -2974,8 +3058,7 @@ void LiveRangeConnector::ResolveControlFlow(const InstructionBlock* block, void LiveRangeConnector::ConnectRanges(Zone* local_zone) { - ZoneMap, InstructionOperand> - delayed_insertion_map(local_zone); + DelayedInsertionMap delayed_insertion_map(local_zone); for (auto first_range : data()->live_ranges()) { if (first_range == nullptr || first_range->IsChild()) continue; for (auto second_range = first_range->next(); second_range != nullptr; @@ -2991,7 +3074,7 @@ void LiveRangeConnector::ConnectRanges(Zone* local_zone) { } auto prev_operand = first_range->GetAssignedOperand(); auto cur_operand = second_range->GetAssignedOperand(); - if (prev_operand == cur_operand) continue; + if (prev_operand.Equals(cur_operand)) continue; bool delay_insertion = false; Instruction::GapPosition gap_pos; int gap_index = pos.ToInstructionIndex(); diff --git a/src/compiler/register-allocator.h b/src/compiler/register-allocator.h index 50b89ede05..41f00af2d5 100644 --- a/src/compiler/register-allocator.h +++ b/src/compiler/register-allocator.h @@ -13,7 +13,6 @@ namespace internal { namespace compiler { enum RegisterKind { - UNALLOCATED_REGISTERS, GENERAL_REGISTERS, DOUBLE_REGISTERS }; @@ -272,7 +271,7 @@ class SpillRange; // intervals over the instruction ordering. class LiveRange final : public ZoneObject { public: - explicit LiveRange(int id); + explicit LiveRange(int id, MachineType machine_type); UseInterval* first_interval() const { return first_interval_; } UsePosition* first_pos() const { return first_pos_; } @@ -289,6 +288,8 @@ class LiveRange final : public ZoneObject { InstructionOperand GetAssignedOperand() const; int spill_start_index() const { return spill_start_index_; } + MachineType machine_type() const { return MachineTypeField::decode(bits_); } + int assigned_register() const { return AssignedRegisterField::decode(bits_); } bool HasRegisterAssigned() const { return assigned_register() != kUnassignedRegister; @@ -299,10 +300,7 @@ class LiveRange final : public ZoneObject { bool spilled() const { return SpilledField::decode(bits_); } void Spill(); - RegisterKind kind() const { return RegisterKindField::decode(bits_); } - void set_kind(RegisterKind kind) { - bits_ = RegisterKindField::update(bits_, kind); - } + RegisterKind kind() const; // Correct only for parent. bool is_phi() const { return IsPhiField::decode(bits_); } @@ -386,14 +384,14 @@ class LiveRange final : public ZoneObject { return spill_type() == SpillType::kSpillOperand; } bool HasSpillRange() const { return spill_type() == SpillType::kSpillRange; } + AllocatedOperand GetSpillRangeOperand() const; void SpillAtDefinition(Zone* zone, int gap_index, InstructionOperand* operand); void SetSpillOperand(InstructionOperand* operand); void SetSpillRange(SpillRange* spill_range); - void CommitSpillOperand(AllocatedOperand* operand); void CommitSpillsAtDefinition(InstructionSequence* sequence, - InstructionOperand* operand, + const InstructionOperand& operand, bool might_be_duplicated); void SetSpillStartIndex(int start) { @@ -416,7 +414,7 @@ class LiveRange final : public ZoneObject { void Verify() const; void ConvertUsesToOperand(const InstructionOperand& op, - InstructionOperand* spill_op); + const InstructionOperand& spill_op); void SetUseHints(int register_index); void UnsetUseHints() { SetUseHints(kUnassignedRegister); } @@ -437,9 +435,9 @@ class LiveRange final : public ZoneObject { typedef BitField HasSlotUseField; typedef BitField IsPhiField; typedef BitField IsNonLoopPhiField; - typedef BitField RegisterKindField; - typedef BitField SpillTypeField; - typedef BitField AssignedRegisterField; + typedef BitField SpillTypeField; + typedef BitField AssignedRegisterField; + typedef BitField MachineTypeField; int id_; int spill_start_index_; @@ -468,13 +466,23 @@ class LiveRange final : public ZoneObject { class SpillRange final : public ZoneObject { public: + static const int kUnassignedSlot = -1; SpillRange(LiveRange* range, Zone* zone); UseInterval* interval() const { return use_interval_; } - RegisterKind kind() const { return live_ranges_[0]->kind(); } + // Currently, only 4 or 8 byte slots are supported. + int ByteWidth() const; bool IsEmpty() const { return live_ranges_.empty(); } bool TryMerge(SpillRange* other); - void SetOperand(AllocatedOperand* op); + + void set_assigned_slot(int index) { + DCHECK_EQ(kUnassignedSlot, assigned_slot_); + assigned_slot_ = index; + } + int assigned_slot() { + DCHECK_NE(kUnassignedSlot, assigned_slot_); + return assigned_slot_; + } private: LifetimePosition End() const { return end_position_; } @@ -486,6 +494,7 @@ class SpillRange final : public ZoneObject { ZoneVector live_ranges_; UseInterval* use_interval_; LifetimePosition end_position_; + int assigned_slot_; DISALLOW_COPY_AND_ASSIGN(SpillRange); }; @@ -549,7 +558,12 @@ class RegisterAllocationData final : public ZoneObject { const char* debug_name() const { return debug_name_; } const RegisterConfiguration* config() const { return config_; } + MachineType MachineTypeFor(int virtual_register); + LiveRange* LiveRangeFor(int index); + // Creates a new live range. + LiveRange* NewLiveRange(int index, MachineType machine_type); + LiveRange* NewChildRangeFor(LiveRange* range); SpillRange* AssignSpillRangeToLiveRange(LiveRange* range); @@ -563,9 +577,6 @@ class RegisterAllocationData final : public ZoneObject { bool ExistsUseWithoutDefinition(); - // Creates a new live range. - LiveRange* NewLiveRange(int index); - void MarkAllocated(RegisterKind kind, int index); PhiMapValue* InitializePhiMap(const InstructionBlock* block, @@ -586,6 +597,7 @@ class RegisterAllocationData final : public ZoneObject { ZoneVector spill_ranges_; BitVector* assigned_registers_; BitVector* assigned_double_registers_; + int virtual_register_count_; DISALLOW_COPY_AND_ASSIGN(RegisterAllocationData); }; @@ -664,9 +676,6 @@ class LiveRangeBuilder final : public ZoneObject { void MapPhiHint(InstructionOperand* operand, UsePosition* use_pos); void ResolvePhiHint(InstructionOperand* operand, UsePosition* use_pos); - // Returns the register kind required by the given virtual register. - RegisterKind RequiredRegisterKind(int virtual_register) const; - UsePosition* NewUsePosition(LifetimePosition pos, InstructionOperand* operand, void* hint, UsePositionHintType hint_type); UsePosition* NewUsePosition(LifetimePosition pos) { diff --git a/test/cctest/compiler/test-gap-resolver.cc b/test/cctest/compiler/test-gap-resolver.cc index 09a7154089..a081ddb8fe 100644 --- a/test/cctest/compiler/test-gap-resolver.cc +++ b/test/cctest/compiler/test-gap-resolver.cc @@ -89,7 +89,8 @@ class InterpreterState { if (key.is_constant) { return ConstantOperand(key.index); } - return AllocatedOperand(key.kind, key.index); + return AllocatedOperand( + key.kind, InstructionSequence::DefaultRepresentation(), key.index); } friend std::ostream& operator<<(std::ostream& os, @@ -148,7 +149,7 @@ class ParallelMoveCreator : public HandleAndZoneScope { ParallelMove* Create(int size) { ParallelMove* parallel_move = new (main_zone()) ParallelMove(main_zone()); - std::set seen; + std::set seen; for (int i = 0; i < size; ++i) { MoveOperands mo(CreateRandomOperand(true), CreateRandomOperand(false)); if (!mo.IsRedundant() && seen.find(mo.destination()) == seen.end()) { @@ -160,18 +161,38 @@ class ParallelMoveCreator : public HandleAndZoneScope { } private: + MachineType RandomType() { + int index = rng_->NextInt(3); + switch (index) { + case 0: + return kRepWord32; + case 1: + return kRepWord64; + case 2: + return kRepTagged; + } + UNREACHABLE(); + return kMachNone; + } + + MachineType RandomDoubleType() { + int index = rng_->NextInt(2); + if (index == 0) return kRepFloat64; + return kRepFloat32; + } + InstructionOperand CreateRandomOperand(bool is_source) { int index = rng_->NextInt(6); // destination can't be Constant. switch (rng_->NextInt(is_source ? 5 : 4)) { case 0: - return StackSlotOperand(index); + return StackSlotOperand(RandomType(), index); case 1: - return DoubleStackSlotOperand(index); + return DoubleStackSlotOperand(RandomDoubleType(), index); case 2: - return RegisterOperand(index); + return RegisterOperand(RandomType(), index); case 3: - return DoubleRegisterOperand(index); + return DoubleRegisterOperand(RandomDoubleType(), index); case 4: return ConstantOperand(index); } diff --git a/test/cctest/compiler/test-instruction.cc b/test/cctest/compiler/test-instruction.cc index 22ee613b64..d3c4577588 100644 --- a/test/cctest/compiler/test-instruction.cc +++ b/test/cctest/compiler/test-instruction.cc @@ -263,8 +263,8 @@ TEST(InstructionAddGapMove) { CHECK(move); CHECK_EQ(1u, move->size()); MoveOperands* cur = move->at(0); - CHECK(op1 == cur->source()); - CHECK(op2 == cur->destination()); + CHECK(op1.Equals(cur->source())); + CHECK(op2.Equals(cur->destination())); } } @@ -308,15 +308,15 @@ TEST(InstructionOperands) { CHECK(k == m->TempCount()); for (size_t z = 0; z < i; z++) { - CHECK(outputs[z] == *m->OutputAt(z)); + CHECK(outputs[z].Equals(*m->OutputAt(z))); } for (size_t z = 0; z < j; z++) { - CHECK(inputs[z] == *m->InputAt(z)); + CHECK(inputs[z].Equals(*m->InputAt(z))); } for (size_t z = 0; z < k; z++) { - CHECK(temps[z] == *m->TempAt(z)); + CHECK(temps[z].Equals(*m->TempAt(z))); } } } diff --git a/test/cctest/compiler/test-jump-threading.cc b/test/cctest/compiler/test-jump-threading.cc index c1b9f95bd1..e0a4a2fc62 100644 --- a/test/cctest/compiler/test-jump-threading.cc +++ b/test/cctest/compiler/test-jump-threading.cc @@ -59,13 +59,14 @@ class TestCode : public HandleAndZoneScope { Start(); sequence_.AddInstruction(Instruction::New(main_zone(), kArchNop)); int index = static_cast(sequence_.instructions().size()) - 1; - AddGapMove(index, RegisterOperand(13), RegisterOperand(13)); + AddGapMove(index, RegisterOperand(kRepWord32, 13), + RegisterOperand(kRepWord32, 13)); } void NonRedundantMoves() { Start(); sequence_.AddInstruction(Instruction::New(main_zone(), kArchNop)); int index = static_cast(sequence_.instructions().size()) - 1; - AddGapMove(index, ConstantOperand(11), RegisterOperand(11)); + AddGapMove(index, ConstantOperand(11), RegisterOperand(kRepWord32, 11)); } void Other() { Start(); diff --git a/test/unittests/compiler/instruction-selector-unittest.cc b/test/unittests/compiler/instruction-selector-unittest.cc index 01aa80af77..645b0f689b 100644 --- a/test/unittests/compiler/instruction-selector-unittest.cc +++ b/test/unittests/compiler/instruction-selector-unittest.cc @@ -96,12 +96,12 @@ InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build( } for (auto i : s.virtual_registers_) { int const virtual_register = i.second; - if (sequence.IsDouble(virtual_register)) { + if (sequence.IsFloat(virtual_register)) { EXPECT_FALSE(sequence.IsReference(virtual_register)); s.doubles_.insert(virtual_register); } if (sequence.IsReference(virtual_register)) { - EXPECT_FALSE(sequence.IsDouble(virtual_register)); + EXPECT_FALSE(sequence.IsFloat(virtual_register)); s.references_.insert(virtual_register); } } diff --git a/test/unittests/compiler/move-optimizer-unittest.cc b/test/unittests/compiler/move-optimizer-unittest.cc index c82f4270bc..975706abbb 100644 --- a/test/unittests/compiler/move-optimizer-unittest.cc +++ b/test/unittests/compiler/move-optimizer-unittest.cc @@ -33,7 +33,7 @@ class MoveOptimizerTest : public InstructionSequenceTest { auto to = ConvertMoveArg(to_op); for (auto move : *moves) { if (move->IsRedundant()) continue; - if (move->source() == from && move->destination() == to) { + if (move->source().Equals(from) && move->destination().Equals(to)) { return true; } } @@ -67,10 +67,10 @@ class MoveOptimizerTest : public InstructionSequenceTest { case kConstant: return ConstantOperand(op.value_); case kFixedSlot: - return StackSlotOperand(op.value_); + return StackSlotOperand(kRepWord32, op.value_); case kFixedRegister: CHECK(0 <= op.value_ && op.value_ < num_general_registers()); - return RegisterOperand(op.value_); + return RegisterOperand(kRepWord32, op.value_); default: break; }