mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 20:32:21 +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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@111060 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
3d72367d30
commit
e2c6d131d1
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -54,6 +54,5 @@ bb1: ; preds = %entry
|
||||
return: ; preds = %entry
|
||||
ret void
|
||||
; CHECK: @test5
|
||||
; CHECK-NEXT: bb:
|
||||
; 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…
Reference in New Issue
Block a user