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

llvmlistbot at llvm.org llvmlistbot at llvm.org
Wed Oct 21 01:16:47 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-mlir-tosa

Author: Wijkqwe

<details>
<summary>Changes</summary>

Part of #<!-- -->233457.

`ResizeOp::verify()` reads `scale`/`offset`/`border` from their
`tosa.const_shape` producers and checks their values. That is not local to the
operation, so these `ERROR_IF` conditions move to `tosa-validate`.

Changes:

- `ResizeOp::verify()`: drop the constant-value checks (non-positive scale,
  output size divisibility / calculated size); keep only the local check that
  block-scaled input requires `NEAREST_NEIGHBOR` mode.
- `checkErrorIfResize()`: add the missing `scale > 0` check.
- `levelCheckResize()` and `ResizeOp::inferReturnTypeComponents()`: bail out on
  non-positive scale instead of dividing by it.

Assisted-by: AI.

---
Full diff: https://github.com/llvm/llvm-project/pull/234101.diff


3 Files Affected:

- (modified) mlir/lib/Dialect/Tosa/IR/TosaOps.cpp (+6-82) 
- (modified) mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp (+12) 
- (modified) mlir/test/Dialect/Tosa/tosa-infer-shapes.mlir (+14) 


``````````diff
diff --git a/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp b/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
index 99c352ab8ed3c3..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]) /
@@ -3746,93 +3751,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..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(
@@ -1135,6 +1143,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(
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
+}

``````````

</details>


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


More information about the Mlir-commits mailing list