@@ -87,6 +87,8 @@ BasicBlock *getExitFor(const ConvergenceRegion *CR) {
87
87
// Returns the merge block designated by I if I is a merge instruction, nullptr
88
88
// otherwise.
89
89
BasicBlock *getDesignatedMergeBlock (Instruction *I) {
90
+ if (I == nullptr )
91
+ return nullptr ;
90
92
IntrinsicInst *II = dyn_cast<IntrinsicInst>(I);
91
93
if (II == nullptr )
92
94
return nullptr ;
@@ -102,6 +104,8 @@ BasicBlock *getDesignatedMergeBlock(Instruction *I) {
102
104
// Returns the continue block designated by I if I is an OpLoopMerge, nullptr
103
105
// otherwise.
104
106
BasicBlock *getDesignatedContinueBlock (Instruction *I) {
107
+ if (I == nullptr )
108
+ return nullptr ;
105
109
IntrinsicInst *II = dyn_cast<IntrinsicInst>(I);
106
110
if (II == nullptr )
107
111
return nullptr ;
@@ -447,55 +451,52 @@ class SPIRVStructurizer : public FunctionPass {
447
451
// clang-format on
448
452
std::vector<Edge>
449
453
createAliasBlocksForComplexEdges (std::vector<Edge> Edges) {
450
- std::unordered_map<BasicBlock *, BasicBlock *> Seen;
454
+ std::unordered_set< BasicBlock *> Seen;
451
455
std::vector<Edge> Output;
452
456
Output.reserve (Edges.size ());
453
457
454
458
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;
459
470
}
460
471
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);
477
473
}
478
474
479
475
return Output;
480
476
}
481
477
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
+
482
485
// Given a construct defined by |Header|, and a list of exiting edges
483
486
// |Edges|, creates a new single exit node, fixing up those edges.
484
487
BasicBlock *createSingleExitNode (BasicBlock *Header,
485
488
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
-
492
489
// Given 2 edges: Src1 -> Dst, Src2 -> Dst:
493
490
// If Dst has an PHI node, and Src1 and Src2 are both operands, both Src1
494
491
// and Src2 cannot be hidden by NewExit. Create 2 new nodes: Alias1,
495
492
// Alias2 to which NewExit will branch before going to Dst. Then, patchup
496
493
// Dst PHI node to look for Alias1 and Alias2.
497
494
std::vector<Edge> FixedEdges = createAliasBlocksForComplexEdges (Edges);
498
495
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);
499
500
for (auto &[Src, Dst] : FixedEdges) {
500
501
if (DstToIndex.count (Dst) != 0 )
501
502
continue ;
@@ -506,33 +507,38 @@ class SPIRVStructurizer : public FunctionPass {
506
507
if (Dsts.size () == 1 ) {
507
508
for (auto &[Src, Dst] : FixedEdges) {
508
509
replaceBranchTargets (Src, Dst, NewExit);
509
- replacePhiTargets (Dst, Src, NewExit);
510
+ // replacePhiTargets(Dst, Src, NewExit);
510
511
}
511
512
ExitBuilder.CreateBr (Dsts[0 ]);
512
513
return NewExit;
513
514
}
514
515
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());
517
520
518
521
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);
520
525
replaceBranchTargets (Src, Dst, NewExit);
521
- replacePhiTargets (Dst, Src, NewExit);
522
526
}
523
527
528
+ llvm::Value *Load =
529
+ ExitBuilder.CreateLoad (ExitBuilder.getInt32Ty (), Variable);
530
+
524
531
// If we can avoid an OpSwitch, generate an OpBranch. Reason is some
525
532
// OpBranch are allowed to exist without a new OpSelectionMerge if one of
526
533
// the branch is the parent's merge node, while OpSwitches are not.
527
534
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 );
530
537
ExitBuilder.CreateCondBr (Condition, Dsts[0 ], Dsts[1 ]);
531
538
return NewExit;
532
539
}
533
540
534
- SwitchInst *Sw =
535
- ExitBuilder.CreateSwitch (PhiNode, Dsts[0 ], Dsts.size () - 1 );
541
+ SwitchInst *Sw = ExitBuilder.CreateSwitch (Load, Dsts[0 ], Dsts.size () - 1 );
536
542
for (auto It = Dsts.begin () + 1 ; It != Dsts.end (); ++It) {
537
543
Sw->addCase (DstToIndex[*It], *It);
538
544
}
@@ -576,7 +582,7 @@ class SPIRVStructurizer : public FunctionPass {
576
582
577
583
// Creates a new basic block in F with a single OpUnreachable instruction.
578
584
BasicBlock *CreateUnreachable (Function &F) {
579
- BasicBlock *BB = BasicBlock::Create (F.getContext (), " new.exit " , &F);
585
+ BasicBlock *BB = BasicBlock::Create (F.getContext (), " unreachable " , &F);
580
586
IRBuilder<> Builder (BB);
581
587
Builder.CreateUnreachable ();
582
588
return BB;
@@ -1127,6 +1133,18 @@ class SPIRVStructurizer : public FunctionPass {
1127
1133
continue ;
1128
1134
1129
1135
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
+
1130
1148
Instruction *SplitInstruction = Merge->getTerminator ();
1131
1149
if (isMergeInstruction (SplitInstruction->getPrevNode ()))
1132
1150
SplitInstruction = SplitInstruction->getPrevNode ();
0 commit comments