1b8f8dbc2SMatt Arsenault //===- AMDGPUUnifyDivergentExitNodes.cpp ----------------------------------===//
2b8f8dbc2SMatt Arsenault //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b8f8dbc2SMatt Arsenault //
7b8f8dbc2SMatt Arsenault //===----------------------------------------------------------------------===//
8b8f8dbc2SMatt Arsenault //
9092a3ce5SJay Foad // This is a variant of the UnifyFunctionExitNodes pass. Rather than ensuring
10b8f8dbc2SMatt Arsenault // there is at most one ret and one unreachable instruction, it ensures there is
11b8f8dbc2SMatt Arsenault // at most one divergent exiting block.
12b8f8dbc2SMatt Arsenault //
13b8f8dbc2SMatt Arsenault // StructurizeCFG can't deal with multi-exit regions formed by branches to
14b8f8dbc2SMatt Arsenault // multiple return nodes. It is not desirable to structurize regions with
15b8f8dbc2SMatt Arsenault // uniform branches, so unifying those to the same return block as divergent
16b8f8dbc2SMatt Arsenault // branches inhibits use of scalar branching. It still can't deal with the case
17b8f8dbc2SMatt Arsenault // where one branch goes to return, and one unreachable. Replace unreachable in
18b8f8dbc2SMatt Arsenault // this case with a return.
19b8f8dbc2SMatt Arsenault //
20b8f8dbc2SMatt Arsenault //===----------------------------------------------------------------------===//
21b8f8dbc2SMatt Arsenault 
22b8f8dbc2SMatt Arsenault #include "AMDGPU.h"
23ad3ec089SJay Foad #include "SIDefines.h"
246cadde7fSEugene Zelenko #include "llvm/ADT/ArrayRef.h"
256cadde7fSEugene Zelenko #include "llvm/ADT/SmallPtrSet.h"
266cadde7fSEugene Zelenko #include "llvm/ADT/SmallVector.h"
276cadde7fSEugene Zelenko #include "llvm/ADT/StringRef.h"
284b806473SRoman Lebedev #include "llvm/Analysis/DomTreeUpdater.h"
2935617ed4SNicolai Haehnle #include "llvm/Analysis/LegacyDivergenceAnalysis.h"
30b8f8dbc2SMatt Arsenault #include "llvm/Analysis/PostDominators.h"
31b8f8dbc2SMatt Arsenault #include "llvm/Analysis/TargetTransformInfo.h"
32b8f8dbc2SMatt Arsenault #include "llvm/IR/BasicBlock.h"
33b8f8dbc2SMatt Arsenault #include "llvm/IR/CFG.h"
346cadde7fSEugene Zelenko #include "llvm/IR/Constants.h"
354b806473SRoman Lebedev #include "llvm/IR/Dominators.h"
36b8f8dbc2SMatt Arsenault #include "llvm/IR/Function.h"
374b806473SRoman Lebedev #include "llvm/IR/IRBuilder.h"
386cadde7fSEugene Zelenko #include "llvm/IR/InstrTypes.h"
39b8f8dbc2SMatt Arsenault #include "llvm/IR/Instructions.h"
406cadde7fSEugene Zelenko #include "llvm/IR/Intrinsics.h"
416a87e9b0Sdfukalov #include "llvm/IR/IntrinsicsAMDGPU.h"
42b8f8dbc2SMatt Arsenault #include "llvm/IR/Type.h"
4305da2fe5SReid Kleckner #include "llvm/InitializePasses.h"
446cadde7fSEugene Zelenko #include "llvm/Pass.h"
456cadde7fSEugene Zelenko #include "llvm/Support/Casting.h"
46b8f8dbc2SMatt Arsenault #include "llvm/Transforms/Scalar.h"
47a373d18eSDavid Blaikie #include "llvm/Transforms/Utils.h"
4805da2fe5SReid Kleckner #include "llvm/Transforms/Utils/Local.h"
496cadde7fSEugene Zelenko 
50b8f8dbc2SMatt Arsenault using namespace llvm;
51b8f8dbc2SMatt Arsenault 
52b8f8dbc2SMatt Arsenault #define DEBUG_TYPE "amdgpu-unify-divergent-exit-nodes"
53b8f8dbc2SMatt Arsenault 
54b8f8dbc2SMatt Arsenault namespace {
55b8f8dbc2SMatt Arsenault 
56b8f8dbc2SMatt Arsenault class AMDGPUUnifyDivergentExitNodes : public FunctionPass {
57dc2f6bf5SJay Foad private:
58dc2f6bf5SJay Foad   const TargetTransformInfo *TTI = nullptr;
59dc2f6bf5SJay Foad 
60b8f8dbc2SMatt Arsenault public:
61b8f8dbc2SMatt Arsenault   static char ID; // Pass identification, replacement for typeid
626cadde7fSEugene Zelenko 
AMDGPUUnifyDivergentExitNodes()63b8f8dbc2SMatt Arsenault   AMDGPUUnifyDivergentExitNodes() : FunctionPass(ID) {
64b8f8dbc2SMatt Arsenault     initializeAMDGPUUnifyDivergentExitNodesPass(*PassRegistry::getPassRegistry());
65b8f8dbc2SMatt Arsenault   }
66b8f8dbc2SMatt Arsenault 
67b8f8dbc2SMatt Arsenault   // We can preserve non-critical-edgeness when we unify function exit nodes
68b8f8dbc2SMatt Arsenault   void getAnalysisUsage(AnalysisUsage &AU) const override;
69dc2f6bf5SJay Foad   BasicBlock *unifyReturnBlockSet(Function &F, DomTreeUpdater &DTU,
70dc2f6bf5SJay Foad                                   ArrayRef<BasicBlock *> ReturningBlocks,
71d9b9fdd9SRuiling Song                                   StringRef Name);
72b8f8dbc2SMatt Arsenault   bool runOnFunction(Function &F) override;
73b8f8dbc2SMatt Arsenault };
74b8f8dbc2SMatt Arsenault 
756cadde7fSEugene Zelenko } // end anonymous namespace
76b8f8dbc2SMatt Arsenault 
77b8f8dbc2SMatt Arsenault char AMDGPUUnifyDivergentExitNodes::ID = 0;
786cadde7fSEugene Zelenko 
796cadde7fSEugene Zelenko char &llvm::AMDGPUUnifyDivergentExitNodesID = AMDGPUUnifyDivergentExitNodes::ID;
806cadde7fSEugene Zelenko 
81b8f8dbc2SMatt Arsenault INITIALIZE_PASS_BEGIN(AMDGPUUnifyDivergentExitNodes, DEBUG_TYPE,
82b8f8dbc2SMatt Arsenault                      "Unify divergent function exit nodes", false, false)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)834b806473SRoman Lebedev INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
84b8f8dbc2SMatt Arsenault INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass)
8535617ed4SNicolai Haehnle INITIALIZE_PASS_DEPENDENCY(LegacyDivergenceAnalysis)
86b8f8dbc2SMatt Arsenault INITIALIZE_PASS_END(AMDGPUUnifyDivergentExitNodes, DEBUG_TYPE,
87b8f8dbc2SMatt Arsenault                     "Unify divergent function exit nodes", false, false)
88b8f8dbc2SMatt Arsenault 
89b8f8dbc2SMatt Arsenault void AMDGPUUnifyDivergentExitNodes::getAnalysisUsage(AnalysisUsage &AU) const{
904b806473SRoman Lebedev   if (RequireAndPreserveDomTree)
914b806473SRoman Lebedev     AU.addRequired<DominatorTreeWrapperPass>();
924b806473SRoman Lebedev 
93b8f8dbc2SMatt Arsenault   AU.addRequired<PostDominatorTreeWrapperPass>();
94b8f8dbc2SMatt Arsenault 
9535617ed4SNicolai Haehnle   AU.addRequired<LegacyDivergenceAnalysis>();
96b8f8dbc2SMatt Arsenault 
974b806473SRoman Lebedev   if (RequireAndPreserveDomTree) {
984b806473SRoman Lebedev     AU.addPreserved<DominatorTreeWrapperPass>();
997c8b8063SRoman Lebedev     // FIXME: preserve PostDominatorTreeWrapperPass
1004b806473SRoman Lebedev   }
1014b806473SRoman Lebedev 
102b8f8dbc2SMatt Arsenault   // No divergent values are changed, only blocks and branch edges.
10335617ed4SNicolai Haehnle   AU.addPreserved<LegacyDivergenceAnalysis>();
104b8f8dbc2SMatt Arsenault 
105b8f8dbc2SMatt Arsenault   // We preserve the non-critical-edgeness property
106b8f8dbc2SMatt Arsenault   AU.addPreservedID(BreakCriticalEdgesID);
107b8f8dbc2SMatt Arsenault 
108b8f8dbc2SMatt Arsenault   // This is a cluster of orthogonal Transforms
109b8f8dbc2SMatt Arsenault   AU.addPreservedID(LowerSwitchID);
110b8f8dbc2SMatt Arsenault   FunctionPass::getAnalysisUsage(AU);
111b8f8dbc2SMatt Arsenault 
112b8f8dbc2SMatt Arsenault   AU.addRequired<TargetTransformInfoWrapperPass>();
113b8f8dbc2SMatt Arsenault }
114b8f8dbc2SMatt Arsenault 
115b8f8dbc2SMatt Arsenault /// \returns true if \p BB is reachable through only uniform branches.
116b8f8dbc2SMatt Arsenault /// XXX - Is there a more efficient way to find this?
isUniformlyReached(const LegacyDivergenceAnalysis & DA,BasicBlock & BB)11735617ed4SNicolai Haehnle static bool isUniformlyReached(const LegacyDivergenceAnalysis &DA,
118b8f8dbc2SMatt Arsenault                                BasicBlock &BB) {
1197925aa09SKazu Hirata   SmallVector<BasicBlock *, 8> Stack(predecessors(&BB));
120b8f8dbc2SMatt Arsenault   SmallPtrSet<BasicBlock *, 8> Visited;
121b8f8dbc2SMatt Arsenault 
122b8f8dbc2SMatt Arsenault   while (!Stack.empty()) {
123b8f8dbc2SMatt Arsenault     BasicBlock *Top = Stack.pop_back_val();
124b8f8dbc2SMatt Arsenault     if (!DA.isUniform(Top->getTerminator()))
125b8f8dbc2SMatt Arsenault       return false;
126b8f8dbc2SMatt Arsenault 
127b8f8dbc2SMatt Arsenault     for (BasicBlock *Pred : predecessors(Top)) {
128b8f8dbc2SMatt Arsenault       if (Visited.insert(Pred).second)
129b8f8dbc2SMatt Arsenault         Stack.push_back(Pred);
130b8f8dbc2SMatt Arsenault     }
131b8f8dbc2SMatt Arsenault   }
132b8f8dbc2SMatt Arsenault 
133b8f8dbc2SMatt Arsenault   return true;
134b8f8dbc2SMatt Arsenault }
135b8f8dbc2SMatt Arsenault 
unifyReturnBlockSet(Function & F,DomTreeUpdater & DTU,ArrayRef<BasicBlock * > ReturningBlocks,StringRef Name)136dc2f6bf5SJay Foad BasicBlock *AMDGPUUnifyDivergentExitNodes::unifyReturnBlockSet(
137dc2f6bf5SJay Foad     Function &F, DomTreeUpdater &DTU, ArrayRef<BasicBlock *> ReturningBlocks,
138d9b9fdd9SRuiling Song     StringRef Name) {
139b8f8dbc2SMatt Arsenault   // Otherwise, we need to insert a new basic block into the function, add a PHI
140b8f8dbc2SMatt Arsenault   // nodes (if the function returns values), and convert all of the return
141b8f8dbc2SMatt Arsenault   // instructions into unconditional branches.
142b8f8dbc2SMatt Arsenault   BasicBlock *NewRetBlock = BasicBlock::Create(F.getContext(), Name, &F);
14387d98c14SConnor Abbott   IRBuilder<> B(NewRetBlock);
14487d98c14SConnor Abbott 
145b8f8dbc2SMatt Arsenault   PHINode *PN = nullptr;
146b8f8dbc2SMatt Arsenault   if (F.getReturnType()->isVoidTy()) {
14787d98c14SConnor Abbott     B.CreateRetVoid();
148b8f8dbc2SMatt Arsenault   } else {
149b8f8dbc2SMatt Arsenault     // If the function doesn't return void... add a PHI node to the block...
15087d98c14SConnor Abbott     PN = B.CreatePHI(F.getReturnType(), ReturningBlocks.size(),
151b8f8dbc2SMatt Arsenault                      "UnifiedRetVal");
15287d98c14SConnor Abbott     B.CreateRet(PN);
153b8f8dbc2SMatt Arsenault   }
154b8f8dbc2SMatt Arsenault 
155b8f8dbc2SMatt Arsenault   // Loop over all of the blocks, replacing the return instruction with an
156b8f8dbc2SMatt Arsenault   // unconditional branch.
1574b806473SRoman Lebedev   std::vector<DominatorTree::UpdateType> Updates;
1584b806473SRoman Lebedev   Updates.reserve(ReturningBlocks.size());
159b8f8dbc2SMatt Arsenault   for (BasicBlock *BB : ReturningBlocks) {
160b8f8dbc2SMatt Arsenault     // Add an incoming element to the PHI node for every return instruction that
161b8f8dbc2SMatt Arsenault     // is merging into this new block...
162b8f8dbc2SMatt Arsenault     if (PN)
163b8f8dbc2SMatt Arsenault       PN->addIncoming(BB->getTerminator()->getOperand(0), BB);
164b8f8dbc2SMatt Arsenault 
165d049da37SChangpeng Fang     // Remove and delete the return inst.
166d049da37SChangpeng Fang     BB->getTerminator()->eraseFromParent();
167b8f8dbc2SMatt Arsenault     BranchInst::Create(NewRetBlock, BB);
1684b806473SRoman Lebedev     Updates.push_back({DominatorTree::Insert, BB, NewRetBlock});
169b8f8dbc2SMatt Arsenault   }
170b8f8dbc2SMatt Arsenault 
1714b806473SRoman Lebedev   if (RequireAndPreserveDomTree)
1724b806473SRoman Lebedev     DTU.applyUpdates(Updates);
1734b806473SRoman Lebedev   Updates.clear();
1744b806473SRoman Lebedev 
175b8f8dbc2SMatt Arsenault   for (BasicBlock *BB : ReturningBlocks) {
176b8f8dbc2SMatt Arsenault     // Cleanup possible branch to unconditional branch to the return.
177dc2f6bf5SJay Foad     simplifyCFG(BB, *TTI, RequireAndPreserveDomTree ? &DTU : nullptr,
17849dac4acSRoman Lebedev                 SimplifyCFGOptions().bonusInstThreshold(2));
179b8f8dbc2SMatt Arsenault   }
180b8f8dbc2SMatt Arsenault 
181b8f8dbc2SMatt Arsenault   return NewRetBlock;
182b8f8dbc2SMatt Arsenault }
183b8f8dbc2SMatt Arsenault 
runOnFunction(Function & F)184b8f8dbc2SMatt Arsenault bool AMDGPUUnifyDivergentExitNodes::runOnFunction(Function &F) {
1854b806473SRoman Lebedev   DominatorTree *DT = nullptr;
1864b806473SRoman Lebedev   if (RequireAndPreserveDomTree)
1874b806473SRoman Lebedev     DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
1884b806473SRoman Lebedev 
189b8f8dbc2SMatt Arsenault   auto &PDT = getAnalysis<PostDominatorTreeWrapperPass>().getPostDomTree();
190ce06d507SConnor Abbott 
191d9b9fdd9SRuiling Song   // If there's only one exit, we don't need to do anything.
192d9b9fdd9SRuiling Song   if (PDT.root_size() <= 1)
19313ab22abSConnor Abbott     return false;
194b8f8dbc2SMatt Arsenault 
19535617ed4SNicolai Haehnle   LegacyDivergenceAnalysis &DA = getAnalysis<LegacyDivergenceAnalysis>();
196dc2f6bf5SJay Foad   TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
197b8f8dbc2SMatt Arsenault 
198b8f8dbc2SMatt Arsenault   // Loop over all of the blocks in a function, tracking all of the blocks that
199b8f8dbc2SMatt Arsenault   // return.
200b8f8dbc2SMatt Arsenault   SmallVector<BasicBlock *, 4> ReturningBlocks;
201b8f8dbc2SMatt Arsenault   SmallVector<BasicBlock *, 4> UnreachableBlocks;
202b8f8dbc2SMatt Arsenault 
203391bcf88SChangpeng Fang   // Dummy return block for infinite loop.
204391bcf88SChangpeng Fang   BasicBlock *DummyReturnBB = nullptr;
205391bcf88SChangpeng Fang 
20672e4da45SJay Foad   bool Changed = false;
2074b806473SRoman Lebedev   std::vector<DominatorTree::UpdateType> Updates;
2084b806473SRoman Lebedev 
209dfcc68c5SNicolai Hähnle   for (BasicBlock *BB : PDT.roots()) {
210b8f8dbc2SMatt Arsenault     if (isa<ReturnInst>(BB->getTerminator())) {
211b8f8dbc2SMatt Arsenault       if (!isUniformlyReached(DA, *BB))
212b8f8dbc2SMatt Arsenault         ReturningBlocks.push_back(BB);
213b8f8dbc2SMatt Arsenault     } else if (isa<UnreachableInst>(BB->getTerminator())) {
214b8f8dbc2SMatt Arsenault       if (!isUniformlyReached(DA, *BB))
215b8f8dbc2SMatt Arsenault         UnreachableBlocks.push_back(BB);
216391bcf88SChangpeng Fang     } else if (BranchInst *BI = dyn_cast<BranchInst>(BB->getTerminator())) {
217391bcf88SChangpeng Fang 
218391bcf88SChangpeng Fang       ConstantInt *BoolTrue = ConstantInt::getTrue(F.getContext());
219391bcf88SChangpeng Fang       if (DummyReturnBB == nullptr) {
220391bcf88SChangpeng Fang         DummyReturnBB = BasicBlock::Create(F.getContext(),
221391bcf88SChangpeng Fang                                            "DummyReturnBlock", &F);
222391bcf88SChangpeng Fang         Type *RetTy = F.getReturnType();
223391bcf88SChangpeng Fang         Value *RetVal = RetTy->isVoidTy() ? nullptr : UndefValue::get(RetTy);
224391bcf88SChangpeng Fang         ReturnInst::Create(F.getContext(), RetVal, DummyReturnBB);
225391bcf88SChangpeng Fang         ReturningBlocks.push_back(DummyReturnBB);
226391bcf88SChangpeng Fang       }
227391bcf88SChangpeng Fang 
228391bcf88SChangpeng Fang       if (BI->isUnconditional()) {
229391bcf88SChangpeng Fang         BasicBlock *LoopHeaderBB = BI->getSuccessor(0);
230391bcf88SChangpeng Fang         BI->eraseFromParent(); // Delete the unconditional branch.
231391bcf88SChangpeng Fang         // Add a new conditional branch with a dummy edge to the return block.
232391bcf88SChangpeng Fang         BranchInst::Create(LoopHeaderBB, DummyReturnBB, BoolTrue, BB);
2334b806473SRoman Lebedev         Updates.push_back({DominatorTree::Insert, BB, DummyReturnBB});
234391bcf88SChangpeng Fang       } else { // Conditional branch.
235*5648f717SKazu Hirata         SmallVector<BasicBlock *, 2> Successors(successors(BB));
2364b806473SRoman Lebedev 
237391bcf88SChangpeng Fang         // Create a new transition block to hold the conditional branch.
238688afeb8SDiego Novillo         BasicBlock *TransitionBB = BB->splitBasicBlock(BI, "TransitionBlock");
239391bcf88SChangpeng Fang 
2404b806473SRoman Lebedev         Updates.reserve(Updates.size() + 2 * Successors.size() + 2);
2414b806473SRoman Lebedev 
2424b806473SRoman Lebedev         // 'Successors' become successors of TransitionBB instead of BB,
2434b806473SRoman Lebedev         // and TransitionBB becomes a single successor of BB.
2444b806473SRoman Lebedev         Updates.push_back({DominatorTree::Insert, BB, TransitionBB});
2454b806473SRoman Lebedev         for (BasicBlock *Successor : Successors) {
2464b806473SRoman Lebedev           Updates.push_back({DominatorTree::Insert, TransitionBB, Successor});
2474b806473SRoman Lebedev           Updates.push_back({DominatorTree::Delete, BB, Successor});
2484b806473SRoman Lebedev         }
2494b806473SRoman Lebedev 
250688afeb8SDiego Novillo         // Create a branch that will always branch to the transition block and
251688afeb8SDiego Novillo         // references DummyReturnBB.
252688afeb8SDiego Novillo         BB->getTerminator()->eraseFromParent();
253391bcf88SChangpeng Fang         BranchInst::Create(TransitionBB, DummyReturnBB, BoolTrue, BB);
2544b806473SRoman Lebedev         Updates.push_back({DominatorTree::Insert, BB, DummyReturnBB});
255391bcf88SChangpeng Fang       }
25672e4da45SJay Foad       Changed = true;
257b8f8dbc2SMatt Arsenault     }
258b8f8dbc2SMatt Arsenault   }
259b8f8dbc2SMatt Arsenault 
260b8f8dbc2SMatt Arsenault   if (!UnreachableBlocks.empty()) {
261b8f8dbc2SMatt Arsenault     BasicBlock *UnreachableBlock = nullptr;
262b8f8dbc2SMatt Arsenault 
263b8f8dbc2SMatt Arsenault     if (UnreachableBlocks.size() == 1) {
264b8f8dbc2SMatt Arsenault       UnreachableBlock = UnreachableBlocks.front();
265b8f8dbc2SMatt Arsenault     } else {
266b8f8dbc2SMatt Arsenault       UnreachableBlock = BasicBlock::Create(F.getContext(),
267b8f8dbc2SMatt Arsenault                                             "UnifiedUnreachableBlock", &F);
268b8f8dbc2SMatt Arsenault       new UnreachableInst(F.getContext(), UnreachableBlock);
269b8f8dbc2SMatt Arsenault 
2704b806473SRoman Lebedev       Updates.reserve(Updates.size() + UnreachableBlocks.size());
271b8f8dbc2SMatt Arsenault       for (BasicBlock *BB : UnreachableBlocks) {
272d049da37SChangpeng Fang         // Remove and delete the unreachable inst.
273d049da37SChangpeng Fang         BB->getTerminator()->eraseFromParent();
274b8f8dbc2SMatt Arsenault         BranchInst::Create(UnreachableBlock, BB);
2754b806473SRoman Lebedev         Updates.push_back({DominatorTree::Insert, BB, UnreachableBlock});
276b8f8dbc2SMatt Arsenault       }
27772e4da45SJay Foad       Changed = true;
278b8f8dbc2SMatt Arsenault     }
279b8f8dbc2SMatt Arsenault 
280b8f8dbc2SMatt Arsenault     if (!ReturningBlocks.empty()) {
281b8f8dbc2SMatt Arsenault       // Don't create a new unreachable inst if we have a return. The
282b8f8dbc2SMatt Arsenault       // structurizer/annotator can't handle the multiple exits
283b8f8dbc2SMatt Arsenault 
284b8f8dbc2SMatt Arsenault       Type *RetTy = F.getReturnType();
285b8f8dbc2SMatt Arsenault       Value *RetVal = RetTy->isVoidTy() ? nullptr : UndefValue::get(RetTy);
286d049da37SChangpeng Fang       // Remove and delete the unreachable inst.
287d049da37SChangpeng Fang       UnreachableBlock->getTerminator()->eraseFromParent();
288b8f8dbc2SMatt Arsenault 
289b8f8dbc2SMatt Arsenault       Function *UnreachableIntrin =
290b8f8dbc2SMatt Arsenault         Intrinsic::getDeclaration(F.getParent(), Intrinsic::amdgcn_unreachable);
291b8f8dbc2SMatt Arsenault 
292b8f8dbc2SMatt Arsenault       // Insert a call to an intrinsic tracking that this is an unreachable
293b8f8dbc2SMatt Arsenault       // point, in case we want to kill the active lanes or something later.
294b8f8dbc2SMatt Arsenault       CallInst::Create(UnreachableIntrin, {}, "", UnreachableBlock);
295b8f8dbc2SMatt Arsenault 
296b8f8dbc2SMatt Arsenault       // Don't create a scalar trap. We would only want to trap if this code was
297b8f8dbc2SMatt Arsenault       // really reached, but a scalar trap would happen even if no lanes
298b8f8dbc2SMatt Arsenault       // actually reached here.
299b8f8dbc2SMatt Arsenault       ReturnInst::Create(F.getContext(), RetVal, UnreachableBlock);
300b8f8dbc2SMatt Arsenault       ReturningBlocks.push_back(UnreachableBlock);
30172e4da45SJay Foad       Changed = true;
302b8f8dbc2SMatt Arsenault     }
303b8f8dbc2SMatt Arsenault   }
304b8f8dbc2SMatt Arsenault 
3057c8b8063SRoman Lebedev   // FIXME: add PDT here once simplifycfg is ready.
3067c8b8063SRoman Lebedev   DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager);
3074b806473SRoman Lebedev   if (RequireAndPreserveDomTree)
3084b806473SRoman Lebedev     DTU.applyUpdates(Updates);
3094b806473SRoman Lebedev   Updates.clear();
3104b806473SRoman Lebedev 
311b8f8dbc2SMatt Arsenault   // Now handle return blocks.
312b8f8dbc2SMatt Arsenault   if (ReturningBlocks.empty())
31372e4da45SJay Foad     return Changed; // No blocks return
314b8f8dbc2SMatt Arsenault 
315d9b9fdd9SRuiling Song   if (ReturningBlocks.size() == 1)
31672e4da45SJay Foad     return Changed; // Already has a single return block
317b8f8dbc2SMatt Arsenault 
318d9b9fdd9SRuiling Song   unifyReturnBlockSet(F, DTU, ReturningBlocks, "UnifiedReturnBlock");
319b8f8dbc2SMatt Arsenault   return true;
320b8f8dbc2SMatt Arsenault }
321