10b57cec5SDimitry Andric //===- UnifyFunctionExitNodes.cpp - Make all functions have a single exit -===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 9e8d8bef9SDimitry Andric // This pass is used to ensure that functions have at most one return and one 10e8d8bef9SDimitry Andric // unreachable instruction in them. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "llvm/Transforms/Utils/UnifyFunctionExitNodes.h" 150b57cec5SDimitry Andric #include "llvm/IR/BasicBlock.h" 160b57cec5SDimitry Andric #include "llvm/IR/Function.h" 170b57cec5SDimitry Andric #include "llvm/IR/Instructions.h" 180b57cec5SDimitry Andric #include "llvm/IR/Type.h" 190b57cec5SDimitry Andric #include "llvm/Transforms/Utils.h" 200b57cec5SDimitry Andric using namespace llvm; 210b57cec5SDimitry Andric 22e8d8bef9SDimitry Andric namespace { 23e8d8bef9SDimitry Andric 24e8d8bef9SDimitry Andric bool unifyUnreachableBlocks(Function &F) { 250b57cec5SDimitry Andric std::vector<BasicBlock *> UnreachableBlocks; 26e8d8bef9SDimitry Andric 270b57cec5SDimitry Andric for (BasicBlock &I : F) 28e8d8bef9SDimitry Andric if (isa<UnreachableInst>(I.getTerminator())) 290b57cec5SDimitry Andric UnreachableBlocks.push_back(&I); 300b57cec5SDimitry Andric 31e8d8bef9SDimitry Andric if (UnreachableBlocks.size() <= 1) 32e8d8bef9SDimitry Andric return false; 33e8d8bef9SDimitry Andric 34e8d8bef9SDimitry Andric BasicBlock *UnreachableBlock = 35e8d8bef9SDimitry Andric BasicBlock::Create(F.getContext(), "UnifiedUnreachableBlock", &F); 360b57cec5SDimitry Andric new UnreachableInst(F.getContext(), UnreachableBlock); 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric for (BasicBlock *BB : UnreachableBlocks) { 39*bdd1243dSDimitry Andric BB->back().eraseFromParent(); // Remove the unreachable inst. 400b57cec5SDimitry Andric BranchInst::Create(UnreachableBlock, BB); 410b57cec5SDimitry Andric } 42e8d8bef9SDimitry Andric 43e8d8bef9SDimitry Andric return true; 440b57cec5SDimitry Andric } 450b57cec5SDimitry Andric 46e8d8bef9SDimitry Andric bool unifyReturnBlocks(Function &F) { 47e8d8bef9SDimitry Andric std::vector<BasicBlock *> ReturningBlocks; 48e8d8bef9SDimitry Andric 49e8d8bef9SDimitry Andric for (BasicBlock &I : F) 50e8d8bef9SDimitry Andric if (isa<ReturnInst>(I.getTerminator())) 51e8d8bef9SDimitry Andric ReturningBlocks.push_back(&I); 52e8d8bef9SDimitry Andric 53e8d8bef9SDimitry Andric if (ReturningBlocks.size() <= 1) 540b57cec5SDimitry Andric return false; 550b57cec5SDimitry Andric 56e8d8bef9SDimitry Andric // Insert a new basic block into the function, add PHI nodes (if the function 57e8d8bef9SDimitry Andric // returns values), and convert all of the return instructions into 58e8d8bef9SDimitry Andric // unconditional branches. 590b57cec5SDimitry Andric BasicBlock *NewRetBlock = BasicBlock::Create(F.getContext(), 600b57cec5SDimitry Andric "UnifiedReturnBlock", &F); 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric PHINode *PN = nullptr; 630b57cec5SDimitry Andric if (F.getReturnType()->isVoidTy()) { 640b57cec5SDimitry Andric ReturnInst::Create(F.getContext(), nullptr, NewRetBlock); 650b57cec5SDimitry Andric } else { 660b57cec5SDimitry Andric // If the function doesn't return void... add a PHI node to the block... 670b57cec5SDimitry Andric PN = PHINode::Create(F.getReturnType(), ReturningBlocks.size(), 680b57cec5SDimitry Andric "UnifiedRetVal"); 69*bdd1243dSDimitry Andric PN->insertInto(NewRetBlock, NewRetBlock->end()); 700b57cec5SDimitry Andric ReturnInst::Create(F.getContext(), PN, NewRetBlock); 710b57cec5SDimitry Andric } 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric // Loop over all of the blocks, replacing the return instruction with an 740b57cec5SDimitry Andric // unconditional branch. 750b57cec5SDimitry Andric for (BasicBlock *BB : ReturningBlocks) { 760b57cec5SDimitry Andric // Add an incoming element to the PHI node for every return instruction that 770b57cec5SDimitry Andric // is merging into this new block... 780b57cec5SDimitry Andric if (PN) 790b57cec5SDimitry Andric PN->addIncoming(BB->getTerminator()->getOperand(0), BB); 800b57cec5SDimitry Andric 81*bdd1243dSDimitry Andric BB->back().eraseFromParent(); // Remove the return insn 820b57cec5SDimitry Andric BranchInst::Create(NewRetBlock, BB); 830b57cec5SDimitry Andric } 84e8d8bef9SDimitry Andric 850b57cec5SDimitry Andric return true; 860b57cec5SDimitry Andric } 87e8d8bef9SDimitry Andric } // namespace 88e8d8bef9SDimitry Andric 89e8d8bef9SDimitry Andric PreservedAnalyses UnifyFunctionExitNodesPass::run(Function &F, 90e8d8bef9SDimitry Andric FunctionAnalysisManager &AM) { 91e8d8bef9SDimitry Andric bool Changed = false; 92e8d8bef9SDimitry Andric Changed |= unifyUnreachableBlocks(F); 93e8d8bef9SDimitry Andric Changed |= unifyReturnBlocks(F); 94e8d8bef9SDimitry Andric return Changed ? PreservedAnalyses() : PreservedAnalyses::all(); 95e8d8bef9SDimitry Andric } 96