| 517 | } |
| 518 | |
| 519 | Loop* LoopUtils::CloneAndAttachLoopToHeader(LoopCloningResult* cloning_result) { |
| 520 | // Clone the loop. |
| 521 | Loop* cloned_loop = CloneLoop(cloning_result); |
| 522 | if (!cloned_loop) { |
| 523 | return nullptr; |
| 524 | } |
| 525 | |
| 526 | // Create a new exit block/label for the new loop. |
| 527 | uint32_t new_label_id = context_->TakeNextId(); |
| 528 | if (new_label_id == 0) { |
| 529 | return nullptr; |
| 530 | } |
| 531 | std::unique_ptr<Instruction> new_label{ |
| 532 | new Instruction(context_, spv::Op::OpLabel, 0, new_label_id, {})}; |
| 533 | std::unique_ptr<BasicBlock> new_exit_bb{new BasicBlock(std::move(new_label))}; |
| 534 | new_exit_bb->SetParent(loop_->GetMergeBlock()->GetParent()); |
| 535 | |
| 536 | // Create an unconditional branch to the header block. |
| 537 | InstructionBuilder builder{context_, new_exit_bb.get()}; |
| 538 | builder.AddBranch(loop_->GetHeaderBlock()->id()); |
| 539 | |
| 540 | // Save the ids of the new and old merge block. |
| 541 | const uint32_t old_merge_block = loop_->GetMergeBlock()->id(); |
| 542 | const uint32_t new_merge_block = new_exit_bb->id(); |
| 543 | |
| 544 | // Replace the uses of the old merge block in the new loop with the new merge |
| 545 | // block. |
| 546 | for (std::unique_ptr<BasicBlock>& basic_block : cloning_result->cloned_bb_) { |
| 547 | for (Instruction& inst : *basic_block) { |
| 548 | // For each operand in each instruction check if it is using the old merge |
| 549 | // block and change it to be the new merge block. |
| 550 | auto replace_merge_use = [old_merge_block, |
| 551 | new_merge_block](uint32_t* id) { |
| 552 | if (*id == old_merge_block) *id = new_merge_block; |
| 553 | }; |
| 554 | inst.ForEachInOperand(replace_merge_use); |
| 555 | } |
| 556 | } |
| 557 | |
| 558 | const uint32_t old_header = loop_->GetHeaderBlock()->id(); |
| 559 | const uint32_t new_header = cloned_loop->GetHeaderBlock()->id(); |
| 560 | analysis::DefUseManager* def_use = context_->get_def_use_mgr(); |
| 561 | |
| 562 | def_use->ForEachUse(old_header, |
| 563 | [new_header, this](Instruction* inst, uint32_t operand) { |
| 564 | if (!this->loop_->IsInsideLoop(inst)) |
| 565 | inst->SetOperand(operand, {new_header}); |
| 566 | }); |
| 567 | |
| 568 | BasicBlock* pre_header = loop_->GetOrCreatePreHeaderBlock(); |
| 569 | if (!pre_header) { |
| 570 | return nullptr; |
| 571 | } |
| 572 | def_use->ForEachUse( |
| 573 | pre_header->id(), |
| 574 | [new_merge_block, this](Instruction* inst, uint32_t operand) { |
| 575 | if (this->loop_->IsInsideLoop(inst)) |
| 576 | inst->SetOperand(operand, {new_merge_block}); |
no test coverage detected