[Mlir-commits] [mlir] [mlir][arith] Fix APInt bitwidth mismatch crash in int-range-optimizations (PR #205110)

Anutosh Bhat llvmlistbot at llvm.org
Mon Jun 22 06:56:21 PDT 2026


https://github.com/anutosh491 created https://github.com/llvm/llvm-project/pull/205110

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.



>From ac2e6554e07e3c3e9c847f361b14f0f65a66d385 Mon Sep 17 00:00:00 2001
From: anutosh491 <andersonbhat491 at gmail.com>
Date: Mon, 22 Jun 2026 19:23:38 +0530
Subject: [PATCH] [mlir][arith] Fix APInt bitwidth mismatch crash in
 int-range-optimizations

---
 .../Transforms/IntRangeOptimizations.cpp      | 29 ++++++++++++++-----
 .../Dialect/Arith/int-range-opts-crash.mlir   | 14 +++++++++
 2 files changed, 36 insertions(+), 7 deletions(-)

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



More information about the Mlir-commits mailing list