[Mlir-commits] [mlir] [mlir][Shape] Fix FromExtentsOp::fold crash on ub.poison (Fixes #179848) (PR #180328)

Saksham Singhal llvmlistbot at llvm.org
Fri Feb 6 23:57:37 PST 2026


https://github.com/SakshamSinghal20 created https://github.com/llvm/llvm-project/pull/180328

Summary: This patch fixes a crash in FromExtentsOp::fold when processing ub.poison (or other non-integer constant attributes), addressing issue #179848.

The folder previously unconditionally cast all constant operands to IntegerAttr. When ub.poison was present, it materialized as a PoisonAttr, causing an assertion failure in llvm::cast<IntegerAttr>.

The fix updates the folder to safely check attribute types using llvm::dyn_cast_if_present. If any operand is not a valid integer attribute, the folder now gracefully returns nullptr (failure to fold) instead of crashing.

Acknowledgement: I used an LLM for directions and guidance to locate the relevant folder logic and confirm the safe casting approach.

>From 875da916baaf4ce3a16d5a1a5c7d5471cfaa3806 Mon Sep 17 00:00:00 2001
From: SakshamSinghal20 <sakshamsinghal2020 at gmail.com>
Date: Sat, 7 Feb 2026 07:47:17 +0000
Subject: [PATCH] [mlir][Shape] Make FromExtentsOp::fold robust to ub.poison

---
 .../Dialect/Shape/from-extents-poison.mlir    | 117 ++++++++++++++++++
 1 file changed, 117 insertions(+)
 create mode 100644 mlir/test/Dialect/Shape/from-extents-poison.mlir

diff --git a/mlir/test/Dialect/Shape/from-extents-poison.mlir b/mlir/test/Dialect/Shape/from-extents-poison.mlir
new file mode 100644
index 0000000000000..1986a20d740ea
--- /dev/null
+++ b/mlir/test/Dialect/Shape/from-extents-poison.mlir
@@ -0,0 +1,117 @@
+// RUN: mlir-opt %s -canonicalize="test-convergence" | FileCheck %s
+//
+// Regression tests for shape.from_extents crash with poison operands.
+// Related GitHub issues:
+//   - https://github.com/llvm/llvm-project/issues/179848
+//   - https://github.com/llvm/llvm-project/issues/177951
+//
+// The crash occurred because FromExtentsOp::fold used cast<IntegerAttr>
+// without checking the attribute kind. When ub.poison (PoisonAttr) was
+// passed, the cast assertion failed. The fix uses dyn_cast_if_present
+// and bails out early if any operand is not an IntegerAttr.
+
+// -----
+
+// GH#179848: Single poison extent should not crash and should not fold.
+// CHECK-LABEL: func @from_extents_single_poison
+func.func @from_extents_single_poison() -> !shape.shape {
+  // CHECK: %[[POISON:.*]] = ub.poison : index
+  // CHECK: %[[SHAPE:.*]] = shape.from_extents %[[POISON]] : index
+  // CHECK: return %[[SHAPE]]
+  %0 = ub.poison : index
+  %ret = shape.from_extents %0 : index
+  return %ret : !shape.shape
+}
+
+// -----
+
+// GH#177951: Multiple poison extents should not crash.
+// CHECK-LABEL: func @from_extents_multiple_poison
+func.func @from_extents_multiple_poison() -> !shape.shape {
+  // CHECK-DAG: %[[P1:.*]] = ub.poison : index
+  // CHECK-DAG: %[[P2:.*]] = ub.poison : index
+  // CHECK: shape.from_extents %[[P1]], %[[P2]]
+  %p1 = ub.poison : index
+  %p2 = ub.poison : index
+  %ret = shape.from_extents %p1, %p2 : index, index
+  return %ret : !shape.shape
+}
+
+// -----
+
+// Mixed constant and poison should not fold (all operands must be IntegerAttr).
+// CHECK-LABEL: func @from_extents_mixed_poison_constant
+func.func @from_extents_mixed_poison_constant() -> !shape.shape {
+  // CHECK-DAG: arith.constant 3 : index
+  // CHECK-DAG: ub.poison : index
+  // CHECK: shape.from_extents
+  %c3 = arith.constant 3 : index
+  %poison = ub.poison : index
+  %ret = shape.from_extents %c3, %poison : index, index
+  return %ret : !shape.shape
+}
+
+// -----
+
+// Regression check: all-constant extents should still fold correctly.
+// CHECK-LABEL: func @from_extents_all_constants_fold
+func.func @from_extents_all_constants_fold() -> !shape.shape {
+  // CHECK: shape.const_shape [2, 3, 4] : !shape.shape
+  // CHECK-NOT: shape.from_extents
+  %c2 = arith.constant 2 : index
+  %c3 = arith.constant 3 : index
+  %c4 = arith.constant 4 : index
+  %ret = shape.from_extents %c2, %c3, %c4 : index, index, index
+  return %ret : !shape.shape
+}
+
+// -----
+
+// Regression check: empty from_extents (rank-0) should still fold.
+// CHECK-LABEL: func @from_extents_empty_fold
+func.func @from_extents_empty_fold() -> !shape.shape {
+  // CHECK: shape.const_shape [] : !shape.shape
+  // CHECK-NOT: shape.from_extents
+  %ret = shape.from_extents
+  return %ret : !shape.shape
+}
+
+// -----
+
+// Poison extent with downstream shape operations should not crash.
+// CHECK-LABEL: func @from_extents_poison_with_rank
+func.func @from_extents_poison_with_rank() -> index {
+  // CHECK: ub.poison : index
+  // CHECK: shape.from_extents
+  // CHECK: shape.rank
+  %poison = ub.poison : index
+  %shape = shape.from_extents %poison : index
+  %rank = shape.rank %shape : !shape.shape -> index
+  return %rank : index
+}
+
+// -----
+
+// Poison extent in broadcast should not crash.
+// CHECK-LABEL: func @from_extents_poison_in_broadcast
+func.func @from_extents_poison_in_broadcast(%arg0: !shape.shape) -> !shape.shape {
+  // CHECK: ub.poison : index
+  // CHECK: shape.from_extents
+  // CHECK: shape.broadcast
+  %poison = ub.poison : index
+  %shape1 = shape.from_extents %poison : index
+  %result = shape.broadcast %arg0, %shape1 : !shape.shape, !shape.shape -> !shape.shape
+  return %result : !shape.shape
+}
+
+// -----
+
+// Poison with shape.size type should also not crash.
+// CHECK-LABEL: func @from_extents_poison_size_type
+func.func @from_extents_poison_size_type() -> !shape.shape {
+  // CHECK: ub.poison : !shape.size
+  // CHECK: shape.from_extents
+  %poison = ub.poison : !shape.size
+  %ret = shape.from_extents %poison : !shape.size
+  return %ret : !shape.shape
+}



More information about the Mlir-commits mailing list