Commit 959288e5 authored by Ross McIlroy's avatar Ross McIlroy Committed by Commit Bot

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

This is a reland of ab7e89f1

Original change's description:
> [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: Tobias Tebbi <tebbi@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#69019}

Bug: v8:9684
Change-Id: I60b902be82b766d98c0f08c9394fcac72d3b914a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2315994Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Auto-Submit: Ross McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69042}
parent 6880a8dd
...@@ -105,4 +105,31 @@ ...@@ -105,4 +105,31 @@
#define V8_NOEXCEPT #define V8_NOEXCEPT
#endif #endif
// Specify memory alignment for structs, classes, etc.
// Use like:
// class ALIGNAS(16) MyClass { ... }
// ALIGNAS(16) int array[4];
//
// In most places you can use the C++11 keyword "alignas", which is preferred.
//
// But compilers have trouble mixing __attribute__((...)) syntax with
// alignas(...) syntax.
//
// Doesn't work in clang or gcc:
// struct alignas(16) __attribute__((packed)) S { char c; };
// Works in clang but not gcc:
// struct __attribute__((packed)) alignas(16) S2 { char c; };
// Works in clang and gcc:
// struct alignas(16) S3 { char c; } __attribute__((packed));
//
// There are also some attributes that must be specified *before* a class
// definition: visibility (used for exporting functions/classes) is one of
// these attributes. This means that it is not possible to use alignas() with a
// class that is marked as exported.
#if defined(V8_CC_MSVC)
#define ALIGNAS(byte_alignment) __declspec(align(byte_alignment))
#else
#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
#endif
#endif // V8_BASE_COMPILER_SPECIFIC_H_ #endif // V8_BASE_COMPILER_SPECIFIC_H_
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "src/compiler/backend/instruction.h" #include "src/compiler/backend/instruction.h"
#include <cstddef>
#include <iomanip> #include <iomanip>
#include "src/codegen/interface-descriptors.h" #include "src/codegen/interface-descriptors.h"
...@@ -169,6 +170,8 @@ std::ostream& operator<<(std::ostream& os, const InstructionOperand& op) { ...@@ -169,6 +170,8 @@ std::ostream& operator<<(std::ostream& os, const InstructionOperand& op) {
return os << "[immediate:" << imm.indexed_value() << "]"; return os << "[immediate:" << imm.indexed_value() << "]";
} }
} }
case InstructionOperand::PENDING:
return os << "[pending: " << PendingOperand::cast(op).next() << "]";
case InstructionOperand::ALLOCATED: { case InstructionOperand::ALLOCATED: {
LocationOperand allocated = LocationOperand::cast(op); LocationOperand allocated = LocationOperand::cast(op);
if (op.IsStackSlot()) { if (op.IsStackSlot()) {
...@@ -296,6 +299,9 @@ Instruction::Instruction(InstructionCode opcode) ...@@ -296,6 +299,9 @@ Instruction::Instruction(InstructionCode opcode)
block_(nullptr) { block_(nullptr) {
parallel_moves_[0] = nullptr; parallel_moves_[0] = nullptr;
parallel_moves_[1] = 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, Instruction::Instruction(InstructionCode opcode, size_t output_count,
......
...@@ -33,7 +33,7 @@ namespace compiler { ...@@ -33,7 +33,7 @@ namespace compiler {
class Schedule; class Schedule;
class SourcePositionTable; class SourcePositionTable;
class V8_EXPORT_PRIVATE InstructionOperand { class V8_EXPORT_PRIVATE ALIGNAS(8) InstructionOperand {
public: public:
static const int kInvalidVirtualRegister = -1; static const int kInvalidVirtualRegister = -1;
...@@ -42,6 +42,7 @@ class V8_EXPORT_PRIVATE InstructionOperand { ...@@ -42,6 +42,7 @@ class V8_EXPORT_PRIVATE InstructionOperand {
UNALLOCATED, UNALLOCATED,
CONSTANT, CONSTANT,
IMMEDIATE, IMMEDIATE,
PENDING,
// Location operand kinds. // Location operand kinds.
ALLOCATED, ALLOCATED,
FIRST_LOCATION_OPERAND_KIND = ALLOCATED FIRST_LOCATION_OPERAND_KIND = ALLOCATED
...@@ -67,6 +68,10 @@ class V8_EXPORT_PRIVATE InstructionOperand { ...@@ -67,6 +68,10 @@ class V8_EXPORT_PRIVATE InstructionOperand {
// embedded directly in instructions, e.g. small integers and on some // embedded directly in instructions, e.g. small integers and on some
// platforms Objects. // platforms Objects.
INSTRUCTION_OPERAND_PREDICATE(Immediate, IMMEDIATE) 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 // AllocatedOperands are registers or stack slots that are assigned by the
// register allocator and are always associated with a virtual register. // register allocator and are always associated with a virtual register.
INSTRUCTION_OPERAND_PREDICATE(Allocated, ALLOCATED) INSTRUCTION_OPERAND_PREDICATE(Allocated, ALLOCATED)
...@@ -99,6 +104,10 @@ class V8_EXPORT_PRIVATE InstructionOperand { ...@@ -99,6 +104,10 @@ class V8_EXPORT_PRIVATE InstructionOperand {
} }
bool Equals(const InstructionOperand& that) const { 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_; return this->value_ == that.value_;
} }
...@@ -107,10 +116,15 @@ class V8_EXPORT_PRIVATE InstructionOperand { ...@@ -107,10 +116,15 @@ class V8_EXPORT_PRIVATE InstructionOperand {
} }
bool EqualsCanonicalized(const InstructionOperand& that) const { 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(); return this->GetCanonicalizedValue() == that.GetCanonicalizedValue();
} }
bool CompareCanonicalized(const InstructionOperand& that) const { bool CompareCanonicalized(const InstructionOperand& that) const {
DCHECK(!IsPending());
return this->GetCanonicalizedValue() < that.GetCanonicalizedValue(); return this->GetCanonicalizedValue() < that.GetCanonicalizedValue();
} }
...@@ -404,6 +418,44 @@ class ImmediateOperand : public InstructionOperand { ...@@ -404,6 +418,44 @@ class ImmediateOperand : public InstructionOperand {
using ValueField = base::BitField64<int32_t, 32, 32>; 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 { class LocationOperand : public InstructionOperand {
public: public:
enum LocationKind { REGISTER, STACK_SLOT }; enum LocationKind { REGISTER, STACK_SLOT };
......
...@@ -284,6 +284,7 @@ UsePositionHintType UsePosition::HintTypeForOperand( ...@@ -284,6 +284,7 @@ UsePositionHintType UsePosition::HintTypeForOperand(
DCHECK(op.IsStackSlot() || op.IsFPStackSlot()); DCHECK(op.IsStackSlot() || op.IsFPStackSlot());
return UsePositionHintType::kNone; return UsePositionHintType::kNone;
} }
case InstructionOperand::PENDING:
case InstructionOperand::INVALID: case InstructionOperand::INVALID:
break; break;
} }
......
...@@ -1211,6 +1211,7 @@ std::ostream& operator<<(std::ostream& os, const InstructionOperandAsJSON& o) { ...@@ -1211,6 +1211,7 @@ std::ostream& operator<<(std::ostream& os, const InstructionOperandAsJSON& o) {
<< MachineReprToString(allocated->representation()) << "\""; << MachineReprToString(allocated->representation()) << "\"";
break; break;
} }
case InstructionOperand::PENDING:
case InstructionOperand::INVALID: case InstructionOperand::INVALID:
UNREACHABLE(); 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