[llvm] [SCEV] Fold sext-AddRec on positive step (PR #217422)

via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 19 11:22:12 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-risc-v

@llvm/pr-subscribers-llvm-transforms

Author: Ramkumar Ramachandra (artagnon)

<details>
<summary>Changes</summary>

We mirror the zext-AddRec case for sext, by pushing the sext into the AddRec when certain conditions are satisfied, including a positive step. This results in many improvements.

-- 8< --
Based on https://github.com/llvm/llvm-project/pull/217362.

---

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


29 Files Affected:

- (modified) llvm/lib/Analysis/ScalarEvolution.cpp (+25-89) 
- (modified) llvm/test/Analysis/ScalarEvolution/incorrect-nsw.ll (+3-3) 
- (modified) llvm/test/Analysis/ScalarEvolution/min-max-exprs.ll (+3-3) 
- (modified) llvm/test/Analysis/ScalarEvolution/sext-iv-2.ll (+35-7) 
- (modified) llvm/test/Analysis/ScalarEvolution/sext-mul.ll (+4-4) 
- (modified) llvm/test/Transforms/IndVarSimplify/ARM/code-size.ll (+10-10) 
- (modified) llvm/test/Transforms/IndVarSimplify/X86/overflow-intrinsics.ll (+2-2) 
- (modified) llvm/test/Transforms/IndVarSimplify/backedge-on-min-max.ll (+2-2) 
- (modified) llvm/test/Transforms/IndVarSimplify/floating-point-iv.ll (+1-1) 
- (modified) llvm/test/Transforms/IndVarSimplify/infer-poison-flags.ll (+1-1) 
- (modified) llvm/test/Transforms/IndVarSimplify/loop-predication.ll (+8-8) 
- (modified) llvm/test/Transforms/IndVarSimplify/pointer-loop-guards.ll (+1-1) 
- (modified) llvm/test/Transforms/IndVarSimplify/pr57247.ll (+1-1) 
- (modified) llvm/test/Transforms/IndVarSimplify/strengthen-overflow.ll (+2-2) 
- (modified) llvm/test/Transforms/IndVarSimplify/turn-to-invariant.ll (+3-3) 
- (modified) llvm/test/Transforms/LoopStrengthReduce/X86/2012-01-13-phielim.ll (+1-1) 
- (modified) llvm/test/Transforms/LoopStrengthReduce/X86/pr17473.ll (+36-2) 
- (modified) llvm/test/Transforms/LoopVectorize/RISCV/strided-access-wide-stride.ll (+9-14) 
- (modified) llvm/test/Transforms/LoopVectorize/RISCV/tail-folding-iv-outside-user.ll (+3-20) 
- (modified) llvm/test/Transforms/LoopVectorize/X86/replicating-load-store-costs.ll (+1-4) 
- (modified) llvm/test/Transforms/LoopVectorize/alias-mask-data-tail-folding-style.ll (+1-6) 
- (modified) llvm/test/Transforms/LoopVectorize/div-exact.ll (+4-12) 
- (modified) llvm/test/Transforms/LoopVectorize/first-order-recurrence-complex.ll (+6-16) 
- (modified) llvm/test/Transforms/LoopVectorize/first-order-recurrence-dead-instructions.ll (+3-26) 
- (modified) llvm/test/Transforms/LoopVectorize/interleaved-accesses-dead-member.ll (+2-10) 
- (modified) llvm/test/Transforms/LoopVectorize/iv_outside_user.ll (+2-7) 
- (modified) llvm/test/Transforms/LoopVectorize/pointer-induction.ll (+6-16) 
- (modified) llvm/test/Transforms/LoopVectorize/simplify-logic.ll (+8-40) 
- (modified) llvm/test/Transforms/LoopVectorize/widen-intrinsic-tail-fold.ll (+6-38) 


``````````diff
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 52a03d2cad62d..6bec4b0283ee6 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -1972,7 +1972,7 @@ const SCEV *ScalarEvolution::getSignExtendExprImpl(SCEVUse Op, Type *Ty,
     if (AR->hasNoSignedWrap()) {
       Start = getExtendAddRecStart<SCEVSignExtendExpr>(AR, Ty, this, Depth + 1);
       Step = getSignExtendExpr(Step, Ty, Depth + 1);
-      return getAddRecExpr(Start, Step, L, SCEV::FlagNSW);
+      return getAddRecExpr(Start, Step, L, AR->getNoWrapFlags());
     }
   }
 
@@ -2044,96 +2044,39 @@ const SCEV *ScalarEvolution::getSignExtendExprImpl(SCEVUse Op, Type *Ty,
   // operands (often constants).  This allows analysis of something like
   // this:  for (signed char X = 0; X < 100; ++X) { int Y = X; }
   if (match(Op, m_scev_AffineAddRec(m_SCEV(Start), m_SCEV(Step), m_Loop(L)))) {
+    // Redo the AddRec check, computing nsw this time.
     const auto *AR = cast<SCEVAddRecExpr>(Op);
-    unsigned BitWidth = getTypeSizeInBits(AR->getType());
-
-    // The no-signed-wrap case is handled before the uniquing lookup above.
-
-    // Check whether the backedge-taken count is SCEVCouldNotCompute.
-    // Note that this serves two purposes: It filters out loops that are
-    // simply not analyzable, and it covers the case where this code is
-    // being called from within backedge-taken count analysis, such that
-    // attempting to ask for the backedge-taken count would likely result
-    // in infinite recursion. In the later case, the analysis code will
-    // cope with a conservative value, and it will take care to purge
-    // that value once it has finished.
-    const SCEV *MaxBECount = getConstantMaxBackedgeTakenCount(L);
-    if (!isa<SCEVCouldNotCompute>(MaxBECount)) {
-      // Manually compute the final value for AR, checking for
-      // overflow.
-
-      // Check whether the backedge-taken count can be losslessly casted to
-      // the addrec's type. The count is always unsigned.
-      const SCEV *CastedMaxBECount =
-          getTruncateOrZeroExtend(MaxBECount, Start->getType(), Depth);
-      const SCEV *RecastedMaxBECount = getTruncateOrZeroExtend(
-          CastedMaxBECount, MaxBECount->getType(), Depth);
-      if (MaxBECount == RecastedMaxBECount) {
-        Type *WideTy = IntegerType::get(getContext(), BitWidth * 2);
-        // Check whether Start+Step*MaxBECount has no signed overflow.
-        const SCEV *SMul =
-            getMulExpr(CastedMaxBECount, Step, SCEV::FlagAnyWrap, Depth + 1);
-        const SCEV *SAdd = getSignExtendExpr(
-            getAddExpr(Start, SMul, SCEV::FlagAnyWrap, Depth + 1), WideTy,
-            Depth + 1);
-        const SCEV *WideStart = getSignExtendExpr(Start, WideTy, Depth + 1);
-        const SCEV *WideMaxBECount =
-            getZeroExtendExpr(CastedMaxBECount, WideTy, Depth + 1);
-        const SCEV *OperandExtendedAdd =
-            getAddExpr(WideStart,
-                       getMulExpr(WideMaxBECount,
-                                  getSignExtendExpr(Step, WideTy, Depth + 1),
-                                  SCEV::FlagAnyWrap, Depth + 1),
-                       SCEV::FlagAnyWrap, Depth + 1);
-        if (SAdd == OperandExtendedAdd) {
-          // Cache knowledge of AR NSW, which is propagated to this AddRec.
-          setNoWrapFlags(const_cast<SCEVAddRecExpr *>(AR), SCEV::FlagNSW);
-          // Return the expression with the addrec on the outside.
-          Start =
-              getExtendAddRecStart<SCEVSignExtendExpr>(AR, Ty, this, Depth + 1);
-          Step = getSignExtendExpr(Step, Ty, Depth + 1);
-          return getAddRecExpr(Start, Step, L, AR->getNoWrapFlags());
-        }
-        // Similar to above, only this time treat the step value as unsigned.
-        // This covers loops that count up with an unsigned step.
-        OperandExtendedAdd =
-            getAddExpr(WideStart,
-                       getMulExpr(WideMaxBECount,
-                                  getZeroExtendExpr(Step, WideTy, Depth + 1),
-                                  SCEV::FlagAnyWrap, Depth + 1),
-                       SCEV::FlagAnyWrap, Depth + 1);
-        if (SAdd == OperandExtendedAdd) {
-          // If AR wraps around then
-          //
-          //    abs(Step) * MaxBECount > unsigned-max(AR->getType())
-          // => SAdd != OperandExtendedAdd
-          //
-          // Thus (AR is not NW => SAdd != OperandExtendedAdd) <=>
-          // (SAdd == OperandExtendedAdd => AR is NW)
-
-          setNoWrapFlags(const_cast<SCEVAddRecExpr *>(AR), SCEV::FlagNW);
-
-          // Return the expression with the addrec on the outside.
-          Start =
-              getExtendAddRecStart<SCEVSignExtendExpr>(AR, Ty, this, Depth + 1);
-          Step = getZeroExtendExpr(Step, Ty, Depth + 1);
-          return getAddRecExpr(Start, Step, L, AR->getNoWrapFlags());
-        }
-      }
-    }
-
+    inferNoWrapViaConstantRanges(AR);
     auto NewFlags = proveNoSignedWrapViaInduction(AR);
+    if (!hasFlags(NewFlags, SCEV::FlagNSW) &&
+        proveNoWrapByVaryingStart<SCEVSignExtendExpr>(Start, Step, L))
+      NewFlags |= SCEV::FlagNSW;
     setNoWrapFlags(const_cast<SCEVAddRecExpr *>(AR), NewFlags);
+
+    // If the operand is an affine AddRec with the no-signed-wrap flag, the
+    // sign-extension distributes over the recurrence.
     if (AR->hasNoSignedWrap()) {
-      // Same as nsw case above - duplicated here to avoid a compile time
-      // issue.  It's not clear that the order of checks does matter, but
-      // it's one of two issue possible causes for a change which was
-      // reverted.  Be conservative for the moment.
       Start = getExtendAddRecStart<SCEVSignExtendExpr>(AR, Ty, this, Depth + 1);
       Step = getSignExtendExpr(Step, Ty, Depth + 1);
       return getAddRecExpr(Start, Step, L, AR->getNoWrapFlags());
     }
 
+    // For a positive step, we can extend the operands iff doing so only
+    // traverses values in the range sext([0,UINT_MIN]).
+    if (isKnownPositive(Step)) {
+      unsigned BitWidth = getTypeSizeInBits(AR->getType());
+      const SCEV *N =
+          getConstant(APInt::getMinValue(BitWidth) - getSignedRangeMax(Step));
+      if (isLoopBackedgeGuardedByCond(L, ICmpInst::ICMP_ULT, AR, N) ||
+          isKnownOnEveryIteration(ICmpInst::ICMP_ULT, AR, N)) {
+        setNoWrapFlags(const_cast<SCEVAddRecExpr *>(AR), SCEV::FlagNW);
+        Start =
+            getExtendAddRecStart<SCEVSignExtendExpr>(AR, Ty, this, Depth + 1);
+        Step = getZeroExtendExpr(Step, Ty, Depth + 1);
+        return getAddRecExpr(Start, Step, L, AR->getNoWrapFlags());
+      }
+    }
+
     // sext({C,+,Step}) --> (sext(D) + sext({C-D,+,Step}))<nuw><nsw>
     // if D + (C - D + Step * n) could be proven to not signed wrap
     // where D maximizes the number of trailing zeros of (C - D + Step * n)
@@ -2149,13 +2092,6 @@ const SCEV *ScalarEvolution::getSignExtendExprImpl(SCEVUse Op, Type *Ty,
                           Depth + 1);
       }
     }
-
-    if (proveNoWrapByVaryingStart<SCEVSignExtendExpr>(Start, Step, L)) {
-      setNoWrapFlags(const_cast<SCEVAddRecExpr *>(AR), SCEV::FlagNSW);
-      Start = getExtendAddRecStart<SCEVSignExtendExpr>(AR, Ty, this, Depth + 1);
-      Step = getSignExtendExpr(Step, Ty, Depth + 1);
-      return getAddRecExpr(Start, Step, L, AR->getNoWrapFlags());
-    }
   }
 
   // If the input value is provably positive and we could not simplify
