Commit ab7e89f1 authored by Ross McIlroy's avatar Ross McIlroy Committed by Commit Bot

[TurboProp] Add PendingOperand for use by fast register allocator.

Adds a pending operand type for use with the fast register allocator.
These operands chain together multiple operands together, enabling
the allocator to keep track of multiple pending operands, then
replace them all with the allocated operand in one go.

BUG=v8:9684

Change-Id: I5d8150f3f26549a747a2e89e32e31135e89dff9c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2292302
Commit-Queue: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69019}
parent 9414d539
......@@ -4,6 +4,7 @@
#include "src/compiler/backend/instruction.h"
#include <cstddef>
#include <iomanip>
#include "src/codegen/interface-descriptors.h"
......@@ -169,6 +170,8 @@ std::ostream& operator<<(std::ostream& os, const InstructionOperand& op) {
return os << "[immediate:" << imm.indexed_value() << "]";
}
}
case InstructionOperand::PENDING:
return os << "[pending: " << PendingOperand::cast(op).next() << "]";
case InstructionOperand::ALLOCATED: {
LocationOperand allocated = LocationOperand::cast(op);
if (op.IsStackSlot()) {
......@@ -296,6 +299,9 @@ Instruction::Instruction(InstructionCode opcode)
block_(nullptr) {
parallel_moves_[0] = nullptr;
parallel_moves_[1] = nullptr;
// PendingOperands are required to be 8 byte aligned.
STATIC_ASSERT(offsetof(Instruction, operands_) % 8 == 0);
}
Instruction::Instruction(InstructionCode opcode, size_t output_count,
......
......@@ -33,7 +33,7 @@ namespace compiler {
class Schedule;
class SourcePositionTable;
class V8_EXPORT_PRIVATE InstructionOperand {
class V8_EXPORT_PRIVATE alignas(8) InstructionOperand {
public:
static const int kInvalidVirtualRegister = -1;
......@@ -42,6 +42,7 @@ class V8_EXPORT_PRIVATE InstructionOperand {
UNALLOCATED,
CONSTANT,
IMMEDIATE,
PENDING,
// Location operand kinds.
ALLOCATED,
FIRST_LOCATION_OPERAND_KIND = ALLOCATED
......@@ -67,6 +68,10 @@ class V8_EXPORT_PRIVATE InstructionOperand {
// embedded directly in instructions, e.g. small integers and on some
// platforms Objects.
INSTRUCTION_OPERAND_PREDICATE(Immediate, IMMEDIATE)
// PendingOperands are pending allocation during register allocation and
// shouldn't be seen elsewhere. They chain together multiple operators that
// will be replaced together with the same value when finalized.
INSTRUCTION_OPERAND_PREDICATE(Pending, PENDING)
// AllocatedOperands are registers or stack slots that are assigned by the
// register allocator and are always associated with a virtual register.
INSTRUCTION_OPERAND_PREDICATE(Allocated, ALLOCATED)
......@@ -99,6 +104,10 @@ class V8_EXPORT_PRIVATE InstructionOperand {
}
bool Equals(const InstructionOperand& that) const {
if (IsPending()) {
// Pending operands are only equal if they are the same operand.
return this == &that;
}
return this->value_ == that.value_;
}
......@@ -107,10 +116,15 @@ class V8_EXPORT_PRIVATE InstructionOperand {
}
bool EqualsCanonicalized(const InstructionOperand& that) const {
if (IsPending()) {
// Pending operands can't be canonicalized, so just compare for equality.
return Equals(that);
}
return this->GetCanonicalizedValue() == that.GetCanonicalizedValue();
}
bool CompareCanonicalized(const InstructionOperand& that) const {
DCHECK(!IsPending());
return this->GetCanonicalizedValue() < that.GetCanonicalizedValue();
}
......@@ -404,6 +418,44 @@ class ImmediateOperand : public InstructionOperand {
using ValueField = base::BitField64<int32_t, 32, 32>;
};
class PendingOperand : public InstructionOperand {
public:
PendingOperand() : InstructionOperand(PENDING) {}
explicit PendingOperand(PendingOperand* next_operand) : PendingOperand() {
set_next(next_operand);
}
void set_next(PendingOperand* next) {
DCHECK_NULL(this->next());
uintptr_t shifted_value =
reinterpret_cast<uintptr_t>(next) >> kPointerShift;
DCHECK_EQ(reinterpret_cast<uintptr_t>(next),
shifted_value << kPointerShift);
value_ |= NextOperandField::encode(static_cast<uint64_t>(shifted_value));
}
PendingOperand* next() const {
uintptr_t shifted_value =
static_cast<uint64_t>(NextOperandField::decode(value_));
return reinterpret_cast<PendingOperand*>(shifted_value << kPointerShift);
}
static PendingOperand* New(Zone* zone, PendingOperand* previous_operand) {
return InstructionOperand::New(zone, PendingOperand(previous_operand));
}
INSTRUCTION_OPERAND_CASTS(PendingOperand, PENDING)
private:
// Operands are uint64_t values and so are aligned to 8 byte boundaries,
// therefore we can shift off the bottom three zeros without losing data.
static const uint64_t kPointerShift = 3;
STATIC_ASSERT(alignof(InstructionOperand) >= (1 << kPointerShift));
STATIC_ASSERT(KindField::kSize == 3);
using NextOperandField = base::BitField64<uint64_t, 3, 61>;
};
class LocationOperand : public InstructionOperand {
public:
enum LocationKind { REGISTER, STACK_SLOT };
......
......@@ -284,6 +284,7 @@ UsePositionHintType UsePosition::HintTypeForOperand(
DCHECK(op.IsStackSlot() || op.IsFPStackSlot());
return UsePositionHintType::kNone;
}
case InstructionOperand::PENDING:
case InstructionOperand::INVALID:
break;
}
......
......@@ -1211,6 +1211,7 @@ std::ostream& operator<<(std::ostream& os, const InstructionOperandAsJSON& o) {
<< MachineReprToString(allocated->representation()) << "\"";
break;
}
case InstructionOperand::PENDING:
case InstructionOperand::INVALID:
UNREACHABLE();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment