summaryrefslogtreecommitdiff
path: root/lib/Transforms
diff options
context:
space:
mode:
authorFrits van Bommel <fvbommel@gmail.com>2010-12-05 18:29:03 +0000
committerFrits van Bommel <fvbommel@gmail.com>2010-12-05 18:29:03 +0000
commit7ac40c3ffabcdac9510e7efc4dc75a8ed2b32edb (patch)
treee04a4e375c69339e12fa1bce68fe901d2ba6a9f3 /lib/Transforms
parent9637d5b22ec655d9b2f6cdb5fb23b0ce0ec9c8a5 (diff)
downloadllvm-7ac40c3ffabcdac9510e7efc4dc75a8ed2b32edb.tar.gz
llvm-7ac40c3ffabcdac9510e7efc4dc75a8ed2b32edb.tar.bz2
llvm-7ac40c3ffabcdac9510e7efc4dc75a8ed2b32edb.tar.xz
Teach SimplifyCFG to turn
(indirectbr (select cond, blockaddress(@fn, BlockA), blockaddress(@fn, BlockB))) into (br cond, BlockA, BlockB). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@120943 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Transforms')
-rw-r--r--lib/Transforms/Utils/SimplifyCFG.cpp74
1 files changed, 72 insertions, 2 deletions
diff --git a/lib/Transforms/Utils/SimplifyCFG.cpp b/lib/Transforms/Utils/SimplifyCFG.cpp
index de1f12ec1b..8e3ca419af 100644
--- a/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -374,6 +374,8 @@ static void EraseTerminatorInstAndDCECond(TerminatorInst *TI) {
} else if (BranchInst *BI = dyn_cast<BranchInst>(TI)) {
if (BI->isConditional())
Cond = dyn_cast<Instruction>(BI->getCondition());
+ } else if (IndirectBrInst *IBI = dyn_cast<IndirectBrInst>(TI)) {
+ Cond = dyn_cast<Instruction>(IBI->getAddress());
}
TI->eraseFromParent();
@@ -1718,6 +1720,71 @@ static bool SimplifyCondBranchToCondBranch(BranchInst *PBI, BranchInst *BI) {
return true;
}
+// SimplifyIndirectBrOnSelect - Replaces
+// (indirectbr (select cond, blockaddress(@fn, BlockA),
+// blockaddress(@fn, BlockB)))
+// with
+// (br cond, BlockA, BlockB).
+static bool SimplifyIndirectBrOnSelect(IndirectBrInst *IBI, SelectInst *SI) {
+ // Check that both operands of the select are block addresses.
+ BlockAddress *TBA = dyn_cast<BlockAddress>(SI->getTrueValue());
+ BlockAddress *FBA = dyn_cast<BlockAddress>(SI->getFalseValue());
+ if (!TBA || !FBA)
+ return false;
+
+ // Extract the actual blocks.
+ BasicBlock *TrueBB = TBA->getBasicBlock();
+ BasicBlock *FalseBB = FBA->getBasicBlock();
+
+ // Remove any superfluous successor edges from the CFG.
+ // First, figure out which successors to preserve.
+ // If TrueBB and FalseBB are equal, only try to preserve one copy of that
+ // successor.
+ BasicBlock *KeepEdge1 = TrueBB;
+ BasicBlock *KeepEdge2 = TrueBB != FalseBB ? FalseBB : 0;
+
+ // Then remove the rest.
+ for (unsigned I = 0, E = IBI->getNumSuccessors(); I != E; ++I) {
+ BasicBlock *Succ = IBI->getSuccessor(I);
+ // Make sure only to keep exactly one copy of each edge.
+ if (Succ == KeepEdge1)
+ KeepEdge1 = 0;
+ else if (Succ == KeepEdge2)
+ KeepEdge2 = 0;
+ else
+ Succ->removePredecessor(IBI->getParent());
+ }
+
+ // Insert an appropriate new terminator.
+ if ((KeepEdge1 == 0) && (KeepEdge2 == 0)) {
+ if (TrueBB == FalseBB)
+ // We were only looking for one successor, and it was present.
+ // Create an unconditional branch to it.
+ BranchInst::Create(TrueBB, IBI);
+ else
+ // We found both of the successors we were looking for.
+ // Create a conditional branch sharing the condition of the select.
+ BranchInst::Create(TrueBB, FalseBB, SI->getCondition(), IBI);
+ } else if (KeepEdge1 && (KeepEdge2 || TrueBB == FalseBB)) {
+ // Neither of the selected blocks were successors, so this
+ // indirectbr must be unreachable.
+ new UnreachableInst(IBI->getContext(), IBI);
+ } else {
+ // One of the selected values was a successor, but the other wasn't.
+ // Insert an unconditional branch to the one that was found;
+ // the edge to the one that wasn't must be unreachable.
+ if (KeepEdge1 == 0)
+ // Only TrueBB was found.
+ BranchInst::Create(TrueBB, IBI);
+ else
+ // Only FalseBB was found.
+ BranchInst::Create(FalseBB, IBI);
+ }
+
+ EraseTerminatorInstAndDCECond(IBI);
+ return true;
+}
+
bool SimplifyCFGOpt::run(BasicBlock *BB) {
bool Changed = false;
Function *Fn = BB->getParent();
@@ -2072,13 +2139,16 @@ bool SimplifyCFGOpt::run(BasicBlock *BB) {
if (IBI->getNumDestinations() == 0) {
// If the indirectbr has no successors, change it to unreachable.
new UnreachableInst(IBI->getContext(), IBI);
- IBI->eraseFromParent();
+ EraseTerminatorInstAndDCECond(IBI);
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();
+ EraseTerminatorInstAndDCECond(IBI);
Changed = true;
+ } else if (SelectInst *SI = dyn_cast<SelectInst>(IBI->getAddress())) {
+ if (SimplifyIndirectBrOnSelect(IBI, SI))
+ return SimplifyCFG(BB) | true;
}
}