xref: /freebsd-src/contrib/llvm-project/llvm/lib/CodeGen/UnreachableBlockElim.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- UnreachableBlockElim.cpp - Remove unreachable blocks for codegen --===//
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 //
90b57cec5SDimitry Andric // This pass is an extremely simple version of the SimplifyCFG pass.  Its sole
100b57cec5SDimitry Andric // job is to delete LLVM basic blocks that are not reachable from the entry
110b57cec5SDimitry Andric // node.  To do this, it performs a simple depth first traversal of the CFG,
120b57cec5SDimitry Andric // then deletes any unvisited nodes.
130b57cec5SDimitry Andric //
140b57cec5SDimitry Andric // Note that this pass is really a hack.  In particular, the instruction
150b57cec5SDimitry Andric // selectors for various targets should just not generate code for unreachable
160b57cec5SDimitry Andric // blocks.  Until LLVM has a more systematic way of defining instruction
170b57cec5SDimitry Andric // selectors, however, we cannot really expect them to handle additional
180b57cec5SDimitry Andric // complexity.
190b57cec5SDimitry Andric //
200b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric #include "llvm/CodeGen/UnreachableBlockElim.h"
230b57cec5SDimitry Andric #include "llvm/ADT/DepthFirstIterator.h"
240b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
250b57cec5SDimitry Andric #include "llvm/CodeGen/MachineDominators.h"
260b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
270b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
280b57cec5SDimitry Andric #include "llvm/CodeGen/MachineLoopInfo.h"
290b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
300b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h"
310b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
320b57cec5SDimitry Andric #include "llvm/IR/Dominators.h"
33480093f4SDimitry Andric #include "llvm/InitializePasses.h"
340b57cec5SDimitry Andric #include "llvm/Pass.h"
350b57cec5SDimitry Andric #include "llvm/Transforms/Utils/BasicBlockUtils.h"
360b57cec5SDimitry Andric using namespace llvm;
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric namespace {
390b57cec5SDimitry Andric class UnreachableBlockElimLegacyPass : public FunctionPass {
400b57cec5SDimitry Andric   bool runOnFunction(Function &F) override {
410b57cec5SDimitry Andric     return llvm::EliminateUnreachableBlocks(F);
420b57cec5SDimitry Andric   }
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric public:
450b57cec5SDimitry Andric   static char ID; // Pass identification, replacement for typeid
460b57cec5SDimitry Andric   UnreachableBlockElimLegacyPass() : FunctionPass(ID) {
470b57cec5SDimitry Andric     initializeUnreachableBlockElimLegacyPassPass(
480b57cec5SDimitry Andric         *PassRegistry::getPassRegistry());
490b57cec5SDimitry Andric   }
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
520b57cec5SDimitry Andric     AU.addPreserved<DominatorTreeWrapperPass>();
530b57cec5SDimitry Andric   }
540b57cec5SDimitry Andric };
550b57cec5SDimitry Andric }
560b57cec5SDimitry Andric char UnreachableBlockElimLegacyPass::ID = 0;
570b57cec5SDimitry Andric INITIALIZE_PASS(UnreachableBlockElimLegacyPass, "unreachableblockelim",
580b57cec5SDimitry Andric                 "Remove unreachable blocks from the CFG", false, false)
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric FunctionPass *llvm::createUnreachableBlockEliminationPass() {
610b57cec5SDimitry Andric   return new UnreachableBlockElimLegacyPass();
620b57cec5SDimitry Andric }
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric PreservedAnalyses UnreachableBlockElimPass::run(Function &F,
650b57cec5SDimitry Andric                                                 FunctionAnalysisManager &AM) {
660b57cec5SDimitry Andric   bool Changed = llvm::EliminateUnreachableBlocks(F);
670b57cec5SDimitry Andric   if (!Changed)
680b57cec5SDimitry Andric     return PreservedAnalyses::all();
690b57cec5SDimitry Andric   PreservedAnalyses PA;
700b57cec5SDimitry Andric   PA.preserve<DominatorTreeAnalysis>();
710b57cec5SDimitry Andric   return PA;
720b57cec5SDimitry Andric }
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric namespace {
750b57cec5SDimitry Andric   class UnreachableMachineBlockElim : public MachineFunctionPass {
760b57cec5SDimitry Andric     bool runOnMachineFunction(MachineFunction &F) override;
770b57cec5SDimitry Andric     void getAnalysisUsage(AnalysisUsage &AU) const override;
785ffd83dbSDimitry Andric 
790b57cec5SDimitry Andric   public:
800b57cec5SDimitry Andric     static char ID; // Pass identification, replacement for typeid
810b57cec5SDimitry Andric     UnreachableMachineBlockElim() : MachineFunctionPass(ID) {}
820b57cec5SDimitry Andric   };
830b57cec5SDimitry Andric }
840b57cec5SDimitry Andric char UnreachableMachineBlockElim::ID = 0;
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric INITIALIZE_PASS(UnreachableMachineBlockElim, "unreachable-mbb-elimination",
870b57cec5SDimitry Andric   "Remove unreachable machine basic blocks", false, false)
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric char &llvm::UnreachableMachineBlockElimID = UnreachableMachineBlockElim::ID;
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric void UnreachableMachineBlockElim::getAnalysisUsage(AnalysisUsage &AU) const {
92*0fca6ea1SDimitry Andric   AU.addPreserved<MachineLoopInfoWrapperPass>();
93*0fca6ea1SDimitry Andric   AU.addPreserved<MachineDominatorTreeWrapperPass>();
940b57cec5SDimitry Andric   MachineFunctionPass::getAnalysisUsage(AU);
950b57cec5SDimitry Andric }
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric bool UnreachableMachineBlockElim::runOnMachineFunction(MachineFunction &F) {
980b57cec5SDimitry Andric   df_iterator_default_set<MachineBasicBlock*> Reachable;
990b57cec5SDimitry Andric   bool ModifiedPHI = false;
1000b57cec5SDimitry Andric 
101*0fca6ea1SDimitry Andric   MachineDominatorTreeWrapperPass *MDTWrapper =
102*0fca6ea1SDimitry Andric       getAnalysisIfAvailable<MachineDominatorTreeWrapperPass>();
103*0fca6ea1SDimitry Andric   MachineDominatorTree *MDT = MDTWrapper ? &MDTWrapper->getDomTree() : nullptr;
104*0fca6ea1SDimitry Andric   MachineLoopInfoWrapperPass *MLIWrapper =
105*0fca6ea1SDimitry Andric       getAnalysisIfAvailable<MachineLoopInfoWrapperPass>();
106*0fca6ea1SDimitry Andric   MachineLoopInfo *MLI = MLIWrapper ? &MLIWrapper->getLI() : nullptr;
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric   // Mark all reachable blocks.
1090b57cec5SDimitry Andric   for (MachineBasicBlock *BB : depth_first_ext(&F, Reachable))
1100b57cec5SDimitry Andric     (void)BB/* Mark all reachable blocks */;
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric   // Loop over all dead blocks, remembering them and deleting all instructions
1130b57cec5SDimitry Andric   // in them.
1140b57cec5SDimitry Andric   std::vector<MachineBasicBlock*> DeadBlocks;
115fe6060f1SDimitry Andric   for (MachineBasicBlock &BB : F) {
1160b57cec5SDimitry Andric     // Test for deadness.
117fe6060f1SDimitry Andric     if (!Reachable.count(&BB)) {
118fe6060f1SDimitry Andric       DeadBlocks.push_back(&BB);
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric       // Update dominator and loop info.
121fe6060f1SDimitry Andric       if (MLI) MLI->removeBlock(&BB);
122fe6060f1SDimitry Andric       if (MDT && MDT->getNode(&BB)) MDT->eraseNode(&BB);
1230b57cec5SDimitry Andric 
1247a6dacacSDimitry Andric       while (!BB.succ_empty()) {
125fe6060f1SDimitry Andric         MachineBasicBlock* succ = *BB.succ_begin();
1260b57cec5SDimitry Andric 
12706c3fb27SDimitry Andric         for (MachineInstr &Phi : succ->phis()) {
12806c3fb27SDimitry Andric           for (unsigned i = Phi.getNumOperands() - 1; i >= 2; i -= 2) {
12906c3fb27SDimitry Andric             if (Phi.getOperand(i).isMBB() &&
13006c3fb27SDimitry Andric                 Phi.getOperand(i).getMBB() == &BB) {
13106c3fb27SDimitry Andric               Phi.removeOperand(i);
13206c3fb27SDimitry Andric               Phi.removeOperand(i - 1);
1330b57cec5SDimitry Andric             }
13406c3fb27SDimitry Andric           }
1350b57cec5SDimitry Andric         }
1360b57cec5SDimitry Andric 
137fe6060f1SDimitry Andric         BB.removeSuccessor(BB.succ_begin());
1380b57cec5SDimitry Andric       }
1390b57cec5SDimitry Andric     }
1400b57cec5SDimitry Andric   }
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric   // Actually remove the blocks now.
1430eae32dcSDimitry Andric   for (MachineBasicBlock *BB : DeadBlocks) {
1448bcb0991SDimitry Andric     // Remove any call site information for calls in the block.
1450eae32dcSDimitry Andric     for (auto &I : BB->instrs())
1465ffd83dbSDimitry Andric       if (I.shouldUpdateCallSiteInfo())
1470eae32dcSDimitry Andric         BB->getParent()->eraseCallSiteInfo(&I);
1488bcb0991SDimitry Andric 
1490eae32dcSDimitry Andric     BB->eraseFromParent();
1508bcb0991SDimitry Andric   }
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric   // Cleanup PHI nodes.
1530eae32dcSDimitry Andric   for (MachineBasicBlock &BB : F) {
1540b57cec5SDimitry Andric     // Prune unneeded PHI entries.
1550eae32dcSDimitry Andric     SmallPtrSet<MachineBasicBlock*, 8> preds(BB.pred_begin(),
1560eae32dcSDimitry Andric                                              BB.pred_end());
15706c3fb27SDimitry Andric     for (MachineInstr &Phi : make_early_inc_range(BB.phis())) {
15806c3fb27SDimitry Andric       for (unsigned i = Phi.getNumOperands() - 1; i >= 2; i -= 2) {
15906c3fb27SDimitry Andric         if (!preds.count(Phi.getOperand(i).getMBB())) {
16006c3fb27SDimitry Andric           Phi.removeOperand(i);
16106c3fb27SDimitry Andric           Phi.removeOperand(i - 1);
1620b57cec5SDimitry Andric           ModifiedPHI = true;
1630b57cec5SDimitry Andric         }
16406c3fb27SDimitry Andric       }
1650b57cec5SDimitry Andric 
16606c3fb27SDimitry Andric       if (Phi.getNumOperands() == 3) {
16706c3fb27SDimitry Andric         const MachineOperand &Input = Phi.getOperand(1);
16806c3fb27SDimitry Andric         const MachineOperand &Output = Phi.getOperand(0);
1698bcb0991SDimitry Andric         Register InputReg = Input.getReg();
1708bcb0991SDimitry Andric         Register OutputReg = Output.getReg();
1710b57cec5SDimitry Andric         assert(Output.getSubReg() == 0 && "Cannot have output subregister");
1720b57cec5SDimitry Andric         ModifiedPHI = true;
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric         if (InputReg != OutputReg) {
1750b57cec5SDimitry Andric           MachineRegisterInfo &MRI = F.getRegInfo();
1760b57cec5SDimitry Andric           unsigned InputSub = Input.getSubReg();
1770b57cec5SDimitry Andric           if (InputSub == 0 &&
1780b57cec5SDimitry Andric               MRI.constrainRegClass(InputReg, MRI.getRegClass(OutputReg)) &&
1790b57cec5SDimitry Andric               !Input.isUndef()) {
1800b57cec5SDimitry Andric             MRI.replaceRegWith(OutputReg, InputReg);
1810b57cec5SDimitry Andric           } else {
1820b57cec5SDimitry Andric             // The input register to the PHI has a subregister or it can't be
1830b57cec5SDimitry Andric             // constrained to the proper register class or it is undef:
1840b57cec5SDimitry Andric             // insert a COPY instead of simply replacing the output
1850b57cec5SDimitry Andric             // with the input.
1860b57cec5SDimitry Andric             const TargetInstrInfo *TII = F.getSubtarget().getInstrInfo();
18706c3fb27SDimitry Andric             BuildMI(BB, BB.getFirstNonPHI(), Phi.getDebugLoc(),
1880b57cec5SDimitry Andric                     TII->get(TargetOpcode::COPY), OutputReg)
1890b57cec5SDimitry Andric                 .addReg(InputReg, getRegState(Input), InputSub);
1900b57cec5SDimitry Andric           }
19106c3fb27SDimitry Andric           Phi.eraseFromParent();
1920b57cec5SDimitry Andric         }
1930b57cec5SDimitry Andric       }
1940b57cec5SDimitry Andric     }
1950b57cec5SDimitry Andric   }
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric   F.RenumberBlocks();
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric   return (!DeadBlocks.empty() || ModifiedPHI);
2000b57cec5SDimitry Andric }
201