[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