[llvm] r262978 - [SCEV] Slightly generalize getRangeViaFactoring

Sanjoy Das via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 8 17:50:57 PST 2016


Author: sanjoy
Date: Tue Mar  8 19:50:57 2016
New Revision: 262978

URL: http://llvm.org/viewvc/llvm-project?rev=262978&view=rev
Log:
[SCEV] Slightly generalize getRangeViaFactoring

This change generalizes ScalarEvolution::getRangeViaFactoring to work
with {Ext(C?A:B),+,Ext(C?A:B)} where Ext can be a zero extend, sign
extend or truncate operation.

Modified:
    llvm/trunk/lib/Analysis/ScalarEvolution.cpp
    llvm/trunk/test/Analysis/ScalarEvolution/increasing-or-decreasing-iv.ll

Modified: llvm/trunk/lib/Analysis/ScalarEvolution.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ScalarEvolution.cpp?rev=262978&r1=262977&r2=262978&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/ScalarEvolution.cpp (original)
+++ llvm/trunk/lib/Analysis/ScalarEvolution.cpp Tue Mar  8 19:50:57 2016
@@ -4568,42 +4568,70 @@ ConstantRange ScalarEvolution::getRangeV
     Start = SA->getOperand(1);
   }
 
-  if (!isa<SCEVUnknown>(Start) || !isa<SCEVUnknown>(Step))
-    // We don't have anything new to contribute in this case.
-    return ConstantRange(BitWidth, /* isFullSet = */ true);
-
   //    RangeOf({C?A:B,+,C?P:Q}) == RangeOf(C?{A,+,P}:{B,+,Q})
   // == RangeOf({A,+,P}) union RangeOf({B,+,Q})
 
   struct SelectPattern {
     Value *Condition = nullptr;
-    const APInt *TrueValue = nullptr;
-    const APInt *FalseValue = nullptr;
+    APInt TrueValue;
+    APInt FalseValue;
+
+    explicit SelectPattern(ScalarEvolution &SE, unsigned BitWidth,
+                           const SCEV *S) {
+      Optional<unsigned> CastOp;
+
+      assert(SE.getTypeSizeInBits(S->getType()) == BitWidth &&
+             "Should be!");
+
+      // Peel off a cast operation
+      if (auto *SCast = dyn_cast<SCEVCastExpr>(S)) {
+        CastOp = SCast->getSCEVType();
+        S = SCast->getOperand();
+      }
 
-    explicit SelectPattern(const SCEVUnknown *SU) {
       using namespace llvm::PatternMatch;
 
-      if (!match(SU->getValue(),
-                 m_Select(m_Value(Condition), m_APInt(TrueValue),
-                          m_APInt(FalseValue)))) {
+      auto *SU = dyn_cast<SCEVUnknown>(S);
+      const APInt *TrueVal, *FalseVal;
+      if (!SU ||
+          !match(SU->getValue(), m_Select(m_Value(Condition), m_APInt(TrueVal),
+                                          m_APInt(FalseVal)))) {
         Condition = nullptr;
-        TrueValue = FalseValue = nullptr;
+        return;
       }
-    }
 
-    bool isRecognized() {
-      assert(((Condition && TrueValue && FalseValue) ||
-              (!Condition && !TrueValue && !FalseValue)) &&
-             "Invariant: either all three are non-null or all three are null");
-      return TrueValue != nullptr;
+      TrueValue = *TrueVal;
+      FalseValue = *FalseVal;
+
+      // Re-apply the cast we peeled off earlier
+      if (CastOp.hasValue())
+        switch (*CastOp) {
+        default:
+          llvm_unreachable("Unknown SCEV cast type!");
+
+        case scTruncate:
+          TrueValue = TrueValue.trunc(BitWidth);
+          FalseValue = FalseValue.trunc(BitWidth);
+          break;
+        case scZeroExtend:
+          TrueValue = TrueValue.zext(BitWidth);
+          FalseValue = FalseValue.zext(BitWidth);
+          break;
+        case scSignExtend:
+          TrueValue = TrueValue.sext(BitWidth);
+          FalseValue = FalseValue.sext(BitWidth);
+          break;
+        }
     }
+
+    bool isRecognized() { return Condition != nullptr; }
   };
 
-  SelectPattern StartPattern(cast<SCEVUnknown>(Start));
+  SelectPattern StartPattern(*this, BitWidth, Start);
   if (!StartPattern.isRecognized())
     return ConstantRange(BitWidth, /* isFullSet = */ true);
 
-  SelectPattern StepPattern(cast<SCEVUnknown>(Step));
+  SelectPattern StepPattern(*this, BitWidth, Step);
   if (!StepPattern.isRecognized())
     return ConstantRange(BitWidth, /* isFullSet = */ true);
 
@@ -4622,10 +4650,10 @@ ConstantRange ScalarEvolution::getRangeV
   // FIXME: without the explicit `this` receiver below, MSVC errors out with
   // C2352 and C2512 (otherwise it isn't needed).
 
-  const SCEV *TrueStart = this->getConstant(*StartPattern.TrueValue + Offset);
-  const SCEV *TrueStep = this->getConstant(*StepPattern.TrueValue);
-  const SCEV *FalseStart = this->getConstant(*StartPattern.FalseValue + Offset);
-  const SCEV *FalseStep = this->getConstant(*StepPattern.FalseValue);
+  const SCEV *TrueStart = this->getConstant(StartPattern.TrueValue + Offset);
+  const SCEV *TrueStep = this->getConstant(StepPattern.TrueValue);
+  const SCEV *FalseStart = this->getConstant(StartPattern.FalseValue + Offset);
+  const SCEV *FalseStep = this->getConstant(StepPattern.FalseValue);
 
   ConstantRange TrueRange =
       this->getRangeForAffineAR(TrueStart, TrueStep, MaxBECount, BitWidth);

Modified: llvm/trunk/test/Analysis/ScalarEvolution/increasing-or-decreasing-iv.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/ScalarEvolution/increasing-or-decreasing-iv.ll?rev=262978&r1=262977&r2=262978&view=diff
==============================================================================
--- llvm/trunk/test/Analysis/ScalarEvolution/increasing-or-decreasing-iv.ll (original)
+++ llvm/trunk/test/Analysis/ScalarEvolution/increasing-or-decreasing-iv.ll Tue Mar  8 19:50:57 2016
@@ -100,7 +100,7 @@ loop:
   %iv.sext = sext i32 %iv to i64
   %iv.next = add i32 %iv, %step
 ; CHECK:  %iv.sext = sext i32 %iv to i64
-; CHECK-NEXT:  -->  {(sext i32 %start to i64),+,(sext i32 %step to i64)}<nsw><%loop>
+; CHECK-NEXT:   -->  {(sext i32 %start to i64),+,(sext i32 %step to i64)}<nsw><%loop> U: [0,128) S: [0,128)
   %loop.iv.inc = add i32 %loop.iv, 1
   %be.cond = icmp ne i32 %loop.iv.inc, 128
   br i1 %be.cond, label %loop, label %leave
@@ -128,11 +128,62 @@ loop:
   %iv = phi i16 [ %start, %entry ], [ %iv.next, %loop ]
   %iv.zext = zext i16 %iv to i64
 ; CHECK:  %iv.zext = zext i16 %iv to i64
-; CHECK-NEXT:  -->  {(zext i16 %start to i64),+,(zext i16 %step to i64)}<nuw><%loop>
+; CHECK-NEXT:  -->  {(zext i16 %start to i64),+,(zext i16 %step to i64)}<nuw><%loop> U: [0,64644) S: [0,64644)
   %iv.next = add i16 %iv, %step
   %loop.iv.inc = add i16 %loop.iv, 1
   %be.cond = icmp ne i16 %loop.iv.inc, 128
   br i1 %be.cond, label %loop, label %leave
+
+leave:
+  ret void
+}
+
+define void @f4(i1 %c) {
+; CHECK-LABEL: Classifying expressions for: @f4
+
+; @f4() demonstrates a case where SCEV is not able to compute a
+; precise range for %iv.trunc, though it should be able to, in theory.
+; This is because SCEV looks into affine add recurrences only when the
+; backedge taken count of the loop has the same bitwidth as the
+; induction variable.
+entry:
+  %start = select i1 %c, i32 127, i32 0
+  %step  = select i1 %c, i32 -1,  i32 1
+  br label %loop
+
+loop:
+  %loop.iv = phi i32 [ 0, %entry ], [ %loop.iv.inc, %loop ]
+  %iv = phi i32 [ %start, %entry ], [ %iv.next, %loop ]
+  %iv.trunc = trunc i32 %iv to i16
+; CHECK:  %iv.trunc = trunc i32 %iv to i16
+; CHECK-NEXT:   -->  {(trunc i32 %start to i16),+,(trunc i32 %step to i16)}<%loop> U: full-set S: full-set
+  %iv.next = add i32 %iv, %step
+  %loop.iv.inc = add i32 %loop.iv, 1
+  %be.cond = icmp ne i32 %loop.iv.inc, 128
+  br i1 %be.cond, label %loop, label %leave
+
+leave:
+  ret void
+}
+
+define void @f5(i1 %c) {
+; CHECK-LABEL: Classifying expressions for: @f5
+entry:
+  %start = select i1 %c, i32 127, i32 0
+  %step  = select i1 %c, i32 -1,  i32 1
+  br label %loop
+
+loop:
+  %loop.iv = phi i16 [ 0, %entry ], [ %loop.iv.inc, %loop ]
+  %iv = phi i32 [ %start, %entry ], [ %iv.next, %loop ]
+  %iv.trunc = trunc i32 %iv to i16
+; CHECK:  %iv.trunc = trunc i32 %iv to i16
+; CHECK-NEXT:  -->  {(trunc i32 %start to i16),+,(trunc i32 %step to i16)}<%loop> U: [0,128) S: [0,128)
+  %iv.next = add i32 %iv, %step
+
+  %loop.iv.inc = add i16 %loop.iv, 1
+  %be.cond = icmp ne i16 %loop.iv.inc, 128
+  br i1 %be.cond, label %loop, label %leave
 
 leave:
   ret void




More information about the llvm-commits mailing list