Index: src/compiler/register-allocator-verifier.cc |
diff --git a/src/compiler/register-allocator-verifier.cc b/src/compiler/register-allocator-verifier.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b8aefe1f12647154524928fd79b5f42104b3087e |
--- /dev/null |
+++ b/src/compiler/register-allocator-verifier.cc |
@@ -0,0 +1,179 @@ |
+// 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); |
Jarin
2014/11/10 11:24:59
What is wrong with the ANY constraint?
dcarney
2014/11/10 11:27:17
it's only used for phi gap moves, not as an instru
|
+ 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 |