LCOV - code coverage report
Current view: top level - src/compiler - register-allocator-verifier.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 228 258 88.4 %
Date: 2017-10-20 Functions: 15 17 88.2 %

          Line data    Source code
       1             : // Copyright 2014 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/compiler/register-allocator-verifier.h"
       6             : 
       7             : #include "src/bit-vector.h"
       8             : #include "src/compiler/instruction.h"
       9             : #include "src/ostreams.h"
      10             : 
      11             : namespace v8 {
      12             : namespace internal {
      13             : namespace compiler {
      14             : 
      15             : namespace {
      16             : 
      17         996 : size_t OperandCount(const Instruction* instr) {
      18        1992 :   return instr->InputCount() + instr->OutputCount() + instr->TempCount();
      19             : }
      20             : 
      21         332 : void VerifyEmptyGaps(const Instruction* instr) {
      22         996 :   for (int i = Instruction::FIRST_GAP_POSITION;
      23             :        i <= Instruction::LAST_GAP_POSITION; i++) {
      24             :     Instruction::GapPosition inner_pos =
      25             :         static_cast<Instruction::GapPosition>(i);
      26         664 :     CHECK_NULL(instr->GetParallelMove(inner_pos));
      27             :   }
      28         332 : }
      29             : 
      30         664 : void VerifyAllocatedGaps(const Instruction* instr, const char* caller_info) {
      31        1992 :   for (int i = Instruction::FIRST_GAP_POSITION;
      32             :        i <= Instruction::LAST_GAP_POSITION; i++) {
      33             :     Instruction::GapPosition inner_pos =
      34             :         static_cast<Instruction::GapPosition>(i);
      35             :     const ParallelMove* moves = instr->GetParallelMove(inner_pos);
      36        1328 :     if (moves == nullptr) continue;
      37        1225 :     for (const MoveOperands* move : *moves) {
      38         511 :       if (move->IsRedundant()) continue;
      39         284 :       CHECK_WITH_MSG(
      40             :           move->source().IsAllocated() || move->source().IsConstant(),
      41             :           caller_info);
      42         284 :       CHECK_WITH_MSG(move->destination().IsAllocated(), caller_info);
      43             :     }
      44             :   }
      45         664 : }
      46             : 
      47             : }  // namespace
      48             : 
      49          42 : RegisterAllocatorVerifier::RegisterAllocatorVerifier(
      50             :     Zone* zone, const RegisterConfiguration* config,
      51             :     const InstructionSequence* sequence)
      52             :     : zone_(zone),
      53             :       config_(config),
      54             :       sequence_(sequence),
      55             :       constraints_(zone),
      56             :       assessments_(zone),
      57          84 :       outstanding_assessments_(zone) {
      58          42 :   constraints_.reserve(sequence->instructions().size());
      59             :   // TODO(dcarney): model unique constraints.
      60             :   // Construct OperandConstraints for all InstructionOperands, eliminating
      61             :   // kSameAsFirst along the way.
      62        2144 :   for (const Instruction* instr : sequence->instructions()) {
      63             :     // All gaps should be totally unallocated at this point.
      64         332 :     VerifyEmptyGaps(instr);
      65             :     const size_t operand_count = OperandCount(instr);
      66             :     OperandConstraint* op_constraints =
      67             :         zone->NewArray<OperandConstraint>(operand_count);
      68             :     size_t count = 0;
      69        1184 :     for (size_t i = 0; i < instr->InputCount(); ++i, ++count) {
      70         520 :       BuildConstraint(instr->InputAt(i), &op_constraints[count]);
      71         260 :       VerifyInput(op_constraints[count]);
      72             :     }
      73         332 :     for (size_t i = 0; i < instr->TempCount(); ++i, ++count) {
      74           0 :       BuildConstraint(instr->TempAt(i), &op_constraints[count]);
      75           0 :       VerifyTemp(op_constraints[count]);
      76             :     }
      77         686 :     for (size_t i = 0; i < instr->OutputCount(); ++i, ++count) {
      78         177 :       BuildConstraint(instr->OutputAt(i), &op_constraints[count]);
      79         177 :       if (op_constraints[count].type_ == kSameAsFirst) {
      80           5 :         CHECK_LT(0, instr->InputCount());
      81           5 :         op_constraints[count].type_ = op_constraints[0].type_;
      82           5 :         op_constraints[count].value_ = op_constraints[0].value_;
      83             :       }
      84         177 :       VerifyOutput(op_constraints[count]);
      85             :     }
      86             :     InstructionConstraint instr_constraint = {instr, operand_count,
      87         332 :                                               op_constraints};
      88         332 :     constraints()->push_back(instr_constraint);
      89             :   }
      90          42 : }
      91             : 
      92         260 : void RegisterAllocatorVerifier::VerifyInput(
      93             :     const OperandConstraint& constraint) {
      94         260 :   CHECK_NE(kSameAsFirst, constraint.type_);
      95         260 :   if (constraint.type_ != kImmediate && constraint.type_ != kExplicit) {
      96         159 :     CHECK_NE(InstructionOperand::kInvalidVirtualRegister,
      97             :              constraint.virtual_register_);
      98             :   }
      99         260 : }
     100             : 
     101           0 : void RegisterAllocatorVerifier::VerifyTemp(
     102             :     const OperandConstraint& constraint) {
     103           0 :   CHECK_NE(kSameAsFirst, constraint.type_);
     104           0 :   CHECK_NE(kImmediate, constraint.type_);
     105           0 :   CHECK_NE(kExplicit, constraint.type_);
     106           0 :   CHECK_NE(kConstant, constraint.type_);
     107           0 : }
     108             : 
     109         177 : void RegisterAllocatorVerifier::VerifyOutput(
     110             :     const OperandConstraint& constraint) {
     111         177 :   CHECK_NE(kImmediate, constraint.type_);
     112         177 :   CHECK_NE(kExplicit, constraint.type_);
     113         177 :   CHECK_NE(InstructionOperand::kInvalidVirtualRegister,
     114             :            constraint.virtual_register_);
     115         177 : }
     116             : 
     117         168 : void RegisterAllocatorVerifier::VerifyAssignment(const char* caller_info) {
     118          84 :   caller_info_ = caller_info;
     119         168 :   CHECK(sequence()->instructions().size() == constraints()->size());
     120             :   auto instr_it = sequence()->begin();
     121         748 :   for (const auto& instr_constraint : *constraints()) {
     122         664 :     const Instruction* instr = instr_constraint.instruction_;
     123             :     // All gaps should be totally allocated at this point.
     124         664 :     VerifyAllocatedGaps(instr, caller_info_);
     125         664 :     const size_t operand_count = instr_constraint.operand_constaints_size_;
     126             :     const OperandConstraint* op_constraints =
     127         664 :         instr_constraint.operand_constraints_;
     128         664 :     CHECK_EQ(instr, *instr_it);
     129         664 :     CHECK(operand_count == OperandCount(instr));
     130             :     size_t count = 0;
     131         520 :     for (size_t i = 0; i < instr->InputCount(); ++i, ++count) {
     132        1040 :       CheckConstraint(instr->InputAt(i), &op_constraints[count]);
     133             :     }
     134           0 :     for (size_t i = 0; i < instr->TempCount(); ++i, ++count) {
     135           0 :       CheckConstraint(instr->TempAt(i), &op_constraints[count]);
     136             :     }
     137         354 :     for (size_t i = 0; i < instr->OutputCount(); ++i, ++count) {
     138         354 :       CheckConstraint(instr->OutputAt(i), &op_constraints[count]);
     139             :     }
     140             :     ++instr_it;
     141             :   }
     142          84 : }
     143             : 
     144         437 : void RegisterAllocatorVerifier::BuildConstraint(const InstructionOperand* op,
     145         129 :                                                 OperandConstraint* constraint) {
     146         437 :   constraint->value_ = kMinInt;
     147         437 :   constraint->virtual_register_ = InstructionOperand::kInvalidVirtualRegister;
     148         437 :   if (op->IsConstant()) {
     149          61 :     constraint->type_ = kConstant;
     150          61 :     constraint->value_ = ConstantOperand::cast(op)->virtual_register();
     151          61 :     constraint->virtual_register_ = constraint->value_;
     152         376 :   } else if (op->IsExplicit()) {
     153           0 :     constraint->type_ = kExplicit;
     154         376 :   } else if (op->IsImmediate()) {
     155             :     const ImmediateOperand* imm = ImmediateOperand::cast(op);
     156             :     int value = imm->type() == ImmediateOperand::INLINE ? imm->inline_value()
     157         101 :                                                         : imm->indexed_value();
     158         101 :     constraint->type_ = kImmediate;
     159         101 :     constraint->value_ = value;
     160             :   } else {
     161         275 :     CHECK(op->IsUnallocated());
     162             :     const UnallocatedOperand* unallocated = UnallocatedOperand::cast(op);
     163             :     int vreg = unallocated->virtual_register();
     164         275 :     constraint->virtual_register_ = vreg;
     165         275 :     if (unallocated->basic_policy() == UnallocatedOperand::FIXED_SLOT) {
     166          51 :       constraint->type_ = kFixedSlot;
     167          51 :       constraint->value_ = unallocated->fixed_slot_index();
     168             :     } else {
     169         224 :       switch (unallocated->extended_policy()) {
     170             :         case UnallocatedOperand::ANY:
     171             :         case UnallocatedOperand::NONE:
     172          38 :           if (sequence()->IsFP(vreg)) {
     173           0 :             constraint->type_ = kNoneFP;
     174             :           } else {
     175          38 :             constraint->type_ = kNone;
     176             :           }
     177             :           break;
     178             :         case UnallocatedOperand::FIXED_REGISTER:
     179          88 :           if (unallocated->HasSecondaryStorage()) {
     180           0 :             constraint->type_ = kRegisterAndSlot;
     181           0 :             constraint->spilled_slot_ = unallocated->GetSecondaryStorage();
     182             :           } else {
     183          88 :             constraint->type_ = kFixedRegister;
     184             :           }
     185          88 :           constraint->value_ = unallocated->fixed_register_index();
     186          88 :           break;
     187             :         case UnallocatedOperand::FIXED_FP_REGISTER:
     188           2 :           constraint->type_ = kFixedFPRegister;
     189           2 :           constraint->value_ = unallocated->fixed_register_index();
     190           2 :           break;
     191             :         case UnallocatedOperand::MUST_HAVE_REGISTER:
     192          68 :           if (sequence()->IsFP(vreg)) {
     193          12 :             constraint->type_ = kFPRegister;
     194             :           } else {
     195          56 :             constraint->type_ = kRegister;
     196             :           }
     197             :           break;
     198             :         case UnallocatedOperand::MUST_HAVE_SLOT:
     199          23 :           constraint->type_ = kSlot;
     200             :           constraint->value_ =
     201          23 :               ElementSizeLog2Of(sequence()->GetRepresentation(vreg));
     202          23 :           break;
     203             :         case UnallocatedOperand::SAME_AS_FIRST_INPUT:
     204           5 :           constraint->type_ = kSameAsFirst;
     205           5 :           break;
     206             :       }
     207             :     }
     208             :   }
     209         437 : }
     210             : 
     211         874 : void RegisterAllocatorVerifier::CheckConstraint(
     212             :     const InstructionOperand* op, const OperandConstraint* constraint) {
     213         874 :   switch (constraint->type_) {
     214             :     case kConstant:
     215         122 :       CHECK_WITH_MSG(op->IsConstant(), caller_info_);
     216         244 :       CHECK_EQ(ConstantOperand::cast(op)->virtual_register(),
     217             :                constraint->value_);
     218             :       return;
     219             :     case kImmediate: {
     220         202 :       CHECK_WITH_MSG(op->IsImmediate(), caller_info_);
     221             :       const ImmediateOperand* imm = ImmediateOperand::cast(op);
     222             :       int value = imm->type() == ImmediateOperand::INLINE
     223             :                       ? imm->inline_value()
     224         202 :                       : imm->indexed_value();
     225         202 :       CHECK_EQ(value, constraint->value_);
     226             :       return;
     227             :     }
     228             :     case kRegister:
     229         122 :       CHECK_WITH_MSG(op->IsRegister(), caller_info_);
     230             :       return;
     231             :     case kFPRegister:
     232          24 :       CHECK_WITH_MSG(op->IsFPRegister(), caller_info_);
     233             :       return;
     234             :     case kExplicit:
     235           0 :       CHECK_WITH_MSG(op->IsExplicit(), caller_info_);
     236             :       return;
     237             :     case kFixedRegister:
     238             :     case kRegisterAndSlot:
     239         176 :       CHECK_WITH_MSG(op->IsRegister(), caller_info_);
     240         352 :       CHECK_EQ(LocationOperand::cast(op)->register_code(), constraint->value_);
     241             :       return;
     242             :     case kFixedFPRegister:
     243           4 :       CHECK_WITH_MSG(op->IsFPRegister(), caller_info_);
     244           8 :       CHECK_EQ(LocationOperand::cast(op)->register_code(), constraint->value_);
     245             :       return;
     246             :     case kFixedSlot:
     247         102 :       CHECK_WITH_MSG(op->IsStackSlot() || op->IsFPStackSlot(), caller_info_);
     248         204 :       CHECK_EQ(LocationOperand::cast(op)->index(), constraint->value_);
     249             :       return;
     250             :     case kSlot:
     251          46 :       CHECK_WITH_MSG(op->IsStackSlot() || op->IsFPStackSlot(), caller_info_);
     252          92 :       CHECK_EQ(ElementSizeLog2Of(LocationOperand::cast(op)->representation()),
     253             :                constraint->value_);
     254             :       return;
     255             :     case kNone:
     256         110 :       CHECK_WITH_MSG(op->IsRegister() || op->IsStackSlot(), caller_info_);
     257             :       return;
     258             :     case kNoneFP:
     259           0 :       CHECK_WITH_MSG(op->IsFPRegister() || op->IsFPStackSlot(), caller_info_);
     260             :       return;
     261             :     case kSameAsFirst:
     262           0 :       CHECK_WITH_MSG(false, caller_info_);
     263             :       return;
     264             :   }
     265             : }
     266             : 
     267         332 : void BlockAssessments::PerformMoves(const Instruction* instruction) {
     268             :   const ParallelMove* first =
     269             :       instruction->GetParallelMove(Instruction::GapPosition::START);
     270         332 :   PerformParallelMoves(first);
     271             :   const ParallelMove* last =
     272             :       instruction->GetParallelMove(Instruction::GapPosition::END);
     273         332 :   PerformParallelMoves(last);
     274         332 : }
     275             : 
     276         664 : void BlockAssessments::PerformParallelMoves(const ParallelMove* moves) {
     277        1328 :   if (moves == nullptr) return;
     278             : 
     279         195 :   CHECK(map_for_moves_.empty());
     280         618 :   for (MoveOperands* move : *moves) {
     281         228 :     if (move->IsEliminated() || move->IsRedundant()) continue;
     282         163 :     auto it = map_.find(move->source());
     283             :     // The RHS of a parallel move should have been already assessed.
     284         163 :     CHECK(it != map_.end());
     285             :     // The LHS of a parallel move should not have been assigned in this
     286             :     // parallel move.
     287         326 :     CHECK(map_for_moves_.find(move->destination()) == map_for_moves_.end());
     288             :     // Copy the assessment to the destination.
     289         163 :     map_for_moves_[move->destination()] = it->second;
     290             :   }
     291         553 :   for (auto pair : map_for_moves_) {
     292         163 :     map_[pair.first] = pair.second;
     293             :   }
     294             :   map_for_moves_.clear();
     295             : }
     296             : 
     297          10 : void BlockAssessments::DropRegisters() {
     298         150 :   for (auto iterator = map().begin(), end = map().end(); iterator != end;) {
     299             :     auto current = iterator;
     300             :     ++iterator;
     301         130 :     InstructionOperand op = current->first;
     302         130 :     if (op.IsAnyRegister()) map().erase(current);
     303             :   }
     304          10 : }
     305             : 
     306           0 : void BlockAssessments::Print() const {
     307           0 :   OFStream os(stdout);
     308           0 :   for (const auto pair : map()) {
     309             :     const InstructionOperand op = pair.first;
     310             :     const Assessment* assessment = pair.second;
     311             :     // Use operator<< so we can write the assessment on the same
     312             :     // line. Since we need a register configuration, just pick
     313             :     // Turbofan for now.
     314           0 :     PrintableInstructionOperand wrapper = {RegisterConfiguration::Default(),
     315           0 :                                            op};
     316           0 :     os << wrapper << " : ";
     317           0 :     if (assessment->kind() == AssessmentKind::Final) {
     318           0 :       os << "v" << FinalAssessment::cast(assessment)->virtual_register();
     319             :     } else {
     320           0 :       os << "P";
     321             :     }
     322             :     os << std::endl;
     323             :   }
     324           0 :   os << std::endl;
     325           0 : }
     326             : 
     327         142 : BlockAssessments* RegisterAllocatorVerifier::CreateForBlock(
     328         287 :     const InstructionBlock* block) {
     329             :   RpoNumber current_block_id = block->rpo_number();
     330             : 
     331             :   BlockAssessments* ret = new (zone()) BlockAssessments(zone());
     332         142 :   if (block->PredecessorCount() == 0) {
     333             :     // TODO(mtrofin): the following check should hold, however, in certain
     334             :     // unit tests it is invalidated by the last block. Investigate and
     335             :     // normalize the CFG.
     336             :     // CHECK_EQ(0, current_block_id.ToInt());
     337             :     // The phi size test below is because we can, technically, have phi
     338             :     // instructions with one argument. Some tests expose that, too.
     339         179 :   } else if (block->PredecessorCount() == 1 && block->phis().size() == 0) {
     340          79 :     const BlockAssessments* prev_block = assessments_[block->predecessors()[0]];
     341          79 :     ret->CopyFrom(prev_block);
     342             :   } else {
     343          98 :     for (RpoNumber pred_id : block->predecessors()) {
     344             :       // For every operand coming from any of the predecessors, create an
     345             :       // Unfinalized assessment.
     346             :       auto iterator = assessments_.find(pred_id);
     347          39 :       if (iterator == assessments_.end()) {
     348             :         // This block is the head of a loop, and this predecessor is the
     349             :         // loopback
     350             :         // arc.
     351             :         // Validate this is a loop case, otherwise the CFG is malformed.
     352           2 :         CHECK(pred_id >= current_block_id);
     353           2 :         CHECK(block->IsLoopHeader());
     354             :         continue;
     355             :       }
     356          37 :       const BlockAssessments* pred_assessments = iterator->second;
     357          37 :       CHECK_NOT_NULL(pred_assessments);
     358         292 :       for (auto pair : pred_assessments->map()) {
     359         218 :         InstructionOperand operand = pair.first;
     360         218 :         if (ret->map().find(operand) == ret->map().end()) {
     361             :           ret->map().insert(std::make_pair(
     362         435 :               operand, new (zone()) PendingAssessment(zone(), block, operand)));
     363             :         }
     364             :       }
     365             :     }
     366             :   }
     367         142 :   return ret;
     368             : }
     369             : 
     370          53 : void RegisterAllocatorVerifier::ValidatePendingAssessment(
     371             :     RpoNumber block_id, InstructionOperand op,
     372             :     const BlockAssessments* current_assessments,
     373          51 :     PendingAssessment* const assessment, int virtual_register) {
     374          57 :   if (assessment->IsAliasOf(virtual_register)) return;
     375             : 
     376             :   // When validating a pending assessment, it is possible some of the
     377             :   // assessments for the original operand (the one where the assessment was
     378             :   // created for first) are also pending. To avoid recursion, we use a work
     379             :   // list. To deal with cycles, we keep a set of seen nodes.
     380          49 :   Zone local_zone(zone()->allocator(), ZONE_NAME);
     381          49 :   ZoneQueue<std::pair<const PendingAssessment*, int>> worklist(&local_zone);
     382             :   ZoneSet<RpoNumber> seen(&local_zone);
     383          49 :   worklist.push(std::make_pair(assessment, virtual_register));
     384             :   seen.insert(block_id);
     385             : 
     386         134 :   while (!worklist.empty()) {
     387          85 :     auto work = worklist.front();
     388          85 :     const PendingAssessment* current_assessment = work.first;
     389             :     int current_virtual_register = work.second;
     390          85 :     InstructionOperand current_operand = current_assessment->operand();
     391             :     worklist.pop();
     392             : 
     393             :     const InstructionBlock* origin = current_assessment->origin();
     394          87 :     CHECK(origin->PredecessorCount() > 1 || origin->phis().size() > 0);
     395             : 
     396             :     // Check if the virtual register is a phi first, instead of relying on
     397             :     // the incoming assessments. In particular, this handles the case
     398             :     // v1 = phi v0 v0, which structurally is identical to v0 having been
     399             :     // defined at the top of a diamond, and arriving at the node joining the
     400             :     // diamond's branches.
     401             :     const PhiInstruction* phi = nullptr;
     402         438 :     for (const PhiInstruction* candidate : origin->phis()) {
     403         313 :       if (candidate->virtual_register() == current_virtual_register) {
     404             :         phi = candidate;
     405             :         break;
     406             :       }
     407             :     }
     408             : 
     409             :     int op_index = 0;
     410         338 :     for (RpoNumber pred : origin->predecessors()) {
     411             :       int expected =
     412         258 :           phi != nullptr ? phi->operands()[op_index] : current_virtual_register;
     413             : 
     414         168 :       ++op_index;
     415             :       auto pred_assignment = assessments_.find(pred);
     416         168 :       if (pred_assignment == assessments_.end()) {
     417           6 :         CHECK(origin->IsLoopHeader());
     418             :         auto todo_iter = outstanding_assessments_.find(pred);
     419             :         DelayedAssessments* set = nullptr;
     420           6 :         if (todo_iter == outstanding_assessments_.end()) {
     421             :           set = new (zone()) DelayedAssessments(zone());
     422           4 :           outstanding_assessments_.insert(std::make_pair(pred, set));
     423             :         } else {
     424           4 :           set = todo_iter->second;
     425             :         }
     426           6 :         set->AddDelayedAssessment(current_operand, expected);
     427             :         continue;
     428             :       }
     429             : 
     430         162 :       const BlockAssessments* pred_assessments = pred_assignment->second;
     431             :       auto found_contribution = pred_assessments->map().find(current_operand);
     432         162 :       CHECK(found_contribution != pred_assessments->map().end());
     433         162 :       Assessment* contribution = found_contribution->second;
     434             : 
     435         162 :       switch (contribution->kind()) {
     436             :         case Final:
     437         126 :           CHECK_EQ(FinalAssessment::cast(contribution)->virtual_register(),
     438             :                    expected);
     439             :           break;
     440             :         case Pending: {
     441             :           // This happens if we have a diamond feeding into another one, and
     442             :           // the inner one never being used - other than for carrying the value.
     443          36 :           const PendingAssessment* next = PendingAssessment::cast(contribution);
     444          36 :           if (seen.find(pred) == seen.end()) {
     445          36 :             worklist.push({next, expected});
     446             :             seen.insert(pred);
     447             :           }
     448             :           // Note that we do not want to finalize pending assessments at the
     449             :           // beginning of a block - which is the information we'd have
     450             :           // available here. This is because this operand may be reused to
     451             :           // define duplicate phis.
     452             :           break;
     453             :         }
     454             :       }
     455             :     }
     456             :   }
     457          49 :   assessment->AddAlias(virtual_register);
     458             : }
     459             : 
     460         159 : void RegisterAllocatorVerifier::ValidateUse(
     461             :     RpoNumber block_id, BlockAssessments* current_assessments,
     462             :     InstructionOperand op, int virtual_register) {
     463             :   auto iterator = current_assessments->map().find(op);
     464             :   // We should have seen this operand before.
     465         159 :   CHECK(iterator != current_assessments->map().end());
     466         159 :   Assessment* assessment = iterator->second;
     467             : 
     468         159 :   switch (assessment->kind()) {
     469             :     case Final:
     470         107 :       CHECK_EQ(FinalAssessment::cast(assessment)->virtual_register(),
     471             :                virtual_register);
     472             :       break;
     473             :     case Pending: {
     474          52 :       PendingAssessment* pending = PendingAssessment::cast(assessment);
     475             :       ValidatePendingAssessment(block_id, op, current_assessments, pending,
     476          52 :                                 virtual_register);
     477          52 :       break;
     478             :     }
     479             :   }
     480         159 : }
     481             : 
     482         226 : void RegisterAllocatorVerifier::VerifyGapMoves() {
     483          42 :   CHECK(assessments_.empty());
     484          42 :   CHECK(outstanding_assessments_.empty());
     485          42 :   const size_t block_count = sequence()->instruction_blocks().size();
     486         184 :   for (size_t block_index = 0; block_index < block_count; ++block_index) {
     487         616 :     const InstructionBlock* block =
     488         284 :         sequence()->instruction_blocks()[block_index];
     489         142 :     BlockAssessments* block_assessments = CreateForBlock(block);
     490             : 
     491         948 :     for (int instr_index = block->code_start(); instr_index < block->code_end();
     492             :          ++instr_index) {
     493         332 :       const InstructionConstraint& instr_constraint = constraints_[instr_index];
     494        1765 :       const Instruction* instr = instr_constraint.instruction_;
     495         332 :       block_assessments->PerformMoves(instr);
     496             : 
     497             :       const OperandConstraint* op_constraints =
     498         332 :           instr_constraint.operand_constraints_;
     499             :       size_t count = 0;
     500        1184 :       for (size_t i = 0; i < instr->InputCount(); ++i, ++count) {
     501         260 :         if (op_constraints[count].type_ == kImmediate ||
     502             :             op_constraints[count].type_ == kExplicit) {
     503         101 :           continue;
     504             :         }
     505         159 :         int virtual_register = op_constraints[count].virtual_register_;
     506         159 :         InstructionOperand op = *instr->InputAt(i);
     507             :         ValidateUse(block->rpo_number(), block_assessments, op,
     508         159 :                     virtual_register);
     509             :       }
     510         332 :       for (size_t i = 0; i < instr->TempCount(); ++i, ++count) {
     511             :         block_assessments->Drop(*instr->TempAt(i));
     512             :       }
     513         332 :       if (instr->IsCall()) {
     514          10 :         block_assessments->DropRegisters();
     515             :       }
     516         686 :       for (size_t i = 0; i < instr->OutputCount(); ++i, ++count) {
     517         177 :         int virtual_register = op_constraints[count].virtual_register_;
     518         177 :         block_assessments->AddDefinition(*instr->OutputAt(i), virtual_register);
     519         177 :         if (op_constraints[count].type_ == kRegisterAndSlot) {
     520             :           const AllocatedOperand* reg_op =
     521             :               AllocatedOperand::cast(instr->OutputAt(i));
     522             :           MachineRepresentation rep = reg_op->representation();
     523             :           const AllocatedOperand* stack_op = AllocatedOperand::New(
     524             :               zone(), LocationOperand::LocationKind::STACK_SLOT, rep,
     525           0 :               op_constraints[i].spilled_slot_);
     526           0 :           block_assessments->AddDefinition(*stack_op, virtual_register);
     527             :         }
     528             :       }
     529             :     }
     530             :     // Now commit the assessments for this block. If there are any delayed
     531             :     // assessments, ValidatePendingAssessment should see this block, too.
     532         142 :     assessments_[block->rpo_number()] = block_assessments;
     533             : 
     534         284 :     auto todo_iter = outstanding_assessments_.find(block->rpo_number());
     535         142 :     if (todo_iter == outstanding_assessments_.end()) continue;
     536           2 :     DelayedAssessments* todo = todo_iter->second;
     537          10 :     for (auto pair : todo->map()) {
     538           6 :       InstructionOperand op = pair.first;
     539             :       int vreg = pair.second;
     540             :       auto found_op = block_assessments->map().find(op);
     541           6 :       CHECK(found_op != block_assessments->map().end());
     542          12 :       switch (found_op->second->kind()) {
     543             :         case Final:
     544           5 :           CHECK_EQ(FinalAssessment::cast(found_op->second)->virtual_register(),
     545             :                    vreg);
     546             :           break;
     547             :         case Pending:
     548             :           ValidatePendingAssessment(block->rpo_number(), op, block_assessments,
     549             :                                     PendingAssessment::cast(found_op->second),
     550           1 :                                     vreg);
     551           1 :           break;
     552             :       }
     553             :     }
     554             :   }
     555          42 : }
     556             : 
     557             : }  // namespace compiler
     558             : }  // namespace internal
     559             : }  // namespace v8

Generated by: LCOV version 1.10