[Mlir-commits] [mlir] [mlir][tosa] Move ResizeOp shape checks from verifier to tosa-validate (PR #234101)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Sun Oct 25 20:23:32 PDT 2026


https://github.com/Wijkqwe updated https://github.com/llvm/llvm-project/pull/234101

>From 3cf6629fc8d558b25a6430dde7aa876a7f893cb4 Mon Sep 17 00:00:00 2001
From: wzy <WZYqwe2004 at outlook.com>
Date: Wed, 21 Oct 2026 15:35:52 +0800
Subject: [PATCH 1/5] it just works

---
 mlir/lib/Dialect/Tosa/IR/TosaOps.cpp          | 83 +------------------
 .../Tosa/Transforms/TosaValidation.cpp        |  4 +
 2 files changed, 5 insertions(+), 82 deletions(-)

diff --git a/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp b/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
index 99c352ab8ed3c3..f298c90ae6310a 100644
--- a/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
+++ b/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
@@ -3746,93 +3746,12 @@ LogicalResult tosa::ResizeOp::inferReturnTypeComponents(
 }
 
 LogicalResult tosa::ResizeOp::verify() {
-  const Value input = getInput();
-  const Value output = getOutput();
-  const Type inputElementType = getElementTypeOrSelf(input.getType());
+  const Type inputElementType = getElementTypeOrSelf(getInput().getType());
 
   if (isa<BlockScaledType>(inputElementType) &&
       getMode() != ResizeMode::NEAREST_NEIGHBOR)
     return emitOpError("requires NEAREST_NEIGHBOR mode for block scaled input");
 
-  const RankedTensorType inputType =
-      llvm::dyn_cast<RankedTensorType>(input.getType());
-  const RankedTensorType outputType =
-      llvm::dyn_cast<RankedTensorType>(output.getType());
-
-  SmallVector<int64_t> scaleValues;
-  SmallVector<int64_t> offsetValues;
-  SmallVector<int64_t> borderValues;
-  if (!tosa::getConstShapeValues(getScale().getDefiningOp(), scaleValues) ||
-      !tosa::getConstShapeValues(getOffset().getDefiningOp(), offsetValues) ||
-      !tosa::getConstShapeValues(getBorder().getDefiningOp(), borderValues)) {
-    // Skip following checks if shape is not constant
-    return success();
-  }
-
-  if (llvm::any_of(scaleValues, [](int64_t s) { return s <= 0; }))
-    return emitOpError("expect all scale values to be > 0, got ")
-           << scaleValues;
-
-  const int64_t scaleYN = scaleValues[0];
-  const int64_t scaleYD = scaleValues[1];
-  const int64_t scaleXN = scaleValues[2];
-  const int64_t scaleXD = scaleValues[3];
-
-  const int64_t offsetY = offsetValues[0];
-  const int64_t offsetX = offsetValues[1];
-
-  const int64_t borderY = borderValues[0];
-  const int64_t borderX = borderValues[1];
-
-  if (!inputType)
-    return success();
-  if (!outputType)
-    return success();
-
-  const int64_t oh = outputType.getDimSize(1);
-  const int64_t ow = outputType.getDimSize(2);
-  const int64_t ih = inputType.getDimSize(1);
-  const int64_t iw = inputType.getDimSize(2);
-
-  // Don't check with input height that could be broadcast (ih != 1)
-  // since Linalg, a consumer of TOSA, expects broadcasting support
-  // in resize to be available. Taking the cautious approach for now,
-  // we can consider removing support for broadcasting later.
-  if (ih != ShapedType::kDynamic && ih != 1) {
-    const std::optional<int64_t> calculatedOutHeightMinusOne =
-        idivCheck((ih - 1) * scaleYN - offsetY + borderY, scaleYD);
-    if (!calculatedOutHeightMinusOne.has_value())
-      return emitOpError("expected (input_height - 1) * scale_y_n - offset_y + "
-                         "border_y ")
-             << "to be wholly divisible by scale_y_d, got ((" << ih
-             << " - 1) * " << scaleYN << " - " << offsetY << " + " << borderY
-             << ") / " << scaleYD;
-    const int64_t calculatedOutHeight = calculatedOutHeightMinusOne.value() + 1;
-    if (oh != ShapedType::kDynamic && calculatedOutHeight != oh)
-      return emitOpError("calculated output height did not match expected: ")
-             << "calculated=" << calculatedOutHeight << ", expected=" << oh;
-  }
-
-  // Don't check with input width that could be broadcast (iw != 1)
-  // since Linalg, a consumer of TOSA, expects broadcasting support
-  // in resize to be available. Taking the cautious approach for now,
-  // we can consider removing support for broadcasting later.
-  if (iw != ShapedType::kDynamic && iw != 1) {
-    const int64_t scaledInWidth = (iw - 1) * scaleXN - offsetX + borderX;
-    const std::optional<int64_t> calculatedOutWidthMinusOne =
-        idivCheck(scaledInWidth, scaleXD);
-    if (!calculatedOutWidthMinusOne.has_value())
-      return emitOpError("expected (input_width - 1) * scale_x_n - offset_x + "
-                         "border_x ")
-             << "to be wholly divisible by scale_x_d, got ((" << iw
-             << " - 1) * " << scaleXN << " - " << offsetX << " + " << borderX
-             << ") / " << scaleXD;
-    const int64_t calculatedOutWidth = calculatedOutWidthMinusOne.value() + 1;
-    if (ow != ShapedType::kDynamic && calculatedOutWidth != ow)
-      return emitOpError("calculated output width did not match expected: ")
-             << "calculated=" << calculatedOutWidth << ", expected=" << ow;
-  }
-
   return success();
 }
 
diff --git a/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp b/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
index 5d465065497abf..c6156627e6e0e6 100644
--- a/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
+++ b/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
@@ -1135,6 +1135,10 @@ LogicalResult checkErrorIfResize(Operation *op) {
   const int64_t scaleXN = scale[2];
   const int64_t scaleXD = scale[3];
 
+  // ERROR_IF(scale <= 0)
+  if (llvm::any_of(scale, [](int64_t s) { return s <= 0; }))
+    return op->emitOpError("expect all scale values to be > 0, got ") << scale;
+
   // Ensure scale values don't overflow int32 accumulator
   if (scaleYN > (1 << 11) || scaleXN > (1 << 11))
     return op->emitOpError(

>From ada75084428562165286011ea76a03af80fe0107 Mon Sep 17 00:00:00 2001
From: wzy <WZYqwe2004 at outlook.com>
Date: Wed, 21 Oct 2026 16:04:27 +0800
Subject: [PATCH 2/5] fixed failed test

---
 mlir/lib/Dialect/Tosa/IR/TosaOps.cpp | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp b/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
index f298c90ae6310a..82f9f6b52b3645 100644
--- a/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
+++ b/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
@@ -3720,6 +3720,11 @@ LogicalResult tosa::ResizeOp::inferReturnTypeComponents(
     return failure();
   }
 
+  // Non-positive scale values are invalid, so the output shape cannot be
+  // inferred here. They are reported by the ERROR_IF check in tosa-validate.
+  if (llvm::any_of(scaleInt, [](int64_t s) { return s <= 0; }))
+    return failure();
+
   // Compute the output shape based on attributes: scale, offset, and border.
   const int64_t outputHeight =
       (((inputHeight - 1) * scaleInt[0] - offsetInt[0] + borderInt[0]) /

>From 96f9f787c4e5141587a827b57c0fa4ba03c6229e Mon Sep 17 00:00:00 2001
From: wzy <WZYqwe2004 at outlook.com>
Date: Wed, 21 Oct 2026 16:06:19 +0800
Subject: [PATCH 3/5] fixed abort

---
 .../lib/Dialect/Tosa/Transforms/TosaValidation.cpp |  8 ++++++++
 mlir/test/Dialect/Tosa/tosa-infer-shapes.mlir      | 14 ++++++++++++++
 2 files changed, 22 insertions(+)

diff --git a/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp b/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
index c6156627e6e0e6..ba03de78443552 100644
--- a/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
+++ b/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
@@ -608,6 +608,14 @@ struct TosaValidation : public tosa::impl::TosaValidationBase<TosaValidation> {
       const int64_t scaleYD = scale[1];
       const int64_t scaleXN = scale[2];
       const int64_t scaleXD = scale[3];
+
+      // Invalid (non-positive) scale values are reported by the ERROR_IF
+      // check in applyErrorIfCheck(). Skip the level ratio check here to
+      // avoid dividing by a non-positive value and reporting a misleading
+      // level error for an already-invalid scale.
+      if (llvm::any_of(scale, [](int64_t s) { return s <= 0; }))
+        return success();
+
       if (failed(
               levelCheckScale(op, scaleYN / scaleYD, "scale_y_n/scale_y_d")) ||
           failed(
diff --git a/mlir/test/Dialect/Tosa/tosa-infer-shapes.mlir b/mlir/test/Dialect/Tosa/tosa-infer-shapes.mlir
index 7ffdcbfcf99c43..b9fa1923788d0e 100644
--- a/mlir/test/Dialect/Tosa/tosa-infer-shapes.mlir
+++ b/mlir/test/Dialect/Tosa/tosa-infer-shapes.mlir
@@ -2340,3 +2340,17 @@ func.func @while_with_sparse_tensor_encoding() {
   }
   return
 }
+
+// -----
+
+// A resize with invalid (non-positive) scale values cannot infer an output
+// shape, so the result type is left unchanged.
+// CHECK-LABEL: @resize_invalid_scale
+func.func @resize_invalid_scale(%arg0: tensor<1x50x48x1xf32>) {
+  %scale = tosa.const_shape values(dense<[2, 0, -1, 2]> : tensor<4xindex>) : () -> !tosa.shape<4>
+  %offset = tosa.const_shape values(dense<0> : tensor<2xindex>) : () -> !tosa.shape<2>
+  %border = tosa.const_shape values(dense<0> : tensor<2xindex>) : () -> !tosa.shape<2>
+  // CHECK: -> tensor<?x?x?x?xf32>
+  %0 = tosa.resize %arg0, %scale, %offset, %border mode<NEAREST_NEIGHBOR> : (tensor<1x50x48x1xf32>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<?x?x?x?xf32>
+  return
+}

>From 9c8f3e67a833872e60acec76360c662d37d32ce1 Mon Sep 17 00:00:00 2001
From: wzy <WZYqwe2004 at outlook.com>
Date: Mon, 26 Oct 2026 11:14:24 +0800
Subject: [PATCH 4/5] added tests

---
 mlir/test/Dialect/Tosa/error_if_check.mlir | 12 ++++++++++++
 mlir/test/Dialect/Tosa/level_check.mlir    | 13 +++++++++++++
 2 files changed, 25 insertions(+)

diff --git a/mlir/test/Dialect/Tosa/error_if_check.mlir b/mlir/test/Dialect/Tosa/error_if_check.mlir
index b87f124f64ac27..4837ec8c58a5e0 100644
--- a/mlir/test/Dialect/Tosa/error_if_check.mlir
+++ b/mlir/test/Dialect/Tosa/error_if_check.mlir
@@ -86,6 +86,18 @@ func.func @test_resize_invalid_boarder_x(%arg0: tensor<1x8x8x8xf32>) -> tensor<?
 
 // -----
 
+// CHECK-LABEL: test_resize_nonpositive_scale
+func.func @test_resize_nonpositive_scale(%arg0: tensor<1x8x8x8xf32>) -> tensor<?x?x?x?xf32> {
+  %scale = tosa.const_shape values(dense<[2, 0, -1, 2]> : tensor<4xindex>) : () -> !tosa.shape<4>
+  %offset = tosa.const_shape values(dense<0> : tensor<2xindex>) : () -> !tosa.shape<2>
+  %border = tosa.const_shape values(dense<0> : tensor<2xindex>) : () -> !tosa.shape<2>
+  // expected-error at +1 {{'tosa.resize' op expect all scale values to be > 0, got 2, 0, -1, 2}}
+  %1 = tosa.resize %arg0, %scale, %offset, %border mode<BILINEAR> : (tensor<1x8x8x8xf32>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<?x?x?x?xf32>
+  return %1 : tensor<?x?x?x?xf32>
+}
+
+// -----
+
 // CHECK-LABEL: test_reshape_inferable_dim
 func.func @test_reshape_inferable_dim(%arg0: tensor<4xf32>) -> tensor<?x2xf32> {
   %shape = tosa.const_shape values(dense<[-1, 2]> : tensor<2xindex>) : () -> !tosa.shape<2>
diff --git a/mlir/test/Dialect/Tosa/level_check.mlir b/mlir/test/Dialect/Tosa/level_check.mlir
index 2d1dfbf5b45b85..cde4f4d9e3fdec 100644
--- a/mlir/test/Dialect/Tosa/level_check.mlir
+++ b/mlir/test/Dialect/Tosa/level_check.mlir
@@ -1202,6 +1202,19 @@ func.func @test_resize_scale_x(%arg0: tensor<1x32x32x8xf32>) -> tensor<1x64x7970
 
 // -----
 
+// A non-positive scale is invalid and reported by the ERROR_IF check under
+// strict-op-spec-alignment. Here (non-strict), the level check must skip the
+// scale ratio comparison to avoid dividing by scale_x_d = 0.
+func.func @test_resize_nonpositive_scale_skips_level_check(%arg0: tensor<1x32x32x8xf32>) -> tensor<1x64x64x8xf32> {
+  %scale = tosa.const_shape values(dense<[4, 2, 1, 0]> : tensor<4xindex>) : () -> !tosa.shape<4>
+  %offset = tosa.const_shape values(dense<0> : tensor<2xindex>) : () -> !tosa.shape<2>
+  %border = tosa.const_shape values(dense<0> : tensor<2xindex>) : () -> !tosa.shape<2>
+  %1 = tosa.resize %arg0, %scale, %offset, %border mode<BILINEAR> : (tensor<1x32x32x8xf32>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<1x64x64x8xf32>
+  return %1 : tensor<1x64x64x8xf32>
+}
+
+// -----
+
 func.func @test_tensor_size_valid(%arg0: tensor<1x536870911xf32>) {
   %0 = tosa.const_shape values(dense<0> : tensor<2xindex>) : () -> !tosa.shape<2>
   %1 = tosa.const_shape values(dense<1> : tensor<2xindex>) : () -> !tosa.shape<2>

>From ab7cd86a797f98ce25aaa517b31f0351b8ff35b5 Mon Sep 17 00:00:00 2001
From: wzy <WZYqwe2004 at outlook.com>
Date: Mon, 26 Oct 2026 11:14:48 +0800
Subject: [PATCH 5/5] move

---
 mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp b/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
index ba03de78443552..24307015eecf77 100644
--- a/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
+++ b/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
@@ -1138,15 +1138,15 @@ LogicalResult checkErrorIfResize(Operation *op) {
   if (!tosa::getConstShapeValues(resize.getScale().getDefiningOp(), scale))
     return failure();
 
+  // ERROR_IF(scale <= 0)
+  if (llvm::any_of(scale, [](int64_t s) { return s <= 0; }))
+    return op->emitOpError("expect all scale values to be > 0, got ") << scale;
+
   const int64_t scaleYN = scale[0];
   const int64_t scaleYD = scale[1];
   const int64_t scaleXN = scale[2];
   const int64_t scaleXD = scale[3];
 
-  // ERROR_IF(scale <= 0)
-  if (llvm::any_of(scale, [](int64_t s) { return s <= 0; }))
-    return op->emitOpError("expect all scale values to be > 0, got ") << scale;
-
   // Ensure scale values don't overflow int32 accumulator
   if (scaleYN > (1 << 11) || scaleXN > (1 << 11))
     return op->emitOpError(



More information about the Mlir-commits mailing list