[llvm] 9fcc880 - [ConstraintElim] Support loops where header is also latch. (#221494)

via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 7 04:56:38 PDT 2026


Author: Florian Hahn
Date: 2026-09-07T11:56:32Z
New Revision: 9fcc880e5a724c7fb95b646595eb081033a601d7

URL: https://github.com/llvm/llvm-project/commit/9fcc880e5a724c7fb95b646595eb081033a601d7
DIFF: https://github.com/llvm/llvm-project/commit/9fcc880e5a724c7fb95b646595eb081033a601d7.diff

LOG: [ConstraintElim] Support loops where header is also latch. (#221494)

Remove the bail out for header == latch. We now support deriving facts
from the latch condition and the restriction is no longer necessary.

This enables inferring additional flags in a number of cases, and a few
additional folds in practice:
https://github.com/dtcxzyw/llvm-opt-benchmark-nightly/pull/1200.

It also removes a surprising limitation when writing manual tests.

PR: https://github.com/llvm/llvm-project/pull/221494

Added: 
    

Modified: 
    llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
    llvm/test/Transforms/ConstraintElimination/induction-condition-in-loop-exit-postinc.ll
    llvm/test/Transforms/ConstraintElimination/induction-relational-predicate-latch.ll
    llvm/test/Transforms/ConstraintElimination/induction-symbolic-start-postinc.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 26b9ad4073dfe..58f8dbb425b9d 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -1127,7 +1127,7 @@ void State::addInfoForInductions(BasicBlock &BB) {
   if (PeeledOnEdge && *PeeledOnEdge != ContinueOnTrue)
     return;
 
-  if (!L->contains(InLoopSucc) || !L->isLoopExiting(&BB) || InLoopSucc == &BB)
+  if (!L->contains(InLoopSucc) || !L->isLoopExiting(&BB))
     return;
 
   BasicBlock *LoopPred = L->getLoopPredecessor();

diff  --git a/llvm/test/Transforms/ConstraintElimination/induction-condition-in-loop-exit-postinc.ll b/llvm/test/Transforms/ConstraintElimination/induction-condition-in-loop-exit-postinc.ll
index 1fa5344c9911d..44741db16af6d 100644
--- a/llvm/test/Transforms/ConstraintElimination/induction-condition-in-loop-exit-postinc.ll
+++ b/llvm/test/Transforms/ConstraintElimination/induction-condition-in-loop-exit-postinc.ll
@@ -711,6 +711,44 @@ exit:
   ret void
 }
 
+; Same as @latch_postdec_negative_step_folds, but the header is also to latch.
+define void @latch_postdec_negative_step_header_is_latch() {
+; CHECK-LABEL: define void @latch_postdec_negative_step_header_is_latch() {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    br label %[[LOOP:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[IV:%.*]] = phi i8 [ 5, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    [[IV_NEXT]] = add i8 [[IV]], -1
+; CHECK-NEXT:    [[EC:%.*]] = icmp eq i8 [[IV_NEXT]], 2
+; CHECK-NEXT:    br i1 [[EC]], label %[[EXIT:.*]], label %[[LOOP]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop
+
+loop:
+  %iv = phi i8 [ 5, %entry ], [ %iv.next, %loop ]
+  %ugt = icmp ugt i8 %iv, 2
+  call void @use(i1 %ugt)
+  %ule = icmp ule i8 %iv, 5
+  call void @use(i1 %ule)
+  %sgt = icmp sgt i8 %iv, 2
+  call void @use(i1 %sgt)
+  %sle = icmp sle i8 %iv, 5
+  call void @use(i1 %sle)
+  %iv.next = add i8 %iv, -1
+  %ec = icmp eq i8 %iv.next, 2
+  br i1 %ec, label %exit, label %loop
+
+exit:
+  ret void
+}
+
 ; B == StartValue for a latch post-decrement compare: %iv never reaches
 ; B + 1 == 6 before wrapping around the whole range, so nothing must be folded.
 ; The first iteration alone already has %iv == B.

diff  --git a/llvm/test/Transforms/ConstraintElimination/induction-relational-predicate-latch.ll b/llvm/test/Transforms/ConstraintElimination/induction-relational-predicate-latch.ll
index abb3648b34ed6..803679831b988 100644
--- a/llvm/test/Transforms/ConstraintElimination/induction-relational-predicate-latch.ll
+++ b/llvm/test/Transforms/ConstraintElimination/induction-relational-predicate-latch.ll
@@ -128,8 +128,7 @@ define void @stride2_slt_header_is_latch(i64 %n) {
 ; CHECK-NEXT:    br label %[[LOOP:.*]]
 ; CHECK:       [[LOOP]]:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[C:%.*]] = icmp slt i64 [[IV]], [[N]]
-; CHECK-NEXT:    call void @use(i1 [[C]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[IV_NEXT]] = add nsw i64 [[IV]], 2
 ; CHECK-NEXT:    [[EC:%.*]] = icmp slt i64 [[IV_NEXT]], [[N]]
 ; CHECK-NEXT:    br i1 [[EC]], label %[[LOOP]], label %[[EXIT:.*]]

diff  --git a/llvm/test/Transforms/ConstraintElimination/induction-symbolic-start-postinc.ll b/llvm/test/Transforms/ConstraintElimination/induction-symbolic-start-postinc.ll
index d509e95fe8bcb..6fbf5942a4d5c 100644
--- a/llvm/test/Transforms/ConstraintElimination/induction-symbolic-start-postinc.ll
+++ b/llvm/test/Transforms/ConstraintElimination/induction-symbolic-start-postinc.ll
@@ -544,7 +544,6 @@ 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:%.*]]) {
@@ -554,8 +553,7 @@ define void @postinc_symbolic_start_header_is_latch(i32 %start, i32 %n) {
 ; 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:    call void @use(i1 true)
 ; 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]]
@@ -624,3 +622,40 @@ loop:
 exit:
   ret void
 }
+
+; The facts derived from the header/latch also hold in the exit block.
+define void @postinc_symbolic_start_header_is_latch_exit_block(i32 %start, i32 %n) {
+; CHECK-LABEL: define void @postinc_symbolic_start_header_is_latch_exit_block(
+; 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:    [[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:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 true)
+; 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 ]
+  %iv.next = add i32 %iv, 1
+  %ec = icmp eq i32 %iv.next, %n
+  br i1 %ec, label %exit, label %loop
+
+exit:
+  %t = icmp ult i32 %iv, %n
+  call void @use(i1 %t)
+  %c.1 = icmp ule i32 %iv.next, %n
+  call void @use(i1 %c.1)
+  ret void
+}


        


More information about the llvm-commits mailing list