1 | //===- UnifyFunctionExitNodes.cpp - Make all functions have a single exit -===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This pass is used to ensure that functions have at most one return and one |
10 | // unreachable instruction in them. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "llvm/Transforms/Utils/UnifyFunctionExitNodes.h" |
15 | #include "llvm/IR/BasicBlock.h" |
16 | #include "llvm/IR/Function.h" |
17 | #include "llvm/IR/Instructions.h" |
18 | #include "llvm/IR/Type.h" |
19 | #include "llvm/Transforms/Utils.h" |
20 | using namespace llvm; |
21 | |
22 | namespace { |
23 | |
24 | bool unifyUnreachableBlocks(Function &F) { |
25 | std::vector<BasicBlock *> UnreachableBlocks; |
26 | |
27 | for (BasicBlock &I : F) |
28 | if (isa<UnreachableInst>(Val: I.getTerminator())) |
29 | UnreachableBlocks.push_back(x: &I); |
30 | |
31 | if (UnreachableBlocks.size() <= 1) |
32 | return false; |
33 | |
34 | BasicBlock *UnreachableBlock = |
35 | BasicBlock::Create(Context&: F.getContext(), Name: "UnifiedUnreachableBlock" , Parent: &F); |
36 | new UnreachableInst(F.getContext(), UnreachableBlock); |
37 | |
38 | for (BasicBlock *BB : UnreachableBlocks) { |
39 | BB->back().eraseFromParent(); // Remove the unreachable inst. |
40 | BranchInst::Create(IfTrue: UnreachableBlock, InsertBefore: BB); |
41 | } |
42 | |
43 | return true; |
44 | } |
45 | |
46 | bool unifyReturnBlocks(Function &F) { |
47 | std::vector<BasicBlock *> ReturningBlocks; |
48 | |
49 | for (BasicBlock &I : F) |
50 | if (isa<ReturnInst>(Val: I.getTerminator())) |
51 | ReturningBlocks.push_back(x: &I); |
52 | |
53 | if (ReturningBlocks.size() <= 1) |
54 | return false; |
55 | |
56 | // Insert a new basic block into the function, add PHI nodes (if the function |
57 | // returns values), and convert all of the return instructions into |
58 | // unconditional branches. |
59 | BasicBlock *NewRetBlock = BasicBlock::Create(Context&: F.getContext(), |
60 | Name: "UnifiedReturnBlock" , Parent: &F); |
61 | |
62 | PHINode *PN = nullptr; |
63 | if (F.getReturnType()->isVoidTy()) { |
64 | ReturnInst::Create(C&: F.getContext(), retVal: nullptr, InsertBefore: NewRetBlock); |
65 | } else { |
66 | // If the function doesn't return void... add a PHI node to the block... |
67 | PN = PHINode::Create(Ty: F.getReturnType(), NumReservedValues: ReturningBlocks.size(), |
68 | NameStr: "UnifiedRetVal" ); |
69 | PN->insertInto(ParentBB: NewRetBlock, It: NewRetBlock->end()); |
70 | ReturnInst::Create(C&: F.getContext(), retVal: PN, InsertBefore: NewRetBlock); |
71 | } |
72 | |
73 | // Loop over all of the blocks, replacing the return instruction with an |
74 | // unconditional branch. |
75 | for (BasicBlock *BB : ReturningBlocks) { |
76 | // Add an incoming element to the PHI node for every return instruction that |
77 | // is merging into this new block... |
78 | if (PN) |
79 | PN->addIncoming(V: BB->getTerminator()->getOperand(i: 0), BB); |
80 | |
81 | BB->back().eraseFromParent(); // Remove the return insn |
82 | BranchInst::Create(IfTrue: NewRetBlock, InsertBefore: BB); |
83 | } |
84 | |
85 | return true; |
86 | } |
87 | } // namespace |
88 | |
89 | PreservedAnalyses UnifyFunctionExitNodesPass::run(Function &F, |
90 | FunctionAnalysisManager &AM) { |
91 | bool Changed = false; |
92 | Changed |= unifyUnreachableBlocks(F); |
93 | Changed |= unifyReturnBlocks(F); |
94 | return Changed ? PreservedAnalyses() : PreservedAnalyses::all(); |
95 | } |
96 | |