415 lines
15 KiB
C++
415 lines
15 KiB
C++
//===- SimplifyCFG.cpp ----------------------------------------------------===//
|
|
//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the control flow graph (CFG) simplifications
|
|
// presented as part of the 'Getting Started With LLVM: Basics' tutorial at the
|
|
// US LLVM Developers Meeting 2019. It also contains additional material.
|
|
//
|
|
// The current file contains three different CFG simplifications. There are
|
|
// multiple versions of each implementation (e.g. _v1 and _v2), which implement
|
|
// additional functionality (e.g. preserving analysis like the DominatorTree) or
|
|
// use additional utilities to simplify the code (e.g. LLVM's PatternMatch.h).
|
|
// The available simplifications are:
|
|
// 1. Trivially Dead block Removal (removeDeadBlocks_v[1,2]).
|
|
// This simplifications removes all blocks without predecessors in the CFG
|
|
// from a function.
|
|
// 2. Conditional Branch Elimination (eliminateCondBranches_v[1,2,3])
|
|
// This simplification replaces conditional branches with constant integer
|
|
// conditions with unconditional branches.
|
|
// 3. Single Predecessor Block Merging (mergeIntoSinglePredecessor_v[1,2])
|
|
// This simplification merges blocks with a single predecessor into the
|
|
// predecessor, if that block has a single successor.
|
|
//
|
|
// TODOs
|
|
// * Hook up pass to the new pass manager.
|
|
// * Preserve LoopInfo.
|
|
// * Add fixed point iteration to delete all dead blocks
|
|
// * Add implementation using reachability to discover dead blocks.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "SimplifyCFG.h"
|
|
#include "InitializePasses.h"
|
|
#include "llvm/Analysis/DomTreeUpdater.h"
|
|
#include "llvm/IR/Dominators.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/IR/PassManager.h"
|
|
#include "llvm/IR/PatternMatch.h"
|
|
#include "llvm/InitializePasses.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
|
|
using namespace llvm;
|
|
using namespace PatternMatch;
|
|
|
|
enum TutorialVersion { V1, V2, V3 };
|
|
static cl::opt<TutorialVersion>
|
|
Version("tut-simplifycfg-version", cl::desc("Select tutorial version"),
|
|
cl::Hidden, cl::ValueOptional, cl::init(V1),
|
|
cl::values(clEnumValN(V1, "v1", "version 1"),
|
|
clEnumValN(V2, "v2", "version 2"),
|
|
clEnumValN(V3, "v3", "version 3"),
|
|
// Sentinel value for unspecified option.
|
|
clEnumValN(V3, "", "")));
|
|
|
|
#define DEBUG_TYPE "tut-simplifycfg"
|
|
|
|
// Remove trivially dead blocks. First version, not preserving the
|
|
// DominatorTree.
|
|
static bool removeDeadBlocks_v1(Function &F) {
|
|
bool Changed = false;
|
|
|
|
// Remove trivially dead blocks.
|
|
for (BasicBlock &BB : make_early_inc_range(F)) {
|
|
// Skip blocks we know to not be trivially dead. We know a block is
|
|
// guaranteed to be dead, iff it is neither the entry block nor
|
|
// has any predecessors.
|
|
if (&F.getEntryBlock() == &BB || !pred_empty(&BB))
|
|
continue;
|
|
|
|
// Notify successors of BB that BB is going to be removed. This removes
|
|
// incoming values from BB from PHIs in the successors. Note that this will
|
|
// not actually remove BB from the predecessor lists of its successors.
|
|
for (BasicBlock *Succ : successors(&BB))
|
|
Succ->removePredecessor(&BB);
|
|
// TODO: Find a better place to put such small variations.
|
|
// Alternatively, we can update the PHI nodes manually:
|
|
// for (PHINode &PN : make_early_inc_range(Succ->phis()))
|
|
// PN.removeIncomingValue(&BB);
|
|
|
|
// Replace all instructions in BB with an undef constant. The block is
|
|
// unreachable, so the results of the instructions should never get used.
|
|
while (!BB.empty()) {
|
|
Instruction &I = BB.back();
|
|
I.replaceAllUsesWith(UndefValue::get(I.getType()));
|
|
I.eraseFromParent();
|
|
}
|
|
|
|
// Finally remove the basic block.
|
|
BB.eraseFromParent();
|
|
Changed = true;
|
|
}
|
|
|
|
return Changed;
|
|
}
|
|
|
|
// Remove trivially dead blocks. This is the second version and preserves the
|
|
// dominator tree.
|
|
static bool removeDeadBlocks_v2(Function &F, DominatorTree &DT) {
|
|
bool Changed = false;
|
|
DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
|
|
SmallVector<DominatorTree::UpdateType, 8> DTUpdates;
|
|
|
|
// Remove trivially dead blocks.
|
|
for (BasicBlock &BB : make_early_inc_range(F)) {
|
|
// Skip blocks we know to not be trivially dead. We know a block is
|
|
// guaranteed to be dead, iff it is neither the entry block nor
|
|
// has any predecessors.
|
|
if (&F.getEntryBlock() == &BB || !pred_empty(&BB))
|
|
continue;
|
|
|
|
// Notify successors of BB that BB is going to be removed. This removes
|
|
// incoming values from BB from PHIs in the successors. Note that this will
|
|
// not actually remove BB from the predecessor lists of its successors.
|
|
for (BasicBlock *Succ : successors(&BB)) {
|
|
Succ->removePredecessor(&BB);
|
|
|
|
// Collect updates that need to be applied to the dominator tree.
|
|
DTUpdates.push_back({DominatorTree::Delete, &BB, Succ});
|
|
}
|
|
|
|
// Remove BB via the DomTreeUpdater. DomTreeUpdater::deleteBB conveniently
|
|
// removes the instructions in BB as well.
|
|
DTU.deleteBB(&BB);
|
|
Changed = true;
|
|
}
|
|
|
|
// Apply updates permissively, to remove duplicates.
|
|
DTU.applyUpdatesPermissive(DTUpdates);
|
|
|
|
return Changed;
|
|
}
|
|
|
|
// Eliminate branches with constant conditionals. This is the first version,
|
|
// which *does not* preserve the dominator tree.
|
|
static bool eliminateCondBranches_v1(Function &F) {
|
|
bool Changed = false;
|
|
|
|
// Eliminate branches with constant conditionals.
|
|
for (BasicBlock &BB : F) {
|
|
// Skip blocks without conditional branches as terminators.
|
|
BranchInst *BI = dyn_cast<BranchInst>(BB.getTerminator());
|
|
if (!BI || !BI->isConditional())
|
|
continue;
|
|
|
|
// Skip blocks with conditional branches without ConstantInt conditions.
|
|
ConstantInt *CI = dyn_cast<ConstantInt>(BI->getCondition());
|
|
if (!CI)
|
|
continue;
|
|
|
|
// We use the branch condition (CI), to select the successor we remove:
|
|
// if CI == 1 (true), we remove the second successor, otherwise the first.
|
|
BasicBlock *RemovedSucc = BI->getSuccessor(CI->isOne());
|
|
// Tell RemovedSucc we will remove BB from its predecessors.
|
|
RemovedSucc->removePredecessor(&BB);
|
|
|
|
// Replace the conditional branch with an unconditional one, by creating
|
|
// a new unconditional branch to the selected successor and removing the
|
|
// conditional one.
|
|
BranchInst::Create(BI->getSuccessor(CI->isZero()), BI);
|
|
BI->eraseFromParent();
|
|
Changed = true;
|
|
}
|
|
|
|
return Changed;
|
|
}
|
|
|
|
// Eliminate branches with constant conditionals. This is the second
|
|
// version, which *does* preserve the dominator tree.
|
|
static bool eliminateCondBranches_v2(Function &F, DominatorTree &DT) {
|
|
bool Changed = false;
|
|
|
|
DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
|
|
SmallVector<DominatorTree::UpdateType, 8> DTUpdates;
|
|
// Eliminate branches with constant conditionals.
|
|
for (BasicBlock &BB : F) {
|
|
// Skip blocks without conditional branches as terminators.
|
|
BranchInst *BI = dyn_cast<BranchInst>(BB.getTerminator());
|
|
if (!BI || !BI->isConditional())
|
|
continue;
|
|
|
|
// Skip blocks with conditional branches without ConstantInt conditions.
|
|
ConstantInt *CI = dyn_cast<ConstantInt>(BI->getCondition());
|
|
if (!CI)
|
|
continue;
|
|
|
|
// We use the branch condition (CI), to select the successor we remove:
|
|
// if CI == 1 (true), we remove the second successor, otherwise the first.
|
|
BasicBlock *RemovedSucc = BI->getSuccessor(CI->isOne());
|
|
// Tell RemovedSucc we will remove BB from its predecessors.
|
|
RemovedSucc->removePredecessor(&BB);
|
|
|
|
// Replace the conditional branch with an unconditional one, by creating
|
|
// a new unconditional branch to the selected successor and removing the
|
|
// conditional one.
|
|
BranchInst *NewBranch =
|
|
BranchInst::Create(BI->getSuccessor(CI->isZero()), BI);
|
|
BI->eraseFromParent();
|
|
|
|
// Delete the edge between BB and RemovedSucc in the DominatorTree, iff
|
|
// the conditional branch did not use RemovedSucc as both the true and false
|
|
// branches.
|
|
if (NewBranch->getSuccessor(0) != RemovedSucc)
|
|
DTUpdates.push_back({DominatorTree::Delete, &BB, RemovedSucc});
|
|
Changed = true;
|
|
}
|
|
|
|
// Apply updates permissively, to remove duplicates.
|
|
DTU.applyUpdatesPermissive(DTUpdates);
|
|
|
|
return Changed;
|
|
}
|
|
|
|
// Eliminate branches with constant conditionals. This is the third
|
|
// version, which uses PatternMatch.h.
|
|
static bool eliminateCondBranches_v3(Function &F, DominatorTree &DT) {
|
|
bool Changed = false;
|
|
DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
|
|
SmallVector<DominatorTree::UpdateType, 8> DTUpdates;
|
|
|
|
// Eliminate branches with constant conditionals.
|
|
for (BasicBlock &BB : F) {
|
|
ConstantInt *CI = nullptr;
|
|
BasicBlock *TakenSucc, *RemovedSucc;
|
|
// Check if the terminator is a conditional branch, with constant integer
|
|
// condition and also capture the successor blocks as TakenSucc and
|
|
// RemovedSucc.
|
|
if (!match(BB.getTerminator(),
|
|
m_Br(m_ConstantInt(CI), m_BasicBlock(TakenSucc),
|
|
m_BasicBlock(RemovedSucc))))
|
|
continue;
|
|
|
|
// If the condition is false, swap TakenSucc and RemovedSucc.
|
|
if (CI->isZero())
|
|
std::swap(TakenSucc, RemovedSucc);
|
|
|
|
// Tell RemovedSucc we will remove BB from its predecessors.
|
|
RemovedSucc->removePredecessor(&BB);
|
|
|
|
// Replace the conditional branch with an unconditional one, by creating
|
|
// a new unconditional branch to the selected successor and removing the
|
|
// conditional one.
|
|
|
|
BranchInst *NewBranch = BranchInst::Create(TakenSucc, BB.getTerminator());
|
|
BB.getTerminator()->eraseFromParent();
|
|
|
|
// Delete the edge between BB and RemovedSucc in the DominatorTree, iff
|
|
// the conditional branch did not use RemovedSucc as both the true and false
|
|
// branches.
|
|
if (NewBranch->getSuccessor(0) != RemovedSucc)
|
|
DTUpdates.push_back({DominatorTree::Delete, &BB, RemovedSucc});
|
|
Changed = true;
|
|
}
|
|
|
|
// Apply updates permissively, to remove duplicates.
|
|
DTU.applyUpdatesPermissive(DTUpdates);
|
|
return Changed;
|
|
}
|
|
|
|
// Merge basic blocks into their single predecessor, if their predecessor has a
|
|
// single successor. This is the first version and does not preserve the
|
|
// DominatorTree.
|
|
static bool mergeIntoSinglePredecessor_v1(Function &F) {
|
|
bool Changed = false;
|
|
|
|
// Merge blocks with single predecessors.
|
|
for (BasicBlock &BB : make_early_inc_range(F)) {
|
|
BasicBlock *Pred = BB.getSinglePredecessor();
|
|
// Make sure BB has a single predecessor Pred and BB is the single
|
|
// successor of Pred.
|
|
if (!Pred || Pred->getSingleSuccessor() != &BB)
|
|
continue;
|
|
|
|
// Do not try to merge self loops. That can happen in dead blocks.
|
|
if (Pred == &BB)
|
|
continue;
|
|
|
|
// Need to replace it before nuking the branch.
|
|
BB.replaceAllUsesWith(Pred);
|
|
// PHI nodes in BB can only have a single incoming value. Remove them.
|
|
for (PHINode &PN : make_early_inc_range(BB.phis())) {
|
|
PN.replaceAllUsesWith(PN.getIncomingValue(0));
|
|
PN.eraseFromParent();
|
|
}
|
|
// Move all instructions from BB to Pred.
|
|
for (Instruction &I : make_early_inc_range(BB))
|
|
I.moveBefore(Pred->getTerminator());
|
|
|
|
// Remove the Pred's terminator (which jumped to BB). BB's terminator
|
|
// will become Pred's terminator.
|
|
Pred->getTerminator()->eraseFromParent();
|
|
BB.eraseFromParent();
|
|
|
|
Changed = true;
|
|
}
|
|
|
|
return Changed;
|
|
}
|
|
|
|
// Merge basic blocks into their single predecessor, if their predecessor has a
|
|
// single successor. This is the second version and does preserve the
|
|
// DominatorTree.
|
|
static bool mergeIntoSinglePredecessor_v2(Function &F, DominatorTree &DT) {
|
|
bool Changed = false;
|
|
DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
|
|
SmallVector<DominatorTree::UpdateType, 8> DTUpdates;
|
|
|
|
// Merge blocks with single predecessors.
|
|
for (BasicBlock &BB : make_early_inc_range(F)) {
|
|
BasicBlock *Pred = BB.getSinglePredecessor();
|
|
// Make sure BB has a single predecessor Pred and BB is the single
|
|
// successor of Pred.
|
|
if (!Pred || Pred->getSingleSuccessor() != &BB)
|
|
continue;
|
|
|
|
// Do not try to merge self loops. That can happen in dead blocks.
|
|
if (Pred == &BB)
|
|
continue;
|
|
|
|
// Tell DTU about the changes to the CFG: All edges from BB to its
|
|
// successors get removed and we add edges between Pred and BB's successors.
|
|
for (BasicBlock *Succ : successors(&BB)) {
|
|
DTUpdates.push_back({DominatorTree::Delete, &BB, Succ});
|
|
DTUpdates.push_back({DominatorTree::Insert, Pred, Succ});
|
|
}
|
|
// Also remove the edge between Pred and BB.
|
|
DTUpdates.push_back({DominatorTree::Delete, Pred, &BB});
|
|
|
|
// Need to replace it before nuking the branch.
|
|
BB.replaceAllUsesWith(Pred);
|
|
// PHI nodes in BB can only have a single incoming value. Remove them.
|
|
for (PHINode &PN : make_early_inc_range(BB.phis())) {
|
|
PN.replaceAllUsesWith(PN.getIncomingValue(0));
|
|
PN.eraseFromParent();
|
|
}
|
|
// Move all instructions from BB to Pred.
|
|
for (Instruction &I : make_early_inc_range(BB))
|
|
I.moveBefore(Pred->getTerminator());
|
|
|
|
// Remove the Pred's terminator (which jumped to BB). BB's terminator
|
|
// will become Pred's terminator.
|
|
Pred->getTerminator()->eraseFromParent();
|
|
DTU.deleteBB(&BB);
|
|
|
|
Changed = true;
|
|
}
|
|
|
|
// Apply updates permissively, to remove duplicates.
|
|
DTU.applyUpdatesPermissive(DTUpdates);
|
|
return Changed;
|
|
}
|
|
|
|
static bool doSimplify_v1(Function &F) {
|
|
return eliminateCondBranches_v1(F) | mergeIntoSinglePredecessor_v1(F) |
|
|
removeDeadBlocks_v1(F);
|
|
}
|
|
|
|
static bool doSimplify_v2(Function &F, DominatorTree &DT) {
|
|
return eliminateCondBranches_v2(F, DT) |
|
|
mergeIntoSinglePredecessor_v2(F, DT) | removeDeadBlocks_v2(F, DT);
|
|
}
|
|
|
|
static bool doSimplify_v3(Function &F, DominatorTree &DT) {
|
|
return eliminateCondBranches_v3(F, DT) |
|
|
mergeIntoSinglePredecessor_v2(F, DT) | removeDeadBlocks_v2(F, DT);
|
|
}
|
|
|
|
namespace {
|
|
struct SimplifyCFGLegacyPass : public FunctionPass {
|
|
static char ID;
|
|
SimplifyCFGLegacyPass() : FunctionPass(ID) {
|
|
initializeSimplifyCFGLegacyPassPass(*PassRegistry::getPassRegistry());
|
|
}
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
AU.addRequired<DominatorTreeWrapperPass>();
|
|
// Version 1 of the implementation does not preserve the dominator tree.
|
|
if (Version != V1)
|
|
AU.addPreserved<DominatorTreeWrapperPass>();
|
|
|
|
FunctionPass::getAnalysisUsage(AU);
|
|
}
|
|
|
|
bool runOnFunction(Function &F) override {
|
|
if (skipFunction(F))
|
|
return false;
|
|
|
|
switch (Version) {
|
|
case V1:
|
|
return doSimplify_v1(F);
|
|
case V2: {
|
|
auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
|
|
return doSimplify_v2(F, DT);
|
|
}
|
|
case V3: {
|
|
auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
|
|
return doSimplify_v3(F, DT);
|
|
}
|
|
}
|
|
|
|
llvm_unreachable("Unsupported version");
|
|
}
|
|
};
|
|
} // namespace
|
|
|
|
char SimplifyCFGLegacyPass::ID = 0;
|
|
INITIALIZE_PASS_BEGIN(SimplifyCFGLegacyPass, DEBUG_TYPE,
|
|
"Tutorial CFG simplification", false, false)
|
|
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
|
|
INITIALIZE_PASS_END(SimplifyCFGLegacyPass, DEBUG_TYPE,
|
|
"Tutorial CFG simplifications", false, false)
|