Index: src/compiler/register-allocator-verifier.cc |
diff --git a/src/compiler/register-allocator-verifier.cc b/src/compiler/register-allocator-verifier.cc |
index eddcb3657a6a373ec56067f68aa4482b29d5ea6a..c0a3614e7d9e40d6a96e6716d3e04feeaba42b49 100644 |
--- a/src/compiler/register-allocator-verifier.cc |
+++ b/src/compiler/register-allocator-verifier.cc |
@@ -52,9 +52,7 @@ RegisterAllocatorVerifier::RegisterAllocatorVerifier( |
sequence_(sequence), |
constraints_(zone), |
assessments_(zone), |
- outstanding_assessments_(zone), |
- worklist_(zone), |
- seen_(zone) { |
+ outstanding_assessments_(zone) { |
constraints_.reserve(sequence->instructions().size()); |
// TODO(dcarney): model unique constraints. |
// Construct OperandConstraints for all InstructionOperands, eliminating |
@@ -347,24 +345,25 @@ BlockAssessments* RegisterAllocatorVerifier::CreateForBlock( |
} |
void RegisterAllocatorVerifier::ValidatePendingAssessment( |
- RpoNumber block_id, InstructionOperand op, PendingAssessment* assessment, |
+ RpoNumber block_id, InstructionOperand op, |
+ BlockAssessments* current_assessments, const PendingAssessment* assessment, |
int virtual_register) { |
// When validating a pending assessment, it is possible some of the |
// assessments |
// for the original operand (the one where the assessment was created for |
// first) are also pending. To avoid recursion, we use a work list. To |
// deal with cycles, we keep a set of seen nodes. |
- CHECK(worklist_.empty()); |
- CHECK(seen_.empty()); |
- worklist_.push(std::make_pair(assessment, virtual_register)); |
- seen_.insert(block_id); |
- |
- while (!worklist_.empty()) { |
- auto work = worklist_.front(); |
- PendingAssessment* current_assessment = work.first; |
+ ZoneQueue<std::pair<const PendingAssessment*, int>> worklist(zone()); |
+ ZoneSet<RpoNumber> seen(zone()); |
+ worklist.push(std::make_pair(assessment, virtual_register)); |
+ seen.insert(block_id); |
+ |
+ while (!worklist.empty()) { |
+ auto work = worklist.front(); |
+ const PendingAssessment* current_assessment = work.first; |
int current_virtual_register = work.second; |
InstructionOperand current_operand = current_assessment->operand(); |
- worklist_.pop(); |
+ worklist.pop(); |
const InstructionBlock* origin = current_assessment->origin(); |
CHECK(origin->PredecessorCount() > 1 || origin->phis().size() > 0); |
@@ -410,16 +409,17 @@ void RegisterAllocatorVerifier::ValidatePendingAssessment( |
switch (contribution->kind()) { |
case Final: |
- CHECK_EQ(FinalAssessment::cast(contribution)->virtual_register(), |
- expected); |
+ ValidateFinalAssessment( |
+ block_id, current_operand, current_assessments, |
+ FinalAssessment::cast(contribution), expected); |
break; |
case Pending: { |
// This happens if we have a diamond feeding into another one, and |
// the inner one never being used - other than for carrying the value. |
PendingAssessment* next = PendingAssessment::cast(contribution); |
- if (seen_.find(pred) == seen_.end()) { |
- worklist_.push({next, expected}); |
- seen_.insert(pred); |
+ if (seen.find(pred) == seen.end()) { |
+ worklist.push({next, expected}); |
+ seen.insert(pred); |
} |
// Note that we do not want to finalize pending assessments at the |
// beginning of a block - which is the information we'd have |
@@ -431,8 +431,26 @@ void RegisterAllocatorVerifier::ValidatePendingAssessment( |
} |
} |
} |
- seen_.clear(); |
- CHECK(worklist_.empty()); |
+ // If everything checks out, we may make the assessment. |
+ current_assessments->map()[op] = |
+ new (zone()) FinalAssessment(virtual_register, assessment); |
+} |
+ |
+void RegisterAllocatorVerifier::ValidateFinalAssessment( |
+ RpoNumber block_id, InstructionOperand op, |
+ BlockAssessments* current_assessments, const FinalAssessment* assessment, |
+ int virtual_register) { |
+ if (assessment->virtual_register() == virtual_register) return; |
+ // If we have 2 phis with the exact same operand list, and the first phi is |
+ // used before the second one, via the operand incoming to the block, |
+ // and the second one's operand is defined (via a parallel move) after the |
+ // use, then the original operand will be assigned to the first phi. We |
+ // then look at the original pending assessment to ascertain if op |
+ // is virtual_register. |
+ const PendingAssessment* old = assessment->original_pending_assessment(); |
+ CHECK_NOT_NULL(old); |
+ ValidatePendingAssessment(block_id, op, current_assessments, old, |
+ virtual_register); |
} |
void RegisterAllocatorVerifier::ValidateUse( |
@@ -445,16 +463,14 @@ void RegisterAllocatorVerifier::ValidateUse( |
switch (assessment->kind()) { |
case Final: |
- // The virtual registers should match. |
- CHECK_EQ(FinalAssessment::cast(assessment)->virtual_register(), |
- virtual_register); |
+ ValidateFinalAssessment(block_id, op, current_assessments, |
+ FinalAssessment::cast(assessment), |
+ virtual_register); |
break; |
case Pending: { |
- ValidatePendingAssessment( |
- block_id, op, PendingAssessment::cast(assessment), virtual_register); |
- // If everything checks out, we may make the assessment. |
- current_assessments->map()[op] = |
- new (zone()) FinalAssessment(virtual_register); |
+ const PendingAssessment* pending = PendingAssessment::cast(assessment); |
+ ValidatePendingAssessment(block_id, op, current_assessments, pending, |
+ virtual_register); |
break; |
} |
} |
@@ -522,14 +538,17 @@ void RegisterAllocatorVerifier::VerifyGapMoves() { |
CHECK(found_op != block_assessments->map().end()); |
switch (found_op->second->kind()) { |
case Final: |
- CHECK(FinalAssessment::cast(found_op->second)->virtual_register() == |
- vreg); |
+ ValidateFinalAssessment(block->rpo_number(), op, block_assessments, |
+ FinalAssessment::cast(found_op->second), |
+ vreg); |
break; |
case Pending: |
- ValidatePendingAssessment(block->rpo_number(), op, |
- PendingAssessment::cast(found_op->second), |
- vreg); |
- block_assessments->map()[op] = new (zone()) FinalAssessment(vreg); |
+ const PendingAssessment* pending = |
+ PendingAssessment::cast(found_op->second); |
+ ValidatePendingAssessment(block->rpo_number(), op, block_assessments, |
+ pending, vreg); |
+ block_assessments->map()[op] = |
+ new (zone()) FinalAssessment(vreg, pending); |
break; |
} |
} |