MCPcopy Create free account
hub / github.com/KhronosGroup/SPIRV-Tools / CloneAndAttachLoopToHeader

Method CloneAndAttachLoopToHeader

source/opt/loop_utils.cpp:519–586  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

517}
518
519Loop* 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});

Callers 1

SplitLoopMethod · 0.80

Calls 15

GetMergeBlockMethod · 0.80
getMethod · 0.80
ForEachInOperandMethod · 0.80
ForEachUseMethod · 0.80
SetOperandMethod · 0.80
SetMergeBlockMethod · 0.80
SetPreHeaderBlockMethod · 0.80
GetPreHeaderBlockMethod · 0.80
TakeNextIdMethod · 0.45
SetParentMethod · 0.45
GetParentMethod · 0.45

Tested by

no test coverage detected