| 531 | } |
| 532 | |
| 533 | void LoopFusion::Fuse() { |
| 534 | assert(AreCompatible() && "Can't fuse, loops aren't compatible"); |
| 535 | assert(IsLegal() && "Can't fuse, illegal"); |
| 536 | |
| 537 | // Save the pointers/ids, won't be found in the middle of doing modifications. |
| 538 | auto header_1 = loop_1_->GetHeaderBlock()->id(); |
| 539 | auto condition_1 = loop_1_->FindConditionBlock()->id(); |
| 540 | auto continue_1 = loop_1_->GetContinueBlock()->id(); |
| 541 | auto continue_0 = loop_0_->GetContinueBlock()->id(); |
| 542 | auto condition_block_of_0 = loop_0_->FindConditionBlock(); |
| 543 | |
| 544 | // Find the blocks whose branches need updating. |
| 545 | auto first_block_of_1 = &*(++containing_function_->FindBlock(condition_1)); |
| 546 | auto last_block_of_1 = &*(--containing_function_->FindBlock(continue_1)); |
| 547 | auto last_block_of_0 = &*(--containing_function_->FindBlock(continue_0)); |
| 548 | |
| 549 | // Update the branch for |last_block_of_loop_0| to go to |first_block_of_1|. |
| 550 | last_block_of_0->ForEachSuccessorLabel( |
| 551 | [first_block_of_1](uint32_t* succ) { *succ = first_block_of_1->id(); }); |
| 552 | |
| 553 | // Update the branch for the |last_block_of_loop_1| to go to the continue |
| 554 | // block of |loop_0_|. |
| 555 | last_block_of_1->ForEachSuccessorLabel( |
| 556 | [this](uint32_t* succ) { *succ = loop_0_->GetContinueBlock()->id(); }); |
| 557 | |
| 558 | // Update merge block id in the header of |loop_0_| to the merge block of |
| 559 | // |loop_1_|. |
| 560 | loop_0_->GetHeaderBlock()->ForEachInst([this](Instruction* inst) { |
| 561 | if (inst->opcode() == spv::Op::OpLoopMerge) { |
| 562 | inst->SetInOperand(0, {loop_1_->GetMergeBlock()->id()}); |
| 563 | } |
| 564 | }); |
| 565 | |
| 566 | // Update condition branch target in |loop_0_| to the merge block of |
| 567 | // |loop_1_|. |
| 568 | condition_block_of_0->ForEachInst([this](Instruction* inst) { |
| 569 | if (inst->opcode() == spv::Op::OpBranchConditional) { |
| 570 | auto loop_0_merge_block_id = loop_0_->GetMergeBlock()->id(); |
| 571 | |
| 572 | if (inst->GetSingleWordInOperand(1) == loop_0_merge_block_id) { |
| 573 | inst->SetInOperand(1, {loop_1_->GetMergeBlock()->id()}); |
| 574 | } else { |
| 575 | inst->SetInOperand(2, {loop_1_->GetMergeBlock()->id()}); |
| 576 | } |
| 577 | } |
| 578 | }); |
| 579 | |
| 580 | // Move OpPhi instructions not corresponding to the induction variable from |
| 581 | // the header of |loop_1_| to the header of |loop_0_|. |
| 582 | std::vector<Instruction*> instructions_to_move{}; |
| 583 | for (auto& instruction : *loop_1_->GetHeaderBlock()) { |
| 584 | if (instruction.opcode() == spv::Op::OpPhi && |
| 585 | &instruction != induction_1_) { |
| 586 | instructions_to_move.push_back(&instruction); |
| 587 | } |
| 588 | } |
| 589 | |
| 590 | for (auto& it : instructions_to_move) { |
no test coverage detected