19size_t OperandCount(
const Instruction*
instr) {
23void VerifyEmptyGaps(
const Instruction*
instr) {
32void VerifyAllocatedGaps(
const Instruction*
instr,
const char* caller_info) {
38 if (moves ==
nullptr)
continue;
39 for (
const MoveOperands* move : *moves) {
40 if (move->IsRedundant())
continue;
42 move->source().IsAllocated() || move->source().IsConstant(),
49int GetValue(
const ImmediateOperand* imm) {
50 switch (imm->type()) {
52 return imm->inline_int32_value();
54 return static_cast<int>(imm->inline_int64_value());
57 return imm->indexed_value();
71 outstanding_assessments_(zone),
72 spill_slot_delta_(frame->GetTotalFrameSlotCount() -
73 frame->GetSpillSlotCount()) {
80 VerifyEmptyGaps(instr);
81 const size_t operand_count = OperandCount(instr);
82 OperandConstraint* op_constraints =
83 zone->AllocateArray<OperandConstraint>(operand_count);
85 for (size_t i = 0; i < instr->InputCount(); ++i, ++count) {
86 BuildConstraint(instr->InputAt(i), &op_constraints[count]);
87 VerifyInput(op_constraints[count]);
96 int input_index = op_constraints[
count].value_;
98 op_constraints[
count].type_ = op_constraints[input_index].type_;
99 op_constraints[
count].value_ = op_constraints[input_index].value_;
109void RegisterAllocatorVerifier::VerifyInput(
112 if (constraint.
type_ != kImmediate) {
113 CHECK_NE(InstructionOperand::kInvalidVirtualRegister,
118void RegisterAllocatorVerifier::VerifyTemp(
125void RegisterAllocatorVerifier::VerifyOutput(
128 CHECK_NE(InstructionOperand::kInvalidVirtualRegister,
132void RegisterAllocatorVerifier::VerifyAssignment(
const char* caller_info) {
133 caller_info_ = caller_info;
134 CHECK(sequence()->instructions().
size() == constraints()->
size());
135 auto instr_it = sequence()->begin();
136 for (
const auto& instr_constraint : *constraints()) {
139 VerifyAllocatedGaps(
instr, caller_info_);
140 const size_t operand_count = instr_constraint.operand_constaints_size_;
142 instr_constraint.operand_constraints_;
147 CheckConstraint(
instr->InputAt(
i), &op_constraints[
count]);
150 CheckConstraint(
instr->TempAt(
i), &op_constraints[
count]);
153 CheckConstraint(
instr->OutputAt(
i), &op_constraints[
count]);
163 if (op->IsConstant()) {
165 constraint->
value_ = ConstantOperand::cast(op)->virtual_register();
167 }
else if (op->IsImmediate()) {
169 constraint->
type_ = kImmediate;
170 constraint->
value_ = GetValue(imm);
172 CHECK(op->IsUnallocated());
176 if (unallocated->
basic_policy() == UnallocatedOperand::FIXED_SLOT) {
177 constraint->
type_ = kFixedSlot;
181 case UnallocatedOperand::REGISTER_OR_SLOT:
182 case UnallocatedOperand::NONE:
183 if (sequence()->IsFP(vreg)) {
184 constraint->
type_ = kRegisterOrSlotFP;
189 case UnallocatedOperand::REGISTER_OR_SLOT_OR_CONSTANT:
190 DCHECK(!sequence()->IsFP(vreg));
193 case UnallocatedOperand::FIXED_REGISTER:
195 constraint->
type_ = kRegisterAndSlot;
198 constraint->
type_ = kFixedRegister;
202 case UnallocatedOperand::FIXED_FP_REGISTER:
203 constraint->
type_ = kFixedFPRegister;
206 case UnallocatedOperand::MUST_HAVE_REGISTER:
207 if (sequence()->IsFP(vreg)) {
208 constraint->
type_ = kFPRegister;
213 case UnallocatedOperand::MUST_HAVE_SLOT:
214 constraint->
type_ = kSlot;
218 case UnallocatedOperand::SAME_AS_INPUT:
219 constraint->
type_ = kSameAsInput;
227void RegisterAllocatorVerifier::CheckConstraint(
229 switch (constraint->
type_) {
232 CHECK_EQ(ConstantOperand::cast(op)->virtual_register(),
238 int value = GetValue(imm);
249 case kRegisterAndSlot:
251 CHECK_EQ(LocationOperand::cast(op)->register_code(), constraint->
value_);
253 case kFixedFPRegister:
255 CHECK_EQ(LocationOperand::cast(op)->register_code(), constraint->
value_);
269 case kRegisterOrSlotFP:
282void BlockAssessments::PerformMoves(
const Instruction* instruction) {
284 instruction->GetParallelMove(Instruction::GapPosition::START);
285 PerformParallelMoves(first);
287 instruction->GetParallelMove(Instruction::GapPosition::END);
288 PerformParallelMoves(last);
291void BlockAssessments::PerformParallelMoves(
const ParallelMove* moves) {
292 if (moves ==
nullptr)
return;
294 CHECK(map_for_moves_.empty());
296 if (move->IsEliminated() || move->IsRedundant())
continue;
297 auto it =
map_.find(move->source());
302 CHECK(map_for_moves_.find(move->destination()) == map_for_moves_.end());
304 CHECK(!IsStaleReferenceStackSlot(move->source()));
306 map_for_moves_[move->destination()] = it->second;
308 for (
auto pair : map_for_moves_) {
316 stale_ref_stack_slots().erase(op);
318 map_for_moves_.clear();
321void BlockAssessments::DropRegisters() {
323 auto current = iterator;
330void BlockAssessments::CheckReferenceMap(
const ReferenceMap* reference_map) {
332 for (
auto pair :
map()) {
340 loc_op->
index() >= spill_slot_delta()) {
341 stale_ref_stack_slots().insert(op);
349 if (ref_map_operand.IsStackSlot()) {
350 auto pair =
map().find(ref_map_operand);
352 stale_ref_stack_slots().erase(pair->first);
358 std::optional<int> vreg) {
360 if (vreg.has_value() && !sequence_->IsReference(*vreg))
return false;
364 stale_ref_stack_slots().find(op) != stale_ref_stack_slots().end();
367void BlockAssessments::Print()
const {
369 for (
const auto& pair :
map()) {
375 if (assessment->
kind() == AssessmentKind::Final) {
376 os <<
"v" << FinalAssessment::cast(assessment)->virtual_register();
380 if (stale_ref_stack_slots().find(op) != stale_ref_stack_slots().
end()) {
381 os <<
" (stale reference)";
390 RpoNumber current_block_id = block->rpo_number();
394 if (block->PredecessorCount() == 0) {
401 }
else if (block->PredecessorCount() == 1 && block->phis().empty()) {
402 const BlockAssessments* prev_block = assessments_[block->predecessors()[0]];
405 for (
RpoNumber pred_id : block->predecessors()) {
408 auto iterator = assessments_.find(pred_id);
409 if (iterator == assessments_.end()) {
414 CHECK(pred_id >= current_block_id);
415 CHECK(block->IsLoopHeader());
420 for (
auto pair : pred_assessments->
map()) {
422 if (ret->
map().find(operand) == ret->
map().end()) {
423 ret->
map().insert(std::make_pair(
424 operand, zone()->New<PendingAssessment>(zone(), block, operand)));
438void RegisterAllocatorVerifier::ValidatePendingAssessment(
442 if (assessment->
IsAliasOf(virtual_register))
return;
451 worklist.push(std::make_pair(assessment, virtual_register));
452 seen.insert(block_id);
454 while (!worklist.empty()) {
455 auto work = worklist.front();
457 int current_virtual_register = work.second;
471 if (candidate->virtual_register() == current_virtual_register) {
480 phi !=
nullptr ? phi->operands()[op_index] : current_virtual_register;
483 auto pred_assignment = assessments_.find(pred);
484 if (pred_assignment == assessments_.end()) {
486 auto [todo_iter, inserted] = outstanding_assessments_.try_emplace(pred);
496 auto found_contribution = pred_assessments->
map().find(current_operand);
497 CHECK(found_contribution != pred_assessments->
map().end());
498 Assessment* contribution = found_contribution->second;
500 switch (contribution->
kind()) {
502 CHECK_EQ(FinalAssessment::cast(contribution)->virtual_register(),
509 auto [it, inserted] = seen.insert(pred);
511 worklist.push({next, expected});
522 assessment->
AddAlias(virtual_register);
525void RegisterAllocatorVerifier::ValidateUse(
528 auto iterator = current_assessments->
map().find(op);
530 CHECK(iterator != current_assessments->
map().end());
536 switch (assessment->
kind()) {
538 CHECK_EQ(FinalAssessment::cast(assessment)->virtual_register(),
543 ValidatePendingAssessment(block_id, op, current_assessments, pending,
550void RegisterAllocatorVerifier::VerifyGapMoves() {
551 CHECK(assessments_.empty());
552 CHECK(outstanding_assessments_.empty());
553 const size_t block_count = sequence()->instruction_blocks().size();
554 for (
size_t block_index = 0; block_index < block_count; ++block_index) {
556 sequence()->instruction_blocks()[block_index];
559 for (
int instr_index = block->code_start(); instr_index < block->code_end();
569 if (op_constraints[
count].
type_ == kImmediate) {
574 ValidateUse(block->rpo_number(), block_assessments, op,
580 if (
instr->IsCall()) {
583 if (
instr->HasReferenceMap()) {
589 if (op_constraints[
count].
type_ == kRegisterAndSlot) {
591 AllocatedOperand::cast(
instr->OutputAt(
i));
594 zone(), LocationOperand::LocationKind::STACK_SLOT, rep,
595 op_constraints[
i].spilled_slot_);
596 block_assessments->
AddDefinition(*stack_op, virtual_register);
602 assessments_[block->rpo_number()] = block_assessments;
604 auto todo_iter = outstanding_assessments_.find(block->rpo_number());
605 if (todo_iter == outstanding_assessments_.end())
continue;
607 for (
auto pair : todo->
map()) {
609 int vreg = pair.second;
610 auto found_op = block_assessments->
map().find(op);
611 CHECK(found_op != block_assessments->
map().end());
615 switch (found_op->second->kind()) {
617 CHECK_EQ(FinalAssessment::cast(found_op->second)->virtual_register(),
621 ValidatePendingAssessment(block->rpo_number(), op, block_assessments,
622 PendingAssessment::cast(found_op->second),
void reserve(size_t new_cap)
void push_back(const T &value)
AssessmentKind kind() const
void CheckReferenceMap(const ReferenceMap *reference_map)
bool IsStaleReferenceStackSlot(InstructionOperand op, std::optional< int > vreg=std::nullopt)
void CopyFrom(const BlockAssessments *other)
void PerformMoves(const Instruction *instruction)
void AddDefinition(InstructionOperand operand, int virtual_register)
OperandSet & stale_ref_stack_slots()
void Drop(InstructionOperand operand)
bool IsLoopHeader() const
Predecessors & predecessors()
size_t PredecessorCount() const
const PhiInstructions & phis() const
bool IsFPRegister() const
bool IsFPStackSlot() const
bool IsAnyRegister() const
size_t OutputCount() const
size_t InputCount() const
ParallelMove * GetParallelMove(GapPosition pos)
MachineRepresentation representation() const
const InstructionBlock * origin() const
InstructionOperand operand() const
bool IsAliasOf(int vreg) const
const ZoneVector< InstructionOperand > & reference_operands() const
void AddDelayedAssessment(InstructionOperand op, int vreg)
const ZoneMap< InstructionOperand, int, OperandAsKeyLess > & map() const
static void VerifyOutput(const OperandConstraint &constraint)
RegisterAllocatorVerifier(Zone *zone, const RegisterConfiguration *config, const InstructionSequence *sequence, const Frame *frame)
static void VerifyTemp(const OperandConstraint &constraint)
void BuildConstraint(const InstructionOperand *op, OperandConstraint *constraint)
Constraints * constraints()
int32_t virtual_register() const
bool HasSecondaryStorage() const
int GetSecondaryStorage() const
BasicPolicy basic_policy() const
ExtendedPolicy extended_policy() const
int fixed_register_index() const
int fixed_slot_index() const
@ kRegisterOrSlotOrConstant
Node::Uses::const_iterator begin(const Node::Uses &uses)
constexpr bool CanBeTaggedOrCompressedPointer(MachineRepresentation rep)
V8_EXPORT_PRIVATE constexpr int ElementSizeLog2Of(MachineRepresentation)
#define CHECK_LT(lhs, rhs)
#define CHECK_WITH_MSG(condition, message)
#define CHECK_NOT_NULL(val)
#define CHECK_NE(lhs, rhs)
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
OperandConstraint * operand_constraints_
const Instruction * instruction_