[Mlir-commits] [mlir] [mlir][tosa] Make TOSA RESIZE's scale, offset, border as Input (PR #124956)
Hsiangkai Wang
llvmlistbot at llvm.org
Thu Feb 13 09:12:13 PST 2025
https://github.com/Hsiangkai updated https://github.com/llvm/llvm-project/pull/124956
>From 139755666cf518ecbe0e7e91c525f959f897c4f4 Mon Sep 17 00:00:00 2001
From: Hsiangkai Wang <hsiangkai.wang at arm.com>
Date: Wed, 12 Feb 2025 10:33:34 +0000
Subject: [PATCH 1/3] [mlir][tosa] Make TOSA RESIZE's scale, offset, border as
Input
Move the `scale`, `offset`, and `border` parameters of the RESIZE operator
in the MLIR TOSA dialect from attributes to inputs and update lit tests
appropriately.
Add the verifier of the `tosa::ResizeOp` operation.
Co-authored-by: Tai Ly <tai.ly at arm.com>
Co-authored-by: Luke Hutton <luke.hutton at arm.com>
---
mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td | 7 +-
.../mlir/Dialect/Tosa/Utils/ConversionUtils.h | 3 +
.../Conversion/TosaToLinalg/TosaToLinalg.cpp | 21 ++-
.../Dialect/Tosa/IR/TosaCanonicalizations.cpp | 19 ++-
mlir/lib/Dialect/Tosa/IR/TosaOps.cpp | 95 +++++++++++-
.../Tosa/Transforms/TosaValidation.cpp | 121 ++++++++++++++-
.../Dialect/Tosa/Utils/ConversionUtils.cpp | 18 +++
.../TosaToLinalg/tosa-to-linalg-resize.mlir | 140 ++++++++----------
mlir/test/Dialect/Tosa/canonicalize.mlir | 10 +-
mlir/test/Dialect/Tosa/invalid.mlir | 59 ++++++++
mlir/test/Dialect/Tosa/level_check.mlir | 22 ++-
mlir/test/Dialect/Tosa/ops.mlir | 5 +-
mlir/test/Dialect/Tosa/tosa-infer-shapes.mlir | 40 ++++-
13 files changed, 446 insertions(+), 114 deletions(-)
diff --git a/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td b/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td
index b8755da8db32e..5dfef9130177c 100644
--- a/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td
+++ b/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td
@@ -1822,9 +1822,9 @@ def Tosa_ResizeOp : Tosa_InferShapedTypeOp<"resize"> {
let arguments = (ins
Tosa_Tensor4D:$input,
- Tosa_IntArrayAttr4:$scale,
- Tosa_IntArrayAttr2:$offset,
- Tosa_IntArrayAttr2:$border,
+ Rank4TosaShape:$scale,
+ Rank2TosaShape:$offset,
+ Rank2TosaShape:$border,
Tosa_ResizeTypeAttr:$mode
);
@@ -1833,6 +1833,7 @@ def Tosa_ResizeOp : Tosa_InferShapedTypeOp<"resize"> {
);
let hasFolder = 1;
+ let hasVerifier = 1;
}
//===----------------------------------------------------------------------===//
diff --git a/mlir/include/mlir/Dialect/Tosa/Utils/ConversionUtils.h b/mlir/include/mlir/Dialect/Tosa/Utils/ConversionUtils.h
index 4e2f1b9cb19a9..3e80a7321ad8c 100644
--- a/mlir/include/mlir/Dialect/Tosa/Utils/ConversionUtils.h
+++ b/mlir/include/mlir/Dialect/Tosa/Utils/ConversionUtils.h
@@ -240,6 +240,9 @@ SmallVector<int64_t> convertFromMlirShape(ArrayRef<int64_t> shape);
bool getConstShapeValue(Operation *op,
llvm::SmallVector<int64_t> &result_shape);
+// returns a small vector of int64_t values that attr contains
+SmallVector<int64_t> convertFromIntAttr(const DenseElementsAttr &attr,
+ const int rank);
} // namespace tosa
} // namespace mlir
diff --git a/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp b/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp
index d849c782bf08b..7b70b3ab8afc9 100644
--- a/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp
+++ b/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp
@@ -1387,7 +1387,10 @@ class ResizeUnaryConverter : public OpRewritePattern<tosa::ResizeOp> {
return success();
}
- ArrayRef<int64_t> scale = op.getScale();
+ SmallVector<int64_t> scale;
+ if (!tosa::getConstShapeValue(op.getScale().getDefiningOp(), scale)) {
+ return failure();
+ }
// Collapse the unit width and height away.
SmallVector<ReassociationExprs, 4> reassociationMap(2);
@@ -1488,8 +1491,9 @@ class MaterializeResizeBroadcast : public OpRewritePattern<tosa::ResizeOp> {
resizeShape.push_back(channels);
auto resizeTy = resultTy.clone(resizeShape);
- auto resize =
- builder.create<tosa::ResizeOp>(resizeTy, input, op->getAttrs());
+ auto resize = builder.create<tosa::ResizeOp>(resizeTy, input, op.getScale(),
+ op.getOffset(), op.getBorder(),
+ op.getMode());
// Collapse an unit result dims.
SmallVector<ReassociationExprs, 4> reassociationMap(2);
@@ -1604,9 +1608,14 @@ class GenericResizeConverter : public OpRewritePattern<tosa::ResizeOp> {
Value inY = b.create<arith::IndexCastOp>(b.getI32Type(), y);
Value inX = b.create<arith::IndexCastOp>(b.getI32Type(), x);
- ArrayRef<int64_t> offset = op.getOffset();
- ArrayRef<int64_t> border = op.getBorder();
- ArrayRef<int64_t> scale = op.getScale();
+ SmallVector<int64_t> scale, offset, border;
+ if (!tosa::getConstShapeValue(op.getScale().getDefiningOp(), scale) ||
+ !tosa::getConstShapeValue(op.getOffset().getDefiningOp(), offset) ||
+ !tosa::getConstShapeValue(op.getBorder().getDefiningOp(), border)) {
+ return rewriter.notifyMatchFailure(
+ op, "tosa.resize scale/offset/border should have compile time "
+ "constant values.");
+ }
Value yScaleN, yScaleD, xScaleN, xScaleD;
yScaleN = b.create<arith::ConstantOp>(b.getI32IntegerAttr(scale[0]));
diff --git a/mlir/lib/Dialect/Tosa/IR/TosaCanonicalizations.cpp b/mlir/lib/Dialect/Tosa/IR/TosaCanonicalizations.cpp
index 69b3f6d674167..b9bcedb7fe71d 100644
--- a/mlir/lib/Dialect/Tosa/IR/TosaCanonicalizations.cpp
+++ b/mlir/lib/Dialect/Tosa/IR/TosaCanonicalizations.cpp
@@ -1034,9 +1034,22 @@ OpFoldResult PadOp::fold(FoldAdaptor adaptor) {
// Fold away cases where a tosa.resize operation returns a copy
// of the input image.
OpFoldResult ResizeOp::fold(FoldAdaptor adaptor) {
- ArrayRef<int64_t> offset = getOffset();
- ArrayRef<int64_t> border = getBorder();
- ArrayRef<int64_t> scale = getScale();
+ auto scaleAttr =
+ llvm::dyn_cast_if_present<DenseElementsAttr>(adaptor.getScale());
+ auto offsetAttr =
+ llvm::dyn_cast_if_present<DenseElementsAttr>(adaptor.getOffset());
+ auto borderAttr =
+ llvm::dyn_cast_if_present<DenseElementsAttr>(adaptor.getBorder());
+ if (!scaleAttr || !offsetAttr || !borderAttr) {
+ return {};
+ }
+
+ auto scale = tosa::convertFromIntAttr(scaleAttr, /* rank = */ 4);
+ auto offset = tosa::convertFromIntAttr(offsetAttr, /* rank = */ 2);
+ auto border = tosa::convertFromIntAttr(borderAttr, /* rank = */ 2);
+ if (scale.size() != 4 || offset.size() != 2 || border.size() != 2) {
+ return {};
+ }
// Check unit scaling.
if (scale[0] != scale[1] || scale[2] != scale[3]) {
diff --git a/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp b/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
index 4928be38476a9..e703e01597687 100644
--- a/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
+++ b/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
@@ -1685,9 +1685,14 @@ LogicalResult tosa::ResizeOp::inferReturnTypeComponents(
(inputWidth == ShapedType::kDynamic))
return failure();
- llvm::ArrayRef<int64_t> scaleInt = adaptor.getScale();
- llvm::ArrayRef<int64_t> offsetInt = adaptor.getOffset();
- llvm::ArrayRef<int64_t> borderInt = adaptor.getBorder();
+ SmallVector<int64_t> scaleInt, offsetInt, borderInt;
+ if (!tosa::getConstShapeValue(adaptor.getScale().getDefiningOp(), scaleInt) ||
+ !tosa::getConstShapeValue(adaptor.getOffset().getDefiningOp(),
+ offsetInt) ||
+ !tosa::getConstShapeValue(adaptor.getBorder().getDefiningOp(),
+ borderInt)) {
+ return failure();
+ }
// Compute the output shape based on attributes: scale, offset, and border.
outputShape[1] =
@@ -1704,6 +1709,90 @@ LogicalResult tosa::ResizeOp::inferReturnTypeComponents(
return success();
}
+LogicalResult tosa::ResizeOp::verify() {
+ const Value input = getInput();
+ const Value output = getOutput();
+ const RankedTensorType inputType =
+ llvm::dyn_cast<RankedTensorType>(input.getType());
+ const RankedTensorType outputType =
+ llvm::dyn_cast<RankedTensorType>(output.getType());
+
+ if (!inputType)
+ return emitOpError("expect a ranked input tensor");
+ if (!outputType)
+ return emitOpError("expect a ranked output tensor");
+
+ 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);
+
+ SmallVector<int64_t> scaleValues;
+ SmallVector<int64_t> offsetValues;
+ SmallVector<int64_t> borderValues;
+ if (!tosa::getConstShapeValue(getScale().getDefiningOp(), scaleValues) ||
+ !tosa::getConstShapeValue(getOffset().getDefiningOp(), offsetValues) ||
+ !tosa::getConstShapeValue(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];
+
+ auto idivCheck = [](const int64_t lhs,
+ const int64_t rhs) -> std::optional<int64_t> {
+ if (lhs % rhs != 0)
+ return std::nullopt;
+ return lhs / rhs;
+ };
+
+ if (ih != ShapedType::kDynamic) {
+ 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;
+ }
+
+ if (iw != ShapedType::kDynamic) {
+ 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();
+}
+
LogicalResult tosa::ScatterOp::inferReturnTypeComponents(
MLIRContext *context, ::std::optional<Location> location,
ScatterOp::Adaptor adaptor,
diff --git a/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp b/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
index 678bb47935bd2..e62caf997d6b0 100644
--- a/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
+++ b/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
@@ -18,6 +18,7 @@
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/Dialect/Tosa/IR/TosaOps.h"
+#include "mlir/Dialect/Tosa/Utils/ConversionUtils.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/Matchers.h"
@@ -119,6 +120,9 @@ struct TosaValidation : public tosa::impl::TosaValidationBase<TosaValidation> {
// check variable read/write data types against variable declarations
LogicalResult applyVariableCheck(Operation *op);
+ // check error if conditions
+ LogicalResult applyErrorIfCheck(Operation *op);
+
private:
void populateConstantOperandChecks() {
constCheckers.emplace_back(checkConstantOperandPad);
@@ -383,11 +387,14 @@ struct TosaValidation : public tosa::impl::TosaValidationBase<TosaValidation> {
// Resize op: level check max scales
bool levelCheckResize(Operation *op) {
if (auto resize = dyn_cast<tosa::ResizeOp>(op)) {
- auto scale = resize.getScale();
- int16_t scaleYN = scale[0];
- int16_t scaleYD = scale[1];
- int16_t scaleXN = scale[2];
- int16_t scaleXD = scale[3];
+ SmallVector<int64_t> scale;
+ if (!tosa::getConstShapeValue(resize.getScale().getDefiningOp(), scale)) {
+ return false;
+ }
+ const int64_t scaleYN = scale[0];
+ const int64_t scaleYD = scale[1];
+ const int64_t scaleXN = scale[2];
+ const int64_t scaleXD = scale[3];
if (!levelCheckScale(op, scaleYN / scaleYD,
"scale_y_n/scale_y_d <= MAX_SCALE") ||
!levelCheckScale(op, scaleXN / scaleXD,
@@ -519,6 +526,106 @@ LogicalResult TosaValidation::applyVariableCheck(Operation *op) {
return success();
}
+bool checkErrorIfResize(Operation *op) {
+ if (auto resize = dyn_cast<tosa::ResizeOp>(op)) {
+ const Value input = resize.getInput();
+ const Value output = resize.getOutput();
+ const RankedTensorType inputType =
+ llvm::dyn_cast<RankedTensorType>(input.getType());
+ const RankedTensorType outputType =
+ llvm::dyn_cast<RankedTensorType>(output.getType());
+
+ if (!inputType || !outputType) {
+ op->emitOpError("expect ranked input/output tensor");
+ return false;
+ }
+
+ // Ensure the image size is supported by GPU APIs and that for integer
+ // implementations, position * stride does not overflow int32_t.
+ if (inputType.hasStaticShape() && outputType.hasStaticShape()) {
+ const SmallVector<int64_t, 4> sizes = {
+ outputType.getDimSize(1), outputType.getDimSize(2),
+ inputType.getDimSize(1), inputType.getDimSize(2)};
+ const int64_t *maxDim = llvm::max_element(sizes);
+ if (maxDim != sizes.end() && *maxDim >= 16384) {
+ op->emitOpError("expect input/output height/width dims to be < 16384, ")
+ << "got [OH, OW, IH, IW] = " << sizes;
+ return false;
+ }
+ }
+
+ SmallVector<int64_t> scale;
+ if (!tosa::getConstShapeValue(resize.getScale().getDefiningOp(), scale)) {
+ return false;
+ }
+
+ const int64_t scaleYN = scale[0];
+ const int64_t scaleYD = scale[1];
+ const int64_t scaleXN = scale[2];
+ const int64_t scaleXD = scale[3];
+
+ // Ensure scale values don't overflow int32 accumulator
+ if (scaleYN > (1 << 11) || scaleXN > (1 << 11)) {
+ op->emitOpError("expect all scale numerator values to be <= (1 << 11), "
+ "got scale_y_n=")
+ << scaleYN << ", scale_x_n=" << scaleXN;
+ return false;
+ }
+
+ if (scaleYD >= 16 * scaleYN || scaleXD >= 16 * scaleXN) {
+ op->emitOpError("expect a downscale ratio larger than 1/16, got y=")
+ << scaleYN << "/" << scaleYD << ", x=" << scaleXN << "/" << scaleXD;
+ return false;
+ }
+
+ SmallVector<int64_t> offset;
+ SmallVector<int64_t> border;
+ if (!tosa::getConstShapeValue(resize.getOffset().getDefiningOp(), offset) ||
+ !tosa::getConstShapeValue(resize.getBorder().getDefiningOp(), border)) {
+ return false;
+ }
+
+ const int64_t offsetY = offset[0];
+ const int64_t offsetX = offset[1];
+ const int64_t borderY = border[0];
+ const int64_t borderX = border[1];
+
+ // Set a consistent lower limit of 1/16 downscale to simplify
+ // implementations
+ if (offsetY < -scaleYN || offsetY >= 16 * scaleYN) {
+ op->emitOpError(
+ "expect offsetY / scaleYNumerator to be in range [-1, 16), got ")
+ << offsetY << "/" << scaleYN;
+ return false;
+ }
+ if (offsetX < -scaleXN || offsetX >= 16 * scaleXN) {
+ op->emitOpError(
+ "expect offsetX / scaleXNumerator to be in range [-1, 16), got ")
+ << offsetX << "/" << scaleXN;
+ return false;
+ }
+ if (borderY < -16 * scaleYN || borderY >= scaleYN) {
+ op->emitOpError(
+ "expect borderY / scaleYNumerator to be in range [-16, 1), got ")
+ << borderY << "/" << scaleYN;
+ return false;
+ }
+ if (borderX < -16 * scaleXN || borderX >= scaleXN) {
+ op->emitOpError(
+ "expect borderX / scaleXNumerator to be in range [-16, 1), got ")
+ << borderX << "/" << scaleXN;
+ return false;
+ }
+ }
+ return true;
+}
+
+LogicalResult TosaValidation::applyErrorIfCheck(Operation *op) {
+ if (!checkErrorIfResize(op))
+ return failure();
+ return success();
+}
+
bool TosaValidation::isValidElementType(Type type) {
if (isa<FloatType>(type)) {
if (!isEnabledProfile(TosaProfileEnum::MainInference))
@@ -582,6 +689,10 @@ void TosaValidation::runOnOperation() {
// do variable type checks
if (failed(applyVariableCheck(op)))
signalPassFailure();
+
+ // do error if checks
+ if (StrictOperationSpecAlignment && failed(applyErrorIfCheck(op)))
+ signalPassFailure();
});
}
} // namespace
diff --git a/mlir/lib/Dialect/Tosa/Utils/ConversionUtils.cpp b/mlir/lib/Dialect/Tosa/Utils/ConversionUtils.cpp
index 8ab12d038849f..d1a8732dac212 100644
--- a/mlir/lib/Dialect/Tosa/Utils/ConversionUtils.cpp
+++ b/mlir/lib/Dialect/Tosa/Utils/ConversionUtils.cpp
@@ -198,3 +198,21 @@ bool mlir::tosa::getConstShapeValue(Operation *op,
// for undefined op, return false.
return false;
}
+
+// returns a small vector of int64_t values that attr contains
+SmallVector<int64_t>
+mlir::tosa::convertFromIntAttr(const DenseElementsAttr &attr, const int rank) {
+ if (attr.isSplat()) {
+ int64_t v = attr.getSplatValue<APInt>().getSExtValue();
+ return SmallVector<int64_t>(rank, v);
+ }
+
+ if (auto int_array_attr = llvm::dyn_cast<DenseIntElementsAttr>(attr)) {
+ SmallVector<int64_t> vec;
+ for (APInt val : int_array_attr.getValues<APInt>()) {
+ vec.push_back(val.getSExtValue());
+ }
+ return vec;
+ }
+ return {};
+}
diff --git a/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-resize.mlir b/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-resize.mlir
index d42d0a46692d4..ad9f03d1c1d60 100644
--- a/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-resize.mlir
+++ b/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-resize.mlir
@@ -2,7 +2,10 @@
// CHECK-LABEL: @unary_resize_nearest_fp32
func.func @unary_resize_nearest_fp32(%arg0 : tensor<3x1x1x7xf32>) -> tensor<3x1x1x7xf32> {
- %resize = "tosa.resize"(%arg0) {mode = "NEAREST_NEIGHBOR", scale = array<i64: 2, 2, 1, 1>, offset = array<i64: 0, 0>, border = array<i64: 0, 0>} : (tensor<3x1x1x7xf32>) -> tensor<3x1x1x7xf32>
+ %scale = tosa.const_shape { value = dense<[2, 2, 1, 1]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %resize = tosa.resize %arg0, %scale, %offset, %border {mode = "NEAREST_NEIGHBOR"} : (tensor<3x1x1x7xf32>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<3x1x1x7xf32>
// CHECK: return %arg0
return %resize : tensor<3x1x1x7xf32>
}
@@ -11,7 +14,10 @@ func.func @unary_resize_nearest_fp32(%arg0 : tensor<3x1x1x7xf32>) -> tensor<3x1x
// CHECK-LABEL: @unary_resize_nearest_fp16
func.func @unary_resize_nearest_fp16(%arg0 : tensor<3x1x1x7xf16>) -> tensor<3x1x1x7xf16> {
- %resize = "tosa.resize"(%arg0) {mode = "NEAREST_NEIGHBOR", scale = array<i64: 2, 2, 1, 1>, offset = array<i64: 0, 0>, border = array<i64: 0, 0>} : (tensor<3x1x1x7xf16>) -> tensor<3x1x1x7xf16>
+ %scale = tosa.const_shape { value = dense<[2, 2, 1, 1]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %resize = tosa.resize %arg0, %scale, %offset, %border {mode = "NEAREST_NEIGHBOR"} : (tensor<3x1x1x7xf16>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<3x1x1x7xf16>
// CHECK: return %arg0
return %resize : tensor<3x1x1x7xf16>
}
@@ -20,7 +26,10 @@ func.func @unary_resize_nearest_fp16(%arg0 : tensor<3x1x1x7xf16>) -> tensor<3x1x
// CHECK-LABEL: @unary_resize_bilinear_fp32
func.func @unary_resize_bilinear_fp32(%arg0 : tensor<3x1x1x7xf32>) -> tensor<3x1x1x7xf32> {
- %resize = "tosa.resize"(%arg0) {mode = "BILINEAR", scale = array<i64: 2, 2, 1, 1>, offset = array<i64: 0, 0>, border = array<i64: 0, 0>} : (tensor<3x1x1x7xf32>) -> tensor<3x1x1x7xf32>
+ %scale = tosa.const_shape { value = dense<[2, 2, 1, 1]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %resize = tosa.resize %arg0, %scale, %offset, %border {mode = "BILINEAR"} : (tensor<3x1x1x7xf32>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<3x1x1x7xf32>
// CHECK: return %arg0
return %resize : tensor<3x1x1x7xf32>
}
@@ -29,7 +38,10 @@ func.func @unary_resize_bilinear_fp32(%arg0 : tensor<3x1x1x7xf32>) -> tensor<3x1
// CHECK-LABEL: @unary_resize_bilinear_fp16
func.func @unary_resize_bilinear_fp16(%arg0 : tensor<3x1x1x7xf16>) -> tensor<3x1x1x7xf16> {
- %resize = "tosa.resize"(%arg0) {mode = "BILINEAR", scale = array<i64: 2, 2, 1, 1>, offset = array<i64: 0, 0>, border = array<i64: 0, 0>} : (tensor<3x1x1x7xf16>) -> tensor<3x1x1x7xf16>
+ %scale = tosa.const_shape { value = dense<[2, 2, 1, 1]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %resize = tosa.resize %arg0, %scale, %offset, %border {mode = "BILINEAR"} : (tensor<3x1x1x7xf16>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<3x1x1x7xf16>
// CHECK: return %arg0
return %resize : tensor<3x1x1x7xf16>
}
@@ -38,71 +50,22 @@ func.func @unary_resize_bilinear_fp16(%arg0 : tensor<3x1x1x7xf16>) -> tensor<3x1
// CHECK-LABEL: @unary_resize_nearest_i8
func.func @unary_resize_nearest_i8(%arg0 : tensor<3x1x1x7xi8>) -> tensor<3x1x1x7xi8> {
- %resize = "tosa.resize"(%arg0) {mode = "NEAREST_NEIGHBOR", scale = array<i64: 2, 1, 3, 1>, offset = array<i64: 0, 0>, border = array<i64: 0, 0>} : (tensor<3x1x1x7xi8>) -> tensor<3x1x1x7xi8>
+ %scale = tosa.const_shape { value = dense<[2, 1, 3, 1]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %resize = tosa.resize %arg0, %scale, %offset, %border {mode = "NEAREST_NEIGHBOR"} : (tensor<3x1x1x7xi8>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<3x1x1x7xi8>
// CHECK: return %arg0
return %resize : tensor<3x1x1x7xi8>
}
// -----
-// CHECK-LABEL: @broadcast_resize_nearest_f32
-func.func @broadcast_resize_nearest_f32(%arg0 : tensor<3x1x1x7xf32>) -> tensor<3x1x5x7xf32> {
- // CHECK: %[[COLLAPSE:.+]] = tensor.collapse_shape %arg0
- // CHECK-NEXT{literal}: [[0], [1, 2, 3]] : tensor<3x1x1x7xf32> into tensor<3x7xf32>
- // CHECK: %[[EMPTY:.+]] = tensor.empty() : tensor<3x1x5x7xf32>
- // CHECK: %[[GENERIC:.+]] = linalg.generic
- // CHECK-SAME: indexing_maps = [#map, #map1], iterator_types = ["parallel", "parallel", "parallel", "parallel"]}
- // CHECK-SAME: ins(%[[COLLAPSE]] : tensor<3x7xf32>) outs(%[[EMPTY]] : tensor<3x1x5x7xf32>)
- // CHECK: ^bb0(%[[IN:.+]]: f32, %[[OUT:.+]]: f32):
- // CHECK: linalg.yield %[[IN]] : f32
- %resize = "tosa.resize"(%arg0) {mode = "NEAREST_NEIGHBOR", scale = array<i64: 2, 1, 3, 1>, offset = array<i64: 0, 0>, border = array<i64: 0, 0>} : (tensor<3x1x1x7xf32>) -> tensor<3x1x5x7xf32>
-
- // CHECK: return %[[GENERIC]]
- return %resize : tensor<3x1x5x7xf32>
-}
-
-// -----
-
-// CHECK-LABEL: @broadcast_resize_bilinear_i8
-func.func @broadcast_resize_bilinear_i8(%arg0 : tensor<3x1x1x7xi8>) -> tensor<3x4x5x7xi32> {
- // CHECK: %[[COLLAPSE:.+]] = tensor.collapse_shape %arg0
- // CHECK-SAME{literal}: [[0], [1, 2, 3]] : tensor<3x1x1x7xi8> into tensor<3x7xi8>
- // CHECK: %[[EMPTY:.+]] = tensor.empty() : tensor<3x7xi32>
- // CHECK: %[[RESIZE:.+]] = linalg.generic
- // CHECK-SAME: {indexing_maps = [#map, #map], iterator_types = ["parallel", "parallel"]}
- // CHECK-SAME: ins(%[[COLLAPSE]] : tensor<3x7xi8>) outs(%[[EMPTY]] : tensor<3x7xi32>)
- // CHECK: ^bb0(%[[IN:.+]]: i8, %[[OUT:.+]]: i32):
- // CHECK: %[[EXT:.+]] = arith.extsi %[[IN]] : i8 to i32
- // CHECK-DAG: %[[C2:.+]] = arith.constant 2 : i32
- // CHECK: %[[MUL:.+]] = arith.muli %[[EXT]], %[[C2]] : i32
- // CHECK-DAG: %[[C3:.+]] = arith.constant 3 : i32
- // CHECK: %[[OUT:.+]] = arith.muli %[[MUL]], %[[C3]] : i32
- // CHECK: linalg.yield %[[OUT]] : i32
- // CHECK: } -> tensor<3x7xi32>
- // CHECK: %[[EXPAND:.+]] = tensor.expand_shape %1
- // CHECK-SAME{literal}: [[0], [1, 2, 3]] : tensor<3x7xi32> into tensor<3x1x1x7xi32>
- // CHECK: %[[COLLAPSE:.+]] = tensor.collapse_shape %expanded
- // CHECK-SAME{literal}:[[0], [1, 2, 3]] : tensor<3x1x1x7xi32> into tensor<3x7xi32>
- // CHECK: %[[EMPTY:.+]] = tensor.empty() : tensor<3x4x5x7xi32>
- // CHECK: %[[BROADCAST:.+]] = linalg.generic
- // CHECK-SAME: indexing_maps = [#map1, #map2], iterator_types = ["parallel", "parallel", "parallel", "parallel"]}
- // CHECK-SAME: ins(%[[COLLAPSE]] : tensor<3x7xi32>) outs(%[[EMPTY]] : tensor<3x4x5x7xi32>) {
- // CHECK: ^bb0(%[[IN:.+]]: i32, %[[OUT:.+]]: i32):
- // CHECK: linalg.yield %[[IN]] : i32
- %resize = "tosa.resize"(%arg0) {mode = "BILINEAR", scale = array<i64: 2, 1, 3, 1>, offset = array<i64: 0, 0>, border = array<i64: 0, 0>} : (tensor<3x1x1x7xi8>) -> tensor<3x4x5x7xi32>
-
- // CHECK: return %[[BROADCAST]]
- return %resize : tensor<3x4x5x7xi32>
-}
-
-// -----
-
// CHECK-LABEL: @unary_resize_bilinear_i32
func.func @unary_resize_bilinear_i32(%arg0 : tensor<3x1x1x7xi8>) -> tensor<3x1x1x7xi32> {
// CHECK: %[[COLLAPSE:.+]] = tensor.collapse_shape %arg0
// CHECK-SAME{literal}: [[0], [1, 2, 3]] : tensor<3x1x1x7xi8> into tensor<3x7xi8>
// CHECK: %[[EMPTY:.+]] = tensor.empty() : tensor<3x7xi32>
- // CHECK: %[[GENERIC:.+]] = linalg.generic
+ // CHECK: %[[GENERIC:.+]] = linalg.generic
// CHECK-SAME: indexing_maps = [#map, #map]
// CHECK-SAME: iterator_types = ["parallel", "parallel"]}
// CHECK-SAME: ins(%[[COLLAPSE]] : tensor<3x7xi8>) outs(%[[EMPTY]] : tensor<3x7xi32>) {
@@ -111,12 +74,15 @@ func.func @unary_resize_bilinear_i32(%arg0 : tensor<3x1x1x7xi8>) -> tensor<3x1x1
// CHECK-DAG: %[[C2:.+]] = arith.constant 2 : i32
// CHECK: %[[MUL0:.+]] = arith.muli %[[EXT]], %[[C2]] : i32
// CHECK-DAG: %[[C1:.+]] = arith.constant 2 : i32
- // CHECK: %4 = arith.muli %3, %[[C1]] : i32
- // CHECK: linalg.yield %4 : i32
+ // CHECK: %7 = arith.muli %6, %[[C1]] : i32
+ // CHECK: linalg.yield %7 : i32
// CHECK: } -> tensor<3x7xi32>
// CHECK: %[[EXPAND:.+]] = tensor.expand_shape %[[GENERIC:.+]]
// CHECK-SAME{literal} [[0], [1, 2, 3]] : tensor<3x7xi32> into tensor<3x1x1x7xi32>
- %resize = "tosa.resize"(%arg0) {mode = "BILINEAR", scale = array<i64: 2, 1, 2, 1>, offset = array<i64: 0, 0>, border = array<i64: 0, 0>} : (tensor<3x1x1x7xi8>) -> tensor<3x1x1x7xi32>
+ %scale = tosa.const_shape { value = dense<[2, 1, 2, 1]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %resize = tosa.resize %arg0, %scale, %offset, %border {mode = "BILINEAR"} : (tensor<3x1x1x7xi8>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<3x1x1x7xi32>
// CHECK: return %[[EXPAND]]
return %resize : tensor<3x1x1x7xi32>
@@ -184,7 +150,10 @@ func.func @resize_nearest_int(%arg0: tensor<1x15x13x1xi8>) -> () {
// CHECK: linalg.yield %[[EXTRACT]]
// Round to the nearest index.
- %0 = "tosa.resize"(%arg0) {mode = "NEAREST_NEIGHBOR", scale = array<i64: 11, 7, 89, 6>, offset = array<i64: 0, 0>, border = array<i64: 0, 0>} : (tensor<1x15x13x1xi8>) -> tensor<1x23x179x1xi8>
+ %scale = tosa.const_shape { value = dense<[11, 7, 89, 6]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %0 = tosa.resize %arg0, %scale, %offset, %border {mode = "NEAREST_NEIGHBOR"} : (tensor<1x15x13x1xi8>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<1x23x179x1xi8>
return
}
@@ -193,7 +162,7 @@ func.func @resize_nearest_int(%arg0: tensor<1x15x13x1xi8>) -> () {
// CHECK-LABEL: @resize_bilinear_int
// CHECK-SAME: (%[[ARG0:[0-9a-zA-Z_]*]]:
func.func @resize_bilinear_int(%arg0: tensor<1x19x20x1xi8>) {
- // CHECK: %[[INIT:.+]] = tensor.empty() : tensor<1x304x320x1xi48>
+ // CHECK: %[[INIT:.+]] = tensor.empty() : tensor<1x289x305x1xi48>
// CHECK: %[[GENERIC:.+]] = linalg.generic
// CHECK: %[[IDX_0:.+]] = linalg.index 0
// CHECK: %[[IDX_1:.+]] = linalg.index 1
@@ -285,7 +254,10 @@ func.func @resize_bilinear_int(%arg0: tensor<1x19x20x1xi8>) {
// CHECK: linalg.yield %[[RESULT]]
// Round to the nearest index.
- %0 = "tosa.resize"(%arg0) {mode = "BILINEAR", scale = array<i64: 16, 1, 16, 1>, offset = array<i64: 0, 0>, border = array<i64: 0, 0>} : (tensor<1x19x20x1xi8>) -> tensor<1x304x320x1xi48>
+ %scale = tosa.const_shape { value = dense<[16, 1, 16, 1]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %0 = tosa.resize %arg0, %scale, %offset, %border {mode = "BILINEAR"} : (tensor<1x19x20x1xi8>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<1x289x305x1xi48>
return
}
@@ -349,7 +321,10 @@ func.func @resize_nearest_fp32(%input: tensor<1x50x48x1xf32>) -> () {
// CHECK: %[[EXTRACT:.+]] = tensor.extract %arg0[%[[IDX0]], %[[IDY]], %[[IDX]], %[[IDX3]]]
// CHECK: linalg.yield %[[EXTRACT]]
- %output = "tosa.resize"(%input) {mode = "NEAREST_NEIGHBOR", scale = array<i64: 64, 2, 64, 2>, offset = array<i64: -31, -31>, border = array<i64: 31, 31>} : (tensor<1x50x48x1xf32>) -> tensor<1x1600x1536x1xf32>
+ %scale = tosa.const_shape { value = dense<[64, 2, 64, 2]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<[-31, -31]> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<[31, 31]> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %output = tosa.resize %input, %scale, %offset, %border {mode = "NEAREST_NEIGHBOR"} : (tensor<1x50x48x1xf32>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<1x1600x1536x1xf32>
return
}
@@ -357,7 +332,7 @@ func.func @resize_nearest_fp32(%input: tensor<1x50x48x1xf32>) -> () {
// CHECK-LABEL: @resize_bilinear_fp
func.func @resize_bilinear_fp(%input: tensor<1x23x24x1xf32>) -> () {
- // CHECK: %[[INIT:.+]] = tensor.empty() : tensor<1x92x96x1xf32>
+ // CHECK: %[[INIT:.+]] = tensor.empty() : tensor<1x89x93x1xf32>
// CHECK: %[[GENERIC:.+]] = linalg.generic
// CHECK: %[[IDX_0:.+]] = linalg.index 0
// CHECK: %[[IDX_1:.+]] = linalg.index 1
@@ -441,7 +416,10 @@ func.func @resize_bilinear_fp(%input: tensor<1x23x24x1xf32>) -> () {
// CHECK: linalg.yield %[[RESULT]]
// Round by bilinear interpolation
- %output = "tosa.resize"(%input) {mode = "BILINEAR", scale = array<i64: 4, 1, 4, 1>, offset = array<i64: 0, 0>, border = array<i64: 0, 0>} : (tensor<1x23x24x1xf32>) -> tensor<1x92x96x1xf32>
+ %scale = tosa.const_shape { value = dense<[4, 1, 4, 1]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %output = tosa.resize %input, %scale, %offset, %border {mode = "BILINEAR"} : (tensor<1x23x24x1xf32>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<1x89x93x1xf32>
return
}
@@ -455,7 +433,10 @@ func.func @resize_dyn(%input: tensor<?x2x2x1xi8>) -> () {
// CHECK: %[[BATCH:.+]] = tensor.dim %arg0, %[[C0]]
// CHECK: %[[INIT:.+]] = tensor.empty(%[[BATCH]]) : tensor<?x4x4x1xi32>
// CHECK: %[[GENERIC:.+]] = linalg.generic
- %output = "tosa.resize"(%input) { scale = array<i64: 4, 2, 4, 2>, offset = array<i64: -1, -1>, border = array<i64: 1, 1>, mode = "BILINEAR" } : (tensor<?x2x2x1xi8>) -> (tensor<?x4x4x1xi32>)
+ %scale = tosa.const_shape { value = dense<[4, 2, 4, 2]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<[-1, -1]> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<[1, 1]> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %output = tosa.resize %input, %scale, %offset, %border { mode = "BILINEAR" } : (tensor<?x2x2x1xi8>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> (tensor<?x4x4x1xi32>)
return
}
@@ -463,14 +444,17 @@ func.func @resize_dyn(%input: tensor<?x2x2x1xi8>) -> () {
// CHECK-LABEL: @resize_bilinear_int48
func.func @resize_bilinear_int48(%arg0: tensor<1x19x19x1xi16>) {
- %0 = "tosa.resize"(%arg0) {mode = "BILINEAR", scale = array<i64: 16, 1, 16, 1>, offset = array<i64: 0, 0>, border = array<i64: 0, 0>} : (tensor<1x19x19x1xi16>) -> tensor<1x289x289x1xi48>
+ %scale = tosa.const_shape { value = dense<[16, 1, 16, 1]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %0 = tosa.resize %arg0, %scale, %offset, %border {mode = "BILINEAR"} : (tensor<1x19x19x1xi16>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<1x289x289x1xi48>
return
}
// -----
// CHECK-LABEL: skip_interpolate_bilinear_i8
-func.func @skip_interpolate_bilinear_i8(%arg0 : tensor<3x1x2x7xi8>) -> tensor<3x1x5x7xi32> {
+func.func @skip_interpolate_bilinear_i8(%arg0 : tensor<3x1x2x7xi8>) -> tensor<3x1x4x7xi32> {
// CHECK: %[[GENERIC:.+]] = linalg.generic
// CHECK: %[[BATCH:.+]] = linalg.index 0
// CHECK: %[[CHANNEL:.+]] = linalg.index 3
@@ -486,14 +470,17 @@ func.func @skip_interpolate_bilinear_i8(%arg0 : tensor<3x1x2x7xi8>) -> tensor<3x
// CHECK: %[[ADD:.+]] = arith.addi %[[MUL0]], %[[MUL1]]
// CHECK: %[[RES:.+]] = arith.muli %[[ADD]], %[[C2]]
// CHECK: linalg.yield %[[RES]]
- %resize = "tosa.resize"(%arg0) {mode = "BILINEAR", scale = array<i64: 2, 1, 3, 1>, offset = array<i64: 0, 0>, border = array<i64: 0, 0>} : (tensor<3x1x2x7xi8>) -> tensor<3x1x5x7xi32>
+ %scale = tosa.const_shape { value = dense<[2, 1, 3, 1]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %resize = tosa.resize %arg0, %scale, %offset, %border {mode = "BILINEAR"} : (tensor<3x1x2x7xi8>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<3x1x4x7xi32>
// CHECK: return %[[GENERIC]]
- return %resize : tensor<3x1x5x7xi32>
+ return %resize : tensor<3x1x4x7xi32>
}
// CHECK-LABEL: skip_interpolate_bilinear_f32
-func.func @skip_interpolate_bilinear_f32(%arg0 : tensor<3x1x2x7xf32>) -> tensor<3x1x5x7xf32> {
+func.func @skip_interpolate_bilinear_f32(%arg0 : tensor<3x1x2x7xf32>) -> tensor<3x1x4x7xf32> {
// CHECK: %[[GENERIC:.+]] = linalg.generic
// CHECK: %[[BATCH:.+]] = linalg.index 0 : index
// CHECK: %[[CHANNEL:.+]] = linalg.index 3 : index
@@ -505,8 +492,11 @@ func.func @skip_interpolate_bilinear_f32(%arg0 : tensor<3x1x2x7xf32>) -> tensor<
// CHECK: %[[MUL1:.+]] = arith.mulf %[[EXTRACT1]], %[[DX]]
// CHECK: %[[ADD:.+]] = arith.addf %[[MUL0]], %[[MUL1]]
// CHECK: linalg.yield %[[ADD]]
- %resize = "tosa.resize"(%arg0) {mode = "BILINEAR", scale = array<i64: 2, 1, 3, 1>, offset = array<i64: 0, 0>, border = array<i64: 0, 0>} : (tensor<3x1x2x7xf32>) -> tensor<3x1x5x7xf32>
+ %scale = tosa.const_shape { value = dense<[2, 1, 3, 1]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %resize = tosa.resize %arg0, %scale, %offset, %border {mode = "BILINEAR"} : (tensor<3x1x2x7xf32>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<3x1x4x7xf32>
// CHECK: return %[[GENERIC]]
- return %resize : tensor<3x1x5x7xf32>
+ return %resize : tensor<3x1x4x7xf32>
}
diff --git a/mlir/test/Dialect/Tosa/canonicalize.mlir b/mlir/test/Dialect/Tosa/canonicalize.mlir
index 24d572244a9b0..0e177a076ee7a 100644
--- a/mlir/test/Dialect/Tosa/canonicalize.mlir
+++ b/mlir/test/Dialect/Tosa/canonicalize.mlir
@@ -721,7 +721,10 @@ func.func @single_bit_reshape() -> tensor<1xi1> {
// CHECK-LABEL: @fold_resize_nearest
func.func @fold_resize_nearest(%arg0 : tensor<1x15x13x1xi8>) -> tensor<1x15x13x1xi8> {
// CHECK: return %arg0
- %resize = tosa.resize %arg0 {mode = "NEAREST_NEIGHBOR" , scale = array<i64: 2, 2, 1, 1>, offset = array<i64: 0, 0>, border = array<i64: 0, 0>} : (tensor<1x15x13x1xi8>) -> tensor<1x15x13x1xi8>
+ %scale = tosa.const_shape { value = dense<[2, 2, 1, 1]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %resize = tosa.resize %arg0, %scale, %offset, %border {mode = "NEAREST_NEIGHBOR"} : (tensor<1x15x13x1xi8>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<1x15x13x1xi8>
return %resize : tensor<1x15x13x1xi8>
}
@@ -730,7 +733,10 @@ func.func @fold_resize_nearest(%arg0 : tensor<1x15x13x1xi8>) -> tensor<1x15x13x1
// CHECK-LABEL: @fold_resize_bilinear
func.func @fold_resize_bilinear(%arg0 : tensor<1x15x13x1xi8>) -> tensor<1x15x13x1xi8> {
// CHECK: return %arg0
- %resize = tosa.resize %arg0 {mode = "BILINEAR" , scale = array<i64: 2, 2, 1, 1>, offset = array<i64: 0, 0>, border = array<i64: 0, 0>} : (tensor<1x15x13x1xi8>) -> tensor<1x15x13x1xi8>
+ %scale = tosa.const_shape { value = dense<[2, 2, 1, 1]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %resize = tosa.resize %arg0, %scale, %offset, %border {mode = "BILINEAR"} : (tensor<1x15x13x1xi8>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<1x15x13x1xi8>
return %resize : tensor<1x15x13x1xi8>
}
diff --git a/mlir/test/Dialect/Tosa/invalid.mlir b/mlir/test/Dialect/Tosa/invalid.mlir
index 913191be86f85..9575b73afc6a4 100644
--- a/mlir/test/Dialect/Tosa/invalid.mlir
+++ b/mlir/test/Dialect/Tosa/invalid.mlir
@@ -1127,3 +1127,62 @@ func.func @test_mul_non_broadcast(%arg0: tensor<13x21x2xf32>, %arg1: tensor<3x1x
%0 = tosa.mul %arg0, %arg1, %shift : (tensor<13x21x2xf32>, tensor<3x1x3xf32>, tensor<1xi8>) -> tensor<13x21x3xf32>
return %0 : tensor<13x21x3xf32>
}
+
+// -----
+// CHECK-LABEL: test_resize_invalid_scale_values
+func.func @test_resize_invalid_scale_values(%arg0: tensor<1x8x8x8xf32>) -> tensor<?x?x?x?xf32> {
+ %scale = tosa.const_shape { value = dense<[2, 0, -1, 2]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = 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_resize_invalid_wholly_divisible_height
+func.func @test_resize_invalid_wholly_divisible_height(%arg0: tensor<1x8x8x8xf32>) -> tensor<1x8x8x8xf32> {
+ %scale = tosa.const_shape { value = dense<[1, 3, 1, 1]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ // expected-error at +1 {{'tosa.resize' op expected (input_height - 1) * scale_y_n - offset_y + border_y to be wholly divisible by scale_y_d, got ((8 - 1) * 1 - 0 + 0) / 3}}
+ %1 = tosa.resize %arg0, %scale, %offset, %border { mode = "BILINEAR" } : (tensor<1x8x8x8xf32>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<1x8x8x8xf32>
+ return %1 : tensor<1x8x8x8xf32>
+}
+
+// -----
+
+// CHECK-LABEL: test_resize_invalid_output_height
+func.func @test_resize_invalid_output_height(%arg0: tensor<1x8x8x8xf32>) -> tensor<1x9x8x8xf32> {
+ %scale = tosa.const_shape { value = dense<[2, 1, 1, 1]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ // expected-error at +1 {{'tosa.resize' op calculated output height did not match expected: calculated=15, expected=9}}
+ %1 = tosa.resize %arg0, %scale, %offset, %border { mode = "BILINEAR" } : (tensor<1x8x8x8xf32>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<1x9x8x8xf32>
+ return %1 : tensor<1x9x8x8xf32>
+}
+
+// -----
+
+// CHECK-LABEL: test_resize_invalid_wholly_divisible_width
+func.func @test_resize_invalid_wholly_divisible_width(%arg0: tensor<1x8x8x8xf32>) -> tensor<1x8x8x8xf32> {
+ %scale = tosa.const_shape { value = dense<[1, 1, 1, 3]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ // expected-error at +1 {{'tosa.resize' op expected (input_width - 1) * scale_x_n - offset_x + border_x to be wholly divisible by scale_x_d, got ((8 - 1) * 1 - 0 + 0) / 3}}
+ %1 = tosa.resize %arg0, %scale, %offset, %border { mode = "BILINEAR" } : (tensor<1x8x8x8xf32>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<1x8x8x8xf32>
+ return %1 : tensor<1x8x8x8xf32>
+}
+
+// -----
+
+// CHECK-LABEL: test_resize_invalid_output_width
+func.func @test_resize_invalid_output_width(%arg0: tensor<1x8x8x8xf32>) -> tensor<1x8x9x8xf32> {
+ %scale = tosa.const_shape { value = dense<[1, 1, 2, 1]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ // expected-error at +1 {{'tosa.resize' op calculated output width did not match expected: calculated=15, expected=9}}
+ %1 = tosa.resize %arg0, %scale, %offset, %border { mode = "BILINEAR" } : (tensor<1x8x8x8xf32>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<1x8x9x8xf32>
+ return %1 : tensor<1x8x9x8xf32>
+}
diff --git a/mlir/test/Dialect/Tosa/level_check.mlir b/mlir/test/Dialect/Tosa/level_check.mlir
index a7f76f2d0fa64..6f49195d30e97 100644
--- a/mlir/test/Dialect/Tosa/level_check.mlir
+++ b/mlir/test/Dialect/Tosa/level_check.mlir
@@ -676,20 +676,26 @@ func.func @test_transpose_conv2d_stride_x(%arg0: tensor<1x32x32x8xf32>, %arg1: t
// -----
-func.func @test_resize_scale_y(%arg0: tensor<1x32x32x8xf32>) -> tensor<1x64x64x8xf32> {
+func.func @test_resize_scale_y(%arg0: tensor<1x32x32x8xf32>) -> tensor<1x7970x64x8xf32> {
+ %scale = tosa.const_shape { value = dense<[257, 1, 4, 2]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<[-1, -1]> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<[1, 1]> : tensor<2xindex> } : () -> !tosa.shape<2>
// expected-error at +1 {{'tosa.resize' op failed level check: scale_y_n/scale_y_d <= MAX_SCALE}}
- %1 = "tosa.resize"(%arg0) { scale = array<i64: 257, 1, 4, 2>, offset = array<i64: -1, -1>, border = array<i64: 1, 1>, mode = "BILINEAR"} :
- (tensor<1x32x32x8xf32>) -> tensor<1x64x64x8xf32>
- return %1 : tensor<1x64x64x8xf32>
+ %1 = tosa.resize %arg0, %scale, %offset, %border {mode = "BILINEAR"} :
+ (tensor<1x32x32x8xf32>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<1x7970x64x8xf32>
+ return %1 : tensor<1x7970x64x8xf32>
}
// -----
-func.func @test_resize_scale_x(%arg0: tensor<1x32x32x8xf32>) -> tensor<1x64x64x8xf32> {
+func.func @test_resize_scale_x(%arg0: tensor<1x32x32x8xf32>) -> tensor<1x64x7970x8xf32> {
+ %scale = tosa.const_shape { value = dense<[4, 2, 257, 1]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<[-1, -1]> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<[1, 1]> : tensor<2xindex> } : () -> !tosa.shape<2>
// expected-error at +1 {{'tosa.resize' op failed level check: scale_x_n/scale_x_d <= MAX_SCALE}}
- %1 = "tosa.resize"(%arg0) { scale = array<i64: 4, 2, 257, 1>, offset = array<i64: -1, -1>, border = array<i64: 1, 1>, mode = "BILINEAR"} :
- (tensor<1x32x32x8xf32>) -> tensor<1x64x64x8xf32>
- return %1 : tensor<1x64x64x8xf32>
+ %1 = tosa.resize %arg0, %scale, %offset, %border {mode = "BILINEAR"} :
+ (tensor<1x32x32x8xf32>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<1x64x7970x8xf32>
+ return %1 : tensor<1x64x7970x8xf32>
}
// -----
diff --git a/mlir/test/Dialect/Tosa/ops.mlir b/mlir/test/Dialect/Tosa/ops.mlir
index 348849cfaa572..e4a7ee8508548 100644
--- a/mlir/test/Dialect/Tosa/ops.mlir
+++ b/mlir/test/Dialect/Tosa/ops.mlir
@@ -677,7 +677,10 @@ func.func @test_scatter(%arg0: tensor<13x21x3xf32>, %arg1: tensor<13x26xi32>, %a
// -----
// CHECK-LABEL: resize
func.func @test_resize(%arg0: tensor<1x32x32x8xf32>) -> tensor<1x64x64x8xf32> {
- %1 = tosa.resize %arg0 { scale = array<i64: 4, 2, 4, 2>, offset = array<i64: -1, -1>, border = array<i64: 1, 1>, mode = "BILINEAR" } : (tensor<1x32x32x8xf32>) -> tensor<1x64x64x8xf32>
+ %scale = tosa.const_shape { value = dense<[4, 2, 4, 2]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<[-1, -1]> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<[1, 1]> : 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>
}
diff --git a/mlir/test/Dialect/Tosa/tosa-infer-shapes.mlir b/mlir/test/Dialect/Tosa/tosa-infer-shapes.mlir
index 7dc9b048085fa..4adc43c611b51 100644
--- a/mlir/test/Dialect/Tosa/tosa-infer-shapes.mlir
+++ b/mlir/test/Dialect/Tosa/tosa-infer-shapes.mlir
@@ -1040,8 +1040,11 @@ func.func @transpose_conv2d_strided(%arg0: tensor<1x5x7x1xf32>, %arg1: tensor<1x
// CHECK-LABEL: @resize_int_horizontal
func.func @resize_int_horizontal(%arg0: tensor<1x15x13x1xi8>) {
+ %scale = tosa.const_shape { value = dense<[11, 7, 89, 6]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
// CHECK: -> tensor<1x23x179x1xi8>
- %0 = tosa.resize %arg0 {mode = "NEAREST_NEIGHBOR", scale = array<i64: 11, 7, 89, 6>, offset = array<i64: 0, 0>, border = array<i64: 0, 0>} : (tensor<1x15x13x1xi8>) -> tensor<?x?x?x?xi8>
+ %0 = tosa.resize %arg0, %scale, %offset, %border {mode = "NEAREST_NEIGHBOR"} : (tensor<1x15x13x1xi8>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<?x?x?x?xi8>
return
}
@@ -1049,8 +1052,11 @@ func.func @resize_int_horizontal(%arg0: tensor<1x15x13x1xi8>) {
// CHECK-LABEL: @resize_int_vertical
func.func @resize_int_vertical(%arg0: tensor<1x49x42x1xi16>) {
+ %scale = tosa.const_shape { value = dense<[37, 16, 219, 41]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
// CHECK: -> tensor<1x112x220x1xi16>
- %0 = tosa.resize %arg0 {mode = "NEAREST_NEIGHBOR", scale = array<i64: 37, 16, 219, 41>, offset = array<i64: 0, 0>, border = array<i64: 0, 0>} : (tensor<1x49x42x1xi16>) -> tensor<?x?x?x?xi16>
+ %0 = tosa.resize %arg0, %scale, %offset, %border {mode = "NEAREST_NEIGHBOR"} : (tensor<1x49x42x1xi16>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<?x?x?x?xi16>
return
}
@@ -1058,8 +1064,11 @@ func.func @resize_int_vertical(%arg0: tensor<1x49x42x1xi16>) {
// CHECK-LABEL: @resize_int_power_of_two_upscale
func.func @resize_int_power_of_two_upscale(%arg0: tensor<1x23x19x1xi8>) {
+ %scale = tosa.const_shape { value = dense<[16, 1, 16, 1]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
// CHECK: -> tensor<1x353x289x1xi32>
- %0 = tosa.resize %arg0 {mode = "BILINEAR", scale = array<i64: 16, 1, 16, 1>, offset = array<i64: 0, 0>, border = array<i64: 0, 0>} : (tensor<1x23x19x1xi8>) -> tensor<?x?x?x?xi32>
+ %0 = tosa.resize %arg0, %scale, %offset, %border {mode = "BILINEAR"} : (tensor<1x23x19x1xi8>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<?x?x?x?xi32>
return
}
@@ -1067,24 +1076,33 @@ func.func @resize_int_power_of_two_upscale(%arg0: tensor<1x23x19x1xi8>) {
// CHECK-LABEL: @resize_int_power_of_two_upscale_offsetted
func.func @resize_int_power_of_two_upscale_offsetted(%arg0: tensor<1x41x26x1xi16>) {
+ %scale = tosa.const_shape { value = dense<[16, 2, 16, 2]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<[-7, -7]> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<[7, 7]> : tensor<2xindex> } : () -> !tosa.shape<2>
// CHECK: -> tensor<1x328x208x1xi48>
- %0 = tosa.resize %arg0 {mode = "BILINEAR", scale = array<i64: 16, 2, 16, 2>, offset = array<i64: -7, -7>, border = array<i64: 7, 7>} : (tensor<1x41x26x1xi16>) -> tensor<?x?x?x?xi48>
+ %0 = tosa.resize %arg0, %scale, %offset, %border {mode = "BILINEAR"} : (tensor<1x41x26x1xi16>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<?x?x?x?xi48>
return
}
// -----
// CHECK-LABEL: @resize_fp_horizontal
func.func @resize_fp_horizontal(%arg0: tensor<1x50x48x1xf32>) {
+ %scale = tosa.const_shape { value = dense<[15, 7, 84, 47]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
// CHECK: -> tensor<1x106x85x1xf32>
- %0 = tosa.resize %arg0 {mode = "BILINEAR", scale = array<i64: 15, 7, 84, 47>, offset = array<i64: 0, 0>, border = array<i64: 0, 0>} : (tensor<1x50x48x1xf32>) -> tensor<?x?x?x?xf32>
+ %0 = tosa.resize %arg0, %scale, %offset, %border {mode = "BILINEAR"} : (tensor<1x50x48x1xf32>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<?x?x?x?xf32>
return
}
// -----
// CHECK-LABEL: @resize_fp_vertical
func.func @resize_fp_vertical(%arg0: tensor<1x50x48x1xf32>) {
+ %scale = tosa.const_shape { value = dense<[127, 49, 12, 47]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
// CHECK: -> tensor<1x128x13x1xf32>
- %0 = tosa.resize %arg0 {mode = "NEAREST_NEIGHBOR", scale = array<i64: 127, 49, 12, 47>, offset = array<i64: 0, 0>, border = array<i64: 0, 0>} : (tensor<1x50x48x1xf32>) -> 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
}
@@ -1092,8 +1110,11 @@ func.func @resize_fp_vertical(%arg0: tensor<1x50x48x1xf32>) {
// CHECK-LABEL: @resize_fp_power_of_two_upscale
func.func @resize_fp_power_of_two_upscale(%arg0: tensor<1x23x23x1xf32>) {
+ %scale = tosa.const_shape { value = dense<[4, 1, 4, 1]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
// CHECK: -> tensor<1x89x89x1xf32>
- %0 = tosa.resize %arg0 {mode = "BILINEAR", scale = array<i64: 4, 1, 4, 1>, offset = array<i64: 0, 0>, border = array<i64: 0, 0>} : (tensor<1x23x23x1xf32>) -> tensor<?x?x?x?xf32>
+ %0 = tosa.resize %arg0, %scale, %offset, %border {mode = "BILINEAR"} : (tensor<1x23x23x1xf32>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<?x?x?x?xf32>
return
}
@@ -1101,8 +1122,11 @@ func.func @resize_fp_power_of_two_upscale(%arg0: tensor<1x23x23x1xf32>) {
// CHECK-LABEL: @resize_fp_power_of_two_upscale_offsetted
func.func @resize_fp_power_of_two_upscale_offsetted(%arg0: tensor<1x50x48x1xf32>) {
+ %scale = tosa.const_shape { value = dense<[64, 2, 64, 2]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<[-31, -31]> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<[31, 31]> : tensor<2xindex> } : () -> !tosa.shape<2>
// CHECK: -> tensor<1x1600x1536x1xf32>
- %0 = tosa.resize %arg0 {mode = "NEAREST_NEIGHBOR", scale = array<i64: 64, 2, 64, 2>, offset = array<i64: -31, -31>, border = array<i64: 31, 31>} : (tensor<1x50x48x1xf32>) -> 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 2c9578bf046de47de350d199586e6a1619a1cdc4 Mon Sep 17 00:00:00 2001
From: Hsiangkai Wang <hsiangkai.wang at arm.com>
Date: Wed, 12 Feb 2025 11:30:27 +0000
Subject: [PATCH 2/3] Address comments
---
.../Tosa/Transforms/TosaValidation.cpp | 163 +++++++++---------
1 file changed, 83 insertions(+), 80 deletions(-)
diff --git a/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp b/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
index e62caf997d6b0..0f067bb0a7756 100644
--- a/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
+++ b/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
@@ -527,96 +527,99 @@ LogicalResult TosaValidation::applyVariableCheck(Operation *op) {
}
bool checkErrorIfResize(Operation *op) {
- if (auto resize = dyn_cast<tosa::ResizeOp>(op)) {
- const Value input = resize.getInput();
- const Value output = resize.getOutput();
- const RankedTensorType inputType =
- llvm::dyn_cast<RankedTensorType>(input.getType());
- const RankedTensorType outputType =
- llvm::dyn_cast<RankedTensorType>(output.getType());
-
- if (!inputType || !outputType) {
- op->emitOpError("expect ranked input/output tensor");
- return false;
- }
+ auto resize = dyn_cast<tosa::ResizeOp>(op);
+ if (!resize)
+ return true;
- // Ensure the image size is supported by GPU APIs and that for integer
- // implementations, position * stride does not overflow int32_t.
- if (inputType.hasStaticShape() && outputType.hasStaticShape()) {
- const SmallVector<int64_t, 4> sizes = {
- outputType.getDimSize(1), outputType.getDimSize(2),
- inputType.getDimSize(1), inputType.getDimSize(2)};
- const int64_t *maxDim = llvm::max_element(sizes);
- if (maxDim != sizes.end() && *maxDim >= 16384) {
- op->emitOpError("expect input/output height/width dims to be < 16384, ")
- << "got [OH, OW, IH, IW] = " << sizes;
- return false;
- }
- }
+ const Value input = resize.getInput();
+ const Value output = resize.getOutput();
+ const RankedTensorType inputType =
+ llvm::dyn_cast<RankedTensorType>(input.getType());
+ const RankedTensorType outputType =
+ llvm::dyn_cast<RankedTensorType>(output.getType());
- SmallVector<int64_t> scale;
- if (!tosa::getConstShapeValue(resize.getScale().getDefiningOp(), scale)) {
+ if (!inputType || !outputType) {
+ op->emitOpError("expect ranked input/output tensor");
+ return false;
+ }
+
+ // Ensure the image size is supported by GPU APIs and that for integer
+ // implementations, position * stride does not overflow int32_t.
+ if (inputType.hasStaticShape() && outputType.hasStaticShape()) {
+ const SmallVector<int64_t, 4> sizes = {
+ outputType.getDimSize(1), outputType.getDimSize(2),
+ inputType.getDimSize(1), inputType.getDimSize(2)};
+ const int64_t *maxDim = llvm::max_element(sizes);
+ if (maxDim != sizes.end() && *maxDim >= 16384) {
+ op->emitOpError("expect input/output height/width dims to be < 16384, ")
+ << "got [OH, OW, IH, IW] = " << sizes;
return false;
}
+ }
- const int64_t scaleYN = scale[0];
- const int64_t scaleYD = scale[1];
- const int64_t scaleXN = scale[2];
- const int64_t scaleXD = scale[3];
+ SmallVector<int64_t> scale;
+ if (!tosa::getConstShapeValue(resize.getScale().getDefiningOp(), scale)) {
+ return false;
+ }
- // Ensure scale values don't overflow int32 accumulator
- if (scaleYN > (1 << 11) || scaleXN > (1 << 11)) {
- op->emitOpError("expect all scale numerator values to be <= (1 << 11), "
- "got scale_y_n=")
- << scaleYN << ", scale_x_n=" << scaleXN;
- return false;
- }
+ const int64_t scaleYN = scale[0];
+ const int64_t scaleYD = scale[1];
+ const int64_t scaleXN = scale[2];
+ const int64_t scaleXD = scale[3];
- if (scaleYD >= 16 * scaleYN || scaleXD >= 16 * scaleXN) {
- op->emitOpError("expect a downscale ratio larger than 1/16, got y=")
- << scaleYN << "/" << scaleYD << ", x=" << scaleXN << "/" << scaleXD;
- return false;
- }
+ // Ensure scale values don't overflow int32 accumulator
+ if (scaleYN > (1 << 11) || scaleXN > (1 << 11)) {
+ op->emitOpError("expect all scale numerator values to be <= (1 << 11), "
+ "got scale_y_n=")
+ << scaleYN << ", scale_x_n=" << scaleXN;
+ return false;
+ }
- SmallVector<int64_t> offset;
- SmallVector<int64_t> border;
- if (!tosa::getConstShapeValue(resize.getOffset().getDefiningOp(), offset) ||
- !tosa::getConstShapeValue(resize.getBorder().getDefiningOp(), border)) {
- return false;
- }
+ if (scaleYD >= 16 * scaleYN || scaleXD >= 16 * scaleXN) {
+ op->emitOpError("expect a downscale ratio larger than 1/16, got y=")
+ << scaleYN << "/" << scaleYD << ", x=" << scaleXN << "/" << scaleXD;
+ return false;
+ }
- const int64_t offsetY = offset[0];
- const int64_t offsetX = offset[1];
- const int64_t borderY = border[0];
- const int64_t borderX = border[1];
-
- // Set a consistent lower limit of 1/16 downscale to simplify
- // implementations
- if (offsetY < -scaleYN || offsetY >= 16 * scaleYN) {
- op->emitOpError(
- "expect offsetY / scaleYNumerator to be in range [-1, 16), got ")
- << offsetY << "/" << scaleYN;
- return false;
- }
- if (offsetX < -scaleXN || offsetX >= 16 * scaleXN) {
- op->emitOpError(
- "expect offsetX / scaleXNumerator to be in range [-1, 16), got ")
- << offsetX << "/" << scaleXN;
- return false;
- }
- if (borderY < -16 * scaleYN || borderY >= scaleYN) {
- op->emitOpError(
- "expect borderY / scaleYNumerator to be in range [-16, 1), got ")
- << borderY << "/" << scaleYN;
- return false;
- }
- if (borderX < -16 * scaleXN || borderX >= scaleXN) {
- op->emitOpError(
- "expect borderX / scaleXNumerator to be in range [-16, 1), got ")
- << borderX << "/" << scaleXN;
- return false;
- }
+ SmallVector<int64_t> offset;
+ SmallVector<int64_t> border;
+ if (!tosa::getConstShapeValue(resize.getOffset().getDefiningOp(), offset) ||
+ !tosa::getConstShapeValue(resize.getBorder().getDefiningOp(), border)) {
+ return false;
}
+
+ const int64_t offsetY = offset[0];
+ const int64_t offsetX = offset[1];
+ // Set a consistent lower limit of 1/16 downscale to simplify
+ // implementations
+ if (offsetY < -scaleYN || offsetY >= 16 * scaleYN) {
+ op->emitOpError(
+ "expect offsetY / scaleYNumerator to be in range [-1, 16), got ")
+ << offsetY << "/" << scaleYN;
+ return false;
+ }
+ if (offsetX < -scaleXN || offsetX >= 16 * scaleXN) {
+ op->emitOpError(
+ "expect offsetX / scaleXNumerator to be in range [-1, 16), got ")
+ << offsetX << "/" << scaleXN;
+ return false;
+ }
+
+ const int64_t borderY = border[0];
+ const int64_t borderX = border[1];
+ if (borderY < -16 * scaleYN || borderY >= scaleYN) {
+ op->emitOpError(
+ "expect borderY / scaleYNumerator to be in range [-16, 1), got ")
+ << borderY << "/" << scaleYN;
+ return false;
+ }
+ if (borderX < -16 * scaleXN || borderX >= scaleXN) {
+ op->emitOpError(
+ "expect borderX / scaleXNumerator to be in range [-16, 1), got ")
+ << borderX << "/" << scaleXN;
+ return false;
+ }
+
return true;
}
>From d3a6828f0ed51992e6786237cc464ed75f93fc39 Mon Sep 17 00:00:00 2001
From: Hsiangkai Wang <hsiangkai.wang at arm.com>
Date: Thu, 13 Feb 2025 17:10:08 +0000
Subject: [PATCH 3/3] add back test cases
---
.../TosaToLinalg/tosa-to-linalg-resize.mlir | 26 ++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-resize.mlir b/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-resize.mlir
index ad9f03d1c1d60..557a1ed8686b6 100644
--- a/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-resize.mlir
+++ b/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-resize.mlir
@@ -1,4 +1,4 @@
-// RUN: mlir-opt --split-input-file -pass-pipeline="builtin.module(func.func(tosa-to-linalg))" %s -o -| FileCheck %s
+// RUN: mlir-opt --split-input-file -pass-pipeline="builtin.module(func.func(tosa-to-linalg))" %s -verify-diagnostics -o - | FileCheck %s
// CHECK-LABEL: @unary_resize_nearest_fp32
func.func @unary_resize_nearest_fp32(%arg0 : tensor<3x1x1x7xf32>) -> tensor<3x1x1x7xf32> {
@@ -60,6 +60,30 @@ func.func @unary_resize_nearest_i8(%arg0 : tensor<3x1x1x7xi8>) -> tensor<3x1x1x7
// -----
+func.func @broadcast_resize_nearest_f32(%arg0 : tensor<3x1x1x7xf32>) -> tensor<3x1x5x7xf32> {
+ %scale = tosa.const_shape { value = dense<[2, 1, 3, 1]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ // expected-error @+1 {{'tosa.resize' op calculated output width did not match expected: calculated=1, expected=5}}
+ %resize = tosa.resize %arg0, %scale, %offset, %border {mode = "NEAREST_NEIGHBOR"} : (tensor<3x1x1x7xf32>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<3x1x5x7xf32>
+
+ return %resize : tensor<3x1x5x7xf32>
+}
+
+// -----
+
+func.func @broadcast_resize_bilinear_i8(%arg0 : tensor<3x1x1x7xi8>) -> tensor<3x4x5x7xi32> {
+ %scale = tosa.const_shape { value = dense<[2, 1, 3, 1]> : tensor<4xindex> } : () -> !tosa.shape<4>
+ %offset = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %border = tosa.const_shape { value = dense<0> : tensor<2xindex> } : () -> !tosa.shape<2>
+ // expected-error @+1 {{'tosa.resize' op calculated output height did not match expected: calculated=1, expected=4}}
+ %resize = tosa.resize %arg0, %scale, %offset, %border {mode = "BILINEAR"} : (tensor<3x1x1x7xi8>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<3x4x5x7xi32>
+
+ return %resize : tensor<3x4x5x7xi32>
+}
+
+// -----
+
// CHECK-LABEL: @unary_resize_bilinear_i32
func.func @unary_resize_bilinear_i32(%arg0 : tensor<3x1x1x7xi8>) -> tensor<3x1x1x7xi32> {
// CHECK: %[[COLLAPSE:.+]] = tensor.collapse_shape %arg0
More information about the Mlir-commits
mailing list