5 #include "src/compiler/backend/register-allocator-verifier.h" 7 #include "src/bit-vector.h" 8 #include "src/compiler/backend/instruction.h" 9 #include "src/ostreams.h" 17 size_t OperandCount(
const Instruction* instr) {
18 return instr->InputCount() + instr->OutputCount() + instr->TempCount();
21 void VerifyEmptyGaps(
const Instruction* instr) {
22 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 CHECK_NULL(instr->GetParallelMove(inner_pos));
30 void VerifyAllocatedGaps(
const Instruction* instr,
const char* caller_info) {
31 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 if (moves ==
nullptr)
continue;
37 for (
const MoveOperands* move : *moves) {
38 if (move->IsRedundant())
continue;
40 move->source().IsAllocated() || move->source().IsConstant(),
42 CHECK_WITH_MSG(move->destination().IsAllocated(), caller_info);
49 RegisterAllocatorVerifier::RegisterAllocatorVerifier(
50 Zone* zone,
const RegisterConfiguration* config,
51 const InstructionSequence* sequence)
57 outstanding_assessments_(zone) {
58 constraints_.reserve(sequence->instructions().size());
62 for (
const Instruction* instr : sequence->instructions()) {
64 VerifyEmptyGaps(instr);
65 const size_t operand_count = OperandCount(instr);
66 OperandConstraint* op_constraints =
67 zone->NewArray<OperandConstraint>(operand_count);
69 for (
size_t i = 0;
i < instr->InputCount(); ++
i, ++count) {
70 BuildConstraint(instr->InputAt(
i), &op_constraints[count]);
71 VerifyInput(op_constraints[count]);
73 for (
size_t i = 0;
i < instr->TempCount(); ++
i, ++count) {
74 BuildConstraint(instr->TempAt(
i), &op_constraints[count]);
75 VerifyTemp(op_constraints[count]);
77 for (
size_t i = 0;
i < instr->OutputCount(); ++
i, ++count) {
78 BuildConstraint(instr->OutputAt(
i), &op_constraints[count]);
79 if (op_constraints[count].type_ == kSameAsFirst) {
80 CHECK_LT(0, instr->InputCount());
81 op_constraints[count].type_ = op_constraints[0].type_;
82 op_constraints[count].value_ = op_constraints[0].value_;
84 VerifyOutput(op_constraints[count]);
86 InstructionConstraint instr_constraint = {instr, operand_count,
88 constraints()->push_back(instr_constraint);
92 void RegisterAllocatorVerifier::VerifyInput(
93 const OperandConstraint& constraint) {
94 CHECK_NE(kSameAsFirst, constraint.type_);
95 if (constraint.type_ != kImmediate && constraint.type_ != kExplicit) {
96 CHECK_NE(InstructionOperand::kInvalidVirtualRegister,
97 constraint.virtual_register_);
101 void RegisterAllocatorVerifier::VerifyTemp(
102 const OperandConstraint& constraint) {
103 CHECK_NE(kSameAsFirst, constraint.type_);
104 CHECK_NE(kImmediate, constraint.type_);
105 CHECK_NE(kExplicit, constraint.type_);
106 CHECK_NE(kConstant, constraint.type_);
109 void RegisterAllocatorVerifier::VerifyOutput(
110 const OperandConstraint& constraint) {
111 CHECK_NE(kImmediate, constraint.type_);
112 CHECK_NE(kExplicit, constraint.type_);
113 CHECK_NE(InstructionOperand::kInvalidVirtualRegister,
114 constraint.virtual_register_);
117 void RegisterAllocatorVerifier::VerifyAssignment(
const char* caller_info) {
118 caller_info_ = caller_info;
119 CHECK(sequence()->instructions().size() == constraints()->size());
120 auto instr_it = sequence()->begin();
121 for (
const auto& instr_constraint : *constraints()) {
122 const Instruction* instr = instr_constraint.instruction_;
124 VerifyAllocatedGaps(instr, caller_info_);
125 const size_t operand_count = instr_constraint.operand_constaints_size_;
126 const OperandConstraint* op_constraints =
127 instr_constraint.operand_constraints_;
128 CHECK_EQ(instr, *instr_it);
129 CHECK(operand_count == OperandCount(instr));
131 for (
size_t i = 0;
i < instr->InputCount(); ++
i, ++count) {
132 CheckConstraint(instr->InputAt(
i), &op_constraints[count]);
134 for (
size_t i = 0;
i < instr->TempCount(); ++
i, ++count) {
135 CheckConstraint(instr->TempAt(
i), &op_constraints[count]);
137 for (
size_t i = 0;
i < instr->OutputCount(); ++
i, ++count) {
138 CheckConstraint(instr->OutputAt(
i), &op_constraints[count]);
144 void RegisterAllocatorVerifier::BuildConstraint(
const InstructionOperand* op,
145 OperandConstraint* constraint) {
146 constraint->value_ = kMinInt;
147 constraint->virtual_register_ = InstructionOperand::kInvalidVirtualRegister;
148 if (op->IsConstant()) {
149 constraint->type_ = kConstant;
150 constraint->value_ = ConstantOperand::cast(op)->virtual_register();
151 constraint->virtual_register_ = constraint->value_;
152 }
else if (op->IsExplicit()) {
153 constraint->type_ = kExplicit;
154 }
else if (op->IsImmediate()) {
155 const ImmediateOperand* imm = ImmediateOperand::cast(op);
156 int value = imm->type() == ImmediateOperand::INLINE ? imm->inline_value()
157 : imm->indexed_value();
158 constraint->type_ = kImmediate;
159 constraint->value_ = value;
161 CHECK(op->IsUnallocated());
162 const UnallocatedOperand* unallocated = UnallocatedOperand::cast(op);
163 int vreg = unallocated->virtual_register();
164 constraint->virtual_register_ = vreg;
165 if (unallocated->basic_policy() == UnallocatedOperand::FIXED_SLOT) {
166 constraint->type_ = kFixedSlot;
167 constraint->value_ = unallocated->fixed_slot_index();
169 switch (unallocated->extended_policy()) {
170 case UnallocatedOperand::REGISTER_OR_SLOT:
171 case UnallocatedOperand::NONE:
172 if (sequence()->IsFP(vreg)) {
173 constraint->type_ = kRegisterOrSlotFP;
175 constraint->type_ = kRegisterOrSlot;
178 case UnallocatedOperand::REGISTER_OR_SLOT_OR_CONSTANT:
179 DCHECK(!sequence()->IsFP(vreg));
180 constraint->type_ = kRegisterOrSlotOrConstant;
182 case UnallocatedOperand::FIXED_REGISTER:
183 if (unallocated->HasSecondaryStorage()) {
184 constraint->type_ = kRegisterAndSlot;
185 constraint->spilled_slot_ = unallocated->GetSecondaryStorage();
187 constraint->type_ = kFixedRegister;
189 constraint->value_ = unallocated->fixed_register_index();
191 case UnallocatedOperand::FIXED_FP_REGISTER:
192 constraint->type_ = kFixedFPRegister;
193 constraint->value_ = unallocated->fixed_register_index();
195 case UnallocatedOperand::MUST_HAVE_REGISTER:
196 if (sequence()->IsFP(vreg)) {
197 constraint->type_ = kFPRegister;
199 constraint->type_ = kRegister;
202 case UnallocatedOperand::MUST_HAVE_SLOT:
203 constraint->type_ = kSlot;
205 ElementSizeLog2Of(sequence()->GetRepresentation(vreg));
207 case UnallocatedOperand::SAME_AS_FIRST_INPUT:
208 constraint->type_ = kSameAsFirst;
215 void RegisterAllocatorVerifier::CheckConstraint(
216 const InstructionOperand* op,
const OperandConstraint* constraint) {
217 switch (constraint->type_) {
219 CHECK_WITH_MSG(op->IsConstant(), caller_info_);
220 CHECK_EQ(ConstantOperand::cast(op)->virtual_register(),
224 CHECK_WITH_MSG(op->IsImmediate(), caller_info_);
225 const ImmediateOperand* imm = ImmediateOperand::cast(op);
226 int value = imm->type() == ImmediateOperand::INLINE
227 ? imm->inline_value()
228 : imm->indexed_value();
229 CHECK_EQ(value, constraint->value_);
233 CHECK_WITH_MSG(op->IsRegister(), caller_info_);
236 CHECK_WITH_MSG(op->IsFPRegister(), caller_info_);
239 CHECK_WITH_MSG(op->IsExplicit(), caller_info_);
242 case kRegisterAndSlot:
243 CHECK_WITH_MSG(op->IsRegister(), caller_info_);
244 CHECK_EQ(LocationOperand::cast(op)->register_code(), constraint->value_);
246 case kFixedFPRegister:
247 CHECK_WITH_MSG(op->IsFPRegister(), caller_info_);
248 CHECK_EQ(LocationOperand::cast(op)->register_code(), constraint->value_);
251 CHECK_WITH_MSG(op->IsStackSlot() || op->IsFPStackSlot(), caller_info_);
252 CHECK_EQ(LocationOperand::cast(op)->index(), constraint->value_);
255 CHECK_WITH_MSG(op->IsStackSlot() || op->IsFPStackSlot(), caller_info_);
256 CHECK_EQ(ElementSizeLog2Of(LocationOperand::cast(op)->representation()),
259 case kRegisterOrSlot:
260 CHECK_WITH_MSG(op->IsRegister() || op->IsStackSlot(), caller_info_);
262 case kRegisterOrSlotFP:
263 CHECK_WITH_MSG(op->IsFPRegister() || op->IsFPStackSlot(), caller_info_);
265 case kRegisterOrSlotOrConstant:
266 CHECK_WITH_MSG(op->IsRegister() || op->IsStackSlot() || op->IsConstant(),
270 CHECK_WITH_MSG(
false, caller_info_);
275 void BlockAssessments::PerformMoves(
const Instruction* instruction) {
276 const ParallelMove* first =
277 instruction->GetParallelMove(Instruction::GapPosition::START);
278 PerformParallelMoves(first);
279 const ParallelMove* last =
280 instruction->GetParallelMove(Instruction::GapPosition::END);
281 PerformParallelMoves(last);
284 void BlockAssessments::PerformParallelMoves(
const ParallelMove* moves) {
285 if (moves ==
nullptr)
return;
287 CHECK(map_for_moves_.empty());
288 for (MoveOperands* move : *moves) {
289 if (move->IsEliminated() || move->IsRedundant())
continue;
290 auto it = map_.find(move->source());
292 CHECK(it != map_.end());
295 CHECK(map_for_moves_.find(move->destination()) == map_for_moves_.end());
297 map_for_moves_[move->destination()] = it->second;
299 for (
auto pair : map_for_moves_) {
300 map_[pair.first] = pair.second;
302 map_for_moves_.clear();
305 void BlockAssessments::DropRegisters() {
306 for (
auto iterator = map().begin(), end = map().end(); iterator != end;) {
307 auto current = iterator;
309 InstructionOperand op = current->first;
310 if (op.IsAnyRegister()) map().erase(current);
314 void BlockAssessments::Print()
const {
316 for (
const auto pair : map()) {
317 const InstructionOperand op = pair.first;
318 const Assessment* assessment = pair.second;
322 if (assessment->kind() == AssessmentKind::Final) {
323 os <<
"v" << FinalAssessment::cast(assessment)->virtual_register();
332 BlockAssessments* RegisterAllocatorVerifier::CreateForBlock(
333 const InstructionBlock* block) {
334 RpoNumber current_block_id = block->rpo_number();
336 BlockAssessments* ret =
new (zone()) BlockAssessments(zone());
337 if (block->PredecessorCount() == 0) {
344 }
else if (block->PredecessorCount() == 1 && block->phis().size() == 0) {
345 const BlockAssessments* prev_block = assessments_[block->predecessors()[0]];
346 ret->CopyFrom(prev_block);
348 for (RpoNumber pred_id : block->predecessors()) {
351 auto iterator = assessments_.find(pred_id);
352 if (iterator == assessments_.end()) {
357 CHECK(pred_id >= current_block_id);
358 CHECK(block->IsLoopHeader());
361 const BlockAssessments* pred_assessments = iterator->second;
362 CHECK_NOT_NULL(pred_assessments);
363 for (
auto pair : pred_assessments->map()) {
364 InstructionOperand operand = pair.first;
365 if (ret->map().find(operand) == ret->map().end()) {
366 ret->map().insert(std::make_pair(
367 operand,
new (zone()) PendingAssessment(zone(), block, operand)));
375 void RegisterAllocatorVerifier::ValidatePendingAssessment(
376 RpoNumber block_id, InstructionOperand op,
377 const BlockAssessments* current_assessments,
378 PendingAssessment*
const assessment,
int virtual_register) {
379 if (assessment->IsAliasOf(virtual_register))
return;
385 Zone local_zone(zone()->allocator(), ZONE_NAME);
386 ZoneQueue<std::pair<const PendingAssessment*, int>> worklist(&local_zone);
387 ZoneSet<RpoNumber> seen(&local_zone);
388 worklist.push(std::make_pair(assessment, virtual_register));
389 seen.insert(block_id);
391 while (!worklist.empty()) {
392 auto work = worklist.front();
393 const PendingAssessment* current_assessment = work.first;
394 int current_virtual_register = work.second;
395 InstructionOperand current_operand = current_assessment->operand();
398 const InstructionBlock* origin = current_assessment->origin();
399 CHECK(origin->PredecessorCount() > 1 || origin->phis().size() > 0);
406 const PhiInstruction* phi =
nullptr;
407 for (
const PhiInstruction* candidate : origin->phis()) {
408 if (candidate->virtual_register() == current_virtual_register) {
415 for (RpoNumber pred : origin->predecessors()) {
417 phi !=
nullptr ? phi->operands()[op_index] : current_virtual_register;
420 auto pred_assignment = assessments_.find(pred);
421 if (pred_assignment == assessments_.end()) {
422 CHECK(origin->IsLoopHeader());
423 auto todo_iter = outstanding_assessments_.find(pred);
424 DelayedAssessments*
set =
nullptr;
425 if (todo_iter == outstanding_assessments_.end()) {
426 set =
new (zone()) DelayedAssessments(zone());
427 outstanding_assessments_.insert(std::make_pair(pred,
set));
429 set = todo_iter->second;
431 set->AddDelayedAssessment(current_operand, expected);
435 const BlockAssessments* pred_assessments = pred_assignment->second;
436 auto found_contribution = pred_assessments->map().find(current_operand);
437 CHECK(found_contribution != pred_assessments->map().end());
438 Assessment* contribution = found_contribution->second;
440 switch (contribution->kind()) {
442 CHECK_EQ(FinalAssessment::cast(contribution)->virtual_register(),
448 const PendingAssessment* next = PendingAssessment::cast(contribution);
449 if (seen.find(pred) == seen.end()) {
450 worklist.push({next, expected});
462 assessment->AddAlias(virtual_register);
465 void RegisterAllocatorVerifier::ValidateUse(
466 RpoNumber block_id, BlockAssessments* current_assessments,
467 InstructionOperand op,
int virtual_register) {
468 auto iterator = current_assessments->map().find(op);
470 CHECK(iterator != current_assessments->map().end());
471 Assessment* assessment = iterator->second;
473 switch (assessment->kind()) {
475 CHECK_EQ(FinalAssessment::cast(assessment)->virtual_register(),
479 PendingAssessment* pending = PendingAssessment::cast(assessment);
480 ValidatePendingAssessment(block_id, op, current_assessments, pending,
487 void RegisterAllocatorVerifier::VerifyGapMoves() {
488 CHECK(assessments_.empty());
489 CHECK(outstanding_assessments_.empty());
490 const size_t block_count = sequence()->instruction_blocks().size();
491 for (
size_t block_index = 0; block_index < block_count; ++block_index) {
492 const InstructionBlock* block =
493 sequence()->instruction_blocks()[block_index];
494 BlockAssessments* block_assessments = CreateForBlock(block);
496 for (
int instr_index = block->code_start(); instr_index < block->code_end();
498 const InstructionConstraint& instr_constraint = constraints_[instr_index];
499 const Instruction* instr = instr_constraint.instruction_;
500 block_assessments->PerformMoves(instr);
502 const OperandConstraint* op_constraints =
503 instr_constraint.operand_constraints_;
505 for (
size_t i = 0;
i < instr->InputCount(); ++
i, ++count) {
506 if (op_constraints[count].type_ == kImmediate ||
507 op_constraints[count].type_ == kExplicit) {
510 int virtual_register = op_constraints[count].virtual_register_;
511 InstructionOperand op = *instr->InputAt(
i);
512 ValidateUse(block->rpo_number(), block_assessments, op,
515 for (
size_t i = 0;
i < instr->TempCount(); ++
i, ++count) {
516 block_assessments->Drop(*instr->TempAt(
i));
518 if (instr->IsCall()) {
519 block_assessments->DropRegisters();
521 for (
size_t i = 0;
i < instr->OutputCount(); ++
i, ++count) {
522 int virtual_register = op_constraints[count].virtual_register_;
523 block_assessments->AddDefinition(*instr->OutputAt(
i), virtual_register);
524 if (op_constraints[count].type_ == kRegisterAndSlot) {
525 const AllocatedOperand* reg_op =
526 AllocatedOperand::cast(instr->OutputAt(
i));
527 MachineRepresentation rep = reg_op->representation();
528 const AllocatedOperand* stack_op = AllocatedOperand::New(
529 zone(), LocationOperand::LocationKind::STACK_SLOT, rep,
530 op_constraints[
i].spilled_slot_);
531 block_assessments->AddDefinition(*stack_op, virtual_register);
537 assessments_[block->rpo_number()] = block_assessments;
539 auto todo_iter = outstanding_assessments_.find(block->rpo_number());
540 if (todo_iter == outstanding_assessments_.end())
continue;
541 DelayedAssessments* todo = todo_iter->second;
542 for (
auto pair : todo->map()) {
543 InstructionOperand op = pair.first;
544 int vreg = pair.second;
545 auto found_op = block_assessments->map().find(op);
546 CHECK(found_op != block_assessments->map().end());
547 switch (found_op->second->kind()) {
549 CHECK_EQ(FinalAssessment::cast(found_op->second)->virtual_register(),
553 ValidatePendingAssessment(block->rpo_number(), op, block_assessments,
554 PendingAssessment::cast(found_op->second),