[llvm] [SCEV] Use AddRec monotonicity in isKnownViaNonRecursiveReasoning. (PR #218280)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Sun Aug 23 12:18:12 PDT 2026


https://github.com/fhahn created https://github.com/llvm/llvm-project/pull/218280

Monotonic AddRecs are never less than their start value; use that in
when reasoning about predicates involving an AddRec and its start value.

Improves results in a few cases on llvm-opt-benchmark-nightly:
https://github.com/dtcxzyw/llvm-opt-benchmark-nightly/pull/996

>From f2e8481281094ba2ae5dcbfb5fb644e498485ed6 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 21 Aug 2026 15:54:58 +0100
Subject: [PATCH 1/2] Precommit test

---
 .../addrec-vs-start-monotonic.ll              | 318 ++++++++++++++++++
 .../addrec-vs-start-monotonic.ll              | 156 +++++++++
 2 files changed, 474 insertions(+)
 create mode 100644 llvm/test/Analysis/ScalarEvolution/addrec-vs-start-monotonic.ll
 create mode 100644 llvm/test/Transforms/IndVarSimplify/addrec-vs-start-monotonic.ll

diff --git a/llvm/test/Analysis/ScalarEvolution/addrec-vs-start-monotonic.ll b/llvm/test/Analysis/ScalarEvolution/addrec-vs-start-monotonic.ll
new file mode 100644
index 0000000000000..46bd202a09985
--- /dev/null
+++ b/llvm/test/Analysis/ScalarEvolution/addrec-vs-start-monotonic.ll
@@ -0,0 +1,318 @@
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -disable-output -passes='print<scalar-evolution>' %s 2>&1 | FileCheck %s
+
+define void @dec_to_start_of_nuw_ptr_addrec(ptr %start, i32 %n) {
+; CHECK-LABEL: 'dec_to_start_of_nuw_ptr_addrec'
+; CHECK-NEXT:  Classifying expressions for: @dec_to_start_of_nuw_ptr_addrec
+; CHECK-NEXT:    %p = phi ptr [ %start, %entry ], [ %p.next, %up.latch ]
+; CHECK-NEXT:    --> {%start,+,1}<nuw><%up.header> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %up.header: Computable }
+; CHECK-NEXT:    %v = phi i32 [ %n, %entry ], [ %v.next, %up.latch ]
+; CHECK-NEXT:    --> %v U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %up.header: Variant }
+; CHECK-NEXT:    %p.next = getelementptr nuw i8, ptr %p, i64 1
+; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%up.header> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %up.header: Computable }
+; CHECK-NEXT:    %v.next = mul i32 %v, 10
+; CHECK-NEXT:    --> (10 * %v) U: [0,-1) S: [-2147483648,2147483647) Exits: <<Unknown>> LoopDispositions: { %up.header: Variant }
+; CHECK-NEXT:    %q = phi ptr [ %p, %up.header ], [ %q.next, %down.latch ]
+; CHECK-NEXT:    --> {{\{\{}}%start,+,1}<nuw><%up.header>,+,-1}<%down.header> U: full-set S: full-set Exits: ((-1 * (ptrtoaddr ptr %start to i64)) + ({(ptrtoaddr ptr %start to i64),+,1}<nuw><%up.header> umin (ptrtoaddr ptr %start to i64)) + %start) LoopDispositions: { %down.header: Computable }
+; CHECK-NEXT:    %q.next = getelementptr i8, ptr %q, i64 -1
+; CHECK-NEXT:    --> {{\{\{}}(-1 + %start),+,1}<nw><%up.header>,+,-1}<%down.header> U: full-set S: full-set Exits: (-1 + (-1 * (ptrtoaddr ptr %start to i64)) + ({(ptrtoaddr ptr %start to i64),+,1}<nuw><%up.header> umin (ptrtoaddr ptr %start to i64)) + %start) LoopDispositions: { %down.header: Computable }
+; CHECK-NEXT:  Determining loop execution counts for: @dec_to_start_of_nuw_ptr_addrec
+; CHECK-NEXT:  Loop %down.header: backedge-taken count is ((-1 * ({(ptrtoaddr ptr %start to i64),+,1}<nuw><%up.header> umin (ptrtoaddr ptr %start to i64))) + {(ptrtoaddr ptr %start to i64),+,1}<nuw><%up.header>)
+; CHECK-NEXT:  Loop %down.header: constant max backedge-taken count is i64 -1
+; CHECK-NEXT:  Loop %down.header: symbolic max backedge-taken count is ((-1 * ({(ptrtoaddr ptr %start to i64),+,1}<nuw><%up.header> umin (ptrtoaddr ptr %start to i64))) + {(ptrtoaddr ptr %start to i64),+,1}<nuw><%up.header>)
+; CHECK-NEXT:  Loop %down.header: Trip multiple is 1
+; CHECK-NEXT:  Loop %up.header: Unpredictable backedge-taken count.
+; CHECK-NEXT:  Loop %up.header: Unpredictable constant max backedge-taken count.
+; CHECK-NEXT:  Loop %up.header: Unpredictable symbolic max backedge-taken count.
+;
+entry:
+  br label %up.header
+
+up.header:
+  %p = phi ptr [ %start, %entry ], [ %p.next, %up.latch ]
+  %v = phi i32 [ %n, %entry ], [ %v.next, %up.latch ]
+  %pos = icmp sgt i32 %v, 0
+  br i1 %pos, label %up.latch, label %down.header
+
+up.latch:
+  %p.next = getelementptr nuw i8, ptr %p, i64 1
+  %v.next = mul i32 %v, 10
+  br label %up.header
+
+down.header:
+  %q = phi ptr [ %p, %up.header ], [ %q.next, %down.latch ]
+  %in.range = icmp ugt ptr %q, %start
+  br i1 %in.range, label %down.latch, label %exit
+
+down.latch:
+  %q.next = getelementptr i8, ptr %q, i64 -1
+  br label %down.header
+
+exit:
+  ret void
+}
+
+; Same for an integer recurrence.
+define void @dec_to_start_of_nuw_int_addrec(i64 %start, i32 %n) {
+; CHECK-LABEL: 'dec_to_start_of_nuw_int_addrec'
+; CHECK-NEXT:  Classifying expressions for: @dec_to_start_of_nuw_int_addrec
+; CHECK-NEXT:    %x = phi i64 [ %start, %entry ], [ %x.next, %up.latch ]
+; CHECK-NEXT:    --> {%start,+,1}<nuw><%up.header> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %up.header: Computable }
+; CHECK-NEXT:    %v = phi i32 [ %n, %entry ], [ %v.next, %up.latch ]
+; CHECK-NEXT:    --> %v U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %up.header: Variant }
+; CHECK-NEXT:    %x.next = add nuw i64 %x, 1
+; CHECK-NEXT:    --> {(1 + %start),+,1}<nw><%up.header> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %up.header: Computable }
+; CHECK-NEXT:    %v.next = mul i32 %v, 10
+; CHECK-NEXT:    --> (10 * %v) U: [0,-1) S: [-2147483648,2147483647) Exits: <<Unknown>> LoopDispositions: { %up.header: Variant }
+; CHECK-NEXT:    %y = phi i64 [ %x, %up.header ], [ %y.next, %down.latch ]
+; CHECK-NEXT:    --> {{\{\{}}%start,+,1}<nuw><%up.header>,+,-1}<%down.header> U: full-set S: full-set Exits: ({%start,+,1}<nuw><%up.header> umin %start) LoopDispositions: { %down.header: Computable }
+; CHECK-NEXT:    %y.next = add i64 %y, -1
+; CHECK-NEXT:    --> {{\{\{}}(-1 + %start),+,1}<nw><%up.header>,+,-1}<%down.header> U: full-set S: full-set Exits: (-1 + ({%start,+,1}<nuw><%up.header> umin %start)) LoopDispositions: { %down.header: Computable }
+; CHECK-NEXT:  Determining loop execution counts for: @dec_to_start_of_nuw_int_addrec
+; CHECK-NEXT:  Loop %down.header: backedge-taken count is ((-1 * ({%start,+,1}<nuw><%up.header> umin %start)) + {%start,+,1}<nuw><%up.header>)
+; CHECK-NEXT:  Loop %down.header: constant max backedge-taken count is i64 -1
+; CHECK-NEXT:  Loop %down.header: symbolic max backedge-taken count is ((-1 * ({%start,+,1}<nuw><%up.header> umin %start)) + {%start,+,1}<nuw><%up.header>)
+; CHECK-NEXT:  Loop %down.header: Trip multiple is 1
+; CHECK-NEXT:  Loop %up.header: Unpredictable backedge-taken count.
+; CHECK-NEXT:  Loop %up.header: Unpredictable constant max backedge-taken count.
+; CHECK-NEXT:  Loop %up.header: Unpredictable symbolic max backedge-taken count.
+;
+entry:
+  br label %up.header
+
+up.header:
+  %x = phi i64 [ %start, %entry ], [ %x.next, %up.latch ]
+  %v = phi i32 [ %n, %entry ], [ %v.next, %up.latch ]
+  %pos = icmp sgt i32 %v, 0
+  br i1 %pos, label %up.latch, label %down.header
+
+up.latch:
+  %x.next = add nuw i64 %x, 1
+  %v.next = mul i32 %v, 10
+  br label %up.header
+
+down.header:
+  %y = phi i64 [ %x, %up.header ], [ %y.next, %down.latch ]
+  %in.range = icmp ugt i64 %y, %start
+  br i1 %in.range, label %down.latch, label %exit
+
+down.latch:
+  %y.next = add i64 %y, -1
+  br label %down.header
+
+exit:
+  ret void
+}
+
+define void @dec_to_start_of_wrapping_ptr_addrec(ptr %start, i32 %n) {
+; CHECK-LABEL: 'dec_to_start_of_wrapping_ptr_addrec'
+; CHECK-NEXT:  Classifying expressions for: @dec_to_start_of_wrapping_ptr_addrec
+; CHECK-NEXT:    %p = phi ptr [ %start, %entry ], [ %p.next, %up.latch ]
+; CHECK-NEXT:    --> {%start,+,1}<%up.header> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %up.header: Computable }
+; CHECK-NEXT:    %v = phi i32 [ %n, %entry ], [ %v.next, %up.latch ]
+; CHECK-NEXT:    --> %v U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %up.header: Variant }
+; CHECK-NEXT:    %p.next = getelementptr i8, ptr %p, i64 1
+; CHECK-NEXT:    --> {(1 + %start),+,1}<%up.header> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %up.header: Computable }
+; CHECK-NEXT:    %v.next = mul i32 %v, 10
+; CHECK-NEXT:    --> (10 * %v) U: [0,-1) S: [-2147483648,2147483647) Exits: <<Unknown>> LoopDispositions: { %up.header: Variant }
+; CHECK-NEXT:    %q = phi ptr [ %p, %up.header ], [ %q.next, %down.latch ]
+; CHECK-NEXT:    --> {{\{\{}}%start,+,1}<%up.header>,+,-1}<%down.header> U: full-set S: full-set Exits: ((-1 * (ptrtoaddr ptr %start to i64)) + ({(ptrtoaddr ptr %start to i64),+,1}<%up.header> umin (ptrtoaddr ptr %start to i64)) + %start) LoopDispositions: { %down.header: Computable }
+; CHECK-NEXT:    %q.next = getelementptr i8, ptr %q, i64 -1
+; CHECK-NEXT:    --> {{\{\{}}(-1 + %start),+,1}<%up.header>,+,-1}<%down.header> U: full-set S: full-set Exits: (-1 + (-1 * (ptrtoaddr ptr %start to i64)) + ({(ptrtoaddr ptr %start to i64),+,1}<%up.header> umin (ptrtoaddr ptr %start to i64)) + %start) LoopDispositions: { %down.header: Computable }
+; CHECK-NEXT:  Determining loop execution counts for: @dec_to_start_of_wrapping_ptr_addrec
+; CHECK-NEXT:  Loop %down.header: backedge-taken count is ((-1 * ({(ptrtoaddr ptr %start to i64),+,1}<%up.header> umin (ptrtoaddr ptr %start to i64))) + {(ptrtoaddr ptr %start to i64),+,1}<%up.header>)
+; CHECK-NEXT:  Loop %down.header: constant max backedge-taken count is i64 -1
+; CHECK-NEXT:  Loop %down.header: symbolic max backedge-taken count is ((-1 * ({(ptrtoaddr ptr %start to i64),+,1}<%up.header> umin (ptrtoaddr ptr %start to i64))) + {(ptrtoaddr ptr %start to i64),+,1}<%up.header>)
+; CHECK-NEXT:  Loop %down.header: Trip multiple is 1
+; CHECK-NEXT:  Loop %up.header: Unpredictable backedge-taken count.
+; CHECK-NEXT:  Loop %up.header: Unpredictable constant max backedge-taken count.
+; CHECK-NEXT:  Loop %up.header: Unpredictable symbolic max backedge-taken count.
+;
+entry:
+  br label %up.header
+
+up.header:
+  %p = phi ptr [ %start, %entry ], [ %p.next, %up.latch ]
+  %v = phi i32 [ %n, %entry ], [ %v.next, %up.latch ]
+  %pos = icmp sgt i32 %v, 0
+  br i1 %pos, label %up.latch, label %down.header
+
+up.latch:
+  %p.next = getelementptr i8, ptr %p, i64 1
+  %v.next = mul i32 %v, 10
+  br label %up.header
+
+down.header:
+  %q = phi ptr [ %p, %up.header ], [ %q.next, %down.latch ]
+  %in.range = icmp ugt ptr %q, %start
+  br i1 %in.range, label %down.latch, label %exit
+
+down.latch:
+  %q.next = getelementptr i8, ptr %q, i64 -1
+  br label %down.header
+
+exit:
+  ret void
+}
+
+; With nsw and a step that cannot be negative, the recurrence cannot be
+; signed-below %start.
+define void @dec_to_start_of_nsw_addrec(i64 %start, i32 %n, i64 %step.raw) {
+; CHECK-LABEL: 'dec_to_start_of_nsw_addrec'
+; CHECK-NEXT:  Classifying expressions for: @dec_to_start_of_nsw_addrec
+; 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.latch ]
+; CHECK-NEXT:    --> {%start,+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nsw><%up.header> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %up.header: Computable }
+; CHECK-NEXT:    %v = phi i32 [ %n, %entry ], [ %v.next, %up.latch ]
+; CHECK-NEXT:    --> %v U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %up.header: Variant }
+; CHECK-NEXT:    %x.next = add nsw i64 %x, %step
+; CHECK-NEXT:    --> {((zext i3 (trunc i64 %step.raw to i3) to i64) + %start),+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nw><%up.header> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %up.header: Computable }
+; CHECK-NEXT:    %v.next = mul i32 %v, 10
+; CHECK-NEXT:    --> (10 * %v) U: [0,-1) S: [-2147483648,2147483647) Exits: <<Unknown>> LoopDispositions: { %up.header: Variant }
+; CHECK-NEXT:    %y = phi i64 [ %x, %up.header ], [ %y.next, %down.latch ]
+; CHECK-NEXT:    --> {{\{\{}}%start,+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nsw><%up.header>,+,-1}<%down.header> U: full-set S: full-set Exits: ({%start,+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nsw><%up.header> smin %start) LoopDispositions: { %down.header: Computable }
+; CHECK-NEXT:    %y.next = add i64 %y, -1
+; CHECK-NEXT:    --> {{\{\{}}(-1 + %start),+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nw><%up.header>,+,-1}<%down.header> U: full-set S: full-set Exits: (-1 + ({%start,+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nsw><%up.header> smin %start)) LoopDispositions: { %down.header: Computable }
+; CHECK-NEXT:  Determining loop execution counts for: @dec_to_start_of_nsw_addrec
+; CHECK-NEXT:  Loop %down.header: backedge-taken count is ((-1 * ({%start,+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nsw><%up.header> smin %start)) + {%start,+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nsw><%up.header>)
+; CHECK-NEXT:  Loop %down.header: constant max backedge-taken count is i64 -1
+; CHECK-NEXT:  Loop %down.header: symbolic max backedge-taken count is ((-1 * ({%start,+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nsw><%up.header> smin %start)) + {%start,+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nsw><%up.header>)
+; CHECK-NEXT:  Loop %down.header: Trip multiple is 1
+; CHECK-NEXT:  Loop %up.header: Unpredictable backedge-taken count.
+; CHECK-NEXT:  Loop %up.header: Unpredictable constant max backedge-taken count.
+; CHECK-NEXT:  Loop %up.header: Unpredictable symbolic max backedge-taken count.
+;
+entry:
+  %step = and i64 %step.raw, 7
+  br label %up.header
+
+up.header:
+  %x = phi i64 [ %start, %entry ], [ %x.next, %up.latch ]
+  %v = phi i32 [ %n, %entry ], [ %v.next, %up.latch ]
+  %pos = icmp sgt i32 %v, 0
+  br i1 %pos, label %up.latch, label %down.header
+
+up.latch:
+  %x.next = add nsw i64 %x, %step
+  %v.next = mul i32 %v, 10
+  br label %up.header
+
+down.header:
+  %y = phi i64 [ %x, %up.header ], [ %y.next, %down.latch ]
+  %in.range = icmp sgt i64 %y, %start
+  br i1 %in.range, label %down.latch, label %exit
+
+down.latch:
+  %y.next = add i64 %y, -1
+  br label %down.header
+
+exit:
+  ret void
+}
+
+; AddRec is nsw, but step may be negative.
+define void @dec_to_start_of_nsw_addrec_unknown_step(i64 %start, i32 %n, i64 %step) {
+; CHECK-LABEL: 'dec_to_start_of_nsw_addrec_unknown_step'
+; CHECK-NEXT:  Classifying expressions for: @dec_to_start_of_nsw_addrec_unknown_step
+; CHECK-NEXT:    %x = phi i64 [ %start, %entry ], [ %x.next, %up.latch ]
+; CHECK-NEXT:    --> {%start,+,%step}<nsw><%up.header> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %up.header: Computable }
+; CHECK-NEXT:    %v = phi i32 [ %n, %entry ], [ %v.next, %up.latch ]
+; CHECK-NEXT:    --> %v U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %up.header: Variant }
+; CHECK-NEXT:    %x.next = add nsw i64 %x, %step
+; CHECK-NEXT:    --> {(%start + %step),+,%step}<nw><%up.header> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %up.header: Computable }
+; CHECK-NEXT:    %v.next = mul i32 %v, 10
+; CHECK-NEXT:    --> (10 * %v) U: [0,-1) S: [-2147483648,2147483647) Exits: <<Unknown>> LoopDispositions: { %up.header: Variant }
+; CHECK-NEXT:    %y = phi i64 [ %x, %up.header ], [ %y.next, %down.latch ]
+; CHECK-NEXT:    --> {{\{\{}}%start,+,%step}<nsw><%up.header>,+,-1}<%down.header> U: full-set S: full-set Exits: ({%start,+,%step}<nsw><%up.header> smin %start) LoopDispositions: { %down.header: Computable }
+; CHECK-NEXT:    %y.next = add i64 %y, -1
+; CHECK-NEXT:    --> {{\{\{}}(-1 + %start),+,%step}<nw><%up.header>,+,-1}<%down.header> U: full-set S: full-set Exits: (-1 + ({%start,+,%step}<nsw><%up.header> smin %start)) LoopDispositions: { %down.header: Computable }
+; CHECK-NEXT:  Determining loop execution counts for: @dec_to_start_of_nsw_addrec_unknown_step
+; CHECK-NEXT:  Loop %down.header: backedge-taken count is ((-1 * ({%start,+,%step}<nsw><%up.header> smin %start)) + {%start,+,%step}<nsw><%up.header>)
+; CHECK-NEXT:  Loop %down.header: constant max backedge-taken count is i64 -1
+; CHECK-NEXT:  Loop %down.header: symbolic max backedge-taken count is ((-1 * ({%start,+,%step}<nsw><%up.header> smin %start)) + {%start,+,%step}<nsw><%up.header>)
+; CHECK-NEXT:  Loop %down.header: Trip multiple is 1
+; CHECK-NEXT:  Loop %up.header: Unpredictable backedge-taken count.
+; CHECK-NEXT:  Loop %up.header: Unpredictable constant max backedge-taken count.
+; CHECK-NEXT:  Loop %up.header: Unpredictable symbolic max backedge-taken count.
+;
+entry:
+  br label %up.header
+
+up.header:
+  %x = phi i64 [ %start, %entry ], [ %x.next, %up.latch ]
+  %v = phi i32 [ %n, %entry ], [ %v.next, %up.latch ]
+  %pos = icmp sgt i32 %v, 0
+  br i1 %pos, label %up.latch, label %down.header
+
+up.latch:
+  %x.next = add nsw i64 %x, %step
+  %v.next = mul i32 %v, 10
+  br label %up.header
+
+down.header:
+  %y = phi i64 [ %x, %up.header ], [ %y.next, %down.latch ]
+  %in.range = icmp sgt i64 %y, %start
+  br i1 %in.range, label %down.latch, label %exit
+
+down.latch:
+  %y.next = add i64 %y, -1
+  br label %down.header
+
+exit:
+  ret void
+}
+
+define void @dec_to_start_of_nsw_addrec_unsigned_clamp(i64 %start, i32 %n, i64 %step.raw) {
+; CHECK-LABEL: 'dec_to_start_of_nsw_addrec_unsigned_clamp'
+; CHECK-NEXT:  Classifying expressions for: @dec_to_start_of_nsw_addrec_unsigned_clamp
+; 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.latch ]
+; CHECK-NEXT:    --> {%start,+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nsw><%up.header> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %up.header: Computable }
+; CHECK-NEXT:    %v = phi i32 [ %n, %entry ], [ %v.next, %up.latch ]
+; CHECK-NEXT:    --> %v U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %up.header: Variant }
+; CHECK-NEXT:    %x.next = add nsw i64 %x, %step
+; CHECK-NEXT:    --> {((zext i3 (trunc i64 %step.raw to i3) to i64) + %start),+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nw><%up.header> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %up.header: Computable }
+; CHECK-NEXT:    %v.next = mul i32 %v, 10
+; CHECK-NEXT:    --> (10 * %v) U: [0,-1) S: [-2147483648,2147483647) Exits: <<Unknown>> LoopDispositions: { %up.header: Variant }
+; CHECK-NEXT:    %y = phi i64 [ %x, %up.header ], [ %y.next, %down.latch ]
+; CHECK-NEXT:    --> {{\{\{}}%start,+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nsw><%up.header>,+,-1}<%down.header> U: full-set S: full-set Exits: ({%start,+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nsw><%up.header> umin %start) LoopDispositions: { %down.header: Computable }
+; CHECK-NEXT:    %y.next = add i64 %y, -1
+; CHECK-NEXT:    --> {{\{\{}}(-1 + %start),+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nw><%up.header>,+,-1}<%down.header> U: full-set S: full-set Exits: (-1 + ({%start,+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nsw><%up.header> umin %start)) LoopDispositions: { %down.header: Computable }
+; CHECK-NEXT:  Determining loop execution counts for: @dec_to_start_of_nsw_addrec_unsigned_clamp
+; CHECK-NEXT:  Loop %down.header: backedge-taken count is ((-1 * ({%start,+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nsw><%up.header> umin %start)) + {%start,+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nsw><%up.header>)
+; CHECK-NEXT:  Loop %down.header: constant max backedge-taken count is i64 -1
+; CHECK-NEXT:  Loop %down.header: symbolic max backedge-taken count is ((-1 * ({%start,+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nsw><%up.header> umin %start)) + {%start,+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nsw><%up.header>)
+; CHECK-NEXT:  Loop %down.header: Trip multiple is 1
+; CHECK-NEXT:  Loop %up.header: Unpredictable backedge-taken count.
+; CHECK-NEXT:  Loop %up.header: Unpredictable constant max backedge-taken count.
+; CHECK-NEXT:  Loop %up.header: Unpredictable symbolic max backedge-taken count.
+;
+entry:
+  %step = and i64 %step.raw, 7
+  br label %up.header
+
+up.header:
+  %x = phi i64 [ %start, %entry ], [ %x.next, %up.latch ]
+  %v = phi i32 [ %n, %entry ], [ %v.next, %up.latch ]
+  %pos = icmp sgt i32 %v, 0
+  br i1 %pos, label %up.latch, label %down.header
+
+up.latch:
+  %x.next = add nsw i64 %x, %step
+  %v.next = mul i32 %v, 10
+  br label %up.header
+
+down.header:
+  %y = phi i64 [ %x, %up.header ], [ %y.next, %down.latch ]
+  %in.range = icmp ugt i64 %y, %start
+  br i1 %in.range, label %down.latch, label %exit
+
+down.latch:
+  %y.next = add i64 %y, -1
+  br label %down.header
+
+exit:
+  ret void
+}
diff --git a/llvm/test/Transforms/IndVarSimplify/addrec-vs-start-monotonic.ll b/llvm/test/Transforms/IndVarSimplify/addrec-vs-start-monotonic.ll
new file mode 100644
index 0000000000000..534bdc6d366a4
--- /dev/null
+++ b/llvm/test/Transforms/IndVarSimplify/addrec-vs-start-monotonic.ll
@@ -0,0 +1,156 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals none --version 6
+; RUN: opt -p indvars -S %s | FileCheck %s
+
+define void @nuw_strict_vs_nonstrict(i64 %start, i64 %n, ptr %out) {
+; CHECK-LABEL: define void @nuw_strict_vs_nonstrict(
+; CHECK-SAME: i64 [[START:%.*]], i64 [[N:%.*]], ptr [[OUT:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    br label %[[LOOP:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[START]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
+; CHECK-NEXT:    [[LT:%.*]] = icmp ult i64 [[IV]], [[START]]
+; CHECK-NEXT:    [[GE:%.*]] = icmp uge i64 [[IV]], [[START]]
+; CHECK-NEXT:    [[GT:%.*]] = icmp ugt i64 [[IV]], [[START]]
+; CHECK-NEXT:    [[LE:%.*]] = icmp ule i64 [[IV]], [[START]]
+; CHECK-NEXT:    store volatile i1 [[LT]], ptr [[OUT]], align 1
+; CHECK-NEXT:    store volatile i1 [[GE]], ptr [[OUT]], align 1
+; CHECK-NEXT:    store volatile i1 [[GT]], ptr [[OUT]], align 1
+; CHECK-NEXT:    store volatile i1 [[LE]], ptr [[OUT]], align 1
+; CHECK-NEXT:    [[IV_NEXT]] = add nuw i64 [[IV]], 1
+; CHECK-NEXT:    [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]]
+; CHECK-NEXT:    br i1 [[EC]], label %[[EXIT:.*]], label %[[LOOP]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop
+
+loop:
+  %iv = phi i64 [ %start, %entry ], [ %iv.next, %loop ]
+  %lt = icmp ult i64 %iv, %start
+  %ge = icmp uge i64 %iv, %start
+  %gt = icmp ugt i64 %iv, %start
+  %le = icmp ule i64 %iv, %start
+  store volatile i1 %lt, ptr %out
+  store volatile i1 %ge, ptr %out
+  store volatile i1 %gt, ptr %out
+  store volatile i1 %le, ptr %out
+  %iv.next = add nuw i64 %iv, 1
+  %ec = icmp eq i64 %iv.next, %n
+  br i1 %ec, label %exit, label %loop
+
+exit:
+  ret void
+}
+
+define void @nuw_addrec_on_rhs(i64 %start, i64 %n, ptr %out) {
+; CHECK-LABEL: define void @nuw_addrec_on_rhs(
+; CHECK-SAME: i64 [[START:%.*]], i64 [[N:%.*]], ptr [[OUT:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    br label %[[LOOP:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[START]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
+; CHECK-NEXT:    [[GT:%.*]] = icmp ugt i64 [[START]], [[IV]]
+; CHECK-NEXT:    [[LE:%.*]] = icmp ule i64 [[START]], [[IV]]
+; CHECK-NEXT:    [[LT:%.*]] = icmp ult i64 [[START]], [[IV]]
+; CHECK-NEXT:    store volatile i1 [[GT]], ptr [[OUT]], align 1
+; CHECK-NEXT:    store volatile i1 [[LE]], ptr [[OUT]], align 1
+; CHECK-NEXT:    store volatile i1 [[LT]], ptr [[OUT]], align 1
+; CHECK-NEXT:    [[IV_NEXT]] = add nuw i64 [[IV]], 1
+; CHECK-NEXT:    [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]]
+; CHECK-NEXT:    br i1 [[EC]], label %[[EXIT:.*]], label %[[LOOP]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop
+
+loop:
+  %iv = phi i64 [ %start, %entry ], [ %iv.next, %loop ]
+  %gt = icmp ugt i64 %start, %iv
+  %le = icmp ule i64 %start, %iv
+  %lt = icmp ult i64 %start, %iv
+  store volatile i1 %gt, ptr %out
+  store volatile i1 %le, ptr %out
+  store volatile i1 %lt, ptr %out
+  %iv.next = add nuw i64 %iv, 1
+  %ec = icmp eq i64 %iv.next, %n
+  br i1 %ec, label %exit, label %loop
+
+exit:
+  ret void
+}
+
+define void @nsw_nonneg_step(i64 %start, i64 %n, i64 %step.raw, ptr %out) {
+; CHECK-LABEL: define void @nsw_nonneg_step(
+; CHECK-SAME: i64 [[START:%.*]], i64 [[N:%.*]], i64 [[STEP_RAW:%.*]], ptr [[OUT:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[STEP:%.*]] = and i64 [[STEP_RAW]], 7
+; CHECK-NEXT:    br label %[[LOOP:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[START]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
+; CHECK-NEXT:    [[SLT:%.*]] = icmp slt i64 [[IV]], [[START]]
+; CHECK-NEXT:    [[ULT:%.*]] = icmp ult i64 [[IV]], [[START]]
+; CHECK-NEXT:    [[SGT:%.*]] = icmp sgt i64 [[IV]], [[START]]
+; CHECK-NEXT:    store volatile i1 [[SLT]], ptr [[OUT]], align 1
+; CHECK-NEXT:    store volatile i1 [[ULT]], ptr [[OUT]], align 1
+; CHECK-NEXT:    store volatile i1 [[SGT]], ptr [[OUT]], align 1
+; CHECK-NEXT:    [[IV_NEXT]] = add nsw i64 [[IV]], [[STEP]]
+; CHECK-NEXT:    [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]]
+; CHECK-NEXT:    br i1 [[EC]], label %[[EXIT:.*]], label %[[LOOP]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %step = and i64 %step.raw, 7
+  br label %loop
+
+loop:
+  %iv = phi i64 [ %start, %entry ], [ %iv.next, %loop ]
+  %slt = icmp slt i64 %iv, %start
+  %ult = icmp ult i64 %iv, %start
+  %sgt = icmp sgt i64 %iv, %start
+  store volatile i1 %slt, ptr %out
+  store volatile i1 %ult, ptr %out
+  store volatile i1 %sgt, ptr %out
+  %iv.next = add nsw i64 %iv, %step
+  %ec = icmp eq i64 %iv.next, %n
+  br i1 %ec, label %exit, label %loop
+
+exit:
+  ret void
+}
+
+define void @nsw_negative_step(i64 %start, i64 %n, ptr %out) {
+; CHECK-LABEL: define void @nsw_negative_step(
+; CHECK-SAME: i64 [[START:%.*]], i64 [[N:%.*]], ptr [[OUT:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    br label %[[LOOP:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[START]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
+; CHECK-NEXT:    [[SLT:%.*]] = icmp slt i64 [[IV]], [[START]]
+; CHECK-NEXT:    [[SGE:%.*]] = icmp sge i64 [[IV]], [[START]]
+; CHECK-NEXT:    store volatile i1 [[SLT]], ptr [[OUT]], align 1
+; CHECK-NEXT:    store volatile i1 [[SGE]], ptr [[OUT]], align 1
+; CHECK-NEXT:    [[IV_NEXT]] = add nsw i64 [[IV]], -1
+; CHECK-NEXT:    [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]]
+; CHECK-NEXT:    br i1 [[EC]], label %[[EXIT:.*]], label %[[LOOP]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop
+
+loop:
+  %iv = phi i64 [ %start, %entry ], [ %iv.next, %loop ]
+  %slt = icmp slt i64 %iv, %start
+  %sge = icmp sge i64 %iv, %start
+  store volatile i1 %slt, ptr %out
+  store volatile i1 %sge, ptr %out
+  %iv.next = add nsw i64 %iv, -1
+  %ec = icmp eq i64 %iv.next, %n
+  br i1 %ec, label %exit, label %loop
+
+exit:
+  ret void
+}

>From 056fef37d94da48fbb651073da743ca1a9349c9d Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Mon, 10 Aug 2026 21:35:28 +0100
Subject: [PATCH 2/2] [SCEV] Use AddRec monotonicity in
 isKnownViaNonRecursiveReasoning.

Monotonic AddRecs are never less than their start value; use that in
when reasoning about predicates involving an AddRec and its start value.

Improves results in a few cases on llvm-opt-benchmark-nightly:
https://github.com/dtcxzyw/llvm-opt-benchmark-nightly/pull/996
---
 llvm/lib/Analysis/ScalarEvolution.cpp         | 28 +++++++++++++++++++
 .../addrec-vs-start-monotonic.ll              | 24 ++++++++--------
 .../addrec-vs-start-monotonic.ll              | 15 ++++------
 3 files changed, 45 insertions(+), 22 deletions(-)

diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 2be8495c164fc..d005df1369507 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -12913,6 +12913,33 @@ static bool IsKnownPredicateViaAddRecStart(ScalarEvolution &SE,
   return SE.isKnownPredicate(Pred, LStart, RStart);
 }
 
+/// Is LHS `Pred` RHS true because one of them is an AddRec that is known not to
+/// go below its own start value, which is the other side?
+static bool IsKnownPredicateViaAddRecMonotonicity(ScalarEvolution &SE,
+                                                  CmpPredicate Pred,
+                                                  const SCEV *LHS,
+                                                  const SCEV *RHS) {
+  // Normalize to (AddRec Pred Start).
+  if (!isa<SCEVAddRecExpr>(LHS) && isa<SCEVAddRecExpr>(RHS)) {
+    Pred = ICmpInst::getSwappedCmpPredicate(Pred);
+    std::swap(LHS, RHS);
+  }
+
+  // The recurrence is equal to Start in the first iteration, so only the
+  // non-strict predicate holds.
+  if (Pred != ICmpInst::ICMP_UGE && Pred != ICmpInst::ICMP_SGE)
+    return false;
+
+  const auto *AR = dyn_cast<SCEVAddRecExpr>(LHS);
+  if (!AR || AR->getStart() != RHS)
+    return false;
+
+  // A recurrence that neither wraps nor steps backwards never goes below the
+  // value it started at.
+  return SE.getMonotonicPredicateType(AR, Pred) ==
+         ScalarEvolution::MonotonicallyIncreasing;
+}
+
 /// Is LHS `Pred` RHS true on the virtue of LHS or RHS being a Min or Max
 /// expression?
 static bool IsKnownPredicateViaMinOrMax(ScalarEvolution &SE, CmpPredicate Pred,
@@ -13173,6 +13200,7 @@ bool ScalarEvolution::isKnownViaNonRecursiveReasoning(CmpPredicate Pred,
          isKnownPredicateViaConstantRanges(Pred, LHS, RHS) ||
          IsKnownPredicateViaMinOrMax(*this, Pred, LHS, RHS) ||
          IsKnownPredicateViaAddRecStart(*this, Pred, LHS, RHS) ||
+         IsKnownPredicateViaAddRecMonotonicity(*this, Pred, LHS, RHS) ||
          isKnownPredicateViaNoOverflow(Pred, LHS, RHS);
 }
 
diff --git a/llvm/test/Analysis/ScalarEvolution/addrec-vs-start-monotonic.ll b/llvm/test/Analysis/ScalarEvolution/addrec-vs-start-monotonic.ll
index 46bd202a09985..6d8df85620ce4 100644
--- a/llvm/test/Analysis/ScalarEvolution/addrec-vs-start-monotonic.ll
+++ b/llvm/test/Analysis/ScalarEvolution/addrec-vs-start-monotonic.ll
@@ -13,13 +13,13 @@ define void @dec_to_start_of_nuw_ptr_addrec(ptr %start, i32 %n) {
 ; CHECK-NEXT:    %v.next = mul i32 %v, 10
 ; CHECK-NEXT:    --> (10 * %v) U: [0,-1) S: [-2147483648,2147483647) Exits: <<Unknown>> LoopDispositions: { %up.header: Variant }
 ; CHECK-NEXT:    %q = phi ptr [ %p, %up.header ], [ %q.next, %down.latch ]
-; CHECK-NEXT:    --> {{\{\{}}%start,+,1}<nuw><%up.header>,+,-1}<%down.header> U: full-set S: full-set Exits: ((-1 * (ptrtoaddr ptr %start to i64)) + ({(ptrtoaddr ptr %start to i64),+,1}<nuw><%up.header> umin (ptrtoaddr ptr %start to i64)) + %start) LoopDispositions: { %down.header: Computable }
+; CHECK-NEXT:    --> {{\{\{}}%start,+,1}<nuw><%up.header>,+,-1}<%down.header> U: full-set S: full-set Exits: %start LoopDispositions: { %down.header: Computable }
 ; CHECK-NEXT:    %q.next = getelementptr i8, ptr %q, i64 -1
-; CHECK-NEXT:    --> {{\{\{}}(-1 + %start),+,1}<nw><%up.header>,+,-1}<%down.header> U: full-set S: full-set Exits: (-1 + (-1 * (ptrtoaddr ptr %start to i64)) + ({(ptrtoaddr ptr %start to i64),+,1}<nuw><%up.header> umin (ptrtoaddr ptr %start to i64)) + %start) LoopDispositions: { %down.header: Computable }
+; CHECK-NEXT:    --> {{\{\{}}(-1 + %start),+,1}<nw><%up.header>,+,-1}<%down.header> U: full-set S: full-set Exits: (-1 + %start) LoopDispositions: { %down.header: Computable }
 ; CHECK-NEXT:  Determining loop execution counts for: @dec_to_start_of_nuw_ptr_addrec
-; CHECK-NEXT:  Loop %down.header: backedge-taken count is ((-1 * ({(ptrtoaddr ptr %start to i64),+,1}<nuw><%up.header> umin (ptrtoaddr ptr %start to i64))) + {(ptrtoaddr ptr %start to i64),+,1}<nuw><%up.header>)
+; CHECK-NEXT:  Loop %down.header: backedge-taken count is {0,+,1}<nuw><%up.header>
 ; CHECK-NEXT:  Loop %down.header: constant max backedge-taken count is i64 -1
-; CHECK-NEXT:  Loop %down.header: symbolic max backedge-taken count is ((-1 * ({(ptrtoaddr ptr %start to i64),+,1}<nuw><%up.header> umin (ptrtoaddr ptr %start to i64))) + {(ptrtoaddr ptr %start to i64),+,1}<nuw><%up.header>)
+; CHECK-NEXT:  Loop %down.header: symbolic max backedge-taken count is {0,+,1}<nuw><%up.header>
 ; CHECK-NEXT:  Loop %down.header: Trip multiple is 1
 ; CHECK-NEXT:  Loop %up.header: Unpredictable backedge-taken count.
 ; CHECK-NEXT:  Loop %up.header: Unpredictable constant max backedge-taken count.
@@ -65,13 +65,13 @@ define void @dec_to_start_of_nuw_int_addrec(i64 %start, i32 %n) {
 ; CHECK-NEXT:    %v.next = mul i32 %v, 10
 ; CHECK-NEXT:    --> (10 * %v) U: [0,-1) S: [-2147483648,2147483647) Exits: <<Unknown>> LoopDispositions: { %up.header: Variant }
 ; CHECK-NEXT:    %y = phi i64 [ %x, %up.header ], [ %y.next, %down.latch ]
-; CHECK-NEXT:    --> {{\{\{}}%start,+,1}<nuw><%up.header>,+,-1}<%down.header> U: full-set S: full-set Exits: ({%start,+,1}<nuw><%up.header> umin %start) LoopDispositions: { %down.header: Computable }
+; CHECK-NEXT:    --> {{\{\{}}%start,+,1}<nuw><%up.header>,+,-1}<%down.header> U: full-set S: full-set Exits: %start LoopDispositions: { %down.header: Computable }
 ; CHECK-NEXT:    %y.next = add i64 %y, -1
-; CHECK-NEXT:    --> {{\{\{}}(-1 + %start),+,1}<nw><%up.header>,+,-1}<%down.header> U: full-set S: full-set Exits: (-1 + ({%start,+,1}<nuw><%up.header> umin %start)) LoopDispositions: { %down.header: Computable }
+; CHECK-NEXT:    --> {{\{\{}}(-1 + %start),+,1}<nw><%up.header>,+,-1}<%down.header> U: full-set S: full-set Exits: (-1 + %start) LoopDispositions: { %down.header: Computable }
 ; CHECK-NEXT:  Determining loop execution counts for: @dec_to_start_of_nuw_int_addrec
-; CHECK-NEXT:  Loop %down.header: backedge-taken count is ((-1 * ({%start,+,1}<nuw><%up.header> umin %start)) + {%start,+,1}<nuw><%up.header>)
+; CHECK-NEXT:  Loop %down.header: backedge-taken count is {0,+,1}<nuw><%up.header>
 ; CHECK-NEXT:  Loop %down.header: constant max backedge-taken count is i64 -1
-; CHECK-NEXT:  Loop %down.header: symbolic max backedge-taken count is ((-1 * ({%start,+,1}<nuw><%up.header> umin %start)) + {%start,+,1}<nuw><%up.header>)
+; CHECK-NEXT:  Loop %down.header: symbolic max backedge-taken count is {0,+,1}<nuw><%up.header>
 ; CHECK-NEXT:  Loop %down.header: Trip multiple is 1
 ; CHECK-NEXT:  Loop %up.header: Unpredictable backedge-taken count.
 ; CHECK-NEXT:  Loop %up.header: Unpredictable constant max backedge-taken count.
@@ -171,13 +171,13 @@ define void @dec_to_start_of_nsw_addrec(i64 %start, i32 %n, i64 %step.raw) {
 ; CHECK-NEXT:    %v.next = mul i32 %v, 10
 ; CHECK-NEXT:    --> (10 * %v) U: [0,-1) S: [-2147483648,2147483647) Exits: <<Unknown>> LoopDispositions: { %up.header: Variant }
 ; CHECK-NEXT:    %y = phi i64 [ %x, %up.header ], [ %y.next, %down.latch ]
-; CHECK-NEXT:    --> {{\{\{}}%start,+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nsw><%up.header>,+,-1}<%down.header> U: full-set S: full-set Exits: ({%start,+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nsw><%up.header> smin %start) LoopDispositions: { %down.header: Computable }
+; CHECK-NEXT:    --> {{\{\{}}%start,+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nsw><%up.header>,+,-1}<%down.header> U: full-set S: full-set Exits: %start LoopDispositions: { %down.header: Computable }
 ; CHECK-NEXT:    %y.next = add i64 %y, -1
-; CHECK-NEXT:    --> {{\{\{}}(-1 + %start),+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nw><%up.header>,+,-1}<%down.header> U: full-set S: full-set Exits: (-1 + ({%start,+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nsw><%up.header> smin %start)) LoopDispositions: { %down.header: Computable }
+; CHECK-NEXT:    --> {{\{\{}}(-1 + %start),+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nw><%up.header>,+,-1}<%down.header> U: full-set S: full-set Exits: (-1 + %start) LoopDispositions: { %down.header: Computable }
 ; CHECK-NEXT:  Determining loop execution counts for: @dec_to_start_of_nsw_addrec
-; CHECK-NEXT:  Loop %down.header: backedge-taken count is ((-1 * ({%start,+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nsw><%up.header> smin %start)) + {%start,+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nsw><%up.header>)
+; CHECK-NEXT:  Loop %down.header: backedge-taken count is {0,+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nuw><%up.header>
 ; CHECK-NEXT:  Loop %down.header: constant max backedge-taken count is i64 -1
-; CHECK-NEXT:  Loop %down.header: symbolic max backedge-taken count is ((-1 * ({%start,+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nsw><%up.header> smin %start)) + {%start,+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nsw><%up.header>)
+; CHECK-NEXT:  Loop %down.header: symbolic max backedge-taken count is {0,+,(zext i3 (trunc i64 %step.raw to i3) to i64)}<nuw><%up.header>
 ; CHECK-NEXT:  Loop %down.header: Trip multiple is 1
 ; CHECK-NEXT:  Loop %up.header: Unpredictable backedge-taken count.
 ; CHECK-NEXT:  Loop %up.header: Unpredictable constant max backedge-taken count.
diff --git a/llvm/test/Transforms/IndVarSimplify/addrec-vs-start-monotonic.ll b/llvm/test/Transforms/IndVarSimplify/addrec-vs-start-monotonic.ll
index 534bdc6d366a4..a5d2f59618692 100644
--- a/llvm/test/Transforms/IndVarSimplify/addrec-vs-start-monotonic.ll
+++ b/llvm/test/Transforms/IndVarSimplify/addrec-vs-start-monotonic.ll
@@ -8,12 +8,10 @@ define void @nuw_strict_vs_nonstrict(i64 %start, i64 %n, ptr %out) {
 ; CHECK-NEXT:    br label %[[LOOP:.*]]
 ; CHECK:       [[LOOP]]:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[START]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[LT:%.*]] = icmp ult i64 [[IV]], [[START]]
-; CHECK-NEXT:    [[GE:%.*]] = icmp uge i64 [[IV]], [[START]]
 ; CHECK-NEXT:    [[GT:%.*]] = icmp ugt i64 [[IV]], [[START]]
 ; CHECK-NEXT:    [[LE:%.*]] = icmp ule i64 [[IV]], [[START]]
-; CHECK-NEXT:    store volatile i1 [[LT]], ptr [[OUT]], align 1
-; CHECK-NEXT:    store volatile i1 [[GE]], ptr [[OUT]], align 1
+; CHECK-NEXT:    store volatile i1 false, ptr [[OUT]], align 1
+; CHECK-NEXT:    store volatile i1 true, ptr [[OUT]], align 1
 ; CHECK-NEXT:    store volatile i1 [[GT]], ptr [[OUT]], align 1
 ; CHECK-NEXT:    store volatile i1 [[LE]], ptr [[OUT]], align 1
 ; CHECK-NEXT:    [[IV_NEXT]] = add nuw i64 [[IV]], 1
@@ -50,11 +48,9 @@ define void @nuw_addrec_on_rhs(i64 %start, i64 %n, ptr %out) {
 ; CHECK-NEXT:    br label %[[LOOP:.*]]
 ; CHECK:       [[LOOP]]:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[START]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[GT:%.*]] = icmp ugt i64 [[START]], [[IV]]
-; CHECK-NEXT:    [[LE:%.*]] = icmp ule i64 [[START]], [[IV]]
 ; CHECK-NEXT:    [[LT:%.*]] = icmp ult i64 [[START]], [[IV]]
-; CHECK-NEXT:    store volatile i1 [[GT]], ptr [[OUT]], align 1
-; CHECK-NEXT:    store volatile i1 [[LE]], ptr [[OUT]], align 1
+; CHECK-NEXT:    store volatile i1 false, ptr [[OUT]], align 1
+; CHECK-NEXT:    store volatile i1 true, ptr [[OUT]], align 1
 ; CHECK-NEXT:    store volatile i1 [[LT]], ptr [[OUT]], align 1
 ; CHECK-NEXT:    [[IV_NEXT]] = add nuw i64 [[IV]], 1
 ; CHECK-NEXT:    [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]]
@@ -89,10 +85,9 @@ define void @nsw_nonneg_step(i64 %start, i64 %n, i64 %step.raw, ptr %out) {
 ; CHECK-NEXT:    br label %[[LOOP:.*]]
 ; CHECK:       [[LOOP]]:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[START]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[SLT:%.*]] = icmp slt i64 [[IV]], [[START]]
 ; CHECK-NEXT:    [[ULT:%.*]] = icmp ult i64 [[IV]], [[START]]
 ; CHECK-NEXT:    [[SGT:%.*]] = icmp sgt i64 [[IV]], [[START]]
-; CHECK-NEXT:    store volatile i1 [[SLT]], ptr [[OUT]], align 1
+; CHECK-NEXT:    store volatile i1 false, ptr [[OUT]], align 1
 ; CHECK-NEXT:    store volatile i1 [[ULT]], ptr [[OUT]], align 1
 ; CHECK-NEXT:    store volatile i1 [[SGT]], ptr [[OUT]], align 1
 ; CHECK-NEXT:    [[IV_NEXT]] = add nsw i64 [[IV]], [[STEP]]



More information about the llvm-commits mailing list