[llvm] [SCEV] Propagate a recurrence's nsw flag to its exit value. (PR #225423)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 28 03:56:18 PDT 2026
https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/225423
>From 1580a7a1b81e4540a97d40c929964e7483ac4b18 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 22 Sep 2026 11:31:21 +0100
Subject: [PATCH 1/2] precommit extra test
---
.../IndVarSimplify/exit-value-nowrap-flags.ll | 102 ++++++++++++++++++
1 file changed, 102 insertions(+)
diff --git a/llvm/test/Transforms/IndVarSimplify/exit-value-nowrap-flags.ll b/llvm/test/Transforms/IndVarSimplify/exit-value-nowrap-flags.ll
index 363d25e16e6584..6bcb5544c09092 100644
--- a/llvm/test/Transforms/IndVarSimplify/exit-value-nowrap-flags.ll
+++ b/llvm/test/Transforms/IndVarSimplify/exit-value-nowrap-flags.ll
@@ -72,6 +72,39 @@ exit:
ret i32 %v
}
+; Both %start and %step are negative, so we can only keep nsw on the add.
+define i32 @nsw_start_stop_negative(i32 range(i32 -1024, 0) %start, i32 range(i32 -8, 0) %step, i32 %n) {
+; CHECK-LABEL: define i32 @nsw_start_stop_negative(
+; CHECK-SAME: i32 range(i32 -1024, 0) [[START:%.*]], i32 range(i32 -8, 0) [[STEP:%.*]], i32 [[N:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br label %[[LOOP_HEADER:.*]]
+; CHECK: [[LOOP_HEADER]]:
+; CHECK-NEXT: br i1 true, label %[[EXIT:.*]], label %[[LOOP_LATCH:.*]]
+; CHECK: [[LOOP_LATCH]]:
+; CHECK-NEXT: br label %[[LOOP_HEADER]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: [[TMP0:%.*]] = mul i32 [[N]], [[STEP]]
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[START]], [[TMP0]]
+; CHECK-NEXT: ret i32 [[TMP1]]
+;
+entry:
+ br label %loop.header
+
+loop.header:
+ %v = phi i32 [ %start, %entry ], [ %v.next, %loop.latch ]
+ %i = phi i32 [ 0, %entry ], [ %i.next, %loop.latch ]
+ %done = icmp eq i32 %i, %n
+ br i1 %done, label %exit, label %loop.latch
+
+loop.latch:
+ %v.next = add nsw i32 %v, %step
+ %i.next = add i32 %i, 1
+ br label %loop.header
+
+exit:
+ ret i32 %v
+}
+
; Start is non-negative but Step is negative.
define i32 @nsw_dropped_mixed_signs(i32 %start.in, i32 %step.in, i32 %n) {
; CHECK-LABEL: define i32 @nsw_dropped_mixed_signs(
@@ -110,6 +143,75 @@ exit:
ret i32 %v
}
+; Start is non-negative but Step is negative, and the multiply can overflow:
+; with i8, %start == -128 and %step == 63 the recurrence steps through
+; -128, -65, -2, 61 without wrapping, while 3 * 63 = 189 wraps.
+define i8 @nsw_dropped_mixed_signs_mul_overflows(i8 range(i8 -128, 0) %start, i8 range(i8 0, 64) %step) {
+; CHECK-LABEL: define i8 @nsw_dropped_mixed_signs_mul_overflows(
+; CHECK-SAME: i8 range(i8 -128, 0) [[START:%.*]], i8 range(i8 0, 64) [[STEP:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: br i1 true, label %[[EXIT:.*]], label %[[LATCH:.*]]
+; CHECK: [[LATCH]]:
+; CHECK-NEXT: br label %[[LOOP]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: [[TMP0:%.*]] = mul nuw i8 [[STEP]], 3
+; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[START]], [[TMP0]]
+; CHECK-NEXT: ret i8 [[TMP1]]
+;
+entry:
+ br label %loop
+
+loop:
+ %v = phi i8 [ %start, %entry ], [ %v.next, %latch ]
+ %i = phi i8 [ 0, %entry ], [ %i.next, %latch ]
+ %done = icmp eq i8 %i, 3
+ br i1 %done, label %exit, label %latch
+
+latch:
+ %v.next = add nsw i8 %v, %step
+ %i.next = add i8 %i, 1
+ br label %loop
+
+exit:
+ ret i8 %v
+}
+
+; Both %start and %step are non-negative and the count is a non-negative
+; constant, so both the multiply and the add keep nsw.
+define i32 @nsw_kept_same_sign_const_count(i32 range(i32 0, -2147483648) %start, i32 range(i32 0, -2147483648) %step) {
+; CHECK-LABEL: define i32 @nsw_kept_same_sign_const_count(
+; CHECK-SAME: i32 range(i32 0, -2147483648) [[START:%.*]], i32 range(i32 0, -2147483648) [[STEP:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: br i1 true, label %[[EXIT:.*]], label %[[LATCH:.*]]
+; CHECK: [[LATCH]]:
+; CHECK-NEXT: br label %[[LOOP]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: [[TMP0:%.*]] = mul nuw i32 [[STEP]], 10
+; CHECK-NEXT: [[TMP1:%.*]] = add nuw i32 [[START]], [[TMP0]]
+; CHECK-NEXT: ret i32 [[TMP1]]
+;
+entry:
+ br label %loop
+
+loop:
+ %v = phi i32 [ %start, %entry ], [ %v.next, %latch ]
+ %i = phi i32 [ 0, %entry ], [ %i.next, %latch ]
+ %done = icmp eq i32 %i, 10
+ br i1 %done, label %exit, label %latch
+
+latch:
+ %v.next = add nsw i32 %v, %step
+ %i.next = add i32 %i, 1
+ br label %loop
+
+exit:
+ ret i32 %v
+}
+
; The exit count is (-1 + %n) and Start is 0, so the sum folds away completely.
define i32 @nuw_dropped_sum_folded_away(i32 %n) {
; CHECK-LABEL: define i32 @nuw_dropped_sum_folded_away(
>From 9134f581f8feed1c9b81b0db99baf4090f0312b4 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Sun, 20 Sep 2026 13:25:41 +0100
Subject: [PATCH 2/2] [SCEV] Propagate a recurrence's nsw flag to its exit
value.
Similar to NUW, we can also propagate an AddRec's NSW to the exit value,
with some additional constraints
* If both Start and Step are non-negative, NSW can be preserved on both
the add and multiply in (Start + (It * Step))
https://alive2.llvm.org/ce/z/CcGYzT
* If both Start and Step are negative, NSW can be preserved on the add in
(Start + (It * Step)) and on the multiply if It is positive.
https://alive2.llvm.org/ce/z/LuiCSU
---
llvm/lib/Analysis/ScalarEvolution.cpp | 24 +++++-
.../ScalarEvolution/different-loops-recs.ll | 12 +--
.../exit-value-nowrap-flags.ll | 83 ++++++++++++++++++-
.../increasing-or-decreasing-iv.ll | 2 +-
...ge-taken-count-guard-info-operand-order.ll | 12 +--
.../max-backedge-taken-count-guard-info.ll | 10 +--
.../max-be-count-not-constant.ll | 2 +-
.../ScalarEvolution/nsw-offset-assume.ll | 6 +-
.../Analysis/ScalarEvolution/nsw-offset.ll | 6 +-
llvm/test/Analysis/ScalarEvolution/pr92560.ll | 2 +-
.../IndVarSimplify/exit-value-nowrap-flags.ll | 10 +--
.../IndVarSimplify/loop_evaluate_1.ll | 2 +-
12 files changed, 134 insertions(+), 37 deletions(-)
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index c5e1af4bf060fa..07d5d37825b5e0 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -998,8 +998,25 @@ SCEVUse SCEVAddRecExpr::evaluateAtIteration(ArrayRef<SCEVUse> Operands,
if (isa<SCEVCouldNotCompute>(Coeff))
return Coeff;
+ SCEV::NoWrapFlags MulFlags = UseFlags;
+ if (ScalarEvolution::hasFlags(MulFlags, SCEV::FlagNSW)) {
+ SCEVUse Start = Operands[0];
+ SCEVUse Step = Operands[1];
+ if (!SE.isKnownNonNegative(Start) || !SE.isKnownNonNegative(Step)) {
+ // If Start and Step do not have the same sign, either the multiply or
+ // the add in Start + (It * Step) may wrap.
+ if (!SE.isKnownNonPositive(Start) || !SE.isKnownNonPositive(Step)) {
+ UseFlags = ScalarEvolution::clearFlags(UseFlags, SCEV::FlagNSW);
+ MulFlags = ScalarEvolution::clearFlags(MulFlags, SCEV::FlagNSW);
+ } else if (!SE.isKnownNonNegative(Coeff)) {
+ // It * Step may wrap signed if It (aka Coeff) is negative.
+ MulFlags = ScalarEvolution::clearFlags(MulFlags, SCEV::FlagNSW);
+ }
+ }
+ }
+
SCEVUse Mul = SE.getMulExpr(Operands[i].getPointer(), Coeff,
- {SCEV::FlagNone, UseFlags});
+ {SCEV::FlagNone, MulFlags});
Result = SE.getAddExpr(Result, Mul, {SCEV::FlagNone, UseFlags});
}
return Result;
@@ -1012,8 +1029,9 @@ SCEVUse SCEVAddRecExpr::getExitValue(ScalarEvolution &SE) const {
// 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::FlagNone);
+ isAffine()
+ ? getNoWrapFlags(SCEV::FlagNUW | SCEV::FlagNSW)
+ : SCEV::FlagNone);
}
//===----------------------------------------------------------------------===//
diff --git a/llvm/test/Analysis/ScalarEvolution/different-loops-recs.ll b/llvm/test/Analysis/ScalarEvolution/different-loops-recs.ll
index 13f3660c2e7826..e56d88c86c2b78 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 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6))<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 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6))<nuw><nsw>)<nuw> LoopDispositions: { %loop1: Computable }
+; CHECK-NEXT: --> {6,+,3}<nuw><nsw><%loop1> U: [6,508) S: [6,508) Exits: (6 + (3 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6))<nuw><nsw>)<nuw><u nsw> 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 + ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6) + %a) LoopDispositions: { %loop1: Computable }
; CHECK-NEXT: %phi2.inc = add i32 %phi2, 2
; CHECK-NEXT: --> {(2 + %b),+,2}<nw><%loop1> U: full-set S: full-set Exits: (2 + (2 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6))<nuw><nsw> + %b) LoopDispositions: { %loop1: Computable }
; CHECK-NEXT: %phi3.inc = add i32 %phi3, 3
-; CHECK-NEXT: --> {9,+,3}<nuw><nsw><%loop1> U: [9,511) S: [9,511) Exits: (9 + (3 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6))<nuw><nsw>)<nuw> LoopDispositions: { %loop1: Computable }
+; CHECK-NEXT: --> {9,+,3}<nuw><nsw><%loop1> U: [9,511) S: [9,511) Exits: (9 + (3 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6))<nuw><nsw>)<nuw><u nsw> LoopDispositions: { %loop1: Computable }
; CHECK-NEXT: %sum1 = add i32 %phi1, %phi2
; CHECK-NEXT: --> {(%a + %b),+,3}<%loop1> U: full-set S: full-set Exits: ((3 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6))<nuw><nsw> + %a + %b) LoopDispositions: { %loop1: Computable }
; CHECK-NEXT: %sum2 = add i32 %sum1, %phi3
@@ -131,17 +131,17 @@ define void @test_01(i32 %a, i32 %b) {
; CHECK-NEXT: %phi5 = phi i32 [ 53, %loop1 ], [ %phi5.inc, %loop2 ]
; CHECK-NEXT: --> {53,+,2}<nuw><nsw><%loop2> U: [53,388) S: [53,388) Exits: (53 + (2 * ((-160 + (-6 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6)) + (-2 * %a) + (-2 * %b) + (1000 umax (165 + (2 * %a) + (2 * %b) + (6 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6))<nuw>))) /u 6))<nuw><nsw>)<nuw><nsw> LoopDispositions: { %loop2: Computable }
; CHECK-NEXT: %phi6 = phi i32 [ 43, %loop1 ], [ %phi6.inc, %loop2 ]
-; CHECK-NEXT: --> {43,+,3}<nuw><nsw><%loop2> U: [43,545) S: [43,545) Exits: (43 + (3 * ((-160 + (-6 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6)) + (-2 * %a) + (-2 * %b) + (1000 umax (165 + (2 * %a) + (2 * %b) + (6 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6))<nuw>))) /u 6))<nuw><nsw>)<nuw> LoopDispositions: { %loop2: Computable }
+; CHECK-NEXT: --> {43,+,3}<nuw><nsw><%loop2> U: [43,545) S: [43,545) Exits: (43 + (3 * ((-160 + (-6 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6)) + (-2 * %a) + (-2 * %b) + (1000 umax (165 + (2 * %a) + (2 * %b) + (6 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6))<nuw>))) /u 6))<nuw><nsw>)<nuw><u nsw> LoopDispositions: { %loop2: Computable }
; CHECK-NEXT: %phi4.inc = add i32 %phi4, 1
; CHECK-NEXT: --> {64,+,1}<nuw><nsw><%loop2> U: [64,232) S: [64,232) Exits: (64 + ((-160 + (-6 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6)) + (-2 * %a) + (-2 * %b) + (1000 umax (165 + (2 * %a) + (2 * %b) + (6 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6))<nuw>))) /u 6))<nuw><nsw> LoopDispositions: { %loop2: Computable }
; CHECK-NEXT: %phi5.inc = add i32 %phi5, 2
; CHECK-NEXT: --> {55,+,2}<nuw><nsw><%loop2> U: [55,390) S: [55,390) Exits: (55 + (2 * ((-160 + (-6 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6)) + (-2 * %a) + (-2 * %b) + (1000 umax (165 + (2 * %a) + (2 * %b) + (6 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6))<nuw>))) /u 6))<nuw><nsw>)<nuw><nsw> LoopDispositions: { %loop2: Computable }
; CHECK-NEXT: %phi6.inc = add i32 %phi6, 3
-; CHECK-NEXT: --> {46,+,3}<nuw><nsw><%loop2> U: [46,548) S: [46,548) Exits: (46 + (3 * ((-160 + (-6 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6)) + (-2 * %a) + (-2 * %b) + (1000 umax (165 + (2 * %a) + (2 * %b) + (6 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6))<nuw>))) /u 6))<nuw><nsw>)<nuw> LoopDispositions: { %loop2: Computable }
+; CHECK-NEXT: --> {46,+,3}<nuw><nsw><%loop2> U: [46,548) S: [46,548) Exits: (46 + (3 * ((-160 + (-6 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6)) + (-2 * %a) + (-2 * %b) + (1000 umax (165 + (2 * %a) + (2 * %b) + (6 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6))<nuw>))) /u 6))<nuw><nsw>)<nuw><u nsw> LoopDispositions: { %loop2: Computable }
; CHECK-NEXT: %sum3 = add i32 %phi4, %phi5
-; CHECK-NEXT: --> {116,+,3}<%loop2> U: [116,618) S: [116,618) Exits: (116 + (3 * ((-160 + (-6 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6)) + (-2 * %a) + (-2 * %b) + (1000 umax (165 + (2 * %a) + (2 * %b) + (6 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6))<nuw>))) /u 6))<nuw><nsw>)<nuw> LoopDispositions: { %loop2: Computable }
+; CHECK-NEXT: --> {116,+,3}<%loop2> U: [116,618) S: [116,618) Exits: (116 + (3 * ((-160 + (-6 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6)) + (-2 * %a) + (-2 * %b) + (1000 umax (165 + (2 * %a) + (2 * %b) + (6 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6))<nuw>))) /u 6))<nuw><nsw>)<nuw><u nsw> LoopDispositions: { %loop2: Computable }
; CHECK-NEXT: %sum4 = add i32 %sum3, %phi6
-; CHECK-NEXT: --> {159,+,6}<%loop2> U: [159,1162) S: [159,1162) Exits: (159 + (6 * ((-160 + (-6 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6)) + (-2 * %a) + (-2 * %b) + (1000 umax (165 + (2 * %a) + (2 * %b) + (6 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6))<nuw>))) /u 6))<nuw>)<u nuw> LoopDispositions: { %loop2: Computable }
+; CHECK-NEXT: --> {159,+,6}<%loop2> U: [159,1162) S: [159,1162) Exits: (159 + (6 * ((-160 + (-6 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6)) + (-2 * %a) + (-2 * %b) + (1000 umax (165 + (2 * %a) + (2 * %b) + (6 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6))<nuw>))) /u 6))<nuw><u nsw>)<u nuw><u nsw> LoopDispositions: { %loop2: Computable }
; CHECK-NEXT: %is2 = add i32 %sum4, %b
; CHECK-NEXT: --> {(159 + %b),+,6}<nw><%loop2> U: full-set S: full-set Exits: (159 + (6 * ((-160 + (-6 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6)) + (-2 * %a) + (-2 * %b) + (1000 umax (165 + (2 * %a) + (2 * %b) + (6 * ((-1 + (-2 * %a) + (-1 * %b) + (1000 umax (6 + (2 * %a) + %b))) /u 6))<nuw>))) /u 6))<nuw> + %b) LoopDispositions: { %loop2: Computable }
; CHECK-NEXT: %ec2 = add i32 %is1, %is2
diff --git a/llvm/test/Analysis/ScalarEvolution/exit-value-nowrap-flags.ll b/llvm/test/Analysis/ScalarEvolution/exit-value-nowrap-flags.ll
index bce3e717a7f47e..2ff163e67be354 100644
--- a/llvm/test/Analysis/ScalarEvolution/exit-value-nowrap-flags.ll
+++ b/llvm/test/Analysis/ScalarEvolution/exit-value-nowrap-flags.ll
@@ -148,7 +148,7 @@ define void @exit_value_nsw_nonneg(i64 %start.raw, i64 %step.raw) {
; CHECK-NEXT: %step = and i64 %step.raw, 7
; CHECK-NEXT: --> (zext i3 (trunc i64 %step.raw to i3) to i64) U: [0,8) S: [0,8)
; CHECK-NEXT: %x = phi i64 [ %start, %entry ], [ %x.next, %up ]
-; CHECK-NEXT: --> {(zext i8 (trunc i64 %start.raw to i8) to i64),+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nuw><nsw><%up> U: [0,319) S: [0,319) Exits: ((zext i8 (trunc i64 %start.raw to i8) to i64) + (9 * (zext i3 (trunc i64 %step.raw to i3) to i64))<nuw><nsw>)<u nuw> LoopDispositions: { %up: Computable }
+; CHECK-NEXT: --> {(zext i8 (trunc i64 %start.raw to i8) to i64),+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nuw><nsw><%up> U: [0,319) S: [0,319) Exits: ((zext i8 (trunc i64 %start.raw to i8) to i64) + (9 * (zext i3 (trunc i64 %step.raw to i3) to i64))<nuw><nsw>)<u nuw><u nsw> LoopDispositions: { %up: Computable }
; CHECK-NEXT: %i = phi i32 [ 0, %entry ], [ %i.next, %up ]
; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%up> U: [0,10) S: [0,10) Exits: 9 LoopDispositions: { %up: Computable }
; CHECK-NEXT: %x.next = add nsw i64 %x, %step
@@ -185,7 +185,7 @@ define void @exit_value_nsw_nonpos(i64 %start.raw, i64 %step.raw) {
; CHECK-NEXT: %step = or i64 %step.raw, -8
; CHECK-NEXT: --> %step U: [-8,0) S: [-8,0)
; CHECK-NEXT: %x = phi i64 [ %start, %entry ], [ %x.next, %up ]
-; CHECK-NEXT: --> {%start,+,%step}<nsw><%up> U: [-328,0) S: [-328,0) Exits: ((9 * %step)<nsw> + %start) LoopDispositions: { %up: Computable }
+; CHECK-NEXT: --> {%start,+,%step}<nsw><%up> U: [-328,0) S: [-328,0) Exits: ((9 * %step)<nsw> + %start)<u nsw> LoopDispositions: { %up: Computable }
; CHECK-NEXT: %i = phi i32 [ 0, %entry ], [ %i.next, %up ]
; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%up> U: [0,10) S: [0,10) Exits: 9 LoopDispositions: { %up: Computable }
; CHECK-NEXT: %x.next = add nsw i64 %x, %step
@@ -252,6 +252,85 @@ exit:
ret void
}
+; Same as @exit_value_nsw_mixed_signs, but with a bit width where the multiply
+; really does overflow: for %step == 63 the recurrence steps through
+; -128, -65, -2, 61 without wrapping, while 3 * 63 = 189 is not representable
+; in i8, so the multiply must not be nsw.
+define void @exit_value_nsw_mixed_signs_mul_overflows(i8 %start.raw, i8 %step.raw) {
+; CHECK-LABEL: 'exit_value_nsw_mixed_signs_mul_overflows'
+; CHECK-NEXT: Classifying expressions for: @exit_value_nsw_mixed_signs_mul_overflows
+; CHECK-NEXT: %start = or i8 %start.raw, -128
+; CHECK-NEXT: --> %start U: [-128,0) S: [-128,0)
+; CHECK-NEXT: %step = and i8 %step.raw, 63
+; CHECK-NEXT: --> (zext i6 (trunc i8 %step.raw to i6) to i8) U: [0,64) S: [0,64)
+; CHECK-NEXT: %x = phi i8 [ %start, %entry ], [ %x.next, %up ]
+; CHECK-NEXT: --> {%start,+,(zext i6 (trunc i8 %step.raw to i6) to i8)}<nsw><%up> U: full-set S: full-set Exits: ((3 * (zext i6 (trunc i8 %step.raw to i6) to i8))<nuw> + %start) LoopDispositions: { %up: Computable }
+; CHECK-NEXT: %i = phi i8 [ 0, %entry ], [ %i.next, %up ]
+; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%up> U: [0,4) S: [0,4) Exits: 3 LoopDispositions: { %up: Computable }
+; CHECK-NEXT: %x.next = add nsw i8 %x, %step
+; CHECK-NEXT: --> {((zext i6 (trunc i8 %step.raw to i6) to i8) + %start),+,(zext i6 (trunc i8 %step.raw to i6) to i8)}<nw><%up> U: full-set S: full-set Exits: ((4 * (zext i6 (trunc i8 %step.raw to i6) to i8))<nuw> + %start) LoopDispositions: { %up: Computable }
+; CHECK-NEXT: %i.next = add i8 %i, 1
+; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%up> U: [1,5) S: [1,5) Exits: 4 LoopDispositions: { %up: Computable }
+; CHECK-NEXT: Determining loop execution counts for: @exit_value_nsw_mixed_signs_mul_overflows
+; CHECK-NEXT: Loop %up: backedge-taken count is i8 3
+; CHECK-NEXT: Loop %up: constant max backedge-taken count is i8 3
+; CHECK-NEXT: Loop %up: symbolic max backedge-taken count is i8 3
+; CHECK-NEXT: Loop %up: Trip multiple is 4
+;
+entry:
+ %start = or i8 %start.raw, -128
+ %step = and i8 %step.raw, 63
+ br label %up
+up:
+ %x = phi i8 [ %start, %entry ], [ %x.next, %up ]
+ %i = phi i8 [ 0, %entry ], [ %i.next, %up ]
+ %x.next = add nsw i8 %x, %step
+ %i.next = add i8 %i, 1
+ %c = icmp ult i8 %i.next, 4
+ br i1 %c, label %up, label %exit
+exit:
+ ret void
+}
+
+; Both %start and %step are non-negative and the count is a non-negative
+; constant, so the multiply keeps nsw even though its operands' ranges alone do
+; not rule out an overflow.
+define void @exit_value_nsw_nonneg_wide_ranges(i32 %start.raw, i32 %step.raw) {
+; CHECK-LABEL: 'exit_value_nsw_nonneg_wide_ranges'
+; CHECK-NEXT: Classifying expressions for: @exit_value_nsw_nonneg_wide_ranges
+; CHECK-NEXT: %start = and i32 %start.raw, 2147483647
+; CHECK-NEXT: --> (zext i31 (trunc i32 %start.raw to i31) to i32) U: [0,-2147483648) S: [0,-2147483648)
+; CHECK-NEXT: %step = and i32 %step.raw, 2147483647
+; CHECK-NEXT: --> (zext i31 (trunc i32 %step.raw to i31) to i32) U: [0,-2147483648) S: [0,-2147483648)
+; CHECK-NEXT: %x = phi i32 [ %start, %entry ], [ %x.next, %up ]
+; CHECK-NEXT: --> {(zext i31 (trunc i32 %start.raw to i31) to i32),+,(zext i31 (trunc i32 %step.raw to i31) to i32)}<nuw><nsw><%up> U: [0,-2147483648) S: [0,-2147483648) Exits: ((zext i31 (trunc i32 %start.raw to i31) to i32) + (9 * (zext i31 (trunc i32 %step.raw to i31) to i32))<u nuw><u nsw>)<u nuw><u nsw> LoopDispositions: { %up: Computable }
+; CHECK-NEXT: %i = phi i32 [ 0, %entry ], [ %i.next, %up ]
+; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%up> U: [0,10) S: [0,10) Exits: 9 LoopDispositions: { %up: Computable }
+; CHECK-NEXT: %x.next = add nsw i32 %x, %step
+; CHECK-NEXT: --> {((zext i31 (trunc i32 %step.raw to i31) to i32) + (zext i31 (trunc i32 %start.raw to i31) to i32)),+,(zext i31 (trunc i32 %step.raw to i31) to i32)}<nw><%up> U: full-set S: full-set Exits: ((zext i31 (trunc i32 %start.raw to i31) to i32) + (10 * (zext i31 (trunc i32 %step.raw to i31) to i32))) LoopDispositions: { %up: Computable }
+; CHECK-NEXT: %i.next = add i32 %i, 1
+; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%up> U: [1,11) S: [1,11) Exits: 10 LoopDispositions: { %up: Computable }
+; CHECK-NEXT: Determining loop execution counts for: @exit_value_nsw_nonneg_wide_ranges
+; CHECK-NEXT: Loop %up: backedge-taken count is i32 9
+; CHECK-NEXT: Loop %up: constant max backedge-taken count is i32 9
+; CHECK-NEXT: Loop %up: symbolic max backedge-taken count is i32 9
+; CHECK-NEXT: Loop %up: Trip multiple is 10
+;
+entry:
+ %start = and i32 %start.raw, 2147483647
+ %step = and i32 %step.raw, 2147483647
+ br label %up
+up:
+ %x = phi i32 [ %start, %entry ], [ %x.next, %up ]
+ %i = phi i32 [ 0, %entry ], [ %i.next, %up ]
+ %x.next = add nsw i32 %x, %step
+ %i.next = add i32 %i, 1
+ %c = icmp ult i32 %i.next, 10
+ br i1 %c, label %up, label %exit
+exit:
+ ret void
+}
+
define void @exit_value_nsw_count_is_smin(i8 %t) {
; CHECK-LABEL: 'exit_value_nsw_count_is_smin'
; CHECK-NEXT: Classifying expressions for: @exit_value_nsw_count_is_smin
diff --git a/llvm/test/Analysis/ScalarEvolution/increasing-or-decreasing-iv.ll b/llvm/test/Analysis/ScalarEvolution/increasing-or-decreasing-iv.ll
index 7170645ccc659a..ef16438d21ede1 100644
--- a/llvm/test/Analysis/ScalarEvolution/increasing-or-decreasing-iv.ll
+++ b/llvm/test/Analysis/ScalarEvolution/increasing-or-decreasing-iv.ll
@@ -177,7 +177,7 @@ define void @f3(i1 %c) {
; CHECK-NEXT: %iv = phi i16 [ %start, %entry ], [ %iv.next, %loop ]
; CHECK-NEXT: --> {%start,+,%step}<%loop> U: [0,-892) S: [0,-892) Exits: ((127 * %step)<nuw> + %start) LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %iv.zext = zext i16 %iv to i64
-; CHECK-NEXT: --> {(zext i16 %start to i64),+,(zext i16 %step to i64)}<nuw><%loop> U: [0,64644) S: [0,64644) Exits: ((zext i16 %start to i64) + (127 * (zext i16 %step to i64))<nuw><nsw>)<u nuw> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: --> {(zext i16 %start to i64),+,(zext i16 %step to i64)}<nuw><%loop> U: [0,64644) S: [0,64644) Exits: ((zext i16 %start to i64) + (127 * (zext i16 %step to i64))<nuw><nsw>)<u nuw><u nsw> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %iv.next = add i16 %iv, %step
; CHECK-NEXT: --> {(%step + %start),+,%step}<nw><%loop> U: full-set S: full-set Exits: ((128 * %step)<nuw> + %start) LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %loop.iv.inc = add i16 %loop.iv, 1
diff --git a/llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info-operand-order.ll b/llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info-operand-order.ll
index ff5a0cab28dcde..e8fb4069b37122 100644
--- a/llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info-operand-order.ll
+++ b/llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info-operand-order.ll
@@ -9,7 +9,7 @@ define void @test_multiple_const_guards_order1(ptr nocapture %a, i64 %i) {
; CHECK-NEXT: %idx = getelementptr inbounds i32, ptr %a, i64 %iv
; CHECK-NEXT: --> {%a,+,4}<nuw><%loop> U: full-set S: full-set Exits: ((4 * %i)<u nuw> + %a)<u nuw> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %iv.next = add nuw nsw i64 %iv, 1
-; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,11) S: [1,11) Exits: (1 + %i)<u nuw> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,11) S: [1,11) Exits: (1 + %i)<u nuw><u nsw> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: Determining loop execution counts for: @test_multiple_const_guards_order1
; CHECK-NEXT: Loop %loop: backedge-taken count is %i
; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i64 9
@@ -44,7 +44,7 @@ define void @test_multiple_const_guards_order2(ptr nocapture %a, i64 %i) {
; CHECK-NEXT: %idx = getelementptr inbounds i32, ptr %a, i64 %iv
; CHECK-NEXT: --> {%a,+,4}<nuw><%loop> U: full-set S: full-set Exits: ((4 * %i)<u nuw> + %a)<u nuw> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %iv.next = add nuw nsw i64 %iv, 1
-; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,11) S: [1,11) Exits: (1 + %i)<u nuw> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,11) S: [1,11) Exits: (1 + %i)<u nuw><u nsw> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: Determining loop execution counts for: @test_multiple_const_guards_order2
; CHECK-NEXT: Loop %loop: backedge-taken count is %i
; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i64 9
@@ -79,7 +79,7 @@ define void @test_multiple_var_guards_order1(ptr nocapture %a, i64 %i, i64 %N) {
; CHECK-NEXT: %idx = getelementptr inbounds i32, ptr %a, i64 %iv
; CHECK-NEXT: --> {%a,+,4}<nuw><%loop> U: full-set S: full-set Exits: ((4 * %i)<u nuw> + %a)<u nuw> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %iv.next = add nuw nsw i64 %iv, 1
-; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,12) S: [1,12) Exits: (1 + %i)<u nuw> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,12) S: [1,12) Exits: (1 + %i)<u nuw><u nsw> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: Determining loop execution counts for: @test_multiple_var_guards_order1
; CHECK-NEXT: Loop %loop: backedge-taken count is %i
; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i64 10
@@ -114,7 +114,7 @@ define void @test_multiple_var_guards_order2(ptr nocapture %a, i64 %i, i64 %N) {
; CHECK-NEXT: %idx = getelementptr inbounds i32, ptr %a, i64 %iv
; CHECK-NEXT: --> {%a,+,4}<nuw><%loop> U: full-set S: full-set Exits: ((4 * %i)<u nuw> + %a)<u nuw> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %iv.next = add nuw nsw i64 %iv, 1
-; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,12) S: [1,12) Exits: (1 + %i)<u nuw> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,12) S: [1,12) Exits: (1 + %i)<u nuw><u nsw> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: Determining loop execution counts for: @test_multiple_var_guards_order2
; CHECK-NEXT: Loop %loop: backedge-taken count is %i
; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i64 10
@@ -147,7 +147,7 @@ define i32 @sle_sgt_ult_umax_to_smax(i32 %num) {
; CHECK-NEXT: %iv = phi i32 [ 0, %guard.3 ], [ %iv.next, %loop ]
; CHECK-NEXT: --> {0,+,4}<nuw><nsw><%loop> U: [0,25) S: [0,25) Exits: (4 * ((-4 + %num) /u 4))<nuw> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %iv.next = add nuw i32 %iv, 4
-; CHECK-NEXT: --> {4,+,4}<nuw><nsw><%loop> U: [4,29) S: [4,29) Exits: (4 + (4 * ((-4 + %num) /u 4))<nuw>)<u nuw> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: --> {4,+,4}<nuw><nsw><%loop> U: [4,29) S: [4,29) Exits: (4 + (4 * ((-4 + %num) /u 4))<nuw><u nsw>)<u nuw><u nsw> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: Determining loop execution counts for: @sle_sgt_ult_umax_to_smax
; CHECK-NEXT: Loop %loop: backedge-taken count is ((-4 + %num) /u 4)
; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i32 6
@@ -257,7 +257,7 @@ define void @const_max_btc_32_or_order_2(i64 %n) {
; CHECK-NEXT: %iv = phi i64 [ %iv.next, %loop ], [ 0, %ph ]
; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%loop> U: [0,33) S: [0,33) Exits: %n LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %iv.next = add i64 %iv, 1
-; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,34) S: [1,34) Exits: (1 + %n)<u nuw> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,34) S: [1,34) Exits: (1 + %n)<u nuw><u nsw> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: Determining loop execution counts for: @const_max_btc_32_or_order_2
; CHECK-NEXT: Loop %loop: backedge-taken count is %n
; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i64 32
diff --git a/llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info.ll b/llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info.ll
index fbc4c8aa5645dc..fd9751af3d03fc 100644
--- a/llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info.ll
+++ b/llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info.ll
@@ -135,7 +135,7 @@ define void @test_guard_eq_12(ptr nocapture %a, i64 %N) {
; CHECK-NEXT: %idx = getelementptr inbounds i32, ptr %a, i64 %iv
; CHECK-NEXT: --> {%a,+,4}<nuw><%loop> U: full-set S: full-set Exits: ((4 * %N)<u nuw> + %a)<u nuw> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %iv.next = add nuw nsw i64 %iv, 1
-; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,14) S: [1,14) Exits: (1 + %N)<u nuw> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,14) S: [1,14) Exits: (1 + %N)<u nuw><u nsw> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: Determining loop execution counts for: @test_guard_eq_12
; CHECK-NEXT: Loop %loop: backedge-taken count is %N
; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i64 12
@@ -166,7 +166,7 @@ define void @test_guard_ule_12(ptr nocapture %a, i64 %N) {
; CHECK-NEXT: %idx = getelementptr inbounds i32, ptr %a, i64 %iv
; CHECK-NEXT: --> {%a,+,4}<nuw><%loop> U: full-set S: full-set Exits: ((4 * %N)<u nuw> + %a)<u nuw> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %iv.next = add nuw nsw i64 %iv, 1
-; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,14) S: [1,14) Exits: (1 + %N)<u nuw> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,14) S: [1,14) Exits: (1 + %N)<u nuw><u nsw> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: Determining loop execution counts for: @test_guard_ule_12
; CHECK-NEXT: Loop %loop: backedge-taken count is %N
; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i64 12
@@ -197,7 +197,7 @@ define void @test_guard_ule_12_step2(ptr nocapture %a, i64 %N) {
; CHECK-NEXT: %idx = getelementptr inbounds i32, ptr %a, i64 %iv
; CHECK-NEXT: --> {%a,+,8}<nuw><%loop> U: full-set S: full-set Exits: ((8 * (%N /u 2))<u nuw> + %a)<u nuw> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %iv.next = add nuw nsw i64 %iv, 2
-; CHECK-NEXT: --> {2,+,2}<nuw><nsw><%loop> U: [2,15) S: [2,15) Exits: (2 + (2 * (%N /u 2))<nuw>)<u nuw> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: --> {2,+,2}<nuw><nsw><%loop> U: [2,15) S: [2,15) Exits: (2 + (2 * (%N /u 2))<nuw><u nsw>)<u nuw><u nsw> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: Determining loop execution counts for: @test_guard_ule_12_step2
; CHECK-NEXT: Loop %loop: backedge-taken count is (%N /u 2)
; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i64 6
@@ -738,7 +738,7 @@ define void @guard_pessimizes_analysis_step2(i1 %c, i32 %N) {
; CHECK-NEXT: %init = phi i32 [ 2, %entry ], [ 3, %bb1 ]
; CHECK-NEXT: --> %init U: [2,4) S: [2,4)
; CHECK-NEXT: %iv = phi i32 [ %iv.next, %loop ], [ %init, %loop.ph ]
-; CHECK-NEXT: --> {%init,+,2}<nuw><nsw><%loop> U: [2,10) S: [2,10) Exits: ((2 * ((8 + (-1 * %init)<nsw>)<nsw> /u 2))<nuw><nsw> + %init)<u nuw> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: --> {%init,+,2}<nuw><nsw><%loop> U: [2,10) S: [2,10) Exits: ((2 * ((8 + (-1 * %init)<nsw>)<nsw> /u 2))<nuw><nsw> + %init)<u nuw><u nsw> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %iv.next = add nuw nsw i32 %iv, 2
; CHECK-NEXT: --> {(2 + %init)<nuw><nsw>,+,2}<nuw><nsw><%loop> U: [4,12) S: [4,12) Exits: (2 + (2 * ((8 + (-1 * %init)<nsw>)<nsw> /u 2))<nuw><nsw> + %init) LoopDispositions: { %loop: Computable }
; CHECK-NEXT: Determining loop execution counts for: @guard_pessimizes_analysis_step2
@@ -2051,7 +2051,7 @@ define void @guard_on_ptrtoaddr(ptr %p) {
; CHECK-NEXT: %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%loop> U: [0,1001) S: [0,1001) Exits: (ptrtoaddr ptr %p to i64) LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %iv.next = add i64 %iv, 1
-; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,1002) S: [1,1002) Exits: (1 + (ptrtoaddr ptr %p to i64))<u nuw> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,1002) S: [1,1002) Exits: (1 + (ptrtoaddr ptr %p to i64))<u nuw><u nsw> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: Determining loop execution counts for: @guard_on_ptrtoaddr
; CHECK-NEXT: Loop %loop: backedge-taken count is (ptrtoaddr ptr %p to i64)
; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i64 1000
diff --git a/llvm/test/Analysis/ScalarEvolution/max-be-count-not-constant.ll b/llvm/test/Analysis/ScalarEvolution/max-be-count-not-constant.ll
index 7fe767612271e1..ee9888cf78e482 100644
--- a/llvm/test/Analysis/ScalarEvolution/max-be-count-not-constant.ll
+++ b/llvm/test/Analysis/ScalarEvolution/max-be-count-not-constant.ll
@@ -18,7 +18,7 @@ define void @pluto(i32 %arg) {
; CHECK-NEXT: %tmp3 = phi i32 [ 0, %bb ], [ %tmp4, %bb2 ]
; CHECK-NEXT: --> {0,+,(2 + %tmp)<nsw>}<nuw><nsw><%bb2> U: [0,3) S: [0,3) Exits: ((2 + %tmp)<nsw> * (1 /u (2 + %tmp)<nsw>))<nuw> LoopDispositions: { %bb2: Computable }
; CHECK-NEXT: %tmp4 = add nuw nsw i32 %tmp1, %tmp3
-; CHECK-NEXT: --> {(2 + %tmp)<nsw>,+,(2 + %tmp)<nsw>}<nuw><nsw><%bb2> U: [1,5) S: [1,5) Exits: (2 + ((2 + %tmp)<nsw> * (1 /u (2 + %tmp)<nsw>))<nuw> + %tmp) LoopDispositions: { %bb2: Computable }
+; CHECK-NEXT: --> {(2 + %tmp)<nsw>,+,(2 + %tmp)<nsw>}<nuw><nsw><%bb2> U: [1,5) S: [1,5) Exits: (2 + ((2 + %tmp)<nsw> * (1 /u (2 + %tmp)<nsw>))<nuw><u nsw> + %tmp) LoopDispositions: { %bb2: Computable }
; CHECK-NEXT: Determining loop execution counts for: @pluto
; CHECK-NEXT: Loop %bb2: backedge-taken count is (1 /u (2 + %tmp)<nsw>)
; CHECK-NEXT: Loop %bb2: constant max backedge-taken count is i32 1
diff --git a/llvm/test/Analysis/ScalarEvolution/nsw-offset-assume.ll b/llvm/test/Analysis/ScalarEvolution/nsw-offset-assume.ll
index 81e2c0008e7584..c46104644cd162 100644
--- a/llvm/test/Analysis/ScalarEvolution/nsw-offset-assume.ll
+++ b/llvm/test/Analysis/ScalarEvolution/nsw-offset-assume.ll
@@ -26,13 +26,13 @@ define void @foo(i32 %no, ptr nocapture %d, ptr nocapture %q) nounwind {
; CHECK-NEXT: %5 = getelementptr inbounds double, ptr %q, i64 %4
; CHECK-NEXT: --> {%q,+,16}<nuw><%bb> U: full-set S: full-set Exits: ((16 * ((1 + (zext i32 (-2 + (2 * (%no /u 2))<nuw>) to i64))<nuw><nsw> /u 2))<nuw><nsw> + %q)<u nuw> LoopDispositions: { %bb: Computable }
; CHECK-NEXT: %7 = or disjoint i32 %i.01, 1
-; CHECK-NEXT: --> {1,+,2}<nuw><nsw><%bb> U: [1,2147483646) S: [1,2147483646) Exits: (1 + (2 * ((-1 + (2 * (%no /u 2))<nuw>) /u 2))<nuw>)<nuw><nsw> LoopDispositions: { %bb: Computable }
+; CHECK-NEXT: --> {1,+,2}<nuw><nsw><%bb> U: [1,2147483646) S: [1,2147483646) Exits: (1 + (2 * ((-1 + (2 * (%no /u 2))<nuw>) /u 2))<nuw><u nsw>)<nuw><nsw> LoopDispositions: { %bb: Computable }
; CHECK-NEXT: %8 = sext i32 %7 to i64
; CHECK-NEXT: --> {1,+,2}<nuw><nsw><%bb> U: [1,2147483646) S: [1,2147483646) Exits: (1 + (2 * ((1 + (zext i32 (-2 + (2 * (%no /u 2))<nuw>) to i64))<nuw><nsw> /u 2))<nuw><nsw>)<nuw><nsw> LoopDispositions: { %bb: Computable }
; CHECK-NEXT: %9 = getelementptr inbounds double, ptr %q, i64 %8
; CHECK-NEXT: --> {(8 + %q),+,16}<nuw><%bb> U: full-set S: full-set Exits: (8 + (16 * ((1 + (zext i32 (-2 + (2 * (%no /u 2))<nuw>) to i64))<nuw><nsw> /u 2))<nuw><nsw> + %q) LoopDispositions: { %bb: Computable }
; CHECK-NEXT: %t7 = add nsw i32 %i.01, 1
-; CHECK-NEXT: --> {1,+,2}<nuw><nsw><%bb> U: [1,2147483646) S: [1,2147483646) Exits: (1 + (2 * ((-1 + (2 * (%no /u 2))<nuw>) /u 2))<nuw>)<nuw><nsw> LoopDispositions: { %bb: Computable }
+; CHECK-NEXT: --> {1,+,2}<nuw><nsw><%bb> U: [1,2147483646) S: [1,2147483646) Exits: (1 + (2 * ((-1 + (2 * (%no /u 2))<nuw>) /u 2))<nuw><u nsw>)<nuw><nsw> LoopDispositions: { %bb: Computable }
; CHECK-NEXT: %t8 = sext i32 %t7 to i64
; CHECK-NEXT: --> {1,+,2}<nuw><nsw><%bb> U: [1,2147483646) S: [1,2147483646) Exits: (1 + (2 * ((1 + (zext i32 (-2 + (2 * (%no /u 2))<nuw>) to i64))<nuw><nsw> /u 2))<nuw><nsw>)<nuw><nsw> LoopDispositions: { %bb: Computable }
; CHECK-NEXT: %t9 = getelementptr inbounds double, ptr %q, i64 %t8
@@ -42,7 +42,7 @@ define void @foo(i32 %no, ptr nocapture %d, ptr nocapture %q) nounwind {
; CHECK-NEXT: %15 = getelementptr inbounds double, ptr %d, i64 %14
; CHECK-NEXT: --> {%d,+,16}<nuw><%bb> U: full-set S: full-set Exits: ((16 * ((1 + (zext i32 (-2 + (2 * (%no /u 2))<nuw>) to i64))<nuw><nsw> /u 2))<nuw><nsw> + %d)<u nuw> LoopDispositions: { %bb: Computable }
; CHECK-NEXT: %16 = add nsw i32 %i.01, 2
-; CHECK-NEXT: --> {2,+,2}<nuw><nsw><%bb> U: [2,2147483647) S: [2,2147483647) Exits: (2 + (2 * ((-1 + (2 * (%no /u 2))<nuw>) /u 2))<nuw>)<u nuw> LoopDispositions: { %bb: Computable }
+; CHECK-NEXT: --> {2,+,2}<nuw><nsw><%bb> U: [2,2147483647) S: [2,2147483647) Exits: (2 + (2 * ((-1 + (2 * (%no /u 2))<nuw>) /u 2))<nuw><u nsw>)<u nuw><u nsw> LoopDispositions: { %bb: Computable }
; CHECK-NEXT: Determining loop execution counts for: @foo
; CHECK-NEXT: Loop %bb: backedge-taken count is ((-1 + (2 * (%no /u 2))<nuw>) /u 2)
; CHECK-NEXT: Loop %bb: constant max backedge-taken count is i32 1073741822
diff --git a/llvm/test/Analysis/ScalarEvolution/nsw-offset.ll b/llvm/test/Analysis/ScalarEvolution/nsw-offset.ll
index 9f3d7a28328f8a..b01fd6d2ed3623 100644
--- a/llvm/test/Analysis/ScalarEvolution/nsw-offset.ll
+++ b/llvm/test/Analysis/ScalarEvolution/nsw-offset.ll
@@ -23,13 +23,13 @@ define void @foo(i32 %no, ptr nocapture %d, ptr nocapture %q) nounwind {
; CHECK-NEXT: %5 = getelementptr inbounds double, ptr %q, i64 %4
; CHECK-NEXT: --> {%q,+,16}<nuw><%bb> U: full-set S: full-set Exits: ((16 * ((1 + (zext i32 (-2 + (2 * (%no /u 2))<nuw>) to i64))<nuw><nsw> /u 2))<nuw><nsw> + %q)<u nuw> LoopDispositions: { %bb: Computable }
; CHECK-NEXT: %7 = or disjoint i32 %i.01, 1
-; CHECK-NEXT: --> {1,+,2}<nuw><nsw><%bb> U: [1,2147483646) S: [1,2147483646) Exits: (1 + (2 * ((-1 + (2 * (%no /u 2))<nuw>) /u 2))<nuw>)<nuw><nsw> LoopDispositions: { %bb: Computable }
+; CHECK-NEXT: --> {1,+,2}<nuw><nsw><%bb> U: [1,2147483646) S: [1,2147483646) Exits: (1 + (2 * ((-1 + (2 * (%no /u 2))<nuw>) /u 2))<nuw><u nsw>)<nuw><nsw> LoopDispositions: { %bb: Computable }
; CHECK-NEXT: %8 = sext i32 %7 to i64
; CHECK-NEXT: --> {1,+,2}<nuw><nsw><%bb> U: [1,2147483646) S: [1,2147483646) Exits: (1 + (2 * ((1 + (zext i32 (-2 + (2 * (%no /u 2))<nuw>) to i64))<nuw><nsw> /u 2))<nuw><nsw>)<nuw><nsw> LoopDispositions: { %bb: Computable }
; CHECK-NEXT: %9 = getelementptr inbounds double, ptr %q, i64 %8
; CHECK-NEXT: --> {(8 + %q),+,16}<nuw><%bb> U: full-set S: full-set Exits: (8 + (16 * ((1 + (zext i32 (-2 + (2 * (%no /u 2))<nuw>) to i64))<nuw><nsw> /u 2))<nuw><nsw> + %q) LoopDispositions: { %bb: Computable }
; CHECK-NEXT: %t7 = add nsw i32 %i.01, 1
-; CHECK-NEXT: --> {1,+,2}<nuw><nsw><%bb> U: [1,2147483646) S: [1,2147483646) Exits: (1 + (2 * ((-1 + (2 * (%no /u 2))<nuw>) /u 2))<nuw>)<nuw><nsw> LoopDispositions: { %bb: Computable }
+; CHECK-NEXT: --> {1,+,2}<nuw><nsw><%bb> U: [1,2147483646) S: [1,2147483646) Exits: (1 + (2 * ((-1 + (2 * (%no /u 2))<nuw>) /u 2))<nuw><u nsw>)<nuw><nsw> LoopDispositions: { %bb: Computable }
; CHECK-NEXT: %t8 = sext i32 %t7 to i64
; CHECK-NEXT: --> {1,+,2}<nuw><nsw><%bb> U: [1,2147483646) S: [1,2147483646) Exits: (1 + (2 * ((1 + (zext i32 (-2 + (2 * (%no /u 2))<nuw>) to i64))<nuw><nsw> /u 2))<nuw><nsw>)<nuw><nsw> LoopDispositions: { %bb: Computable }
; CHECK-NEXT: %t9 = getelementptr inbounds double, ptr %q, i64 %t8
@@ -39,7 +39,7 @@ define void @foo(i32 %no, ptr nocapture %d, ptr nocapture %q) nounwind {
; CHECK-NEXT: %15 = getelementptr inbounds double, ptr %d, i64 %14
; CHECK-NEXT: --> {%d,+,16}<nuw><%bb> U: full-set S: full-set Exits: ((16 * ((1 + (zext i32 (-2 + (2 * (%no /u 2))<nuw>) to i64))<nuw><nsw> /u 2))<nuw><nsw> + %d)<u nuw> LoopDispositions: { %bb: Computable }
; CHECK-NEXT: %16 = add nsw i32 %i.01, 2
-; CHECK-NEXT: --> {2,+,2}<nuw><nsw><%bb> U: [2,2147483647) S: [2,2147483647) Exits: (2 + (2 * ((-1 + (2 * (%no /u 2))<nuw>) /u 2))<nuw>)<u nuw> LoopDispositions: { %bb: Computable }
+; CHECK-NEXT: --> {2,+,2}<nuw><nsw><%bb> U: [2,2147483647) S: [2,2147483647) Exits: (2 + (2 * ((-1 + (2 * (%no /u 2))<nuw>) /u 2))<nuw><u nsw>)<u nuw><u nsw> LoopDispositions: { %bb: Computable }
; CHECK-NEXT: Determining loop execution counts for: @foo
; CHECK-NEXT: Loop %bb: backedge-taken count is ((-1 + (2 * (%no /u 2))<nuw>) /u 2)
; CHECK-NEXT: Loop %bb: constant max backedge-taken count is i32 1073741822
diff --git a/llvm/test/Analysis/ScalarEvolution/pr92560.ll b/llvm/test/Analysis/ScalarEvolution/pr92560.ll
index bf1feec555af99..2695d5b66e9352 100644
--- a/llvm/test/Analysis/ScalarEvolution/pr92560.ll
+++ b/llvm/test/Analysis/ScalarEvolution/pr92560.ll
@@ -9,7 +9,7 @@ define dso_local void @simple(i32 noundef %n) local_unnamed_addr {
; CHECK-NEXT: %left.05 = phi i32 [ %inc, %while.body ], [ 0, %entry ]
; CHECK-NEXT: --> {0,+,4}<nuw><nsw><%while.body> U: [0,2147483641) S: [0,2147483641) Exits: (4 * (((-4 + (-1 * (1 umin (-4 + (4 smax (-4 + %n)))<nsw>))<nuw><nsw> + (4 smax (-4 + %n))) /u 8) + (1 umin (-4 + (4 smax (-4 + %n)))<nsw>)))<nuw> LoopDispositions: { %while.body: Computable }
; CHECK-NEXT: %inc = add nuw nsw i32 %left.05, 4
-; CHECK-NEXT: --> {4,+,4}<nuw><nsw><%while.body> U: [4,2147483645) S: [4,2147483645) Exits: (4 + (4 * (((-4 + (-1 * (1 umin (-4 + (4 smax (-4 + %n)))<nsw>))<nuw><nsw> + (4 smax (-4 + %n))) /u 8) + (1 umin (-4 + (4 smax (-4 + %n)))<nsw>)))<nuw>)<nuw> LoopDispositions: { %while.body: Computable }
+; CHECK-NEXT: --> {4,+,4}<nuw><nsw><%while.body> U: [4,2147483645) S: [4,2147483645) Exits: (4 + (4 * (((-4 + (-1 * (1 umin (-4 + (4 smax (-4 + %n)))<nsw>))<nuw><nsw> + (4 smax (-4 + %n))) /u 8) + (1 umin (-4 + (4 smax (-4 + %n)))<nsw>)))<nuw><u nsw>)<nuw><u nsw> LoopDispositions: { %while.body: Computable }
; CHECK-NEXT: %dec = add nsw i32 %right.06, -4
; CHECK-NEXT: --> {(-4 + %n),+,-4}<nsw><%while.body> U: full-set S: full-set Exits: (-4 + (-4 * (((-4 + (-1 * (1 umin (-4 + (4 smax (-4 + %n)))<nsw>))<nuw><nsw> + (4 smax (-4 + %n))) /u 8) + (1 umin (-4 + (4 smax (-4 + %n)))<nsw>)))<nsw> + %n) LoopDispositions: { %while.body: Computable }
; CHECK-NEXT: Determining loop execution counts for: @simple
diff --git a/llvm/test/Transforms/IndVarSimplify/exit-value-nowrap-flags.ll b/llvm/test/Transforms/IndVarSimplify/exit-value-nowrap-flags.ll
index 6bcb5544c09092..12a8cb5e153525 100644
--- a/llvm/test/Transforms/IndVarSimplify/exit-value-nowrap-flags.ll
+++ b/llvm/test/Transforms/IndVarSimplify/exit-value-nowrap-flags.ll
@@ -48,8 +48,8 @@ define i32 @nsw_kept_same_sign(i32 %start.in, i32 %step.in, i32 %n) {
; CHECK: [[LATCH]]:
; CHECK-NEXT: br label %[[LOOP]]
; CHECK: [[EXIT]]:
-; CHECK-NEXT: [[TMP0:%.*]] = mul nuw i32 [[N]], [[STEP]]
-; CHECK-NEXT: [[TMP1:%.*]] = add nuw i32 [[TMP0]], [[START]]
+; CHECK-NEXT: [[TMP0:%.*]] = mul nuw nsw i32 [[N]], [[STEP]]
+; CHECK-NEXT: [[TMP1:%.*]] = add nuw nsw i32 [[TMP0]], [[START]]
; CHECK-NEXT: ret i32 [[TMP1]]
;
entry:
@@ -84,7 +84,7 @@ define i32 @nsw_start_stop_negative(i32 range(i32 -1024, 0) %start, i32 range(i3
; CHECK-NEXT: br label %[[LOOP_HEADER]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[TMP0:%.*]] = mul i32 [[N]], [[STEP]]
-; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[START]], [[TMP0]]
+; CHECK-NEXT: [[TMP1:%.*]] = add nsw i32 [[START]], [[TMP0]]
; CHECK-NEXT: ret i32 [[TMP1]]
;
entry:
@@ -190,8 +190,8 @@ define i32 @nsw_kept_same_sign_const_count(i32 range(i32 0, -2147483648) %start,
; CHECK: [[LATCH]]:
; CHECK-NEXT: br label %[[LOOP]]
; CHECK: [[EXIT]]:
-; CHECK-NEXT: [[TMP0:%.*]] = mul nuw i32 [[STEP]], 10
-; CHECK-NEXT: [[TMP1:%.*]] = add nuw i32 [[START]], [[TMP0]]
+; CHECK-NEXT: [[TMP0:%.*]] = mul nuw nsw i32 [[STEP]], 10
+; CHECK-NEXT: [[TMP1:%.*]] = add nuw nsw i32 [[START]], [[TMP0]]
; CHECK-NEXT: ret i32 [[TMP1]]
;
entry:
diff --git a/llvm/test/Transforms/IndVarSimplify/loop_evaluate_1.ll b/llvm/test/Transforms/IndVarSimplify/loop_evaluate_1.ll
index e496f8f6014c2f..8406eee2d27635 100644
--- a/llvm/test/Transforms/IndVarSimplify/loop_evaluate_1.ll
+++ b/llvm/test/Transforms/IndVarSimplify/loop_evaluate_1.ll
@@ -30,7 +30,7 @@ define i32 @test2(i32 %arg) {
; CHECK-NEXT: [[TMP:%.*]] = icmp ugt i32 [[ARG:%.*]], 10
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[ARG]], -11
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[TMP0]], 1
-; CHECK-NEXT: [[TMP2:%.*]] = add nuw i32 [[TMP1]], 1
+; CHECK-NEXT: [[TMP2:%.*]] = add nuw nsw i32 [[TMP1]], 1
; CHECK-NEXT: [[TMP8:%.*]] = select i1 [[TMP]], i32 [[TMP2]], i32 0
; CHECK-NEXT: ret i32 [[TMP8]]
;
More information about the llvm-commits
mailing list