Fix a corner case in the new indvars promotion logic: if there
authorDan Gohman <gohman@apple.com>
Wed, 18 Feb 2009 00:52:00 +0000 (00:52 +0000)
committerDan Gohman <gohman@apple.com>
Wed, 18 Feb 2009 00:52:00 +0000 (00:52 +0000)
are multiple IV's in a loop, some of them may under go signed
or unsigned wrapping even if the IV that's used in the loop
exit condition doesn't. Restrict sign-extension-elimination
and zero-extension-elimination to only those that operate on
the original loop-controlling IV.

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

lib/Transforms/Scalar/IndVarSimplify.cpp
test/Transforms/IndVarSimplify/preserve-signed-wrap.ll [new file with mode: 0644]

index 4cfe3595beeaa2d075ec7b9dbe1263e410affe22..c496c57836f37af7b546b0391ca27999fc3b56b9 100644 (file)
@@ -463,21 +463,24 @@ static const Type *getEffectiveIndvarType(const PHINode *Phi) {
 }
 
 /// TestOrigIVForWrap - Analyze the original induction variable
-/// in the loop to determine whether it would ever undergo signed
-/// or unsigned overflow.
+/// that controls the loop's iteration to determine whether it
+/// would ever undergo signed or unsigned overflow.
+///
+/// In addition to setting the NoSignedWrap and NoUnsignedWrap
+/// variables, return the PHI for this induction variable.
 ///
 /// TODO: This duplicates a fair amount of ScalarEvolution logic.
 /// Perhaps this can be merged with ScalarEvolution::getIterationCount
 /// and/or ScalarEvolution::get{Sign,Zero}ExtendExpr.
 ///
