@@ -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,66 @@ 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)
472+ // Dst has a PHI node. We also need to create an alias output block.
473+ if (!hasPhiNode (Dst)) {
474+ Output.emplace_back (Src, Dst);
463475 continue ;
476+ }
464477
465- // The same Src block branches to 2 distinct blocks. This will be an
466- // issue for the generated OpPhi. Creating alias block .
478+ // Dst already targeted AND contains a PHI node. We'll need alias
479+ // blocks .
467480 BasicBlock *NewSrc =
468- BasicBlock::Create (F.getContext (), " new.exit.src " , &F);
481+ BasicBlock::Create (F.getContext (), " phi.alias " , &F);
469482 replaceBranchTargets (Src, Dst, NewSrc);
470- replacePhiTargets (Dst, Src, NewSrc);
471-
483+ // replacePhiTargets(Dst, Src, NewSrc);
472484 IRBuilder<> Builder (NewSrc);
473485 Builder.CreateBr (Dst);
474-
475- Seen.emplace (NewSrc, Dst);
476- Output.emplace_back (NewSrc, Dst);
486+ Output.emplace_back (Src, NewSrc);
477487 }
478488
479489 return Output;
480490 }
481491
492+ AllocaInst *CreateVariable (Function &F, Type *Type,
493+ BasicBlock::iterator Position) {
494+ const DataLayout &DL = F.getDataLayout ();
495+ return new AllocaInst (Type, DL.getAllocaAddrSpace (), nullptr , " reg" ,
496+ Position);
497+ }
498+
482499 // Given a construct defined by |Header|, and a list of exiting edges
483500 // |Edges|, creates a new single exit node, fixing up those edges.
484501 BasicBlock *createSingleExitNode (BasicBlock *Header,
485502 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-
492503 // Given 2 edges: Src1 -> Dst, Src2 -> Dst:
493504 // If Dst has an PHI node, and Src1 and Src2 are both operands, both Src1
494505 // and Src2 cannot be hidden by NewExit. Create 2 new nodes: Alias1,
495506 // Alias2 to which NewExit will branch before going to Dst. Then, patchup
496507 // Dst PHI node to look for Alias1 and Alias2.
497508 std::vector<Edge> FixedEdges = createAliasBlocksForComplexEdges (Edges);
498509
510+ std::vector<BasicBlock *> Dsts;
511+ std::unordered_map<BasicBlock *, ConstantInt *> DstToIndex;
512+ auto NewExit = BasicBlock::Create (F.getContext (), " new.exit" , &F);
513+ IRBuilder<> ExitBuilder (NewExit);
499514 for (auto &[Src, Dst] : FixedEdges) {
500515 if (DstToIndex.count (Dst) != 0 )
501516 continue ;
@@ -506,33 +521,38 @@ class SPIRVStructurizer : public FunctionPass {
506521 if (Dsts.size () == 1 ) {
507522 for (auto &[Src, Dst] : FixedEdges) {
508523 replaceBranchTargets (Src, Dst, NewExit);
509- replacePhiTargets (Dst, Src, NewExit);
524+ // replacePhiTargets(Dst, Src, NewExit);
510525 }
511526 ExitBuilder.CreateBr (Dsts[0 ]);
512527 return NewExit;
513528 }
514529
515- PHINode *PhiNode =
516- ExitBuilder.CreatePHI (ExitBuilder.getInt32Ty (), FixedEdges.size ());
530+ AllocaInst *Variable = CreateVariable (F, ExitBuilder.getInt32Ty (),
531+ F.begin ()->getFirstInsertionPt ());
532+ // PHINode *PhiNode = ExitBuilder.CreatePHI(ExitBuilder.getInt32Ty(),
533+ // FixedEdges.size());
517534
518535 for (auto &[Src, Dst] : FixedEdges) {
519- PhiNode->addIncoming (DstToIndex[Dst], Src);
536+ IRBuilder<> B2 (Src);
537+ B2.SetInsertPoint (Src->getFirstInsertionPt ());
538+ B2.CreateStore (DstToIndex[Dst], Variable);
520539 replaceBranchTargets (Src, Dst, NewExit);
521- replacePhiTargets (Dst, Src, NewExit);
522540 }
523541
542+ llvm::Value *Load =
543+ ExitBuilder.CreateLoad (ExitBuilder.getInt32Ty (), Variable);
544+
524545 // If we can avoid an OpSwitch, generate an OpBranch. Reason is some
525546 // OpBranch are allowed to exist without a new OpSelectionMerge if one of
526547 // the branch is the parent's merge node, while OpSwitches are not.
527548 if (Dsts.size () == 2 ) {
528- Value *Condition = ExitBuilder. CreateCmp (CmpInst::ICMP_EQ,
529- DstToIndex[Dsts[0 ]], PhiNode );
549+ Value *Condition =
550+ ExitBuilder. CreateCmp (CmpInst::ICMP_EQ, DstToIndex[Dsts[0 ]], Load );
530551 ExitBuilder.CreateCondBr (Condition, Dsts[0 ], Dsts[1 ]);
531552 return NewExit;
532553 }
533554
534- SwitchInst *Sw =
535- ExitBuilder.CreateSwitch (PhiNode, Dsts[0 ], Dsts.size () - 1 );
555+ SwitchInst *Sw = ExitBuilder.CreateSwitch (Load, Dsts[0 ], Dsts.size () - 1 );
536556 for (auto It = Dsts.begin () + 1 ; It != Dsts.end (); ++It) {
537557 Sw->addCase (DstToIndex[*It], *It);
538558 }
@@ -576,7 +596,7 @@ class SPIRVStructurizer : public FunctionPass {
576596
577597 // Creates a new basic block in F with a single OpUnreachable instruction.
578598 BasicBlock *CreateUnreachable (Function &F) {
579- BasicBlock *BB = BasicBlock::Create (F.getContext (), " new.exit " , &F);
599+ BasicBlock *BB = BasicBlock::Create (F.getContext (), " unreachable " , &F);
580600 IRBuilder<> Builder (BB);
581601 Builder.CreateUnreachable ();
582602 return BB;
@@ -1127,6 +1147,18 @@ class SPIRVStructurizer : public FunctionPass {
11271147 continue ;
11281148
11291149 Modified = true ;
1150+
1151+ if (Merge == nullptr ) {
1152+ Merge = *successors (Header).begin ();
1153+ IRBuilder<> Builder (Header);
1154+ Builder.SetInsertPoint (Header->getTerminator ());
1155+
1156+ auto MergeAddress = BlockAddress::get (Merge->getParent (), Merge);
1157+ SmallVector<Value *, 1 > Args = {MergeAddress};
1158+ Builder.CreateIntrinsic (Intrinsic::spv_selection_merge, {}, {Args});
1159+ continue ;
1160+ }
1161+
11301162 Instruction *SplitInstruction = Merge->getTerminator ();
11311163 if (isMergeInstruction (SplitInstruction->getPrevNode ()))
11321164 SplitInstruction = SplitInstruction->getPrevNode ();
0 commit comments