xref: /src/contrib/llvm-project/llvm/lib/Transforms/Utils/UnifyFunctionExitNodes.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
1009b1c42SEd Schouten //===- UnifyFunctionExitNodes.cpp - Make all functions have a single exit -===//
2009b1c42SEd Schouten //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6009b1c42SEd Schouten //
7009b1c42SEd Schouten //===----------------------------------------------------------------------===//
8009b1c42SEd Schouten //
9b60736ecSDimitry Andric // This pass is used to ensure that functions have at most one return and one
10b60736ecSDimitry Andric // unreachable instruction in them.
11009b1c42SEd Schouten //
12009b1c42SEd Schouten //===----------------------------------------------------------------------===//
13009b1c42SEd Schouten 
14009b1c42SEd Schouten #include "llvm/Transforms/Utils/UnifyFunctionExitNodes.h"
154a16efa3SDimitry Andric #include "llvm/IR/BasicBlock.h"
164a16efa3SDimitry Andric #include "llvm/IR/Function.h"
174a16efa3SDimitry Andric #include "llvm/IR/Instructions.h"
184a16efa3SDimitry Andric #include "llvm/IR/Type.h"
19eb11fae6SDimitry Andric #include "llvm/Transforms/Utils.h"
20009b1c42SEd Schouten using namespace llvm;
21009b1c42SEd Schouten 
22b60736ecSDimitry Andric namespace {
23b60736ecSDimitry Andric 
unifyUnreachableBlocks(Function & F)24b60736ecSDimitry Andric bool unifyUnreachableBlocks(Function &F) {
25009b1c42SEd Schouten   std::vector<BasicBlock *> UnreachableBlocks;
26b60736ecSDimitry Andric 
27dd58ef01SDimitry Andric   for (BasicBlock &I : F)
28b60736ecSDimitry Andric     if (isa<UnreachableInst>(I.getTerminator()))
29dd58ef01SDimitry Andric       UnreachableBlocks.push_back(&I);
30009b1c42SEd Schouten 
31b60736ecSDimitry Andric   if (UnreachableBlocks.size() <= 1)
32b60736ecSDimitry Andric     return false;
33b60736ecSDimitry Andric 
34b60736ecSDimitry Andric   BasicBlock *UnreachableBlock =
35b60736ecSDimitry Andric       BasicBlock::Create(F.getContext(), "UnifiedUnreachableBlock", &F);
3659850d08SRoman Divacky   new UnreachableInst(F.getContext(), UnreachableBlock);
37009b1c42SEd Schouten 
3801095a5dSDimitry Andric   for (BasicBlock *BB : UnreachableBlocks) {
39e3b55780SDimitry Andric     BB->back().eraseFromParent(); // Remove the unreachable inst.
40009b1c42SEd Schouten     BranchInst::Create(UnreachableBlock, BB);
41009b1c42SEd Schouten   }
42b60736ecSDimitry Andric 
43b60736ecSDimitry Andric   return true;
44009b1c42SEd Schouten }
45009b1c42SEd Schouten 
unifyReturnBlocks(Function & F)46b60736ecSDimitry Andric bool unifyReturnBlocks(Function &F) {
47b60736ecSDimitry Andric   std::vector<BasicBlock *> ReturningBlocks;
48b60736ecSDimitry Andric 
49b60736ecSDimitry Andric   for (BasicBlock &I : F)
50b60736ecSDimitry Andric     if (isa<ReturnInst>(I.getTerminator()))
51b60736ecSDimitry Andric       ReturningBlocks.push_back(&I);
52b60736ecSDimitry Andric 
53b60736ecSDimitry Andric   if (ReturningBlocks.size() <= 1)
54009b1c42SEd Schouten     return false;
55009b1c42SEd Schouten 
56b60736ecSDimitry Andric   // Insert a new basic block into the function, add PHI nodes (if the function
57b60736ecSDimitry Andric   // returns values), and convert all of the return instructions into
58b60736ecSDimitry Andric   // unconditional branches.
5959850d08SRoman Divacky   BasicBlock *NewRetBlock = BasicBlock::Create(F.getContext(),
6059850d08SRoman Divacky                                                "UnifiedReturnBlock", &F);
61009b1c42SEd Schouten 
625ca98fd9SDimitry Andric   PHINode *PN = nullptr;
63829000e0SRoman Divacky   if (F.getReturnType()->isVoidTy()) {
645ca98fd9SDimitry Andric     ReturnInst::Create(F.getContext(), nullptr, NewRetBlock);
65009b1c42SEd Schouten   } else {
66009b1c42SEd Schouten     // If the function doesn't return void... add a PHI node to the block...
676b943ff3SDimitry Andric     PN = PHINode::Create(F.getReturnType(), ReturningBlocks.size(),
686b943ff3SDimitry Andric                          "UnifiedRetVal");
69e3b55780SDimitry Andric     PN->insertInto(NewRetBlock, NewRetBlock->end());
7059850d08SRoman Divacky     ReturnInst::Create(F.getContext(), PN, NewRetBlock);
71009b1c42SEd Schouten   }
72009b1c42SEd Schouten 
73009b1c42SEd Schouten   // Loop over all of the blocks, replacing the return instruction with an
74009b1c42SEd Schouten   // unconditional branch.
7501095a5dSDimitry Andric   for (BasicBlock *BB : ReturningBlocks) {
76009b1c42SEd Schouten     // Add an incoming element to the PHI node for every return instruction that
77009b1c42SEd Schouten     // is merging into this new block...
78009b1c42SEd Schouten     if (PN)
79009b1c42SEd Schouten       PN->addIncoming(BB->getTerminator()->getOperand(0), BB);
80009b1c42SEd Schouten 
81e3b55780SDimitry Andric     BB->back().eraseFromParent(); // Remove the return insn
82009b1c42SEd Schouten     BranchInst::Create(NewRetBlock, BB);
83009b1c42SEd Schouten   }
84b60736ecSDimitry Andric 
85009b1c42SEd Schouten   return true;
86009b1c42SEd Schouten }
87b60736ecSDimitry Andric } // namespace
88b60736ecSDimitry Andric 
run(Function & F,FunctionAnalysisManager & AM)89b60736ecSDimitry Andric PreservedAnalyses UnifyFunctionExitNodesPass::run(Function &F,
90b60736ecSDimitry Andric                                                   FunctionAnalysisManager &AM) {
91b60736ecSDimitry Andric   bool Changed = false;
92b60736ecSDimitry Andric   Changed |= unifyUnreachableBlocks(F);
93b60736ecSDimitry Andric   Changed |= unifyReturnBlocks(F);
94b60736ecSDimitry Andric   return Changed ? PreservedAnalyses() : PreservedAnalyses::all();
95b60736ecSDimitry Andric }
96