-static void TestOrigIVForWrap(const Loop *L,
-                              const BranchInst *BI,
-                              const Instruction *OrigCond,
-                              bool &NoSignedWrap,
-                              bool &NoUnsignedWrap) {
+static const PHINode *TestOrigIVForWrap(const Loop *L,
+                                        const BranchInst *BI,
+                                        const Instruction *OrigCond,
+                                        bool &NoSignedWrap,
+                                        bool &NoUnsignedWrap) {
   // Verify that the loop is sane and find the exit condition.
   const ICmpInst *Cmp = dyn_cast<ICmpInst>(OrigCond);
-  if (!Cmp) return;
+  if (!Cmp) return 0;
 
   const Value *CmpLHS = Cmp->getOperand(0);
   const Value *CmpRHS = Cmp->getOperand(1);
@@ -530,7 +533,7 @@ static void TestOrigIVForWrap(const Loop *L,
   }
   // For now, analyze only LT loops for signed overflow.
   if (Pred != ICmpInst::ICMP_SLT && Pred != ICmpInst::ICMP_ULT)
-    return;
+    return 0;
 
   bool isSigned = Pred == ICmpInst::ICMP_SLT;
 
@@ -543,7 +546,7 @@ static void TestOrigIVForWrap(const Loop *L,
       if (!isa<ConstantInt>(CmpRHS) ||
           !cast<ConstantInt>(CmpRHS)->getValue()
             .isSignedIntN(IncrVal->getType()->getPrimitiveSizeInBits()))
-        return;
+        return 0;
       IncrVal = SI->getOperand(0);
     }
   } else {
@@ -551,7 +554,7 @@ static void TestOrigIVForWrap(const Loop *L,
       if (!isa<ConstantInt>(CmpRHS) ||
           !cast<ConstantInt>(CmpRHS)->getValue()
             .isIntN(IncrVal->getType()->getPrimitiveSizeInBits()))
-        return;
+        return 0;
       IncrVal = ZI->getOperand(0);
     }
   }
@@ -562,26 +565,26 @@ static void TestOrigIVForWrap(const Loop *L,
       IncrOp->getOpcode() != Instruction::Add ||
       !isa<ConstantInt>(IncrOp->getOperand(1)) ||
       !cast<ConstantInt>(IncrOp->getOperand(1))->equalsInt(1))
-    return;
+    return 0;
 
   // Make sure the PHI looks like a normal IV.
   const PHINode *PN = dyn_cast<PHINode>(IncrOp->getOperand(0));
   if (!PN || PN->getNumIncomingValues() != 2)
-    return;
+    return 0;
   unsigned IncomingEdge = L->contains(PN->getIncomingBlock(0));
   unsigned BackEdge = !IncomingEdge;
   if (!L->contains(PN->getIncomingBlock(BackEdge)) ||
       PN->getIncomingValue(BackEdge) != IncrOp)
-    return;
+    return 0;
   if (!L->contains(TrueBB))
-    return;
+    return 0;
 
   // For now, only analyze loops with a constant start value, so that
   // we can easily determine if the start value is not a maximum value
   // which would wrap on the first iteration.
   const Value *InitialVal = PN->getIncomingValue(IncomingEdge);
   if (!isa<ConstantInt>(InitialVal))
-    return;
+    return 0;
 
   // The original induction variable will start at some non-max value,
   // it counts up by one, and the loop iterates only while it remans
@@ -592,6 +595,7 @@ static void TestOrigIVForWrap(const Loop *L,
   else if (!isSigned &&
            !cast<ConstantInt>(InitialVal)->getValue().isMaxValue())
     NoUnsignedWrap = true;
+  return PN;
 }
 
 bool IndVarSimplify::runOnLoop(Loop *L, LPPassManager &LPM) {
@@ -675,13 +679,15 @@ bool IndVarSimplify::runOnLoop(Loop *L, LPPassManager &LPM) {
   // using it.  We can currently only handle loops with a single exit.
   bool NoSignedWrap = false;
   bool NoUnsignedWrap = false;
+  const PHINode *OrigControllingPHI = 0;
   if (!isa<SCEVCouldNotCompute>(IterationCount) && ExitingBlock)
     // Can't rewrite non-branch yet.
     if (BranchInst *BI = dyn_cast<BranchInst>(ExitingBlock->getTerminator())) {
       if (Instruction *OrigCond = dyn_cast<Instruction>(BI->getCondition())) {
         // Determine if the OrigIV will ever undergo overflow.
-        TestOrigIVForWrap(L, BI, OrigCond,
-                          NoSignedWrap, NoUnsignedWrap);
+        OrigControllingPHI =
+          TestOrigIVForWrap(L, BI, OrigCond,
+                            NoSignedWrap, NoUnsignedWrap);
 
         // We'll be replacing the original condition, so it'll be dead.
         DeadInsts.insert(OrigCond);
@@ -722,7 +728,7 @@ bool IndVarSimplify::runOnLoop(Loop *L, LPPassManager &LPM) {
     /// If the new canonical induction variable is wider than the original,
     /// and the original has uses that are casts to wider types, see if the
     /// truncate and extend can be omitted.
-    if (PN->getType() != LargestType)
+    if (PN == OrigControllingPHI && PN->getType() != LargestType)
       for (Value::use_iterator UI = PN->use_begin(), UE = PN->use_end();
            UI != UE; ++UI) {
         if (isa<SExtInst>(UI) && NoSignedWrap) {
diff --git a/test/Transforms/IndVarSimplify/preserve-signed-wrap.ll b/test/Transforms/IndVarSimplify/preserve-signed-wrap.ll
new file mode 100644 (file)
index 0000000..0a91ec8
--- /dev/null
@@ -0,0 +1,38 @@
+; RUN: llvm-as < %s | opt -indvars | llvm-dis > %t
+; RUN: grep sext %t | count 1
+; RUN: grep phi %t | count 1
+; RUN: grep {phi i64} %t
+
+; Indvars should insert a 64-bit induction variable to eliminate the
+; sext for the addressing, however it shouldn't eliminate the sext
+; on the other phi, since that value undergoes signed wrapping.
+
+define void @foo(i32* nocapture %d, i32 %n) nounwind {
+entry:
+       %0 = icmp sgt i32 %n, 0         ; <i1> [#uses=1]
+       br i1 %0, label %bb.nph, label %return
+
+bb.nph:                ; preds = %entry
+       br label %bb
+
+bb:            ; preds = %bb1, %bb.nph
+       %i.02 = phi i32 [ %5, %bb1 ], [ 0, %bb.nph ]            ; <i32> [#uses=2]
+       %p.01 = phi i8 [ %4, %bb1 ], [ -1, %bb.nph ]            ; <i8> [#uses=2]
+       %1 = sext i8 %p.01 to i32               ; <i32> [#uses=1]
+       %2 = sext i32 %i.02 to i64              ; <i64> [#uses=1]
+       %3 = getelementptr i32* %d, i64 %2              ; <i32*> [#uses=1]
+       store i32 %1, i32* %3, align 4
+       %4 = add i8 %p.01, 1            ; <i8> [#uses=1]
+       %5 = add i32 %i.02, 1           ; <i32> [#uses=2]
+       br label %bb1
+
+bb1:           ; preds = %bb
+       %6 = icmp slt i32 %5, %n                ; <i1> [#uses=1]
+       br i1 %6, label %bb, label %bb1.return_crit_edge
+
+bb1.return_crit_edge:          ; preds = %bb1
+       br label %return
+
+return:                ; preds = %bb1.return_crit_edge, %entry
+       ret void
+}