11cb0ef41Sopenharmony_ci// Copyright 2014 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include "src/compiler/backend/register-allocator-verifier.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include "src/compiler/backend/instruction.h"
81cb0ef41Sopenharmony_ci#include "src/utils/bit-vector.h"
91cb0ef41Sopenharmony_ci#include "src/utils/ostreams.h"
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_cinamespace v8 {
121cb0ef41Sopenharmony_cinamespace internal {
131cb0ef41Sopenharmony_cinamespace compiler {
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_cinamespace {
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_cisize_t OperandCount(const Instruction* instr) {
181cb0ef41Sopenharmony_ci  return instr->InputCount() + instr->OutputCount() + instr->TempCount();
191cb0ef41Sopenharmony_ci}
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_civoid VerifyEmptyGaps(const Instruction* instr) {
221cb0ef41Sopenharmony_ci  for (int i = Instruction::FIRST_GAP_POSITION;
231cb0ef41Sopenharmony_ci       i <= Instruction::LAST_GAP_POSITION; i++) {
241cb0ef41Sopenharmony_ci    Instruction::GapPosition inner_pos =
251cb0ef41Sopenharmony_ci        static_cast<Instruction::GapPosition>(i);
261cb0ef41Sopenharmony_ci    CHECK_NULL(instr->GetParallelMove(inner_pos));
271cb0ef41Sopenharmony_ci  }
281cb0ef41Sopenharmony_ci}
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_civoid VerifyAllocatedGaps(const Instruction* instr, const char* caller_info) {
311cb0ef41Sopenharmony_ci  for (int i = Instruction::FIRST_GAP_POSITION;
321cb0ef41Sopenharmony_ci       i <= Instruction::LAST_GAP_POSITION; i++) {
331cb0ef41Sopenharmony_ci    Instruction::GapPosition inner_pos =
341cb0ef41Sopenharmony_ci        static_cast<Instruction::GapPosition>(i);
351cb0ef41Sopenharmony_ci    const ParallelMove* moves = instr->GetParallelMove(inner_pos);
361cb0ef41Sopenharmony_ci    if (moves == nullptr) continue;
371cb0ef41Sopenharmony_ci    for (const MoveOperands* move : *moves) {
381cb0ef41Sopenharmony_ci      if (move->IsRedundant()) continue;
391cb0ef41Sopenharmony_ci      CHECK_WITH_MSG(
401cb0ef41Sopenharmony_ci          move->source().IsAllocated() || move->source().IsConstant(),
411cb0ef41Sopenharmony_ci          caller_info);
421cb0ef41Sopenharmony_ci      CHECK_WITH_MSG(move->destination().IsAllocated(), caller_info);
431cb0ef41Sopenharmony_ci    }
441cb0ef41Sopenharmony_ci  }
451cb0ef41Sopenharmony_ci}
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ciint GetValue(const ImmediateOperand* imm) {
481cb0ef41Sopenharmony_ci  switch (imm->type()) {
491cb0ef41Sopenharmony_ci    case ImmediateOperand::INLINE_INT32:
501cb0ef41Sopenharmony_ci      return imm->inline_int32_value();
511cb0ef41Sopenharmony_ci    case ImmediateOperand::INLINE_INT64:
521cb0ef41Sopenharmony_ci      return static_cast<int>(imm->inline_int64_value());
531cb0ef41Sopenharmony_ci    case ImmediateOperand::INDEXED_RPO:
541cb0ef41Sopenharmony_ci    case ImmediateOperand::INDEXED_IMM:
551cb0ef41Sopenharmony_ci      return imm->indexed_value();
561cb0ef41Sopenharmony_ci  }
571cb0ef41Sopenharmony_ci}
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ci}  // namespace
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ciRegisterAllocatorVerifier::RegisterAllocatorVerifier(
621cb0ef41Sopenharmony_ci    Zone* zone, const RegisterConfiguration* config,
631cb0ef41Sopenharmony_ci    const InstructionSequence* sequence, const Frame* frame)
641cb0ef41Sopenharmony_ci    : zone_(zone),
651cb0ef41Sopenharmony_ci      config_(config),
661cb0ef41Sopenharmony_ci      sequence_(sequence),
671cb0ef41Sopenharmony_ci      constraints_(zone),
681cb0ef41Sopenharmony_ci      assessments_(zone),
691cb0ef41Sopenharmony_ci      outstanding_assessments_(zone),
701cb0ef41Sopenharmony_ci      spill_slot_delta_(frame->GetTotalFrameSlotCount() -
711cb0ef41Sopenharmony_ci                        frame->GetSpillSlotCount()) {
721cb0ef41Sopenharmony_ci  constraints_.reserve(sequence->instructions().size());
731cb0ef41Sopenharmony_ci  // TODO(dcarney): model unique constraints.
741cb0ef41Sopenharmony_ci  // Construct OperandConstraints for all InstructionOperands, eliminating
751cb0ef41Sopenharmony_ci  // kSameAsInput along the way.
761cb0ef41Sopenharmony_ci  for (const Instruction* instr : sequence->instructions()) {
771cb0ef41Sopenharmony_ci    // All gaps should be totally unallocated at this point.
781cb0ef41Sopenharmony_ci    VerifyEmptyGaps(instr);
791cb0ef41Sopenharmony_ci    const size_t operand_count = OperandCount(instr);
801cb0ef41Sopenharmony_ci    OperandConstraint* op_constraints =
811cb0ef41Sopenharmony_ci        zone->NewArray<OperandConstraint>(operand_count);
821cb0ef41Sopenharmony_ci    size_t count = 0;
831cb0ef41Sopenharmony_ci    for (size_t i = 0; i < instr->InputCount(); ++i, ++count) {
841cb0ef41Sopenharmony_ci      BuildConstraint(instr->InputAt(i), &op_constraints[count]);
851cb0ef41Sopenharmony_ci      VerifyInput(op_constraints[count]);
861cb0ef41Sopenharmony_ci    }
871cb0ef41Sopenharmony_ci    for (size_t i = 0; i < instr->TempCount(); ++i, ++count) {
881cb0ef41Sopenharmony_ci      BuildConstraint(instr->TempAt(i), &op_constraints[count]);
891cb0ef41Sopenharmony_ci      VerifyTemp(op_constraints[count]);
901cb0ef41Sopenharmony_ci    }
911cb0ef41Sopenharmony_ci    for (size_t i = 0; i < instr->OutputCount(); ++i, ++count) {
921cb0ef41Sopenharmony_ci      BuildConstraint(instr->OutputAt(i), &op_constraints[count]);
931cb0ef41Sopenharmony_ci      if (op_constraints[count].type_ == kSameAsInput) {
941cb0ef41Sopenharmony_ci        int input_index = op_constraints[count].value_;
951cb0ef41Sopenharmony_ci        CHECK_LT(input_index, instr->InputCount());
961cb0ef41Sopenharmony_ci        op_constraints[count].type_ = op_constraints[input_index].type_;
971cb0ef41Sopenharmony_ci        op_constraints[count].value_ = op_constraints[input_index].value_;
981cb0ef41Sopenharmony_ci      }
991cb0ef41Sopenharmony_ci      VerifyOutput(op_constraints[count]);
1001cb0ef41Sopenharmony_ci    }
1011cb0ef41Sopenharmony_ci    InstructionConstraint instr_constraint = {instr, operand_count,
1021cb0ef41Sopenharmony_ci                                              op_constraints};
1031cb0ef41Sopenharmony_ci    constraints()->push_back(instr_constraint);
1041cb0ef41Sopenharmony_ci  }
1051cb0ef41Sopenharmony_ci}
1061cb0ef41Sopenharmony_ci
1071cb0ef41Sopenharmony_civoid RegisterAllocatorVerifier::VerifyInput(
1081cb0ef41Sopenharmony_ci    const OperandConstraint& constraint) {
1091cb0ef41Sopenharmony_ci  CHECK_NE(kSameAsInput, constraint.type_);
1101cb0ef41Sopenharmony_ci  if (constraint.type_ != kImmediate) {
1111cb0ef41Sopenharmony_ci    CHECK_NE(InstructionOperand::kInvalidVirtualRegister,
1121cb0ef41Sopenharmony_ci             constraint.virtual_register_);
1131cb0ef41Sopenharmony_ci  }
1141cb0ef41Sopenharmony_ci}
1151cb0ef41Sopenharmony_ci
1161cb0ef41Sopenharmony_civoid RegisterAllocatorVerifier::VerifyTemp(
1171cb0ef41Sopenharmony_ci    const OperandConstraint& constraint) {
1181cb0ef41Sopenharmony_ci  CHECK_NE(kSameAsInput, constraint.type_);
1191cb0ef41Sopenharmony_ci  CHECK_NE(kImmediate, constraint.type_);
1201cb0ef41Sopenharmony_ci  CHECK_NE(kConstant, constraint.type_);
1211cb0ef41Sopenharmony_ci}
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_civoid RegisterAllocatorVerifier::VerifyOutput(
1241cb0ef41Sopenharmony_ci    const OperandConstraint& constraint) {
1251cb0ef41Sopenharmony_ci  CHECK_NE(kImmediate, constraint.type_);
1261cb0ef41Sopenharmony_ci  CHECK_NE(InstructionOperand::kInvalidVirtualRegister,
1271cb0ef41Sopenharmony_ci           constraint.virtual_register_);
1281cb0ef41Sopenharmony_ci}
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_civoid RegisterAllocatorVerifier::VerifyAssignment(const char* caller_info) {
1311cb0ef41Sopenharmony_ci  caller_info_ = caller_info;
1321cb0ef41Sopenharmony_ci  CHECK(sequence()->instructions().size() == constraints()->size());
1331cb0ef41Sopenharmony_ci  auto instr_it = sequence()->begin();
1341cb0ef41Sopenharmony_ci  for (const auto& instr_constraint : *constraints()) {
1351cb0ef41Sopenharmony_ci    const Instruction* instr = instr_constraint.instruction_;
1361cb0ef41Sopenharmony_ci    // All gaps should be totally allocated at this point.
1371cb0ef41Sopenharmony_ci    VerifyAllocatedGaps(instr, caller_info_);
1381cb0ef41Sopenharmony_ci    const size_t operand_count = instr_constraint.operand_constaints_size_;
1391cb0ef41Sopenharmony_ci    const OperandConstraint* op_constraints =
1401cb0ef41Sopenharmony_ci        instr_constraint.operand_constraints_;
1411cb0ef41Sopenharmony_ci    CHECK_EQ(instr, *instr_it);
1421cb0ef41Sopenharmony_ci    CHECK(operand_count == OperandCount(instr));
1431cb0ef41Sopenharmony_ci    size_t count = 0;
1441cb0ef41Sopenharmony_ci    for (size_t i = 0; i < instr->InputCount(); ++i, ++count) {
1451cb0ef41Sopenharmony_ci      CheckConstraint(instr->InputAt(i), &op_constraints[count]);
1461cb0ef41Sopenharmony_ci    }
1471cb0ef41Sopenharmony_ci    for (size_t i = 0; i < instr->TempCount(); ++i, ++count) {
1481cb0ef41Sopenharmony_ci      CheckConstraint(instr->TempAt(i), &op_constraints[count]);
1491cb0ef41Sopenharmony_ci    }
1501cb0ef41Sopenharmony_ci    for (size_t i = 0; i < instr->OutputCount(); ++i, ++count) {
1511cb0ef41Sopenharmony_ci      CheckConstraint(instr->OutputAt(i), &op_constraints[count]);
1521cb0ef41Sopenharmony_ci    }
1531cb0ef41Sopenharmony_ci    ++instr_it;
1541cb0ef41Sopenharmony_ci  }
1551cb0ef41Sopenharmony_ci}
1561cb0ef41Sopenharmony_ci
1571cb0ef41Sopenharmony_civoid RegisterAllocatorVerifier::BuildConstraint(const InstructionOperand* op,
1581cb0ef41Sopenharmony_ci                                                OperandConstraint* constraint) {
1591cb0ef41Sopenharmony_ci  constraint->value_ = kMinInt;
1601cb0ef41Sopenharmony_ci  constraint->virtual_register_ = InstructionOperand::kInvalidVirtualRegister;
1611cb0ef41Sopenharmony_ci  if (op->IsConstant()) {
1621cb0ef41Sopenharmony_ci    constraint->type_ = kConstant;
1631cb0ef41Sopenharmony_ci    constraint->value_ = ConstantOperand::cast(op)->virtual_register();
1641cb0ef41Sopenharmony_ci    constraint->virtual_register_ = constraint->value_;
1651cb0ef41Sopenharmony_ci  } else if (op->IsImmediate()) {
1661cb0ef41Sopenharmony_ci    const ImmediateOperand* imm = ImmediateOperand::cast(op);
1671cb0ef41Sopenharmony_ci    constraint->type_ = kImmediate;
1681cb0ef41Sopenharmony_ci    constraint->value_ = GetValue(imm);
1691cb0ef41Sopenharmony_ci  } else {
1701cb0ef41Sopenharmony_ci    CHECK(op->IsUnallocated());
1711cb0ef41Sopenharmony_ci    const UnallocatedOperand* unallocated = UnallocatedOperand::cast(op);
1721cb0ef41Sopenharmony_ci    int vreg = unallocated->virtual_register();
1731cb0ef41Sopenharmony_ci    constraint->virtual_register_ = vreg;
1741cb0ef41Sopenharmony_ci    if (unallocated->basic_policy() == UnallocatedOperand::FIXED_SLOT) {
1751cb0ef41Sopenharmony_ci      constraint->type_ = kFixedSlot;
1761cb0ef41Sopenharmony_ci      constraint->value_ = unallocated->fixed_slot_index();
1771cb0ef41Sopenharmony_ci    } else {
1781cb0ef41Sopenharmony_ci      switch (unallocated->extended_policy()) {
1791cb0ef41Sopenharmony_ci        case UnallocatedOperand::REGISTER_OR_SLOT:
1801cb0ef41Sopenharmony_ci        case UnallocatedOperand::NONE:
1811cb0ef41Sopenharmony_ci          if (sequence()->IsFP(vreg)) {
1821cb0ef41Sopenharmony_ci            constraint->type_ = kRegisterOrSlotFP;
1831cb0ef41Sopenharmony_ci          } else {
1841cb0ef41Sopenharmony_ci            constraint->type_ = kRegisterOrSlot;
1851cb0ef41Sopenharmony_ci          }
1861cb0ef41Sopenharmony_ci          break;
1871cb0ef41Sopenharmony_ci        case UnallocatedOperand::REGISTER_OR_SLOT_OR_CONSTANT:
1881cb0ef41Sopenharmony_ci          DCHECK(!sequence()->IsFP(vreg));
1891cb0ef41Sopenharmony_ci          constraint->type_ = kRegisterOrSlotOrConstant;
1901cb0ef41Sopenharmony_ci          break;
1911cb0ef41Sopenharmony_ci        case UnallocatedOperand::FIXED_REGISTER:
1921cb0ef41Sopenharmony_ci          if (unallocated->HasSecondaryStorage()) {
1931cb0ef41Sopenharmony_ci            constraint->type_ = kRegisterAndSlot;
1941cb0ef41Sopenharmony_ci            constraint->spilled_slot_ = unallocated->GetSecondaryStorage();
1951cb0ef41Sopenharmony_ci          } else {
1961cb0ef41Sopenharmony_ci            constraint->type_ = kFixedRegister;
1971cb0ef41Sopenharmony_ci          }
1981cb0ef41Sopenharmony_ci          constraint->value_ = unallocated->fixed_register_index();
1991cb0ef41Sopenharmony_ci          break;
2001cb0ef41Sopenharmony_ci        case UnallocatedOperand::FIXED_FP_REGISTER:
2011cb0ef41Sopenharmony_ci          constraint->type_ = kFixedFPRegister;
2021cb0ef41Sopenharmony_ci          constraint->value_ = unallocated->fixed_register_index();
2031cb0ef41Sopenharmony_ci          break;
2041cb0ef41Sopenharmony_ci        case UnallocatedOperand::MUST_HAVE_REGISTER:
2051cb0ef41Sopenharmony_ci          if (sequence()->IsFP(vreg)) {
2061cb0ef41Sopenharmony_ci            constraint->type_ = kFPRegister;
2071cb0ef41Sopenharmony_ci          } else {
2081cb0ef41Sopenharmony_ci            constraint->type_ = kRegister;
2091cb0ef41Sopenharmony_ci          }
2101cb0ef41Sopenharmony_ci          break;
2111cb0ef41Sopenharmony_ci        case UnallocatedOperand::MUST_HAVE_SLOT:
2121cb0ef41Sopenharmony_ci          constraint->type_ = kSlot;
2131cb0ef41Sopenharmony_ci          constraint->value_ =
2141cb0ef41Sopenharmony_ci              ElementSizeLog2Of(sequence()->GetRepresentation(vreg));
2151cb0ef41Sopenharmony_ci          break;
2161cb0ef41Sopenharmony_ci        case UnallocatedOperand::SAME_AS_INPUT:
2171cb0ef41Sopenharmony_ci          constraint->type_ = kSameAsInput;
2181cb0ef41Sopenharmony_ci          constraint->value_ = unallocated->input_index();
2191cb0ef41Sopenharmony_ci          break;
2201cb0ef41Sopenharmony_ci      }
2211cb0ef41Sopenharmony_ci    }
2221cb0ef41Sopenharmony_ci  }
2231cb0ef41Sopenharmony_ci}
2241cb0ef41Sopenharmony_ci
2251cb0ef41Sopenharmony_civoid RegisterAllocatorVerifier::CheckConstraint(
2261cb0ef41Sopenharmony_ci    const InstructionOperand* op, const OperandConstraint* constraint) {
2271cb0ef41Sopenharmony_ci  switch (constraint->type_) {
2281cb0ef41Sopenharmony_ci    case kConstant:
2291cb0ef41Sopenharmony_ci      CHECK_WITH_MSG(op->IsConstant(), caller_info_);
2301cb0ef41Sopenharmony_ci      CHECK_EQ(ConstantOperand::cast(op)->virtual_register(),
2311cb0ef41Sopenharmony_ci               constraint->value_);
2321cb0ef41Sopenharmony_ci      return;
2331cb0ef41Sopenharmony_ci    case kImmediate: {
2341cb0ef41Sopenharmony_ci      CHECK_WITH_MSG(op->IsImmediate(), caller_info_);
2351cb0ef41Sopenharmony_ci      const ImmediateOperand* imm = ImmediateOperand::cast(op);
2361cb0ef41Sopenharmony_ci      int value = GetValue(imm);
2371cb0ef41Sopenharmony_ci      CHECK_EQ(value, constraint->value_);
2381cb0ef41Sopenharmony_ci      return;
2391cb0ef41Sopenharmony_ci    }
2401cb0ef41Sopenharmony_ci    case kRegister:
2411cb0ef41Sopenharmony_ci      CHECK_WITH_MSG(op->IsRegister(), caller_info_);
2421cb0ef41Sopenharmony_ci      return;
2431cb0ef41Sopenharmony_ci    case kFPRegister:
2441cb0ef41Sopenharmony_ci      CHECK_WITH_MSG(op->IsFPRegister(), caller_info_);
2451cb0ef41Sopenharmony_ci      return;
2461cb0ef41Sopenharmony_ci    case kFixedRegister:
2471cb0ef41Sopenharmony_ci    case kRegisterAndSlot:
2481cb0ef41Sopenharmony_ci      CHECK_WITH_MSG(op->IsRegister(), caller_info_);
2491cb0ef41Sopenharmony_ci      CHECK_EQ(LocationOperand::cast(op)->register_code(), constraint->value_);
2501cb0ef41Sopenharmony_ci      return;
2511cb0ef41Sopenharmony_ci    case kFixedFPRegister:
2521cb0ef41Sopenharmony_ci      CHECK_WITH_MSG(op->IsFPRegister(), caller_info_);
2531cb0ef41Sopenharmony_ci      CHECK_EQ(LocationOperand::cast(op)->register_code(), constraint->value_);
2541cb0ef41Sopenharmony_ci      return;
2551cb0ef41Sopenharmony_ci    case kFixedSlot:
2561cb0ef41Sopenharmony_ci      CHECK_WITH_MSG(op->IsStackSlot() || op->IsFPStackSlot(), caller_info_);
2571cb0ef41Sopenharmony_ci      CHECK_EQ(LocationOperand::cast(op)->index(), constraint->value_);
2581cb0ef41Sopenharmony_ci      return;
2591cb0ef41Sopenharmony_ci    case kSlot:
2601cb0ef41Sopenharmony_ci      CHECK_WITH_MSG(op->IsStackSlot() || op->IsFPStackSlot(), caller_info_);
2611cb0ef41Sopenharmony_ci      CHECK_EQ(ElementSizeLog2Of(LocationOperand::cast(op)->representation()),
2621cb0ef41Sopenharmony_ci               constraint->value_);
2631cb0ef41Sopenharmony_ci      return;
2641cb0ef41Sopenharmony_ci    case kRegisterOrSlot:
2651cb0ef41Sopenharmony_ci      CHECK_WITH_MSG(op->IsRegister() || op->IsStackSlot(), caller_info_);
2661cb0ef41Sopenharmony_ci      return;
2671cb0ef41Sopenharmony_ci    case kRegisterOrSlotFP:
2681cb0ef41Sopenharmony_ci      CHECK_WITH_MSG(op->IsFPRegister() || op->IsFPStackSlot(), caller_info_);
2691cb0ef41Sopenharmony_ci      return;
2701cb0ef41Sopenharmony_ci    case kRegisterOrSlotOrConstant:
2711cb0ef41Sopenharmony_ci      CHECK_WITH_MSG(op->IsRegister() || op->IsStackSlot() || op->IsConstant(),
2721cb0ef41Sopenharmony_ci                     caller_info_);
2731cb0ef41Sopenharmony_ci      return;
2741cb0ef41Sopenharmony_ci    case kSameAsInput:
2751cb0ef41Sopenharmony_ci      CHECK_WITH_MSG(false, caller_info_);
2761cb0ef41Sopenharmony_ci      return;
2771cb0ef41Sopenharmony_ci  }
2781cb0ef41Sopenharmony_ci}
2791cb0ef41Sopenharmony_ci
2801cb0ef41Sopenharmony_civoid BlockAssessments::PerformMoves(const Instruction* instruction) {
2811cb0ef41Sopenharmony_ci  const ParallelMove* first =
2821cb0ef41Sopenharmony_ci      instruction->GetParallelMove(Instruction::GapPosition::START);
2831cb0ef41Sopenharmony_ci  PerformParallelMoves(first);
2841cb0ef41Sopenharmony_ci  const ParallelMove* last =
2851cb0ef41Sopenharmony_ci      instruction->GetParallelMove(Instruction::GapPosition::END);
2861cb0ef41Sopenharmony_ci  PerformParallelMoves(last);
2871cb0ef41Sopenharmony_ci}
2881cb0ef41Sopenharmony_ci
2891cb0ef41Sopenharmony_civoid BlockAssessments::PerformParallelMoves(const ParallelMove* moves) {
2901cb0ef41Sopenharmony_ci  if (moves == nullptr) return;
2911cb0ef41Sopenharmony_ci
2921cb0ef41Sopenharmony_ci  CHECK(map_for_moves_.empty());
2931cb0ef41Sopenharmony_ci  for (MoveOperands* move : *moves) {
2941cb0ef41Sopenharmony_ci    if (move->IsEliminated() || move->IsRedundant()) continue;
2951cb0ef41Sopenharmony_ci    auto it = map_.find(move->source());
2961cb0ef41Sopenharmony_ci    // The RHS of a parallel move should have been already assessed.
2971cb0ef41Sopenharmony_ci    CHECK(it != map_.end());
2981cb0ef41Sopenharmony_ci    // The LHS of a parallel move should not have been assigned in this
2991cb0ef41Sopenharmony_ci    // parallel move.
3001cb0ef41Sopenharmony_ci    CHECK(map_for_moves_.find(move->destination()) == map_for_moves_.end());
3011cb0ef41Sopenharmony_ci    // The RHS of a parallel move should not be a stale reference.
3021cb0ef41Sopenharmony_ci    CHECK(!IsStaleReferenceStackSlot(move->source()));
3031cb0ef41Sopenharmony_ci    // Copy the assessment to the destination.
3041cb0ef41Sopenharmony_ci    map_for_moves_[move->destination()] = it->second;
3051cb0ef41Sopenharmony_ci  }
3061cb0ef41Sopenharmony_ci  for (auto pair : map_for_moves_) {
3071cb0ef41Sopenharmony_ci    // Re-insert the existing key for the new assignment so that it has the
3081cb0ef41Sopenharmony_ci    // correct representation (which is ignored by the canonicalizing map
3091cb0ef41Sopenharmony_ci    // comparator).
3101cb0ef41Sopenharmony_ci    InstructionOperand op = pair.first;
3111cb0ef41Sopenharmony_ci    map_.erase(op);
3121cb0ef41Sopenharmony_ci    map_.insert(pair);
3131cb0ef41Sopenharmony_ci    // Destination is no longer a stale reference.
3141cb0ef41Sopenharmony_ci    stale_ref_stack_slots().erase(op);
3151cb0ef41Sopenharmony_ci  }
3161cb0ef41Sopenharmony_ci  map_for_moves_.clear();
3171cb0ef41Sopenharmony_ci}
3181cb0ef41Sopenharmony_ci
3191cb0ef41Sopenharmony_civoid BlockAssessments::DropRegisters() {
3201cb0ef41Sopenharmony_ci  for (auto iterator = map().begin(), end = map().end(); iterator != end;) {
3211cb0ef41Sopenharmony_ci    auto current = iterator;
3221cb0ef41Sopenharmony_ci    ++iterator;
3231cb0ef41Sopenharmony_ci    InstructionOperand op = current->first;
3241cb0ef41Sopenharmony_ci    if (op.IsAnyRegister()) map().erase(current);
3251cb0ef41Sopenharmony_ci  }
3261cb0ef41Sopenharmony_ci}
3271cb0ef41Sopenharmony_ci
3281cb0ef41Sopenharmony_civoid BlockAssessments::CheckReferenceMap(const ReferenceMap* reference_map) {
3291cb0ef41Sopenharmony_ci  // First mark all existing reference stack spill slots as stale.
3301cb0ef41Sopenharmony_ci  for (auto pair : map()) {
3311cb0ef41Sopenharmony_ci    InstructionOperand op = pair.first;
3321cb0ef41Sopenharmony_ci    if (op.IsStackSlot()) {
3331cb0ef41Sopenharmony_ci      const LocationOperand* loc_op = LocationOperand::cast(&op);
3341cb0ef41Sopenharmony_ci      // Only mark arguments that are spill slots as stale, the reference map
3351cb0ef41Sopenharmony_ci      // doesn't track arguments or fixed stack slots, which are implicitly
3361cb0ef41Sopenharmony_ci      // tracked by the GC.
3371cb0ef41Sopenharmony_ci      if (CanBeTaggedOrCompressedPointer(loc_op->representation()) &&
3381cb0ef41Sopenharmony_ci          loc_op->index() >= spill_slot_delta()) {
3391cb0ef41Sopenharmony_ci        stale_ref_stack_slots().insert(op);
3401cb0ef41Sopenharmony_ci      }
3411cb0ef41Sopenharmony_ci    }
3421cb0ef41Sopenharmony_ci  }
3431cb0ef41Sopenharmony_ci
3441cb0ef41Sopenharmony_ci  // Now remove any stack spill slots in the reference map from the list of
3451cb0ef41Sopenharmony_ci  // stale slots.
3461cb0ef41Sopenharmony_ci  for (auto ref_map_operand : reference_map->reference_operands()) {
3471cb0ef41Sopenharmony_ci    if (ref_map_operand.IsStackSlot()) {
3481cb0ef41Sopenharmony_ci      auto pair = map().find(ref_map_operand);
3491cb0ef41Sopenharmony_ci      CHECK(pair != map().end());
3501cb0ef41Sopenharmony_ci      stale_ref_stack_slots().erase(pair->first);
3511cb0ef41Sopenharmony_ci    }
3521cb0ef41Sopenharmony_ci  }
3531cb0ef41Sopenharmony_ci}
3541cb0ef41Sopenharmony_ci
3551cb0ef41Sopenharmony_cibool BlockAssessments::IsStaleReferenceStackSlot(InstructionOperand op) {
3561cb0ef41Sopenharmony_ci  if (!op.IsStackSlot()) return false;
3571cb0ef41Sopenharmony_ci
3581cb0ef41Sopenharmony_ci  const LocationOperand* loc_op = LocationOperand::cast(&op);
3591cb0ef41Sopenharmony_ci  return CanBeTaggedOrCompressedPointer(loc_op->representation()) &&
3601cb0ef41Sopenharmony_ci         stale_ref_stack_slots().find(op) != stale_ref_stack_slots().end();
3611cb0ef41Sopenharmony_ci}
3621cb0ef41Sopenharmony_ci
3631cb0ef41Sopenharmony_civoid BlockAssessments::Print() const {
3641cb0ef41Sopenharmony_ci  StdoutStream os;
3651cb0ef41Sopenharmony_ci  for (const auto& pair : map()) {
3661cb0ef41Sopenharmony_ci    const InstructionOperand op = pair.first;
3671cb0ef41Sopenharmony_ci    const Assessment* assessment = pair.second;
3681cb0ef41Sopenharmony_ci    // Use operator<< so we can write the assessment on the same
3691cb0ef41Sopenharmony_ci    // line.
3701cb0ef41Sopenharmony_ci    os << op << " : ";
3711cb0ef41Sopenharmony_ci    if (assessment->kind() == AssessmentKind::Final) {
3721cb0ef41Sopenharmony_ci      os << "v" << FinalAssessment::cast(assessment)->virtual_register();
3731cb0ef41Sopenharmony_ci    } else {
3741cb0ef41Sopenharmony_ci      os << "P";
3751cb0ef41Sopenharmony_ci    }
3761cb0ef41Sopenharmony_ci    if (stale_ref_stack_slots().find(op) != stale_ref_stack_slots().end()) {
3771cb0ef41Sopenharmony_ci      os << " (stale reference)";
3781cb0ef41Sopenharmony_ci    }
3791cb0ef41Sopenharmony_ci    os << std::endl;
3801cb0ef41Sopenharmony_ci  }
3811cb0ef41Sopenharmony_ci  os << std::endl;
3821cb0ef41Sopenharmony_ci}
3831cb0ef41Sopenharmony_ci
3841cb0ef41Sopenharmony_ciBlockAssessments* RegisterAllocatorVerifier::CreateForBlock(
3851cb0ef41Sopenharmony_ci    const InstructionBlock* block) {
3861cb0ef41Sopenharmony_ci  RpoNumber current_block_id = block->rpo_number();
3871cb0ef41Sopenharmony_ci
3881cb0ef41Sopenharmony_ci  BlockAssessments* ret =
3891cb0ef41Sopenharmony_ci      zone()->New<BlockAssessments>(zone(), spill_slot_delta());
3901cb0ef41Sopenharmony_ci  if (block->PredecessorCount() == 0) {
3911cb0ef41Sopenharmony_ci    // TODO(mtrofin): the following check should hold, however, in certain
3921cb0ef41Sopenharmony_ci    // unit tests it is invalidated by the last block. Investigate and
3931cb0ef41Sopenharmony_ci    // normalize the CFG.
3941cb0ef41Sopenharmony_ci    // CHECK_EQ(0, current_block_id.ToInt());
3951cb0ef41Sopenharmony_ci    // The phi size test below is because we can, technically, have phi
3961cb0ef41Sopenharmony_ci    // instructions with one argument. Some tests expose that, too.
3971cb0ef41Sopenharmony_ci  } else if (block->PredecessorCount() == 1 && block->phis().size() == 0) {
3981cb0ef41Sopenharmony_ci    const BlockAssessments* prev_block = assessments_[block->predecessors()[0]];
3991cb0ef41Sopenharmony_ci    ret->CopyFrom(prev_block);
4001cb0ef41Sopenharmony_ci  } else {
4011cb0ef41Sopenharmony_ci    for (RpoNumber pred_id : block->predecessors()) {
4021cb0ef41Sopenharmony_ci      // For every operand coming from any of the predecessors, create an
4031cb0ef41Sopenharmony_ci      // Unfinalized assessment.
4041cb0ef41Sopenharmony_ci      auto iterator = assessments_.find(pred_id);
4051cb0ef41Sopenharmony_ci      if (iterator == assessments_.end()) {
4061cb0ef41Sopenharmony_ci        // This block is the head of a loop, and this predecessor is the
4071cb0ef41Sopenharmony_ci        // loopback
4081cb0ef41Sopenharmony_ci        // arc.
4091cb0ef41Sopenharmony_ci        // Validate this is a loop case, otherwise the CFG is malformed.
4101cb0ef41Sopenharmony_ci        CHECK(pred_id >= current_block_id);
4111cb0ef41Sopenharmony_ci        CHECK(block->IsLoopHeader());
4121cb0ef41Sopenharmony_ci        continue;
4131cb0ef41Sopenharmony_ci      }
4141cb0ef41Sopenharmony_ci      const BlockAssessments* pred_assessments = iterator->second;
4151cb0ef41Sopenharmony_ci      CHECK_NOT_NULL(pred_assessments);
4161cb0ef41Sopenharmony_ci      for (auto pair : pred_assessments->map()) {
4171cb0ef41Sopenharmony_ci        InstructionOperand operand = pair.first;
4181cb0ef41Sopenharmony_ci        if (ret->map().find(operand) == ret->map().end()) {
4191cb0ef41Sopenharmony_ci          ret->map().insert(std::make_pair(
4201cb0ef41Sopenharmony_ci              operand, zone()->New<PendingAssessment>(zone(), block, operand)));
4211cb0ef41Sopenharmony_ci        }
4221cb0ef41Sopenharmony_ci      }
4231cb0ef41Sopenharmony_ci
4241cb0ef41Sopenharmony_ci      // Any references stack slots that became stale in predecessors will be
4251cb0ef41Sopenharmony_ci      // stale here.
4261cb0ef41Sopenharmony_ci      ret->stale_ref_stack_slots().insert(
4271cb0ef41Sopenharmony_ci          pred_assessments->stale_ref_stack_slots().begin(),
4281cb0ef41Sopenharmony_ci          pred_assessments->stale_ref_stack_slots().end());
4291cb0ef41Sopenharmony_ci    }
4301cb0ef41Sopenharmony_ci  }
4311cb0ef41Sopenharmony_ci  return ret;
4321cb0ef41Sopenharmony_ci}
4331cb0ef41Sopenharmony_ci
4341cb0ef41Sopenharmony_civoid RegisterAllocatorVerifier::ValidatePendingAssessment(
4351cb0ef41Sopenharmony_ci    RpoNumber block_id, InstructionOperand op,
4361cb0ef41Sopenharmony_ci    const BlockAssessments* current_assessments,
4371cb0ef41Sopenharmony_ci    PendingAssessment* const assessment, int virtual_register) {
4381cb0ef41Sopenharmony_ci  if (assessment->IsAliasOf(virtual_register)) return;
4391cb0ef41Sopenharmony_ci
4401cb0ef41Sopenharmony_ci  // When validating a pending assessment, it is possible some of the
4411cb0ef41Sopenharmony_ci  // assessments for the original operand (the one where the assessment was
4421cb0ef41Sopenharmony_ci  // created for first) are also pending. To avoid recursion, we use a work
4431cb0ef41Sopenharmony_ci  // list. To deal with cycles, we keep a set of seen nodes.
4441cb0ef41Sopenharmony_ci  Zone local_zone(zone()->allocator(), ZONE_NAME);
4451cb0ef41Sopenharmony_ci  ZoneQueue<std::pair<const PendingAssessment*, int>> worklist(&local_zone);
4461cb0ef41Sopenharmony_ci  ZoneSet<RpoNumber> seen(&local_zone);
4471cb0ef41Sopenharmony_ci  worklist.push(std::make_pair(assessment, virtual_register));
4481cb0ef41Sopenharmony_ci  seen.insert(block_id);
4491cb0ef41Sopenharmony_ci
4501cb0ef41Sopenharmony_ci  while (!worklist.empty()) {
4511cb0ef41Sopenharmony_ci    auto work = worklist.front();
4521cb0ef41Sopenharmony_ci    const PendingAssessment* current_assessment = work.first;
4531cb0ef41Sopenharmony_ci    int current_virtual_register = work.second;
4541cb0ef41Sopenharmony_ci    InstructionOperand current_operand = current_assessment->operand();
4551cb0ef41Sopenharmony_ci    worklist.pop();
4561cb0ef41Sopenharmony_ci
4571cb0ef41Sopenharmony_ci    const InstructionBlock* origin = current_assessment->origin();
4581cb0ef41Sopenharmony_ci    CHECK(origin->PredecessorCount() > 1 || origin->phis().size() > 0);
4591cb0ef41Sopenharmony_ci
4601cb0ef41Sopenharmony_ci    // Check if the virtual register is a phi first, instead of relying on
4611cb0ef41Sopenharmony_ci    // the incoming assessments. In particular, this handles the case
4621cb0ef41Sopenharmony_ci    // v1 = phi v0 v0, which structurally is identical to v0 having been
4631cb0ef41Sopenharmony_ci    // defined at the top of a diamond, and arriving at the node joining the
4641cb0ef41Sopenharmony_ci    // diamond's branches.
4651cb0ef41Sopenharmony_ci    const PhiInstruction* phi = nullptr;
4661cb0ef41Sopenharmony_ci    for (const PhiInstruction* candidate : origin->phis()) {
4671cb0ef41Sopenharmony_ci      if (candidate->virtual_register() == current_virtual_register) {
4681cb0ef41Sopenharmony_ci        phi = candidate;
4691cb0ef41Sopenharmony_ci        break;
4701cb0ef41Sopenharmony_ci      }
4711cb0ef41Sopenharmony_ci    }
4721cb0ef41Sopenharmony_ci
4731cb0ef41Sopenharmony_ci    int op_index = 0;
4741cb0ef41Sopenharmony_ci    for (RpoNumber pred : origin->predecessors()) {
4751cb0ef41Sopenharmony_ci      int expected =
4761cb0ef41Sopenharmony_ci          phi != nullptr ? phi->operands()[op_index] : current_virtual_register;
4771cb0ef41Sopenharmony_ci
4781cb0ef41Sopenharmony_ci      ++op_index;
4791cb0ef41Sopenharmony_ci      auto pred_assignment = assessments_.find(pred);
4801cb0ef41Sopenharmony_ci      if (pred_assignment == assessments_.end()) {
4811cb0ef41Sopenharmony_ci        CHECK(origin->IsLoopHeader());
4821cb0ef41Sopenharmony_ci        auto todo_iter = outstanding_assessments_.find(pred);
4831cb0ef41Sopenharmony_ci        DelayedAssessments* set = nullptr;
4841cb0ef41Sopenharmony_ci        if (todo_iter == outstanding_assessments_.end()) {
4851cb0ef41Sopenharmony_ci          set = zone()->New<DelayedAssessments>(zone());
4861cb0ef41Sopenharmony_ci          outstanding_assessments_.insert(std::make_pair(pred, set));
4871cb0ef41Sopenharmony_ci        } else {
4881cb0ef41Sopenharmony_ci          set = todo_iter->second;
4891cb0ef41Sopenharmony_ci        }
4901cb0ef41Sopenharmony_ci        set->AddDelayedAssessment(current_operand, expected);
4911cb0ef41Sopenharmony_ci        continue;
4921cb0ef41Sopenharmony_ci      }
4931cb0ef41Sopenharmony_ci
4941cb0ef41Sopenharmony_ci      const BlockAssessments* pred_assessments = pred_assignment->second;
4951cb0ef41Sopenharmony_ci      auto found_contribution = pred_assessments->map().find(current_operand);
4961cb0ef41Sopenharmony_ci      CHECK(found_contribution != pred_assessments->map().end());
4971cb0ef41Sopenharmony_ci      Assessment* contribution = found_contribution->second;
4981cb0ef41Sopenharmony_ci
4991cb0ef41Sopenharmony_ci      switch (contribution->kind()) {
5001cb0ef41Sopenharmony_ci        case Final:
5011cb0ef41Sopenharmony_ci          CHECK_EQ(FinalAssessment::cast(contribution)->virtual_register(),
5021cb0ef41Sopenharmony_ci                   expected);
5031cb0ef41Sopenharmony_ci          break;
5041cb0ef41Sopenharmony_ci        case Pending: {
5051cb0ef41Sopenharmony_ci          // This happens if we have a diamond feeding into another one, and
5061cb0ef41Sopenharmony_ci          // the inner one never being used - other than for carrying the value.
5071cb0ef41Sopenharmony_ci          const PendingAssessment* next = PendingAssessment::cast(contribution);
5081cb0ef41Sopenharmony_ci          if (seen.find(pred) == seen.end()) {
5091cb0ef41Sopenharmony_ci            worklist.push({next, expected});
5101cb0ef41Sopenharmony_ci            seen.insert(pred);
5111cb0ef41Sopenharmony_ci          }
5121cb0ef41Sopenharmony_ci          // Note that we do not want to finalize pending assessments at the
5131cb0ef41Sopenharmony_ci          // beginning of a block - which is the information we'd have
5141cb0ef41Sopenharmony_ci          // available here. This is because this operand may be reused to
5151cb0ef41Sopenharmony_ci          // define duplicate phis.
5161cb0ef41Sopenharmony_ci          break;
5171cb0ef41Sopenharmony_ci        }
5181cb0ef41Sopenharmony_ci      }
5191cb0ef41Sopenharmony_ci    }
5201cb0ef41Sopenharmony_ci  }
5211cb0ef41Sopenharmony_ci  assessment->AddAlias(virtual_register);
5221cb0ef41Sopenharmony_ci}
5231cb0ef41Sopenharmony_ci
5241cb0ef41Sopenharmony_civoid RegisterAllocatorVerifier::ValidateUse(
5251cb0ef41Sopenharmony_ci    RpoNumber block_id, BlockAssessments* current_assessments,
5261cb0ef41Sopenharmony_ci    InstructionOperand op, int virtual_register) {
5271cb0ef41Sopenharmony_ci  auto iterator = current_assessments->map().find(op);
5281cb0ef41Sopenharmony_ci  // We should have seen this operand before.
5291cb0ef41Sopenharmony_ci  CHECK(iterator != current_assessments->map().end());
5301cb0ef41Sopenharmony_ci  Assessment* assessment = iterator->second;
5311cb0ef41Sopenharmony_ci
5321cb0ef41Sopenharmony_ci  // The operand shouldn't be a stale reference stack slot.
5331cb0ef41Sopenharmony_ci  CHECK(!current_assessments->IsStaleReferenceStackSlot(op));
5341cb0ef41Sopenharmony_ci
5351cb0ef41Sopenharmony_ci  switch (assessment->kind()) {
5361cb0ef41Sopenharmony_ci    case Final:
5371cb0ef41Sopenharmony_ci      CHECK_EQ(FinalAssessment::cast(assessment)->virtual_register(),
5381cb0ef41Sopenharmony_ci               virtual_register);
5391cb0ef41Sopenharmony_ci      break;
5401cb0ef41Sopenharmony_ci    case Pending: {
5411cb0ef41Sopenharmony_ci      PendingAssessment* pending = PendingAssessment::cast(assessment);
5421cb0ef41Sopenharmony_ci      ValidatePendingAssessment(block_id, op, current_assessments, pending,
5431cb0ef41Sopenharmony_ci                                virtual_register);
5441cb0ef41Sopenharmony_ci      break;
5451cb0ef41Sopenharmony_ci    }
5461cb0ef41Sopenharmony_ci  }
5471cb0ef41Sopenharmony_ci}
5481cb0ef41Sopenharmony_ci
5491cb0ef41Sopenharmony_civoid RegisterAllocatorVerifier::VerifyGapMoves() {
5501cb0ef41Sopenharmony_ci  CHECK(assessments_.empty());
5511cb0ef41Sopenharmony_ci  CHECK(outstanding_assessments_.empty());
5521cb0ef41Sopenharmony_ci  const size_t block_count = sequence()->instruction_blocks().size();
5531cb0ef41Sopenharmony_ci  for (size_t block_index = 0; block_index < block_count; ++block_index) {
5541cb0ef41Sopenharmony_ci    const InstructionBlock* block =
5551cb0ef41Sopenharmony_ci        sequence()->instruction_blocks()[block_index];
5561cb0ef41Sopenharmony_ci    BlockAssessments* block_assessments = CreateForBlock(block);
5571cb0ef41Sopenharmony_ci
5581cb0ef41Sopenharmony_ci    for (int instr_index = block->code_start(); instr_index < block->code_end();
5591cb0ef41Sopenharmony_ci         ++instr_index) {
5601cb0ef41Sopenharmony_ci      const InstructionConstraint& instr_constraint = constraints_[instr_index];
5611cb0ef41Sopenharmony_ci      const Instruction* instr = instr_constraint.instruction_;
5621cb0ef41Sopenharmony_ci      block_assessments->PerformMoves(instr);
5631cb0ef41Sopenharmony_ci
5641cb0ef41Sopenharmony_ci      const OperandConstraint* op_constraints =
5651cb0ef41Sopenharmony_ci          instr_constraint.operand_constraints_;
5661cb0ef41Sopenharmony_ci      size_t count = 0;
5671cb0ef41Sopenharmony_ci      for (size_t i = 0; i < instr->InputCount(); ++i, ++count) {
5681cb0ef41Sopenharmony_ci        if (op_constraints[count].type_ == kImmediate) {
5691cb0ef41Sopenharmony_ci          continue;
5701cb0ef41Sopenharmony_ci        }
5711cb0ef41Sopenharmony_ci        int virtual_register = op_constraints[count].virtual_register_;
5721cb0ef41Sopenharmony_ci        InstructionOperand op = *instr->InputAt(i);
5731cb0ef41Sopenharmony_ci        ValidateUse(block->rpo_number(), block_assessments, op,
5741cb0ef41Sopenharmony_ci                    virtual_register);
5751cb0ef41Sopenharmony_ci      }
5761cb0ef41Sopenharmony_ci      for (size_t i = 0; i < instr->TempCount(); ++i, ++count) {
5771cb0ef41Sopenharmony_ci        block_assessments->Drop(*instr->TempAt(i));
5781cb0ef41Sopenharmony_ci      }
5791cb0ef41Sopenharmony_ci      if (instr->IsCall()) {
5801cb0ef41Sopenharmony_ci        block_assessments->DropRegisters();
5811cb0ef41Sopenharmony_ci      }
5821cb0ef41Sopenharmony_ci      if (instr->HasReferenceMap()) {
5831cb0ef41Sopenharmony_ci        block_assessments->CheckReferenceMap(instr->reference_map());
5841cb0ef41Sopenharmony_ci      }
5851cb0ef41Sopenharmony_ci      for (size_t i = 0; i < instr->OutputCount(); ++i, ++count) {
5861cb0ef41Sopenharmony_ci        int virtual_register = op_constraints[count].virtual_register_;
5871cb0ef41Sopenharmony_ci        block_assessments->AddDefinition(*instr->OutputAt(i), virtual_register);
5881cb0ef41Sopenharmony_ci        if (op_constraints[count].type_ == kRegisterAndSlot) {
5891cb0ef41Sopenharmony_ci          const AllocatedOperand* reg_op =
5901cb0ef41Sopenharmony_ci              AllocatedOperand::cast(instr->OutputAt(i));
5911cb0ef41Sopenharmony_ci          MachineRepresentation rep = reg_op->representation();
5921cb0ef41Sopenharmony_ci          const AllocatedOperand* stack_op = AllocatedOperand::New(
5931cb0ef41Sopenharmony_ci              zone(), LocationOperand::LocationKind::STACK_SLOT, rep,
5941cb0ef41Sopenharmony_ci              op_constraints[i].spilled_slot_);
5951cb0ef41Sopenharmony_ci          block_assessments->AddDefinition(*stack_op, virtual_register);
5961cb0ef41Sopenharmony_ci        }
5971cb0ef41Sopenharmony_ci      }
5981cb0ef41Sopenharmony_ci    }
5991cb0ef41Sopenharmony_ci    // Now commit the assessments for this block. If there are any delayed
6001cb0ef41Sopenharmony_ci    // assessments, ValidatePendingAssessment should see this block, too.
6011cb0ef41Sopenharmony_ci    assessments_[block->rpo_number()] = block_assessments;
6021cb0ef41Sopenharmony_ci
6031cb0ef41Sopenharmony_ci    auto todo_iter = outstanding_assessments_.find(block->rpo_number());
6041cb0ef41Sopenharmony_ci    if (todo_iter == outstanding_assessments_.end()) continue;
6051cb0ef41Sopenharmony_ci    DelayedAssessments* todo = todo_iter->second;
6061cb0ef41Sopenharmony_ci    for (auto pair : todo->map()) {
6071cb0ef41Sopenharmony_ci      InstructionOperand op = pair.first;
6081cb0ef41Sopenharmony_ci      int vreg = pair.second;
6091cb0ef41Sopenharmony_ci      auto found_op = block_assessments->map().find(op);
6101cb0ef41Sopenharmony_ci      CHECK(found_op != block_assessments->map().end());
6111cb0ef41Sopenharmony_ci      // This block is a jump back to the loop header, ensure that the op hasn't
6121cb0ef41Sopenharmony_ci      // become a stale reference during the blocks in the loop.
6131cb0ef41Sopenharmony_ci      CHECK(!block_assessments->IsStaleReferenceStackSlot(op));
6141cb0ef41Sopenharmony_ci      switch (found_op->second->kind()) {
6151cb0ef41Sopenharmony_ci        case Final:
6161cb0ef41Sopenharmony_ci          CHECK_EQ(FinalAssessment::cast(found_op->second)->virtual_register(),
6171cb0ef41Sopenharmony_ci                   vreg);
6181cb0ef41Sopenharmony_ci          break;
6191cb0ef41Sopenharmony_ci        case Pending:
6201cb0ef41Sopenharmony_ci          ValidatePendingAssessment(block->rpo_number(), op, block_assessments,
6211cb0ef41Sopenharmony_ci                                    PendingAssessment::cast(found_op->second),
6221cb0ef41Sopenharmony_ci                                    vreg);
6231cb0ef41Sopenharmony_ci          break;
6241cb0ef41Sopenharmony_ci      }
6251cb0ef41Sopenharmony_ci    }
6261cb0ef41Sopenharmony_ci  }
6271cb0ef41Sopenharmony_ci}
6281cb0ef41Sopenharmony_ci
6291cb0ef41Sopenharmony_ci}  // namespace compiler
6301cb0ef41Sopenharmony_ci}  // namespace internal
6311cb0ef41Sopenharmony_ci}  // namespace v8
632