[Mlir-commits] [mlir] a7bf249 - [mlir][IntRangeAnalysis] Fix assertion in inferAffineExpr for mod with range crossing modulus boundary (#188842)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Fri Apr 3 01:15:57 PDT 2026
Author: Zhewen Yu
Date: 2026-04-03T10:15:52+02:00
New Revision: a7bf24919f879fed809b16bff33623d821b11226
URL: https://github.com/llvm/llvm-project/commit/a7bf24919f879fed809b16bff33623d821b11226
DIFF: https://github.com/llvm/llvm-project/commit/a7bf24919f879fed809b16bff33623d821b11226.diff
LOG: [mlir][IntRangeAnalysis] Fix assertion in inferAffineExpr for mod with range crossing modulus boundary (#188842)
The "small range with constant divisor" optimization in
`inferAffineExpr` for `AffineExprKind::Mod` assumed that if the dividend
range span (`lhsMax - lhsMin`) is less than the divisor, then the mod
results form a contiguous range. This is not always true, as the range
can straddle a modulus boundary.
For example, `[14, 17] mod 8`:
- Span is 3 < 8, so the old condition passed
- But `14%8=6` and `17%8=1` (wraps at 16)
- `umin=6, umax=1` → assertion `umin.ule(umax)` fails
The fix adds a same-quotient check (`lhsMin/rhs == lhsMax/rhs`) to
ensure both endpoints fall within the same modular period. When they
don't, we fall back to the conservative `[0, divisor-1]` range.
Assisted-by: Cursor (Claude)
Signed-off-by: Yu-Zhewen <zhewenyu at amd.com>
Added:
Modified:
mlir/lib/Interfaces/Utils/InferIntRangeCommon.cpp
mlir/test/Dialect/Affine/int-range-interface.mlir
Removed:
################################################################################
diff --git a/mlir/lib/Interfaces/Utils/InferIntRangeCommon.cpp b/mlir/lib/Interfaces/Utils/InferIntRangeCommon.cpp
index 21f07ddce4495..c9f49fda726e7 100644
--- a/mlir/lib/Interfaces/Utils/InferIntRangeCommon.cpp
+++ b/mlir/lib/Interfaces/Utils/InferIntRangeCommon.cpp
@@ -854,12 +854,14 @@ mlir::intrange::inferAffineExpr(AffineExpr expr,
umax = lhsMax;
}
// Special case: sweeping out a contiguous range with constant divisor.
- // Only applies when dividend is non-negative to ensure result range is
- // contiguous.
+ // Only applies when dividend is non-negative and the range does not
+ // cross a modulus boundary (same quotient), ensuring contiguity.
else if (rhsMin == rhsMax && lhsMin.isNonNegative() &&
- (lhsMax - lhsMin).ult(rhsMax)) {
- // For non-negative dividends, Euclidean mod is same as unsigned
- // remainder.
+ (lhsMax - lhsMin).ult(rhsMax) &&
+ lhsMin.udiv(rhsMax) == lhsMax.udiv(rhsMax)) {
+ // For non-negative dividends within the same modular period,
+ // Euclidean mod is same as unsigned remainder and the result is
+ // contiguous.
umin = lhsMin.urem(rhsMax);
umax = lhsMax.urem(rhsMax);
// Result should be contiguous since we're not wrapping around.
diff --git a/mlir/test/Dialect/Affine/int-range-interface.mlir b/mlir/test/Dialect/Affine/int-range-interface.mlir
index ca8df8a9e5788..ac64ad09ee244 100644
--- a/mlir/test/Dialect/Affine/int-range-interface.mlir
+++ b/mlir/test/Dialect/Affine/int-range-interface.mlir
@@ -147,6 +147,18 @@ func.func @affine_apply_mod_variable_divisor() -> index {
func.return %1 : index
}
+// CHECK-LABEL: func @affine_apply_mod_cross_boundary
+// CHECK: test.reflect_bounds {smax = 7 : index, smin = 0 : index, umax = 7 : index, umin = 0 : index}
+func.func @affine_apply_mod_cross_boundary() -> index {
+ %d0 = test.with_bounds { umin = 14 : index, umax = 17 : index,
+ smin = 14 : index, smax = 17 : index } : index
+ // Range [14, 17] spans a mod-8 boundary (at 16): 14%8=6, 17%8=1.
+ // Span 3 < 8 but the range wraps, so we fall back to [0, 7].
+ %0 = affine.apply affine_map<(d0) -> (d0 mod 8)>(%d0)
+ %1 = test.reflect_bounds %0 : index
+ func.return %1 : index
+}
+
// CHECK-LABEL: func @affine_apply_mod_negative_dividend
// CHECK: test.reflect_bounds {smax = 3 : index, smin = 0 : index, umax = 3 : index, umin = 0 : index}
func.func @affine_apply_mod_negative_dividend() -> index {
More information about the Mlir-commits
mailing list