#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"),
clEnumValN(V3, "", "")));
#define DEBUG_TYPE "tut-simplifycfg"
static bool removeDeadBlocks_v1(Function &F) {
bool Changed = false;
for (BasicBlock &BB : make_early_inc_range(F)) {
if (&F.getEntryBlock() == &BB || !pred_empty(&BB))
continue;
for (BasicBlock *Succ : successors(&BB))
Succ->removePredecessor(&BB);
while (!BB.empty()) {
Instruction &I = BB.back();
I.replaceAllUsesWith(UndefValue::get(I.getType()));
I.eraseFromParent();
}
BB.eraseFromParent();
Changed = true;
}
return Changed;
}
static bool removeDeadBlocks_v2(Function &F, DominatorTree &DT) {
bool Changed = false;
DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
SmallVector<DominatorTree::UpdateType, 8> DTUpdates;
for (BasicBlock &BB : make_early_inc_range(F)) {
if (&F.getEntryBlock() == &BB || !pred_empty(&BB))
continue;
for (BasicBlock *Succ : successors(&BB)) {
Succ->removePredecessor(&BB);
DTUpdates.push_back({DominatorTree::Delete, &BB, Succ});
}
DTU.deleteBB(&BB);
Changed = true;
}
DTU.applyUpdatesPermissive(DTUpdates);
return Changed;
}
static bool eliminateCondBranches_v1(Function &F) {
bool Changed = false;
for (BasicBlock &BB : F) {
BranchInst *BI = dyn_cast<BranchInst>(BB.getTerminator());
if (!BI || !BI->isConditional())
continue;
ConstantInt *CI = dyn_cast<ConstantInt>(BI->getCondition());
if (!CI)
continue;
BasicBlock *RemovedSucc = BI->getSuccessor(CI->isOne());
RemovedSucc->removePredecessor(&BB);
BranchInst::Create(BI->getSuccessor(CI->isZero()), BI);
BI->eraseFromParent();
Changed = true;
}
return Changed;
}
static bool eliminateCondBranches_v2(Function &F, DominatorTree &DT) {
bool Changed = false;
DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
SmallVector<DominatorTree::UpdateType, 8> DTUpdates;
for (BasicBlock &BB : F) {
BranchInst *BI = dyn_cast<BranchInst>(BB.getTerminator());
if (!BI || !BI->isConditional())
continue;
ConstantInt *CI = dyn_cast<ConstantInt>(BI->getCondition());
if (!CI)
continue;
BasicBlock *RemovedSucc = BI->getSuccessor(CI->isOne());
RemovedSucc->removePredecessor(&BB);
BranchInst *NewBranch =
BranchInst::Create(BI->getSuccessor(CI->isZero()), BI);
BI->eraseFromParent();
if (NewBranch->getSuccessor(0) != RemovedSucc)
DTUpdates.push_back({DominatorTree::Delete, &BB, RemovedSucc});
Changed = true;
}
DTU.applyUpdatesPermissive(DTUpdates);
return Changed;
}
static bool eliminateCondBranches_v3(Function &F, DominatorTree &DT) {
bool Changed = false;
DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
SmallVector<DominatorTree::UpdateType, 8> DTUpdates;
for (BasicBlock &BB : F) {
ConstantInt *CI = nullptr;
BasicBlock *TakenSucc, *RemovedSucc;
if (!match(BB.getTerminator(),
m_Br(m_ConstantInt(CI), m_BasicBlock(TakenSucc),
m_BasicBlock(RemovedSucc))))
continue;
if (CI->isZero())
std::swap(TakenSucc, RemovedSucc);
RemovedSucc->removePredecessor(&BB);
BranchInst *NewBranch = BranchInst::Create(TakenSucc, BB.getTerminator());
BB.getTerminator()->eraseFromParent();
if (NewBranch->getSuccessor(0) != RemovedSucc)
DTUpdates.push_back({DominatorTree::Delete, &BB, RemovedSucc});
Changed = true;
}
DTU.applyUpdatesPermissive(DTUpdates);
return Changed;
}
static bool mergeIntoSinglePredecessor_v1(Function &F) {
bool Changed = false;
for (BasicBlock &BB : make_early_inc_range(F)) {
BasicBlock *Pred = BB.getSinglePredecessor();
if (!Pred || Pred->getSingleSuccessor() != &BB)
continue;
if (Pred == &BB)
continue;
BB.replaceAllUsesWith(Pred);
for (PHINode &PN : make_early_inc_range(BB.phis())) {
PN.replaceAllUsesWith(PN.getIncomingValue(0));
PN.eraseFromParent();
}
for (Instruction &I : make_early_inc_range(BB))
I.moveBefore(Pred->getTerminator());
Pred->getTerminator()->eraseFromParent();
BB.eraseFromParent();
Changed = true;
}
return Changed;
}
static bool mergeIntoSinglePredecessor_v2(Function &F, DominatorTree &DT) {
bool Changed = false;
DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
SmallVector<DominatorTree::UpdateType, 8> DTUpdates;
for (BasicBlock &BB : make_early_inc_range(F)) {
BasicBlock *Pred = BB.getSinglePredecessor();
if (!Pred || Pred->getSingleSuccessor() != &BB)
continue;
if (Pred == &BB)
continue;
for (BasicBlock *Succ : successors(&BB)) {
DTUpdates.push_back({DominatorTree::Delete, &BB, Succ});
DTUpdates.push_back({DominatorTree::Insert, Pred, Succ});
}
DTUpdates.push_back({DominatorTree::Delete, Pred, &BB});
BB.replaceAllUsesWith(Pred);
for (PHINode &PN : make_early_inc_range(BB.phis())) {
PN.replaceAllUsesWith(PN.getIncomingValue(0));
PN.eraseFromParent();
}
for (Instruction &I : make_early_inc_range(BB))
I.moveBefore(Pred->getTerminator());
Pred->getTerminator()->eraseFromParent();
DTU.deleteBB(&BB);
Changed = true;
}
DTU.applyUpdatesPermissive(DTUpdates);
return Changed;
}
static bool doSimplify_v1(Function &F) {
return (int)eliminateCondBranches_v1(F) | mergeIntoSinglePredecessor_v1(F) |
removeDeadBlocks_v1(F);
}
static bool doSimplify_v2(Function &F, DominatorTree &DT) {
return (int)eliminateCondBranches_v2(F, DT) |
mergeIntoSinglePredecessor_v2(F, DT) | removeDeadBlocks_v2(F, DT);
}
static bool doSimplify_v3(Function &F, DominatorTree &DT) {
return (int)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>();
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");
}
};
}
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)