mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-04-10 03:30:59 +00:00
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:
parent
a4d3174cba
commit
d04a608a73
@ -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,
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
51
test/Transforms/SimplifyCFG/indirectbr.ll
Normal file
51
test/Transforms/SimplifyCFG/indirectbr.ll
Normal 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
|
||||||
|
}
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user