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