summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: c4a8430)
raw | patch | inline | side by side (parent: c4a8430)
author | Rafael Espindola <rafael.espindola@gmail.com> | |
Wed, 29 Jun 2011 05:25:47 +0000 (05:25 +0000) | ||
committer | Rafael Espindola <rafael.espindola@gmail.com> | |
Wed, 29 Jun 2011 05:25:47 +0000 (05:25 +0000) |
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@134057 91177308-0d34-0410-b5e6-96231b3b80d8
include/llvm/BasicBlock.h | patch | blob | history | |
lib/Transforms/Utils/Local.cpp | patch | blob | history | |
lib/Transforms/Utils/SimplifyCFG.cpp | patch | blob | history | |
lib/VMCore/BasicBlock.cpp | patch | blob | history | |
test/Transforms/SimplifyCFG/lifetime.ll | [new file with mode: 0644] | patch | blob |
index b02c249c7ee6a0aebab369c5e9659e5a80fe6a87..3b953c06a81b3a869d9f6da1d2734907c5a77561 100644 (file)
return const_cast<BasicBlock*>(this)->getFirstNonPHIOrDbg();
}
+ // Same as above, but also skip lifetime intrinsics.
+ Instruction* getFirstNonPHIOrDbgOrLifetime();
+ const Instruction* getFirstNonPHIOrDbgOrLifetime() const {
+ return const_cast<BasicBlock*>(this)->getFirstNonPHIOrDbgOrLifetime();
+ }
+
/// removeFromParent - This method unlinks 'this' from the containing
/// function, but does not delete it.
///
index b1dd733ffe54f0494ff1ee9f63e051f1c2bb7d03..00469454851520093f3c4ff28ca8ab5973d92d20 100644 (file)
/// TryToSimplifyUncondBranchFromEmptyBlock - BB is known to contain an
/// unconditional branch, and contains no instructions other than PHI nodes,
-/// potential debug intrinsics and the branch. If possible, eliminate BB by
-/// rewriting all the predecessors to branch to the successor block and return
-/// true. If we can't transform, return false.
+/// potential side-effect free intrinsics and the branch. If possible,
+/// eliminate BB by 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!");
}
}
- while (PHINode *PN = dyn_cast<PHINode>(&BB->front())) {
- if (Succ->getSinglePredecessor()) {
- // BB is the only predecessor of Succ, so Succ will end up with exactly
- // the same predecessors BB had.
- Succ->getInstList().splice(Succ->begin(),
- BB->getInstList(), BB->begin());
- } else {
+ if (Succ->getSinglePredecessor()) {
+ // BB is the only predecessor of Succ, so Succ will end up with exactly
+ // the same predecessors BB had.
+
+ // Copy over any phi, debug or lifetime instruction.
+ BB->getTerminator()->eraseFromParent();
+ Succ->getInstList().splice(Succ->begin(), BB->getInstList());
+ } else {
+ while (PHINode *PN = dyn_cast<PHINode>(&BB->front())) {
// We explicitly check for such uses in CanPropagatePredecessorsForPHIs.
assert(PN->use_empty() && "There shouldn't be any uses here!");
PN->eraseFromParent();
index 7b93b4a8e25e7afdc5937a722502ec35946481b6..49726d5533dd9d11b6b00db62a488bdcb8380fd6 100644 (file)
@@ -2604,7 +2604,7 @@ bool SimplifyCFGOpt::SimplifyUncondBranch(BranchInst *BI, IRBuilder<> &Builder){
BasicBlock *BB = BI->getParent();
// If the Terminator is the only non-phi instruction, simplify the block.
- BasicBlock::iterator I = BB->getFirstNonPHIOrDbg();
+ BasicBlock::iterator I = BB->getFirstNonPHIOrDbgOrLifetime();
if (I->isTerminator() && BB != &BB->getParent()->getEntryBlock() &&
TryToSimplifyUncondBranchFromEmptyBlock(BB))
return true;
index 7d470440affbe85c97b147fb90ee61a01cd8f9fd..70265c899d7e8714a95546109644673aa47fa839 100644 (file)
return &*i;
}
+Instruction* BasicBlock::getFirstNonPHIOrDbgOrLifetime() {
+ // All valid basic blocks should have a terminator,
+ // which is not a PHINode. If we have an invalid basic
+ // block we'll get an assertion failure when dereferencing
+ // a past-the-end iterator.
+ BasicBlock::iterator i = begin();
+ for (;; ++i) {
+ if (isa<PHINode>(i) || isa<DbgInfoIntrinsic>(i))
+ continue;
+
+ const IntrinsicInst *II = dyn_cast<IntrinsicInst>(i);
+ if (!II)
+ break;
+ if (II->getIntrinsicID() != Intrinsic::lifetime_start &&
+ II->getIntrinsicID() != Intrinsic::lifetime_end)
+ break;
+ }
+ return &*i;
+}
+
void BasicBlock::dropAllReferences() {
for(iterator I = begin(), E = end(); I != E; ++I)
I->dropAllReferences();
diff --git a/test/Transforms/SimplifyCFG/lifetime.ll b/test/Transforms/SimplifyCFG/lifetime.ll
--- /dev/null
@@ -0,0 +1,29 @@
+; RUN: opt < %s -simplifycfg -S | FileCheck %s
+
+; Test that a lifetime intrinsic doesn't prevent us from simplifying this.
+
+; CHECK: foo
+; CHECK: entry:
+; CHECK-NOT: bb0:
+; CHECK-NOT: bb1:
+; CHECK: ret
+define void @foo(i1 %x) {
+entry:
+ %a = alloca i8
+ call void @llvm.lifetime.start(i64 -1, i8* %a) nounwind
+ br i1 %x, label %bb0, label %bb1
+
+bb0:
+ call void @llvm.lifetime.end(i64 -1, i8* %a) nounwind
+ br label %bb1
+
+bb1:
+ call void @f()
+ ret void
+}
+
+declare void @f()
+
+declare void @llvm.lifetime.start(i64, i8* nocapture) nounwind
+
+declare void @llvm.lifetime.end(i64, i8* nocapture) nounwind