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.

llvm-svn: 111060
This commit is contained in:
Dan Gohman 2010-08-14 00:29:42 +00:00
parent a4d3174cba
commit d04a608a73
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 /// of the CFG. It returns true if a modification was made, possibly deleting
/// the basic block that was pointed to. /// 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); bool SimplifyCFG(BasicBlock *BB, const TargetData *TD = 0);
/// FoldBranchToCommonDest - If this basic block is ONLY a setcc and a branch, /// 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) { while (LocalChange) {
LocalChange = false; LocalChange = false;
// Loop over all of the basic blocks (except the first one) and remove them // Loop over all of the basic blocks and remove them if they are unneeded...
// 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)) { if (SimplifyCFG(BBIt++, TD)) {
LocalChange = true; LocalChange = true;
++NumSimpl; ++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 /// rewriting all the predecessors to branch to the successor block and return
/// true. If we can't transform, return false. /// true. If we can't transform, return false.
bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB) { bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB) {
assert(BB != &BB->getParent()->getEntryBlock() &&
"TryToSimplifyUncondBranchFromEmptyBlock called on entry block!");
// We can't eliminate infinite loops. // We can't eliminate infinite loops.
BasicBlock *Succ = cast<BranchInst>(BB->getTerminator())->getSuccessor(0); BasicBlock *Succ = cast<BranchInst>(BB->getTerminator())->getSuccessor(0);
if (BB == Succ) return false; 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 && BB->getParent() && "Block not embedded in function!");
assert(BB->getTerminator() && "Degenerate basic block encountered!"); 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 // Remove basic blocks that have no predecessors (except the entry block)...
// as a predecessor. These are unreachable. // or that just have themself as a predecessor. These are unreachable.
if (pred_begin(BB) == pred_end(BB) || BB->getSinglePredecessor() == BB) { if ((pred_begin(BB) == pred_end(BB) &&
&BB->getParent()->getEntryBlock() != BB) ||
BB->getSinglePredecessor() == BB) {
DEBUG(dbgs() << "Removing BB: \n" << *BB); DEBUG(dbgs() << "Removing BB: \n" << *BB);
DeleteDeadBlock(BB); DeleteDeadBlock(BB);
return true; return true;
@ -1880,8 +1880,9 @@ bool SimplifyCFGOpt::run(BasicBlock *BB) {
while (isa<DbgInfoIntrinsic>(BBI)) while (isa<DbgInfoIntrinsic>(BBI))
++BBI; ++BBI;
if (BBI->isTerminator()) // Terminator is the only non-phi instruction! if (BBI->isTerminator()) // Terminator is the only non-phi instruction!
if (TryToSimplifyUncondBranchFromEmptyBlock(BB)) if (BB != &BB->getParent()->getEntryBlock())
return true; if (TryToSimplifyUncondBranchFromEmptyBlock(BB))
return true;
} else { // Conditional branch } else { // Conditional branch
if (isValueEqualityComparison(BI)) { if (isValueEqualityComparison(BI)) {
@ -2049,12 +2050,37 @@ bool SimplifyCFGOpt::run(BasicBlock *BB) {
} }
// If this block is now dead, remove it. // 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. // We know there are no successors, so just nuke the block.
M->getBasicBlockList().erase(BB); M->getBasicBlockList().erase(BB);
return true; 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 // 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 // is a conditional branch, see if we can hoist any code from this block up
// into our predecessor. // into our predecessor.
pred_iterator PI(pred_begin(BB)), PE(pred_end(BB)); pred_iterator PI(pred_begin(BB)), PE(pred_end(BB));
BasicBlock *OnlyPred = *PI++; BasicBlock *OnlyPred = 0;
for (; PI != PE; ++PI) // Search all predecessors, see if they are all same for (; PI != PE; ++PI) { // Search all predecessors, see if they are all same
if (*PI != OnlyPred) { if (!OnlyPred)
OnlyPred = *PI;
else if (*PI != OnlyPred) {
OnlyPred = 0; // There are multiple different predecessors... OnlyPred = 0; // There are multiple different predecessors...
break; break;
} }
}
if (OnlyPred) if (OnlyPred)
if (BranchInst *BI = dyn_cast<BranchInst>(OnlyPred->getTerminator())) 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 /// eliminates unreachable basic blocks, and does other "peephole" optimization
/// of the CFG. It returns true if a modification was made. /// 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) { bool llvm::SimplifyCFG(BasicBlock *BB, const TargetData *TD) {
return SimplifyCFGOpt(TD).run(BB); return SimplifyCFGOpt(TD).run(BB);
} }

View File

@ -54,6 +54,5 @@ bb1: ; preds = %entry
return: ; preds = %entry return: ; preds = %entry
ret void ret void
; CHECK: @test5 ; CHECK: @test5
; CHECK-NEXT: bb:
; CHECK-NEXT: ret void ; 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
}