summaryrefslogtreecommitdiffstats
path: root/llvm/examples/IRTransforms/SimplifyCFG.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/examples/IRTransforms/SimplifyCFG.cpp')
-rw-r--r--llvm/examples/IRTransforms/SimplifyCFG.cpp413
1 files changed, 413 insertions, 0 deletions
diff --git a/llvm/examples/IRTransforms/SimplifyCFG.cpp b/llvm/examples/IRTransforms/SimplifyCFG.cpp
new file mode 100644
index 00000000000..44bbedf4dc4
--- /dev/null
+++ b/llvm/examples/IRTransforms/SimplifyCFG.cpp
@@ -0,0 +1,413 @@
+//===- 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/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)
OpenPOWER on IntegriCloud