diff --git a/llvm/test/Analysis/ScalarEvolution/incorrect-nsw.ll b/llvm/test/Analysis/ScalarEvolution/incorrect-nsw.ll
index f7edf493c64c4..1490c6710bced 100644
--- a/llvm/test/Analysis/ScalarEvolution/incorrect-nsw.ll
+++ b/llvm/test/Analysis/ScalarEvolution/incorrect-nsw.ll
@@ -3,13 +3,13 @@
 define void @bad.nsw() {
 ; CHECK-LABEL: Classifying expressions for: @bad.nsw
 ; CHECK-LABEL: Classifying expressions for: @bad.nsw
- entry: 
+ entry:
   br label %loop
 
  loop:
   %i = phi i8 [ -1, %entry ], [ %i.inc, %loop ]
 ; CHECK:  %i = phi i8 [ -1, %entry ], [ %i.inc, %loop ]
-; CHECK-NEXT: -->  {-1,+,-128}<nw><%loop>
+; CHECK-NEXT: -->  {-1,+,-128}<%loop>
 ; CHECK-NOT: -->  {-1,+,-128}<nsw><%loop>
 
   %counter = phi i8 [ 0, %entry ], [ %counter.inc, %loop ]
@@ -22,5 +22,5 @@ define void @bad.nsw() {
   br i1 %continue, label %exit, label %loop
 
  exit:
-  ret void  
+  ret void
 }
diff --git a/llvm/test/Analysis/ScalarEvolution/min-max-exprs.ll b/llvm/test/Analysis/ScalarEvolution/min-max-exprs.ll
index 6ededf2477711..73a20f03548ba 100644
--- a/llvm/test/Analysis/ScalarEvolution/min-max-exprs.ll
+++ b/llvm/test/Analysis/ScalarEvolution/min-max-exprs.ll
@@ -26,13 +26,13 @@ define void @f(ptr %A, i32 %N) {
 ; CHECK-NEXT:    %tmp3 = add nuw nsw i32 %i.0, 3
 ; CHECK-NEXT:    --> {3,+,1}<nuw><%bb1> U: [3,-2147483645) S: [3,-2147483645) Exits: (3 + (0 smax %N))<nuw> LoopDispositions: { %bb1: Computable }
 ; CHECK-NEXT:    %tmp5 = sext i32 %tmp3 to i64
-; CHECK-NEXT:    --> (sext i32 {3,+,1}<nuw><%bb1> to i64) U: [-2147483648,2147483648) S: [-2147483648,2147483648) Exits: (sext i32 (3 + (0 smax %N))<nuw> to i64) LoopDispositions: { %bb1: Computable }
+; CHECK-NEXT:    --> {3,+,1}<nuw><%bb1> U: [3,2147483651) S: [3,2147483651) Exits: (3 + (zext i32 (0 smax %N) to i64))<nuw><nsw> LoopDispositions: { %bb1: Computable }
 ; CHECK-NEXT:    %tmp6 = sext i32 %N to i64
 ; CHECK-NEXT:    --> (sext i32 %N to i64) U: [-2147483648,2147483648) S: [-2147483648,2147483648) Exits: (sext i32 %N to i64) LoopDispositions: { %bb1: Invariant }
 ; CHECK-NEXT:    %tmp9 = select i1 %tmp4, i64 %tmp5, i64 %tmp6
-; CHECK-NEXT:    --> ((sext i32 {3,+,1}<nuw><%bb1> to i64) smin (sext i32 %N to i64)) U: [-2147483648,2147483648) S: [-2147483648,2147483648) Exits: ((sext i32 (3 + (0 smax %N))<nuw> to i64) smin (sext i32 %N to i64)) LoopDispositions: { %bb1: Computable }
+; CHECK-NEXT:    --> ((sext i32 %N to i64) smin {3,+,1}<nuw><nsw><%bb1>) U: [-2147483648,2147483648) S: [-2147483648,2147483648) Exits: ((sext i32 %N to i64) smin (3 + (zext i32 (0 smax %N) to i64))<nuw><nsw>) LoopDispositions: { %bb1: Computable }
 ; CHECK-NEXT:    %tmp11 = getelementptr inbounds i32, ptr %A, i64 %tmp9
-; CHECK-NEXT:    --> ((4 * ((sext i32 {3,+,1}<nuw><%bb1> to i64) smin (sext i32 %N to i64)))<nsw> + %A) U: full-set S: full-set Exits: ((4 * ((sext i32 (3 + (0 smax %N))<nuw> to i64) smin (sext i32 %N to i64)))<nsw> + %A) LoopDispositions: { %bb1: Computable }
+; CHECK-NEXT:    --> ((4 * ((sext i32 %N to i64) smin {3,+,1}<nuw><nsw><%bb1>))<nsw> + %A) U: full-set S: full-set Exits: ((4 * ((sext i32 %N to i64) smin (3 + (zext i32 (0 smax %N) to i64))<nuw><nsw>))<nsw> + %A) LoopDispositions: { %bb1: Computable }
 ; CHECK-NEXT:    %tmp12 = load i32, ptr %tmp11, align 4
 ; CHECK-NEXT:    --> %tmp12 U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %bb1: Variant }
 ; CHECK-NEXT:    %tmp13 = shl nsw i32 %tmp12, 1
diff --git a/llvm/test/Analysis/ScalarEvolution/sext-iv-2.ll b/llvm/test/Analysis/ScalarEvolution/sext-iv-2.ll
index 572b3f7271b88..b5d05a31356b6 100644
--- a/llvm/test/Analysis/ScalarEvolution/sext-iv-2.ll
+++ b/llvm/test/Analysis/ScalarEvolution/sext-iv-2.ll
@@ -1,17 +1,45 @@
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 6
 ; RUN: opt < %s -disable-output "-passes=print<scalar-evolution>" 2>&1 | FileCheck %s
 
-; CHECK: %tmp3 = sext i8 %tmp2 to i32
-; CHECK: -->  (sext i8 {0,+,1}<nuw><%bb1> to i32) U: [-128,128) S: [-128,128)               Exits: -1
-; CHECK: %tmp4 = mul i32 %tmp3, %i.02
-; CHECK: -->  ((sext i8 {0,+,1}<nuw><%bb1> to i32) * {0,+,1}<nuw><nsw><%bb>) U: [-3968,3938) S: [-3968,3938)                Exits: {0,+,-1}<nsw><%bb>
-
-; These sexts are not foldable.
-
 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64"
 
 @table = common global [32 x [256 x i32]] zeroinitializer, align 32		; <ptr> [#uses=2]
 
 define i32 @main() nounwind {
+; CHECK-LABEL: 'main'
+; CHECK-NEXT:  Classifying expressions for: @main
+; CHECK-NEXT:    %i.02 = phi i32 [ %tmp10, %bb4 ], [ 0, %bb.nph3 ]
+; CHECK-NEXT:    --> {0,+,1}<nuw><nsw><%bb> U: [0,32) S: [0,32) Exits: 31 LoopDispositions: { %bb: Computable, %bb1: Invariant }
+; CHECK-NEXT:    %j.01 = phi i32 [ %tmp8, %bb2 ], [ 0, %bb.nph ]
+; CHECK-NEXT:    --> {0,+,1}<nuw><nsw><%bb1> U: [0,256) S: [0,256) Exits: 255 LoopDispositions: { %bb1: Computable, %bb: Uniform }
+; CHECK-NEXT:    %tmp2 = trunc i32 %j.01 to i8
+; CHECK-NEXT:    --> {0,+,1}<%bb1> U: full-set S: full-set Exits: -1 LoopDispositions: { %bb1: Computable, %bb: Uniform }
+; CHECK-NEXT:    %tmp3 = sext i8 %tmp2 to i32
+; CHECK-NEXT:    --> {0,+,1}<nuw><nsw><%bb1> U: [0,256) S: [0,256) Exits: 255 LoopDispositions: { %bb1: Computable, %bb: Uniform }
+; CHECK-NEXT:    %tmp4 = mul i32 %tmp3, %i.02
+; CHECK-NEXT:    --> {0,+,{0,+,1}<nuw><nsw><%bb>}<%bb1> U: [0,7906) S: [0,7906) Exits: {0,+,255}<nuw><nsw><%bb> LoopDispositions: { %bb1: Computable, %bb: Variant }
+; CHECK-NEXT:    %tmp5 = sext i32 %i.02 to i64
+; CHECK-NEXT:    --> {0,+,1}<nuw><nsw><%bb> U: [0,32) S: [0,32) Exits: {0,+,1}<nuw><nsw><%bb> LoopDispositions: { %bb1: Invariant, %bb: Computable }
+; CHECK-NEXT:    %tmp6 = sext i32 %j.01 to i64
+; CHECK-NEXT:    --> {0,+,1}<nuw><nsw><%bb1> U: [0,256) S: [0,256) Exits: 255 LoopDispositions: { %bb1: Computable, %bb: Uniform }
+; CHECK-NEXT:    %tmp7 = getelementptr [32 x [256 x i32]], ptr @table, i64 0, i64 %tmp5, i64 %tmp6
+; CHECK-NEXT:    --> {{\{\{}}@table,+,1024}<nw><%bb>,+,4}<nw><%bb1> U: [32,-35) S: [-9223372036854775808,9223372036854775805) Exits: {(1020 + @table)<nuw>,+,1024}<nuw><%bb> LoopDispositions: { %bb1: Computable, %bb: Variant }
+; CHECK-NEXT:    %tmp8 = add i32 %j.01, 1
+; CHECK-NEXT:    --> {1,+,1}<nuw><nsw><%bb1> U: [1,257) S: [1,257) Exits: 256 LoopDispositions: { %bb1: Computable, %bb: Uniform }
+; CHECK-NEXT:    %tmp10 = add i32 %i.02, 1
+; CHECK-NEXT:    --> {1,+,1}<nuw><nsw><%bb> U: [1,33) S: [1,33) Exits: 32 LoopDispositions: { %bb: Computable, %bb1: Invariant }
+; CHECK-NEXT:    %tmp12 = load i32, ptr getelementptr ([32 x [256 x i32]], ptr @table, i64 0, i64 9, i64 132), align 16
+; CHECK-NEXT:    --> %tmp12 U: full-set S: full-set
+; CHECK-NEXT:  Determining loop execution counts for: @main
+; CHECK-NEXT:  Loop %bb1: backedge-taken count is i32 255
+; CHECK-NEXT:  Loop %bb1: constant max backedge-taken count is i32 255
+; CHECK-NEXT:  Loop %bb1: symbolic max backedge-taken count is i32 255
+; CHECK-NEXT:  Loop %bb1: Trip multiple is 256
+; CHECK-NEXT:  Loop %bb: backedge-taken count is i32 31
+; CHECK-NEXT:  Loop %bb: constant max backedge-taken count is i32 31
+; CHECK-NEXT:  Loop %bb: symbolic max backedge-taken count is i32 31
+; CHECK-NEXT:  Loop %bb: Trip multiple is 32
+;
 entry:
 	br i1 false, label %bb5, label %bb.nph3
 
diff --git a/llvm/test/Analysis/ScalarEvolution/sext-mul.ll b/llvm/test/Analysis/ScalarEvolution/sext-mul.ll
index 5d6a1dec72e13..41bab08a9ae82 100644
--- a/llvm/test/Analysis/ScalarEvolution/sext-mul.ll
+++ b/llvm/test/Analysis/ScalarEvolution/sext-mul.ll
@@ -11,17 +11,17 @@ define void @foo(ptr nocapture %arg, i32 %arg1, i32 %arg2) {
 ; CHECK-NEXT:    %tmp9 = shl i64 %tmp8, 33
 ; CHECK-NEXT:    --> {0,+,8589934592}<nuw><%bb7> U: [0,-17179869183) S: [-9223372036854775808,9223372028264841217) Exits: (-8589934592 + (8589934592 * (zext i32 %arg2 to i64))) LoopDispositions: { %bb7: Computable }
 ; CHECK-NEXT:    %tmp10 = ashr exact i64 %tmp9, 32
-; CHECK-NEXT:    --> (sext i32 {0,+,2}<nuw><%bb7> to i64) U: [0,-1) S: [-2147483648,2147483647) Exits: (sext i32 (-2 + (2 * %arg2)) to i64) LoopDispositions: { %bb7: Computable }
+; CHECK-NEXT:    --> {0,+,2}<nuw><nsw><%bb7> U: [0,4294967293) S: [0,4294967293) Exits: (-2 + (2 * (zext i32 %arg2 to i64))<nuw><nsw>)<nsw> LoopDispositions: { %bb7: Computable }
 ; CHECK-NEXT:    %tmp11 = getelementptr inbounds i32, ptr %arg, i64 %tmp10
-; CHECK-NEXT:    --> ((4 * (sext i32 {0,+,2}<nuw><%bb7> to i64))<nsw> + %arg) U: full-set S: full-set Exits: ((4 * (sext i32 (-2 + (2 * %arg2)) to i64))<nsw> + %arg) LoopDispositions: { %bb7: Computable }
+; CHECK-NEXT:    --> {%arg,+,8}<nuw><%bb7> U: full-set S: full-set Exits: (-8 + (8 * (zext i32 %arg2 to i64))<nuw><nsw> + %arg) LoopDispositions: { %bb7: Computable }
 ; CHECK-NEXT:    %tmp12 = load i32, ptr %tmp11, align 4
 ; CHECK-NEXT:    --> %tmp12 U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %bb7: Variant }
 ; CHECK-NEXT:    %tmp13 = sub nsw i32 %tmp12, %arg1
 ; CHECK-NEXT:    --> ((-1 * %arg1) + %tmp12) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %bb7: Variant }
 ; CHECK-NEXT:    %tmp14 = or disjoint i64 %tmp10, 1
-; CHECK-NEXT:    --> (1 + (sext i32 {0,+,2}<nuw><%bb7> to i64))<nuw><nsw> U: [1,0) S: [-2147483647,2147483648) Exits: (1 + (sext i32 (-2 + (2 * %arg2)) to i64))<nuw><nsw> LoopDispositions: { %bb7: Computable }
+; CHECK-NEXT:    --> {1,+,2}<nuw><nsw><%bb7> U: [1,4294967294) S: [1,4294967294) Exits: (-1 + (2 * (zext i32 %arg2 to i64))<nuw><nsw>)<nsw> LoopDispositions: { %bb7: Computable }
 ; CHECK-NEXT:    %tmp15 = getelementptr inbounds i32, ptr %arg, i64 %tmp14
-; CHECK-NEXT:    --> (4 + (4 * (sext i32 {0,+,2}<nuw><%bb7> to i64))<nsw> + %arg) U: full-set S: full-set Exits: (4 + (4 * (sext i32 (-2 + (2 * %arg2)) to i64))<nsw> + %arg) LoopDispositions: { %bb7: Computable }
+; CHECK-NEXT:    --> {(4 + %arg),+,8}<nuw><%bb7> U: full-set S: full-set Exits: (-4 + (8 * (zext i32 %arg2 to i64))<nuw><nsw> + %arg) LoopDispositions: { %bb7: Computable }
 ; CHECK-NEXT:    %tmp16 = load i32, ptr %tmp15, align 4
 ; CHECK-NEXT:    --> %tmp16 U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %bb7: Variant }
 ; CHECK-NEXT:    %tmp17 = mul nsw i32 %tmp16, %arg1
diff --git a/llvm/test/Transforms/IndVarSimplify/ARM/code-size.ll b/llvm/test/Transforms/IndVarSimplify/ARM/code-size.ll
index 712b6ae399f2e..b5549b706957f 100644
--- a/llvm/test/Transforms/IndVarSimplify/ARM/code-size.ll
+++ b/llvm/test/Transforms/IndVarSimplify/ARM/code-size.ll
@@ -149,7 +149,7 @@ define i32 @test1(ptr %array, i32 %length, i32 %n) #0 {
 ; CHECK-V8M-NEXT:    [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
 ; CHECK-V8M-NEXT:    [[ARRAY_I:%.*]] = load i32, ptr [[ARRAY_I_PTR]], align 4
 ; CHECK-V8M-NEXT:    [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
-; CHECK-V8M-NEXT:    [[I_NEXT]] = add nuw i32 [[I]], 1
+; CHECK-V8M-NEXT:    [[I_NEXT]] = add nuw nsw i32 [[I]], 1
 ; CHECK-V8M-NEXT:    [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
 ; CHECK-V8M-NEXT:    br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
 ; CHECK-V8M:       exit:
@@ -176,7 +176,7 @@ define i32 @test1(ptr %array, i32 %length, i32 %n) #0 {
 ; CHECK-V8A-NEXT:    [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY:%.*]], i64 [[I_I64]]
 ; CHECK-V8A-NEXT:    [[ARRAY_I:%.*]] = load i32, ptr [[ARRAY_I_PTR]], align 4
 ; CHECK-V8A-NEXT:    [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
-; CHECK-V8A-NEXT:    [[I_NEXT]] = add nuw i32 [[I]], 1
+; CHECK-V8A-NEXT:    [[I_NEXT]] = add nuw nsw i32 [[I]], 1
 ; CHECK-V8A-NEXT:    [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
 ; CHECK-V8A-NEXT:    br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
 ; CHECK-V8A:       exit:
@@ -317,7 +317,7 @@ define i32 @two_range_checks(ptr %array.1, i32 %length.1, ptr %array.2, i32 %len
 ; CHECK-V8M-NEXT:    [[ARRAY_2_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY_2:%.*]], i64 [[I_I64]]
 ; CHECK-V8M-NEXT:    [[ARRAY_2_I:%.*]] = load i32, ptr [[ARRAY_2_I_PTR]], align 4
 ; CHECK-V8M-NEXT:    [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC_1]], [[ARRAY_2_I]]
-; CHECK-V8M-NEXT:    [[I_NEXT]] = add nuw i32 [[I]], 1
+; CHECK-V8M-NEXT:    [[I_NEXT]] = add nuw nsw i32 [[I]], 1
 ; CHECK-V8M-NEXT:    [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
 ; CHECK-V8M-NEXT:    br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT:%.*]]
 ; CHECK-V8M:       exit:
@@ -348,7 +348,7 @@ define i32 @two_range_checks(ptr %array.1, i32 %length.1, ptr %array.2, i32 %len
 ; CHECK-V8A-NEXT:    [[ARRAY_2_I_PTR:%.*]] = getelementptr inbounds i32, ptr [[ARRAY_2:%.*]], i64 [[I_I64]]
 ; CHECK-V8A-NEXT:    [[ARRAY_2_I:%.*]] = load i32, ptr [[ARRAY_2_I_PTR]], align 4
 ; CHECK-V8A-NEXT:    [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC_1]], [[ARRAY_2_I]]
-; CHECK-V8A-NEXT:    [[I_NEXT]] = add nuw i32 [[I]], 1
+; CHECK-V8A-NEXT:    [[I_NEXT]] =...
[truncated]

``````````

</details>


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


More information about the llvm-commits mailing list