xref: /freebsd/contrib/llvm-project/llvm/lib/CodeGen/GCEmptyBasicBlocks.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
1*5f757f3fSDimitry Andric //===-- GCEmptyBasicBlocks.cpp ----------------------------------*- C++ -*-===//
2*5f757f3fSDimitry Andric //
3*5f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*5f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*5f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*5f757f3fSDimitry Andric //
7*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
8*5f757f3fSDimitry Andric ///
9*5f757f3fSDimitry Andric /// \file
10*5f757f3fSDimitry Andric /// This file contains the implementation of empty blocks garbage collection
11*5f757f3fSDimitry Andric /// pass.
12*5f757f3fSDimitry Andric ///
13*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
14*5f757f3fSDimitry Andric #include "llvm/ADT/SmallVector.h"
15*5f757f3fSDimitry Andric #include "llvm/ADT/Statistic.h"
16*5f757f3fSDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
17*5f757f3fSDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
18*5f757f3fSDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
19*5f757f3fSDimitry Andric #include "llvm/CodeGen/MachineJumpTableInfo.h"
20*5f757f3fSDimitry Andric #include "llvm/CodeGen/Passes.h"
21*5f757f3fSDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
22*5f757f3fSDimitry Andric #include "llvm/InitializePasses.h"
23*5f757f3fSDimitry Andric 
24*5f757f3fSDimitry Andric using namespace llvm;
25*5f757f3fSDimitry Andric 
26*5f757f3fSDimitry Andric #define DEBUG_TYPE "gc-empty-basic-blocks"
27*5f757f3fSDimitry Andric 
28*5f757f3fSDimitry Andric STATISTIC(NumEmptyBlocksRemoved, "Number of empty blocks removed");
29*5f757f3fSDimitry Andric 
30*5f757f3fSDimitry Andric class GCEmptyBasicBlocks : public MachineFunctionPass {
31*5f757f3fSDimitry Andric public:
32*5f757f3fSDimitry Andric   static char ID;
33*5f757f3fSDimitry Andric 
34*5f757f3fSDimitry Andric   GCEmptyBasicBlocks() : MachineFunctionPass(ID) {
35*5f757f3fSDimitry Andric     initializeGCEmptyBasicBlocksPass(*PassRegistry::getPassRegistry());
36*5f757f3fSDimitry Andric   }
37*5f757f3fSDimitry Andric 
38*5f757f3fSDimitry Andric   StringRef getPassName() const override {
39*5f757f3fSDimitry Andric     return "Remove Empty Basic Blocks.";
40*5f757f3fSDimitry Andric   }
41*5f757f3fSDimitry Andric 
42*5f757f3fSDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
43*5f757f3fSDimitry Andric };
44*5f757f3fSDimitry Andric 
45*5f757f3fSDimitry Andric bool GCEmptyBasicBlocks::runOnMachineFunction(MachineFunction &MF) {
46*5f757f3fSDimitry Andric   if (MF.size() < 2)
47*5f757f3fSDimitry Andric     return false;
48*5f757f3fSDimitry Andric   MachineJumpTableInfo *JTI = MF.getJumpTableInfo();
49*5f757f3fSDimitry Andric   int NumRemoved = 0;
50*5f757f3fSDimitry Andric 
51*5f757f3fSDimitry Andric   // Iterate over all blocks except the last one. We can't remove the last block
52*5f757f3fSDimitry Andric   // since it has no fallthrough block to rewire its predecessors to.
53*5f757f3fSDimitry Andric   for (MachineFunction::iterator MBB = MF.begin(),
54*5f757f3fSDimitry Andric                                  LastMBB = MachineFunction::iterator(MF.back()),
55*5f757f3fSDimitry Andric                                  NextMBB;
56*5f757f3fSDimitry Andric        MBB != LastMBB; MBB = NextMBB) {
57*5f757f3fSDimitry Andric     NextMBB = std::next(MBB);
58*5f757f3fSDimitry Andric     // TODO If a block is an eh pad, or it has address taken, we don't remove
59*5f757f3fSDimitry Andric     // it. Removing such blocks is possible, but it probably requires a more
60*5f757f3fSDimitry Andric     // complex logic.
61*5f757f3fSDimitry Andric     if (MBB->isEHPad() || MBB->hasAddressTaken())
62*5f757f3fSDimitry Andric       continue;
63*5f757f3fSDimitry Andric     // Skip blocks with real code.
64*5f757f3fSDimitry Andric     bool HasAnyRealCode = llvm::any_of(*MBB, [](const MachineInstr &MI) {
65*5f757f3fSDimitry Andric       return !MI.isPosition() && !MI.isImplicitDef() && !MI.isKill() &&
66*5f757f3fSDimitry Andric              !MI.isDebugInstr();
67*5f757f3fSDimitry Andric     });
68*5f757f3fSDimitry Andric     if (HasAnyRealCode)
69*5f757f3fSDimitry Andric       continue;
70*5f757f3fSDimitry Andric 
71*5f757f3fSDimitry Andric     LLVM_DEBUG(dbgs() << "Removing basic block " << MBB->getName()
72*5f757f3fSDimitry Andric                       << " in function " << MF.getName() << ":\n"
73*5f757f3fSDimitry Andric                       << *MBB << "\n");
74*5f757f3fSDimitry Andric     SmallVector<MachineBasicBlock *, 8> Preds(MBB->predecessors());
75*5f757f3fSDimitry Andric     // Rewire the predecessors of this block to use the next block.
76*5f757f3fSDimitry Andric     for (auto &Pred : Preds)
77*5f757f3fSDimitry Andric       Pred->ReplaceUsesOfBlockWith(&*MBB, &*NextMBB);
78*5f757f3fSDimitry Andric     // Update the jump tables.
79*5f757f3fSDimitry Andric     if (JTI)
80*5f757f3fSDimitry Andric       JTI->ReplaceMBBInJumpTables(&*MBB, &*NextMBB);
81*5f757f3fSDimitry Andric     // Remove this block from predecessors of all its successors.
82*5f757f3fSDimitry Andric     while (!MBB->succ_empty())
83*5f757f3fSDimitry Andric       MBB->removeSuccessor(MBB->succ_end() - 1);
84*5f757f3fSDimitry Andric     // Finally, remove the block from the function.
85*5f757f3fSDimitry Andric     MBB->eraseFromParent();
86*5f757f3fSDimitry Andric     ++NumRemoved;
87*5f757f3fSDimitry Andric   }
88*5f757f3fSDimitry Andric   NumEmptyBlocksRemoved += NumRemoved;
89*5f757f3fSDimitry Andric   return NumRemoved != 0;
90*5f757f3fSDimitry Andric }
91*5f757f3fSDimitry Andric 
92*5f757f3fSDimitry Andric char GCEmptyBasicBlocks::ID = 0;
93*5f757f3fSDimitry Andric INITIALIZE_PASS(GCEmptyBasicBlocks, "gc-empty-basic-blocks",
94*5f757f3fSDimitry Andric                 "Removes empty basic blocks and redirects their uses to their "
95*5f757f3fSDimitry Andric                 "fallthrough blocks.",
96*5f757f3fSDimitry Andric                 false, false)
97*5f757f3fSDimitry Andric 
98*5f757f3fSDimitry Andric MachineFunctionPass *llvm::createGCEmptyBasicBlocksPass() {
99*5f757f3fSDimitry Andric   return new GCEmptyBasicBlocks();
100*5f757f3fSDimitry Andric }
101