[llvm] [ConstraintElim] Allow a non-constant start values in addInfoForInduct. (PR #220262)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 2 03:57:15 PDT 2026


https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/220262

>From 830667bc3392582991737b09b4c8c095d42cf1cd Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 1 Sep 2026 13:57:43 +0100
Subject: [PATCH 1/2] [ConstraintElim] Precommit tests with symbolic IV start.

---
 .../induction-symbolic-start-postinc.ll       | 633 ++++++++++++++++++
 1 file changed, 633 insertions(+)
 create mode 100644 llvm/test/Transforms/ConstraintElimination/induction-symbolic-start-postinc.ll

diff --git a/llvm/test/Transforms/ConstraintElimination/induction-symbolic-start-postinc.ll b/llvm/test/Transforms/ConstraintElimination/induction-symbolic-start-postinc.ll
new file mode 100644
index 0000000000000..7a5763f4747c7
--- /dev/null
+++ b/llvm/test/Transforms/ConstraintElimination/induction-symbolic-start-postinc.ll
@@ -0,0 +1,633 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -p constraint-elimination -S %s | FileCheck %s
+
+declare void @use(i1)
+
+; Symbolic start with step 1: the strict precondition gives both unsigned facts.
+define void @postinc_symbolic_start_unsigned(i32 %start, i32 %n, i1 %c) {
+; CHECK-LABEL: define void @postinc_symbolic_start_unsigned(
+; CHECK-SAME: i32 [[START:%.*]], i32 [[N:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[PRE:%.*]] = icmp ult i32 [[START]], [[N]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[PRE]])
+; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
+; CHECK:       [[LOOP_HEADER]]:
+; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
+; CHECK-NEXT:    [[T:%.*]] = icmp ult i32 [[IV]], [[N]]
+; CHECK-NEXT:    call void @use(i1 [[T]])
+; CHECK-NEXT:    [[T_2:%.*]] = icmp uge i32 [[IV]], [[START]]
+; CHECK-NEXT:    call void @use(i1 [[T_2]])
+; CHECK-NEXT:    [[C_1:%.*]] = icmp slt i32 [[IV]], [[N]]
+; CHECK-NEXT:    call void @use(i1 [[C_1]])
+; CHECK-NEXT:    [[C_2:%.*]] = icmp sge i32 [[IV]], [[START]]
+; CHECK-NEXT:    call void @use(i1 [[C_2]])
+; CHECK-NEXT:    br i1 [[C]], label %[[EXIT:.*]], label %[[LOOP_LATCH]]
+; CHECK:       [[LOOP_LATCH]]:
+; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
+; CHECK-NEXT:    [[EC:%.*]] = icmp eq i32 [[IV_NEXT]], [[N]]
+; CHECK-NEXT:    br i1 [[EC]], label %[[EXIT]], label %[[LOOP_HEADER]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %pre = icmp ult i32 %start, %n
+  call void @llvm.assume(i1 %pre)
+  br label %loop.header
+
+loop.header:
+  %iv = phi i32 [ %start, %entry ], [ %iv.next, %loop.latch ]
+  %t = icmp ult i32 %iv, %n
+  call void @use(i1 %t)
+  %t.2 = icmp uge i32 %iv, %start
+  call void @use(i1 %t.2)
+  %c.1 = icmp slt i32 %iv, %n
+  call void @use(i1 %c.1)
+  %c.2 = icmp sge i32 %iv, %start
+  call void @use(i1 %c.2)
+  br i1 %c, label %exit, label %loop.latch
+
+loop.latch:
+  %iv.next = add i32 %iv, 1
+  %ec = icmp eq i32 %iv.next, %n
+  br i1 %ec, label %exit, label %loop.header
+
+exit:
+  ret void
+}
+
+; The signed facts need the signed precondition.
+define void @postinc_symbolic_start_signed(i32 %start, i32 %n, i1 %c) {
+; CHECK-LABEL: define void @postinc_symbolic_start_signed(
+; CHECK-SAME: i32 [[START:%.*]], i32 [[N:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[PRE:%.*]] = icmp slt i32 [[START]], [[N]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[PRE]])
+; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
+; CHECK:       [[LOOP_HEADER]]:
+; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
+; CHECK-NEXT:    [[T:%.*]] = icmp slt i32 [[IV]], [[N]]
+; CHECK-NEXT:    call void @use(i1 [[T]])
+; CHECK-NEXT:    [[T_2:%.*]] = icmp sge i32 [[IV]], [[START]]
+; CHECK-NEXT:    call void @use(i1 [[T_2]])
+; CHECK-NEXT:    [[C_1:%.*]] = icmp ult i32 [[IV]], [[N]]
+; CHECK-NEXT:    call void @use(i1 [[C_1]])
+; CHECK-NEXT:    [[C_2:%.*]] = icmp uge i32 [[IV]], [[START]]
+; CHECK-NEXT:    call void @use(i1 [[C_2]])
+; CHECK-NEXT:    br i1 [[C]], label %[[EXIT:.*]], label %[[LOOP_LATCH]]
+; CHECK:       [[LOOP_LATCH]]:
+; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
+; CHECK-NEXT:    [[EC:%.*]] = icmp eq i32 [[IV_NEXT]], [[N]]
+; CHECK-NEXT:    br i1 [[EC]], label %[[EXIT]], label %[[LOOP_HEADER]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %pre = icmp slt i32 %start, %n
+  call void @llvm.assume(i1 %pre)
+  br label %loop.header
+
+loop.header:
+  %iv = phi i32 [ %start, %entry ], [ %iv.next, %loop.latch ]
+  %t = icmp slt i32 %iv, %n
+  call void @use(i1 %t)
+  %t.2 = icmp sge i32 %iv, %start
+  call void @use(i1 %t.2)
+  %c.1 = icmp ult i32 %iv, %n
+  call void @use(i1 %c.1)
+  %c.2 = icmp uge i32 %iv, %start
+  call void @use(i1 %c.2)
+  br i1 %c, label %exit, label %loop.latch
+
+loop.latch:
+  %iv.next = add i32 %iv, 1
+  %ec = icmp eq i32 %iv.next, %n
+  br i1 %ec, label %exit, label %loop.header
+
+exit:
+  ret void
+}
+
+; Step 4 with a symbolic distance 4 * %k to the bound, a multiple of the step.
+define void @postinc_symbolic_start_step4(i32 %start, i32 %k, i1 %c) {
+; CHECK-LABEL: define void @postinc_symbolic_start_step4(
+; CHECK-SAME: i32 [[START:%.*]], i32 [[K:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[K_4:%.*]] = shl i32 [[K]], 2
+; CHECK-NEXT:    [[B:%.*]] = add i32 [[START]], [[K_4]]
+; CHECK-NEXT:    [[PRE:%.*]] = icmp ult i32 [[START]], [[B]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[PRE]])
+; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
+; CHECK:       [[LOOP_HEADER]]:
+; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
+; CHECK-NEXT:    [[T:%.*]] = icmp ult i32 [[IV]], [[B]]
+; CHECK-NEXT:    call void @use(i1 [[T]])
+; CHECK-NEXT:    br i1 [[C]], label %[[EXIT:.*]], label %[[LOOP_LATCH]]
+; CHECK:       [[LOOP_LATCH]]:
+; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 4
+; CHECK-NEXT:    [[EC:%.*]] = icmp eq i32 [[IV_NEXT]], [[B]]
+; CHECK-NEXT:    br i1 [[EC]], label %[[EXIT]], label %[[LOOP_HEADER]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %k.4 = shl i32 %k, 2
+  %b = add i32 %start, %k.4
+  %pre = icmp ult i32 %start, %b
+  call void @llvm.assume(i1 %pre)
+  br label %loop.header
+
+loop.header:
+  %iv = phi i32 [ %start, %entry ], [ %iv.next, %loop.latch ]
+  %t = icmp ult i32 %iv, %b
+  call void @use(i1 %t)
+  br i1 %c, label %exit, label %loop.latch
+
+loop.latch:
+  %iv.next = add i32 %iv, 4
+  %ec = icmp eq i32 %iv.next, %b
+  br i1 %ec, label %exit, label %loop.header
+
+exit:
+  ret void
+}
+
+; The A <=u B fact added to dedicated exit blocks uses the same precondition.
+define void @postinc_symbolic_start_exit_block(i32 %start, i32 %k, i1 %c) {
+; CHECK-LABEL: define void @postinc_symbolic_start_exit_block(
+; CHECK-SAME: i32 [[START:%.*]], i32 [[K:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[K_4:%.*]] = shl i32 [[K]], 2
+; CHECK-NEXT:    [[B:%.*]] = add i32 [[START]], [[K_4]]
+; CHECK-NEXT:    [[PRE:%.*]] = icmp ult i32 [[START]], [[B]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[PRE]])
+; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
+; CHECK:       [[LOOP_HEADER]]:
+; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
+; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 4
+; CHECK-NEXT:    [[EC:%.*]] = icmp eq i32 [[IV_NEXT]], [[B]]
+; CHECK-NEXT:    br i1 [[EC]], label %[[EXIT:.*]], label %[[LOOP_LATCH]]
+; CHECK:       [[LOOP_LATCH]]:
+; CHECK-NEXT:    br i1 [[C]], label %[[EXIT]], label %[[LOOP_HEADER]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    [[T:%.*]] = icmp ule i32 [[IV_NEXT]], [[B]]
+; CHECK-NEXT:    call void @use(i1 [[T]])
+; CHECK-NEXT:    [[C_1:%.*]] = icmp sle i32 [[IV_NEXT]], [[B]]
+; CHECK-NEXT:    call void @use(i1 [[C_1]])
+; CHECK-NEXT:    ret void
+;
+entry:
+  %k.4 = shl i32 %k, 2
+  %b = add i32 %start, %k.4
+  %pre = icmp ult i32 %start, %b
+  call void @llvm.assume(i1 %pre)
+  br label %loop.header
+
+loop.header:
+  %iv = phi i32 [ %start, %entry ], [ %iv.next, %loop.latch ]
+  %iv.next = add i32 %iv, 4
+  %ec = icmp eq i32 %iv.next, %b
+  br i1 %ec, label %exit, label %loop.latch
+
+loop.latch:
+  br i1 %c, label %exit, label %loop.header
+
+exit:
+  %t = icmp ule i32 %iv.next, %b
+  call void @use(i1 %t)
+  %c.1 = icmp sle i32 %iv.next, %b
+  call void @use(i1 %c.1)
+  ret void
+}
+
+define void @postinc_constant_start_step4(i8 %k0, i1 %c) {
+; CHECK-LABEL: define void @postinc_constant_start_step4(
+; CHECK-SAME: i8 [[K0:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[K:%.*]] = and i8 [[K0]], 12
+; CHECK-NEXT:    [[N:%.*]] = add i8 [[K]], 4
+; CHECK-NEXT:    [[PRE:%.*]] = icmp ult i8 4, [[N]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[PRE]])
+; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
+; CHECK:       [[LOOP_HEADER]]:
+; CHECK-NEXT:    [[IV:%.*]] = phi i8 [ 4, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
+; CHECK-NEXT:    [[T:%.*]] = icmp ult i8 [[IV]], [[N]]
+; CHECK-NEXT:    call void @use(i1 [[T]])
+; CHECK-NEXT:    [[C_1:%.*]] = icmp slt i8 [[IV]], [[N]]
+; CHECK-NEXT:    call void @use(i1 [[C_1]])
+; CHECK-NEXT:    br i1 [[C]], label %[[EXIT:.*]], label %[[LOOP_LATCH]]
+; CHECK:       [[LOOP_LATCH]]:
+; CHECK-NEXT:    [[IV_NEXT]] = add i8 [[IV]], 4
+; CHECK-NEXT:    [[EC:%.*]] = icmp eq i8 [[IV_NEXT]], [[N]]
+; CHECK-NEXT:    br i1 [[EC]], label %[[EXIT]], label %[[LOOP_HEADER]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %k = and i8 %k0, 12
+  %n = add i8 %k, 4
+  %pre = icmp ult i8 4, %n
+  call void @llvm.assume(i1 %pre)
+  br label %loop.header
+
+loop.header:
+  %iv = phi i8 [ 4, %entry ], [ %iv.next, %loop.latch ]
+  %t = icmp ult i8 %iv, %n
+  call void @use(i1 %t)
+  %c.1 = icmp slt i8 %iv, %n
+  call void @use(i1 %c.1)
+  br i1 %c, label %exit, label %loop.latch
+
+loop.latch:
+  %iv.next = add i8 %iv, 4
+  %ec = icmp eq i8 %iv.next, %n
+  br i1 %ec, label %exit, label %loop.header
+
+exit:
+  ret void
+}
+
+define void @phi_compare_symbolic_start_non_strict_precondition(i32 %start, i32 %n, i1 %c) {
+; CHECK-LABEL: define void @phi_compare_symbolic_start_non_strict_precondition(
+; CHECK-SAME: i32 [[START:%.*]], i32 [[N:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[PRE:%.*]] = icmp ule i32 [[START]], [[N]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[PRE]])
+; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
+; CHECK:       [[LOOP_HEADER]]:
+; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
+; CHECK-NEXT:    [[EC:%.*]] = icmp eq i32 [[IV]], [[N]]
+; CHECK-NEXT:    br i1 [[EC]], label %[[EXIT:.*]], label %[[LOOP_LATCH]]
+; CHECK:       [[LOOP_LATCH]]:
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    [[C_0:%.*]] = icmp sge i32 [[IV]], [[START]]
+; CHECK-NEXT:    call void @use(i1 [[C_0]])
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
+; CHECK-NEXT:    br i1 [[C]], label %[[EXIT]], label %[[LOOP_HEADER]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %pre = icmp ule i32 %start, %n
+  call void @llvm.assume(i1 %pre)
+  br label %loop.header
+
+loop.header:
+  %iv = phi i32 [ %start, %entry ], [ %iv.next, %loop.latch ]
+  %ec = icmp eq i32 %iv, %n
+  br i1 %ec, label %exit, label %loop.latch
+
+loop.latch:
+  %t = icmp uge i32 %iv, %start
+  call void @use(i1 %t)
+  %c.0 = icmp sge i32 %iv, %start
+  call void @use(i1 %c.0)
+  %c.1 = icmp uge i32 %iv, %start
+  call void @use(i1 %c.1)
+  %iv.next = add i32 %iv, 1
+  br i1 %c, label %exit, label %loop.header
+
+exit:
+  ret void
+}
+
+; Test without a precondition on start value.
+define void @postinc_symbolic_start_no_precondition(i32 %start, i32 %n, i1 %c) {
+; CHECK-LABEL: define void @postinc_symbolic_start_no_precondition(
+; CHECK-SAME: i32 [[START:%.*]], i32 [[N:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
+; CHECK:       [[LOOP_HEADER]]:
+; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
+; CHECK-NEXT:    [[C_0:%.*]] = icmp ult i32 [[IV]], [[N]]
+; CHECK-NEXT:    call void @use(i1 [[C_0]])
+; CHECK-NEXT:    [[C_1:%.*]] = icmp slt i32 [[IV]], [[N]]
+; CHECK-NEXT:    call void @use(i1 [[C_1]])
+; CHECK-NEXT:    [[C_2:%.*]] = icmp ule i32 [[IV]], [[N]]
+; CHECK-NEXT:    call void @use(i1 [[C_2]])
+; CHECK-NEXT:    [[C_3:%.*]] = icmp sle i32 [[IV]], [[N]]
+; CHECK-NEXT:    call void @use(i1 [[C_3]])
+; CHECK-NEXT:    br i1 [[C]], label %[[EXIT:.*]], label %[[LOOP_LATCH]]
+; CHECK:       [[LOOP_LATCH]]:
+; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
+; CHECK-NEXT:    [[EC:%.*]] = icmp eq i32 [[IV_NEXT]], [[N]]
+; CHECK-NEXT:    br i1 [[EC]], label %[[EXIT]], label %[[LOOP_HEADER]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop.header
+
+loop.header:
+  %iv = phi i32 [ %start, %entry ], [ %iv.next, %loop.latch ]
+  %c.0 = icmp ult i32 %iv, %n
+  call void @use(i1 %c.0)
+  %c.1 = icmp slt i32 %iv, %n
+  call void @use(i1 %c.1)
+  %c.2 = icmp ule i32 %iv, %n
+  call void @use(i1 %c.2)
+  %c.3 = icmp sle i32 %iv, %n
+  call void @use(i1 %c.3)
+  br i1 %c, label %exit, label %loop.latch
+
+loop.latch:
+  %iv.next = add i32 %iv, 1
+  %ec = icmp eq i32 %iv.next, %n
+  br i1 %ec, label %exit, label %loop.header
+
+exit:
+  ret void
+}
+
+; With Start == N the post-increment steps past N and wraps.
+define void @postinc_symbolic_start_non_strict_precondition(i32 %start, i32 %n, i1 %c) {
+; CHECK-LABEL: define void @postinc_symbolic_start_non_strict_precondition(
+; CHECK-SAME: i32 [[START:%.*]], i32 [[N:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[PRE:%.*]] = icmp ule i32 [[START]], [[N]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[PRE]])
+; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
+; CHECK:       [[LOOP_HEADER]]:
+; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
+; CHECK-NEXT:    [[C_0:%.*]] = icmp ult i32 [[IV]], [[N]]
+; CHECK-NEXT:    call void @use(i1 [[C_0]])
+; CHECK-NEXT:    [[C_1:%.*]] = icmp slt i32 [[IV]], [[N]]
+; CHECK-NEXT:    call void @use(i1 [[C_1]])
+; CHECK-NEXT:    br i1 [[C]], label %[[EXIT:.*]], label %[[LOOP_LATCH]]
+; CHECK:       [[LOOP_LATCH]]:
+; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
+; CHECK-NEXT:    [[EC:%.*]] = icmp eq i32 [[IV_NEXT]], [[N]]
+; CHECK-NEXT:    br i1 [[EC]], label %[[EXIT]], label %[[LOOP_HEADER]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %pre = icmp ule i32 %start, %n
+  call void @llvm.assume(i1 %pre)
+  br label %loop.header
+
+loop.header:
+  %iv = phi i32 [ %start, %entry ], [ %iv.next, %loop.latch ]
+  %c.0 = icmp ult i32 %iv, %n
+  call void @use(i1 %c.0)
+  %c.1 = icmp slt i32 %iv, %n
+  call void @use(i1 %c.1)
+  br i1 %c, label %exit, label %loop.latch
+
+loop.latch:
+  %iv.next = add i32 %iv, 1
+  %ec = icmp eq i32 %iv.next, %n
+  br i1 %ec, label %exit, label %loop.header
+
+exit:
+  ret void
+}
+
+; A distance of 2 * %k is not a multiple of the step 4.
+define void @postinc_symbolic_start_step4_not_divisible(i32 %start, i32 %k, i1 %c) {
+; CHECK-LABEL: define void @postinc_symbolic_start_step4_not_divisible(
+; CHECK-SAME: i32 [[START:%.*]], i32 [[K:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[K_2:%.*]] = shl i32 [[K]], 1
+; CHECK-NEXT:    [[B:%.*]] = add i32 [[START]], [[K_2]]
+; CHECK-NEXT:    [[PRE:%.*]] = icmp ult i32 [[START]], [[B]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[PRE]])
+; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
+; CHECK:       [[LOOP_HEADER]]:
+; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
+; CHECK-NEXT:    [[C_0:%.*]] = icmp ult i32 [[IV]], [[B]]
+; CHECK-NEXT:    call void @use(i1 [[C_0]])
+; CHECK-NEXT:    [[C_1:%.*]] = icmp slt i32 [[IV]], [[B]]
+; CHECK-NEXT:    call void @use(i1 [[C_1]])
+; CHECK-NEXT:    [[C_2:%.*]] = icmp ule i32 [[IV]], [[B]]
+; CHECK-NEXT:    call void @use(i1 [[C_2]])
+; CHECK-NEXT:    [[C_3:%.*]] = icmp sle i32 [[IV]], [[B]]
+; CHECK-NEXT:    call void @use(i1 [[C_3]])
+; CHECK-NEXT:    br i1 [[C]], label %[[EXIT:.*]], label %[[LOOP_LATCH]]
+; CHECK:       [[LOOP_LATCH]]:
+; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 4
+; CHECK-NEXT:    [[EC:%.*]] = icmp eq i32 [[IV_NEXT]], [[B]]
+; CHECK-NEXT:    br i1 [[EC]], label %[[EXIT]], label %[[LOOP_HEADER]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %k.2 = shl i32 %k, 1
+  %b = add i32 %start, %k.2
+  %pre = icmp ult i32 %start, %b
+  call void @llvm.assume(i1 %pre)
+  br label %loop.header
+
+loop.header:
+  %iv = phi i32 [ %start, %entry ], [ %iv.next, %loop.latch ]
+  %c.0 = icmp ult i32 %iv, %b
+  call void @use(i1 %c.0)
+  %c.1 = icmp slt i32 %iv, %b
+  call void @use(i1 %c.1)
+  %c.2 = icmp ule i32 %iv, %b
+  call void @use(i1 %c.2)
+  %c.3 = icmp sle i32 %iv, %b
+  call void @use(i1 %c.3)
+  br i1 %c, label %exit, label %loop.latch
+
+loop.latch:
+  %iv.next = add i32 %iv, 4
+  %ec = icmp eq i32 %iv.next, %b
+  br i1 %ec, label %exit, label %loop.header
+
+exit:
+  ret void
+}
+
+; Currently the step must be a constant, and %k * %step may wrap.
+define void @postinc_symbolic_start_symbolic_step(i32 %start, i32 %k, i32 %step, i1 %c) {
+; CHECK-LABEL: define void @postinc_symbolic_start_symbolic_step(
+; CHECK-SAME: i32 [[START:%.*]], i32 [[K:%.*]], i32 [[STEP:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[K_STEP:%.*]] = mul i32 [[K]], [[STEP]]
+; CHECK-NEXT:    [[B:%.*]] = add i32 [[START]], [[K_STEP]]
+; CHECK-NEXT:    [[PRE:%.*]] = icmp ult i32 [[START]], [[B]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[PRE]])
+; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
+; CHECK:       [[LOOP_HEADER]]:
+; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
+; CHECK-NEXT:    [[C_0:%.*]] = icmp ult i32 [[IV]], [[B]]
+; CHECK-NEXT:    call void @use(i1 [[C_0]])
+; CHECK-NEXT:    [[C_1:%.*]] = icmp slt i32 [[IV]], [[B]]
+; CHECK-NEXT:    call void @use(i1 [[C_1]])
+; CHECK-NEXT:    [[C_2:%.*]] = icmp ule i32 [[IV]], [[B]]
+; CHECK-NEXT:    call void @use(i1 [[C_2]])
+; CHECK-NEXT:    [[C_3:%.*]] = icmp sle i32 [[IV]], [[B]]
+; CHECK-NEXT:    call void @use(i1 [[C_3]])
+; CHECK-NEXT:    br i1 [[C]], label %[[EXIT:.*]], label %[[LOOP_LATCH]]
+; CHECK:       [[LOOP_LATCH]]:
+; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], [[STEP]]
+; CHECK-NEXT:    [[EC:%.*]] = icmp eq i32 [[IV_NEXT]], [[B]]
+; CHECK-NEXT:    br i1 [[EC]], label %[[EXIT]], label %[[LOOP_HEADER]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %k.step = mul i32 %k, %step
+  %b = add i32 %start, %k.step
+  %pre = icmp ult i32 %start, %b
+  call void @llvm.assume(i1 %pre)
+  br label %loop.header
+
+loop.header:
+  %iv = phi i32 [ %start, %entry ], [ %iv.next, %loop.latch ]
+  %c.0 = icmp ult i32 %iv, %b
+  call void @use(i1 %c.0)
+  %c.1 = icmp slt i32 %iv, %b
+  call void @use(i1 %c.1)
+  %c.2 = icmp ule i32 %iv, %b
+  call void @use(i1 %c.2)
+  %c.3 = icmp sle i32 %iv, %b
+  call void @use(i1 %c.3)
+  br i1 %c, label %exit, label %loop.latch
+
+loop.latch:
+  %iv.next = add i32 %iv, %step
+  %ec = icmp eq i32 %iv.next, %b
+  br i1 %ec, label %exit, label %loop.header
+
+exit:
+  ret void
+}
+
+; Derivable with the nuw flags, but the step must be a constant.
+define void @postinc_symbolic_start_symbolic_step_nuw(i32 %start, i32 %k, i32 %step, i1 %c) {
+; CHECK-LABEL: define void @postinc_symbolic_start_symbolic_step_nuw(
+; CHECK-SAME: i32 [[START:%.*]], i32 [[K:%.*]], i32 [[STEP:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[K_STEP:%.*]] = mul nuw i32 [[K]], [[STEP]]
+; CHECK-NEXT:    [[B:%.*]] = add nuw i32 [[START]], [[K_STEP]]
+; CHECK-NEXT:    [[PRE:%.*]] = icmp ult i32 [[START]], [[B]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[PRE]])
+; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
+; CHECK:       [[LOOP_HEADER]]:
+; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
+; CHECK-NEXT:    [[C_0:%.*]] = icmp ult i32 [[IV]], [[B]]
+; CHECK-NEXT:    call void @use(i1 [[C_0]])
+; CHECK-NEXT:    [[C_1:%.*]] = icmp slt i32 [[IV]], [[B]]
+; CHECK-NEXT:    call void @use(i1 [[C_1]])
+; CHECK-NEXT:    [[C_2:%.*]] = icmp ule i32 [[IV]], [[B]]
+; CHECK-NEXT:    call void @use(i1 [[C_2]])
+; CHECK-NEXT:    [[C_3:%.*]] = icmp sle i32 [[IV]], [[B]]
+; CHECK-NEXT:    call void @use(i1 [[C_3]])
+; CHECK-NEXT:    br i1 [[C]], label %[[EXIT:.*]], label %[[LOOP_LATCH]]
+; CHECK:       [[LOOP_LATCH]]:
+; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], [[STEP]]
+; CHECK-NEXT:    [[EC:%.*]] = icmp eq i32 [[IV_NEXT]], [[B]]
+; CHECK-NEXT:    br i1 [[EC]], label %[[EXIT]], label %[[LOOP_HEADER]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %k.step = mul nuw i32 %k, %step
+  %b = add nuw i32 %start, %k.step
+  %pre = icmp ult i32 %start, %b
+  call void @llvm.assume(i1 %pre)
+  br label %loop.header
+
+loop.header:
+  %iv = phi i32 [ %start, %entry ], [ %iv.next, %loop.latch ]
+  %c.0 = icmp ult i32 %iv, %b
+  call void @use(i1 %c.0)
+  %c.1 = icmp slt i32 %iv, %b
+  call void @use(i1 %c.1)
+  %c.2 = icmp ule i32 %iv, %b
+  call void @use(i1 %c.2)
+  %c.3 = icmp sle i32 %iv, %b
+  call void @use(i1 %c.3)
+  br i1 %c, label %exit, label %loop.latch
+
+loop.latch:
+  %iv.next = add i32 %iv, %step
+  %ec = icmp eq i32 %iv.next, %b
+  br i1 %ec, label %exit, label %loop.header
+
+exit:
+  ret void
+}
+
+; TODO: Header == Latch form not supported yet.
+define void @postinc_symbolic_start_header_is_latch(i32 %start, i32 %n) {
+; CHECK-LABEL: define void @postinc_symbolic_start_header_is_latch(
+; CHECK-SAME: i32 [[START:%.*]], i32 [[N:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[PRE:%.*]] = icmp ult i32 [[START]], [[N]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[PRE]])
+; CHECK-NEXT:    br label %[[LOOP:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
+; CHECK-NEXT:    [[T:%.*]] = icmp ult i32 [[IV]], [[N]]
+; CHECK-NEXT:    call void @use(i1 [[T]])
+; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
+; CHECK-NEXT:    [[EC:%.*]] = icmp eq i32 [[IV_NEXT]], [[N]]
+; CHECK-NEXT:    br i1 [[EC]], label %[[EXIT:.*]], label %[[LOOP]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %pre = icmp ult i32 %start, %n
+  call void @llvm.assume(i1 %pre)
+  br label %loop
+
+loop:
+  %iv = phi i32 [ %start, %entry ], [ %iv.next, %loop ]
+  %t = icmp ult i32 %iv, %n
+  call void @use(i1 %t)
+  %iv.next = add i32 %iv, 1
+  %ec = icmp eq i32 %iv.next, %n
+  br i1 %ec, label %exit, label %loop
+
+exit:
+  ret void
+}
+
+define void @phi_compare_symbolic_start_header_is_latch(i32 %start, i32 %n) {
+; CHECK-LABEL: define void @phi_compare_symbolic_start_header_is_latch(
+; CHECK-SAME: i32 [[START:%.*]], i32 [[N:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[PRE:%.*]] = icmp ule i32 [[START]], [[N]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[PRE]])
+; CHECK-NEXT:    br label %[[LOOP:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
+; CHECK-NEXT:    [[C_0:%.*]] = icmp ult i32 [[IV]], [[N]]
+; CHECK-NEXT:    call void @use(i1 [[C_0]])
+; CHECK-NEXT:    [[C_1:%.*]] = icmp slt i32 [[IV]], [[N]]
+; CHECK-NEXT:    call void @use(i1 [[C_1]])
+; CHECK-NEXT:    [[C_2:%.*]] = icmp ule i32 [[IV]], [[N]]
+; CHECK-NEXT:    call void @use(i1 [[C_2]])
+; CHECK-NEXT:    [[C_3:%.*]] = icmp sle i32 [[IV]], [[N]]
+; CHECK-NEXT:    call void @use(i1 [[C_3]])
+; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
+; CHECK-NEXT:    [[EC:%.*]] = icmp eq i32 [[IV]], [[N]]
+; CHECK-NEXT:    br i1 [[EC]], label %[[EXIT:.*]], label %[[LOOP]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %pre = icmp ule i32 %start, %n
+  call void @llvm.assume(i1 %pre)
+  br label %loop
+
+loop:
+  %iv = phi i32 [ %start, %entry ], [ %iv.next, %loop ]
+  %c.0 = icmp ult i32 %iv, %n
+  call void @use(i1 %c.0)
+  %c.1 = icmp slt i32 %iv, %n
+  call void @use(i1 %c.1)
+  %c.2 = icmp ule i32 %iv, %n
+  call void @use(i1 %c.2)
+  %c.3 = icmp sle i32 %iv, %n
+  call void @use(i1 %c.3)
+  %iv.next = add i32 %iv, 1
+  %ec = icmp eq i32 %iv, %n
+  br i1 %ec, label %exit, label %loop
+
+exit:
+  ret void
+}

>From cab11eee371ed0144f2b80536ad728e909d85957 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 1 Sep 2026 11:07:42 +0100
Subject: [PATCH 2/2] [ConstraintElim] Allow a non-constant start values in
 addInfoForInduct.

Generalize the logic to add bounds for IVs with symbolic start values.

At this point we are adding bounds for an exiting condition of the form
'(PN + Step) Pred B', where Pred is either NE or EQ, and have already
established that B - Start is a multiple of the induction step. Hence
Start < B implies Start + Step <= B, and the loop exits at
PN + Step == B before PN wraps.

So there is no need to check if Start + Step wraps separately, as long as
we use a strict predicate for the Start < B precondition.

This enables additional simplifications in a number of cases:
https://github.com/dtcxzyw/llvm-opt-benchmark-nightly/pull/1159

Compile-time impact is in the noise:
https://llvm-compile-time-tracker.com/compare.php?from=b5eb118e0426552dfddf1fa65e002842326b0a8a&to=660f01002fd5f767cade3ba245201558a65d0db0&stat=instructions:u

Alive2 Proofs: https://alive2.llvm.org/ce/z/iuLsTc
---
 .../Scalar/ConstraintElimination.cpp          | 56 ++++++++-----------
 .../induction-symbolic-start-postinc.ll       | 21 +++----
 2 files changed, 29 insertions(+), 48 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 86d4c5f918076..2bf3e83fa15df 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -1209,41 +1209,29 @@ void State::addInfoForInductions(BasicBlock &BB) {
       return;
   }
 
-  Value *LowerBound = StartValue;
-  bool LowerBoundNUW = true, LowerBoundNSW = true;
-  if (IncStep) {
-    auto *StartC = dyn_cast<ConstantInt>(StartValue);
-    if (!StartC)
-      return;
-    bool UOverflow = false, SOverflow = false;
-    APInt Sum = StartC->getValue().uadd_ov(*StepOffset, UOverflow);
-    (void)StartC->getValue().sadd_ov(*StepOffset, SOverflow);
-    LowerBound = ConstantInt::get(StartValue->getType(), Sum);
-    LowerBoundNUW = !UOverflow;
-    LowerBoundNSW = !SOverflow;
-  }
-
-  // AR may wrap. Add PN >= StartValue conditional on LowerBound <= B, which
-  // guarantees that the loop exits before wrapping in combination with the
-  // restrictions on B and the step above.
-  ConditionTy StartBeforeBoundULE = {CmpInst::ICMP_ULE, LowerBound, B};
-  ConditionTy StartBeforeBoundSLE = {CmpInst::ICMP_SLE, LowerBound, B};
-  if (!Info.Unsigned && LowerBoundNUW)
+  // We already established that B - Start is a multiple of Step above. The loop
+  // exits once the compared value reaches B, that is at PN == B when comparing
+  // the phi, and at PN + Step == B for a post-increment. Together with the
+  // added precondition StartValue <= B for the former and the strict
+  // StartValue < B for the latter (which implies StartValue + Step <= B),
+  // neither PN nor the increment can wrap.
+  CmpInst::Predicate UPrecond = IncStep ? CmpInst::ICMP_ULT : CmpInst::ICMP_ULE;
+  ConditionTy StartBeforeBoundUnsigned = {UPrecond, StartValue, B};
+  ConditionTy StartBeforeBoundSigned = {ICmpInst::getSignedPredicate(UPrecond),
+                                        StartValue, B};
+
+  // Add PN >= StartValue, as the loop exits before wrapping.
+  if (!Info.Unsigned)
     WorkList.push_back(FactOrCheck::getConditionFact(
-        DTN, CmpInst::ICMP_UGE, PN, StartValue, StartBeforeBoundULE));
-  if (!Info.Signed && LowerBoundNSW)
+        DTN, CmpInst::ICMP_UGE, PN, StartValue, StartBeforeBoundUnsigned));
+  if (!Info.Signed)
     WorkList.push_back(FactOrCheck::getConditionFact(
-        DTN, CmpInst::ICMP_SGE, PN, StartValue, StartBeforeBoundSLE));
-
-  if (LowerBoundNSW)
-    WorkList.push_back(FactOrCheck::getConditionFact(DTN, CmpInst::ICMP_SLT, PN,
-                                                     B, StartBeforeBoundSLE));
-
-  if (!LowerBoundNUW)
-    return;
-
-  WorkList.push_back(FactOrCheck::getConditionFact(DTN, CmpInst::ICMP_ULT, PN,
-                                                   B, StartBeforeBoundULE));
+        DTN, CmpInst::ICMP_SGE, PN, StartValue, StartBeforeBoundSigned));
+  // Add PN < B, as the loop exits once the compared value reaches B.
+  WorkList.push_back(FactOrCheck::getConditionFact(DTN, CmpInst::ICMP_SLT, PN,
+                                                   B, StartBeforeBoundSigned));
+  WorkList.push_back(FactOrCheck::getConditionFact(
+      DTN, CmpInst::ICMP_ULT, PN, B, StartBeforeBoundUnsigned));
 
   // Try to add condition from the header or latch to the dedicated exit
   // blocks. When exiting either with EQ or NE, we know that the induction value
@@ -1256,7 +1244,7 @@ void State::addInfoForInductions(BasicBlock &BB) {
     // Bail out on non-dedicated exits.
     if (DT.dominates(&BB, EB)) {
       WorkList.emplace_back(FactOrCheck::getConditionFact(
-          DT.getNode(EB), CmpInst::ICMP_ULE, A, B, StartBeforeBoundULE));
+          DT.getNode(EB), CmpInst::ICMP_ULE, A, B, StartBeforeBoundUnsigned));
     }
   }
 }
diff --git a/llvm/test/Transforms/ConstraintElimination/induction-symbolic-start-postinc.ll b/llvm/test/Transforms/ConstraintElimination/induction-symbolic-start-postinc.ll
index 7a5763f4747c7..d509e95fe8bcb 100644
--- a/llvm/test/Transforms/ConstraintElimination/induction-symbolic-start-postinc.ll
+++ b/llvm/test/Transforms/ConstraintElimination/induction-symbolic-start-postinc.ll
@@ -13,10 +13,8 @@ define void @postinc_symbolic_start_unsigned(i32 %start, i32 %n, i1 %c) {
 ; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
 ; CHECK:       [[LOOP_HEADER]]:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
-; CHECK-NEXT:    [[T:%.*]] = icmp ult i32 [[IV]], [[N]]
-; CHECK-NEXT:    call void @use(i1 [[T]])
-; CHECK-NEXT:    [[T_2:%.*]] = icmp uge i32 [[IV]], [[START]]
-; CHECK-NEXT:    call void @use(i1 [[T_2]])
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp slt i32 [[IV]], [[N]]
 ; CHECK-NEXT:    call void @use(i1 [[C_1]])
 ; CHECK-NEXT:    [[C_2:%.*]] = icmp sge i32 [[IV]], [[START]]
@@ -65,10 +63,8 @@ define void @postinc_symbolic_start_signed(i32 %start, i32 %n, i1 %c) {
 ; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
 ; CHECK:       [[LOOP_HEADER]]:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
-; CHECK-NEXT:    [[T:%.*]] = icmp slt i32 [[IV]], [[N]]
-; CHECK-NEXT:    call void @use(i1 [[T]])
-; CHECK-NEXT:    [[T_2:%.*]] = icmp sge i32 [[IV]], [[START]]
-; CHECK-NEXT:    call void @use(i1 [[T_2]])
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ult i32 [[IV]], [[N]]
 ; CHECK-NEXT:    call void @use(i1 [[C_1]])
 ; CHECK-NEXT:    [[C_2:%.*]] = icmp uge i32 [[IV]], [[START]]
@@ -119,8 +115,7 @@ define void @postinc_symbolic_start_step4(i32 %start, i32 %k, i1 %c) {
 ; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
 ; CHECK:       [[LOOP_HEADER]]:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
-; CHECK-NEXT:    [[T:%.*]] = icmp ult i32 [[IV]], [[B]]
-; CHECK-NEXT:    call void @use(i1 [[T]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    br i1 [[C]], label %[[EXIT:.*]], label %[[LOOP_LATCH]]
 ; CHECK:       [[LOOP_LATCH]]:
 ; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 4
@@ -169,8 +164,7 @@ define void @postinc_symbolic_start_exit_block(i32 %start, i32 %k, i1 %c) {
 ; CHECK:       [[LOOP_LATCH]]:
 ; CHECK-NEXT:    br i1 [[C]], label %[[EXIT]], label %[[LOOP_HEADER]]
 ; CHECK:       [[EXIT]]:
-; CHECK-NEXT:    [[T:%.*]] = icmp ule i32 [[IV_NEXT]], [[B]]
-; CHECK-NEXT:    call void @use(i1 [[T]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp sle i32 [[IV_NEXT]], [[B]]
 ; CHECK-NEXT:    call void @use(i1 [[C_1]])
 ; CHECK-NEXT:    ret void
@@ -210,8 +204,7 @@ define void @postinc_constant_start_step4(i8 %k0, i1 %c) {
 ; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
 ; CHECK:       [[LOOP_HEADER]]:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i8 [ 4, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
-; CHECK-NEXT:    [[T:%.*]] = icmp ult i8 [[IV]], [[N]]
-; CHECK-NEXT:    call void @use(i1 [[T]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp slt i8 [[IV]], [[N]]
 ; CHECK-NEXT:    call void @use(i1 [[C_1]])
 ; CHECK-NEXT:    br i1 [[C]], label %[[EXIT:.*]], label %[[LOOP_LATCH]]



More information about the llvm-commits mailing list