[llvm] [SCEVDivision] Prevent propagating nowrap flags when numerator is an addrec (PR #154745)

Ryotaro Kasuga via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 16 00:46:22 PST 2026


https://github.com/kasuga-fj updated https://github.com/llvm/llvm-project/pull/154745

>From 1e2b6d4c5631b1d228fbe3fecc5134de76c7be7a Mon Sep 17 00:00:00 2001
From: Ryotaro Kasuga <kasuga.ryotaro at fujitsu.com>
Date: Wed, 20 Aug 2025 10:11:43 +0000
Subject: [PATCH 1/3] [SCEVDivision] Prevent propagation of incorrect no-wrap
 flags

---
 llvm/lib/Analysis/ScalarEvolutionDivision.cpp |  22 ++-
 .../Delinearization/fixed_size_array.ll       |   2 +-
 llvm/test/Analysis/Delinearization/wraps.ll   | 130 ++++++++++++++++++
 .../Analysis/DependenceAnalysis/DADelin.ll    |   6 +-
 4 files changed, 154 insertions(+), 6 deletions(-)
 create mode 100644 llvm/test/Analysis/Delinearization/wraps.ll

diff --git a/llvm/lib/Analysis/ScalarEvolutionDivision.cpp b/llvm/lib/Analysis/ScalarEvolutionDivision.cpp
index d03930d9e2d99..c374d328c984a 100644
--- a/llvm/lib/Analysis/ScalarEvolutionDivision.cpp
+++ b/llvm/lib/Analysis/ScalarEvolutionDivision.cpp
@@ -141,10 +141,26 @@ void SCEVDivision::visitAddRecExpr(const SCEVAddRecExpr *Numerator) {
   if (Ty != StartQ->getType() || Ty != StartR->getType() ||
       Ty != StepQ->getType() || Ty != StepR->getType())
     return cannotDivide(Numerator);
+
+  // Infer no-wrap flags for Remainder.
+  // TODO: Catch more cases.
+  SCEV::NoWrapFlags NumFlags = Numerator->getNoWrapFlags();
+  SCEV::NoWrapFlags RemFlags = SCEV::NoWrapFlags::FlagAnyWrap;
+  const SCEV *StepNumAbs =
+      SE.getAbsExpr(Numerator->getStepRecurrence(SE), /*IsNSW=*/false);
+  const SCEV *StepRAbs = SE.getAbsExpr(StepR, /*IsNSW=*/false);
+  const Loop *L = Numerator->getLoop();
+
+  // If abs(StepR) <=u abs(StepNumAbs) and both are loop invariant, propagate
+  // the <NW> from Numerator to Remainder.
+  if (ScalarEvolution::hasFlags(NumFlags, SCEV::NoWrapFlags::FlagNW) &&
+      SE.isLoopInvariant(StepNumAbs, L) && SE.isLoopInvariant(StepRAbs, L) &&
+      SE.isKnownPredicate(ICmpInst::ICMP_ULE, StepRAbs, StepNumAbs))
+    RemFlags = ScalarEvolution::setFlags(RemFlags, SCEV::NoWrapFlags::FlagNW);
+
   Quotient = SE.getAddRecExpr(StartQ, StepQ, Numerator->getLoop(),
-                              Numerator->getNoWrapFlags());
-  Remainder = SE.getAddRecExpr(StartR, StepR, Numerator->getLoop(),
-                               Numerator->getNoWrapFlags());
+                              SCEV::NoWrapFlags::FlagAnyWrap);
+  Remainder = SE.getAddRecExpr(StartR, StepR, Numerator->getLoop(), RemFlags);
 }
 
 void SCEVDivision::visitAddExpr(const SCEVAddExpr *Numerator) {
diff --git a/llvm/test/Analysis/Delinearization/fixed_size_array.ll b/llvm/test/Analysis/Delinearization/fixed_size_array.ll
index 0512044990163..e77fd79a49b35 100644
--- a/llvm/test/Analysis/Delinearization/fixed_size_array.ll
+++ b/llvm/test/Analysis/Delinearization/fixed_size_array.ll
@@ -163,7 +163,7 @@ exit:
 ; CHECK:      Delinearization on function a_i_2j1_k:
 ; CHECK:      Base offset: %a
 ; CHECK-NEXT: ArrayDecl[UnknownSize][4][64] with elements of 4 bytes.
-; CHECK-NEXT: ArrayRef[{0,+,1}<nuw><nsw><%for.i.header>][{0,+,1}<nuw><%for.j.header>][{32,+,1}<nw><%for.k>]
+; CHECK-NEXT: ArrayRef[{0,+,1}<nuw><nsw><%for.i.header>][{0,+,1}<%for.j.header>][{32,+,1}<%for.k>]
 define void @a_i_2j1_k(ptr %a) {
 entry:
   br label %for.i.header
diff --git a/llvm/test/Analysis/Delinearization/wraps.ll b/llvm/test/Analysis/Delinearization/wraps.ll
new file mode 100644
index 0000000000000..fc4935bad9939
--- /dev/null
+++ b/llvm/test/Analysis/Delinearization/wraps.ll
@@ -0,0 +1,130 @@
+; RUN: opt < %s -passes='print<delinearization>' -disable-output 2>&1 | FileCheck %s
+
+; In the following case, we don't know the concret value of `m`, so we cannot
+; deduce no-wrap behavior for the quotient/remainder divided by `m`. However,
+; we can infer `{0,+,1}<%loop>` is nuw and nsw from the induction variable.
+;
+; for (int i = 0; i < btc; i++)
+;   a[i * (m + 42)] = 0;
+
+; CHECK:      AccessFunction: {0,+,(42 + %m)}<nuw><nsw><%loop>
+; CHECK-NEXT: Base offset: %a
+; CHECK-NEXT: ArrayDecl[UnknownSize][%m] with elements of 1 bytes.
+; CHECK-NEXT: ArrayRef[{0,+,1}<nuw><nsw><%loop>][{0,+,42}<%loop>]
+define void @divide_by_m0(ptr %a, i64 %m, i64 %btc) {
+entry:
+  %stride = add nsw nuw i64 %m, 42
+  br label %loop
+
+loop:
+  %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+  %offset = phi i64 [ 0, %entry ], [ %offset.next, %loop ]
+  %idx = getelementptr inbounds i8, ptr %a, i64 %offset
+  store i8 0, ptr %idx
+  %i.next = add nsw nuw i64 %i, 1
+  %offset.next = add nsw nuw i64 %offset, %stride
+  %cond = icmp eq i64 %i.next, %btc
+  br i1 %cond, label %exit, label %loop
+
+exit:
+  ret void
+}
+
+; In the following case, we don't know the concret value of `m`, so we cannot
+; deduce no-wrap behavior for the quotient/remainder divided by `m`. Also, we
+; don't infer nsw/nuw from the induction variable in this case.
+;
+; for (int i = 0; i < btc; i++)
+;   a[i * (2 * m + 42)] = 0;
+
+; CHECK:      AccessFunction: {0,+,(42 + (2 * %m))}<nuw><nsw><%loop>
+; CHECK-NEXT: Base offset: %a
+; CHECK-NEXT: ArrayDecl[UnknownSize][%m] with elements of 1 bytes.
+; CHECK-NEXT: ArrayRef[{0,+,2}<%loop>][{0,+,42}<%loop>]
+define void @divide_by_m2(ptr %a, i64 %m, i64 %btc) {
+entry:
+  %m2 = add nsw nuw i64 %m, %m
+  %stride = add nsw nuw i64 %m2, 42
+  br label %loop
+
+loop:
+  %i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
+  %offset = phi i64 [ 0, %entry ], [ %offset.next, %loop ]
+  %idx = getelementptr inbounds i8, ptr %a, i64 %offset
+  store i8 0, ptr %idx
+  %i.next = add nsw nuw i64 %i, 1
+  %offset.next = add nsw nuw i64 %offset, %stride
+  %cond = icmp eq i64 %i.next, %btc
+  br i1 %cond, label %exit, label %loop
+
+exit:
+  ret void
+}
+
+; In the following case, the `i * 2 * d` is always zero, so it's nsw and nuw.
+; However, the quotient divided by `d` is neither nsw nor nuw.
+;
+; if (d == 0)
+;   for (unsigned long long i = 0; i != UINT64_MAX; i++)
+;     a[i * 2 * d] = 42;
+
+; CHECK:      AccessFunction: {0,+,(2 * %d)}<nuw><nsw><%loop>
+; CHECK-NEXT: Base offset: %a
+; CHECK-NEXT: ArrayDecl[UnknownSize][%d] with elements of 1 bytes.
+; CHECK-NEXT: ArrayRef[{0,+,2}<%loop>][0]
+define void @divide_by_zero(ptr %a, i64 %d) {
+entry:
+  %guard = icmp eq i64 %d, 0
+  br i1 %guard, label %loop.preheader, label %exit
+
+loop.preheader:
+  %stride = mul nsw nuw i64 %d, 2  ; since %d is 0, %stride is also 0
+  br label %loop
+
+loop:
+  %i = phi i64 [ 0, %loop.preheader ], [ %i.next, %loop ]
+  %offset = phi i64 [ 0, %loop.preheader ], [ %offset.next, %loop ]
+  %idx = getelementptr inbounds i8, ptr %a, i64 %offset
+  store i8 42, ptr %idx
+  %i.next = add nuw i64 %i, 1
+  %offset.next = add nsw nuw i64 %offset, %stride
+  %cond = icmp eq i64 %i.next, -1
+  br i1 %cond, label %exit, label %loop
+
+exit:
+  ret void
+}
+
+; In the following case, the `i * (d + 1)` is always zero, so it's nsw and nuw.
+; However, the quotient/remainder divided by `d` is not nsw.
+;
+; if (d == UINT64_MAX)
+;   for (unsigned long long i = 0; i != d; i++)
+;     a[i * (d + 1)] = 42;
+
+; CHECK:      AccessFunction: {0,+,(1 + %d)}<nuw><nsw><%loop>
+; CHECK-NEXT: Base offset: %a
+; CHECK-NEXT: ArrayDecl[UnknownSize][%d] with elements of 1 bytes.
+; CHECK-NEXT: ArrayRef[{0,+,1}<nuw><%loop>][{0,+,1}<nuw><%loop>]
+define void @divide_by_minus_one(ptr %a, i64 %d) {
+entry:
+  %guard = icmp eq i64 %d, -1
+  br i1 %guard, label %loop.preheader, label %exit
+
+loop.preheader:
+  %stride = add nsw i64 %d, 1  ; since %d is -1, %stride is 0
+  br label %loop
+
+loop:
+  %i = phi i64 [ 0, %loop.preheader ], [ %i.next, %loop ]
+  %offset = phi i64 [ 0, %loop.preheader ], [ %offset.next, %loop ]
+  %idx = getelementptr inbounds i8, ptr %a, i64 %offset
+  store i8 42, ptr %idx
+  %i.next = add nuw i64 %i, 1
+  %offset.next = add nsw nuw i64 %offset, %stride
+  %cond = icmp eq i64 %i.next, %d
+  br i1 %cond, label %exit, label %loop
+
+exit:
+  ret void
+}
diff --git a/llvm/test/Analysis/DependenceAnalysis/DADelin.ll b/llvm/test/Analysis/DependenceAnalysis/DADelin.ll
index 8f94a455d3724..f670136aed750 100644
--- a/llvm/test/Analysis/DependenceAnalysis/DADelin.ll
+++ b/llvm/test/Analysis/DependenceAnalysis/DADelin.ll
@@ -479,14 +479,16 @@ for.cond.cleanup:                                 ; preds = %for.cond.cleanup3,
 ;;    for (int k = 1; k < o; k++)
 ;;      = A[i*m*o + j*o + k]
 ;;     A[i*m*o + j*o + k - 1] =
+;;
+;; FIXME: Currently fails to infer nsw for the SCEV `{0,+,1}<for.body8>`
 define void @t8(i32 %n, i32 %m, i32 %o, ptr nocapture %A) {
 ; CHECK-LABEL: 't8'
 ; CHECK-NEXT:  Src: %0 = load i32, ptr %arrayidx, align 4 --> Dst: %0 = load i32, ptr %arrayidx, align 4
 ; CHECK-NEXT:    da analyze - none!
 ; CHECK-NEXT:  Src: %0 = load i32, ptr %arrayidx, align 4 --> Dst: store i32 %add12, ptr %arrayidx2, align 4
-; CHECK-NEXT:    da analyze - consistent anti [0 0 1]!
+; CHECK-NEXT:    da analyze - anti [* * *|<]!
 ; CHECK-NEXT:  Src: store i32 %add12, ptr %arrayidx2, align 4 --> Dst: store i32 %add12, ptr %arrayidx2, align 4
-; CHECK-NEXT:    da analyze - none!
+; CHECK-NEXT:    da analyze - output [* * *]!
 ;
 entry:
   %cmp49 = icmp sgt i32 %n, 0

>From 01321161a192f48ad01ea14a740bbc6fc977976a Mon Sep 17 00:00:00 2001
From: Ryotaro Kasuga <kasuga.ryotaro at fujitsu.com>
Date: Mon, 16 Feb 2026 08:09:12 +0000
Subject: [PATCH 2/3] [SCEVDivision] Drop nowrap flags for addrecs

---
 llvm/lib/Analysis/ScalarEvolutionDivision.cpp | 19 +---
 .../Delinearization/fixed_size_array.ll       |  2 +-
 llvm/test/Analysis/Delinearization/wraps.ll   | 87 +++++++++++--------
 .../Analysis/ScalarEvolutionDivision/sdiv.ll  | 14 +--
 4 files changed, 61 insertions(+), 61 deletions(-)

diff --git a/llvm/lib/Analysis/ScalarEvolutionDivision.cpp b/llvm/lib/Analysis/ScalarEvolutionDivision.cpp
index f45b2e0196c23..52d82785f6b9c 100644
--- a/llvm/lib/Analysis/ScalarEvolutionDivision.cpp
+++ b/llvm/lib/Analysis/ScalarEvolutionDivision.cpp
@@ -142,25 +142,10 @@ void SCEVDivision::visitAddRecExpr(const SCEVAddRecExpr *Numerator) {
       Ty != StepQ->getType() || Ty != StepR->getType())
     return cannotDivide(Numerator);
 
-  // Infer no-wrap flags for Remainder.
-  // TODO: Catch more cases.
-  SCEV::NoWrapFlags NumFlags = Numerator->getNoWrapFlags();
-  SCEV::NoWrapFlags RemFlags = SCEV::NoWrapFlags::FlagAnyWrap;
-  const SCEV *StepNumAbs =
-      SE.getAbsExpr(Numerator->getStepRecurrence(SE), /*IsNSW=*/false);
-  const SCEV *StepRAbs = SE.getAbsExpr(StepR, /*IsNSW=*/false);
-  const Loop *L = Numerator->getLoop();
-
-  // If abs(StepR) <=u abs(StepNumAbs) and both are loop invariant, propagate
-  // the <NW> from Numerator to Remainder.
-  if (ScalarEvolution::hasFlags(NumFlags, SCEV::NoWrapFlags::FlagNW) &&
-      SE.isLoopInvariant(StepNumAbs, L) && SE.isLoopInvariant(StepRAbs, L) &&
-      SE.isKnownPredicate(ICmpInst::ICMP_ULE, StepRAbs, StepNumAbs))
-    RemFlags = ScalarEvolution::setFlags(RemFlags, SCEV::NoWrapFlags::FlagNW);
-
   Quotient = SE.getAddRecExpr(StartQ, StepQ, Numerator->getLoop(),
                               SCEV::NoWrapFlags::FlagAnyWrap);
-  Remainder = SE.getAddRecExpr(StartR, StepR, Numerator->getLoop(), RemFlags);
+  Remainder = SE.getAddRecExpr(StartR, StepR, Numerator->getLoop(),
+                               SCEV::NoWrapFlags::FlagAnyWrap);
 }
 
 void SCEVDivision::visitAddExpr(const SCEVAddExpr *Numerator) {
diff --git a/llvm/test/Analysis/Delinearization/fixed_size_array.ll b/llvm/test/Analysis/Delinearization/fixed_size_array.ll
index 59e0cffdd0878..7cd90f2bfb61c 100644
--- a/llvm/test/Analysis/Delinearization/fixed_size_array.ll
+++ b/llvm/test/Analysis/Delinearization/fixed_size_array.ll
@@ -203,7 +203,7 @@ define void @a_i_2j1_k(ptr %a) {
 ; CHECK-NEXT:  AccessFunction: {{\{\{\{}}128,+,1024}<nuw><nsw><%for.i.header>,+,256}<nw><%for.j.header>,+,4}<nw><%for.k>
 ; CHECK-NEXT:  Base offset: %a
 ; CHECK-NEXT:  ArrayDecl[UnknownSize][4][64] with elements of 4 bytes.
-; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><nsw><%for.i.header>][{0,+,1}<nuw><%for.j.header>][{32,+,1}<nw><%for.k>]
+; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><nsw><%for.i.header>][{0,+,1}<%for.j.header>][{32,+,1}<%for.k>]
 ; CHECK-NEXT:  Delinearization validation: Succeeded
 ;
 ; OFF-LABEL: 'a_i_2j1_k'
diff --git a/llvm/test/Analysis/Delinearization/wraps.ll b/llvm/test/Analysis/Delinearization/wraps.ll
index fc4935bad9939..f57334ea61320 100644
--- a/llvm/test/Analysis/Delinearization/wraps.ll
+++ b/llvm/test/Analysis/Delinearization/wraps.ll
@@ -1,17 +1,21 @@
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 6
 ; RUN: opt < %s -passes='print<delinearization>' -disable-output 2>&1 | FileCheck %s
 
-; In the following case, we don't know the concret value of `m`, so we cannot
-; deduce no-wrap behavior for the quotient/remainder divided by `m`. However,
-; we can infer `{0,+,1}<%loop>` is nuw and nsw from the induction variable.
-;
-; for (int i = 0; i < btc; i++)
+; for (i = 0; i < btc; i++)
 ;   a[i * (m + 42)] = 0;
-
-; CHECK:      AccessFunction: {0,+,(42 + %m)}<nuw><nsw><%loop>
-; CHECK-NEXT: Base offset: %a
-; CHECK-NEXT: ArrayDecl[UnknownSize][%m] with elements of 1 bytes.
-; CHECK-NEXT: ArrayRef[{0,+,1}<nuw><nsw><%loop>][{0,+,42}<%loop>]
+;
+; We don't know the concret value of `m`, so we cannot deduce no-wrap flags for
+; the quotient/remainder divided by `m`.
+;
 define void @divide_by_m0(ptr %a, i64 %m, i64 %btc) {
+; CHECK-LABEL: 'divide_by_m0'
+; CHECK-NEXT:  Inst: store i8 0, ptr %idx, align 1
+; CHECK-NEXT:  AccessFunction: {0,+,(42 + %m)}<nuw><nsw><%loop>
+; CHECK-NEXT:  Base offset: %a
+; CHECK-NEXT:  ArrayDecl[UnknownSize][%m] with elements of 1 bytes.
+; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><nsw><%loop>][{0,+,42}<%loop>]
+; CHECK-NEXT:  Delinearization validation: Failed
+;
 entry:
   %stride = add nsw nuw i64 %m, 42
   br label %loop
@@ -30,18 +34,21 @@ exit:
   ret void
 }
 
-; In the following case, we don't know the concret value of `m`, so we cannot
-; deduce no-wrap behavior for the quotient/remainder divided by `m`. Also, we
-; don't infer nsw/nuw from the induction variable in this case.
-;
 ; for (int i = 0; i < btc; i++)
 ;   a[i * (2 * m + 42)] = 0;
-
-; CHECK:      AccessFunction: {0,+,(42 + (2 * %m))}<nuw><nsw><%loop>
-; CHECK-NEXT: Base offset: %a
-; CHECK-NEXT: ArrayDecl[UnknownSize][%m] with elements of 1 bytes.
-; CHECK-NEXT: ArrayRef[{0,+,2}<%loop>][{0,+,42}<%loop>]
-define void @divide_by_m2(ptr %a, i64 %m, i64 %btc) {
+;
+; We don't know the concret value of `m`, so we cannot deduce no-wrap flags for
+; the quotient/remainder divided by `m`.
+;
+define void @divide_by_m1(ptr %a, i64 %m, i64 %btc) {
+; CHECK-LABEL: 'divide_by_m1'
+; CHECK-NEXT:  Inst: store i8 0, ptr %idx, align 1
+; CHECK-NEXT:  AccessFunction: {0,+,(42 + (2 * %m))}<nuw><nsw><%loop>
+; CHECK-NEXT:  Base offset: %a
+; CHECK-NEXT:  ArrayDecl[UnknownSize][%m] with elements of 1 bytes.
+; CHECK-NEXT:  ArrayRef[{0,+,2}<%loop>][{0,+,42}<%loop>]
+; CHECK-NEXT:  Delinearization validation: Failed
+;
 entry:
   %m2 = add nsw nuw i64 %m, %m
   %stride = add nsw nuw i64 %m2, 42
@@ -61,18 +68,22 @@ exit:
   ret void
 }
 
-; In the following case, the `i * 2 * d` is always zero, so it's nsw and nuw.
-; However, the quotient divided by `d` is neither nsw nor nuw.
-;
 ; if (d == 0)
 ;   for (unsigned long long i = 0; i != UINT64_MAX; i++)
 ;     a[i * 2 * d] = 42;
-
-; CHECK:      AccessFunction: {0,+,(2 * %d)}<nuw><nsw><%loop>
-; CHECK-NEXT: Base offset: %a
-; CHECK-NEXT: ArrayDecl[UnknownSize][%d] with elements of 1 bytes.
-; CHECK-NEXT: ArrayRef[{0,+,2}<%loop>][0]
+;
+; `i * 2 * d` is always zero, so it's nsw and nuw. However, the quotient
+; divided by `d` is neither nsw nor nuw.
+;
 define void @divide_by_zero(ptr %a, i64 %d) {
+; CHECK-LABEL: 'divide_by_zero'
+; CHECK-NEXT:  Inst: store i8 42, ptr %idx, align 1
+; CHECK-NEXT:  AccessFunction: {0,+,(2 * %d)}<nuw><nsw><%loop>
+; CHECK-NEXT:  Base offset: %a
+; CHECK-NEXT:  ArrayDecl[UnknownSize][%d] with elements of 1 bytes.
+; CHECK-NEXT:  ArrayRef[{0,+,2}<%loop>][0]
+; CHECK-NEXT:  Delinearization validation: Failed
+;
 entry:
   %guard = icmp eq i64 %d, 0
   br i1 %guard, label %loop.preheader, label %exit
@@ -95,18 +106,22 @@ exit:
   ret void
 }
 
-; In the following case, the `i * (d + 1)` is always zero, so it's nsw and nuw.
-; However, the quotient/remainder divided by `d` is not nsw.
-;
 ; if (d == UINT64_MAX)
 ;   for (unsigned long long i = 0; i != d; i++)
 ;     a[i * (d + 1)] = 42;
-
-; CHECK:      AccessFunction: {0,+,(1 + %d)}<nuw><nsw><%loop>
-; CHECK-NEXT: Base offset: %a
-; CHECK-NEXT: ArrayDecl[UnknownSize][%d] with elements of 1 bytes.
-; CHECK-NEXT: ArrayRef[{0,+,1}<nuw><%loop>][{0,+,1}<nuw><%loop>]
+;
+; `i * (d + 1)` is always zero, so it's nsw and nuw. However, the
+; quotient/remainder divided by `d` is not nsw.
+;
 define void @divide_by_minus_one(ptr %a, i64 %d) {
+; CHECK-LABEL: 'divide_by_minus_one'
+; CHECK-NEXT:  Inst: store i8 42, ptr %idx, align 1
+; CHECK-NEXT:  AccessFunction: {0,+,(1 + %d)}<nuw><nsw><%loop>
+; CHECK-NEXT:  Base offset: %a
+; CHECK-NEXT:  ArrayDecl[UnknownSize][%d] with elements of 1 bytes.
+; CHECK-NEXT:  ArrayRef[{0,+,1}<nuw><%loop>][{0,+,1}<nuw><%loop>]
+; CHECK-NEXT:  Delinearization validation: Failed
+;
 entry:
   %guard = icmp eq i64 %d, -1
   br i1 %guard, label %loop.preheader, label %exit
diff --git a/llvm/test/Analysis/ScalarEvolutionDivision/sdiv.ll b/llvm/test/Analysis/ScalarEvolutionDivision/sdiv.ll
index e3cf15eb63534..e7a78dca2d2cb 100644
--- a/llvm/test/Analysis/ScalarEvolutionDivision/sdiv.ll
+++ b/llvm/test/Analysis/ScalarEvolutionDivision/sdiv.ll
@@ -91,7 +91,7 @@ define void @addrec_step0(i8 %n, i8 %step) {
 ; CHECK-NEXT:  Instruction: %div = sdiv i8 %num, %step
 ; CHECK-NEXT:    Numerator: {0,+,%step}<nuw><nsw><%loop>
 ; CHECK-NEXT:    Denominator: %step
-; CHECK-NEXT:    Quotient: {0,+,1}<nuw><nsw><%loop>
+; CHECK-NEXT:    Quotient: {0,+,1}<%loop>
 ; CHECK-NEXT:    Remainder: 0
 ;
 entry:
@@ -115,14 +115,14 @@ exit:
 ;   if (cond)
 ;     div = (step * i) / step;
 ;
-; FIXME: The quotient can cause signed wrap, e.g., when %step is 0 and %n is
-; larger than 127.
+; The quotient can cause signed wrap, e.g., when %step is 0 and %n is larger
+; than 127.
 define void @addrec_step1(i8 %n, i8 %step) {
 ; CHECK-LABEL: 'addrec_step1'
 ; CHECK-NEXT:  Instruction: %div = sdiv i8 %num, %step
 ; CHECK-NEXT:    Numerator: {0,+,%step}<nuw><nsw><%loop.header>
 ; CHECK-NEXT:    Denominator: %step
-; CHECK-NEXT:    Quotient: {0,+,1}<nuw><nsw><%loop.header>
+; CHECK-NEXT:    Quotient: {0,+,1}<%loop.header>
 ; CHECK-NEXT:    Remainder: 0
 ;
 entry:
@@ -152,14 +152,14 @@ exit:
 ; for (i = 0; i < n; i++)
 ;   div = (a + b) * i / a;
 ;
-; FIXME: Both the quotient and the remainder can cause signed/unsigned wrap,
-; e.g., when %a + %b = 0 && %a != 0.
+; Both the quotient and the remainder can cause signed/unsigned wrap, e.g.,
+; when %a + %b = 0 && %a != 0.
 define void @addrec_a_b(i8 %n, i8 %a, i8 %b) {
 ; CHECK-LABEL: 'addrec_a_b'
 ; CHECK-NEXT:  Instruction: %div = sdiv i8 %num, %step
 ; CHECK-NEXT:    Numerator: {0,+,(%a + %b)}<nuw><nsw><%loop>
 ; CHECK-NEXT:    Denominator: (%a + %b)
-; CHECK-NEXT:    Quotient: {0,+,1}<nuw><nsw><%loop>
+; CHECK-NEXT:    Quotient: {0,+,1}<%loop>
 ; CHECK-NEXT:    Remainder: 0
 ;
 entry:

>From bb607a0b086f7d9c4d3252b441f85df762737f1e Mon Sep 17 00:00:00 2001
From: Ryotaro Kasuga <kasuga.ryotaro at fujitsu.com>
Date: Mon, 16 Feb 2026 08:45:56 +0000
Subject: [PATCH 3/3] forgot to add test changes...

---
 llvm/test/Analysis/Delinearization/a.ll                         | 2 +-
 llvm/test/Analysis/Delinearization/divide_by_one.ll             | 2 +-
 .../Delinearization/multidim_ivs_and_integer_offsets_nts_3d.ll  | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/test/Analysis/Delinearization/a.ll b/llvm/test/Analysis/Delinearization/a.ll
index 5d2d4dc29206e..d2e0fa5020d73 100644
--- a/llvm/test/Analysis/Delinearization/a.ll
+++ b/llvm/test/Analysis/Delinearization/a.ll
@@ -14,7 +14,7 @@ define void @foo(i64 %n, i64 %m, i64 %o, ptr nocapture %A) #0 {
 ; CHECK-NEXT:  AccessFunction: {{\{\{\{}}(28 + (4 * (-4 + (3 * %m)) * %o)),+,(8 * %m * %o)}<%for.i>,+,(12 * %o)}<%for.j>,+,20}<%for.k>
 ; CHECK-NEXT:  Base offset: %A
 ; CHECK-NEXT:  ArrayDecl[UnknownSize][%m][%o] with elements of 4 bytes.
-; CHECK-NEXT:  ArrayRef[{3,+,2}<nuw><%for.i>][{-4,+,3}<nw><%for.j>][{7,+,5}<nw><%for.k>]
+; CHECK-NEXT:  ArrayRef[{3,+,2}<nuw><%for.i>][{-4,+,3}<%for.j>][{7,+,5}<%for.k>]
 ; CHECK-NEXT:  Delinearization validation: Failed
 ;
 entry:
diff --git a/llvm/test/Analysis/Delinearization/divide_by_one.ll b/llvm/test/Analysis/Delinearization/divide_by_one.ll
index 3d8e55984291e..fa7f4cead2b00 100644
--- a/llvm/test/Analysis/Delinearization/divide_by_one.ll
+++ b/llvm/test/Analysis/Delinearization/divide_by_one.ll
@@ -17,7 +17,7 @@ define void @test(ptr nocapture %dst, i32 %stride, i32 %bs) {
 ; CHECK-NEXT:  AccessFunction: {{\{\{}}(-1 + ((1 + %bs) * %stride)),+,(-1 * %stride)}<%for.cond1.preheader>,+,1}<nw><%for.body3>
 ; CHECK-NEXT:  Base offset: %dst
 ; CHECK-NEXT:  ArrayDecl[UnknownSize][%stride] with elements of 1 bytes.
-; CHECK-NEXT:  ArrayRef[{(1 + %bs),+,-1}<nw><%for.cond1.preheader>][{-1,+,1}<nw><%for.body3>]
+; CHECK-NEXT:  ArrayRef[{(1 + %bs),+,-1}<nw><%for.cond1.preheader>][{-1,+,1}<%for.body3>]
 ; CHECK-NEXT:  Delinearization validation: Failed
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  Inst: store i8 %0, ptr %arrayidx7, align 1
diff --git a/llvm/test/Analysis/Delinearization/multidim_ivs_and_integer_offsets_nts_3d.ll b/llvm/test/Analysis/Delinearization/multidim_ivs_and_integer_offsets_nts_3d.ll
index 96ea88df56a9f..479ce6f1e1649 100644
--- a/llvm/test/Analysis/Delinearization/multidim_ivs_and_integer_offsets_nts_3d.ll
+++ b/llvm/test/Analysis/Delinearization/multidim_ivs_and_integer_offsets_nts_3d.ll
@@ -15,7 +15,7 @@ define void @foo(i64 %n, i64 %m, i64 %o, i64 %p, ptr nocapture %A) nounwind uwta
 ; CHECK-NEXT:  AccessFunction: {{\{\{\{}}(56 + (8 * (-4 + (3 * %m)) * (%o + %p))),+,(8 * (%o + %p) * %m)}<%for.cond4.preheader.lr.ph.us>,+,(8 * (%o + %p))}<%for.body6.lr.ph.us.us>,+,8}<%for.body6.us.us>
 ; CHECK-NEXT:  Base offset: %A
 ; CHECK-NEXT:  ArrayDecl[UnknownSize][%m][(%o + %p)] with elements of 8 bytes.
-; CHECK-NEXT:  ArrayRef[{3,+,1}<nuw><%for.cond4.preheader.lr.ph.us>][{-4,+,1}<nw><%for.body6.lr.ph.us.us>][{7,+,1}<nw><%for.body6.us.us>]
+; CHECK-NEXT:  ArrayRef[{3,+,1}<nuw><%for.cond4.preheader.lr.ph.us>][{-4,+,1}<%for.body6.lr.ph.us.us>][{7,+,1}<%for.body6.us.us>]
 ; CHECK-NEXT:  Delinearization validation: Failed
 ;
 entry:



More information about the llvm-commits mailing list