[Mlir-commits] [mlir] [MLIR][Shape] Fix crash in ShapeOfOp canonicalization during inlining (PR #178839)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Mon Feb 9 12:05:42 PST 2026


https://github.com/Sejal-07661 updated https://github.com/llvm/llvm-project/pull/178839

>From ca3a51ac7178ded3e182c8456433598bbdfd41c2 Mon Sep 17 00:00:00 2001
From: Sejal-07661 <sejalsomkuwar4 at gmail.com>
Date: Fri, 30 Jan 2026 10:40:33 +0530
Subject: [PATCH 1/2] [MLIR][Shape] Fix crash in ShapeOfOp canonicalization
 during inlining

---
 mlir/lib/Dialect/Shape/IR/Shape.cpp       | 33 ++++++++++++-----------
 mlir/test/Dialect/Shape/canonicalize.mlir | 18 +++++++++++++
 2 files changed, 36 insertions(+), 15 deletions(-)

diff --git a/mlir/lib/Dialect/Shape/IR/Shape.cpp b/mlir/lib/Dialect/Shape/IR/Shape.cpp
index 95546b4a4deb7..a3aa87adc5b30 100644
--- a/mlir/lib/Dialect/Shape/IR/Shape.cpp
+++ b/mlir/lib/Dialect/Shape/IR/Shape.cpp
@@ -1700,21 +1700,24 @@ struct ShapeOfOpToConstShapeOp : public OpRewritePattern<shape::ShapeOfOp> {
   using OpRewritePattern<shape::ShapeOfOp>::OpRewritePattern;
 
   LogicalResult matchAndRewrite(shape::ShapeOfOp op,
-                                PatternRewriter &rewriter) const override {
-    auto type = llvm::dyn_cast<ShapedType>(op.getArg().getType());
-    if (!type || !type.hasStaticShape())
-      return failure();
-    Location loc = op.getLoc();
-    Value constShape =
-        ConstShapeOp::create(rewriter, loc,
-                             rewriter.getIndexTensorAttr(type.getShape()))
-            .getResult();
-    if (constShape.getType() != op.getResult().getType())
-      constShape = tensor::CastOp::create(rewriter, loc,
-                                          op.getResult().getType(), constShape);
-    rewriter.replaceOp(op, constShape);
-    return success();
-  }
+                              PatternRewriter &rewriter) const override {
+  auto shapedTy = dyn_cast<ShapedType>(op.getArg().getType());
+  if (!shapedTy || !shapedTy.hasStaticShape())
+    return failure();
+
+  Location loc = op.getLoc();
+  auto attr = rewriter.getIndexTensorAttr(shapedTy.getShape());
+
+  // IMPORTANT: Build const_shape with the SAME result type as shape_of.
+  // This avoids creating a tensor.cast to a non-tensor type (!shape.shape).
+  Value constShape = rewriter
+      .create<shape::ConstShapeOp>(loc, op.getType(), attr)
+      .getResult();
+
+  rewriter.replaceOp(op, constShape);
+  return success();
+}
+
 };
 
 // Canonicalize
diff --git a/mlir/test/Dialect/Shape/canonicalize.mlir b/mlir/test/Dialect/Shape/canonicalize.mlir
index 32a7c0186f282..1e1ef4b131e3c 100644
--- a/mlir/test/Dialect/Shape/canonicalize.mlir
+++ b/mlir/test/Dialect/Shape/canonicalize.mlir
@@ -1614,3 +1614,21 @@ func.func @shape_of_0d(%arg0: tensor<f32>) -> tensor<?xindex> {
   %0 = shape.shape_of %arg0 : tensor<f32> -> tensor<?xindex>
   return %0 : tensor<?xindex>
 }
+
+
+// --------------------------------------------
+// ---- shape.shape_of canonicalize regression ----
+
+// RUN: mlir-opt %s -canonicalize | FileCheck %s
+
+module {
+  func.func @main(%arg0: tensor<2x3xi32>) -> !shape.shape {
+    %0 = shape.shape_of %arg0 : tensor<2x3xi32> -> !shape.shape
+    return %0 : !shape.shape
+  }
+}
+
+// CHECK-LABEL: func.func @main
+// CHECK:       shape.const_shape [2, 3] : !shape.shape
+// CHECK-NOT:   shape.shape_of
+

>From f87fd6da35fcb40917e5f9fb66b2df4f47097541 Mon Sep 17 00:00:00 2001
From: Sejal-07661 <sejalsomkuwar4 at gmail.com>
Date: Tue, 10 Feb 2026 01:32:31 +0530
Subject: [PATCH 2/2] [MLIR][Shape] Fix ShapeOfOp canonicalization for dynamic
 extent tensors

---
 mlir/lib/Dialect/Shape/IR/Shape.cpp       | 51 ++++++++++++++++-------
 mlir/test/Dialect/Shape/canonicalize.mlir | 25 +++++------
 2 files changed, 48 insertions(+), 28 deletions(-)

