| 488 | } |
| 489 | |
| 490 | Loop* LoopUtils::CloneAndAttachLoopToHeader(LoopCloningResult* cloning_result) { |
| 491 | // Clone the loop. |
| 492 | Loop* new_loop = CloneLoop(cloning_result); |
| 493 | |
| 494 | // Create a new exit block/label for the new loop. |
| 495 | // TODO(1841): Handle id overflow. |
| 496 | std::unique_ptr<Instruction> new_label{new Instruction( |
| 497 | context_, SpvOp::SpvOpLabel, 0, context_->TakeNextId(), {})}; |
| 498 | std::unique_ptr<BasicBlock> new_exit_bb{new BasicBlock(std::move(new_label))}; |
| 499 | new_exit_bb->SetParent(loop_->GetMergeBlock()->GetParent()); |
| 500 | |
| 501 | // Create an unconditional branch to the header block. |
| 502 | InstructionBuilder builder{context_, new_exit_bb.get()}; |
| 503 | builder.AddBranch(loop_->GetHeaderBlock()->id()); |
| 504 | |
| 505 | // Save the ids of the new and old merge block. |
| 506 | const uint32_t old_merge_block = loop_->GetMergeBlock()->id(); |
| 507 | const uint32_t new_merge_block = new_exit_bb->id(); |
| 508 | |
| 509 | // Replace the uses of the old merge block in the new loop with the new merge |
| 510 | // block. |
| 511 | for (std::unique_ptr<BasicBlock>& basic_block : cloning_result->cloned_bb_) { |
| 512 | for (Instruction& inst : *basic_block) { |
| 513 | // For each operand in each instruction check if it is using the old merge |
| 514 | // block and change it to be the new merge block. |
| 515 | auto replace_merge_use = [old_merge_block, |
| 516 | new_merge_block](uint32_t* id) { |
| 517 | if (*id == old_merge_block) *id = new_merge_block; |
| 518 | }; |
| 519 | inst.ForEachInOperand(replace_merge_use); |
| 520 | } |
| 521 | } |
| 522 | |
| 523 | const uint32_t old_header = loop_->GetHeaderBlock()->id(); |
| 524 | const uint32_t new_header = new_loop->GetHeaderBlock()->id(); |
| 525 | analysis::DefUseManager* def_use = context_->get_def_use_mgr(); |
| 526 | |
| 527 | def_use->ForEachUse(old_header, |
| 528 | [new_header, this](Instruction* inst, uint32_t operand) { |
| 529 | if (!this->loop_->IsInsideLoop(inst)) |
| 530 | inst->SetOperand(operand, {new_header}); |
| 531 | }); |
| 532 | |
| 533 | // TODO(1841): Handle failure to create pre-header. |
| 534 | def_use->ForEachUse( |
| 535 | loop_->GetOrCreatePreHeaderBlock()->id(), |
| 536 | [new_merge_block, this](Instruction* inst, uint32_t operand) { |
| 537 | if (this->loop_->IsInsideLoop(inst)) |
| 538 | inst->SetOperand(operand, {new_merge_block}); |
| 539 | |
| 540 | }); |
| 541 | new_loop->SetMergeBlock(new_exit_bb.get()); |
| 542 | |
| 543 | new_loop->SetPreHeaderBlock(loop_->GetPreHeaderBlock()); |
| 544 | |
| 545 | // Add the new block into the cloned instructions. |
| 546 | cloning_result->cloned_bb_.push_back(std::move(new_exit_bb)); |
| 547 |
no test coverage detected