aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/CodeGen/GCEmptyBasicBlocks.cpp
blob: 598be26e40c8e9a77a45ed4c8964766827c41bf1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
//===-- GCEmptyBasicBlocks.cpp ----------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file contains the implementation of empty blocks garbage collection
/// pass.
///
//===----------------------------------------------------------------------===//
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineJumpTableInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/InitializePasses.h"

using namespace llvm;

#define DEBUG_TYPE "gc-empty-basic-blocks"

STATISTIC(NumEmptyBlocksRemoved, "Number of empty blocks removed");

class GCEmptyBasicBlocks : public MachineFunctionPass {
public:
  static char ID;

  GCEmptyBasicBlocks() : MachineFunctionPass(ID) {
    initializeGCEmptyBasicBlocksPass(*PassRegistry::getPassRegistry());
  }

  StringRef getPassName() const override {
    return "Remove Empty Basic Blocks.";
  }

  bool runOnMachineFunction(MachineFunction &MF) override;
};

bool GCEmptyBasicBlocks::runOnMachineFunction(MachineFunction &MF) {
  if (MF.size() < 2)
    return false;
  MachineJumpTableInfo *JTI = MF.getJumpTableInfo();
  int NumRemoved = 0;

  // Iterate over all blocks except the last one. We can't remove the last block
  // since it has no fallthrough block to rewire its predecessors to.
  for (MachineFunction::iterator MBB = MF.begin(),
                                 LastMBB = MachineFunction::iterator(MF.back()),
                                 NextMBB;
       MBB != LastMBB; MBB = NextMBB) {
    NextMBB = std::next(MBB);
    // TODO If a block is an eh pad, or it has address taken, we don't remove
    // it. Removing such blocks is possible, but it probably requires a more
    // complex logic.
    if (MBB->isEHPad() || MBB->hasAddressTaken())
      continue;
    // Skip blocks with real code.
    bool HasAnyRealCode = llvm::any_of(*MBB, [](const MachineInstr &MI) {
      return !MI.isPosition() && !MI.isImplicitDef() && !MI.isKill() &&
             !MI.isDebugInstr();
    });
    if (HasAnyRealCode)
      continue;

    LLVM_DEBUG(dbgs() << "Removing basic block " << MBB->getName()
                      << " in function " << MF.getName() << ":\n"
                      << *MBB << "\n");
    SmallVector<MachineBasicBlock *, 8> Preds(MBB->predecessors());
    // Rewire the predecessors of this block to use the next block.
    for (auto &Pred : Preds)
      Pred->ReplaceUsesOfBlockWith(&*MBB, &*NextMBB);
    // Update the jump tables.
    if (JTI)
      JTI->ReplaceMBBInJumpTables(&*MBB, &*NextMBB);
    // Remove this block from predecessors of all its successors.
    while (!MBB->succ_empty())
      MBB->removeSuccessor(MBB->succ_end() - 1);
    // Finally, remove the block from the function.
    MBB->eraseFromParent();
    ++NumRemoved;
  }
  NumEmptyBlocksRemoved += NumRemoved;
  return NumRemoved != 0;
}

char GCEmptyBasicBlocks::ID = 0;
INITIALIZE_PASS(GCEmptyBasicBlocks, "gc-empty-basic-blocks",
                "Removes empty basic blocks and redirects their uses to their "
                "fallthrough blocks.",
                false, false)

MachineFunctionPass *llvm::createGCEmptyBasicBlocksPass() {
  return new GCEmptyBasicBlocks();
}