[Mlir-commits] [mlir] [mlir][scf] Fix front peeling skipped due to float rounding in trip count (PR #231100)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Mon Oct 12 22:27:05 PDT 2026


https://github.com/StarOne01 updated https://github.com/llvm/llvm-project/pull/231100

>From 83a4ade9d59187188a242920bb51133597f94963 Mon Sep 17 00:00:00 2001
From: Prashanth <ping at starone01.me>
Date: Mon, 12 Oct 2026 14:27:42 +0530
Subject: [PATCH 1/4] [mlir][scf] Fix front peeling skipped due to float
 rounding in trip count

---
 .../SCF/Transforms/LoopSpecialization.cpp     |  2 +-
 .../Dialect/SCF/for-loop-peeling-front.mlir   | 33 +++++++++++++++++++
 2 files changed, 34 insertions(+), 1 deletion(-)

diff --git a/mlir/lib/Dialect/SCF/Transforms/LoopSpecialization.cpp b/mlir/lib/Dialect/SCF/Transforms/LoopSpecialization.cpp
index 685c57319a216..d0719643603c9 100644
--- a/mlir/lib/Dialect/SCF/Transforms/LoopSpecialization.cpp
+++ b/mlir/lib/Dialect/SCF/Transforms/LoopSpecialization.cpp
@@ -239,7 +239,7 @@ LogicalResult mlir::scf::peelForLoopFirstIteration(RewriterBase &b, ForOp forOp,
   auto stepInt = getConstantIntValue(forOp.getStep());
 
   // Peeling is not needed if there is one or less iteration.
-  if (lbInt && ubInt && stepInt && ceil(float(*ubInt - *lbInt) / *stepInt) <= 1)
+  if (lbInt && ubInt && stepInt && *ubInt - *lbInt <= *stepInt)
     return failure();
 
   // The peeling bound (%lb + %step) is computed with affine.apply, which
diff --git a/mlir/test/Dialect/SCF/for-loop-peeling-front.mlir b/mlir/test/Dialect/SCF/for-loop-peeling-front.mlir
index ec91e4def6484..0eba57e5af771 100644
--- a/mlir/test/Dialect/SCF/for-loop-peeling-front.mlir
+++ b/mlir/test/Dialect/SCF/for-loop-peeling-front.mlir
@@ -242,3 +242,36 @@ func.func @non_index_loop_bounds(%init: i32, %lb: i32, %n: i32) -> i32 {
   }
   return %r : i32
 }
+
+// -----
+
+// Tests loops with constant bounds where the step and (upper bound - lower bound) are
+// very close, so `ceil(float(ub - lb) / step)` used to round to 1, and the front peeling
+// was skipped. See https://github.com/llvm/llvm-project/issues/231062
+
+// CHECK-LABEL:   func.func @peel_front_step_near_ub(
+// CHECK-SAME:                                         %[[MEMREF:[^:]*]]: memref<2xindex>) {
+// CHECK-DAG:       %[[C0:.*]] = arith.constant 0 : index
+// CHECK-DAG:       %[[C16777216:.*]] = arith.constant 16777216 : index
+// CHECK-DAG:       %[[C16777217:.*]] = arith.constant 16777217 : index
+// CHECK:           scf.for %[[IV0:.*]] = %[[C0]] to %[[C16777216]] step %[[C16777216]] {
+// CHECK:             %[[SLOT0:.*]] = arith.divui %[[IV0]], %[[C16777216]] : index
+// CHECK:             memref.store %[[IV0]], %[[MEMREF]][%[[SLOT0]]] : memref<2xindex>
+// CHECK:           }
+// CHECK:           scf.for %[[IV1:.*]] = %[[C16777216]] to %[[C16777217]] step %[[C16777216]] {
+// CHECK:             %[[SLOT1:.*]] = arith.divui %[[IV1]], %[[C16777216]] : index
+// CHECK:             memref.store %[[IV1]], %[[MEMREF]][%[[SLOT1]]] : memref<2xindex>
+// CHECK:           }
+// CHECK:           return
+
+func.func @peel_front_step_near_ub(%out: memref<2xindex>) {
+  %c0 = arith.constant 0 : index
+  %step = arith.constant 16777216 : index
+  %ub = arith.constant 16777217 : index
+
+  scf.for %i = %c0 to %ub step %step {
+    %slot = arith.divui %i, %step : index
+    memref.store %i, %out[%slot] : memref<2xindex>
+  }
+  return
+}
\ No newline at end of file

>From 961d8daaa759a8c0a6886cd3a8e0d8e9602d7a75 Mon Sep 17 00:00:00 2001
From: Prashanth <ping at starone01.me>
Date: Mon, 12 Oct 2026 14:36:04 +0530
Subject: [PATCH 2/4] [mlir][scf] add newline at end of file in
 for-loop-peeling-front.mlir

---
 mlir/test/Dialect/SCF/for-loop-peeling-front.mlir | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mlir/test/Dialect/SCF/for-loop-peeling-front.mlir b/mlir/test/Dialect/SCF/for-loop-peeling-front.mlir
index 0eba57e5af771..84b561a8571f6 100644
--- a/mlir/test/Dialect/SCF/for-loop-peeling-front.mlir
+++ b/mlir/test/Dialect/SCF/for-loop-peeling-front.mlir
@@ -274,4 +274,4 @@ func.func @peel_front_step_near_ub(%out: memref<2xindex>) {
     memref.store %i, %out[%slot] : memref<2xindex>
   }
   return
-}
\ No newline at end of file
+}

