@@ -87,6 +87,8 @@ BasicBlock *getExitFor(const ConvergenceRegion *CR) {
8787// Returns the merge block designated by I if I is a merge instruction, nullptr
8888// otherwise.
8989BasicBlock *getDesignatedMergeBlock (Instruction *I) {
90+ if (I == nullptr )
91+ return nullptr ;
9092 IntrinsicInst *II = dyn_cast<IntrinsicInst>(I);
9193 if (II == nullptr )
9294 return nullptr ;
@@ -102,6 +104,8 @@ BasicBlock *getDesignatedMergeBlock(Instruction *I) {
102104// Returns the continue block designated by I if I is an OpLoopMerge, nullptr
103105// otherwise.
104106BasicBlock *getDesignatedContinueBlock (Instruction *I) {
107+ if (I == nullptr )
108+ return nullptr ;
105109 IntrinsicInst *II = dyn_cast<IntrinsicInst>(I);
106110 if (II == nullptr )
107111 return nullptr ;
@@ -447,55 +451,52 @@ class SPIRVStructurizer : public FunctionPass {
447451 // clang-format on
448452 std::vector<Edge>
449453 createAliasBlocksForComplexEdges (std::vector<Edge> Edges) {
450- std::unordered_map<BasicBlock *, BasicBlock *> Seen;
454+ std::unordered_set< BasicBlock *> Seen;
451455 std::vector<Edge> Output;
452456 Output.reserve (Edges.size ());
453457
454458 for (auto &[Src, Dst] : Edges) {
455- auto [iterator, inserted] = Seen.insert ({Src, Dst});
456- if (inserted) {
457- Output.emplace_back (Src, Dst);
458- continue ;
459+ auto [iterator, inserted] = Seen.insert (Src);
460+ if (!inserted) {
461+ // Src already a source node. Cannot have 2 edges from A to B.
462+ // Creating alias source block.
463+ BasicBlock *NewSrc =
464+ BasicBlock::Create (F.getContext (), " new.src" , &F);
465+ replaceBranchTargets (Src, Dst, NewSrc);
466+ // replacePhiTargets(Dst, Src, NewSrc);
467+ IRBuilder<> Builder (NewSrc);
468+ Builder.CreateBr (Dst);
469+ Src = NewSrc;
459470 }
460471
461- // The exact same edge was already seen. Ignoring.
462- if (iterator->second == Dst)
463- continue ;
464-
465- // The same Src block branches to 2 distinct blocks. This will be an
466- // issue for the generated OpPhi. Creating alias block.
467- BasicBlock *NewSrc =
468- BasicBlock::Create (F.getContext (), " new.exit.src" , &F);
469- replaceBranchTargets (Src, Dst, NewSrc);
470- replacePhiTargets (Dst, Src, NewSrc);
471-
472- IRBuilder<> Builder (NewSrc);
473- Builder.CreateBr (Dst);
474-
475- Seen.emplace (NewSrc, Dst);
476- Output.emplace_back (NewSrc, Dst);
472+ Output.emplace_back (Src, Dst);
477473 }
478474
479475 return Output;
480476 }
481477
478+ AllocaInst *CreateVariable (Function &F, Type *Type,
479+ BasicBlock::iterator Position) {
480+ const DataLayout &DL = F.getDataLayout ();
481+ return new AllocaInst (Type, DL.getAllocaAddrSpace (), nullptr , " reg" ,
482+ Position);
483+ }
484+
482485 // Given a construct defined by |Header|, and a list of exiting edges
483486 // |Edges|, creates a new single exit node, fixing up those edges.
484487 BasicBlock *createSingleExitNode (BasicBlock *Header,
485488 std::vector<Edge> &Edges) {
486- auto NewExit = BasicBlock::Create (F.getContext (), " new.exit" , &F);
487- IRBuilder<> ExitBuilder (NewExit);
488-
489- std::vector<BasicBlock *> Dsts;
490- std::unordered_map<BasicBlock *, ConstantInt *> DstToIndex;
491-
492489 // Given 2 edges: Src1 -> Dst, Src2 -> Dst:
493490 // If Dst has an PHI node, and Src1 and Src2 are both operands, both Src1
494491 // and Src2 cannot be hidden by NewExit. Create 2 new nodes: Alias1,
495492 // Alias2 to which NewExit will branch before going to Dst. Then, patchup
496493 // Dst PHI node to look for Alias1 and Alias2.
497494 std::vector<Edge> FixedEdges = createAliasBlocksForComplexEdges (Edges);
498495
496+ std::vector<BasicBlock *> Dsts;
497+ std::unordered_map<BasicBlock *, ConstantInt *> DstToIndex;
498+ auto NewExit = BasicBlock::Create (F.getContext (), " new.exit" , &F);
499+ IRBuilder<> ExitBuilder (NewExit);
499500 for (auto &[Src, Dst] : FixedEdges) {
500501 if (DstToIndex.count (Dst) != 0 )
501502 continue ;
@@ -506,33 +507,38 @@ class SPIRVStructurizer : public FunctionPass {
506507 if (Dsts.size () == 1 ) {
507508 for (auto &[Src, Dst] : FixedEdges) {
508509 replaceBranchTargets (Src, Dst, NewExit);
509- replacePhiTargets (Dst, Src, NewExit);
510+ // replacePhiTargets(Dst, Src, NewExit);
510511 }
511512 ExitBuilder.CreateBr (Dsts[0 ]);
512513 return NewExit;
513514 }
514515
515- PHINode *PhiNode =
516- ExitBuilder.CreatePHI (ExitBuilder.getInt32Ty (), FixedEdges.size ());
516+ AllocaInst *Variable = CreateVariable (F, ExitBuilder.getInt32Ty (),
517+ F.begin ()->getFirstInsertionPt ());
518+ // PHINode *PhiNode = ExitBuilder.CreatePHI(ExitBuilder.getInt32Ty(),
519+ // FixedEdges.size());
517520
518521 for (auto &[Src, Dst] : FixedEdges) {
519- PhiNode->addIncoming (DstToIndex[Dst], Src);
522+ IRBuilder<> B2 (Src);
523+ B2.SetInsertPoint (Src->getFirstInsertionPt ());
524+ B2.CreateStore (DstToIndex[Dst], Variable);
520525 replaceBranchTargets (Src, Dst, NewExit);
521- replacePhiTargets (Dst, Src, NewExit);
522526 }
523527
528+ llvm::Value *Load =
529+ ExitBuilder.CreateLoad (ExitBuilder.getInt32Ty (), Variable);
530+
524531 // If we can avoid an OpSwitch, generate an OpBranch. Reason is some
525532 // OpBranch are allowed to exist without a new OpSelectionMerge if one of
526533 // the branch is the parent's merge node, while OpSwitches are not.
527534 if (Dsts.size () == 2 ) {
528- Value *Condition = ExitBuilder. CreateCmp (CmpInst::ICMP_EQ,
529- DstToIndex[Dsts[0 ]], PhiNode );
535+ Value *Condition =
536+ ExitBuilder. CreateCmp (CmpInst::ICMP_EQ, DstToIndex[Dsts[0 ]], Load );
530537 ExitBuilder.CreateCondBr (Condition, Dsts[0 ], Dsts[1 ]);
531538 return NewExit;
532539 }
533540
534- SwitchInst *Sw =
535- ExitBuilder.CreateSwitch (PhiNode, Dsts[0 ], Dsts.size () - 1 );
541+ SwitchInst *Sw = ExitBuilder.CreateSwitch (Load, Dsts[0 ], Dsts.size () - 1 );
536542 for (auto It = Dsts.begin () + 1 ; It != Dsts.end (); ++It) {
537543 Sw->addCase (DstToIndex[*It], *It);
538544 }
@@ -576,7 +582,7 @@ class SPIRVStructurizer : public FunctionPass {
576582
577583 // Creates a new basic block in F with a single OpUnreachable instruction.
578584 BasicBlock *CreateUnreachable (Function &F) {
579- BasicBlock *BB = BasicBlock::Create (F.getContext (), " new.exit " , &F);
585+ BasicBlock *BB = BasicBlock::Create (F.getContext (), " unreachable " , &F);
580586 IRBuilder<> Builder (BB);
581587 Builder.CreateUnreachable ();
582588 return BB;
@@ -1127,6 +1133,18 @@ class SPIRVStructurizer : public FunctionPass {
11271133 continue ;
11281134
11291135 Modified = true ;
1136+
1137+ if (Merge == nullptr ) {
1138+ Merge = *successors (Header).begin ();
1139+ IRBuilder<> Builder (Header);
1140+ Builder.SetInsertPoint (Header->getTerminator ());
1141+
1142+ auto MergeAddress = BlockAddress::get (Merge->getParent (), Merge);
1143+ SmallVector<Value *, 1 > Args = {MergeAddress};
1144+ Builder.CreateIntrinsic (Intrinsic::spv_selection_merge, {}, {Args});
1145+ continue ;
1146+ }
1147+
11301148 Instruction *SplitInstruction = Merge->getTerminator ();
11311149 if (isMergeInstruction (SplitInstruction->getPrevNode ()))
11321150 SplitInstruction = SplitInstruction->getPrevNode ();
0 commit comments