xref: /aosp_15_r20/external/llvm/lib/Transforms/Utils/UnifyFunctionExitNodes.cpp (revision 9880d6810fe72a1726cb53787c6711e909410d58)
1*9880d681SAndroid Build Coastguard Worker //===- UnifyFunctionExitNodes.cpp - Make all functions have a single exit -===//
2*9880d681SAndroid Build Coastguard Worker //
3*9880d681SAndroid Build Coastguard Worker //                     The LLVM Compiler Infrastructure
4*9880d681SAndroid Build Coastguard Worker //
5*9880d681SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*9880d681SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*9880d681SAndroid Build Coastguard Worker //
8*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*9880d681SAndroid Build Coastguard Worker //
10*9880d681SAndroid Build Coastguard Worker // This pass is used to ensure that functions have at most one return
11*9880d681SAndroid Build Coastguard Worker // instruction in them.  Additionally, it keeps track of which node is the new
12*9880d681SAndroid Build Coastguard Worker // exit node of the CFG.  If there are no exit nodes in the CFG, the getExitNode
13*9880d681SAndroid Build Coastguard Worker // method will return a null pointer.
14*9880d681SAndroid Build Coastguard Worker //
15*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
16*9880d681SAndroid Build Coastguard Worker 
17*9880d681SAndroid Build Coastguard Worker #include "llvm/Transforms/Utils/UnifyFunctionExitNodes.h"
18*9880d681SAndroid Build Coastguard Worker #include "llvm/ADT/StringExtras.h"
19*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/BasicBlock.h"
20*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/Function.h"
21*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/Instructions.h"
22*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/Type.h"
23*9880d681SAndroid Build Coastguard Worker #include "llvm/Transforms/Scalar.h"
24*9880d681SAndroid Build Coastguard Worker using namespace llvm;
25*9880d681SAndroid Build Coastguard Worker 
26*9880d681SAndroid Build Coastguard Worker char UnifyFunctionExitNodes::ID = 0;
27*9880d681SAndroid Build Coastguard Worker INITIALIZE_PASS(UnifyFunctionExitNodes, "mergereturn",
28*9880d681SAndroid Build Coastguard Worker                 "Unify function exit nodes", false, false)
29*9880d681SAndroid Build Coastguard Worker 
createUnifyFunctionExitNodesPass()30*9880d681SAndroid Build Coastguard Worker Pass *llvm::createUnifyFunctionExitNodesPass() {
31*9880d681SAndroid Build Coastguard Worker   return new UnifyFunctionExitNodes();
32*9880d681SAndroid Build Coastguard Worker }
33*9880d681SAndroid Build Coastguard Worker 
getAnalysisUsage(AnalysisUsage & AU) const34*9880d681SAndroid Build Coastguard Worker void UnifyFunctionExitNodes::getAnalysisUsage(AnalysisUsage &AU) const{
35*9880d681SAndroid Build Coastguard Worker   // We preserve the non-critical-edgeness property
36*9880d681SAndroid Build Coastguard Worker   AU.addPreservedID(BreakCriticalEdgesID);
37*9880d681SAndroid Build Coastguard Worker   // This is a cluster of orthogonal Transforms
38*9880d681SAndroid Build Coastguard Worker   AU.addPreservedID(LowerSwitchID);
39*9880d681SAndroid Build Coastguard Worker }
40*9880d681SAndroid Build Coastguard Worker 
41*9880d681SAndroid Build Coastguard Worker // UnifyAllExitNodes - Unify all exit nodes of the CFG by creating a new
42*9880d681SAndroid Build Coastguard Worker // BasicBlock, and converting all returns to unconditional branches to this
43*9880d681SAndroid Build Coastguard Worker // new basic block.  The singular exit node is returned.
44*9880d681SAndroid Build Coastguard Worker //
45*9880d681SAndroid Build Coastguard Worker // If there are no return stmts in the Function, a null pointer is returned.
46*9880d681SAndroid Build Coastguard Worker //
runOnFunction(Function & F)47*9880d681SAndroid Build Coastguard Worker bool UnifyFunctionExitNodes::runOnFunction(Function &F) {
48*9880d681SAndroid Build Coastguard Worker   // Loop over all of the blocks in a function, tracking all of the blocks that
49*9880d681SAndroid Build Coastguard Worker   // return.
50*9880d681SAndroid Build Coastguard Worker   //
51*9880d681SAndroid Build Coastguard Worker   std::vector<BasicBlock*> ReturningBlocks;
52*9880d681SAndroid Build Coastguard Worker   std::vector<BasicBlock*> UnreachableBlocks;
53*9880d681SAndroid Build Coastguard Worker   for (BasicBlock &I : F)
54*9880d681SAndroid Build Coastguard Worker     if (isa<ReturnInst>(I.getTerminator()))
55*9880d681SAndroid Build Coastguard Worker       ReturningBlocks.push_back(&I);
56*9880d681SAndroid Build Coastguard Worker     else if (isa<UnreachableInst>(I.getTerminator()))
57*9880d681SAndroid Build Coastguard Worker       UnreachableBlocks.push_back(&I);
58*9880d681SAndroid Build Coastguard Worker 
59*9880d681SAndroid Build Coastguard Worker   // Then unreachable blocks.
60*9880d681SAndroid Build Coastguard Worker   if (UnreachableBlocks.empty()) {
61*9880d681SAndroid Build Coastguard Worker     UnreachableBlock = nullptr;
62*9880d681SAndroid Build Coastguard Worker   } else if (UnreachableBlocks.size() == 1) {
63*9880d681SAndroid Build Coastguard Worker     UnreachableBlock = UnreachableBlocks.front();
64*9880d681SAndroid Build Coastguard Worker   } else {
65*9880d681SAndroid Build Coastguard Worker     UnreachableBlock = BasicBlock::Create(F.getContext(),
66*9880d681SAndroid Build Coastguard Worker                                           "UnifiedUnreachableBlock", &F);
67*9880d681SAndroid Build Coastguard Worker     new UnreachableInst(F.getContext(), UnreachableBlock);
68*9880d681SAndroid Build Coastguard Worker 
69*9880d681SAndroid Build Coastguard Worker     for (BasicBlock *BB : UnreachableBlocks) {
70*9880d681SAndroid Build Coastguard Worker       BB->getInstList().pop_back();  // Remove the unreachable inst.
71*9880d681SAndroid Build Coastguard Worker       BranchInst::Create(UnreachableBlock, BB);
72*9880d681SAndroid Build Coastguard Worker     }
73*9880d681SAndroid Build Coastguard Worker   }
74*9880d681SAndroid Build Coastguard Worker 
75*9880d681SAndroid Build Coastguard Worker   // Now handle return blocks.
76*9880d681SAndroid Build Coastguard Worker   if (ReturningBlocks.empty()) {
77*9880d681SAndroid Build Coastguard Worker     ReturnBlock = nullptr;
78*9880d681SAndroid Build Coastguard Worker     return false;                          // No blocks return
79*9880d681SAndroid Build Coastguard Worker   } else if (ReturningBlocks.size() == 1) {
80*9880d681SAndroid Build Coastguard Worker     ReturnBlock = ReturningBlocks.front(); // Already has a single return block
81*9880d681SAndroid Build Coastguard Worker     return false;
82*9880d681SAndroid Build Coastguard Worker   }
83*9880d681SAndroid Build Coastguard Worker 
84*9880d681SAndroid Build Coastguard Worker   // Otherwise, we need to insert a new basic block into the function, add a PHI
85*9880d681SAndroid Build Coastguard Worker   // nodes (if the function returns values), and convert all of the return
86*9880d681SAndroid Build Coastguard Worker   // instructions into unconditional branches.
87*9880d681SAndroid Build Coastguard Worker   //
88*9880d681SAndroid Build Coastguard Worker   BasicBlock *NewRetBlock = BasicBlock::Create(F.getContext(),
89*9880d681SAndroid Build Coastguard Worker                                                "UnifiedReturnBlock", &F);
90*9880d681SAndroid Build Coastguard Worker 
91*9880d681SAndroid Build Coastguard Worker   PHINode *PN = nullptr;
92*9880d681SAndroid Build Coastguard Worker   if (F.getReturnType()->isVoidTy()) {
93*9880d681SAndroid Build Coastguard Worker     ReturnInst::Create(F.getContext(), nullptr, NewRetBlock);
94*9880d681SAndroid Build Coastguard Worker   } else {
95*9880d681SAndroid Build Coastguard Worker     // If the function doesn't return void... add a PHI node to the block...
96*9880d681SAndroid Build Coastguard Worker     PN = PHINode::Create(F.getReturnType(), ReturningBlocks.size(),
97*9880d681SAndroid Build Coastguard Worker                          "UnifiedRetVal");
98*9880d681SAndroid Build Coastguard Worker     NewRetBlock->getInstList().push_back(PN);
99*9880d681SAndroid Build Coastguard Worker     ReturnInst::Create(F.getContext(), PN, NewRetBlock);
100*9880d681SAndroid Build Coastguard Worker   }
101*9880d681SAndroid Build Coastguard Worker 
102*9880d681SAndroid Build Coastguard Worker   // Loop over all of the blocks, replacing the return instruction with an
103*9880d681SAndroid Build Coastguard Worker   // unconditional branch.
104*9880d681SAndroid Build Coastguard Worker   //
105*9880d681SAndroid Build Coastguard Worker   for (BasicBlock *BB : ReturningBlocks) {
106*9880d681SAndroid Build Coastguard Worker     // Add an incoming element to the PHI node for every return instruction that
107*9880d681SAndroid Build Coastguard Worker     // is merging into this new block...
108*9880d681SAndroid Build Coastguard Worker     if (PN)
109*9880d681SAndroid Build Coastguard Worker       PN->addIncoming(BB->getTerminator()->getOperand(0), BB);
110*9880d681SAndroid Build Coastguard Worker 
111*9880d681SAndroid Build Coastguard Worker     BB->getInstList().pop_back();  // Remove the return insn
112*9880d681SAndroid Build Coastguard Worker     BranchInst::Create(NewRetBlock, BB);
113*9880d681SAndroid Build Coastguard Worker   }
114*9880d681SAndroid Build Coastguard Worker   ReturnBlock = NewRetBlock;
115*9880d681SAndroid Build Coastguard Worker   return true;
116*9880d681SAndroid Build Coastguard Worker }
117