[Mlir-commits] [llvm] [mlir] [clang-tidy] pro-type-vararg: Allow type-generic builtins in variadic functions #179845 (PR #179896)

Saksham Singhal llvmlistbot at llvm.org
Thu Feb 5 05:16:56 PST 2026


https://github.com/SakshamSinghal20 updated https://github.com/llvm/llvm-project/pull/179896

>From 0b3f593dfbf4ecdefcf2455dc83783c0c1731cb8 Mon Sep 17 00:00:00 2001
From: SakshamSinghal20 <sakshamsinghal2020 at gmail.com>
Date: Thu, 5 Feb 2026 09:29:19 +0000
Subject: [PATCH 1/2] Fix(llvm): resolve issue #179845 with minimal logic
 change

---
 implementation_plan.md                    | 81 +++++++++++++++++++++++
 mlir/lib/Dialect/Shape/IR/Shape.cpp       | 23 ++++---
 mlir/test/Dialect/Shape/canonicalize.mlir | 25 +++++++
 3 files changed, 118 insertions(+), 11 deletions(-)
 create mode 100644 implementation_plan.md

diff --git a/implementation_plan.md b/implementation_plan.md
new file mode 100644
index 0000000000000..eb1af24bd791b
--- /dev/null
+++ b/implementation_plan.md
@@ -0,0 +1,81 @@
+# Implementation Plan - Fix mlir-opt Crash in Shape Dialect
+
+## Problem Analysis
+The `mlir-opt` tool crashes with an assertion failure in `llvm::cast` during the `--canonicalize` pass. This occurs when `shape.broadcast` or other shape operations consume a `ub.poison` value (or any attribute that is not a `DenseIntElementsAttr`). The folding logic assumes that if an operand is not null, it must be a `DenseIntElementsAttr`, leading to an invalid cast.
+
+**Affected File:** `mlir/lib/Dialect/Shape/IR/Shape.cpp`
+
+**Locations:**
+1.  `BroadcastOp::fold` (lines ~647-681)
+2.  `hasAtMostSingleNonScalar` helper function (lines ~978-988)
+3.  `CstrBroadcastableOp::fold` (lines ~990-1023)
+
+## Proposed Changes
+
+### 1. Update `BroadcastOp::fold`
+Modify the loop that iterates over shapes. Instead of just checking `if (!next)`, check if `next` can be cast to `DenseIntElementsAttr`.
+
+**Current Code:**
+```cpp
+if (!adaptor.getShapes().front())
+  return nullptr;
+// ...
+for (auto next : adaptor.getShapes().drop_front()) {
+  if (!next)
+    return nullptr;
+  // cast ...
+}
+```
+
+**New Code:**
+```cpp
+auto firstAttr = llvm::dyn_cast_if_present<DenseIntElementsAttr>(adaptor.getShapes().front());
+if (!firstAttr)
+  return nullptr;
+// ...
+for (auto next : adaptor.getShapes().drop_front()) {
+  auto nextAttr = llvm::dyn_cast_if_present<DenseIntElementsAttr>(next);
+  if (!nextAttr)
+    return nullptr;
+  // use nextAttr ...
+}
+```
+
+### 2. Update `hasAtMostSingleNonScalar`
+Add a check for `DenseIntElementsAttr` before accessing `getNumElements()`.
+
+**Current Code:**
+```cpp
+if (!a || llvm::cast<DenseIntElementsAttr>(a).getNumElements() != 0) {
+```
+
+**New Code:**
+```cpp
+auto denseAttr = llvm::dyn_cast_if_present<DenseIntElementsAttr>(a);
+if (!denseAttr || denseAttr.getNumElements() != 0) {
+```
+
+### 3. Update `CstrBroadcastableOp::fold`
+Similar to `BroadcastOp`, ensure `dyn_cast` succeeds before accessing values.
+
+**Current Code:**
+```cpp
+if (!operand)
+  return false;
+extents.push_back(llvm::to_vector<6>(
+    llvm::cast<DenseIntElementsAttr>(operand).getValues<int64_t>()));
+```
+
+**New Code:**
+```cpp
+auto denseAttr = llvm::dyn_cast_if_present<DenseIntElementsAttr>(operand);
+if (!denseAttr)
+  return false;
+extents.push_back(llvm::to_vector<6>(
+    denseAttr.getValues<int64_t>()));
+```
+
+## Validation Plan
+1.  **Build:** Run `ninja mlir-opt` (or `ninja check-mlir-shape` if available targets).
+2.  **Reproduction:** Run the `reproduce_issue.mlir` with `mlir-opt --canonicalize` to ensure it no longer crashes.
+3.  **Regression Test:** Add the reproduction case to `mlir/test/Dialect/Shape/canonicalize.mlir` or a new test file.
diff --git a/mlir/lib/Dialect/Shape/IR/Shape.cpp b/mlir/lib/Dialect/Shape/IR/Shape.cpp
index c1210eef4e589..6f7a26374e6f6 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 =
+      llvm::dyn_cast_if_present<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 = llvm::dyn_cast_if_present<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.
@@ -978,7 +978,8 @@ void CstrBroadcastableOp::getCanonicalizationPatterns(
 static bool hasAtMostSingleNonScalar(ArrayRef<Attribute> attributes) {
   bool nonScalarSeen = false;
   for (Attribute a : attributes) {
-    if (!a || llvm::cast<DenseIntElementsAttr>(a).getNumElements() != 0) {
+    auto denseAttr = llvm::dyn_cast_if_present<DenseIntElementsAttr>(a);
+    if (!denseAttr || denseAttr.getNumElements() != 0) {
       if (nonScalarSeen)
         return false;
       nonScalarSeen = true;
@@ -995,10 +996,10 @@ OpFoldResult CstrBroadcastableOp::fold(FoldAdaptor adaptor) {
   if ([&] {
         SmallVector<SmallVector<int64_t, 6>, 6> extents;
         for (const auto &operand : adaptor.getShapes()) {
-          if (!operand)
+          auto denseAttr = llvm::dyn_cast_if_present<DenseIntElementsAttr>(operand);
+          if (!denseAttr)
             return false;
-          extents.push_back(llvm::to_vector<6>(
-              llvm::cast<DenseIntElementsAttr>(operand).getValues<int64_t>()));
+          extents.push_back(llvm::to_vector<6>(denseAttr.getValues<int64_t>()));
         }
         return OpTrait::util::staticallyKnownBroadcastable(extents);
       }())
diff --git a/mlir/test/Dialect/Shape/canonicalize.mlir b/mlir/test/Dialect/Shape/canonicalize.mlir
index f3c25b8c8100e..d7a8432cd0469 100644
--- a/mlir/test/Dialect/Shape/canonicalize.mlir
+++ b/mlir/test/Dialect/Shape/canonicalize.mlir
@@ -1626,3 +1626,28 @@ func.func @shape_of_0d(%arg0: tensor<f32>) -> tensor<?xindex> {
   %0 = shape.shape_of %arg0 : tensor<f32> -> tensor<?xindex>
   return %0 : tensor<?xindex>
 }
+
+// -----
+
+// GH#179845: Verify shape.broadcast doesn't crash on poison operands.
+// CHECK-LABEL: func @broadcast_poison
+func.func @broadcast_poison() {
+  // CHECK: ub.poison
+  // CHECK: shape.broadcast
+  %2 = ub.poison : tensor<3xindex>
+  %3 = shape.broadcast %2, %2 : tensor<3xindex>, tensor<3xindex> -> tensor<3xindex>
+  return
+}
+
+// -----
+
+// GH#179845: Verify cstr_broadcastable doesn't crash on poison operands.
+// CHECK-LABEL: func @cstr_broadcastable_poison
+func.func @cstr_broadcastable_poison() {
+  // CHECK: ub.poison
+  // CHECK: shape.cstr_broadcastable
+  %2 = ub.poison : !shape.shape
+  %0 = shape.cstr_broadcastable %2, %2 : !shape.shape, !shape.shape
+  "consume.witness"(%0) : (!shape.witness) -> ()
+  return
+}

>From cccbdef0805270728fe565882c4ddfd0729ed16a Mon Sep 17 00:00:00 2001
From: SakshamSinghal20 <sakshamsinghal2020 at gmail.com>
Date: Thu, 5 Feb 2026 13:15:39 +0000
Subject: [PATCH 2/2] extra file removed

---
 implementation_plan.md | 81 ------------------------------------------
 1 file changed, 81 deletions(-)
 delete mode 100644 implementation_plan.md

diff --git a/implementation_plan.md b/implementation_plan.md
deleted file mode 100644
index eb1af24bd791b..0000000000000
--- a/implementation_plan.md
+++ /dev/null
@@ -1,81 +0,0 @@
-# Implementation Plan - Fix mlir-opt Crash in Shape Dialect
-
-## Problem Analysis
-The `mlir-opt` tool crashes with an assertion failure in `llvm::cast` during the `--canonicalize` pass. This occurs when `shape.broadcast` or other shape operations consume a `ub.poison` value (or any attribute that is not a `DenseIntElementsAttr`). The folding logic assumes that if an operand is not null, it must be a `DenseIntElementsAttr`, leading to an invalid cast.
-
-**Affected File:** `mlir/lib/Dialect/Shape/IR/Shape.cpp`
-
-**Locations:**
-1.  `BroadcastOp::fold` (lines ~647-681)
-2.  `hasAtMostSingleNonScalar` helper function (lines ~978-988)
-3.  `CstrBroadcastableOp::fold` (lines ~990-1023)
-
-## Proposed Changes
-
-### 1. Update `BroadcastOp::fold`
-Modify the loop that iterates over shapes. Instead of just checking `if (!next)`, check if `next` can be cast to `DenseIntElementsAttr`.
-
-**Current Code:**
-```cpp
-if (!adaptor.getShapes().front())
-  return nullptr;
-// ...
-for (auto next : adaptor.getShapes().drop_front()) {
-  if (!next)
-    return nullptr;
-  // cast ...
-}
-```
-
-**New Code:**
-```cpp
-auto firstAttr = llvm::dyn_cast_if_present<DenseIntElementsAttr>(adaptor.getShapes().front());
-if (!firstAttr)
-  return nullptr;
-// ...
-for (auto next : adaptor.getShapes().drop_front()) {
-  auto nextAttr = llvm::dyn_cast_if_present<DenseIntElementsAttr>(next);
-  if (!nextAttr)
-    return nullptr;
-  // use nextAttr ...
-}
-```
-
-### 2. Update `hasAtMostSingleNonScalar`
-Add a check for `DenseIntElementsAttr` before accessing `getNumElements()`.
-
-**Current Code:**
-```cpp
-if (!a || llvm::cast<DenseIntElementsAttr>(a).getNumElements() != 0) {
-```
-
-**New Code:**
-```cpp
-auto denseAttr = llvm::dyn_cast_if_present<DenseIntElementsAttr>(a);
-if (!denseAttr || denseAttr.getNumElements() != 0) {
-```
-
-### 3. Update `CstrBroadcastableOp::fold`
-Similar to `BroadcastOp`, ensure `dyn_cast` succeeds before accessing values.
-
-**Current Code:**
-```cpp
-if (!operand)
-  return false;
-extents.push_back(llvm::to_vector<6>(
-    llvm::cast<DenseIntElementsAttr>(operand).getValues<int64_t>()));
-```
-
-**New Code:**
-```cpp
-auto denseAttr = llvm::dyn_cast_if_present<DenseIntElementsAttr>(operand);
-if (!denseAttr)
-  return false;
-extents.push_back(llvm::to_vector<6>(
-    denseAttr.getValues<int64_t>()));
-```
-
-## Validation Plan
-1.  **Build:** Run `ninja mlir-opt` (or `ninja check-mlir-shape` if available targets).
-2.  **Reproduction:** Run the `reproduce_issue.mlir` with `mlir-opt --canonicalize` to ensure it no longer crashes.
-3.  **Regression Test:** Add the reproduction case to `mlir/test/Dialect/Shape/canonicalize.mlir` or a new test file.



More information about the Mlir-commits mailing list