[Mlir-commits] [mlir] [mlir][IntRange] Avoid division by zero for empty divisor ranges in divs (PR #234159)
Sajid Zubair
llvmlistbot at llvm.org
Wed Oct 21 04:20:32 PDT 2026
https://github.com/Sajid-Zubair created https://github.com/llvm/llvm-project/pull/234159
inferSub can produce an empty range (smin > smax) when both nsw and nuw saturate, e.g. for `arith.subi 0, 1 overflow<nsw, nuw>`, whose result is poison. inferDivSRange only checked rhsMax.isNegative() to rule out a zero divisor, so it then evaluated sdiv with rhsMin == 0 and asserted in APInt::udiv. Treat an empty divisor range as unknown and return the max range instead.
Fixes #231845
>From 1aa7a4d67b60522c367be2c1af29dee38ad46c13 Mon Sep 17 00:00:00 2001
From: Sajid-Zubair <sajid10zubair at gmail.com>
Date: Wed, 21 Oct 2026 16:49:43 +0530
Subject: [PATCH] [mlir][IntRange] Avoid division by zero for empty divisor
ranges in divs
inferSub can produce an empty range (smin > smax) when both nsw and nuw
saturate, e.g. for `arith.subi 0, 1 overflow<nsw, nuw>`, whose result is
poison. inferDivSRange only checked rhsMax.isNegative() to rule out a zero
divisor, so it then evaluated sdiv with rhsMin == 0 and asserted in
APInt::udiv. Treat an empty divisor range as unknown and return the max
range instead.
Fixes #231845
Assisted by: Opus 5.5
---
mlir/lib/Interfaces/Utils/InferIntRangeCommon.cpp | 5 ++++-
mlir/test/Dialect/Arith/int-range-opts-crash.mlir | 12 ++++++++++++
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/mlir/lib/Interfaces/Utils/InferIntRangeCommon.cpp b/mlir/lib/Interfaces/Utils/InferIntRangeCommon.cpp
index c9f49fda726e7..24fb166ce91c1 100644
--- a/mlir/lib/Interfaces/Utils/InferIntRangeCommon.cpp
+++ b/mlir/lib/Interfaces/Utils/InferIntRangeCommon.cpp
@@ -342,7 +342,10 @@ static ConstantIntRanges inferDivSRange(const ConstantIntRanges &lhs,
DivisionFixupFn fixup) {
const APInt &lhsMin = lhs.smin(), &lhsMax = lhs.smax(), &rhsMin = rhs.smin(),
&rhsMax = rhs.smax();
- bool canDivide = rhsMin.isStrictlyPositive() || rhsMax.isNegative();
+ // An empty (min > max) divisor range can arise from poison, e.g. a
+ // saturated `nsw`/`nuw` subtraction. Don't trust its bounds.
+ bool canDivide = rhsMin.sle(rhsMax) &&
+ (rhsMin.isStrictlyPositive() || rhsMax.isNegative());
if (canDivide) {
auto sdiv = [&fixup](const APInt &a,
diff --git a/mlir/test/Dialect/Arith/int-range-opts-crash.mlir b/mlir/test/Dialect/Arith/int-range-opts-crash.mlir
index fa763c163160d..77b173311f6ac 100644
--- a/mlir/test/Dialect/Arith/int-range-opts-crash.mlir
+++ b/mlir/test/Dialect/Arith/int-range-opts-crash.mlir
@@ -11,3 +11,15 @@ func.func @repro_crash() -> !test.i32 {
// CHECK: return %[[RES]] : !test.i32
return %0 : !test.i32
}
+
+// The divisor is poison (0 - 1 with nuw), giving an empty range.
+// This used to divide by zero in inferDivSRange.
+// CHECK-LABEL: func.func @divs_by_poison_sub
+// CHECK: index.divs
+func.func @divs_by_poison_sub() -> index {
+ %z = arith.constant 0 : index
+ %o = arith.constant 1 : index
+ %bad = arith.subi %z, %o overflow<nsw, nuw> : index
+ %q = index.divs %o, %bad
+ return %q : index
+}
More information about the Mlir-commits
mailing list