[Mlir-commits] [mlir] [mlir][Utils] Add verifyRanksMatch helper (NFC) (PR #175880)

Nick Kreeger llvmlistbot at llvm.org
Thu Jan 15 15:04:49 PST 2026


https://github.com/nkreeger updated https://github.com/llvm/llvm-project/pull/175880

>From 4b0133674265b688ca9befbe4adf790525c7bb3c Mon Sep 17 00:00:00 2001
From: Nick Kreeger <nick.kreeger at microsoft.com>
Date: Wed, 14 Jan 2026 03:44:35 +0000
Subject: [PATCH 1/4] [mlir][Utils] Add verifyRanksMatch helper (NFC)

This change builds on https://github.com/llvm/llvm-project/pull/174336, which introduced shared VerificationUtils with an initial verifyDynamicDimensionCount() method.

This patch adds a new verifyRanksMatch() verification utility that checks if two shaped types have matching ranks and emits consistent error messages. The utility is applied to several ops across multiple MLIR dialects.
---
 .../mlir/Dialect/Utils/VerificationUtils.h    |  6 +++++
 .../Bufferization/IR/BufferizationOps.cpp     |  5 ++--
 mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp      |  7 +++---
 mlir/lib/Dialect/Tosa/IR/TosaOps.cpp          | 23 ++++++++++---------
 mlir/lib/Dialect/Utils/VerificationUtils.cpp  | 16 +++++++++++++
 mlir/test/Dialect/Tosa/invalid.mlir           |  6 ++---
 6 files changed, 44 insertions(+), 19 deletions(-)

diff --git a/mlir/include/mlir/Dialect/Utils/VerificationUtils.h b/mlir/include/mlir/Dialect/Utils/VerificationUtils.h
index c1c3cc6231eb6..94746f0b53254 100644
--- a/mlir/include/mlir/Dialect/Utils/VerificationUtils.h
+++ b/mlir/include/mlir/Dialect/Utils/VerificationUtils.h
@@ -27,6 +27,12 @@ namespace mlir {
 LogicalResult verifyDynamicDimensionCount(Operation *op, ShapedType type,
                                           ValueRange dynamicSizes);
 
+/// Verify that two shaped types have matching ranks. Returns failure and emits
+/// an error if ranks don't match. Unranked types are considered compatible.
+LogicalResult verifyRanksMatch(Operation *op, ShapedType type1,
+                               ShapedType type2, StringRef name1,
+                               StringRef name2);
+
 } // namespace mlir
 
 #endif // MLIR_DIALECT_UTILS_VERIFICATIONUTILS_H
diff --git a/mlir/lib/Dialect/Bufferization/IR/BufferizationOps.cpp b/mlir/lib/Dialect/Bufferization/IR/BufferizationOps.cpp
index eda6bf276be06..d3d9d23302226 100644
--- a/mlir/lib/Dialect/Bufferization/IR/BufferizationOps.cpp
+++ b/mlir/lib/Dialect/Bufferization/IR/BufferizationOps.cpp
@@ -702,8 +702,9 @@ LogicalResult MaterializeInDestinationOp::verify() {
   if (srcType.hasRank() != destType.hasRank())
     return emitOpError("source/destination shapes are incompatible");
   if (srcType.hasRank()) {
-    if (srcType.getRank() != destType.getRank())
-      return emitOpError("rank mismatch between source and destination shape");
+    if (failed(verifyRanksMatch(getOperation(), srcType, destType, "source",
+                                "destination")))
+      return failure();
     for (auto [src, dest] :
          llvm::zip(srcType.getShape(), destType.getShape())) {
       if (src == ShapedType::kDynamic || dest == ShapedType::kDynamic) {
diff --git a/mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp b/mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp
index 210f9584c1e86..e9f617a785d22 100644
--- a/mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp
+++ b/mlir/lib/Dialect/Linalg/IR/LinalgOps.cpp
@@ -24,6 +24,7 @@
 #include "mlir/Dialect/Utils/IndexingUtils.h"
 #include "mlir/Dialect/Utils/ReshapeOpsUtils.h"
 #include "mlir/Dialect/Utils/StaticValueUtils.h"
+#include "mlir/Dialect/Utils/VerificationUtils.h"
 #include "mlir/IR/AffineMap.h"
 #include "mlir/IR/Attributes.h"
 #include "mlir/IR/Builders.h"
@@ -2043,9 +2044,9 @@ LogicalResult TransposeOp::verify() {
 
   int64_t rank = inputType.getRank();
 
-  if (rank != initType.getRank())
-    return emitOpError() << "input rank " << rank
-                         << " does not match init rank " << initType.getRank();
+  if (failed(verifyRanksMatch(getOperation(), inputType, initType, "input",
+                              "init")))
+    return failure();
 
   if (rank != static_cast<int64_t>(permutationRef.size()))
     return emitOpError() << "size of permutation " << permutationRef.size()
diff --git a/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp b/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
index 5656f3de698c5..f123c6ac72083 100644
--- a/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
+++ b/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
@@ -19,6 +19,7 @@
 #include "mlir/Dialect/Tosa/Utils/QuantUtils.h"
 #include "mlir/Dialect/Tosa/Utils/ShapeUtils.h"
 #include "mlir/Dialect/Utils/IndexingUtils.h"
+#include "mlir/Dialect/Utils/VerificationUtils.h"
 #include "mlir/IR/BuiltinTypes.h"
 #include "mlir/IR/DialectImplementation.h"
 #include "mlir/IR/Matchers.h"
@@ -2126,13 +2127,11 @@ LogicalResult tosa::PadOp::verify() {
   if (!inputType || !outputType)
     return success();
 
-  auto inputRank = inputType.getRank();
-  auto outputRank = outputType.getRank();
-  if (inputRank != outputRank)
-    return emitOpError() << "expect same input and output tensor rank, but got "
-                         << "inputRank: " << inputRank
-                         << ", outputRank: " << outputRank;
+  if (failed(verifyRanksMatch(getOperation(), inputType, outputType, "input",
+                              "output")))
+    return failure();
 
+  auto inputRank = inputType.getRank();
   DenseIntElementsAttr paddingAttr;
   if (!matchPattern(getPadding(), m_Constant(&paddingAttr))) {
     return failure();
@@ -2373,9 +2372,9 @@ LogicalResult tosa::TableOp::verify() {
   if (!inputType.hasRank() || !outputType.hasRank())
     return success();
 
-  if (inputType.getRank() != outputType.getRank())
-    return emitOpError()
-           << "expected input tensor rank to equal result tensor rank";
+  if (failed(verifyRanksMatch(getOperation(), inputType, outputType, "input",
+                              "result")))
+    return failure();
 
   auto inputDims = inputType.getShape();
   auto outputDims = outputType.getShape();
@@ -2465,8 +2464,10 @@ LogicalResult tosa::TileOp::verify() {
     if (inputType.getRank() != multiplesRank)
       return emitOpError("expect 'multiples' to have rank ")
              << inputType.getRank() << " but got " << multiplesRank << ".";
-    if (outputType.hasRank() && inputType.getRank() != outputType.getRank())
-      return emitOpError("expect same input and output tensor rank.");
+    if (outputType.hasRank() &&
+        failed(verifyRanksMatch(getOperation(), inputType, outputType, "input",
+                                "output")))
+      return failure();
   } else if (outputType.hasRank() && outputType.getRank() != multiplesRank)
     return emitOpError("expect 'multiples' array to have length ")
            << outputType.getRank() << " but got " << multiplesRank << ".";
diff --git a/mlir/lib/Dialect/Utils/VerificationUtils.cpp b/mlir/lib/Dialect/Utils/VerificationUtils.cpp
index 22b224713a6a3..9b3bfda42b91a 100644
--- a/mlir/lib/Dialect/Utils/VerificationUtils.cpp
+++ b/mlir/lib/Dialect/Utils/VerificationUtils.cpp
@@ -20,3 +20,19 @@ LogicalResult mlir::verifyDynamicDimensionCount(Operation *op, ShapedType type,
   }
   return success();
 }
+
+LogicalResult mlir::verifyRanksMatch(Operation *op, ShapedType type1,
+                                     ShapedType type2, StringRef name1,
+                                     StringRef name2) {
+  if (!type1.hasRank() || !type2.hasRank())
+    return success(); // Unranked types are considered compatible
+
+  int64_t rank1 = type1.getRank();
+  int64_t rank2 = type2.getRank();
+  if (rank1 != rank2) {
+    return op->emitOpError()
+           << name1 << " rank (" << rank1 << ") does not match " << name2
+           << " rank (" << rank2 << ")";
+  }
+  return success();
+}
diff --git a/mlir/test/Dialect/Tosa/invalid.mlir b/mlir/test/Dialect/Tosa/invalid.mlir
index e8206c24f1507..cf93563fb0878 100644
--- a/mlir/test/Dialect/Tosa/invalid.mlir
+++ b/mlir/test/Dialect/Tosa/invalid.mlir
@@ -292,7 +292,7 @@ func.func @test_pad_const_non_const(%arg0: tensor<13x21x3xi8>, %arg1: tensor<1xi
 func.func @test_pad_io_rank_mismatch(%arg0: tensor<13x21xf32>) {
   %0 = tosa.const_shape {values = dense<1> : tensor<4xindex>} : () -> !tosa.shape<4>
   %pad_const = "tosa.const"() {values = dense<3.14> : tensor<1xf32>} : () -> tensor<1xf32>
-  // expected-error at +1 {{'tosa.pad' op expect same input and output tensor rank}}
+  // expected-error at +1 {{'tosa.pad' op input rank (2) does not match output rank (3)}}
   %1 = tosa.pad %arg0, %0, %pad_const : (tensor<13x21xf32>, !tosa.shape<4>, tensor<1xf32>) -> tensor<13x21x3xf32>
 }
 
@@ -663,7 +663,7 @@ func.func @test_tile_invalid_multiples_value() {
 func.func @test_tile_io_rank_mismatch() {
   %0 = tensor.empty() : tensor<4x31xf32>
   %multiples = tosa.const_shape { values = dense<[2, 2]> : tensor<2xindex> } : () -> !tosa.shape<2>
-  // expected-error at +1 {{'tosa.tile' op expect same input and output tensor rank.}}
+  // expected-error at +1 {{'tosa.tile' op input rank (2) does not match output rank (3)}}
   %1 = tosa.tile %0, %multiples : (tensor<4x31xf32>, !tosa.shape<2>) -> tensor<4x31x31xf32>
   return
 }
@@ -682,7 +682,7 @@ func.func @test_table_rank0_table(%arg0: tensor<64xi16>, %arg1: tensor<i16>) {
 
 // CHECK-LABEL: test_table_io_rank_mismatch
 func.func @test_table_io_rank_mismatch(%arg0: tensor<64xi16>, %arg1: tensor<6xi16>) {
-  // expected-error at +1 {{'tosa.table' op expected input tensor rank to equal result tensor rank}}
+  // expected-error at +1 {{'tosa.table' op input rank (1) does not match result rank (2)}}
   %0 = tosa.table %arg0, %arg1 : (tensor<64xi16>, tensor<6xi16>) -> tensor<64x?xi16>
   return
 }

>From 5aca8438df6c95aeddf9ed01939e5d1b01a359b4 Mon Sep 17 00:00:00 2001
From: Nick Kreeger <nick.kreeger at microsoft.com>
Date: Wed, 14 Jan 2026 04:04:06 +0000
Subject: [PATCH 2/4] Fix tests.

---
 mlir/test/Dialect/Bufferization/invalid.mlir | 2 +-
 mlir/test/Dialect/Linalg/invalid.mlir        | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/mlir/test/Dialect/Bufferization/invalid.mlir b/mlir/test/Dialect/Bufferization/invalid.mlir
index 76aba14bc50f2..f3368b9108d65 100644
--- a/mlir/test/Dialect/Bufferization/invalid.mlir
+++ b/mlir/test/Dialect/Bufferization/invalid.mlir
@@ -51,7 +51,7 @@ func.func @invalid_materialize_in_destination(%arg0: tensor<4xf32>, %arg1: tenso
 // -----
 
 func.func @invalid_materialize_in_destination(%arg0: tensor<5x5xf32>, %arg1: tensor<5xf32>) {
-  // expected-error @below{{rank mismatch between source and destination shape}}
+  // expected-error @below{{'bufferization.materialize_in_destination' op source rank (2) does not match destination rank (1)}}
   bufferization.materialize_in_destination %arg0 in %arg1 : (tensor<5x5xf32>, tensor<5xf32>) -> tensor<5xf32>
 }
 
diff --git a/mlir/test/Dialect/Linalg/invalid.mlir b/mlir/test/Dialect/Linalg/invalid.mlir
index d70cdceed6b86..355d801f8732c 100644
--- a/mlir/test/Dialect/Linalg/invalid.mlir
+++ b/mlir/test/Dialect/Linalg/invalid.mlir
@@ -1068,7 +1068,7 @@ func.func @transpose_rank_permutation_size_mismatch(
 
 func.func @transpose_input_init_rank_mismatch(%input: tensor<16x32xf32>,
     %init: tensor<32x64x16xf32>) -> tensor<32x64x16xf32> {
-  // expected-error @+1 {{'linalg.transpose' op input rank 2 does not match init rank 3}}
+  // expected-error @+1 {{'linalg.transpose' op input rank (2) does not match init rank (3)}}
   %transpose = linalg.transpose
       ins(%input:tensor<16x32xf32>)
       outs(%init:tensor<32x64x16xf32>)

>From 285dca490d00b345ea2704590e5076183a353f94 Mon Sep 17 00:00:00 2001
From: Nick Kreeger <nick.kreeger at gmail.com>
Date: Thu, 15 Jan 2026 17:04:31 -0600
Subject: [PATCH 3/4] Update
 mlir/include/mlir/Dialect/Utils/VerificationUtils.h
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Andrzej Warzyński <andrzej.warzynski at gmail.com>
---
 mlir/include/mlir/Dialect/Utils/VerificationUtils.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/mlir/include/mlir/Dialect/Utils/VerificationUtils.h b/mlir/include/mlir/Dialect/Utils/VerificationUtils.h
index 94746f0b53254..ba642c11bd4f2 100644
--- a/mlir/include/mlir/Dialect/Utils/VerificationUtils.h
+++ b/mlir/include/mlir/Dialect/Utils/VerificationUtils.h
@@ -29,9 +29,9 @@ LogicalResult verifyDynamicDimensionCount(Operation *op, ShapedType type,
 
 /// Verify that two shaped types have matching ranks. Returns failure and emits
 /// an error if ranks don't match. Unranked types are considered compatible.
-LogicalResult verifyRanksMatch(Operation *op, ShapedType type1,
-                               ShapedType type2, StringRef name1,
-                               StringRef name2);
+LogicalResult verifyRanksMatch(Operation *op, ShapedType lhs,
+                               ShapedType rhs, StringRef lhsName,
+                               StringRef rhsName);
 
 } // namespace mlir
 

>From 3bfde0f229cfb0865080643c406c38af38b52770 Mon Sep 17 00:00:00 2001
From: Nick Kreeger <nick.kreeger at gmail.com>
Date: Thu, 15 Jan 2026 17:04:40 -0600
Subject: [PATCH 4/4] Update mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Andrzej Warzyński <andrzej.warzynski at gmail.com>
---
 mlir/lib/Dialect/Tosa/IR/TosaOps.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp b/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
index f123c6ac72083..dc3320044ba95 100644
--- a/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
+++ b/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
@@ -2127,7 +2127,7 @@ LogicalResult tosa::PadOp::verify() {
   if (!inputType || !outputType)
     return success();
 
-  if (failed(verifyRanksMatch(getOperation(), inputType, outputType, "input",
+  if (failed(verifyRanksMatch(this, inputType, outputType, "input",
                               "output")))
     return failure();
 



More information about the Mlir-commits mailing list