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

[turbofan] add register assignment verifier

R=jarin@chromium.org

BUG=

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

Cr-Commit-Position: refs/heads/master@{#25242}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@25242 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 9b18d167
......@@ -572,6 +572,8 @@ source_set("v8_base") {
"src/compiler/raw-machine-assembler.h",
"src/compiler/register-allocator.cc",
"src/compiler/register-allocator.h",
"src/compiler/register-allocator-verifier.cc",
"src/compiler/register-allocator-verifier.h",
"src/compiler/register-configuration.cc",
"src/compiler/register-configuration.h",
"src/compiler/representation-change.h",
......
......@@ -332,6 +332,11 @@ class SubKindOperand FINAL : public InstructionOperand {
return reinterpret_cast<SubKindOperand*>(op);
}
static const SubKindOperand* cast(const InstructionOperand* op) {
DCHECK(op->kind() == kOperandKind);
return reinterpret_cast<const SubKindOperand*>(op);
}
static void SetUpCache();
static void TearDownCache();
......@@ -581,7 +586,7 @@ class GapInstruction : public Instruction {
return parallel_moves_[pos];
}
ParallelMove* GetParallelMove(InnerPosition pos) {
ParallelMove* GetParallelMove(InnerPosition pos) const {
return parallel_moves_[pos];
}
......@@ -917,6 +922,7 @@ class InstructionSequence FINAL {
typedef InstructionDeque::const_iterator const_iterator;
const_iterator begin() const { return instructions_.begin(); }
const_iterator end() const { return instructions_.end(); }
const InstructionDeque& instructions() const { return instructions_; }
GapInstruction* GapAt(int index) const {
return GapInstruction::cast(InstructionAt(index));
......
......@@ -584,15 +584,17 @@ 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())) {
if (!allocator.Allocate(data->pipeline_statistics(), verification_type)) {
info()->AbortOptimization(kNotEnoughVirtualRegistersRegalloc);
return Handle<Code>::null();
}
......
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/compiler/instruction.h"
#include "src/compiler/register-allocator-verifier.h"
namespace v8 {
namespace internal {
namespace compiler {
static size_t OperandCount(const Instruction* instr) {
return instr->InputCount() + instr->OutputCount() + instr->TempCount();
}
RegisterAllocatorVerifier::RegisterAllocatorVerifier(
Zone* zone, const InstructionSequence* sequence)
: sequence_(sequence), constraints_(zone) {
constraints_.reserve(sequence->instructions().size());
for (const auto* instr : sequence->instructions()) {
const size_t operand_count = OperandCount(instr);
auto* op_constraints =
zone->NewArray<OperandConstraint>(static_cast<int>(operand_count));
// Construct OperandConstraints for all InstructionOperands, eliminating
// kSameAsFirst along the way.
size_t count = 0;
for (size_t i = 0; i < instr->InputCount(); ++i, ++count) {
BuildConstraint(instr->InputAt(i), &op_constraints[count]);
CHECK_NE(kSameAsFirst, op_constraints[count].type_);
}
for (size_t i = 0; i < instr->OutputCount(); ++i, ++count) {
BuildConstraint(instr->OutputAt(i), &op_constraints[count]);
if (op_constraints[count].type_ == kSameAsFirst) {
CHECK(instr->InputCount() > 0);
op_constraints[count] = op_constraints[0];
}
}
for (size_t i = 0; i < instr->TempCount(); ++i, ++count) {
BuildConstraint(instr->TempAt(i), &op_constraints[count]);
CHECK_NE(kSameAsFirst, op_constraints[count].type_);
}
// All gaps should be totally unallocated at this point.
if (instr->IsGapMoves()) {
const auto* gap = GapInstruction::cast(instr);
for (int i = GapInstruction::FIRST_INNER_POSITION;
i <= GapInstruction::LAST_INNER_POSITION; i++) {
GapInstruction::InnerPosition inner_pos =
static_cast<GapInstruction::InnerPosition>(i);
CHECK_EQ(NULL, gap->GetParallelMove(inner_pos));
}
}
InstructionConstraint instr_constraint = {instr, operand_count,
op_constraints};
constraints()->push_back(instr_constraint);
}
}
void RegisterAllocatorVerifier::VerifyAssignment() {
CHECK(sequence()->instructions().size() == constraints()->size());
auto instr_it = sequence()->begin();
for (const auto& instr_constraint : *constraints()) {
const auto* instr = instr_constraint.instruction_;
const size_t operand_count = instr_constraint.operand_constaints_size_;
const auto* op_constraints = instr_constraint.operand_constraints_;
CHECK_EQ(instr, *instr_it);
CHECK(operand_count == OperandCount(instr));
size_t count = 0;
for (size_t i = 0; i < instr->InputCount(); ++i, ++count) {
CheckConstraint(instr->InputAt(i), &op_constraints[count]);
}
for (size_t i = 0; i < instr->OutputCount(); ++i, ++count) {
CheckConstraint(instr->OutputAt(i), &op_constraints[count]);
}
for (size_t i = 0; i < instr->TempCount(); ++i, ++count) {
CheckConstraint(instr->TempAt(i), &op_constraints[count]);
}
++instr_it;
}
}
void RegisterAllocatorVerifier::BuildConstraint(const InstructionOperand* op,
OperandConstraint* constraint) {
constraint->value_ = kMinInt;
if (op->IsConstant()) {
constraint->type_ = kConstant;
constraint->value_ = ConstantOperand::cast(op)->index();
} else if (op->IsImmediate()) {
constraint->type_ = kImmediate;
constraint->value_ = ImmediateOperand::cast(op)->index();
} else {
CHECK(op->IsUnallocated());
const auto* unallocated = UnallocatedOperand::cast(op);
int vreg = unallocated->virtual_register();
if (unallocated->basic_policy() == UnallocatedOperand::FIXED_SLOT) {
constraint->type_ = kFixedSlot;
constraint->value_ = unallocated->fixed_slot_index();
} else {
switch (unallocated->extended_policy()) {
case UnallocatedOperand::ANY:
CHECK(false);
break;
case UnallocatedOperand::NONE:
if (sequence()->IsDouble(vreg)) {
constraint->type_ = kNoneDouble;
} else {
constraint->type_ = kNone;
}
break;
case UnallocatedOperand::FIXED_REGISTER:
constraint->type_ = kFixedRegister;
constraint->value_ = unallocated->fixed_register_index();
break;
case UnallocatedOperand::FIXED_DOUBLE_REGISTER:
constraint->type_ = kFixedDoubleRegister;
constraint->value_ = unallocated->fixed_register_index();
break;
case UnallocatedOperand::MUST_HAVE_REGISTER:
if (sequence()->IsDouble(vreg)) {
constraint->type_ = kDoubleRegister;
} else {
constraint->type_ = kRegister;
}
break;
case UnallocatedOperand::SAME_AS_FIRST_INPUT:
constraint->type_ = kSameAsFirst;
break;
}
}
}
}
void RegisterAllocatorVerifier::CheckConstraint(
const InstructionOperand* op, const OperandConstraint* constraint) {
switch (constraint->type_) {
case kConstant:
CHECK(op->IsConstant());
CHECK_EQ(op->index(), constraint->value_);
return;
case kImmediate:
CHECK(op->IsImmediate());
CHECK_EQ(op->index(), constraint->value_);
return;
case kRegister:
CHECK(op->IsRegister());
return;
case kFixedRegister:
CHECK(op->IsRegister());
CHECK_EQ(op->index(), constraint->value_);
return;
case kDoubleRegister:
CHECK(op->IsDoubleRegister());
return;
case kFixedDoubleRegister:
CHECK(op->IsDoubleRegister());
CHECK_EQ(op->index(), constraint->value_);
return;
case kFixedSlot:
CHECK(op->IsStackSlot());
CHECK_EQ(op->index(), constraint->value_);
return;
case kNone:
CHECK(op->IsRegister() || op->IsStackSlot());
return;
case kNoneDouble:
CHECK(op->IsDoubleRegister() || op->IsDoubleStackSlot());
return;
case kSameAsFirst:
CHECK(false);
return;
}
}
} // namespace compiler
} // namespace internal
} // namespace v8
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_REGISTER_ALLOCATOR_VERIFIER_H_
#define V8_REGISTER_ALLOCATOR_VERIFIER_H_
#include "src/v8.h"
#include "src/zone-containers.h"
namespace v8 {
namespace internal {
namespace compiler {
class InstructionOperand;
class InstructionSequence;
class RegisterAllocatorVerifier FINAL : public ZoneObject {
public:
RegisterAllocatorVerifier(Zone* zone, const InstructionSequence* sequence);
void VerifyAssignment();
private:
enum ConstraintType {
kConstant,
kImmediate,
kRegister,
kFixedRegister,
kDoubleRegister,
kFixedDoubleRegister,
kFixedSlot,
kNone,
kNoneDouble,
kSameAsFirst
};
struct OperandConstraint {
ConstraintType type_;
int value_; // subkind index when relevant
};
struct InstructionConstraint {
const Instruction* instruction_;
size_t operand_constaints_size_;
OperandConstraint* operand_constraints_;
};
typedef ZoneVector<InstructionConstraint> Constraints;
const InstructionSequence* sequence() const { return sequence_; }
Constraints* constraints() { return &constraints_; }
void BuildConstraint(const InstructionOperand* op,
OperandConstraint* constraint);
void CheckConstraint(const InstructionOperand* op,
const OperandConstraint* constraint);
const InstructionSequence* const sequence_;
Constraints constraints_;
DISALLOW_COPY_AND_ASSIGN(RegisterAllocatorVerifier);
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif
......@@ -5,6 +5,7 @@
#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 {
......@@ -1116,7 +1117,16 @@ void RegisterAllocator::ResolvePhis(const InstructionBlock* block) {
}
bool RegisterAllocator::Allocate(PipelineStatistics* stats) {
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());
}
assigned_registers_ = new (code_zone())
BitVector(config()->num_general_registers(), code_zone());
assigned_double_registers_ = new (code_zone())
......@@ -1158,6 +1168,9 @@ bool RegisterAllocator::Allocate(PipelineStatistics* stats) {
}
frame()->SetAllocatedRegisters(assigned_registers_);
frame()->SetAllocatedDoubleRegisters(assigned_double_registers_);
if (verifier != NULL) {
verifier->VerifyAssignment();
}
return true;
}
......
......@@ -322,12 +322,15 @@ 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);
bool Allocate(PipelineStatistics* stats = NULL,
VerificationType verification_type = kNoVerify);
bool AllocationOk() { return allocation_ok_; }
BitVector* assigned_registers() { return assigned_registers_; }
BitVector* assigned_double_registers() { return assigned_double_registers_; }
......
......@@ -485,6 +485,8 @@
'../../src/compiler/raw-machine-assembler.h',
'../../src/compiler/register-allocator.cc',
'../../src/compiler/register-allocator.h',
'../../src/compiler/register-allocator-verifier.cc',
'../../src/compiler/register-allocator-verifier.h',
'../../src/compiler/register-configuration.cc',
'../../src/compiler/register-configuration.h',
'../../src/compiler/representation-change.h',
......
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