[turbofan] cleanup InstructionOperand a little
- ConstantOperand was using a too-small field too store its virtual register - drop ConvertTo, replace it with simple copy - split AllocatedOperand off from Immediate and Constant to make assignment clearer, also paving the way for small Immediates - put zone first in *Operand::New - driveby: drop delayed ssa deconstruction experiment R=titzer@chromium.org BUG= Review URL: https://codereview.chromium.org/1050803002 Cr-Commit-Position: refs/heads/master@{#27692}
This commit is contained in:
parent
a3dcfa2255
commit
07ff6d9f22
@ -151,7 +151,8 @@ class ArmOperandConverter FINAL : public InstructionOperandConverter {
|
||||
DCHECK(!op->IsDoubleRegister());
|
||||
DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
|
||||
// The linkage computes where all spill slots are located.
|
||||
FrameOffset offset = linkage()->GetFrameOffset(op->index(), frame(), 0);
|
||||
FrameOffset offset = linkage()->GetFrameOffset(
|
||||
AllocatedOperand::cast(op)->index(), frame(), 0);
|
||||
return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
|
||||
}
|
||||
};
|
||||
|
@ -188,7 +188,8 @@ class Arm64OperandConverter FINAL : public InstructionOperandConverter {
|
||||
DCHECK(!op->IsDoubleRegister());
|
||||
DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
|
||||
// The linkage computes where all spill slots are located.
|
||||
FrameOffset offset = linkage()->GetFrameOffset(op->index(), frame(), 0);
|
||||
FrameOffset offset = linkage()->GetFrameOffset(
|
||||
AllocatedOperand::cast(op)->index(), frame(), 0);
|
||||
return MemOperand(offset.from_stack_pointer() ? masm->StackPointer() : fp,
|
||||
offset.offset());
|
||||
}
|
||||
|
@ -90,20 +90,20 @@ class InstructionOperandConverter {
|
||||
}
|
||||
|
||||
Register ToRegister(InstructionOperand* op) {
|
||||
DCHECK(op->IsRegister());
|
||||
return Register::FromAllocationIndex(op->index());
|
||||
return Register::FromAllocationIndex(RegisterOperand::cast(op)->index());
|
||||
}
|
||||
|
||||
DoubleRegister ToDoubleRegister(InstructionOperand* op) {
|
||||
DCHECK(op->IsDoubleRegister());
|
||||
return DoubleRegister::FromAllocationIndex(op->index());
|
||||
return DoubleRegister::FromAllocationIndex(
|
||||
DoubleRegisterOperand::cast(op)->index());
|
||||
}
|
||||
|
||||
Constant ToConstant(InstructionOperand* op) {
|
||||
if (op->IsImmediate()) {
|
||||
return gen_->code()->GetImmediate(op->index());
|
||||
return gen_->code()->GetImmediate(ImmediateOperand::cast(op)->index());
|
||||
}
|
||||
return gen_->code()->GetConstant(op->index());
|
||||
return gen_->code()->GetConstant(
|
||||
ConstantOperand::cast(op)->virtual_register());
|
||||
}
|
||||
|
||||
double ToDouble(InstructionOperand* op) { return ToConstant(op).ToFloat64(); }
|
||||
|
@ -176,9 +176,11 @@ void CodeGenerator::RecordSafepoint(PointerMap* pointers, Safepoint::Kind kind,
|
||||
for (int i = 0; i < operands->length(); i++) {
|
||||
InstructionOperand* pointer = operands->at(i);
|
||||
if (pointer->IsStackSlot()) {
|
||||
safepoint.DefinePointerSlot(pointer->index(), zone());
|
||||
safepoint.DefinePointerSlot(StackSlotOperand::cast(pointer)->index(),
|
||||
zone());
|
||||
} else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
|
||||
Register reg = Register::FromAllocationIndex(pointer->index());
|
||||
Register reg = Register::FromAllocationIndex(
|
||||
RegisterOperand::cast(pointer)->index());
|
||||
safepoint.DefinePointerRegister(reg, zone());
|
||||
}
|
||||
}
|
||||
@ -512,18 +514,19 @@ void CodeGenerator::AddTranslationForOperand(Translation* translation,
|
||||
// rather than creating an int value.
|
||||
if (type == kMachBool || type == kRepBit || type == kMachInt32 ||
|
||||
type == kMachInt8 || type == kMachInt16) {
|
||||
translation->StoreInt32StackSlot(op->index());
|
||||
translation->StoreInt32StackSlot(StackSlotOperand::cast(op)->index());
|
||||
} else if (type == kMachUint32 || type == kMachUint16 ||
|
||||
type == kMachUint8) {
|
||||
translation->StoreUint32StackSlot(op->index());
|
||||
translation->StoreUint32StackSlot(StackSlotOperand::cast(op)->index());
|
||||
} else if ((type & kRepMask) == kRepTagged) {
|
||||
translation->StoreStackSlot(op->index());
|
||||
translation->StoreStackSlot(StackSlotOperand::cast(op)->index());
|
||||
} else {
|
||||
CHECK(false);
|
||||
}
|
||||
} else if (op->IsDoubleStackSlot()) {
|
||||
DCHECK((type & (kRepFloat32 | kRepFloat64)) != 0);
|
||||
translation->StoreDoubleStackSlot(op->index());
|
||||
translation->StoreDoubleStackSlot(
|
||||
DoubleStackSlotOperand::cast(op)->index());
|
||||
} else if (op->IsRegister()) {
|
||||
InstructionOperandConverter converter(this, instr);
|
||||
// TODO(jarin) kMachBool and kRepBit should materialize true and false
|
||||
|
@ -15,12 +15,10 @@ namespace compiler {
|
||||
typedef ZoneList<MoveOperands>::iterator op_iterator;
|
||||
|
||||
#ifdef ENABLE_SLOW_DCHECKS
|
||||
// TODO(svenpanne) Brush up InstructionOperand with comparison?
|
||||
struct InstructionOperandComparator {
|
||||
bool operator()(const InstructionOperand* x,
|
||||
const InstructionOperand* y) const {
|
||||
return (x->kind() < y->kind()) ||
|
||||
(x->kind() == y->kind() && x->index() < y->index());
|
||||
return *x < *y;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
@ -708,7 +708,7 @@ void GraphC1Visualizer::PrintLiveRange(LiveRange* range, const char* type) {
|
||||
PrintIndent();
|
||||
os_ << range->id() << " " << type;
|
||||
if (range->HasRegisterAssigned()) {
|
||||
InstructionOperand op = range->GetAssignedOperand();
|
||||
AllocatedOperand op = AllocatedOperand::cast(range->GetAssignedOperand());
|
||||
int assigned_reg = op.index();
|
||||
if (op.IsDoubleRegister()) {
|
||||
os_ << " \"" << DoubleRegister::AllocationIndexToString(assigned_reg)
|
||||
@ -718,18 +718,21 @@ void GraphC1Visualizer::PrintLiveRange(LiveRange* range, const char* type) {
|
||||
os_ << " \"" << Register::AllocationIndexToString(assigned_reg) << "\"";
|
||||
}
|
||||
} else if (range->IsSpilled()) {
|
||||
auto top = range->TopLevel();
|
||||
int index = -1;
|
||||
if (range->TopLevel()->HasSpillRange()) {
|
||||
if (top->HasSpillRange()) {
|
||||
index = kMaxInt; // This hasn't been set yet.
|
||||
} else if (top->GetSpillOperand()->IsConstant()) {
|
||||
os_ << " \"const(nostack):"
|
||||
<< ConstantOperand::cast(top->GetSpillOperand())->virtual_register()
|
||||
<< "\"";
|
||||
} else {
|
||||
index = range->TopLevel()->GetSpillOperand()->index();
|
||||
}
|
||||
if (range->TopLevel()->Kind() == DOUBLE_REGISTERS) {
|
||||
os_ << " \"double_stack:" << index << "\"";
|
||||
} else if (range->TopLevel()->Kind() == GENERAL_REGISTERS) {
|
||||
os_ << " \"stack:" << index << "\"";
|
||||
} else {
|
||||
os_ << " \"const(nostack):" << index << "\"";
|
||||
index = AllocatedOperand::cast(top->GetSpillOperand())->index();
|
||||
if (top->Kind() == DOUBLE_REGISTERS) {
|
||||
os_ << " \"double_stack:" << index << "\"";
|
||||
} else if (top->Kind() == GENERAL_REGISTERS) {
|
||||
os_ << " \"stack:" << index << "\"";
|
||||
}
|
||||
}
|
||||
}
|
||||
int parent_index = -1;
|
||||
|
@ -47,7 +47,8 @@ class IA32OperandConverter : public InstructionOperandConverter {
|
||||
}
|
||||
DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
|
||||
// The linkage computes where all spill slots are located.
|
||||
FrameOffset offset = linkage()->GetFrameOffset(op->index(), frame(), extra);
|
||||
FrameOffset offset = linkage()->GetFrameOffset(
|
||||
AllocatedOperand::cast(op)->index(), frame(), extra);
|
||||
return Operand(offset.from_stack_pointer() ? esp : ebp, offset.offset());
|
||||
}
|
||||
|
||||
|
@ -42,17 +42,23 @@ std::ostream& operator<<(std::ostream& os,
|
||||
}
|
||||
}
|
||||
case InstructionOperand::CONSTANT:
|
||||
return os << "[constant:" << op.index() << "]";
|
||||
return os << "[constant:" << ConstantOperand::cast(op).virtual_register()
|
||||
<< "]";
|
||||
case InstructionOperand::IMMEDIATE:
|
||||
return os << "[immediate:" << op.index() << "]";
|
||||
return os << "[immediate:" << ImmediateOperand::cast(op).index() << "]";
|
||||
case InstructionOperand::STACK_SLOT:
|
||||
return os << "[stack:" << op.index() << "]";
|
||||
return os << "[stack:" << StackSlotOperand::cast(op).index() << "]";
|
||||
case InstructionOperand::DOUBLE_STACK_SLOT:
|
||||
return os << "[double_stack:" << op.index() << "]";
|
||||
return os << "[double_stack:" << DoubleStackSlotOperand::cast(op).index()
|
||||
<< "]";
|
||||
case InstructionOperand::REGISTER:
|
||||
return os << "[" << conf->general_register_name(op.index()) << "|R]";
|
||||
return os << "["
|
||||
<< conf->general_register_name(
|
||||
RegisterOperand::cast(op).index()) << "|R]";
|
||||
case InstructionOperand::DOUBLE_REGISTER:
|
||||
return os << "[" << conf->double_register_name(op.index()) << "|R]";
|
||||
return os << "["
|
||||
<< conf->double_register_name(
|
||||
DoubleRegisterOperand::cast(op).index()) << "|R]";
|
||||
case InstructionOperand::INVALID:
|
||||
return os << "(x)";
|
||||
}
|
||||
@ -173,7 +179,7 @@ std::ostream& operator<<(std::ostream& os,
|
||||
|
||||
void PointerMap::RecordPointer(InstructionOperand* op, Zone* zone) {
|
||||
// Do not record arguments as pointers.
|
||||
if (op->IsStackSlot() && op->index() < 0) return;
|
||||
if (op->IsStackSlot() && StackSlotOperand::cast(op)->index() < 0) return;
|
||||
DCHECK(!op->IsDoubleRegister() && !op->IsDoubleStackSlot());
|
||||
pointer_operands_.Add(op, zone);
|
||||
}
|
||||
@ -181,7 +187,7 @@ void PointerMap::RecordPointer(InstructionOperand* op, Zone* zone) {
|
||||
|
||||
void PointerMap::RemovePointer(InstructionOperand* op) {
|
||||
// Do not record arguments as pointers.
|
||||
if (op->IsStackSlot() && op->index() < 0) return;
|
||||
if (op->IsStackSlot() && StackSlotOperand::cast(op)->index() < 0) return;
|
||||
DCHECK(!op->IsDoubleRegister() && !op->IsDoubleStackSlot());
|
||||
for (int i = 0; i < pointer_operands_.length(); ++i) {
|
||||
if (pointer_operands_[i]->Equals(op)) {
|
||||
@ -194,7 +200,7 @@ void PointerMap::RemovePointer(InstructionOperand* op) {
|
||||
|
||||
void PointerMap::RecordUntagged(InstructionOperand* op, Zone* zone) {
|
||||
// Do not record arguments as pointers.
|
||||
if (op->IsStackSlot() && op->index() < 0) return;
|
||||
if (op->IsStackSlot() && StackSlotOperand::cast(op)->index() < 0) return;
|
||||
DCHECK(!op->IsDoubleRegister() && !op->IsDoubleStackSlot());
|
||||
untagged_operands_.Add(op, zone);
|
||||
}
|
||||
@ -593,6 +599,16 @@ int InstructionSequence::GetFrameStateDescriptorCount() {
|
||||
}
|
||||
|
||||
|
||||
RpoNumber InstructionSequence::InputRpo(Instruction* instr, size_t index) {
|
||||
InstructionOperand* operand = instr->InputAt(index);
|
||||
Constant constant =
|
||||
operand->IsImmediate()
|
||||
? GetImmediate(ImmediateOperand::cast(operand)->index())
|
||||
: GetConstant(ConstantOperand::cast(operand)->virtual_register());
|
||||
return constant.ToRpoNumber();
|
||||
}
|
||||
|
||||
|
||||
FrameStateDescriptor::FrameStateDescriptor(
|
||||
Zone* zone, const FrameStateCallInfo& state_info, size_t parameters_count,
|
||||
size_t locals_count, size_t stack_count, FrameStateDescriptor* outer_state)
|
||||
|
@ -27,9 +27,7 @@ class Schedule;
|
||||
// A couple of reserved opcodes are used for internal use.
|
||||
const InstructionCode kSourcePositionInstruction = -1;
|
||||
|
||||
#define INSTRUCTION_OPERAND_LIST(V) \
|
||||
V(Constant, CONSTANT) \
|
||||
V(Immediate, IMMEDIATE) \
|
||||
#define ALLOCATED_OPERAND_LIST(V) \
|
||||
V(StackSlot, STACK_SLOT) \
|
||||
V(DoubleStackSlot, DOUBLE_STACK_SLOT) \
|
||||
V(Register, REGISTER) \
|
||||
@ -50,65 +48,50 @@ class InstructionOperand {
|
||||
DOUBLE_REGISTER
|
||||
};
|
||||
|
||||
InstructionOperand() { ConvertTo(INVALID, 0, kInvalidVirtualRegister); }
|
||||
|
||||
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, 0, kInvalidVirtualRegister) {}
|
||||
|
||||
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)
|
||||
ALLOCATED_OPERAND_LIST(INSTRUCTION_OPERAND_PREDICATE)
|
||||
INSTRUCTION_OPERAND_PREDICATE(Constant, CONSTANT)
|
||||
INSTRUCTION_OPERAND_PREDICATE(Immediate, IMMEDIATE)
|
||||
INSTRUCTION_OPERAND_PREDICATE(Unallocated, UNALLOCATED)
|
||||
INSTRUCTION_OPERAND_PREDICATE(Invalid, INVALID)
|
||||
#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);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
protected:
|
||||
InstructionOperand(Kind kind, int index, int virtual_register) {
|
||||
if (kind == REGISTER || kind == DOUBLE_REGISTER) DCHECK(index >= 0);
|
||||
if (kind != UNALLOCATED) {
|
||||
if (kind != UNALLOCATED && kind != CONSTANT) {
|
||||
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);
|
||||
}
|
||||
|
||||
typedef BitField64<Kind, 0, 3> KindField;
|
||||
@ -317,6 +300,138 @@ class UnallocatedOperand : public InstructionOperand {
|
||||
};
|
||||
|
||||
|
||||
class ConstantOperand : public InstructionOperand {
|
||||
public:
|
||||
explicit ConstantOperand(int virtual_register)
|
||||
: InstructionOperand(CONSTANT, 0, 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));
|
||||
}
|
||||
|
||||
static ConstantOperand* cast(InstructionOperand* op) {
|
||||
DCHECK(op->kind() == CONSTANT);
|
||||
return static_cast<ConstantOperand*>(op);
|
||||
}
|
||||
|
||||
static const ConstantOperand* cast(const InstructionOperand* op) {
|
||||
DCHECK(op->kind() == CONSTANT);
|
||||
return static_cast<const ConstantOperand*>(op);
|
||||
}
|
||||
|
||||
static ConstantOperand cast(const InstructionOperand& op) {
|
||||
DCHECK(op.kind() == CONSTANT);
|
||||
return *static_cast<const ConstantOperand*>(&op);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ImmediateOperand : public InstructionOperand {
|
||||
public:
|
||||
explicit ImmediateOperand(int index)
|
||||
: InstructionOperand(IMMEDIATE, index, kInvalidVirtualRegister) {}
|
||||
|
||||
int index() const {
|
||||
return static_cast<int64_t>(value_) >> IndexField::kShift;
|
||||
}
|
||||
|
||||
static ImmediateOperand* New(Zone* zone, int index) {
|
||||
return InstructionOperand::New(zone, ImmediateOperand(index));
|
||||
}
|
||||
|
||||
static ImmediateOperand* cast(InstructionOperand* op) {
|
||||
DCHECK(op->kind() == IMMEDIATE);
|
||||
return static_cast<ImmediateOperand*>(op);
|
||||
}
|
||||
|
||||
static const ImmediateOperand* cast(const InstructionOperand* op) {
|
||||
DCHECK(op->kind() == IMMEDIATE);
|
||||
return static_cast<const ImmediateOperand*>(op);
|
||||
}
|
||||
|
||||
static ImmediateOperand cast(const InstructionOperand& op) {
|
||||
DCHECK(op.kind() == IMMEDIATE);
|
||||
return *static_cast<const ImmediateOperand*>(&op);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class AllocatedOperand : public InstructionOperand {
|
||||
#define ALLOCATED_OPERAND_CHECK(Name, Kind) || kind == Kind
|
||||
#define CHECK_ALLOCATED_KIND() \
|
||||
DCHECK(false ALLOCATED_OPERAND_LIST(ALLOCATED_OPERAND_CHECK)); \
|
||||
USE(kind);
|
||||
|
||||
public:
|
||||
int index() const {
|
||||
return static_cast<int64_t>(value_) >> IndexField::kShift;
|
||||
}
|
||||
|
||||
AllocatedOperand(Kind kind, int index)
|
||||
: InstructionOperand(kind, index, kInvalidVirtualRegister) {
|
||||
CHECK_ALLOCATED_KIND();
|
||||
}
|
||||
|
||||
static AllocatedOperand* New(Zone* zone, Kind kind, int index) {
|
||||
return InstructionOperand::New(zone, AllocatedOperand(kind, index));
|
||||
}
|
||||
|
||||
static AllocatedOperand* cast(InstructionOperand* op) {
|
||||
Kind kind = op->kind();
|
||||
CHECK_ALLOCATED_KIND();
|
||||
return static_cast<AllocatedOperand*>(op);
|
||||
}
|
||||
|
||||
static const AllocatedOperand* cast(const InstructionOperand* op) {
|
||||
Kind kind = op->kind();
|
||||
CHECK_ALLOCATED_KIND();
|
||||
return static_cast<const AllocatedOperand*>(op);
|
||||
}
|
||||
|
||||
static AllocatedOperand cast(const InstructionOperand& op) {
|
||||
Kind kind = op.kind();
|
||||
CHECK_ALLOCATED_KIND();
|
||||
return *static_cast<const AllocatedOperand*>(&op);
|
||||
}
|
||||
|
||||
#undef CHECK_ALLOCATED_KIND
|
||||
#undef ALLOCATED_OPERAND_CAST_CHECK
|
||||
};
|
||||
|
||||
|
||||
#define INSTRUCTION_SUBKIND_OPERAND_CLASS(SubKind, kOperandKind) \
|
||||
class SubKind##Operand FINAL : public AllocatedOperand { \
|
||||
public: \
|
||||
explicit SubKind##Operand(int index) \
|
||||
: AllocatedOperand(kOperandKind, index) {} \
|
||||
\
|
||||
static SubKind##Operand* New(Zone* zone, int index) { \
|
||||
return InstructionOperand::New(zone, SubKind##Operand(index)); \
|
||||
} \
|
||||
\
|
||||
static SubKind##Operand* cast(InstructionOperand* op) { \
|
||||
DCHECK(op->kind() == kOperandKind); \
|
||||
return reinterpret_cast<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); \
|
||||
} \
|
||||
};
|
||||
ALLOCATED_OPERAND_LIST(INSTRUCTION_SUBKIND_OPERAND_CLASS)
|
||||
#undef INSTRUCTION_SUBKIND_OPERAND_CLASS
|
||||
|
||||
|
||||
class MoveOperands FINAL {
|
||||
public:
|
||||
MoveOperands(InstructionOperand* source, InstructionOperand* destination)
|
||||
@ -337,11 +452,11 @@ class MoveOperands FINAL {
|
||||
return !IsEliminated() && source()->Equals(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_ != nullptr, !destination_->IsConstant());
|
||||
return IsEliminated() || source_->Equals(destination_);
|
||||
}
|
||||
|
||||
// We clear both operands to indicate move that's been eliminated.
|
||||
@ -366,35 +481,6 @@ 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 {
|
||||
public:
|
||||
explicit ParallelMove(Zone* zone) : move_operands_(4, zone) {}
|
||||
@ -1016,12 +1102,7 @@ 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);
|
||||
|
||||
private:
|
||||
friend std::ostream& operator<<(std::ostream& os,
|
||||
|
@ -110,7 +110,8 @@ class MipsOperandConverter FINAL : public InstructionOperandConverter {
|
||||
DCHECK(!op->IsDoubleRegister());
|
||||
DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
|
||||
// The linkage computes where all spill slots are located.
|
||||
FrameOffset offset = linkage()->GetFrameOffset(op->index(), frame(), 0);
|
||||
FrameOffset offset = linkage()->GetFrameOffset(
|
||||
AllocatedOperand::cast(op)->index(), frame(), 0);
|
||||
return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
|
||||
}
|
||||
};
|
||||
|
@ -110,7 +110,8 @@ class MipsOperandConverter FINAL : public InstructionOperandConverter {
|
||||
DCHECK(!op->IsDoubleRegister());
|
||||
DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
|
||||
// The linkage computes where all spill slots are located.
|
||||
FrameOffset offset = linkage()->GetFrameOffset(op->index(), frame(), 0);
|
||||
FrameOffset offset = linkage()->GetFrameOffset(
|
||||
AllocatedOperand::cast(op)->index(), frame(), 0);
|
||||
return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
|
||||
}
|
||||
};
|
||||
|
@ -256,8 +256,7 @@ void MoveOptimizer::FinalizeMoves(Instruction* instr) {
|
||||
loads.push_back(move);
|
||||
// Replace source with copy for later use.
|
||||
auto dest = move->destination();
|
||||
move->set_destination(
|
||||
InstructionOperand::New(code_zone(), dest->kind(), dest->index()));
|
||||
move->set_destination(InstructionOperand::New(code_zone(), *dest));
|
||||
continue;
|
||||
}
|
||||
if ((found->destination()->IsStackSlot() ||
|
||||
@ -266,12 +265,10 @@ void MoveOptimizer::FinalizeMoves(Instruction* instr) {
|
||||
move->destination()->IsDoubleStackSlot())) {
|
||||
// Found a better source for this load. Smash it in place to affect other
|
||||
// loads that have already been split.
|
||||
InstructionOperand::Kind found_kind = found->destination()->kind();
|
||||
int found_index = found->destination()->index();
|
||||
auto next_dest =
|
||||
InstructionOperand::New(code_zone(), found_kind, found_index);
|
||||
InstructionOperand::New(code_zone(), *found->destination());
|
||||
auto dest = move->destination();
|
||||
found->destination()->ConvertTo(dest->kind(), dest->index());
|
||||
InstructionOperand::ReplaceWith(found->destination(), dest);
|
||||
move->set_destination(next_dest);
|
||||
}
|
||||
// move from load destination.
|
||||
|
@ -103,7 +103,8 @@ class PPCOperandConverter FINAL : public InstructionOperandConverter {
|
||||
DCHECK(!op->IsDoubleRegister());
|
||||
DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
|
||||
// The linkage computes where all spill slots are located.
|
||||
FrameOffset offset = linkage()->GetFrameOffset(op->index(), frame(), 0);
|
||||
FrameOffset offset = linkage()->GetFrameOffset(
|
||||
AllocatedOperand::cast(op)->index(), frame(), 0);
|
||||
return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
|
||||
}
|
||||
};
|
||||
|
@ -119,7 +119,7 @@ void RegisterAllocatorVerifier::BuildConstraint(const InstructionOperand* op,
|
||||
constraint->virtual_register_ = InstructionOperand::kInvalidVirtualRegister;
|
||||
if (op->IsConstant()) {
|
||||
constraint->type_ = kConstant;
|
||||
constraint->value_ = ConstantOperand::cast(op)->index();
|
||||
constraint->value_ = ConstantOperand::cast(op)->virtual_register();
|
||||
constraint->virtual_register_ = constraint->value_;
|
||||
} else if (op->IsImmediate()) {
|
||||
constraint->type_ = kImmediate;
|
||||
@ -180,29 +180,30 @@ void RegisterAllocatorVerifier::CheckConstraint(
|
||||
switch (constraint->type_) {
|
||||
case kConstant:
|
||||
CHECK(op->IsConstant());
|
||||
CHECK_EQ(op->index(), constraint->value_);
|
||||
CHECK_EQ(ConstantOperand::cast(op)->virtual_register(),
|
||||
constraint->value_);
|
||||
return;
|
||||
case kImmediate:
|
||||
CHECK(op->IsImmediate());
|
||||
CHECK_EQ(op->index(), constraint->value_);
|
||||
CHECK_EQ(ImmediateOperand::cast(op)->index(), constraint->value_);
|
||||
return;
|
||||
case kRegister:
|
||||
CHECK(op->IsRegister());
|
||||
return;
|
||||
case kFixedRegister:
|
||||
CHECK(op->IsRegister());
|
||||
CHECK_EQ(op->index(), constraint->value_);
|
||||
CHECK_EQ(RegisterOperand::cast(op)->index(), constraint->value_);
|
||||
return;
|
||||
case kDoubleRegister:
|
||||
CHECK(op->IsDoubleRegister());
|
||||
return;
|
||||
case kFixedDoubleRegister:
|
||||
CHECK(op->IsDoubleRegister());
|
||||
CHECK_EQ(op->index(), constraint->value_);
|
||||
CHECK_EQ(DoubleRegisterOperand::cast(op)->index(), constraint->value_);
|
||||
return;
|
||||
case kFixedSlot:
|
||||
CHECK(op->IsStackSlot());
|
||||
CHECK_EQ(op->index(), constraint->value_);
|
||||
CHECK_EQ(StackSlotOperand::cast(op)->index(), constraint->value_);
|
||||
return;
|
||||
case kSlot:
|
||||
CHECK(op->IsStackSlot());
|
||||
@ -343,11 +344,11 @@ class OperandMap : public ZoneObject {
|
||||
|
||||
void DropRegisters(const RegisterConfiguration* config) {
|
||||
for (int i = 0; i < config->num_general_registers(); ++i) {
|
||||
InstructionOperand op(InstructionOperand::REGISTER, i);
|
||||
RegisterOperand op(i);
|
||||
Drop(&op);
|
||||
}
|
||||
for (int i = 0; i < config->num_double_registers(); ++i) {
|
||||
InstructionOperand op(InstructionOperand::DOUBLE_REGISTER, i);
|
||||
DoubleRegisterOperand op(i);
|
||||
Drop(&op);
|
||||
}
|
||||
}
|
||||
|
@ -165,6 +165,7 @@ void LiveRange::SpillAtDefinition(Zone* zone, int gap_index,
|
||||
void LiveRange::CommitSpillsAtDefinition(InstructionSequence* sequence,
|
||||
InstructionOperand* op,
|
||||
bool might_be_duplicated) {
|
||||
DCHECK_IMPLIES(op->IsConstant(), spills_at_definition_ == nullptr);
|
||||
DCHECK(!IsChild());
|
||||
auto zone = sequence->zone();
|
||||
for (auto to_spill = spills_at_definition_; to_spill != nullptr;
|
||||
@ -194,7 +195,7 @@ void LiveRange::CommitSpillsAtDefinition(InstructionSequence* sequence,
|
||||
|
||||
void LiveRange::SetSpillOperand(InstructionOperand* operand) {
|
||||
DCHECK(HasNoSpillType());
|
||||
DCHECK(!operand->IsUnallocated());
|
||||
DCHECK(!operand->IsUnallocated() && !operand->IsImmediate());
|
||||
spill_type_ = SpillType::kSpillOperand;
|
||||
spill_operand_ = operand;
|
||||
}
|
||||
@ -208,9 +209,8 @@ void LiveRange::SetSpillRange(SpillRange* spill_range) {
|
||||
}
|
||||
|
||||
|
||||
void LiveRange::CommitSpillOperand(InstructionOperand* operand) {
|
||||
void LiveRange::CommitSpillOperand(AllocatedOperand* operand) {
|
||||
DCHECK(HasSpillRange());
|
||||
DCHECK(!operand->IsUnallocated());
|
||||
DCHECK(!IsChild());
|
||||
spill_type_ = SpillType::kSpillOperand;
|
||||
spill_operand_ = operand;
|
||||
@ -274,9 +274,9 @@ InstructionOperand* LiveRange::GetAssignedOperand(
|
||||
DCHECK(!IsSpilled());
|
||||
switch (Kind()) {
|
||||
case GENERAL_REGISTERS:
|
||||
return cache->RegisterOperand(assigned_register());
|
||||
return cache->GetRegisterOperand(assigned_register());
|
||||
case DOUBLE_REGISTERS:
|
||||
return cache->DoubleRegisterOperand(assigned_register());
|
||||
return cache->GetDoubleRegisterOperand(assigned_register());
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
@ -537,14 +537,14 @@ void LiveRange::ConvertUsesToOperand(InstructionOperand* op,
|
||||
switch (pos->type()) {
|
||||
case UsePositionType::kRequiresSlot:
|
||||
if (spill_op != nullptr) {
|
||||
pos->operand()->ConvertTo(spill_op->kind(), spill_op->index());
|
||||
InstructionOperand::ReplaceWith(pos->operand(), spill_op);
|
||||
}
|
||||
break;
|
||||
case UsePositionType::kRequiresRegister:
|
||||
DCHECK(op->IsRegister() || op->IsDoubleRegister());
|
||||
// Fall through.
|
||||
case UsePositionType::kAny:
|
||||
pos->operand()->ConvertTo(op->kind(), op->index());
|
||||
InstructionOperand::ReplaceWith(pos->operand(), op);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -599,12 +599,10 @@ LifetimePosition LiveRange::FirstIntersection(LiveRange* other) {
|
||||
|
||||
InstructionOperandCache::InstructionOperandCache() {
|
||||
for (size_t i = 0; i < arraysize(general_register_operands_); ++i) {
|
||||
general_register_operands_[i] =
|
||||
i::compiler::RegisterOperand(static_cast<int>(i));
|
||||
general_register_operands_[i] = RegisterOperand(static_cast<int>(i));
|
||||
}
|
||||
for (size_t i = 0; i < arraysize(double_register_operands_); ++i) {
|
||||
double_register_operands_[i] =
|
||||
i::compiler::DoubleRegisterOperand(static_cast<int>(i));
|
||||
double_register_operands_[i] = DoubleRegisterOperand(static_cast<int>(i));
|
||||
}
|
||||
}
|
||||
|
||||
@ -707,18 +705,20 @@ InstructionOperand* RegisterAllocator::AllocateFixed(
|
||||
UnallocatedOperand* operand, int pos, bool is_tagged) {
|
||||
TRACE("Allocating fixed reg for op %d\n", operand->virtual_register());
|
||||
DCHECK(operand->HasFixedPolicy());
|
||||
InstructionOperand allocated;
|
||||
if (operand->HasFixedSlotPolicy()) {
|
||||
operand->ConvertTo(InstructionOperand::STACK_SLOT,
|
||||
operand->fixed_slot_index());
|
||||
allocated = AllocatedOperand(InstructionOperand::STACK_SLOT,
|
||||
operand->fixed_slot_index());
|
||||
} else if (operand->HasFixedRegisterPolicy()) {
|
||||
int reg_index = operand->fixed_register_index();
|
||||
operand->ConvertTo(InstructionOperand::REGISTER, reg_index);
|
||||
allocated = AllocatedOperand(InstructionOperand::REGISTER,
|
||||
operand->fixed_register_index());
|
||||
} else if (operand->HasFixedDoubleRegisterPolicy()) {
|
||||
int reg_index = operand->fixed_register_index();
|
||||
operand->ConvertTo(InstructionOperand::DOUBLE_REGISTER, reg_index);
|
||||
allocated = AllocatedOperand(InstructionOperand::DOUBLE_REGISTER,
|
||||
operand->fixed_register_index());
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
InstructionOperand::ReplaceWith(operand, &allocated);
|
||||
if (is_tagged) {
|
||||
TRACE("Fixed reg is tagged at %d\n", pos);
|
||||
auto instr = InstructionAt(pos);
|
||||
@ -789,11 +789,12 @@ LiveRange* RegisterAllocator::LiveRangeFor(InstructionOperand* operand) {
|
||||
if (operand->IsUnallocated()) {
|
||||
return LiveRangeFor(UnallocatedOperand::cast(operand)->virtual_register());
|
||||
} else if (operand->IsConstant()) {
|
||||
return LiveRangeFor(ConstantOperand::cast(operand)->index());
|
||||
return LiveRangeFor(ConstantOperand::cast(operand)->virtual_register());
|
||||
} else if (operand->IsRegister()) {
|
||||
return FixedLiveRangeFor(operand->index());
|
||||
return FixedLiveRangeFor(RegisterOperand::cast(operand)->index());
|
||||
} else if (operand->IsDoubleRegister()) {
|
||||
return FixedDoubleLiveRangeFor(operand->index());
|
||||
return FixedDoubleLiveRangeFor(
|
||||
DoubleRegisterOperand::cast(operand)->index());
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
@ -922,7 +923,7 @@ bool SpillRange::TryMerge(SpillRange* other) {
|
||||
}
|
||||
|
||||
|
||||
void SpillRange::SetOperand(InstructionOperand* op) {
|
||||
void SpillRange::SetOperand(AllocatedOperand* op) {
|
||||
for (auto range : live_ranges()) {
|
||||
DCHECK(range->GetSpillRange() == this);
|
||||
range->CommitSpillOperand(op);
|
||||
@ -977,7 +978,7 @@ void RegisterAllocator::AssignSpillSlots() {
|
||||
auto op_kind = kind == DOUBLE_REGISTERS
|
||||
? InstructionOperand::DOUBLE_STACK_SLOT
|
||||
: InstructionOperand::STACK_SLOT;
|
||||
auto op = InstructionOperand::New(code_zone(), op_kind, index);
|
||||
auto op = AllocatedOperand::New(code_zone(), op_kind, index);
|
||||
range->SetOperand(op);
|
||||
}
|
||||
}
|
||||
@ -1117,8 +1118,9 @@ void RegisterAllocator::MeetRegisterConstraintsForLastInstructionInBlock(
|
||||
AllocateFixed(output, -1, false);
|
||||
// This value is produced on the stack, we never need to spill it.
|
||||
if (output->IsStackSlot()) {
|
||||
DCHECK(output->index() < frame_->GetSpillSlotCount());
|
||||
range->SetSpillOperand(output);
|
||||
DCHECK(StackSlotOperand::cast(output)->index() <
|
||||
frame_->GetSpillSlotCount());
|
||||
range->SetSpillOperand(StackSlotOperand::cast(output));
|
||||
range->SetSpillStartIndex(end);
|
||||
assigned = true;
|
||||
}
|
||||
@ -1160,7 +1162,7 @@ void RegisterAllocator::MeetConstraintsAfter(int instr_index) {
|
||||
for (size_t i = 0; i < first->OutputCount(); i++) {
|
||||
InstructionOperand* output = first->OutputAt(i);
|
||||
if (output->IsConstant()) {
|
||||
int output_vreg = output->index();
|
||||
int output_vreg = ConstantOperand::cast(output)->virtual_register();
|
||||
auto range = LiveRangeFor(output_vreg);
|
||||
range->SetSpillStartIndex(instr_index + 1);
|
||||
range->SetSpillOperand(output);
|
||||
@ -1176,8 +1178,9 @@ void RegisterAllocator::MeetConstraintsAfter(int instr_index) {
|
||||
|
||||
// This value is produced on the stack, we never need to spill it.
|
||||
if (first_output->IsStackSlot()) {
|
||||
DCHECK(first_output->index() < frame_->GetSpillSlotCount());
|
||||
range->SetSpillOperand(first_output);
|
||||
DCHECK(StackSlotOperand::cast(first_output)->index() <
|
||||
frame_->GetSpillSlotCount());
|
||||
range->SetSpillOperand(StackSlotOperand::cast(first_output));
|
||||
range->SetSpillStartIndex(instr_index + 1);
|
||||
assigned = true;
|
||||
}
|
||||
@ -1241,7 +1244,8 @@ void RegisterAllocator::MeetConstraintsBefore(int instr_index) {
|
||||
bool RegisterAllocator::IsOutputRegisterOf(Instruction* instr, int index) {
|
||||
for (size_t i = 0; i < instr->OutputCount(); i++) {
|
||||
auto output = instr->OutputAt(i);
|
||||
if (output->IsRegister() && output->index() == index) return true;
|
||||
if (output->IsRegister() && RegisterOperand::cast(output)->index() == index)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -1251,7 +1255,9 @@ bool RegisterAllocator::IsOutputDoubleRegisterOf(Instruction* instr,
|
||||
int index) {
|
||||
for (size_t i = 0; i < instr->OutputCount(); i++) {
|
||||
auto output = instr->OutputAt(i);
|
||||
if (output->IsDoubleRegister() && output->index() == index) return true;
|
||||
if (output->IsDoubleRegister() &&
|
||||
DoubleRegisterOperand::cast(output)->index() == index)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -1279,7 +1285,7 @@ void RegisterAllocator::ProcessInstructions(const InstructionBlock* block,
|
||||
int out_vreg = UnallocatedOperand::cast(output)->virtual_register();
|
||||
live->Remove(out_vreg);
|
||||
} else if (output->IsConstant()) {
|
||||
int out_vreg = output->index();
|
||||
int out_vreg = ConstantOperand::cast(output)->virtual_register();
|
||||
live->Remove(out_vreg);
|
||||
}
|
||||
Define(curr_position, output, nullptr);
|
||||
@ -1367,7 +1373,6 @@ void RegisterAllocator::ProcessInstructions(const InstructionBlock* block,
|
||||
int to_vreg = UnallocatedOperand::cast(to)->virtual_register();
|
||||
auto to_range = LiveRangeFor(to_vreg);
|
||||
if (to_range->is_phi()) {
|
||||
DCHECK(!FLAG_turbo_delay_ssa_decon);
|
||||
if (to_range->is_non_loop_phi()) {
|
||||
hint = to_range->current_hint_operand();
|
||||
}
|
||||
@ -1401,15 +1406,13 @@ void RegisterAllocator::ResolvePhis(const InstructionBlock* block) {
|
||||
DCHECK(res.second);
|
||||
USE(res);
|
||||
auto& output = phi->output();
|
||||
if (!FLAG_turbo_delay_ssa_decon) {
|
||||
for (size_t i = 0; i < phi->operands().size(); ++i) {
|
||||
InstructionBlock* cur_block =
|
||||
code()->InstructionBlockAt(block->predecessors()[i]);
|
||||
AddGapMove(cur_block->last_instruction_index(), Instruction::END,
|
||||
&phi->inputs()[i], &output);
|
||||
DCHECK(!InstructionAt(cur_block->last_instruction_index())
|
||||
->HasPointerMap());
|
||||
}
|
||||
for (size_t i = 0; i < phi->operands().size(); ++i) {
|
||||
InstructionBlock* cur_block =
|
||||
code()->InstructionBlockAt(block->predecessors()[i]);
|
||||
AddGapMove(cur_block->last_instruction_index(), Instruction::END,
|
||||
&phi->inputs()[i], &output);
|
||||
DCHECK(
|
||||
!InstructionAt(cur_block->last_instruction_index())->HasPointerMap());
|
||||
}
|
||||
auto live_range = LiveRangeFor(phi_vreg);
|
||||
int gap_index = block->first_instruction_index();
|
||||
@ -1664,27 +1667,6 @@ void RegisterAllocator::ResolveControlFlow() {
|
||||
LiveRangeFinder finder(*this);
|
||||
for (auto block : code()->instruction_blocks()) {
|
||||
if (CanEagerlyResolveControlFlow(block)) continue;
|
||||
if (FLAG_turbo_delay_ssa_decon) {
|
||||
// resolve phis
|
||||
for (auto phi : block->phis()) {
|
||||
auto* block_bound =
|
||||
finder.ArrayFor(phi->virtual_register())->FindSucc(block);
|
||||
auto phi_output =
|
||||
block_bound->range_->GetAssignedOperand(operand_cache());
|
||||
phi->output().ConvertTo(phi_output->kind(), phi_output->index());
|
||||
size_t pred_index = 0;
|
||||
for (auto pred : block->predecessors()) {
|
||||
const InstructionBlock* pred_block = code()->InstructionBlockAt(pred);
|
||||
auto* pred_bound = finder.ArrayFor(phi->operands()[pred_index])
|
||||
->FindPred(pred_block);
|
||||
auto pred_op =
|
||||
pred_bound->range_->GetAssignedOperand(operand_cache());
|
||||
phi->inputs()[pred_index] = *pred_op;
|
||||
ResolveControlFlow(block, phi_output, pred_block, pred_op);
|
||||
pred_index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto live = live_in_sets_[block->rpo_number().ToInt()];
|
||||
BitVector::Iterator iterator(live);
|
||||
while (!iterator.Done()) {
|
||||
@ -1745,26 +1727,24 @@ void RegisterAllocator::BuildLiveRanges() {
|
||||
// block.
|
||||
int phi_vreg = phi->virtual_register();
|
||||
live->Remove(phi_vreg);
|
||||
if (!FLAG_turbo_delay_ssa_decon) {
|
||||
InstructionOperand* hint = nullptr;
|
||||
InstructionOperand* phi_operand = nullptr;
|
||||
auto instr = GetLastInstruction(
|
||||
code()->InstructionBlockAt(block->predecessors()[0]));
|
||||
auto move = instr->GetParallelMove(Instruction::END);
|
||||
for (int j = 0; j < move->move_operands()->length(); ++j) {
|
||||
auto to = move->move_operands()->at(j).destination();
|
||||
if (to->IsUnallocated() &&
|
||||
UnallocatedOperand::cast(to)->virtual_register() == phi_vreg) {
|
||||
hint = move->move_operands()->at(j).source();
|
||||
phi_operand = to;
|
||||
break;
|
||||
}
|
||||
InstructionOperand* hint = nullptr;
|
||||
InstructionOperand* phi_operand = nullptr;
|
||||
auto instr = GetLastInstruction(
|
||||
code()->InstructionBlockAt(block->predecessors()[0]));
|
||||
auto move = instr->GetParallelMove(Instruction::END);
|
||||
for (int j = 0; j < move->move_operands()->length(); ++j) {
|
||||
auto to = move->move_operands()->at(j).destination();
|
||||
if (to->IsUnallocated() &&
|
||||
UnallocatedOperand::cast(to)->virtual_register() == phi_vreg) {
|
||||
hint = move->move_operands()->at(j).source();
|
||||
phi_operand = to;
|
||||
break;
|
||||
}
|
||||
DCHECK(hint != nullptr);
|
||||
auto block_start = LifetimePosition::GapFromInstructionIndex(
|
||||
block->first_instruction_index());
|
||||
Define(block_start, phi_operand, hint);
|
||||
}
|
||||
DCHECK(hint != nullptr);
|
||||
auto block_start = LifetimePosition::GapFromInstructionIndex(
|
||||
block->first_instruction_index());
|
||||
Define(block_start, phi_operand, hint);
|
||||
}
|
||||
|
||||
// Now live is live_in for this block except not including values live
|
||||
@ -2184,7 +2164,7 @@ bool RegisterAllocator::TryAllocateFreeReg(LiveRange* current) {
|
||||
|
||||
auto hint = current->FirstHint();
|
||||
if (hint != nullptr && (hint->IsRegister() || hint->IsDoubleRegister())) {
|
||||
int register_index = hint->index();
|
||||
int register_index = AllocatedOperand::cast(hint)->index();
|
||||
TRACE("Found reg hint %s (free until [%d) for live range %d (end %d[).\n",
|
||||
RegisterName(register_index), free_until_pos[register_index].Value(),
|
||||
current->id(), current->End().Value());
|
||||
|
@ -215,15 +215,15 @@ class InstructionOperandCache FINAL : public ZoneObject {
|
||||
public:
|
||||
InstructionOperandCache();
|
||||
|
||||
InstructionOperand* RegisterOperand(int index) {
|
||||
RegisterOperand* GetRegisterOperand(int index) {
|
||||
DCHECK(index >= 0 &&
|
||||
index < static_cast<int>(arraysize(general_register_operands_)));
|
||||
return &general_register_operands_[index];
|
||||
return RegisterOperand::cast(&general_register_operands_[index]);
|
||||
}
|
||||
InstructionOperand* DoubleRegisterOperand(int index) {
|
||||
DoubleRegisterOperand* GetDoubleRegisterOperand(int index) {
|
||||
DCHECK(index >= 0 &&
|
||||
index < static_cast<int>(arraysize(double_register_operands_)));
|
||||
return &double_register_operands_[index];
|
||||
return DoubleRegisterOperand::cast(&double_register_operands_[index]);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -345,7 +345,7 @@ class LiveRange FINAL : public ZoneObject {
|
||||
InstructionOperand* operand);
|
||||
void SetSpillOperand(InstructionOperand* operand);
|
||||
void SetSpillRange(SpillRange* spill_range);
|
||||
void CommitSpillOperand(InstructionOperand* operand);
|
||||
void CommitSpillOperand(AllocatedOperand* operand);
|
||||
void CommitSpillsAtDefinition(InstructionSequence* sequence,
|
||||
InstructionOperand* operand,
|
||||
bool might_be_duplicated);
|
||||
@ -423,7 +423,7 @@ class SpillRange FINAL : public ZoneObject {
|
||||
RegisterKind Kind() const { return live_ranges_[0]->Kind(); }
|
||||
bool IsEmpty() const { return live_ranges_.empty(); }
|
||||
bool TryMerge(SpillRange* other);
|
||||
void SetOperand(InstructionOperand* op);
|
||||
void SetOperand(AllocatedOperand* op);
|
||||
|
||||
private:
|
||||
LifetimePosition End() const { return end_position_; }
|
||||
|
@ -44,7 +44,8 @@ class X64OperandConverter : public InstructionOperandConverter {
|
||||
Operand ToOperand(InstructionOperand* op, int extra = 0) {
|
||||
DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
|
||||
// The linkage computes where all spill slots are located.
|
||||
FrameOffset offset = linkage()->GetFrameOffset(op->index(), frame(), extra);
|
||||
FrameOffset offset = linkage()->GetFrameOffset(
|
||||
AllocatedOperand::cast(op)->index(), frame(), extra);
|
||||
return Operand(offset.from_stack_pointer() ? rsp : rbp, offset.offset());
|
||||
}
|
||||
|
||||
|
@ -409,9 +409,6 @@ DEFINE_BOOL(turbo_builtin_inlining, true, "enable builtin inlining in TurboFan")
|
||||
DEFINE_BOOL(trace_turbo_inlining, false, "trace TurboFan inlining")
|
||||
DEFINE_BOOL(loop_assignment_analysis, true, "perform loop assignment analysis")
|
||||
DEFINE_BOOL(turbo_profiling, false, "enable profiling in TurboFan")
|
||||
// TODO(dcarney): this is just for experimentation, remove when default.
|
||||
DEFINE_BOOL(turbo_delay_ssa_decon, false,
|
||||
"delay ssa deconstruction in TurboFan register allocator")
|
||||
DEFINE_BOOL(turbo_verify_allocation, DEBUG_BOOL,
|
||||
"verify register allocation in TurboFan")
|
||||
DEFINE_BOOL(turbo_move_optimization, true, "optimize gap moves in TurboFan")
|
||||
|
@ -51,11 +51,22 @@ class InterpreterState {
|
||||
}
|
||||
|
||||
static Key KeyFor(const InstructionOperand* op) {
|
||||
return Key(op->kind(), op->index());
|
||||
int v = op->IsConstant() ? ConstantOperand::cast(op)->virtual_register()
|
||||
: AllocatedOperand::cast(op)->index();
|
||||
return Key(op->kind(), v);
|
||||
}
|
||||
|
||||
static Value ValueFor(const InstructionOperand* op) {
|
||||
return Value(op->kind(), op->index());
|
||||
int v = op->IsConstant() ? ConstantOperand::cast(op)->virtual_register()
|
||||
: AllocatedOperand::cast(op)->index();
|
||||
return Value(op->kind(), v);
|
||||
}
|
||||
|
||||
static InstructionOperand FromKey(Key key) {
|
||||
if (key.first == InstructionOperand::CONSTANT) {
|
||||
return ConstantOperand(key.second);
|
||||
}
|
||||
return AllocatedOperand(key.first, key.second);
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os,
|
||||
@ -63,8 +74,8 @@ class InterpreterState {
|
||||
for (OperandMap::const_iterator it = is.values_.begin();
|
||||
it != is.values_.end(); ++it) {
|
||||
if (it != is.values_.begin()) os << " ";
|
||||
InstructionOperand source(it->first.first, it->first.second);
|
||||
InstructionOperand destination(it->second.first, it->second.second);
|
||||
InstructionOperand source = FromKey(it->first);
|
||||
InstructionOperand destination = FromKey(it->second);
|
||||
MoveOperands mo(&source, &destination);
|
||||
PrintableMoveOperands pmo = {RegisterConfiguration::ArchDefault(), &mo};
|
||||
os << pmo;
|
||||
@ -115,7 +126,7 @@ class ParallelMoveCreator : public HandleAndZoneScope {
|
||||
ParallelMove* parallel_move = new (main_zone()) ParallelMove(main_zone());
|
||||
std::set<InstructionOperand*, InstructionOperandComparator> seen;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
MoveOperands mo(CreateRandomOperand(), CreateRandomOperand());
|
||||
MoveOperands mo(CreateRandomOperand(true), CreateRandomOperand(false));
|
||||
if (!mo.IsRedundant() && seen.find(mo.destination()) == seen.end()) {
|
||||
parallel_move->AddMove(mo.source(), mo.destination(), main_zone());
|
||||
seen.insert(mo.destination());
|
||||
@ -128,24 +139,24 @@ class ParallelMoveCreator : public HandleAndZoneScope {
|
||||
struct InstructionOperandComparator {
|
||||
bool operator()(const InstructionOperand* x,
|
||||
const InstructionOperand* y) const {
|
||||
return (x->kind() < y->kind()) ||
|
||||
(x->kind() == y->kind() && x->index() < y->index());
|
||||
return *x < *y;
|
||||
}
|
||||
};
|
||||
|
||||
InstructionOperand* CreateRandomOperand() {
|
||||
InstructionOperand* CreateRandomOperand(bool is_source) {
|
||||
int index = rng_->NextInt(6);
|
||||
switch (rng_->NextInt(5)) {
|
||||
// destination can't be Constant.
|
||||
switch (rng_->NextInt(is_source ? 5 : 4)) {
|
||||
case 0:
|
||||
return ConstantOperand::New(index, main_zone());
|
||||
return StackSlotOperand::New(main_zone(), index);
|
||||
case 1:
|
||||
return StackSlotOperand::New(index, main_zone());
|
||||
return DoubleStackSlotOperand::New(main_zone(), index);
|
||||
case 2:
|
||||
return DoubleStackSlotOperand::New(index, main_zone());
|
||||
return RegisterOperand::New(main_zone(), index);
|
||||
case 3:
|
||||
return RegisterOperand::New(index, main_zone());
|
||||
return DoubleRegisterOperand::New(main_zone(), index);
|
||||
case 4:
|
||||
return DoubleRegisterOperand::New(index, main_zone());
|
||||
return ConstantOperand::New(main_zone(), index);
|
||||
}
|
||||
UNREACHABLE();
|
||||
return NULL;
|
||||
|
@ -59,15 +59,15 @@ class TestCode : public HandleAndZoneScope {
|
||||
Start();
|
||||
sequence_.AddInstruction(Instruction::New(main_zone(), kArchNop));
|
||||
int index = static_cast<int>(sequence_.instructions().size()) - 1;
|
||||
AddGapMove(index, RegisterOperand::New(13, main_zone()),
|
||||
RegisterOperand::New(13, main_zone()));
|
||||
AddGapMove(index, RegisterOperand::New(main_zone(), 13),
|
||||
RegisterOperand::New(main_zone(), 13));
|
||||
}
|
||||
void NonRedundantMoves() {
|
||||
Start();
|
||||
sequence_.AddInstruction(Instruction::New(main_zone(), kArchNop));
|
||||
int index = static_cast<int>(sequence_.instructions().size()) - 1;
|
||||
AddGapMove(index, ImmediateOperand::New(11, main_zone()),
|
||||
RegisterOperand::New(11, main_zone()));
|
||||
AddGapMove(index, ImmediateOperand::New(main_zone(), 11),
|
||||
RegisterOperand::New(main_zone(), 11));
|
||||
}
|
||||
void Other() {
|
||||
Start();
|
||||
|
@ -76,16 +76,17 @@ InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build(
|
||||
InstructionOperand* output = instr->OutputAt(i);
|
||||
EXPECT_NE(InstructionOperand::IMMEDIATE, output->kind());
|
||||
if (output->IsConstant()) {
|
||||
s.constants_.insert(std::make_pair(
|
||||
output->index(), sequence.GetConstant(output->index())));
|
||||
int vreg = ConstantOperand::cast(output)->virtual_register();
|
||||
s.constants_.insert(std::make_pair(vreg, sequence.GetConstant(vreg)));
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < instr->InputCount(); ++i) {
|
||||
InstructionOperand* input = instr->InputAt(i);
|
||||
EXPECT_NE(InstructionOperand::CONSTANT, input->kind());
|
||||
if (input->IsImmediate()) {
|
||||
s.immediates_.insert(std::make_pair(
|
||||
input->index(), sequence.GetImmediate(input->index())));
|
||||
int index = ImmediateOperand::cast(input)->index();
|
||||
s.immediates_.insert(
|
||||
std::make_pair(index, sequence.GetImmediate(index)));
|
||||
}
|
||||
}
|
||||
s.instructions_.push_back(instr);
|
||||
|
@ -166,7 +166,9 @@ class InstructionSelectorTest : public TestWithContext,
|
||||
}
|
||||
|
||||
int ToVreg(const InstructionOperand* operand) const {
|
||||
if (operand->IsConstant()) return operand->index();
|
||||
if (operand->IsConstant()) {
|
||||
return ConstantOperand::cast(operand)->virtual_register();
|
||||
}
|
||||
EXPECT_EQ(InstructionOperand::UNALLOCATED, operand->kind());
|
||||
return UnallocatedOperand::cast(operand)->virtual_register();
|
||||
}
|
||||
@ -202,14 +204,15 @@ class InstructionSelectorTest : public TestWithContext,
|
||||
Constant ToConstant(const InstructionOperand* operand) const {
|
||||
ConstantMap::const_iterator i;
|
||||
if (operand->IsConstant()) {
|
||||
i = constants_.find(operand->index());
|
||||
i = constants_.find(ConstantOperand::cast(operand)->virtual_register());
|
||||
EXPECT_EQ(ConstantOperand::cast(operand)->virtual_register(), i->first);
|
||||
EXPECT_FALSE(constants_.end() == i);
|
||||
} else {
|
||||
EXPECT_EQ(InstructionOperand::IMMEDIATE, operand->kind());
|
||||
i = immediates_.find(operand->index());
|
||||
i = immediates_.find(ImmediateOperand::cast(operand)->index());
|
||||
EXPECT_EQ(ImmediateOperand::cast(operand)->index(), i->first);
|
||||
EXPECT_FALSE(immediates_.end() == i);
|
||||
}
|
||||
EXPECT_EQ(operand->index(), i->first);
|
||||
return i->second;
|
||||
}
|
||||
|
||||
|
@ -67,12 +67,12 @@ class MoveOptimizerTest : public InstructionSequenceTest {
|
||||
CHECK_NE(kNoValue, op.value_);
|
||||
switch (op.type_) {
|
||||
case kConstant:
|
||||
return ConstantOperand::New(op.value_, zone());
|
||||
return ConstantOperand::New(zone(), op.value_);
|
||||
case kFixedSlot:
|
||||
return StackSlotOperand::New(op.value_, zone());
|
||||
return StackSlotOperand::New(zone(), op.value_);
|
||||
case kFixedRegister:
|
||||
CHECK(0 <= op.value_ && op.value_ < num_general_registers());
|
||||
return RegisterOperand::New(op.value_, zone());
|
||||
return RegisterOperand::New(zone(), op.value_);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user