| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |