Teach SimplifyCFG how to simplify indirectbr instructions.

- Eliminate redundant successors.
 - Convert an indirectbr with one successor into a direct branch.

Also, generalize SimplifyCFG to be able to be run on a function entry block.
It knows quite a few simplifications which are applicable to the entry
block, and it only needs a few checks to avoid trouble with the entry block.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@111060 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Dan Gohman 2010-08-14 00:29:42 +00:00
parent 3d72367d30
commit e2c6d131d1
6 changed files with 96 additions and 19 deletions

View File

@ -118,8 +118,6 @@ bool EliminateDuplicatePHINodes(BasicBlock *BB);
/// of the CFG. It returns true if a modification was made, possibly deleting
/// the basic block that was pointed to.
///
/// WARNING: The entry node of a method may not be simplified.
///
bool SimplifyCFG(BasicBlock *BB, const TargetData *TD = 0);
/// FoldBranchToCommonDest - If this basic block is ONLY a setcc and a branch,

View File

@ -285,10 +285,9 @@ static bool IterativeSimplifyCFG(Function &F, const TargetData *TD) {
while (LocalChange) {
LocalChange = false;
// Loop over all of the basic blocks (except the first one) and remove them
// if they are unneeded...
// Loop over all of the basic blocks and remove them if they are unneeded...
//
for (Function::iterator BBIt = ++F.begin(); BBIt != F.end(); ) {
for (Function::iterator BBIt = F.begin(); BBIt != F.end(); ) {
if (SimplifyCFG(BBIt++, TD)) {
LocalChange = true;
++NumSimpl;

View File

@ -490,6 +490,9 @@ static bool CanPropagatePredecessorsForPHIs(BasicBlock *BB, BasicBlock *Succ) {
/// rewriting all the predecessors to branch to the successor block and return
/// true. If we can't transform, return false.
bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB) {
assert(BB != &BB->getParent()->getEntryBlock() &&
"TryToSimplifyUncondBranchFromEmptyBlock called on entry block!");
// We can't eliminate infinite loops.
BasicBlock *Succ = cast<BranchInst>(BB->getTerminator())->getSuccessor(0);
if (BB == Succ) return false;

View File

@ -1724,12 +1724,12 @@ bool SimplifyCFGOpt::run(BasicBlock *BB) {
assert(BB && BB->getParent() && "Block not embedded in function!");
assert(BB->getTerminator() && "Degenerate basic block encountered!");
assert(&BB->getParent()->getEntryBlock() != BB &&
"Can't Simplify entry block!");
// Remove basic blocks that have no predecessors... or that just have themself
// as a predecessor. These are unreachable.
if (pred_begin(BB) == pred_end(BB) || BB->getSinglePredecessor() == BB) {
// Remove basic blocks that have no predecessors (except the entry block)...
// or that just have themself as a predecessor. These are unreachable.
if ((pred_begin(BB) == pred_end(BB) &&
&BB->getParent()->getEntryBlock() != BB) ||
BB->getSinglePredecessor() == BB) {
DEBUG(dbgs() << "Removing BB: \n" << *BB);
DeleteDeadBlock(BB);
return true;
@ -1880,8 +1880,9 @@ bool SimplifyCFGOpt::run(BasicBlock *BB) {
while (isa<DbgInfoIntrinsic>(BBI))
++BBI;
if (BBI->isTerminator()) // Terminator is the only non-phi instruction!
if (TryToSimplifyUncondBranchFromEmptyBlock(BB))
return true;
if (BB != &BB->getParent()->getEntryBlock())
if (TryToSimplifyUncondBranchFromEmptyBlock(BB))
return true;
} else { // Conditional branch
if (isValueEqualityComparison(BI)) {
@ -2049,12 +2050,37 @@ bool SimplifyCFGOpt::run(BasicBlock *BB) {
}
// If this block is now dead, remove it.
if (pred_begin(BB) == pred_end(BB)) {
if (pred_begin(BB) == pred_end(BB) &&
BB != &BB->getParent()->getEntryBlock()) {
// We know there are no successors, so just nuke the block.
M->getBasicBlockList().erase(BB);
return true;
}
}
} else if (IndirectBrInst *IBI = dyn_cast<IndirectBrInst>(BB->getTerminator())) {
// Eliminate redundant destinations.
SmallPtrSet<Value *, 8> Succs;
for (unsigned i = 0, e = IBI->getNumDestinations(); i != e; ++i) {
BasicBlock *Dest = IBI->getDestination(i);
if (!Succs.insert(Dest)) {
Dest->removePredecessor(BB);
IBI->removeDestination(i);
--i; --e;
Changed = true;
}
}
if (IBI->getNumDestinations() == 0) {
// If the indirectbr has no successors, change it to unreachable.
new UnreachableInst(IBI->getContext(), IBI);
IBI->eraseFromParent();
Changed = true;
} else if (IBI->getNumDestinations() == 1) {
// If the indirectbr has one successor, change it to a direct branch.
BranchInst::Create(IBI->getDestination(0), IBI);
IBI->eraseFromParent();
Changed = true;
}
}
// Merge basic blocks into their predecessor if there is only one distinct
@ -2068,12 +2094,15 @@ bool SimplifyCFGOpt::run(BasicBlock *BB) {
// is a conditional branch, see if we can hoist any code from this block up
// into our predecessor.
pred_iterator PI(pred_begin(BB)), PE(pred_end(BB));
BasicBlock *OnlyPred = *PI++;
for (; PI != PE; ++PI) // Search all predecessors, see if they are all same
if (*PI != OnlyPred) {
BasicBlock *OnlyPred = 0;
for (; PI != PE; ++PI) { // Search all predecessors, see if they are all same
if (!OnlyPred)
OnlyPred = *PI;
else if (*PI != OnlyPred) {
OnlyPred = 0; // There are multiple different predecessors...
break;
}
}
if (OnlyPred)
if (BranchInst *BI = dyn_cast<BranchInst>(OnlyPred->getTerminator()))
@ -2172,8 +2201,6 @@ bool SimplifyCFGOpt::run(BasicBlock *BB) {
/// eliminates unreachable basic blocks, and does other "peephole" optimization
/// of the CFG. It returns true if a modification was made.
///
/// WARNING: The entry node of a function may not be simplified.
///
bool llvm::SimplifyCFG(BasicBlock *BB, const TargetData *TD) {
return SimplifyCFGOpt(TD).run(BB);
}

View File

@ -54,6 +54,5 @@ bb1: ; preds = %entry
return: ; preds = %entry
ret void
; CHECK: @test5
; CHECK-NEXT: bb:
; CHECK-NEXT: ret void
}

View File

@ -0,0 +1,51 @@
; RUN: opt -S -simplifycfg < %s | FileCheck %s
; SimplifyCFG should eliminate redundant indirectbr edges.
; CHECK: indbrtest0
; CHECK: indirectbr i8* %t, [label %BB0, label %BB1, label %BB2]
; CHECK: %x = phi i32 [ 0, %BB0 ], [ 1, %entry ]
declare void @foo()
declare void @A()
declare void @B(i32)
declare void @C()
define void @indbrtest0(i8** %P, i8** %Q) {
entry:
store i8* blockaddress(@indbrtest0, %BB0), i8** %P
store i8* blockaddress(@indbrtest0, %BB1), i8** %P
store i8* blockaddress(@indbrtest0, %BB2), i8** %P
call void @foo()
%t = load i8** %Q
indirectbr i8* %t, [label %BB0, label %BB1, label %BB2, label %BB0, label %BB1, label %BB2]
BB0:
call void @A()
br label %BB1
BB1:
%x = phi i32 [ 0, %BB0 ], [ 1, %entry ], [ 1, %entry ]
call void @B(i32 %x)
ret void
BB2:
call void @C()
ret void
}
; SimplifyCFG should convert the indirectbr into a directbr. It would be even
; better if it removed the branch altogether, but simplifycfdg currently misses
; that because the predecessor is the entry block.
; CHECK: indbrtest1
; CHECK: br label %BB0
define void @indbrtest1(i8** %P, i8** %Q) {
entry:
store i8* blockaddress(@indbrtest1, %BB0), i8** %P
call void @foo()
%t = load i8** %Q
indirectbr i8* %t, [label %BB0, label %BB0]
BB0:
call void @A()
ret void
}