[Mlir-commits] [mlir] [MLIR] Fix crash in int-range-optimizations on type-mismatched IR (PR #183964)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Sat Feb 28 14:59:49 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir-arith
Author: Mehdi Amini (joker-eph)
<details>
<summary>Changes</summary>
When interprocedural integer range analysis propagates a range from a callee's return operand to the call site result, a bit-width mismatch can occur if the callee's return operand type differs from the declared function return type (malformed IR). Inference functions in InferIntRangeInterface assume all argument ranges share the same bit width, so mixing a 32-bit range (from an i32 operand) with a 64-bit range (from an index operand) triggers an assertion failure in APInt::compare.
Fix this by adding a bit-width consistency check in defaultInferResultRanges before invoking any inference function: if the unpacked argument ranges have mismatched widths, skip inference and leave results uninitialized (conservative). Also add the same guard in ConstantIntRanges::rangeUnion and ::intersection for robustness.
Fixes #<!-- -->74234
---
Full diff: https://github.com/llvm/llvm-project/pull/183964.diff
2 Files Affected:
- (modified) mlir/lib/Interfaces/InferIntRangeInterface.cpp (+21)
- (modified) mlir/test/Dialect/Arith/int-range-opts.mlir (+38)
``````````diff
diff --git a/mlir/lib/Interfaces/InferIntRangeInterface.cpp b/mlir/lib/Interfaces/InferIntRangeInterface.cpp
index 84fc9b8b61a11..e2f4708fe52be 100644
--- a/mlir/lib/Interfaces/InferIntRangeInterface.cpp
+++ b/mlir/lib/Interfaces/InferIntRangeInterface.cpp
@@ -90,6 +90,12 @@ ConstantIntRanges::rangeUnion(const ConstantIntRanges &other) const {
if (other.umin().getBitWidth() == 0)
return other;
+ // If bit widths differ (e.g., due to type mismatches in the input IR when
+ // ranges are propagated across call boundaries), conservatively return the
+ // maximum range for this value's bit width.
+ if (umin().getBitWidth() != other.umin().getBitWidth())
+ return maxRange(umin().getBitWidth());
+
const APInt &uminUnion = umin().ult(other.umin()) ? umin() : other.umin();
const APInt &umaxUnion = umax().ugt(other.umax()) ? umax() : other.umax();
const APInt &sminUnion = smin().slt(other.smin()) ? smin() : other.smin();
@@ -177,6 +183,21 @@ void mlir::intrange::detail::defaultInferResultRanges(
unpacked.push_back(range.getValue());
}
+ // Guard against bit-width mismatches between an argument range and its
+ // operand's type. This can occur when interprocedural analysis propagates a
+ // range from a value of one type (e.g. i32) into a lattice anchored to a
+ // value of a different type (e.g. index), which happens with malformed IR
+ // that has type mismatches at call boundaries. All inference functions assume
+ // ranges match their operand types, so skip inference and leave the result
+ // ranges uninitialized (conservative).
+ Operation *op = interface.getOperation();
+ for (auto [operand, range] : llvm::zip(op->getOperands(), unpacked)) {
+ unsigned expectedWidth =
+ ConstantIntRanges::getStorageBitwidth(operand.getType());
+ if (range.umin().getBitWidth() != expectedWidth)
+ return;
+ }
+
interface.inferResultRanges(
unpacked,
[&setResultRanges](Value value, const ConstantIntRanges &argRanges) {
diff --git a/mlir/test/Dialect/Arith/int-range-opts.mlir b/mlir/test/Dialect/Arith/int-range-opts.mlir
index e6e48d30cece5..1358c92709f72 100644
--- a/mlir/test/Dialect/Arith/int-range-opts.mlir
+++ b/mlir/test/Dialect/Arith/int-range-opts.mlir
@@ -148,3 +148,41 @@ func.func @analysis_crash(%arg0: i32, %arg1: tensor<128xi1>) -> tensor<128xi64>
%2 = arith.extsi %1 : tensor<128xi32> to tensor<128xi64>
return %2 : tensor<128xi64>
}
+
+// -----
+
+// Regression test for https://github.com/llvm/llvm-project/issues/74234
+// Verifies no crash when interprocedural range propagation encounters a callee
+// whose return operand type differs from the function's declared return type,
+// causing a bit-width mismatch in the inferred ranges.
+
+// CHECK-LABEL: @issue74234_callee
+func.func private @issue74234_callee() -> index {
+ %c30 = arith.constant 30 : index
+ %2 = builtin.unrealized_conversion_cast %c30 : index to i32
+ llvm.return %2 : i32
+}
+// CHECK-LABEL: @issue74234_caller
+func.func @issue74234_caller() {
+ %c0 = arith.constant 0 : index
+ %0 = func.call @issue74234_callee() : () -> index
+ %1 = index.maxu %c0, %0
+ return
+}
+
+// Exercises rangeUnion with mismatched bit widths: the block argument %arg
+// receives a 32-bit range (from the malformed callee via ^bb1) and a 64-bit
+// range (from the arith.constant via ^bb2). The analysis joins them at ^merge,
+// triggering the bit-width guard in ConstantIntRanges::rangeUnion.
+// CHECK-LABEL: @issue74234_rangeunion
+func.func @issue74234_rangeunion(%cond: i1) -> index {
+ cf.cond_br %cond, ^bb1, ^bb2
+^bb1:
+ %a = func.call @issue74234_callee() : () -> index
+ cf.br ^merge(%a : index)
+^bb2:
+ %b = arith.constant 5 : index
+ cf.br ^merge(%b : index)
+^merge(%arg: index):
+ return %arg : index
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/183964
More information about the Mlir-commits
mailing list