>From 12436849c6fa632341c6499f11e4472bba4b8b25 Mon Sep 17 00:00:00 2001
From: Prashanth <ping at starone01.me>
Date: Tue, 13 Oct 2026 10:52:44 +0530
Subject: [PATCH 3/4] [mlir][scf] add comments explaining how the new
 implementation figures whether there is more than one iteration

---
 mlir/lib/Dialect/SCF/Transforms/LoopSpecialization.cpp | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/mlir/lib/Dialect/SCF/Transforms/LoopSpecialization.cpp b/mlir/lib/Dialect/SCF/Transforms/LoopSpecialization.cpp
index d0719643603c9..e46b588a2f124 100644
--- a/mlir/lib/Dialect/SCF/Transforms/LoopSpecialization.cpp
+++ b/mlir/lib/Dialect/SCF/Transforms/LoopSpecialization.cpp
@@ -238,7 +238,12 @@ LogicalResult mlir::scf::peelForLoopFirstIteration(RewriterBase &b, ForOp forOp,
   auto ubInt = getConstantIntValue(forOp.getUpperBound());
   auto stepInt = getConstantIntValue(forOp.getStep());
 
-  // Peeling is not needed if there is one or less iteration.
+  // Peeling is not needed if there is at most one iteration. 
+  // Per the scf.for semantics, the trip count is
+  // max(0, ceil((UB - LB) / Step)), so for a positive step there is more than
+  // one iteration exactly when UB - LB > Step. 
+  // Compare the integers directly: going through float is lossy and wrongly skipped
+  // peeling of loops with two iterations.
   if (lbInt && ubInt && stepInt && *ubInt - *lbInt <= *stepInt)
     return failure();
 

>From 40d93499a6a1717cf14883e79fd0a0a053b945e3 Mon Sep 17 00:00:00 2001
From: Prashanth <ping at starone01.me>
Date: Tue, 13 Oct 2026 10:56:46 +0530
Subject: [PATCH 4/4] [mlir][scf] format comments explaining how the new
 implementation figures whether there is more than one iteration

---
 mlir/lib/Dialect/SCF/Transforms/LoopSpecialization.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/mlir/lib/Dialect/SCF/Transforms/LoopSpecialization.cpp b/mlir/lib/Dialect/SCF/Transforms/LoopSpecialization.cpp
index e46b588a2f124..70e37a3868548 100644
--- a/mlir/lib/Dialect/SCF/Transforms/LoopSpecialization.cpp
+++ b/mlir/lib/Dialect/SCF/Transforms/LoopSpecialization.cpp
@@ -238,12 +238,12 @@ LogicalResult mlir::scf::peelForLoopFirstIteration(RewriterBase &b, ForOp forOp,
   auto ubInt = getConstantIntValue(forOp.getUpperBound());
   auto stepInt = getConstantIntValue(forOp.getStep());
 
-  // Peeling is not needed if there is at most one iteration. 
+  // Peeling is not needed if there is at most one iteration.
   // Per the scf.for semantics, the trip count is
   // max(0, ceil((UB - LB) / Step)), so for a positive step there is more than
-  // one iteration exactly when UB - LB > Step. 
-  // Compare the integers directly: going through float is lossy and wrongly skipped
-  // peeling of loops with two iterations.
+  // one iteration exactly when UB - LB > Step.
+  // Compare the integers directly: going through float is lossy and wrongly
+  // skipped peeling of loops with two iterations.
   if (lbInt && ubInt && stepInt && *ubInt - *lbInt <= *stepInt)
     return failure();
 



More information about the Mlir-commits mailing list