[llvm] [SCEV] Propagate a recurrence's nuw flag to its exit value. (PR #217378)

via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 19 09:07:42 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-analysis

Author: Florian Hahn (fhahn)

<details>
<summary>Changes</summary>

A recurrence's exit value is its closed form Start + BTC * Step. The sum does
not wrap, if the recurrence does not wrap: the recurrence reached iteration BTC,
so the value it computes there is the value the recurrence had, and that did not wrap.

The flags are attached to the returned use, because they only apply to
this specific expression we evaluated for the exit value, no other,
equivalent SCEVs.

Alive2 Proof: https://alive2.llvm.org/ce/z/0vSRq-

This on its own has small impact on real world code (only retained some
additional flags in most cases):
https://github.com/dtcxzyw/llvm-opt-benchmark-nightly/pull/962, but is
the first end-to-end use of SCEVUse.

---

Patch is 195.00 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/217378.diff


34 Files Affected:

- (modified) llvm/include/llvm/Analysis/ScalarEvolution.h (+7-4) 
- (modified) llvm/include/llvm/Analysis/ScalarEvolutionExpressions.h (+9-3) 
- (modified) llvm/lib/Analysis/ScalarEvolution.cpp (+70-30) 
- (modified) llvm/lib/Transforms/Utils/LoopUtils.cpp (+4-4) 
- (modified) llvm/test/Analysis/ScalarEvolution/alloca.ll (+1-1) 
- (modified) llvm/test/Analysis/ScalarEvolution/backedge-taken-count-guard-info.ll (+1-1) 
- (modified) llvm/test/Analysis/ScalarEvolution/different-loops-recs.ll (+8-8) 
- (modified) llvm/test/Analysis/ScalarEvolution/exit-count-select-safe.ll (+9-9) 
- (modified) llvm/test/Analysis/ScalarEvolution/exit-count-select.ll (+4-4) 
- (added) llvm/test/Analysis/ScalarEvolution/exit-value-nowrap-flags.ll (+324) 
- (modified) llvm/test/Analysis/ScalarEvolution/flags-from-poison-noautogen.ll (+2-2) 
- (modified) llvm/test/Analysis/ScalarEvolution/flags-from-poison.ll (+2-2) 
- (modified) llvm/test/Analysis/ScalarEvolution/increasing-or-decreasing-iv.ll (+1-1) 
- (modified) llvm/test/Analysis/ScalarEvolution/infer-prestart-no-wrap.ll (+1-1) 
- (modified) llvm/test/Analysis/ScalarEvolution/load.ll (+2-2) 
- (modified) llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info-operand-order.ll (+12-12) 
- (modified) llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info-rewrite-expressions.ll (+12-12) 
- (modified) llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info.ll (+15-15) 
- (modified) llvm/test/Analysis/ScalarEvolution/min-max-exprs.ll (+5-5) 
- (modified) llvm/test/Analysis/ScalarEvolution/nsw-offset-assume.ll (+8-8) 
- (modified) llvm/test/Analysis/ScalarEvolution/nsw-offset.ll (+8-8) 
- (modified) llvm/test/Analysis/ScalarEvolution/nsw.ll (+7-7) 
- (modified) llvm/test/Analysis/ScalarEvolution/pr92560.ll (+1-1) 
- (modified) llvm/test/Analysis/ScalarEvolution/ptrtoint-special-pointers.ll (+1-1) 
- (modified) llvm/test/Analysis/ScalarEvolution/ptrtoint.ll (+61-3) 
- (modified) llvm/test/Analysis/ScalarEvolution/ranges.ll (+5-5) 
- (modified) llvm/test/Analysis/ScalarEvolution/sdiv.ll (+1-1) 
- (modified) llvm/test/Analysis/ScalarEvolution/sext-add-inreg-loop.ll (+1-1) 
- (modified) llvm/test/Analysis/ScalarEvolution/srem.ll (+1-1) 
- (modified) llvm/test/Analysis/ScalarEvolution/trip-count-minmax.ll (+1-1) 
- (modified) llvm/test/Analysis/ScalarEvolution/trip-count-scalable-stride.ll (+6-6) 
- (modified) llvm/test/Analysis/ScalarEvolution/trip-count15.ll (+10-1) 
- (modified) llvm/test/Analysis/ScalarEvolution/umin-umax-folds.ll (+6-6) 
- (added) llvm/test/Transforms/IndVarSimplify/exit-value-nowrap-flags.ll (+379) 


