| 617 | } |
| 618 | |
| 619 | opt::BasicBlock* FuzzerPass::GetOrCreateSimpleLoopPreheader( |
| 620 | uint32_t header_id) { |
| 621 | auto header_block = fuzzerutil::MaybeFindBlock(GetIRContext(), header_id); |
| 622 | |
| 623 | assert(header_block && header_block->IsLoopHeader() && |
| 624 | "|header_id| should be the label id of a loop header"); |
| 625 | |
| 626 | auto predecessors = GetIRContext()->cfg()->preds(header_id); |
| 627 | |
| 628 | assert(predecessors.size() >= 2 && |
| 629 | "The block |header_id| should be reachable."); |
| 630 | |
| 631 | auto function = header_block->GetParent(); |
| 632 | |
| 633 | if (predecessors.size() == 2) { |
| 634 | // The header has a single out-of-loop predecessor, which could be a |
| 635 | // preheader. |
| 636 | |
| 637 | opt::BasicBlock* maybe_preheader; |
| 638 | |
| 639 | if (GetIRContext()->GetDominatorAnalysis(function)->Dominates( |
| 640 | header_id, predecessors[0])) { |
| 641 | // The first predecessor is the back-edge block, because the header |
| 642 | // dominates it, so the second one is out of the loop. |
| 643 | maybe_preheader = &*function->FindBlock(predecessors[1]); |
| 644 | } else { |
| 645 | // The first predecessor is out of the loop. |
| 646 | maybe_preheader = &*function->FindBlock(predecessors[0]); |
| 647 | } |
| 648 | |
| 649 | // |maybe_preheader| is a preheader if it branches unconditionally to |
| 650 | // the header. We also require it not to be a loop header. |
| 651 | if (maybe_preheader->terminator()->opcode() == spv::Op::OpBranch && |
| 652 | !maybe_preheader->IsLoopHeader()) { |
| 653 | return maybe_preheader; |
| 654 | } |
| 655 | } |
| 656 | |
| 657 | // We need to add a preheader. |
| 658 | |
| 659 | // Get a fresh id for the preheader. |
| 660 | uint32_t preheader_id = GetFuzzerContext()->GetFreshId(); |
| 661 | |
| 662 | // Get a fresh id for each OpPhi instruction, if there is more than one |
| 663 | // out-of-loop predecessor. |
| 664 | std::vector<uint32_t> phi_ids; |
| 665 | if (predecessors.size() > 2) { |
| 666 | header_block->ForEachPhiInst( |
| 667 | [this, &phi_ids](opt::Instruction* /* unused */) { |
| 668 | phi_ids.push_back(GetFuzzerContext()->GetFreshId()); |
| 669 | }); |
| 670 | } |
| 671 | |
| 672 | // Add the preheader. |
| 673 | ApplyTransformation( |
| 674 | TransformationAddLoopPreheader(header_id, preheader_id, phi_ids)); |
| 675 | |
| 676 | // Make the newly-created preheader the new entry block. |
nothing calls this directly
no test coverage detected