[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