``````````diff
diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h
index d17c21ea3401e..61564c44ee5ed 100644
--- a/llvm/include/llvm/Analysis/ScalarEvolution.h
+++ b/llvm/include/llvm/Analysis/ScalarEvolution.h
@@ -961,10 +961,13 @@ class ScalarEvolution {
   ///
   /// In the case that a relevant loop exit value cannot be computed, the
   /// original value V is returned.
-  LLVM_ABI const SCEV *getSCEVAtScope(const SCEV *S, const Loop *L);
+  ///
+  /// The result may carry use-specific no-wrap flags. Those hold only in
+  /// contexts reached via \p L's exit.
+  LLVM_ABI SCEVUse getSCEVAtScope(const SCEV *S, const Loop *L);
 
   /// This is a convenience function which does getSCEVAtScope(getSCEV(V), L).
-  LLVM_ABI const SCEV *getSCEVAtScope(Value *V, const Loop *L);
+  LLVM_ABI SCEVUse getSCEVAtScope(Value *V, const Loop *L);
 
   /// Test whether entry to the loop is protected by a conditional between LHS
   /// and RHS.  This is used to help avoid max expressions in loop trip
@@ -1920,7 +1923,7 @@ class ScalarEvolution {
   /// This map contains entries for all the expressions that we attempt to
   /// compute getSCEVAtScope information for, which can be expensive in
   /// extreme cases.
-  DenseMap<const SCEV *, SmallVector<std::pair<const Loop *, const SCEV *>, 2>>
+  DenseMap<const SCEV *, SmallVector<std::pair<const Loop *, SCEVUse>, 2>>
       ValuesAtScopes;
 
   /// Reverse map for invalidation purposes: Stores of which SCEV and which
@@ -2082,7 +2085,7 @@ class ScalarEvolution {
 
   /// Implementation code for getSCEVAtScope; called at most once for each
   /// SCEV+Loop pair.
-  const SCEV *computeSCEVAtScope(const SCEV *S, const Loop *L);
+  SCEVUse computeSCEVAtScope(const SCEV *S, const Loop *L);
 
   /// Return the BackedgeTakenInfo for the given loop, lazily computing new
   /// values if the loop hasn't been analyzed yet. The returned result is
diff --git a/llvm/include/llvm/Analysis/ScalarEvolutionExpressions.h b/llvm/include/llvm/Analysis/ScalarEvolutionExpressions.h
index ebee63963c701..3d2bcf7c2bf34 100644
--- a/llvm/include/llvm/Analysis/ScalarEvolutionExpressions.h
+++ b/llvm/include/llvm/Analysis/ScalarEvolutionExpressions.h
@@ -382,9 +382,15 @@ class SCEVAddRecExpr : public SCEVNAryExpr {
 
   /// Return the value of this chain of recurrences at the specified iteration
   /// number. Takes an explicit list of operands to represent an AddRec.
-  LLVM_ABI static const SCEV *evaluateAtIteration(ArrayRef<SCEVUse> Operands,
-                                                  const SCEV *It,
-                                                  ScalarEvolution &SE);
+  LLVM_ABI static SCEVUse
+  evaluateAtIteration(ArrayRef<SCEVUse> Operands, const SCEV *It,
+                      ScalarEvolution &SE,
+                      SCEV::NoWrapFlags UseFlags = SCEV::FlagAnyWrap);
+
+  /// Return the value of this recurrences when its loop exits, i.e. its value
+  /// at the loop's exact backedge-taken count, or SCEVCouldNotCompute if that
+  /// count cannot be computed.
+  LLVM_ABI SCEVUse getExitValue(ScalarEvolution &SE) const;
 
   /// Return the number of iterations of this loop that produce
   /// values in the specified constant range.  Another way of
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 35d650377d719..e64f8a6a0843a 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -1020,6 +1020,27 @@ static const SCEV *BinomialCoefficient(const SCEV *It, unsigned K,
                        SE.getTruncateOrZeroExtend(DivResult, ResultTy));
 }
 
+/// Attach \p UseFlags to \p Res as use-specific flags, but only if \p Res
+/// really is the two-operand \p ExprT over \p LHS and \p RHS - in either order,
+/// as operands get sorted by complexity.
+///
+/// Flags established for that operation say nothing about any other expression:
+/// a folded-away operand, a flattened nested expression or a distributed
+/// constant all give a different computation. They must not be attached to it,
+/// because an n-ary expression's no-wrap flags have to hold for all subsets and
+/// orders of its operands, and SCEVExpander relies on that when it stamps them
+/// on every partial sum or product it builds.
+template <typename ExprT>
+static SCEVUse withUseFlagsIfNotFolded(const SCEV *Res, SCEVUse LHS,
+                                       SCEVUse RHS,
+                                       SCEV::NoWrapFlags UseFlags) {
+  auto *E = dyn_cast<ExprT>(Res);
+  if (E && (equal(E->operands(), ArrayRef<SCEVUse>({LHS, RHS})) ||
+            equal(E->operands(), ArrayRef<SCEVUse>({RHS, LHS}))))
+    return {Res, UseFlags};
+  return Res;
+}
+
 /// Return the value of this chain of recurrences at the specified iteration
 /// number.  We can evaluate this recurrence by multiplying each element in the
 /// chain by the binomial coefficient corresponding to it.  In other words, we
@@ -1033,11 +1054,13 @@ const SCEV *SCEVAddRecExpr::evaluateAtIteration(const SCEV *It,
   return evaluateAtIteration(operands(), It, SE);
 }
 
-const SCEV *SCEVAddRecExpr::evaluateAtIteration(ArrayRef<SCEVUse> Operands,
-                                                const SCEV *It,
-                                                ScalarEvolution &SE) {
+SCEVUse SCEVAddRecExpr::evaluateAtIteration(ArrayRef<SCEVUse> Operands,
+                                            const SCEV *It, ScalarEvolution &SE,
+                                            SCEV::NoWrapFlags UseFlags) {
   assert(Operands.size() > 0);
-  const SCEV *Result = Operands[0].getPointer();
+  assert((Operands.size() == 2 || UseFlags == SCEV::FlagAnyWrap) &&
+         "use-specific flags only supported for affine AddRecs");
+  SCEVUse Result = Operands[0].getPointer();
   for (unsigned i = 1, e = Operands.size(); i != e; ++i) {
     // The computation is correct in the face of overflow provided that the
     // multiplication is performed _after_ the evaluation of the binomial
@@ -1046,12 +1069,24 @@ const SCEV *SCEVAddRecExpr::evaluateAtIteration(ArrayRef<SCEVUse> Operands,
     if (isa<SCEVCouldNotCompute>(Coeff))
       return Coeff;
 
-    Result =
-        SE.getAddExpr(Result, SE.getMulExpr(Operands[i].getPointer(), Coeff));
+    const SCEV *Mul = SE.getMulExpr(Operands[i].getPointer(), Coeff);
+    Result = withUseFlagsIfNotFolded<SCEVAddExpr>(SE.getAddExpr(Result, Mul),
+                                                  Result, Mul, UseFlags);
   }
   return Result;
 }
 
+SCEVUse SCEVAddRecExpr::getExitValue(ScalarEvolution &SE) const {
+  const SCEV *BTC = SE.getBackedgeTakenCount(getLoop());
+  if (isa<SCEVCouldNotCompute>(BTC))
+    return BTC;
+  // The loop reaches iteration BTC, so the value this recurrence computes there
+  // is the value it had, and that did not wrap.
+  return evaluateAtIteration(operands(), BTC, SE,
+                             isAffine() ? getNoWrapFlags(SCEV::FlagNUW)
+                                        : SCEV::FlagAnyWrap);
+}
+
 //===----------------------------------------------------------------------===//
 //                    SCEV Expression folder implementations
 //===----------------------------------------------------------------------===//
@@ -10088,23 +10123,25 @@ const SCEV *ScalarEvolution::computeExitCountExhaustively(const Loop *L,
   return getCouldNotCompute();
 }
 
-const SCEV *ScalarEvolution::getSCEVAtScope(const SCEV *V, const Loop *L) {
-  SmallVector<std::pair<const Loop *, const SCEV *>, 2> &Values =
-      ValuesAtScopes[V];
+SCEVUse ScalarEvolution::getSCEVAtScope(const SCEV *V, const Loop *L) {
+  auto &Values = ValuesAtScopes[V];
   // Check to see if we've folded this expression at this loop before.
   for (auto &LS : Values)
     if (LS.first == L)
-      return LS.second ? LS.second : V;
+      return LS.second ? LS.second : SCEVUse(V);
 
   Values.emplace_back(L, nullptr);
 
   // Otherwise compute it.
-  const SCEV *C = computeSCEVAtScope(V, L);
+  SCEVUse C = computeSCEVAtScope(V, L);
   for (auto &LS : reverse(ValuesAtScopes[V]))
     if (LS.first == L) {
       LS.second = C;
+      // Record the dependency under the bare expression: invalidation walks
+      // expressions, and any use flags on C do not change which expression
+      // this is the value at scope of.
       if (!isa<SCEVConstant>(C))
-        ValuesAtScopesUsers[C].push_back({L, V});
+        ValuesAtScopesUsers[C.getPointer()].push_back({L, V});
       break;
     }
   return C;
@@ -10209,7 +10246,7 @@ const SCEV *ScalarEvolution::getWithOperands(const SCEV *S,
   llvm_unreachable("Unknown SCEV kind!");
 }
 
-const SCEV *ScalarEvolution::computeSCEVAtScope(const SCEV *V, const Loop *L) {
+SCEVUse ScalarEvolution::computeSCEVAtScope(const SCEV *V, const Loop *L) {
   switch (V->getSCEVType()) {
   case scConstant:
   case scVScale:
@@ -10222,8 +10259,8 @@ const SCEV *ScalarEvolution::computeSCEVAtScope(const SCEV *V, const Loop *L) {
     // Avoid performing the look-up in the common case where the specified
     // expression has no loop-variant portions.
     for (unsigned i = 0, e = AddRec->getNumOperands(); i != e; ++i) {
-      const SCEV *OpAtScope = getSCEVAtScope(AddRec->getOperand(i), L);
-      if (OpAtScope == AddRec->getOperand(i))
+      SCEVUse OpAtScope = getSCEVAtScope(AddRec->getOperand(i), L);
+      if (OpAtScope == AddRec->getOperand(i).getPointer())
         continue;
 
       // Okay, at least one of these operands is loop variant but might be
@@ -10249,14 +10286,10 @@ const SCEV *ScalarEvolution::computeSCEVAtScope(const SCEV *V, const Loop *L) {
     // If the scope is outside the addrec's loop, evaluate it by using the
     // loop exit value of the addrec.
     if (!AddRec->getLoop()->contains(L)) {
-      // To evaluate this recurrence, we need to know how many times the AddRec
-      // loop iterates.  Compute this now.
-      const SCEV *BackedgeTakenCount = getBackedgeTakenCount(AddRec->getLoop());
-      if (BackedgeTakenCount == getCouldNotCompute())
+      SCEVUse ExitValue = AddRec->getExitValue(*this);
+      if (isa<SCEVCouldNotCompute>(ExitValue))
         return AddRec;
-
-      // Then, evaluate the AddRec.
-      return AddRec->evaluateAtIteration(BackedgeTakenCount, *this);
+      return ExitValue;
     }
 
     return AddRec;
@@ -10277,7 +10310,7 @@ const SCEV *ScalarEvolution::computeSCEVAtScope(const SCEV *V, const Loop *L) {
     // Avoid performing the look-up in the common case where the specified
     // expression has no loop-variant portions.
     for (unsigned i = 0, e = Ops.size(); i != e; ++i) {
-      const SCEV *OpAtScope = getSCEVAtScope(Ops[i].getPointer(), L);
+      SCEVUse OpAtScope = getSCEVAtScope(Ops[i].getPointer(), L);
       if (OpAtScope != Ops[i].getPointer()) {
         // Okay, at least one of these operands is loop variant but might be
         // foldable.  Build a new instance of the folded commutative expression.
@@ -10408,7 +10441,7 @@ const SCEV *ScalarEvolution::computeSCEVAtScope(const SCEV *V, const Loop *L) {
   llvm_unreachable("Unknown SCEV type!");
 }
 
-const SCEV *ScalarEvolution::getSCEVAtScope(Value *V, const Loop *L) {
+SCEVUse ScalarEvolution::getSCEVAtScope(Value *V, const Loop *L) {
   return getSCEVAtScope(getSCEV(V), L);
 }
 
@@ -14679,7 +14712,7 @@ void ScalarEvolution::forgetMemoizedResultsImpl(const SCEV *S) {
   if (ScopeIt != ValuesAtScopes.end()) {
     for (const auto &Pair : ScopeIt->second)
       if (!isa_and_nonnull<SCEVConstant>(Pair.second))
-        llvm::erase(ValuesAtScopesUsers[Pair.second],
+        llvm::erase(ValuesAtScopesUsers[Pair.second.getPointer()],
                     std::make_pair(Pair.first, S));
     ValuesAtScopes.erase(ScopeIt);
   }
@@ -14687,7 +14720,11 @@ void ScalarEvolution::forgetMemoizedResultsImpl(const SCEV *S) {
   auto ScopeUserIt = ValuesAtScopesUsers.find(S);
   if (ScopeUserIt != ValuesAtScopesUsers.end()) {
     for (const auto &Pair : ScopeUserIt->second)
-      llvm::erase(ValuesAtScopes[Pair.second], std::make_pair(Pair.first, S));
+      // The recorded value at scope is a use of S, which may carry no-wrap
+      // flags that are not part of this key.
+      llvm::erase_if(ValuesAtScopes[Pair.second], [&](const auto &LS) {
+        return LS.first == Pair.first && LS.second.getPointer() == S;
+      });
     ValuesAtScopesUsers.erase(ScopeUserIt);
   }
 
@@ -14932,9 +14969,9 @@ void ScalarEvolution::verify() const {
     const SCEV *Value = ValueAndVec.first;
     for (const auto &LoopAndValueAtScope : ValueAndVec.second) {
       const Loop *L = LoopAndValueAtScope.first;
-      const SCEV *ValueAtScope = LoopAndValueAtScope.second;
+      SCEVUse ValueAtScope = LoopAndValueAtScope.second;
       if (!isa<SCEVConstant>(ValueAtScope)) {
-        auto It = ValuesAtScopesUsers.find(ValueAtScope);
+        auto It = ValuesAtScopesUsers.find(ValueAtScope.getPointer());
         if (It != ValuesAtScopesUsers.end() &&
             is_contained(It->second, std::make_pair(L, Value)))
           continue;
@@ -14952,8 +14989,11 @@ void ScalarEvolution::verify() const {
       const SCEV *Value = LoopAndValue.second;
       assert(!isa<SCEVConstant>(Value));
       auto It = ValuesAtScopes.find(Value);
-      if (It != ValuesAtScopes.end() &&
-          is_contained(It->second, std::make_pair(L, ValueAtScope)))
+      // The recorded value at scope may carry no-wrap flags that are not part
+      // of the key it is recorded under.
+      if (It != ValuesAtScopes.end() && any_of(It->second, [&](const auto &LS) {
+            return LS.first == L && LS.second.getPointer() == ValueAtScope;
+          }))
         continue;
       dbgs() << "Value: " << *Value << ", Loop: " << *L << ", ValueAtScope: "
              << *ValueAtScope << " missing in ValuesAtScopes\n";
diff --git a/llvm/lib/Transforms/Utils/LoopUtils.cpp b/llvm/lib/Transforms/Utils/LoopUtils.cpp
index 7c77acc9d748c..65b282de5962a 100644
--- a/llvm/lib/Transforms/Utils/LoopUtils.cpp
+++ b/llvm/lib/Transforms/Utils/LoopUtils.cpp
@@ -1763,11 +1763,11 @@ static bool hasHardUserWithinLoop(const Loop *L, const Instruction *I) {
 struct RewritePhi {
   PHINode *PN;               // For which PHI node is this replacement?
   unsigned Ith;              // For which incoming value?
-  const SCEV *ExpansionSCEV; // The SCEV of the incoming value we are rewriting.
+  SCEVUse ExpansionSCEV;     // The SCEV of the incoming value we are rewriting.
   Instruction *ExpansionPoint; // Where we'd like to expand that SCEV?
   bool HighCost;               // Is this expansion a high-cost?
 
-  RewritePhi(PHINode *P, unsigned I, const SCEV *Val, Instruction *ExpansionPt,
+  RewritePhi(PHINode *P, unsigned I, SCEVUse Val, Instruction *ExpansionPt,
              bool H)
       : PN(P), Ith(I), ExpansionSCEV(Val), ExpansionPoint(ExpansionPt),
         HighCost(H) {}
@@ -1938,7 +1938,7 @@ int llvm::rewriteLoopExitValues(Loop *L, LoopInfo *LI, TargetLibraryInfo *TLI,
         // expressions which are true for all exits (so as to maximize
         // expression reuse by the SCEVExpander), but resort to per-exit
         // evaluation if that fails.
-        const SCEV *ExitValue = SE->getSCEVAtScope(Inst, L->getParentLoop());
+        SCEVUse ExitValue = SE->getSCEVAtScope(Inst, L->getParentLoop());
         if (isa<SCEVCouldNotCompute>(ExitValue) ||
             !SE->isLoopInvariant(ExitValue, L) ||
             !Rewriter.isSafeToExpand(ExitValue)) {
@@ -1969,7 +1969,7 @@ int llvm::rewriteLoopExitValues(Loop *L, LoopInfo *LI, TargetLibraryInfo *TLI,
 
         // Check if expansions of this SCEV would count as being high cost.
         bool HighCost = Rewriter.isHighCostExpansion(
-            ExitValue, L, SCEVCheapExpansionBudget, TTI, Inst);
+            ExitValue.getPointer(), L, SCEVCheapExpansionBudget, TTI, Inst);
 
         // Note that we must not perform expansions until after
         // we query *all* the costs, because if we perform temporary expansion
diff --git a/llvm/test/Analysis/ScalarEvolution/alloca.ll b/llvm/test/Analysis/ScalarEvolution/alloca.ll
index 97555be0991c1..5ee5f4d3a4f9d 100644
--- a/llvm/test/Analysis/ScalarEvolution/alloca.ll
+++ b/llvm/test/Analysis/ScalarEvolution/alloca.ll
@@ -37,7 +37,7 @@ define void @alloca_icmp_null_exit_count() {
 ; CHECK-NEXT:    %alloca.end = getelementptr inbounds i32, ptr %alloca, i64 3
 ; CHECK-NEXT:    --> (12 + %alloca)<nuw> U: [16,-3) S: [-9223372036854775808,9223372036854775805)
 ; CHECK-NEXT:    %ptr = phi ptr [ %ptr.next, %loop ], [ %alloca, %entry ]
-; CHECK-NEXT:    --> {%alloca,+,4}<nuw><%loop> U: [4,-7) S: [-9223372036854775808,9223372036854775805) Exits: (8 + %alloca)<nuw> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    --> {%alloca,+,4}<nuw><%loop> U: [4,-7) S: [-9223372036854775808,9223372036854775805) Exits: (8 + %alloca)<nuw><u nuw> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %ptr.next = getelementptr i32, ptr %ptr, i64 1
 ; CHECK-NEXT:    --> {(4 + %alloca)<nuw>,+,4}<nuw><%loop> U: [8,-3) S: [-9223372036854775808,9223372036854775805) Exits: (12 + %alloca)<nuw> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %and = and i1 %cmp1, %cmp2
diff --git a/llvm/test/Analysis/ScalarEvolution/backedge-taken-count-guard-info.ll b/llvm/test/Analysis/ScalarEvolution/backedge-taken-count-guard-info.ll
index a5b7b166aaa97..4f94fe38601ba 100644
--- a/llvm/test/Analysis/ScalarEvolution/backedge-taken-count-guard-info.ll
+++ b/llvm/test/Analysis/ScalarEvolution/backedge-taken-count-guard-info.ll
@@ -45,7 +45,7 @@ define void @loop_guard_improves_exact_backedge_taken_count_2(i32 %conv) {
 ; CHECK-NEXT:    %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
 ; CHECK-NEXT:    --> {0,+,1}<nuw><nsw><%loop> U: [0,2) S: [0,2) Exits: (zext i1 (trunc i32 %conv to i1) to i64) LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:    %iv.next = add i64 %iv, 1
-; CHECK-NEXT:    --> {1,+,1}<nuw><nsw><%loop> U: [1,3) S: [1,3) Exits: (1 + (zext i1 (trunc i32 %conv to i1) to i64))<nuw><nsw> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT:    --> {1,+,1}<nuw><nsw><%loop> U: [1,3) S: [1,3) Exits: (1 + (zext i1 (trunc i32 %conv to i1) to i64))<nuw><nsw><u nuw> LoopDispositions: { %loop: Computable }
 ; CHECK-NEXT:  Determining loop execution counts for: @loop_guard_improves_exact_backedge_taken_count_2
 ; CHECK-NEXT:  Loop %loop: backedge-taken count is (zext i1 (trunc i32 %conv to i1) to i64)
 ; CHECK-NEXT:  Loop %loop: constant max backedge-taken count is i64 1
diff --git a/llvm/test/Analysis/ScalarEvolution/different-loops-recs.ll b/llvm/test/Analysis/ScalarEvolution/different-loops-recs.ll
index a13da89b4d6e9..0fbec068c9dc0 100644
--- a/llvm/test/Analysis/ScalarEvolution/different-loops-recs.ll
+++ b/llvm/test/Analysis/ScalarEvolution/different-loops-recs.ll
@@ -113,13 +113,13 @@ define void @test_01(i32 %a, i32 %b) {
 ; CHECK-NEXT:    %phi2 = phi i32 [ %b, %entry ], [ %phi2.inc, %loop1 ]
 ; CHECK-NEXT:    --> {%b,+,2}<nw><%loop1> U: full-set S: full-set Exits: ((2 * (((-6 + (-2 * %a) + (-1 * (1 umin (-6 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b)))))<nuw><nsw> + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6) + (1 umin (-6 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))))))<nuw><nsw> + %b) LoopDispositions: { %loop1: Computable }
 ; CHECK-NEXT:    %phi3 = phi i32 [ 6, %entry ], [ %phi3.inc, %loop1 ]
-; CHECK-NEXT:    --> {6,+,3}<nuw><nsw><%loop1> U: [6,508) S: [6,508) Exits: (6 + (3 * (((-6 + (-2 * %a) + (-1 * (1 umin (-6 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b)))))<nuw><nsw> + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6) + (1 umin (-6 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))))))<nuw>)<nuw> LoopDispositions: { %loop1: Computable }
+; CHECK-NEXT:    --> {6,+,3}<nuw><nsw><%loop1> U: [6,508) S: [6,508) Exits: (6 + (3 * (((-6 + (-2 * %a) + (-1 * (1 umin (-6 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b)))))<nuw><nsw> + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6) + (1 umin (-6 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))))))<nuw>)<nuw><u nuw> LoopDispositions: { %loop1: Computable }
 ; CHECK-NEXT:    %phi1.inc = add i32 %phi1, 1
 ; CHECK-NEXT:    --> {(1 + %a),+,1}<nw><%loop1> U: full-set S: full-set Exits: (1 + ((-6 + (-2 * %a) + (-1 * (1 umin (-6 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b)))))<nuw><nsw> + (-1 * %b) + (...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/217378


More information about the llvm-commits mailing list