[Mlir-commits] [mlir] [mlir][Tosa] Handle empty block-scaled reshape shapes (PR #220872)

Mehdi Amini llvmlistbot at llvm.org
Thu Sep 3 04:06:49 PDT 2026


https://github.com/joker-eph created https://github.com/llvm/llvm-project/pull/220872

Guard the inferred scale shape before accessing its last dimension, and reject rank-zero block-scaled reshape shapes before the unranked-input early exit. Preserve dynamic scale dimensions instead of applying block-size arithmetic to their sentinel.

Found by Coverity.

Assisted-by: Codex

>From aa676630f2bbc2b59bd7a1192651e01fe85f11c2 Mon Sep 17 00:00:00 2001
From: Mehdi Amini <joker.eph at gmail.com>
Date: Wed, 2 Sep 2026 15:25:24 -0700
Subject: [PATCH] [mlir][Tosa] Handle empty block-scaled reshape shapes

Guard the inferred scale shape before accessing its last dimension, and
reject rank-zero block-scaled reshape shapes before the unranked-input
early exit. Preserve dynamic scale dimensions instead of applying block-size
arithmetic to their sentinel.

Valgrind exposed the pre-fix assertion failure:

  mlir-opt: llvm/ADT/SmallVector.h:318: back(): Assertion `!empty()`
  failed.
  #12 mlir::tosa::ReshapeBlockScaledOp::inferReturnTypes(...)
  ==569000== Process terminating with default action of signal 6 (SIGABRT)
  ==569000== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Found by Coverity.

Assisted-by: Codex
---
 mlir/lib/Dialect/Tosa/IR/TosaOps.cpp | 17 ++++++++++-------
 mlir/test/Dialect/Tosa/verifier.mlir |  9 +++++++++
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp b/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
index 7d4d4f0d27a84..c4117d95fed11 100644
--- a/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
+++ b/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
@@ -3192,7 +3192,8 @@ LogicalResult tosa::ReshapeBlockScaledOp::inferReturnTypeComponents(
   llvm::SmallVector<int64_t> newScaleShapeValue;
   if (numInputs == 2) {
     newScaleShapeValue.assign(newShapeValue.begin(), newShapeValue.end());
-    if (ShapedType::isStatic(newScaleShapeValue.back()))
+    if (!newScaleShapeValue.empty() &&
+        ShapedType::isStatic(newScaleShapeValue.back()))
       newScaleShapeValue.back() /= blockSize;
   }
 
@@ -3203,7 +3204,8 @@ LogicalResult tosa::ReshapeBlockScaledOp::inferReturnTypeComponents(
     for (size_t idx = 0; idx < newShapeValue.size(); idx++) {
       if (ShapedType::isDynamic(newScaleShapeValue[idx])) {
         newScaleShapeValue[idx] = newShapeValue[idx];
-        if (idx == (newShapeValue.size() - 1))
+        if (idx + 1 == newShapeValue.size() &&
+            ShapedType::isStatic(newScaleShapeValue[idx]))
           newScaleShapeValue[idx] /= blockSize;
       }
     }
@@ -3234,10 +3236,14 @@ llvm::LogicalResult tosa::ReshapeBlockScaledOp::verify() {
     return failure();
   }
 
+  const uint32_t blockSize = BlockSizeAttr::getBlockSizeValue(getBlockSize());
+  if (inputList.size() == 2 &&
+      cast<tosa::shapeType>(getNewValueShape().getType()).getRank() == 0)
+    return emitOpError("requires new shape to have a rank greater than 0");
+
   const auto inputType = llvm::cast<ShapedType>(inputList[0].getType());
   if (!inputType.hasRank())
     return success();
-  const uint32_t blockSize = BlockSizeAttr::getBlockSizeValue(getBlockSize());
 
   if (inputList.size() == 2) {
     if (blockSize != BlockSizeAttr::getBlockSizeValue(BlockSize::BLOCK_SIZE_32))
@@ -3302,7 +3308,7 @@ llvm::LogicalResult tosa::ReshapeBlockScaledOp::verify() {
       return emitOpError("expect block size to be 1, got ") << blockSize;
   }
 
-  // Get the new value shape dimension values
+  // Get the new value shape dimension values.
   SmallVector<int64_t> shapeValues;
   if (!tosa::getConstShapeValues(getNewValueShape().getDefiningOp(),
                                  shapeValues)) {
@@ -3311,9 +3317,6 @@ llvm::LogicalResult tosa::ReshapeBlockScaledOp::verify() {
   }
 
   if (inputList.size() == 2) {
-    if (static_cast<int64_t>(shapeValues.size()) == 0)
-      return emitOpError("requires new shape to have a rank greater than 0");
-
     const int64_t lastShapeDim = shapeValues.back();
     if (ShapedType::isStatic(lastShapeDim) && lastShapeDim % blockSize != 0)
       return emitOpError("expect last dimension of new shape (")
diff --git a/mlir/test/Dialect/Tosa/verifier.mlir b/mlir/test/Dialect/Tosa/verifier.mlir
index 803ded01698a1..cd71fffbe9962 100644
--- a/mlir/test/Dialect/Tosa/verifier.mlir
+++ b/mlir/test/Dialect/Tosa/verifier.mlir
@@ -2268,6 +2268,15 @@ func.func @test_reshape_block_scaled_rank0_scale_input(%arg0 : tensor<64xf8E4M3F
 
 // -----
 
+func.func @test_reshape_block_scaled_rank0_shape_unranked_inputs(%arg0 : tensor<*xf8E4M3FN>, %arg1 : tensor<*xf8E8M0FNU>) -> () {
+  %s = tosa.const_shape {values = dense<> : tensor<0xindex>} : () -> !tosa.shape<0>
+  // expected-error at +1 {{'tosa.reshape_block_scaled' op requires new shape to have a rank greater than 0}}
+  %0:2 = "tosa.reshape_block_scaled"(%arg0, %arg1, %s) {block_size = #tosa.block_size<BLOCK_SIZE_32> : i32} : (tensor<*xf8E4M3FN>, tensor<*xf8E8M0FNU>, !tosa.shape<0>) -> (tensor<*xf8E4M3FN>, tensor<*xf8E8M0FNU>)
+  return
+}
+
+// -----
+
 func.func @test_reshape_non_block_scaled_block_size_mismatch(%arg0: tensor<13x21x3xf32>) -> tensor<1x819xf32> {
   %s = tosa.const_shape {values = dense<[1, 819]> : tensor<2xindex>} : () -> !tosa.shape<2>
   // expected-error at +1 {{'tosa.reshape_block_scaled' op expect block size to be 1, got 32}}



More information about the Mlir-commits mailing list