[Mlir-commits] [mlir] [mlir][arith] Handle unsigned moduli in int-range optimizations (PR #224933)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Sun Sep 20 07:21:06 PDT 2026


https://github.com/Michael-Chen-NJU created https://github.com/llvm/llvm-project/pull/224933

`DeleteTrivialRem` reads constant moduli as signed values, causing `remui` operations with sign-bit-set moduli to be rejected. Keep the modulus as an `APInt` and apply signedness according to the remainder operation.

Fixes #224630

>From 61cc86ee4678ac6f4a872b67ba38c2e8f774fa15 Mon Sep 17 00:00:00 2001
From: Michael-Chen-NJU <2802328816 at qq.com>
Date: Sun, 20 Sep 2026 22:07:15 +0800
Subject: [PATCH] [mlir][arith] Handle unsigned moduli in int-range
 optimizations

---
 .../Transforms/IntRangeOptimizations.cpp      | 25 +++++++++++--------
 mlir/test/Dialect/Arith/int-range-opts.mlir   | 25 +++++++++++++++++++
 2 files changed, 39 insertions(+), 11 deletions(-)

diff --git a/mlir/lib/Dialect/Arith/Transforms/IntRangeOptimizations.cpp b/mlir/lib/Dialect/Arith/Transforms/IntRangeOptimizations.cpp
index 8d2da09969afe..0ffd87701cdae 100644
--- a/mlir/lib/Dialect/Arith/Transforms/IntRangeOptimizations.cpp
+++ b/mlir/lib/Dialect/Arith/Transforms/IntRangeOptimizations.cpp
@@ -18,7 +18,6 @@
 #include "mlir/Analysis/DataFlow/DeadCodeAnalysis.h"
 #include "mlir/Analysis/DataFlow/IntegerRangeAnalysis.h"
 #include "mlir/Dialect/Arith/IR/Arith.h"
-#include "mlir/Dialect/Utils/StaticValueUtils.h"
 #include "mlir/IR/IRMapping.h"
 #include "mlir/IR/Matchers.h"
 #include "mlir/IR/PatternMatch.h"
@@ -211,23 +210,27 @@ struct DeleteTrivialRem : public OpRewritePattern<RemOp> {
                                 PatternRewriter &rewriter) const override {
     Value lhs = op.getOperand(0);
     Value rhs = op.getOperand(1);
-    auto maybeModulus = getConstantIntValue(rhs);
-    if (!maybeModulus.has_value())
-      return failure();
-    int64_t modulus = *maybeModulus;
-    if (modulus <= 0)
+    APInt modulus;
+    bool isUnsigned = isa<RemUIOp>(op);
+    // Any nonzero bit pattern is a valid unsigned modulus. Keep the existing
+    // positive-modulus restriction for signed remainder.
+    if (!matchPattern(rhs, m_ConstantInt(&modulus)) || modulus.isZero() ||
+        (!isUnsigned && modulus.isNegative()))
       return failure();
     auto *maybeLhsRange = solver.lookupState<IntegerValueRangeLattice>(lhs);
     if (!maybeLhsRange || maybeLhsRange->getValue().isUninitialized())
       return failure();
     const ConstantIntRanges &lhsRange = maybeLhsRange->getValue().getValue();
-    const APInt &min = isa<RemUIOp>(op) ? lhsRange.umin() : lhsRange.smin();
-    const APInt &max = isa<RemUIOp>(op) ? lhsRange.umax() : lhsRange.smax();
+    const APInt &min = isUnsigned ? lhsRange.umin() : lhsRange.smin();
+    const APInt &max = isUnsigned ? lhsRange.umax() : lhsRange.smax();
+    if (min.getBitWidth() != modulus.getBitWidth() ||
+        max.getBitWidth() != modulus.getBitWidth())
+      return failure();
     // The minima and maxima here are given as closed ranges, we must be
-    // strictly less than the modulus.
-    if (min.isNegative() || min.uge(modulus))
+    // non-negative for signed remainder and strictly less than the modulus.
+    if ((!isUnsigned && min.isNegative()) || min.uge(modulus))
       return failure();
-    if (max.isNegative() || max.uge(modulus))
+    if ((!isUnsigned && max.isNegative()) || max.uge(modulus))
       return failure();
     if (!min.ule(max))
       return failure();
diff --git a/mlir/test/Dialect/Arith/int-range-opts.mlir b/mlir/test/Dialect/Arith/int-range-opts.mlir
index 0cfbdf3e33c93..016704d82eef4 100644
--- a/mlir/test/Dialect/Arith/int-range-opts.mlir
+++ b/mlir/test/Dialect/Arith/int-range-opts.mlir
@@ -110,6 +110,31 @@ func.func @trivial_rem() -> i8 {
 
 // -----
 
+// CHECK-LABEL: func @trivial_remui_sign_bit_set_modulus
+// CHECK: [[val:%.+]] = test.with_bounds
+// CHECK-NEXT: return [[val]]
+func.func @trivial_remui_sign_bit_set_modulus() -> i8 {
+  // The i8 bit pattern for -56 represents 200 when interpreted as unsigned.
+  %c200 = arith.constant -56 : i8
+  %val = test.with_bounds { umin = 0 : ui8, umax = 63 : ui8, smin = 0 : si8, smax = 63 : si8 } : i8
+  %mod = arith.remui %val, %c200 : i8
+  return %mod : i8
+}
+
+// -----
+
+// CHECK-LABEL: func @trivial_remui_sign_bit_set_range
+// CHECK: [[val:%.+]] = test.with_bounds
+// CHECK-NEXT: return [[val]]
+func.func @trivial_remui_sign_bit_set_range() -> i8 {
+  %c200 = arith.constant -56 : i8
+  %val = test.with_bounds { umin = 128 : ui8, umax = 199 : ui8, smin = -128 : si8, smax = -57 : si8 } : i8
+  %mod = arith.remui %val, %c200 : i8
+  return %mod : i8
+}
+
+// -----
+
 // CHECK-LABEL: func @non_const_rhs
 // CHECK: [[mod:%.+]] = arith.remui
 // CHECK: return [[mod]]



More information about the Mlir-commits mailing list