Commit fdab306a authored by dcarney@chromium.org's avatar dcarney@chromium.org

[turbofan] add gap move verifier

R=jarin@chromium.org

BUG=

Review URL: https://codereview.chromium.org/704193007

Cr-Commit-Position: refs/heads/master@{#25300}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@25300 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 063eb948
......@@ -435,8 +435,8 @@ InstructionSequence::InstructionSequence(Zone* instruction_zone,
BlockStartInstruction* InstructionSequence::GetBlockStart(
BasicBlock::RpoNumber rpo) {
InstructionBlock* block = InstructionBlockAt(rpo);
BasicBlock::RpoNumber rpo) const {
const InstructionBlock* block = InstructionBlockAt(rpo);
return BlockStartInstruction::cast(InstructionAt(block->code_start()));
}
......
......@@ -60,7 +60,7 @@ class InstructionOperand : public ZoneObject {
INSTRUCTION_OPERAND_PREDICATE(Unallocated, UNALLOCATED, 0)
INSTRUCTION_OPERAND_PREDICATE(Ignored, INVALID, 0)
#undef INSTRUCTION_OPERAND_PREDICATE
bool Equals(InstructionOperand* other) const {
bool Equals(const InstructionOperand* other) const {
return value_ == other->value_;
}
......@@ -120,6 +120,7 @@ class UnallocatedOperand : public InstructionOperand {
explicit UnallocatedOperand(ExtendedPolicy policy)
: InstructionOperand(UNALLOCATED, 0) {
value_ |= VirtualRegisterField::encode(kInvalidVirtualRegister);
value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
value_ |= ExtendedPolicyField::encode(policy);
value_ |= LifetimeField::encode(USED_AT_END);
......@@ -128,6 +129,7 @@ class UnallocatedOperand : public InstructionOperand {
UnallocatedOperand(BasicPolicy policy, int index)
: InstructionOperand(UNALLOCATED, 0) {
DCHECK(policy == FIXED_SLOT);
value_ |= VirtualRegisterField::encode(kInvalidVirtualRegister);
value_ |= BasicPolicyField::encode(policy);
value_ |= index << FixedSlotIndexField::kShift;
DCHECK(this->fixed_slot_index() == index);
......@@ -136,6 +138,7 @@ class UnallocatedOperand : public InstructionOperand {
UnallocatedOperand(ExtendedPolicy policy, int index)
: InstructionOperand(UNALLOCATED, 0) {
DCHECK(policy == FIXED_REGISTER || policy == FIXED_DOUBLE_REGISTER);
value_ |= VirtualRegisterField::encode(kInvalidVirtualRegister);
value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
value_ |= ExtendedPolicyField::encode(policy);
value_ |= LifetimeField::encode(USED_AT_END);
......@@ -144,6 +147,7 @@ class UnallocatedOperand : public InstructionOperand {
UnallocatedOperand(ExtendedPolicy policy, Lifetime lifetime)
: InstructionOperand(UNALLOCATED, 0) {
value_ |= VirtualRegisterField::encode(kInvalidVirtualRegister);
value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
value_ |= ExtendedPolicyField::encode(policy);
value_ |= LifetimeField::encode(lifetime);
......@@ -198,7 +202,8 @@ class UnallocatedOperand : public InstructionOperand {
class LifetimeField : public BitField<Lifetime, 25, 1> {};
class FixedRegisterField : public BitField<int, 26, 6> {};
static const int kMaxVirtualRegisters = VirtualRegisterField::kMax + 1;
static const int kInvalidVirtualRegister = VirtualRegisterField::kMax;
static const int kMaxVirtualRegisters = VirtualRegisterField::kMax;
static const int kFixedSlotIndexWidth = FixedSlotIndexField::kSize;
static const int kMaxFixedSlotIndex = (1 << (kFixedSlotIndexWidth - 1)) - 1;
static const int kMinFixedSlotIndex = -(1 << (kFixedSlotIndexWidth - 1));
......@@ -586,7 +591,11 @@ class GapInstruction : public Instruction {
return parallel_moves_[pos];
}
ParallelMove* GetParallelMove(InnerPosition pos) const {
ParallelMove* GetParallelMove(InnerPosition pos) {
return parallel_moves_[pos];
}
const ParallelMove* GetParallelMove(InnerPosition pos) const {
return parallel_moves_[pos];
}
......@@ -634,6 +643,11 @@ class BlockStartInstruction FINAL : public GapInstruction {
return static_cast<BlockStartInstruction*>(instr);
}
static const BlockStartInstruction* cast(const Instruction* instr) {
DCHECK(instr->IsBlockStart());
return static_cast<const BlockStartInstruction*>(instr);
}
private:
BlockStartInstruction() : GapInstruction(kBlockStartInstruction) {}
};
......@@ -917,7 +931,7 @@ class InstructionSequence FINAL {
void AddGapMove(int index, InstructionOperand* from, InstructionOperand* to);
BlockStartInstruction* GetBlockStart(BasicBlock::RpoNumber rpo);
BlockStartInstruction* GetBlockStart(BasicBlock::RpoNumber rpo) const;
typedef InstructionDeque::const_iterator const_iterator;
const_iterator begin() const { return instructions_.begin(); }
......
......@@ -24,6 +24,7 @@
#include "src/compiler/machine-operator-reducer.h"
#include "src/compiler/pipeline-statistics.h"
#include "src/compiler/register-allocator.h"
#include "src/compiler/register-allocator-verifier.h"
#include "src/compiler/schedule.h"
#include "src/compiler/scheduler.h"
#include "src/compiler/select-lowering.h"
......@@ -575,6 +576,13 @@ Handle<Code> Pipeline::GenerateCode(Linkage* linkage, PipelineData* data) {
data->pipeline_statistics()->BeginPhaseKind("register allocation");
}
#ifdef DEBUG
// Don't track usage for this zone in compiler stats.
Zone verifier_zone(info()->isolate());
RegisterAllocatorVerifier verifier(
&verifier_zone, RegisterConfiguration::ArchDefault(), &sequence);
#endif
// Allocate registers.
Frame frame;
{
......@@ -586,17 +594,14 @@ Handle<Code> Pipeline::GenerateCode(Linkage* linkage, PipelineData* data) {
ZonePool::Scope zone_scope(data->zone_pool());
SmartArrayPointer<char> debug_name;
RegisterAllocator::VerificationType verification_type =
RegisterAllocator::kNoVerify;
#ifdef DEBUG
debug_name = GetDebugName(info());
verification_type = RegisterAllocator::kVerifyAssignment;
#endif
RegisterAllocator allocator(RegisterConfiguration::ArchDefault(),
zone_scope.zone(), &frame, &sequence,
debug_name.get());
if (!allocator.Allocate(data->pipeline_statistics(), verification_type)) {
if (!allocator.Allocate(data->pipeline_statistics())) {
info()->AbortOptimization(kNotEnoughVirtualRegistersRegalloc);
return Handle<Code>::null();
}
......@@ -614,6 +619,11 @@ Handle<Code> Pipeline::GenerateCode(Linkage* linkage, PipelineData* data) {
<< printable;
}
#ifdef DEBUG
verifier.VerifyAssignment();
verifier.VerifyGapMoves();
#endif
if (data->pipeline_statistics() != NULL) {
data->pipeline_statistics()->BeginPhaseKind("code generation");
}
......
This diff is collapsed.
......@@ -17,9 +17,11 @@ class InstructionSequence;
class RegisterAllocatorVerifier FINAL : public ZoneObject {
public:
RegisterAllocatorVerifier(Zone* zone, const InstructionSequence* sequence);
RegisterAllocatorVerifier(Zone* zone, const RegisterConfiguration* config,
const InstructionSequence* sequence);
void VerifyAssignment();
void VerifyGapMoves();
private:
enum ConstraintType {
......@@ -38,6 +40,7 @@ class RegisterAllocatorVerifier FINAL : public ZoneObject {
struct OperandConstraint {
ConstraintType type_;
int value_; // subkind index when relevant
int virtual_register_;
};
struct InstructionConstraint {
......@@ -46,15 +49,30 @@ class RegisterAllocatorVerifier FINAL : public ZoneObject {
OperandConstraint* operand_constraints_;
};
class OutgoingMapping;
typedef ZoneVector<InstructionConstraint> Constraints;
typedef ZoneVector<OutgoingMapping*> OutgoingMappings;
Zone* zone() const { return zone_; }
const RegisterConfiguration* config() { return config_; }
const InstructionSequence* sequence() const { return sequence_; }
Constraints* constraints() { return &constraints_; }
static void VerifyInput(const OperandConstraint& constraint);
static void VerifyTemp(const OperandConstraint& constraint);
static void VerifyOutput(const OperandConstraint& constraint);
void BuildConstraint(const InstructionOperand* op,
OperandConstraint* constraint);
void CheckConstraint(const InstructionOperand* op,
const OperandConstraint* constraint);
void ConstructOutgoingMappings(OutgoingMappings* outgoing_mappings,
bool initial_pass);
Zone* const zone_;
const RegisterConfiguration* config_;
const InstructionSequence* const sequence_;
Constraints constraints_;
......
......@@ -5,7 +5,6 @@
#include "src/compiler/linkage.h"
#include "src/compiler/pipeline-statistics.h"
#include "src/compiler/register-allocator.h"
#include "src/compiler/register-allocator-verifier.h"
#include "src/string-stream.h"
namespace v8 {
......@@ -1117,16 +1116,7 @@ void RegisterAllocator::ResolvePhis(const InstructionBlock* block) {
}
bool RegisterAllocator::Allocate(PipelineStatistics* stats,
VerificationType verification_type) {
SmartPointer<Zone> verifier_zone;
RegisterAllocatorVerifier* verifier = NULL;
if (verification_type == kVerifyAssignment) {
// Don't track usage for this zone in compiler stats.
verifier_zone.Reset(new Zone(local_zone()->isolate()));
verifier = new (verifier_zone.get())
RegisterAllocatorVerifier(verifier_zone.get(), code());
}
bool RegisterAllocator::Allocate(PipelineStatistics* stats) {
assigned_registers_ = new (code_zone())
BitVector(config()->num_general_registers(), code_zone());
assigned_double_registers_ = new (code_zone())
......@@ -1168,9 +1158,6 @@ bool RegisterAllocator::Allocate(PipelineStatistics* stats,
}
frame()->SetAllocatedRegisters(assigned_registers_);
frame()->SetAllocatedDoubleRegisters(assigned_double_registers_);
if (verifier != NULL) {
verifier->VerifyAssignment();
}
return true;
}
......
......@@ -322,15 +322,12 @@ class LiveRange FINAL : public ZoneObject {
class RegisterAllocator FINAL {
public:
enum VerificationType { kNoVerify, kVerifyAssignment };
explicit RegisterAllocator(const RegisterConfiguration* config,
Zone* local_zone, Frame* frame,
InstructionSequence* code,
const char* debug_name = nullptr);
bool Allocate(PipelineStatistics* stats = NULL,
VerificationType verification_type = kNoVerify);
bool Allocate(PipelineStatistics* stats = NULL);
bool AllocationOk() { return allocation_ok_; }
BitVector* assigned_registers() { return assigned_registers_; }
BitVector* assigned_double_registers() { return assigned_double_registers_; }
......
......@@ -129,36 +129,6 @@ TEST(RunBranch) {
}
TEST(RunRedundantBranch1) {
RawMachineAssemblerTester<int32_t> m;
int constant = 944777;
MLabel blocka;
m.Branch(m.Int32Constant(0), &blocka, &blocka);
m.Bind(&blocka);
m.Return(m.Int32Constant(constant));
CHECK_EQ(constant, m.Call());
}
TEST(RunRedundantBranch2) {
RawMachineAssemblerTester<int32_t> m;
int constant = 966777;
MLabel blocka, blockb, blockc;
m.Branch(m.Int32Constant(0), &blocka, &blockc);
m.Bind(&blocka);
m.Branch(m.Int32Constant(0), &blockb, &blockb);
m.Bind(&blockc);
m.Goto(&blockb);
m.Bind(&blockb);
m.Return(m.Int32Constant(constant));
CHECK_EQ(constant, m.Call());
}
TEST(RunDiamond2) {
RawMachineAssemblerTester<int32_t> m;
......
......@@ -4,6 +4,7 @@
#include "src/base/utils/random-number-generator.h"
#include "src/compiler/register-allocator.h"
#include "src/compiler/register-allocator-verifier.h"
#include "test/unittests/test-utils.h"
#include "testing/gmock/include/gmock/gmock.h"
......@@ -37,7 +38,7 @@ static void InitializeRegisterNames() {
}
}
enum BlockCompletionType { kFallThrough, kBranch, kJump };
enum BlockCompletionType { kBlockEnd, kFallThrough, kBranch, kJump };
struct BlockCompletion {
BlockCompletionType type_;
......@@ -77,7 +78,8 @@ class RegisterAllocatorTest : public TestWithZone {
num_double_registers_(kDefaultNRegs),
instruction_blocks_(zone()),
current_block_(nullptr),
is_last_block_(false) {
is_last_block_(false),
block_returns_(false) {
InitializeRegisterNames();
}
......@@ -142,21 +144,29 @@ class RegisterAllocatorTest : public TestWithZone {
void StartBlock() {
CHECK(!is_last_block_);
block_returns_ = false;
NewBlock();
}
void EndBlock(BlockCompletion completion = FallThrough()) {
completions_.push_back(completion);
switch (completion.type_) {
case kBlockEnd:
CHECK(false); // unreachable;
break;
case kFallThrough:
if (is_last_block_) break;
// TODO(dcarney): we don't emit this after returns.
if (is_last_block_ || block_returns_) {
completions_.back().type_ = kBlockEnd;
break;
}
EmitFallThrough();
break;
case kJump:
CHECK(!block_returns_);
EmitJump();
break;
case kBranch:
CHECK(!block_returns_);
EmitBranch(completion.vreg_);
break;
}
......@@ -169,6 +179,7 @@ class RegisterAllocatorTest : public TestWithZone {
CHECK_EQ(nullptr, current_block_);
CHECK(is_last_block_);
WireBlocks();
RegisterAllocatorVerifier verifier(zone(), config(), sequence());
if (FLAG_trace_alloc || FLAG_trace_turbo) {
OFStream os(stdout);
PrintableInstructionSequence printable = {config(), sequence()};
......@@ -180,6 +191,8 @@ class RegisterAllocatorTest : public TestWithZone {
PrintableInstructionSequence printable = {config(), sequence()};
os << "After: " << std::endl << printable << std::endl;
}
verifier.VerifyAssignment();
verifier.VerifyGapMoves();
}
int NewReg() { return sequence()->NextVirtualRegister(); }
......@@ -192,6 +205,7 @@ class RegisterAllocatorTest : public TestWithZone {
}
Instruction* Return(int vreg) {
block_returns_ = true;
InstructionOperand* inputs[1]{UseRegister(vreg)};
return Emit(kArchRet, 0, nullptr, 1, inputs);
}
......@@ -344,12 +358,11 @@ class RegisterAllocatorTest : public TestWithZone {
void WireBlocks() {
CHECK(instruction_blocks_.size() == completions_.size());
size_t offset = 0;
size_t size = instruction_blocks_.size();
for (const auto& completion : completions_) {
switch (completion.type_) {
case kFallThrough:
if (offset == size - 1) break;
// Fallthrough.
case kBlockEnd:
break;
case kFallThrough: // Fallthrough.
case kJump:
WireBlock(offset, completion.offset_0_);
break;
......@@ -393,6 +406,7 @@ class RegisterAllocatorTest : public TestWithZone {
LoopBlocks loop_blocks_;
InstructionBlock* current_block_;
bool is_last_block_;
bool block_returns_;
};
......
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