[llvm] 2734a9e - [NFC][SCEV] Generalize monotonicity check for full and limited iteration space

Max Kazantsev via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 11 21:37:36 PST 2020


Author: Max Kazantsev
Date: 2020-11-12T12:37:07+07:00
New Revision: 2734a9ebf4a31df0131acdfc739395a5e692c342

URL: https://github.com/llvm/llvm-project/commit/2734a9ebf4a31df0131acdfc739395a5e692c342
DIFF: https://github.com/llvm/llvm-project/commit/2734a9ebf4a31df0131acdfc739395a5e692c342.diff

LOG: [NFC][SCEV] Generalize monotonicity check for full and limited iteration space

A piece of logic of `isLoopInvariantExitCondDuringFirstIterations` is actually
a generalized predicate monotonicity check. This patch moves it into the
corresponding method and generalizes it a bit.

Differential Revision: https://reviews.llvm.org/D90395
Reviewed By: apilipenko

Added: 
    

Modified: 
    llvm/include/llvm/Analysis/ScalarEvolution.h
    llvm/lib/Analysis/ScalarEvolution.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h
index e25708dcdc2d..3fd0968cb34a 100644
--- a/llvm/include/llvm/Analysis/ScalarEvolution.h
+++ b/llvm/include/llvm/Analysis/ScalarEvolution.h
@@ -954,9 +954,14 @@ class ScalarEvolution {
   /// monotonically increasing or decreasing, returns
   /// Some(MonotonicallyIncreasing) and Some(MonotonicallyDecreasing)
   /// respectively. If we could not prove either of these facts, returns None.
+  ///
+  /// If NumIter was provided, then we are proving monotonicity during at least
+  /// NumIter first iterations. If it was not provided, then we are proving
+  /// monotonicity on all iteration space.
   Optional<MonotonicPredicateType>
-  getMonotonicPredicateType(const SCEVAddRecExpr *LHS,
-                            ICmpInst::Predicate Pred);
+  getMonotonicPredicateType(const SCEVAddRecExpr *LHS, ICmpInst::Predicate Pred,
+                            Optional<const SCEV *> NumIter = None,
+                            const Instruction *Context = nullptr);
 
   /// Return true if the result of the predicate LHS `Pred` RHS is loop
   /// invariant with respect to L.  Set InvariantPred, InvariantLHS and
@@ -1893,9 +1898,9 @@ class ScalarEvolution {
   /// Try to prove NSW or NUW on \p AR relying on ConstantRange manipulation.
   SCEV::NoWrapFlags proveNoWrapViaConstantRanges(const SCEVAddRecExpr *AR);
 
-  Optional<MonotonicPredicateType>
-  getMonotonicPredicateTypeImpl(const SCEVAddRecExpr *LHS,
-                                ICmpInst::Predicate Pred);
+  Optional<MonotonicPredicateType> getMonotonicPredicateTypeImpl(
+      const SCEVAddRecExpr *LHS, ICmpInst::Predicate Pred,
+      Optional<const SCEV *> NumIter, const Instruction *Context);
 
   /// Return SCEV no-wrap flags that can be proven based on reasoning about
   /// how poison produced from no-wrap flags on this value (e.g. a nuw add)

diff  --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index dc73b71411f3..a6ce5a001b0a 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -9446,15 +9446,19 @@ bool ScalarEvolution::isKnownOnEveryIteration(ICmpInst::Predicate Pred,
 
 Optional<ScalarEvolution::MonotonicPredicateType>
 ScalarEvolution::getMonotonicPredicateType(const SCEVAddRecExpr *LHS,
-                                           ICmpInst::Predicate Pred) {
-  auto Result = getMonotonicPredicateTypeImpl(LHS, Pred);
+                                           ICmpInst::Predicate Pred,
+                                           Optional<const SCEV *> NumIter,
+                                           const Instruction *Context) {
+  assert((!NumIter || !isa<SCEVCouldNotCompute>(*NumIter)) &&
+         "provided number of iterations must be computable!");
+  auto Result = getMonotonicPredicateTypeImpl(LHS, Pred, NumIter, Context);
 
 #ifndef NDEBUG
   // Verify an invariant: inverting the predicate should turn a monotonically
   // increasing change to a monotonically decreasing one, and vice versa.
   if (Result) {
-    auto ResultSwapped =
-        getMonotonicPredicateTypeImpl(LHS, ICmpInst::getSwappedPredicate(Pred));
+    auto ResultSwapped = getMonotonicPredicateTypeImpl(
+        LHS, ICmpInst::getSwappedPredicate(Pred), NumIter, Context);
 
     assert(ResultSwapped.hasValue() && "should be able to analyze both!");
     assert(ResultSwapped.getValue() != Result.getValue() &&
@@ -9467,7 +9471,9 @@ ScalarEvolution::getMonotonicPredicateType(const SCEVAddRecExpr *LHS,
 
 Optional<ScalarEvolution::MonotonicPredicateType>
 ScalarEvolution::getMonotonicPredicateTypeImpl(const SCEVAddRecExpr *LHS,
-                                               ICmpInst::Predicate Pred) {
+                                               ICmpInst::Predicate Pred,
+                                               Optional<const SCEV *> NumIter,
+                                               const Instruction *Context) {
   // A zero step value for LHS means the induction variable is essentially a
   // loop invariant value. We don't really depend on the predicate actually
   // flipping from false to true (for increasing predicates, and the other way
@@ -9486,23 +9492,60 @@ ScalarEvolution::getMonotonicPredicateTypeImpl(const SCEVAddRecExpr *LHS,
   assert((IsGreater || ICmpInst::isLE(Pred) || ICmpInst::isLT(Pred)) &&
          "Should be greater or less!");
 
-  // Check that AR does not wrap.
-  if (ICmpInst::isUnsigned(Pred)) {
-    if (!LHS->hasNoUnsignedWrap())
-      return None;
-    return IsGreater ? MonotonicallyIncreasing : MonotonicallyDecreasing;
-  } else {
-    assert(ICmpInst::isSigned(Pred) &&
-           "Relational predicate is either signed or unsigned!");
-    if (!LHS->hasNoSignedWrap())
-      return None;
+  bool IsUnsigned = ICmpInst::isUnsigned(Pred);
+  assert((IsUnsigned || ICmpInst::isSigned(Pred)) &&
+         "Should be either signed or unsigned!");
+  // Check if we can prove no-wrap in the relevant range.
 
-    const SCEV *Step = LHS->getStepRecurrence(*this);
+  const SCEV *Step = LHS->getStepRecurrence(*this);
+  bool IsStepNonNegative = isKnownNonNegative(Step);
+  bool IsStepNonPositive = isKnownNonPositive(Step);
+  // We need to know which direction the iteration is going.
+  if (!IsStepNonNegative && !IsStepNonPositive)
+    return None;
+
+  auto ProvedNoWrap = [&]() {
+    // If the AddRec already has the flag, we are done.
+    if (IsUnsigned ? LHS->hasNoUnsignedWrap() : LHS->hasNoSignedWrap())
+      return true;
 
-    if (isKnownNonNegative(Step))
+    if (!NumIter)
+      return false;
+    // We could not prove no-wrap on all iteration space. Can we prove it for
+    // first iterations? In order to achieve it, check that:
+    // 1. The addrec does not self-wrap;
+    // 2. start <= end for non-negative step and start >= end for non-positive
+    // step.
+    bool HasNoSelfWrap = LHS->hasNoSelfWrap();
+    if (!HasNoSelfWrap)
+      // If num iter has same type as the AddRec, and step is +/- 1, even max
+      // possible number of iterations is not enough to self-wrap.
+      if (NumIter.getValue()->getType() == LHS->getType())
+        if (Step == getOne(LHS->getType()) ||
+            Step == getMinusOne(LHS->getType()))
+          HasNoSelfWrap = true;
+    if (!HasNoSelfWrap)
+      return false;
+    const SCEV *Start = LHS->getStart();
+    const SCEV *End = LHS->evaluateAtIteration(*NumIter, *this);
+    ICmpInst::Predicate NoOverflowPred =
+        IsStepNonNegative ? ICmpInst::ICMP_SLE : ICmpInst::ICMP_SGE;
+    if (IsUnsigned)
+      NoOverflowPred = ICmpInst::getUnsignedPredicate(NoOverflowPred);
+    return isKnownPredicateAt(NoOverflowPred, Start, End, Context);
+  };
+
+  // If nothing worked, bail.
+  if (!ProvedNoWrap())
+    return None;
+
+  if (IsUnsigned)
+    return IsGreater ? MonotonicallyIncreasing : MonotonicallyDecreasing;
+  else {
+    if (IsStepNonNegative)
       return IsGreater ? MonotonicallyIncreasing : MonotonicallyDecreasing;
 
-    if (isKnownNonPositive(Step))
+    if (IsStepNonPositive)
       return !IsGreater ? MonotonicallyIncreasing : MonotonicallyDecreasing;
 
     return None;
@@ -9565,9 +9608,8 @@ bool ScalarEvolution::isLoopInvariantExitCondDuringFirstIterations(
     ICmpInst::Predicate &InvariantPred, const SCEV *&InvariantLHS,
     const SCEV *&InvariantRHS) {
   // Try to prove the following set of facts:
-  // - The predicate is monotonic.
+  // - The predicate is monotonic in the iteration space.
   // - If the check does not fail on the 1st iteration:
-  //   - No overflow will happen during first MaxIter iterations;
   //   - It will not fail on the MaxIter'th iteration.
   // If the check does fail on the 1st iteration, we leave the loop and no
   // other checks matter.
@@ -9585,23 +9627,7 @@ bool ScalarEvolution::isLoopInvariantExitCondDuringFirstIterations(
   if (!AR || AR->getLoop() != L)
     return false;
 
-  // The predicate must be relational (i.e. <, <=, >=, >).
-  if (!ICmpInst::isRelational(Pred))
-    return false;
-
-  const SCEV *Step = AR->getStepRecurrence(*this);
-  bool IsStepNonPositive = isKnownNonPositive(Step);
-  if (!IsStepNonPositive && !isKnownNonNegative(Step))
-    return false;
-  bool HasNoSelfWrap = AR->hasNoSelfWrap();
-  if (!HasNoSelfWrap)
-    // If num iter has same type as the AddRec, and step is +/- 1, even max
-    // possible number of iterations is not enough to self-wrap.
-    if (MaxIter->getType() == AR->getType())
-      if (Step == getOne(AR->getType()) || Step == getMinusOne(AR->getType()))
-        HasNoSelfWrap = true;
-  // Only proceed with non-self-wrapping ARs.
-  if (!HasNoSelfWrap)
+  if (!getMonotonicPredicateType(AR, Pred, MaxIter, Context))
     return false;
 
   // Value of IV on suggested last iteration.
@@ -9609,21 +9635,10 @@ bool ScalarEvolution::isLoopInvariantExitCondDuringFirstIterations(
   // Does it still meet the requirement?
   if (!isKnownPredicateAt(Pred, Last, RHS, Context))
     return false;
-  // We know that the addrec does not have a self-wrap. To prove that there is
-  // no signed/unsigned wrap, we need to check that
-  // Start <= Last for positive step or Start >= Last for negative step. Either
-  // works for zero step.
-  ICmpInst::Predicate NoOverflowPred =
-      CmpInst::isSigned(Pred) ? ICmpInst::ICMP_SLE : ICmpInst::ICMP_ULE;
-  if (IsStepNonPositive)
-    NoOverflowPred = CmpInst::getSwappedPredicate(NoOverflowPred);
-  const SCEV *Start = AR->getStart();
-  if (!isKnownPredicateAt(NoOverflowPred, Start, Last, Context))
-    return false;
 
   // Everything is fine.
   InvariantPred = Pred;
-  InvariantLHS = Start;
+  InvariantLHS = AR->getStart();
   InvariantRHS = RHS;
   return true;
 }


        


More information about the llvm-commits mailing list