diff options
author | Dan Gohman <gohman@apple.com> | 2010-08-14 00:29:42 +0000 |
---|---|---|
committer | Dan Gohman <gohman@apple.com> | 2010-08-14 00:29:42 +0000 |
commit | e2c6d131d12c779a410740e0a90545def75e0f48 (patch) | |
tree | e899545fbab9934f663643c00460d582f83819de | |
parent | 3d72367d30c9ce6f387764a028763f7a366cc443 (diff) | |
download | external_llvm-e2c6d131d12c779a410740e0a90545def75e0f48.zip external_llvm-e2c6d131d12c779a410740e0a90545def75e0f48.tar.gz external_llvm-e2c6d131d12c779a410740e0a90545def75e0f48.tar.bz2 |
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
-rw-r--r-- | include/llvm/Transforms/Utils/Local.h | 2 | ||||
-rw-r--r-- | lib/Transforms/Scalar/SimplifyCFGPass.cpp | 5 | ||||
-rw-r--r-- | lib/Transforms/Utils/Local.cpp | 3 | ||||
-rw-r--r-- | lib/Transforms/Utils/SimplifyCFG.cpp | 53 | ||||
-rw-r--r-- | test/Transforms/SimplifyCFG/basictest.ll | 1 | ||||
-rw-r--r-- | test/Transforms/SimplifyCFG/indirectbr.ll | 51 |
6 files changed, 96 insertions, 19 deletions
diff --git a/include/llvm/Transforms/Utils/Local.h b/include/llvm/Transforms/Utils/Local.h index b277970..caae27f 100644 --- a/include/llvm/Transforms/Utils/Local.h +++ b/include/llvm/Transforms/Utils/Local.h @@ -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, diff --git a/lib/Transforms/Scalar/SimplifyCFGPass.cpp b/lib/Transforms/Scalar/SimplifyCFGPass.cpp index df6ef2e..360749c 100644 --- a/lib/Transforms/Scalar/SimplifyCFGPass.cpp +++ b/lib/Transforms/Scalar/SimplifyCFGPass.cpp @@ -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; diff --git a/lib/Transforms/Utils/Local.cpp b/lib/Transforms/Utils/Local.cpp index 8e91138..52f0499 100644 --- a/lib/Transforms/Utils/Local.cpp +++ b/lib/Transforms/Utils/Local.cpp @@ -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; diff --git a/lib/Transforms/Utils/SimplifyCFG.cpp b/lib/Transforms/Utils/SimplifyCFG.cpp index 36a245f..db719a0 100644 --- a/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/lib/Transforms/Utils/SimplifyCFG.cpp @@ -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); } diff --git a/test/Transforms/SimplifyCFG/basictest.ll b/test/Transforms/SimplifyCFG/basictest.ll index 83a9fa7..7315ff6 100644 --- a/test/Transforms/SimplifyCFG/basictest.ll +++ b/test/Transforms/SimplifyCFG/basictest.ll @@ -54,6 +54,5 @@ bb1: ; preds = %entry return: ; preds = %entry ret void ; CHECK: @test5 -; CHECK-NEXT: bb: ; CHECK-NEXT: ret void } diff --git a/test/Transforms/SimplifyCFG/indirectbr.ll b/test/Transforms/SimplifyCFG/indirectbr.ll new file mode 100644 index 0000000..b13433c --- /dev/null +++ b/test/Transforms/SimplifyCFG/indirectbr.ll @@ -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 +} + |