Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(478)

Side by Side Diff: src/compiler/register-allocator-verifier.cc

Issue 1895013003: [turbofan] Fixes to validator (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/register-allocator-verifier.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 the V8 project authors. All rights reserved. 1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/bit-vector.h" 5 #include "src/bit-vector.h"
6 #include "src/compiler/instruction.h" 6 #include "src/compiler/instruction.h"
7 #include "src/compiler/register-allocator-verifier.h" 7 #include "src/compiler/register-allocator-verifier.h"
8 8
9 namespace v8 { 9 namespace v8 {
10 namespace internal { 10 namespace internal {
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 } // namespace 45 } // namespace
46 46
47 RegisterAllocatorVerifier::RegisterAllocatorVerifier( 47 RegisterAllocatorVerifier::RegisterAllocatorVerifier(
48 Zone* zone, const RegisterConfiguration* config, 48 Zone* zone, const RegisterConfiguration* config,
49 const InstructionSequence* sequence) 49 const InstructionSequence* sequence)
50 : zone_(zone), 50 : zone_(zone),
51 config_(config), 51 config_(config),
52 sequence_(sequence), 52 sequence_(sequence),
53 constraints_(zone), 53 constraints_(zone),
54 assessments_(zone), 54 assessments_(zone),
55 outstanding_assessments_(zone), 55 outstanding_assessments_(zone) {
56 worklist_(zone),
57 seen_(zone) {
58 constraints_.reserve(sequence->instructions().size()); 56 constraints_.reserve(sequence->instructions().size());
59 // TODO(dcarney): model unique constraints. 57 // TODO(dcarney): model unique constraints.
60 // Construct OperandConstraints for all InstructionOperands, eliminating 58 // Construct OperandConstraints for all InstructionOperands, eliminating
61 // kSameAsFirst along the way. 59 // kSameAsFirst along the way.
62 for (const Instruction* instr : sequence->instructions()) { 60 for (const Instruction* instr : sequence->instructions()) {
63 // All gaps should be totally unallocated at this point. 61 // All gaps should be totally unallocated at this point.
64 VerifyEmptyGaps(instr); 62 VerifyEmptyGaps(instr);
65 const size_t operand_count = OperandCount(instr); 63 const size_t operand_count = OperandCount(instr);
66 OperandConstraint* op_constraints = 64 OperandConstraint* op_constraints =
67 zone->NewArray<OperandConstraint>(operand_count); 65 zone->NewArray<OperandConstraint>(operand_count);
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after
340 ret->map().insert(std::make_pair( 338 ret->map().insert(std::make_pair(
341 operand, new (zone()) PendingAssessment(block, operand))); 339 operand, new (zone()) PendingAssessment(block, operand)));
342 } 340 }
343 } 341 }
344 } 342 }
345 } 343 }
346 return ret; 344 return ret;
347 } 345 }
348 346
349 void RegisterAllocatorVerifier::ValidatePendingAssessment( 347 void RegisterAllocatorVerifier::ValidatePendingAssessment(
350 RpoNumber block_id, InstructionOperand op, PendingAssessment* assessment, 348 RpoNumber block_id, InstructionOperand op,
349 BlockAssessments* current_assessments, const PendingAssessment* assessment,
351 int virtual_register) { 350 int virtual_register) {
352 // When validating a pending assessment, it is possible some of the 351 // When validating a pending assessment, it is possible some of the
353 // assessments 352 // assessments
354 // for the original operand (the one where the assessment was created for 353 // for the original operand (the one where the assessment was created for
355 // first) are also pending. To avoid recursion, we use a work list. To 354 // first) are also pending. To avoid recursion, we use a work list. To
356 // deal with cycles, we keep a set of seen nodes. 355 // deal with cycles, we keep a set of seen nodes.
357 CHECK(worklist_.empty()); 356 ZoneQueue<std::pair<const PendingAssessment*, int>> worklist(zone());
358 CHECK(seen_.empty()); 357 ZoneSet<RpoNumber> seen(zone());
359 worklist_.push(std::make_pair(assessment, virtual_register)); 358 worklist.push(std::make_pair(assessment, virtual_register));
360 seen_.insert(block_id); 359 seen.insert(block_id);
361 360
362 while (!worklist_.empty()) { 361 while (!worklist.empty()) {
363 auto work = worklist_.front(); 362 auto work = worklist.front();
364 PendingAssessment* current_assessment = work.first; 363 const PendingAssessment* current_assessment = work.first;
365 int current_virtual_register = work.second; 364 int current_virtual_register = work.second;
366 InstructionOperand current_operand = current_assessment->operand(); 365 InstructionOperand current_operand = current_assessment->operand();
367 worklist_.pop(); 366 worklist.pop();
368 367
369 const InstructionBlock* origin = current_assessment->origin(); 368 const InstructionBlock* origin = current_assessment->origin();
370 CHECK(origin->PredecessorCount() > 1 || origin->phis().size() > 0); 369 CHECK(origin->PredecessorCount() > 1 || origin->phis().size() > 0);
371 370
372 // Check if the virtual register is a phi first, instead of relying on 371 // Check if the virtual register is a phi first, instead of relying on
373 // the incoming assessments. In particular, this handles the case 372 // the incoming assessments. In particular, this handles the case
374 // v1 = phi v0 v0, which structurally is identical to v0 having been 373 // v1 = phi v0 v0, which structurally is identical to v0 having been
375 // defined at the top of a diamond, and arriving at the node joining the 374 // defined at the top of a diamond, and arriving at the node joining the
376 // diamond's branches. 375 // diamond's branches.
377 const PhiInstruction* phi = nullptr; 376 const PhiInstruction* phi = nullptr;
(...skipping 25 matching lines...) Expand all
403 continue; 402 continue;
404 } 403 }
405 404
406 const BlockAssessments* pred_assessments = pred_assignment->second; 405 const BlockAssessments* pred_assessments = pred_assignment->second;
407 auto found_contribution = pred_assessments->map().find(current_operand); 406 auto found_contribution = pred_assessments->map().find(current_operand);
408 CHECK(found_contribution != pred_assessments->map().end()); 407 CHECK(found_contribution != pred_assessments->map().end());
409 Assessment* contribution = found_contribution->second; 408 Assessment* contribution = found_contribution->second;
410 409
411 switch (contribution->kind()) { 410 switch (contribution->kind()) {
412 case Final: 411 case Final:
413 CHECK_EQ(FinalAssessment::cast(contribution)->virtual_register(), 412 ValidateFinalAssessment(
414 expected); 413 block_id, current_operand, current_assessments,
414 FinalAssessment::cast(contribution), expected);
415 break; 415 break;
416 case Pending: { 416 case Pending: {
417 // This happens if we have a diamond feeding into another one, and 417 // This happens if we have a diamond feeding into another one, and
418 // the inner one never being used - other than for carrying the value. 418 // the inner one never being used - other than for carrying the value.
419 PendingAssessment* next = PendingAssessment::cast(contribution); 419 PendingAssessment* next = PendingAssessment::cast(contribution);
420 if (seen_.find(pred) == seen_.end()) { 420 if (seen.find(pred) == seen.end()) {
421 worklist_.push({next, expected}); 421 worklist.push({next, expected});
422 seen_.insert(pred); 422 seen.insert(pred);
423 } 423 }
424 // Note that we do not want to finalize pending assessments at the 424 // Note that we do not want to finalize pending assessments at the
425 // beginning of a block - which is the information we'd have 425 // beginning of a block - which is the information we'd have
426 // available here. This is because this operand may be reused to 426 // available here. This is because this operand may be reused to
427 // define 427 // define
428 // duplicate phis. 428 // duplicate phis.
429 break; 429 break;
430 } 430 }
431 } 431 }
432 } 432 }
433 } 433 }
434 seen_.clear(); 434 // If everything checks out, we may make the assessment.
435 CHECK(worklist_.empty()); 435 current_assessments->map()[op] =
436 new (zone()) FinalAssessment(virtual_register, assessment);
437 }
438
439 void RegisterAllocatorVerifier::ValidateFinalAssessment(
440 RpoNumber block_id, InstructionOperand op,
441 BlockAssessments* current_assessments, const FinalAssessment* assessment,
442 int virtual_register) {
443 if (assessment->virtual_register() == virtual_register) return;
444 // If we have 2 phis with the exact same operand list, and the first phi is
445 // used before the second one, via the operand incoming to the block,
446 // and the second one's operand is defined (via a parallel move) after the
447 // use, then the original operand will be assigned to the first phi. We
448 // then look at the original pending assessment to ascertain if op
449 // is virtual_register.
450 const PendingAssessment* old = assessment->original_pending_assessment();
451 CHECK_NOT_NULL(old);
452 ValidatePendingAssessment(block_id, op, current_assessments, old,
453 virtual_register);
436 } 454 }
437 455
438 void RegisterAllocatorVerifier::ValidateUse( 456 void RegisterAllocatorVerifier::ValidateUse(
439 RpoNumber block_id, BlockAssessments* current_assessments, 457 RpoNumber block_id, BlockAssessments* current_assessments,
440 InstructionOperand op, int virtual_register) { 458 InstructionOperand op, int virtual_register) {
441 auto iterator = current_assessments->map().find(op); 459 auto iterator = current_assessments->map().find(op);
442 // We should have seen this operand before. 460 // We should have seen this operand before.
443 CHECK(iterator != current_assessments->map().end()); 461 CHECK(iterator != current_assessments->map().end());
444 Assessment* assessment = iterator->second; 462 Assessment* assessment = iterator->second;
445 463
446 switch (assessment->kind()) { 464 switch (assessment->kind()) {
447 case Final: 465 case Final:
448 // The virtual registers should match. 466 ValidateFinalAssessment(block_id, op, current_assessments,
449 CHECK_EQ(FinalAssessment::cast(assessment)->virtual_register(), 467 FinalAssessment::cast(assessment),
450 virtual_register); 468 virtual_register);
451 break; 469 break;
452 case Pending: { 470 case Pending: {
453 ValidatePendingAssessment( 471 const PendingAssessment* pending = PendingAssessment::cast(assessment);
454 block_id, op, PendingAssessment::cast(assessment), virtual_register); 472 ValidatePendingAssessment(block_id, op, current_assessments, pending,
455 // If everything checks out, we may make the assessment. 473 virtual_register);
456 current_assessments->map()[op] =
457 new (zone()) FinalAssessment(virtual_register);
458 break; 474 break;
459 } 475 }
460 } 476 }
461 } 477 }
462 478
463 void RegisterAllocatorVerifier::VerifyGapMoves() { 479 void RegisterAllocatorVerifier::VerifyGapMoves() {
464 CHECK(assessments_.empty()); 480 CHECK(assessments_.empty());
465 CHECK(outstanding_assessments_.empty()); 481 CHECK(outstanding_assessments_.empty());
466 const size_t block_count = sequence()->instruction_blocks().size(); 482 const size_t block_count = sequence()->instruction_blocks().size();
467 for (size_t block_index = 0; block_index < block_count; ++block_index) { 483 for (size_t block_index = 0; block_index < block_count; ++block_index) {
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
515 auto todo_iter = outstanding_assessments_.find(block->rpo_number()); 531 auto todo_iter = outstanding_assessments_.find(block->rpo_number());
516 if (todo_iter == outstanding_assessments_.end()) continue; 532 if (todo_iter == outstanding_assessments_.end()) continue;
517 DelayedAssessments* todo = todo_iter->second; 533 DelayedAssessments* todo = todo_iter->second;
518 for (auto pair : todo->map()) { 534 for (auto pair : todo->map()) {
519 InstructionOperand op = pair.first; 535 InstructionOperand op = pair.first;
520 int vreg = pair.second; 536 int vreg = pair.second;
521 auto found_op = block_assessments->map().find(op); 537 auto found_op = block_assessments->map().find(op);
522 CHECK(found_op != block_assessments->map().end()); 538 CHECK(found_op != block_assessments->map().end());
523 switch (found_op->second->kind()) { 539 switch (found_op->second->kind()) {
524 case Final: 540 case Final:
525 CHECK(FinalAssessment::cast(found_op->second)->virtual_register() == 541 ValidateFinalAssessment(block->rpo_number(), op, block_assessments,
526 vreg); 542 FinalAssessment::cast(found_op->second),
543 vreg);
527 break; 544 break;
528 case Pending: 545 case Pending:
529 ValidatePendingAssessment(block->rpo_number(), op, 546 const PendingAssessment* pending =
530 PendingAssessment::cast(found_op->second), 547 PendingAssessment::cast(found_op->second);
531 vreg); 548 ValidatePendingAssessment(block->rpo_number(), op, block_assessments,
532 block_assessments->map()[op] = new (zone()) FinalAssessment(vreg); 549 pending, vreg);
550 block_assessments->map()[op] =
551 new (zone()) FinalAssessment(vreg, pending);
533 break; 552 break;
534 } 553 }
535 } 554 }
536 } 555 }
537 } 556 }
538 557
539 } // namespace compiler 558 } // namespace compiler
540 } // namespace internal 559 } // namespace internal
541 } // namespace v8 560 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/register-allocator-verifier.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698