[llvm] [ScalarEvolution] howManyLessThans infer stride isPositive from guard (PR #214014)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 3 02:12:55 PDT 2026
================
@@ -0,0 +1,92 @@
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py
+; RUN: opt -disable-output -passes='print<scalar-evolution>' < %s 2>&1 | FileCheck %s
+;
+; howManyLessThans: prove a symbolic stride is positive from a guard dominating
+; the loop, so the backedge-taken count becomes computable.
+
+declare void @llvm.trap()
+
+; Positive: `if (s <= 0) trap` dominates the loop, so on the loop path s > 0.
+; The stride is refined to (1 smax %s) via the loop guards, which is positive,
+; so the backedge-taken count is computable despite the trapping exit.
+define void @pos_stride_guard(i32 %n, i32 %s, i32 %bound, ptr %p) {
+; CHECK-LABEL: 'pos_stride_guard'
+; CHECK-NEXT: Classifying expressions for: @pos_stride_guard
+; CHECK-NEXT: %i = phi i32 [ 0, %ph ], [ %i.next, %latch ]
+; CHECK-NEXT: --> {0,+,%s}<nsw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %addr = getelementptr i32, ptr %p, i32 %i
+; CHECK-NEXT: --> {%p,+,(4 * (sext i32 %s to i64))<nsw>}<%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: %i.next = add nsw i32 %i, %s
+; CHECK-NEXT: --> {%s,+,%s}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: Determining loop execution counts for: @pos_stride_guard
+; CHECK-NEXT: Loop %loop: <multiple exits> Unpredictable backedge-taken count.
+; CHECK-NEXT: exit count for loop: ((-1 + (sext i32 %s to i64) + (0 smax (1 + (sext i32 %bound to i64))<nsw>)) /u (sext i32 %s to i64))
+; CHECK-NEXT: exit count for latch: ***COULDNOTCOMPUTE***
+; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i64 2147483648
+; CHECK-NEXT: Loop %loop: symbolic max backedge-taken count is ((-1 + (sext i32 %s to i64) + (0 smax (1 + (sext i32 %bound to i64))<nsw>)) /u (sext i32 %s to i64))
+; CHECK-NEXT: symbolic max exit count for loop: ((-1 + (sext i32 %s to i64) + (0 smax (1 + (sext i32 %bound to i64))<nsw>)) /u (sext i32 %s to i64))
+; CHECK-NEXT: symbolic max exit count for latch: ***COULDNOTCOMPUTE***
+;
+entry:
+ %sle0 = icmp sle i32 %s, 0
+ br i1 %sle0, label %trapg, label %ph
+trapg:
+ call void @llvm.trap()
+ unreachable
+ph:
+ br label %loop
+loop:
+ %i = phi i32 [ 0, %ph ], [ %i.next, %latch ]
+ %oob = icmp sgt i32 %i, %bound
+ br i1 %oob, label %trap, label %latch
+trap:
+ call void @llvm.trap()
+ unreachable
+latch:
+ %addr = getelementptr i32, ptr %p, i32 %i
+ store i32 0, ptr %addr
+ %i.next = add nsw i32 %i, %s
+ %cmp = icmp slt i32 %i.next, %n
+ br i1 %cmp, label %loop, label %exit
+exit:
+ ret void
+}
+
+; Negative: no dominating stride guard, so the stride's sign is unknown and the
+; multi-exit (trapping) loop's backedge-taken count stays unpredictable.
----------------
fhahn wrote:
```suggestion
; Same as above but without precondition ensuring stride is positive.
```
https://github.com/llvm/llvm-project/pull/214014
More information about the llvm-commits
mailing list