[Mlir-commits] [mlir] [mlir][Shape] Fix crash in BroadcastOp::fold when operand is ub.poison (PR #183931)
Mehdi Amini
llvmlistbot at llvm.org
Sat Feb 28 08:57:00 PST 2026
https://github.com/joker-eph created https://github.com/llvm/llvm-project/pull/183931
BroadcastOp::fold used an unchecked llvm::cast<DenseIntElementsAttr> on each operand's folded attribute. The existing null-check only guarded against a missing (unset) attribute, not against a non-null attribute of a different type such as PoisonAttr (produced when an operand is ub.poison).
Replace the unchecked casts with dyn_cast_or_null, bailing out with nullptr (i.e. no fold) when any operand does not provide a DenseIntElementsAttr.
Add a regression test with a ub.poison operand.
Fixes #179679
>From d05e7ee209055549bcd61a1c5215b92c50719459 Mon Sep 17 00:00:00 2001
From: Mehdi Amini <joker.eph at gmail.com>
Date: Sat, 28 Feb 2026 05:43:37 -0800
Subject: [PATCH] [mlir][Shape] Fix crash in BroadcastOp::fold when operand is
ub.poison
BroadcastOp::fold used an unchecked llvm::cast<DenseIntElementsAttr>
on each operand's folded attribute. The existing null-check only guarded
against a missing (unset) attribute, not against a non-null attribute of
a different type such as PoisonAttr (produced when an operand is
ub.poison).
Replace the unchecked casts with dyn_cast_or_null, bailing out with
nullptr (i.e. no fold) when any operand does not provide a
DenseIntElementsAttr.
Add a regression test with a ub.poison operand.
Fixes #179679
---
mlir/lib/Dialect/Shape/IR/Shape.cpp | 14 +++++++-------
mlir/test/Dialect/Shape/canonicalize.mlir | 18 ++++++++++++++++++
2 files changed, 25 insertions(+), 7 deletions(-)
diff --git a/mlir/lib/Dialect/Shape/IR/Shape.cpp b/mlir/lib/Dialect/Shape/IR/Shape.cpp
index 4d03b7b2b2064..053173bdf8510 100644
--- a/mlir/lib/Dialect/Shape/IR/Shape.cpp
+++ b/mlir/lib/Dialect/Shape/IR/Shape.cpp
@@ -652,18 +652,18 @@ OpFoldResult BroadcastOp::fold(FoldAdaptor adaptor) {
return getShapes().front();
}
- if (!adaptor.getShapes().front())
+ auto firstAttr =
+ dyn_cast_or_null<DenseIntElementsAttr>(adaptor.getShapes().front());
+ if (!firstAttr)
return nullptr;
- SmallVector<int64_t, 6> resultShape(
- llvm::cast<DenseIntElementsAttr>(adaptor.getShapes().front())
- .getValues<int64_t>());
+ SmallVector<int64_t, 6> resultShape(firstAttr.getValues<int64_t>());
for (auto next : adaptor.getShapes().drop_front()) {
- if (!next)
+ auto nextAttr = dyn_cast_or_null<DenseIntElementsAttr>(next);
+ if (!nextAttr)
return nullptr;
- auto nextShape = llvm::to_vector<6>(
- llvm::cast<DenseIntElementsAttr>(next).getValues<int64_t>());
+ auto nextShape = llvm::to_vector<6>(nextAttr.getValues<int64_t>());
SmallVector<int64_t, 6> tmpShape;
// If the shapes are not compatible, we can't fold it.
diff --git a/mlir/test/Dialect/Shape/canonicalize.mlir b/mlir/test/Dialect/Shape/canonicalize.mlir
index 22add87ff3ed4..d1b5e7bb035bf 100644
--- a/mlir/test/Dialect/Shape/canonicalize.mlir
+++ b/mlir/test/Dialect/Shape/canonicalize.mlir
@@ -1636,3 +1636,21 @@ func.func @shape_of_static_with_shape_result(%arg0: tensor<3xf32>) -> !shape.sha
%0 = shape.shape_of %arg0 : tensor<3xf32> -> !shape.shape
return %0 : !shape.shape
}
+
+// -----
+
+// Regression test for https://github.com/llvm/llvm-project/issues/179679:
+// shape.broadcast fold used to crash with an unchecked cast when one of the
+// operands was ub.poison (a non-DenseIntElementsAttr attribute). The fold
+// must bail out gracefully instead.
+
+// CHECK-LABEL: @broadcast_no_crash_on_poison
+// CHECK-NOT: shape.broadcast
+// CHECK: return
+func.func @broadcast_no_crash_on_poison() {
+ %0 = shape.const_shape [1, 2, 3] : tensor<3xindex>
+ %1 = ub.poison : tensor<3xindex>
+ %2 = shape.broadcast %0, %1 : tensor<3xindex>, tensor<3xindex> -> tensor<3xindex>
+ %3 = tensor.rank %2 : tensor<3xindex>
+ return
+}
More information about the Mlir-commits
mailing list