#include "llvm/Transforms/Utils/BreakCriticalEdges.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/BlockFrequencyInfo.h"
#include "llvm/Analysis/BranchProbabilityInfo.h"
#include "llvm/Analysis/CFG.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/MemorySSAUpdater.h"
#include "llvm/Analysis/PostDominators.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Instructions.h"
#include "llvm/InitializePasses.h"
#include "llvm/Transforms/Utils.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Transforms/Utils/ValueMapper.h"
using namespace llvm;
#define DEBUG_TYPE "break-crit-edges"
STATISTIC(NumBroken, "Number of blocks inserted");
namespace {
struct BreakCriticalEdges : public FunctionPass {
static char ID; BreakCriticalEdges() : FunctionPass(ID) {
initializeBreakCriticalEdgesPass(*PassRegistry::getPassRegistry());
}
bool runOnFunction(Function &F) override {
auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>();
auto *DT = DTWP ? &DTWP->getDomTree() : nullptr;
auto *PDTWP = getAnalysisIfAvailable<PostDominatorTreeWrapperPass>();
auto *PDT = PDTWP ? &PDTWP->getPostDomTree() : nullptr;
auto *LIWP = getAnalysisIfAvailable<LoopInfoWrapperPass>();
auto *LI = LIWP ? &LIWP->getLoopInfo() : nullptr;
unsigned N =
SplitAllCriticalEdges(F, CriticalEdgeSplittingOptions(DT, LI, nullptr, PDT));
NumBroken += N;
return N > 0;
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addPreserved<DominatorTreeWrapperPass>();
AU.addPreserved<LoopInfoWrapperPass>();
AU.addPreservedID(LoopSimplifyID);
}
};
}
char BreakCriticalEdges::ID = 0;
INITIALIZE_PASS(BreakCriticalEdges, "break-crit-edges",
"Break critical edges in CFG", false, false)
char &llvm::BreakCriticalEdgesID = BreakCriticalEdges::ID;
FunctionPass *llvm::createBreakCriticalEdgesPass() {
return new BreakCriticalEdges();
}
PreservedAnalyses BreakCriticalEdgesPass::run(Function &F,
FunctionAnalysisManager &AM) {
auto *DT = AM.getCachedResult<DominatorTreeAnalysis>(F);
auto *LI = AM.getCachedResult<LoopAnalysis>(F);
unsigned N = SplitAllCriticalEdges(F, CriticalEdgeSplittingOptions(DT, LI));
NumBroken += N;
if (N == 0)
return PreservedAnalyses::all();
PreservedAnalyses PA;
PA.preserve<DominatorTreeAnalysis>();
PA.preserve<LoopAnalysis>();
return PA;
}
BasicBlock *llvm::SplitCriticalEdge(Instruction *TI, unsigned SuccNum,
const CriticalEdgeSplittingOptions &Options,
const Twine &BBName) {
if (!isCriticalEdge(TI, SuccNum, Options.MergeIdenticalEdges))
return nullptr;
return SplitKnownCriticalEdge(TI, SuccNum, Options, BBName);
}
BasicBlock *
llvm::SplitKnownCriticalEdge(Instruction *TI, unsigned SuccNum,
const CriticalEdgeSplittingOptions &Options,
const Twine &BBName) {
assert(!isa<IndirectBrInst>(TI) &&
"Cannot split critical edge from IndirectBrInst");
BasicBlock *TIBB = TI->getParent();
BasicBlock *DestBB = TI->getSuccessor(SuccNum);
if (DestBB->isEHPad()) return nullptr;
if (Options.IgnoreUnreachableDests &&
isa<UnreachableInst>(DestBB->getFirstNonPHIOrDbgOrLifetime()))
return nullptr;
auto *LI = Options.LI;
SmallVector<BasicBlock *, 4> LoopPreds;
if (LI) {
if (Loop *TIL = LI->getLoopFor(TIBB)) {
for (BasicBlock *P : predecessors(DestBB)) {
if (P == TIBB)
continue; if (LI->getLoopFor(P) != TIL) {
LoopPreds.clear();
break;
}
LoopPreds.push_back(P);
}
if (any_of(LoopPreds, [](BasicBlock *Pred) {
return isa<IndirectBrInst>(Pred->getTerminator());
})) {
if (Options.PreserveLoopSimplify)
return nullptr;
LoopPreds.clear();
}
}
}
BasicBlock *NewBB = nullptr;
if (BBName.str() != "")
NewBB = BasicBlock::Create(TI->getContext(), BBName);
else
NewBB = BasicBlock::Create(TI->getContext(), TIBB->getName() + "." +
DestBB->getName() +
"_crit_edge");
BranchInst *NewBI = BranchInst::Create(DestBB, NewBB);
NewBI->setDebugLoc(TI->getDebugLoc());
Function &F = *TIBB->getParent();
Function::iterator FBBI = TIBB->getIterator();
F.getBasicBlockList().insert(++FBBI, NewBB);
TI->setSuccessor(SuccNum, NewBB);
{
unsigned BBIdx = 0;
for (BasicBlock::iterator I = DestBB->begin(); isa<PHINode>(I); ++I) {
PHINode *PN = cast<PHINode>(I);
if (PN->getIncomingBlock(BBIdx) != TIBB)
BBIdx = PN->getBasicBlockIndex(TIBB);
PN->setIncomingBlock(BBIdx, NewBB);
}
}
if (Options.MergeIdenticalEdges) {
for (unsigned i = SuccNum+1, e = TI->getNumSuccessors(); i != e; ++i) {
if (TI->getSuccessor(i) != DestBB) continue;
DestBB->removePredecessor(TIBB, Options.KeepOneInputPHIs);
TI->setSuccessor(i, NewBB);
}
}
auto *DT = Options.DT;
auto *PDT = Options.PDT;
auto *MSSAU = Options.MSSAU;
if (MSSAU)
MSSAU->wireOldPredecessorsToNewImmediatePredecessor(
DestBB, NewBB, {TIBB}, Options.MergeIdenticalEdges);
if (!DT && !PDT && !LI)
return NewBB;
if (DT || PDT) {
SmallVector<DominatorTree::UpdateType, 3> Updates;
Updates.push_back({DominatorTree::Insert, TIBB, NewBB});
Updates.push_back({DominatorTree::Insert, NewBB, DestBB});
if (!llvm::is_contained(successors(TIBB), DestBB))
Updates.push_back({DominatorTree::Delete, TIBB, DestBB});
if (DT)
DT->applyUpdates(Updates);
if (PDT)
PDT->applyUpdates(Updates);
}
if (LI) {
if (Loop *TIL = LI->getLoopFor(TIBB)) {
if (Loop *DestLoop = LI->getLoopFor(DestBB)) {
if (TIL == DestLoop) {
DestLoop->addBasicBlockToLoop(NewBB, *LI);
} else if (TIL->contains(DestLoop)) {
TIL->addBasicBlockToLoop(NewBB, *LI);
} else if (DestLoop->contains(TIL)) {
DestLoop->addBasicBlockToLoop(NewBB, *LI);
} else {
assert(DestLoop->getHeader() == DestBB &&
"Should not create irreducible loops!");
if (Loop *P = DestLoop->getParentLoop())
P->addBasicBlockToLoop(NewBB, *LI);
}
}
if (!TIL->contains(DestBB)) {
assert(!TIL->contains(NewBB) &&
"Split point for loop exit is contained in loop!");
if (Options.PreserveLCSSA) {
createPHIsForSplitLoopExit(TIBB, NewBB, DestBB);
}
if (!LoopPreds.empty()) {
assert(!DestBB->isEHPad() && "We don't split edges to EH pads!");
BasicBlock *NewExitBB = SplitBlockPredecessors(
DestBB, LoopPreds, "split", DT, LI, MSSAU, Options.PreserveLCSSA);
if (Options.PreserveLCSSA)
createPHIsForSplitLoopExit(LoopPreds, NewExitBB, DestBB);
}
}
}
}
return NewBB;
}
static BasicBlock *
findIBRPredecessor(BasicBlock *BB, SmallVectorImpl<BasicBlock *> &OtherPreds) {
BasicBlock *IBB = nullptr;
for (BasicBlock *PredBB : predecessors(BB)) {
Instruction *PredTerm = PredBB->getTerminator();
switch (PredTerm->getOpcode()) {
case Instruction::IndirectBr:
if (IBB)
return nullptr;
IBB = PredBB;
break;
case Instruction::Br:
case Instruction::Switch:
OtherPreds.push_back(PredBB);
continue;
default:
return nullptr;
}
}
return IBB;
}
bool llvm::SplitIndirectBrCriticalEdges(Function &F,
bool IgnoreBlocksWithoutPHI,
BranchProbabilityInfo *BPI,
BlockFrequencyInfo *BFI) {
SmallSetVector<BasicBlock *, 16> Targets;
for (auto &BB : F) {
auto *IBI = dyn_cast<IndirectBrInst>(BB.getTerminator());
if (!IBI)
continue;
for (unsigned Succ = 0, E = IBI->getNumSuccessors(); Succ != E; ++Succ)
Targets.insert(IBI->getSuccessor(Succ));
}
if (Targets.empty())
return false;
bool ShouldUpdateAnalysis = BPI && BFI;
bool Changed = false;
for (BasicBlock *Target : Targets) {
if (IgnoreBlocksWithoutPHI && Target->phis().empty())
continue;
SmallVector<BasicBlock *, 16> OtherPreds;
BasicBlock *IBRPred = findIBRPredecessor(Target, OtherPreds);
if (!IBRPred || OtherPreds.empty())
continue;
Instruction *FirstNonPHI = Target->getFirstNonPHI();
if (FirstNonPHI->isEHPad() || Target->isLandingPad())
continue;
SmallVector<BranchProbability, 4> EdgeProbabilities;
if (ShouldUpdateAnalysis) {
EdgeProbabilities.reserve(Target->getTerminator()->getNumSuccessors());
for (unsigned I = 0, E = Target->getTerminator()->getNumSuccessors();
I < E; ++I)
EdgeProbabilities.emplace_back(BPI->getEdgeProbability(Target, I));
BPI->eraseBlock(Target);
}
BasicBlock *BodyBlock = Target->splitBasicBlock(FirstNonPHI, ".split");
if (ShouldUpdateAnalysis) {
BPI->setEdgeProbability(BodyBlock, EdgeProbabilities);
BFI->setBlockFreq(BodyBlock, BFI->getBlockFreq(Target).getFrequency());
}
if (IBRPred == Target)
IBRPred = BodyBlock;
ValueToValueMapTy VMap;
BasicBlock *DirectSucc = CloneBasicBlock(Target, VMap, ".clone", &F);
BlockFrequency BlockFreqForDirectSucc;
for (BasicBlock *Pred : OtherPreds) {
BasicBlock *Src = Pred != Target ? Pred : BodyBlock;
Src->getTerminator()->replaceUsesOfWith(Target, DirectSucc);
if (ShouldUpdateAnalysis)
BlockFreqForDirectSucc += BFI->getBlockFreq(Src) *
BPI->getEdgeProbability(Src, DirectSucc);
}
if (ShouldUpdateAnalysis) {
BFI->setBlockFreq(DirectSucc, BlockFreqForDirectSucc.getFrequency());
BlockFrequency NewBlockFreqForTarget =
BFI->getBlockFreq(Target) - BlockFreqForDirectSucc;
BFI->setBlockFreq(Target, NewBlockFreqForTarget.getFrequency());
}
BasicBlock::iterator Indirect = Target->begin(),
End = Target->getFirstNonPHI()->getIterator();
BasicBlock::iterator Direct = DirectSucc->begin();
BasicBlock::iterator MergeInsert = BodyBlock->getFirstInsertionPt();
assert(&*End == Target->getTerminator() &&
"Block was expected to only contain PHIs");
while (Indirect != End) {
PHINode *DirPHI = cast<PHINode>(Direct);
PHINode *IndPHI = cast<PHINode>(Indirect);
DirPHI->removeIncomingValue(IBRPred);
Direct++;
Indirect++;
PHINode *NewIndPHI = PHINode::Create(IndPHI->getType(), 1, "ind", IndPHI);
NewIndPHI->addIncoming(IndPHI->getIncomingValueForBlock(IBRPred),
IBRPred);
PHINode *MergePHI =
PHINode::Create(IndPHI->getType(), 2, "merge", &*MergeInsert);
MergePHI->addIncoming(NewIndPHI, Target);
MergePHI->addIncoming(DirPHI, DirectSucc);
IndPHI->replaceAllUsesWith(MergePHI);
IndPHI->eraseFromParent();
}
Changed = true;
}
return Changed;
}