[Mlir-commits] [mlir] [mlir][arith] Fix APInt bitwidth mismatch crash in int-range-optimizations (PR #205110)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Mon Jun 22 06:57:01 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir-arith
@llvm/pr-subscribers-mlir
Author: Anutosh Bhat (anutosh491)
<details>
<summary>Changes</summary>
Fixes https://github.com/llvm/llvm-project/issues/204909
When an op's `areTypesCompatible()` hook accepts integers of different widths across a region boundary, the range analysis can propagate a constant range whose APInt bitwidth does not match the IR type of the destination value.
This caused `IntegerAttr::get` to `assert` in `maybeReplaceWithConstant`.
Fix by bailing out in `maybeReplaceWithConstant` when the bitwidths mismatch, and adding the same check to the needsReplacing lambda in matchAndRewrite.
The second guard is necessary to mirror the existing isIntOrIndex() guard — without it the pattern claims success without changing the IR, causing the greedy rewrite driver to loop.
---
Full diff: https://github.com/llvm/llvm-project/pull/205110.diff
2 Files Affected:
- (modified) mlir/lib/Dialect/Arith/Transforms/IntRangeOptimizations.cpp (+22-7)
- (modified) mlir/test/Dialect/Arith/int-range-opts-crash.mlir (+14)
``````````diff
diff --git a/mlir/lib/Dialect/Arith/Transforms/IntRangeOptimizations.cpp b/mlir/lib/Dialect/Arith/Transforms/IntRangeOptimizations.cpp
index 9fcda39089b2c..298c0dc2f3bda 100644
--- a/mlir/lib/Dialect/Arith/Transforms/IntRangeOptimizations.cpp
+++ b/mlir/lib/Dialect/Arith/Transforms/IntRangeOptimizations.cpp
@@ -75,6 +75,13 @@ LogicalResult maybeReplaceWithConstant(DataFlowSolver &solver,
// will crash, so eagerly check for an integer type to avoid this.
if (!getElementTypeOrSelf(type).isIntOrIndex())
return failure();
+
+ // Bail out if the inferred APInt bitwidth does not match the storage width
+ // of the IR type; IntegerAttr::get would assert otherwise.
+ unsigned storageWidth = ConstantIntRanges::getStorageBitwidth(type);
+ if (storageWidth != 0 && maybeConstValue->getBitWidth() != storageWidth)
+ return failure();
+
Location loc = value.getLoc();
Operation *maybeDefiningOp = value.getDefiningOp();
Dialect *valueDialect =
@@ -137,14 +144,22 @@ struct MaterializeKnownConstantValues : public RewritePattern {
if (matchPattern(op, m_Constant()))
return failure();
- // We need to check isIntOrIndex() here as well to avoid infinite loops in
- // the greedy pattern rewriter. If we only check it in
- // maybeReplaceWithConstant, this lambda might still return true for
- // non-integral types, causing the pattern to match and claim success
- // without making any changes, leading to non-convergence.
+ // We need to check isIntOrIndex() and APInt bitwidth compatibility here
+ // as well to avoid infinite loops in the greedy pattern rewriter. If we
+ // only check in maybeReplaceWithConstant, this lambda might still return
+ // true for values that cannot be materialized, causing the pattern to
+ // match and claim success without making any changes, leading to
+ // non-convergence.
auto needsReplacing = [&](Value v) {
- return getElementTypeOrSelf(v.getType()).isIntOrIndex() &&
- getMaybeConstantValue(solver, v).has_value() && !v.use_empty();
+ if (!getElementTypeOrSelf(v.getType()).isIntOrIndex())
+ return false;
+ std::optional<APInt> maybeConstValue = getMaybeConstantValue(solver, v);
+ if (!maybeConstValue.has_value() || v.use_empty())
+ return false;
+ unsigned storageWidth =
+ ConstantIntRanges::getStorageBitwidth(v.getType());
+ return storageWidth == 0 ||
+ maybeConstValue->getBitWidth() == storageWidth;
};
bool hasConstantResults = llvm::any_of(op->getResults(), needsReplacing);
if (op->getNumRegions() == 0)
diff --git a/mlir/test/Dialect/Arith/int-range-opts-crash.mlir b/mlir/test/Dialect/Arith/int-range-opts-crash.mlir
index fa763c163160d..99aa03714edb9 100644
--- a/mlir/test/Dialect/Arith/int-range-opts-crash.mlir
+++ b/mlir/test/Dialect/Arith/int-range-opts-crash.mlir
@@ -1,5 +1,19 @@
// RUN: mlir-opt -int-range-optimizations %s | FileCheck %s
+// CHECK-LABEL: func.func @repro_bitwidth_mismatch
+func.func @repro_bitwidth_mismatch() -> i32 {
+ %c0_i32 = arith.constant 0 : i32
+ // CHECK: test.region_types_compat
+ %0 = "test.region_types_compat"(%c0_i32) ({
+ ^bb0(%arg0: i64):
+ %c1_i64 = arith.constant 1 : i64
+ test.types_compat_yield %c1_i64 : i64
+ }) : (i32) -> i32
+ return %0 : i32
+}
+
+// -----
+
// CHECK-LABEL: func.func @repro_crash() -> !test.i32 {
func.func @repro_crash() -> !test.i32 {
%cst = arith.constant 1 : i32
``````````
</details>
https://github.com/llvm/llvm-project/pull/205110
More information about the Mlir-commits
mailing list