diff --git a/mlir/lib/Dialect/Shape/IR/Shape.cpp b/mlir/lib/Dialect/Shape/IR/Shape.cpp
index a3aa87adc5b30..739c7bf5ea427 100644
--- a/mlir/lib/Dialect/Shape/IR/Shape.cpp
+++ b/mlir/lib/Dialect/Shape/IR/Shape.cpp
@@ -1700,26 +1700,49 @@ struct ShapeOfOpToConstShapeOp : public OpRewritePattern<shape::ShapeOfOp> {
   using OpRewritePattern<shape::ShapeOfOp>::OpRewritePattern;
 
   LogicalResult matchAndRewrite(shape::ShapeOfOp op,
-                              PatternRewriter &rewriter) const override {
-  auto shapedTy = dyn_cast<ShapedType>(op.getArg().getType());
-  if (!shapedTy || !shapedTy.hasStaticShape())
-    return failure();
+                                PatternRewriter &rewriter) const override {
+    auto shapedTy = dyn_cast<ShapedType>(op.getArg().getType());
+    if (!shapedTy || !shapedTy.hasStaticShape())
+      return failure();
 
-  Location loc = op.getLoc();
-  auto attr = rewriter.getIndexTensorAttr(shapedTy.getShape());
+    Location loc = op.getLoc();
+    auto shapeAttr = rewriter.getIndexTensorAttr(shapedTy.getShape());
+    Type resultTy = op.getType();
 
-  // IMPORTANT: Build const_shape with the SAME result type as shape_of.
-  // This avoids creating a tensor.cast to a non-tensor type (!shape.shape).
-  Value constShape = rewriter
-      .create<shape::ConstShapeOp>(loc, op.getType(), attr)
-      .getResult();
+    // Case 1: Result is !shape.shape
+    if (llvm::isa<shape::ShapeType>(resultTy)) {
+      Value cs =
+          rewriter.create<shape::ConstShapeOp>(loc, resultTy, shapeAttr)
+              .getResult();
+      rewriter.replaceOp(op, cs);
+      return success();
+    }
 
-  rewriter.replaceOp(op, constShape);
-  return success();
-}
+    // Case 2: Result is an extent tensor (tensor<...xindex>)
+    auto resultTensorTy = llvm::dyn_cast<RankedTensorType>(resultTy);
+    if (!resultTensorTy)
+      return failure();
 
+    // Build const_shape with the concrete ranked type implied by the constant.
+    int64_t rank = static_cast<int64_t>(shapedTy.getShape().size());
+    auto concreteTy = RankedTensorType::get({rank}, rewriter.getIndexType());
+
+    Value cs =
+        rewriter.create<shape::ConstShapeOp>(loc, concreteTy, shapeAttr)
+            .getResult();
+
+    // If shape_of wanted tensor<?xindex>, cast from tensor<Rxindex>.
+    if (concreteTy != resultTensorTy) {
+      cs = rewriter.create<tensor::CastOp>(loc, resultTensorTy, cs).getResult();
+    }
+
+    rewriter.replaceOp(op, cs);
+    return success();
+  }
 };
 
+
+
 // Canonicalize
 //
 // %0 = tensor.reshape %input(%shape) : (tensor<*xf32>, tensor<?xindex>) -> tensor<*xf32>
diff --git a/mlir/test/Dialect/Shape/canonicalize.mlir b/mlir/test/Dialect/Shape/canonicalize.mlir
index 1e1ef4b131e3c..4b929d6e0cbeb 100644
--- a/mlir/test/Dialect/Shape/canonicalize.mlir
+++ b/mlir/test/Dialect/Shape/canonicalize.mlir
@@ -1616,19 +1616,16 @@ func.func @shape_of_0d(%arg0: tensor<f32>) -> tensor<?xindex> {
 }
 
 
-// --------------------------------------------
-// ---- shape.shape_of canonicalize regression ----
-
-// RUN: mlir-opt %s -canonicalize | FileCheck %s
-
-module {
-  func.func @main(%arg0: tensor<2x3xi32>) -> !shape.shape {
-    %0 = shape.shape_of %arg0 : tensor<2x3xi32> -> !shape.shape
-    return %0 : !shape.shape
-  }
-}
+// -----
 
-// CHECK-LABEL: func.func @main
+// CHECK-LABEL: func.func @shape_of_canonicalize_regression
 // CHECK:       shape.const_shape [2, 3] : !shape.shape
-// CHECK-NOT:   shape.shape_of
-
+// CHECK:       shape.const_shape [2, 3] : tensor<2xindex>
+// CHECK:       tensor.cast
+func.func @shape_of_canonicalize_regression(%arg0: tensor<2x3xi32>)
+    -> (!shape.shape, tensor<2xindex>, tensor<?xindex>) {
+  %0 = shape.shape_of %arg0 : tensor<2x3xi32> -> !shape.shape
+  %1 = shape.shape_of %arg0 : tensor<2x3xi32> -> tensor<2xindex>
+  %2 = shape.shape_of %arg0 : tensor<2x3xi32> -> tensor<?xindex>
+  return %0, %1, %2 : !shape.shape, tensor<2xindex>, tensor<?xindex>
+}
\ No newline at end of file



More information about the Mlir-commits mailing list