Make LoopDeletion work on loops with multiple edges, as long as the incoming
authorCameron Zwarich <zwarich@apple.com>
Tue, 22 Feb 2011 22:25:39 +0000 (22:25 +0000)
committerCameron Zwarich <zwarich@apple.com>
Tue, 22 Feb 2011 22:25:39 +0000 (22:25 +0000)
values from all of the loop's exiting blocks are equal. Patch by Andrew Clinton.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@126253 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/Scalar/LoopDeletion.cpp
test/Transforms/LoopDeletion/multiple-exits.ll [new file with mode: 0644]

index 6d1d344a9296537888c7028d7e2ecff2c15033fd..753a558cfe83aa1ebb1aacca811c1ae5afb7072f 100644 (file)
@@ -78,7 +78,6 @@ bool LoopDeletion::IsLoopDead(Loop* L,
                               SmallVector<BasicBlock*, 4>& exitingBlocks,
                               SmallVector<BasicBlock*, 4>& exitBlocks,
                               bool &Changed, BasicBlock *Preheader) {
-  BasicBlock* exitingBlock = exitingBlocks[0];
   BasicBlock* exitBlock = exitBlocks[0];
   
   // Make sure that all PHI entries coming from the loop are loop invariant.
@@ -88,11 +87,21 @@ bool LoopDeletion::IsLoopDead(Loop* L,
   // of the loop.
   BasicBlock::iterator BI = exitBlock->begin();
   while (PHINode* P = dyn_cast<PHINode>(BI)) {
-    Value* incoming = P->getIncomingValueForBlock(exitingBlock);
+    Value* incoming = P->getIncomingValueForBlock(exitingBlocks[0]);
+
+    // Make sure all exiting blocks produce the same incoming value for the exit
+    // block.  If there are different incoming values for different exiting
+    // blocks, then it is impossible to statically determine which value should
+    // be used.
+    for (unsigned i = 1; i < exitingBlocks.size(); ++i) {
+      if (incoming != P->getIncomingValueForBlock(exitingBlocks[i]))
+        return false;
+    }
+      
     if (Instruction* I = dyn_cast<Instruction>(incoming))
       if (!L->makeLoopInvariant(I, Changed, Preheader->getTerminator()))
         return false;
-      
+
     ++BI;
   }
   
@@ -147,10 +156,6 @@ bool LoopDeletion::runOnLoop(Loop* L, LPPassManager& LPM) {
   if (exitBlocks.size() != 1)
     return false;
   
-  // Loops with multiple exits are too complicated to handle correctly.
-  if (exitingBlocks.size() != 1)
-    return false;
-  
   // Finally, we have to check that the loop really is dead.
   bool Changed = false;
   if (!IsLoopDead(L, exitingBlocks, exitBlocks, Changed, preheader))
@@ -166,7 +171,6 @@ bool LoopDeletion::runOnLoop(Loop* L, LPPassManager& LPM) {
   // Now that we know the removal is safe, remove the loop by changing the
   // branch from the preheader to go to the single exit block.  
   BasicBlock* exitBlock = exitBlocks[0];
-  BasicBlock* exitingBlock = exitingBlocks[0];
   
   // Because we're deleting a large chunk of code at once, the sequence in which
   // we remove things is very important to avoid invalidation issues.  Don't
@@ -183,9 +187,12 @@ bool LoopDeletion::runOnLoop(Loop* L, LPPassManager& LPM) {
 
   // Rewrite phis in the exit block to get their inputs from
   // the preheader instead of the exiting block.
+  BasicBlock* exitingBlock = exitingBlocks[0];
   BasicBlock::iterator BI = exitBlock->begin();
   while (PHINode* P = dyn_cast<PHINode>(BI)) {
     P->replaceUsesOfWith(exitingBlock, preheader);
+    for (unsigned i = 1; i < exitingBlocks.size(); ++i)
+      P->removeIncomingValue(exitingBlocks[i]);
     ++BI;
   }
   
diff --git a/test/Transforms/LoopDeletion/multiple-exits.ll b/test/Transforms/LoopDeletion/multiple-exits.ll
new file mode 100644 (file)
index 0000000..6af413b
--- /dev/null
@@ -0,0 +1,26 @@
+; RUN: opt < %s -loop-deletion -S | FileCheck %s
+
+; Checks whether dead loops with multiple exits can be eliminated
+
+; CHECK:      entry:
+; CHECK-NEXT:   br label %return
+
+; CHECK:      return:
+; CHECK-NEXT:   ret void
+
+define void @foo(i64 %n, i64 %m) nounwind {
+entry:
+  br label %bb
+
+bb:
+  %x.0 = phi i64 [ 0, %entry ], [ %t0, %bb2 ]
+  %t0 = add i64 %x.0, 1
+  %t1 = icmp slt i64 %x.0, %n
+  br i1 %t1, label %bb2, label %return
+bb2:
+  %t2 = icmp slt i64 %x.0, %m
+  br i1 %t1, label %bb, label %return
+
+return:
+  ret void
+}