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