[Mlir-commits] [mlir] [mlir][tosa] Add TOSA Avg Pool 2D Adaptive (PR #190200)
Iliyan Georgiev
llvmlistbot at llvm.org
Thu Apr 2 08:47:24 PDT 2026
https://github.com/iliyan-georgiev-arm created https://github.com/llvm/llvm-project/pull/190200
Signed-off-by: Deeptanshu Sekhri <deeptanshu.sekhri at arm.com>
Co-authored-by: Iliyan Georgiev <iliyan.georgiev at arm.com>
>From 8455f20967a337cae538c98381acf358f73b2aca Mon Sep 17 00:00:00 2001
From: Deeptanshu Sekhri <deeptanshu.sekhri at arm.com>
Date: Mon, 23 Mar 2026 18:06:38 +0000
Subject: [PATCH] [mlir][tosa] Add TOSA Avg Pool 2D Adaptive
Signed-off-by: Deeptanshu Sekhri <deeptanshu.sekhri at arm.com>
Co-authored-by: Iliyan Georgiev <iliyan.georgiev at arm.com>
Change-Id: Ia8ef9000fc9e387fcf1b8e0280c9a2163dbc6280
---
.../Dialect/Tosa/IR/TosaComplianceData.h.inc | 22 ++
.../mlir/Dialect/Tosa/IR/TosaOpBase.td | 13 +-
mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td | 44 +++
mlir/lib/Dialect/Tosa/IR/TosaOps.cpp | 320 +++++++++++++-----
.../Tosa/Transforms/TosaProfileCompliance.cpp | 12 +
.../Tosa/Transforms/TosaValidation.cpp | 54 +++
mlir/test/Dialect/Tosa/availability.mlir | 14 +
mlir/test/Dialect/Tosa/dynamic_extension.mlir | 11 +
mlir/test/Dialect/Tosa/invalid.mlir | 193 +++++++++++
mlir/test/Dialect/Tosa/invalid_extension.mlir | 56 +--
mlir/test/Dialect/Tosa/level_check.mlir | 60 ++++
mlir/test/Dialect/Tosa/ops.mlir | 72 ++++
.../Tosa/profile_pro_fp_unsupported.mlir | 11 +
.../Tosa/profile_pro_int_unsupported.mlir | 27 +-
mlir/test/Dialect/Tosa/tosa-infer-shapes.mlir | 83 +++++
.../tosa-validation-version-1p0-invalid.mlir | 50 +++
.../tosa-validation-version-1p1-invalid.mlir | 27 ++
17 files changed, 917 insertions(+), 152 deletions(-)
create mode 100644 mlir/test/Dialect/Tosa/tosa-validation-version-1p1-invalid.mlir
diff --git a/mlir/include/mlir/Dialect/Tosa/IR/TosaComplianceData.h.inc b/mlir/include/mlir/Dialect/Tosa/IR/TosaComplianceData.h.inc
index 7ea0d134941c7..a575024a6144a 100644
--- a/mlir/include/mlir/Dialect/Tosa/IR/TosaComplianceData.h.inc
+++ b/mlir/include/mlir/Dialect/Tosa/IR/TosaComplianceData.h.inc
@@ -13,6 +13,16 @@ profileComplianceMap = {
{{{fp16T, fp16T, fp16T, fp16T, fp16T}, SpecificationVersion::V_1_0},
{{fp16T, fp16T, fp16T, fp32T, fp16T}, SpecificationVersion::V_1_0},
{{fp32T, fp32T, fp32T, fp32T, fp32T}, SpecificationVersion::V_1_0}}}}},
+ {"tosa.avg_pool2d_adaptive",
+ {{{Profile::pro_int},
+ {{{i8T, i8T, i8T, i32T, i8T}, SpecificationVersion::V_1_1_DRAFT}}},
+ {{Profile::pro_fp},
+ {{{fp16T, fp16T, fp16T, fp16T, fp16T},
+ SpecificationVersion::V_1_1_DRAFT},
+ {{fp16T, fp16T, fp16T, fp32T, fp16T},
+ SpecificationVersion::V_1_1_DRAFT},
+ {{fp32T, fp32T, fp32T, fp32T, fp32T},
+ SpecificationVersion::V_1_1_DRAFT}}}}},
{"tosa.conv2d",
{{{Profile::pro_int},
{{{i8T, i8T, i32T, i8T, i8T, i32T, i32T}, SpecificationVersion::V_1_0}}},
@@ -517,6 +527,18 @@ extensionComplianceMap = {
SpecificationVersion::V_1_0}}},
{{Extension::bf16},
{{{bf16T, bf16T, bf16T, fp32T, bf16T}, SpecificationVersion::V_1_0}}}}},
+ {"tosa.avg_pool2d_adaptive",
+ {{{Extension::int16},
+ {{{i16T, i16T, i16T, i32T, i16T}, SpecificationVersion::V_1_1_DRAFT}}},
+ {{Extension::fp8e4m3},
+ {{{fp8e4m3T, fp8e4m3T, fp8e4m3T, fp16T, fp8e4m3T},
+ SpecificationVersion::V_1_1_DRAFT}}},
+ {{Extension::fp8e5m2},
+ {{{fp8e5m2T, fp8e5m2T, fp8e5m2T, fp16T, fp8e5m2T},
+ SpecificationVersion::V_1_1_DRAFT}}},
+ {{Extension::bf16},
+ {{{bf16T, bf16T, bf16T, fp32T, bf16T},
+ SpecificationVersion::V_1_1_DRAFT}}}}},
{"tosa.conv2d",
{{{Extension::int4},
{{{i8T, i4T, i32T, i8T, i4T, i32T, i32T}, SpecificationVersion::V_1_0}}},
diff --git a/mlir/include/mlir/Dialect/Tosa/IR/TosaOpBase.td b/mlir/include/mlir/Dialect/Tosa/IR/TosaOpBase.td
index 9df17ed89b818..1f05aee3e5eec 100644
--- a/mlir/include/mlir/Dialect/Tosa/IR/TosaOpBase.td
+++ b/mlir/include/mlir/Dialect/Tosa/IR/TosaOpBase.td
@@ -167,7 +167,7 @@ def Tosa_MatMulOpQuantInfoBuilder : OpBuilder<
}]>;
// Both the tosa.avg_pool2d and unary ops use the same
-// UnaruOpQuantizationAttr but the avg_pool operator has its own builder as it
+// UnaryOpQuantizationAttr but the avg_pool operator has its own builder as it
// has additional parameters not part of the unary ops.
def Tosa_AvgPool2dOpQuantInfoBuilder : OpBuilder<
(ins "::mlir::Type":$outputType, "::mlir::Value":$input,
@@ -178,6 +178,17 @@ def Tosa_AvgPool2dOpQuantInfoBuilder : OpBuilder<
input, kernel, stride, pad, acc_type);
}]>;
+def Tosa_AvgPool2dAdaptiveOpQuantInfoBuilder
+ : OpBuilder<(ins "::mlir::Type":$outputType, "::mlir::Value":$input,
+ "::mlir::DenseI64ArrayAttr":$kernel,
+ "::mlir::DenseI64ArrayAttr":$stride,
+ "::mlir::DenseI64ArrayAttr":$pad,
+ "::mlir::TypeAttr":$acc_type),
+ [{
+ buildAvgPool2dAdaptiveOpWithQuantInfo($_builder, $_state, outputType,
+ input, kernel, stride, pad, acc_type);
+ }]>;
+
// This builder is called on single-parameter negate operators that have a scale
// relationship between their input and output, expressed by the
// UnaryOpQuantizationAttr.
diff --git a/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td b/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td
index cab2bccfc27b3..c1a4a98f03f9c 100644
--- a/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td
+++ b/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td
@@ -121,6 +121,50 @@ def Tosa_AvgPool2dOp : Tosa_InferShapedTypeOp<"avg_pool2d", [NoMemoryEffect]> {
"operands attr-dict `:` functional-type(operands, results)";
}
+//===----------------------------------------------------------------------===//
+// Operator: avg_pool2d_adaptive
+//===----------------------------------------------------------------------===//
+def Tosa_AvgPool2dAdaptiveOp : Tosa_InferShapedTypeOp<"avg_pool2d_adaptive"> {
+ let summary = "Performs average pooling on the input with shape operands.";
+
+ let description = [{
+ This performs an average pooling over the given input tensor. A sliding
+ window of size given by <kernel size> is passed over the input tensor, with
+ the mean value being placed in the output tensor. When calculating the
+ average, only the number of valid input tensor values, but not padding, are
+ used to calculate the divisor. Compared to avg_pool2d, the kernel/stride/
+ pad values are provided as inputs.
+ }];
+
+ let arguments = (ins Tosa_Tensor4D:$input,
+ Tosa_ScalarIntOrFloatTensor:$input_zp,
+ Tosa_ScalarIntOrFloatTensor:$output_zp, Rank2TosaShape:$kernel,
+ Rank2TosaShape:$stride, Rank4TosaShape:$pad,
+ TypeAttrOf<Tosa_AccType>:$acc_type);
+
+ let results = (outs Tosa_Tensor4D:$output);
+
+ list<Availability> availability =
+ [Profile<[Tosa_PRO_INT, Tosa_PRO_FP]>,
+ Extension<[Tosa_EXT_INT16, Tosa_EXT_FP8E4M3, Tosa_EXT_FP8E5M2,
+ Tosa_EXT_BF16]>,
+ ];
+
+ let builders = [Tosa_AvgPool2dAdaptiveOpQuantInfoBuilder];
+
+ let extraClassDeclaration = [{
+ FailureOr<int64_t> getInputZeroPoint();
+ FailureOr<int64_t> getOutputZeroPoint();
+ LogicalResult verifyInputZeroPoint(int64_t zp);
+ LogicalResult verifyOutputZeroPoint(int64_t zp);
+ }];
+
+ let hasVerifier = 1;
+
+ let assemblyFormat =
+ "operands attr-dict `:` functional-type(operands, results)";
+}
+
//===----------------------------------------------------------------------===//
// Operator: conv2d
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp b/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
index 6072aecdf347b..57353b683de78 100644
--- a/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
+++ b/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
@@ -31,6 +31,7 @@
#include "llvm/ADT/TypeSwitch.h"
#include <numeric>
+#include <type_traits>
using namespace mlir;
using namespace mlir::tosa;
@@ -1077,128 +1078,192 @@ LogicalResult tosa::ArgMaxOp::verify() {
return success();
}
-template <typename T>
-static LogicalResult verifyPoolingOp(T op) {
- const llvm::ArrayRef<int64_t> kernel = op.getKernel();
- if (llvm::any_of(kernel, [](int64_t s) { return s < 1; }))
- return op.emitOpError("expect all kernel values to be >= 1, got ")
+static LogicalResult verifyPoolingOpImpl(Operation *op,
+ ArrayRef<int64_t> kernel,
+ ArrayRef<int64_t> strides,
+ ArrayRef<int64_t> padding, Value input,
+ Value output) {
+ const bool hasKernel = kernel.size() > 0;
+ const bool hasStrides = strides.size() > 0;
+ const bool hasPad = padding.size() > 0;
+
+ if (hasKernel && llvm::any_of(kernel, [](int64_t s) { return s < 1; }))
+ return op->emitOpError("expect all kernel values to be >= 1, got ")
<< kernel;
- const llvm::ArrayRef<int64_t> strides = op.getStride();
- if (llvm::any_of(strides, [](int64_t s) { return s < 1; }))
- return op.emitOpError("expect all stride values to be >= 1, got ")
+ if (hasStrides && llvm::any_of(strides, [](int64_t s) { return s < 1; }))
+ return op->emitOpError("expect all stride values to be >= 1, got ")
<< strides;
- const llvm::ArrayRef<int64_t> padding = op.getPad();
- if (llvm::any_of(padding, [](int64_t p) { return p < 0; }))
- return op.emitOpError("expect all padding values to be >= 0, got ")
+ if (hasPad && llvm::any_of(padding, [](int64_t p) { return p < 0; }))
+ return op->emitOpError("expect all padding values to be >= 0, got ")
<< padding;
- // Padding must be less than kernel size to avoid a divide-by-zero
- const int64_t kernelX = kernel[1];
- const int64_t padLeft = padding[2];
- const int64_t padRight = padding[3];
- if (padRight >= kernelX || padLeft >= kernelX)
- return op.emitOpError("expected left/right padding to be less than the "
- "width of the kernel, got pad_left=")
- << padLeft << ", pad_right=" << padRight << ", kernel_x=" << kernelX;
-
- const int64_t kernelY = kernel[0];
- const int64_t padTop = padding[0];
- const int64_t padBottom = padding[1];
- if (padTop >= kernelY || padBottom >= kernelY)
- return op.emitOpError("expected top/bottom padding to be less than the "
- "height of the kernel, got pad_top=")
- << padTop << ", pad_bottom=" << padBottom
- << ", kernel_y=" << kernelY;
-
- const auto inputType =
- llvm::dyn_cast<RankedTensorType>(op.getInput().getType());
- const auto outputType =
- llvm::dyn_cast<RankedTensorType>(op.getResult().getType());
+ if (hasKernel && hasPad) {
+ // Padding must be less than kernel size to avoid a divide-by-zero
+ const int64_t kernelX = kernel[1];
+ const int64_t padLeft = padding[2];
+ const int64_t padRight = padding[3];
+ if (padRight >= kernelX || padLeft >= kernelX)
+ return op->emitOpError("expected left/right padding to be less than the "
+ "width of the kernel, got pad_left=")
+ << padLeft << ", pad_right=" << padRight
+ << ", kernel_x=" << kernelX;
+
+ const int64_t kernelY = kernel[0];
+ const int64_t padTop = padding[0];
+ const int64_t padBottom = padding[1];
+ if (padTop >= kernelY || padBottom >= kernelY)
+ return op->emitOpError("expected top/bottom padding to be less than the "
+ "height of the kernel, got pad_top=")
+ << padTop << ", pad_bottom=" << padBottom
+ << ", kernel_y=" << kernelY;
+ }
+
+ const auto inputType = llvm::dyn_cast<RankedTensorType>(input.getType());
+ const auto outputType = llvm::dyn_cast<RankedTensorType>(output.getType());
if (!inputType || !outputType)
return success();
- const auto verifyOutputSize =
- [&op](const int64_t inputSize, const int64_t outputSize,
- const int64_t kernelSize, const int64_t strideSize,
- const int64_t padBefore, const int64_t padAfter,
- const llvm::StringRef dimName, const llvm::StringRef dimAxis,
- const llvm::StringRef padBeforeName,
- const llvm::StringRef padAfterName) -> LogicalResult {
- if (ShapedType::isDynamic(inputSize))
- return success();
-
- const std::optional<int64_t> calculatedOutSizeMinusOne =
- idivCheck(inputSize + padBefore + padAfter - kernelSize, strideSize);
- if (!calculatedOutSizeMinusOne.has_value())
- return op.emitOpError("expected input_")
- << dimName << " + pad_" << padBeforeName << " + pad_"
- << padAfterName << " - kernel_" << dimAxis
- << " to be wholly divisible by stride_" << dimAxis << ", got ("
- << inputSize << " + " << padBefore << " + " << padAfter << " - "
- << kernelSize << ") / " << strideSize;
-
- const int64_t calculatedOutSize = calculatedOutSizeMinusOne.value() + 1;
- if (ShapedType::isStatic(outputSize) && calculatedOutSize != outputSize)
- return op.emitOpError("calculated output ")
- << dimName << " did not match expected: " << "calculated="
- << calculatedOutSize << ", expected=" << outputSize;
-
- return success();
- };
+ if (hasKernel && hasStrides && hasPad) {
+ const auto verifyOutputSize =
+ [op](const int64_t inputSize, const int64_t outputSize,
+ const int64_t kernelSize, const int64_t strideSize,
+ const int64_t padBefore, const int64_t padAfter,
+ const llvm::StringRef dimName, const llvm::StringRef dimAxis,
+ const llvm::StringRef padBeforeName,
+ const llvm::StringRef padAfterName) -> LogicalResult {
+ if (ShapedType::isDynamic(inputSize))
+ return success();
+
+ const std::optional<int64_t> calculatedOutSizeMinusOne =
+ idivCheck(inputSize + padBefore + padAfter - kernelSize, strideSize);
+ if (!calculatedOutSizeMinusOne.has_value())
+ return op->emitOpError("expected input_")
+ << dimName << " + pad_" << padBeforeName << " + pad_"
+ << padAfterName << " - kernel_" << dimAxis
+ << " to be wholly divisible by stride_" << dimAxis << ", got ("
+ << inputSize << " + " << padBefore << " + " << padAfter << " - "
+ << kernelSize << ") / " << strideSize;
+
+ const int64_t calculatedOutSize = calculatedOutSizeMinusOne.value() + 1;
+ if (ShapedType::isStatic(outputSize) && calculatedOutSize != outputSize)
+ return op->emitOpError("calculated output ")
+ << dimName << " did not match expected: " << "calculated="
+ << calculatedOutSize << ", expected=" << outputSize;
- if (failed(verifyOutputSize(inputType.getDimSize(1), outputType.getDimSize(1),
- kernel[0], strides[0], padding[0], padding[1],
- "height", "y", "top", "bottom")))
- return failure();
+ return success();
+ };
- if (failed(verifyOutputSize(inputType.getDimSize(2), outputType.getDimSize(2),
- kernel[1], strides[1], padding[2], padding[3],
- "width", "x", "left", "right")))
- return failure();
+ if (failed(verifyOutputSize(inputType.getDimSize(1),
+ outputType.getDimSize(1), kernel[0], strides[0],
+ padding[0], padding[1], "height", "y", "top",
+ "bottom")))
+ return failure();
+ if (failed(verifyOutputSize(
+ inputType.getDimSize(2), outputType.getDimSize(2), kernel[1],
+ strides[1], padding[2], padding[3], "width", "x", "left", "right")))
+ return failure();
+ }
return success();
}
-LogicalResult tosa::AvgPool2dOp::verify() {
- if (failed(verifyPoolingOp(*this)))
- return failure();
+template <typename T>
+static LogicalResult verifyPoolingOp(T op) {
+ return verifyPoolingOpImpl(op.getOperation(), op.getKernel(), op.getStride(),
+ op.getPad(), op.getInput(), op.getOutput());
+}
- const Type inputETy = getStorageElementTypeOrSelf(getInput().getType());
- const Type resultETy = getStorageElementTypeOrSelf(getOutput().getType());
- const Type inputZpETy = getStorageElementTypeOrSelf(getInputZp().getType());
- const Type outputZpETy = getStorageElementTypeOrSelf(getOutputZp().getType());
+template <typename T>
+static LogicalResult verifyAvgPoolCommonTypeAndZpChecks(T op) {
+ const Type inputETy = getStorageElementTypeOrSelf(op.getInput().getType());
+ const Type resultETy = getStorageElementTypeOrSelf(op.getOutput().getType());
+ const Type inputZpETy =
+ getStorageElementTypeOrSelf(op.getInputZp().getType());
+ const Type outputZpETy =
+ getStorageElementTypeOrSelf(op.getOutputZp().getType());
- auto accType = getAccType();
+ auto accType = op.getAccType();
if (llvm::isa<IntegerType>(inputETy) && !accType.isInteger(32))
- return emitOpError("accumulator type for integer tensor is not i32");
+ return op.emitOpError("accumulator type for integer tensor is not i32");
if (inputETy.isF16() && !(accType.isF16() || accType.isF32()))
- return emitOpError("accumulator type for f16 tensor is not f16/f32");
+ return op.emitOpError("accumulator type for f16 tensor is not f16/f32");
if (inputETy.isBF16() && !accType.isF32())
- return emitOpError("accumulator type for bf16 tensor is not f32");
+ return op.emitOpError("accumulator type for bf16 tensor is not f32");
if (inputETy.isF32() && !accType.isF32())
- return emitOpError("accumulator type for f32 tensor is not f32");
+ return op.emitOpError("accumulator type for f32 tensor is not f32");
if (inputETy != inputZpETy)
- return emitOpError("expect both input and its zero point are the same "
- "element type, got ")
+ return op.emitOpError("expect both input and its zero point are the same "
+ "element type, got ")
<< inputETy << " and " << inputZpETy;
if (resultETy != outputZpETy)
- return emitOpError("expect both output and its zero point are the same "
- "element type, got ")
+ return op.emitOpError("expect both output and its zero point are the same "
+ "element type, got ")
<< resultETy << " and " << outputZpETy;
- FailureOr<int64_t> maybeIZp = getInputZeroPoint();
- if (succeeded(maybeIZp) && verifyInputZeroPoint(*maybeIZp).failed())
+ FailureOr<int64_t> maybeIZp = op.getInputZeroPoint();
+ if (succeeded(maybeIZp) && op.verifyInputZeroPoint(*maybeIZp).failed())
return failure();
- FailureOr<int64_t> maybeOZp = getOutputZeroPoint();
- if (succeeded(maybeOZp) && verifyOutputZeroPoint(*maybeOZp).failed())
+ FailureOr<int64_t> maybeOZp = op.getOutputZeroPoint();
+ if (succeeded(maybeOZp) && op.verifyOutputZeroPoint(*maybeOZp).failed())
+ return failure();
+
+ return success();
+}
+
+namespace {
+struct AdaptivePoolingConstShapeValues {
+ llvm::SmallVector<int64_t> kernel;
+ llvm::SmallVector<int64_t> stride;
+ llvm::SmallVector<int64_t> pad;
+};
+} // namespace
+
+template <typename T>
+static constexpr bool IsSupportedAdaptivePoolConstShapeVerifyOp =
+ std::is_same_v<T, tosa::AvgPool2dAdaptiveOp>
+ // || std::is_same_v<T, tosa::MaxPool2dAdaptiveOp>
+ ;
+
+template <typename T,
+ typename std::enable_if<IsSupportedAdaptivePoolConstShapeVerifyOp<T>,
+ int>::type = 0>
+static void extractAdaptivePoolingConstShapeOperands(
+ T op, AdaptivePoolingConstShapeValues &values) {
+ tosa::getConstShapeValues(op.getKernel().getDefiningOp(), values.kernel);
+ tosa::getConstShapeValues(op.getStride().getDefiningOp(), values.stride);
+ tosa::getConstShapeValues(op.getPad().getDefiningOp(), values.pad);
+}
+
+LogicalResult tosa::AvgPool2dOp::verify() {
+ if (failed(verifyPoolingOp(*this)))
+ return failure();
+ if (failed(verifyAvgPoolCommonTypeAndZpChecks(*this)))
+ return failure();
+ return success();
+}
+
+LogicalResult tosa::AvgPool2dAdaptiveOp::verify() {
+ AdaptivePoolingConstShapeValues values;
+ extractAdaptivePoolingConstShapeOperands(*this, values);
+
+ // If pad/stride/kernel are not constant, this is okay, we just can't check
+ // their values. extractAdaptivePoolingConstShapeOperands will return an empty
+ // list for each non CTC input. verifyPoolingOpImpl will need to handle values
+ // not being present, and return success if they cannot be checked.
+
+ if (failed(verifyPoolingOpImpl(getOperation(), values.kernel, values.stride,
+ values.pad, getInput(), getOutput())))
+ return failure();
+
+ if (failed(verifyAvgPoolCommonTypeAndZpChecks(*this)))
return failure();
return success();
@@ -1394,6 +1459,52 @@ buildAvgPool2dOpWithQuantInfo(OpBuilder &builder, OperationState &result,
result.types.push_back(outputType);
}
+/// This builder mirrors avg_pool2d quant-info handling and materializes
+/// kernel/stride/pad as const_shape operands for avg_pool2d_adaptive.
+static void buildAvgPool2dAdaptiveOpWithQuantInfo(
+ OpBuilder &builder, OperationState &result, Type outputType, Value input,
+ DenseI64ArrayAttr kernel, DenseI64ArrayAttr stride, DenseI64ArrayAttr pad,
+ TypeAttr accType) {
+ const Location loc{result.location};
+ int64_t inputZp{0};
+ int64_t outputZp{0};
+
+ if (auto quantAttr =
+ buildUnaryOpQuantizationAttr(builder, input, outputType)) {
+ inputZp = quantAttr.getInputZp();
+ outputZp = quantAttr.getOutputZp();
+ }
+ const std::optional<Value> inputZpOp =
+ createZeroPointTensor(builder, loc, input.getType(), inputZp);
+ if (!inputZpOp) {
+ (void)emitError(loc,
+ "Failed to create input zero point tensor for quantized "
+ "AVG_POOL2D_ADAPTIVE op");
+ }
+ const std::optional<Value> outputZpOp =
+ createZeroPointTensor(builder, loc, outputType, outputZp);
+ if (!outputZpOp) {
+ (void)emitError(loc, "Failed to create output zero point tensor for "
+ "quantized AVG_POOL2D_ADAPTIVE op");
+ }
+
+ if (inputZpOp && outputZpOp) {
+ ImplicitLocOpBuilder b(loc, builder);
+ Value kernelShape = getTosaConstShape(b, kernel.asArrayRef());
+ Value strideShape = getTosaConstShape(b, stride.asArrayRef());
+ Value padShape = getTosaConstShape(b, pad.asArrayRef());
+ result.addOperands({input, inputZpOp.value(), outputZpOp.value(),
+ kernelShape, strideShape, padShape});
+ } else {
+ // Failed to create one or more zero points above: just add input as
+ // operands. This will trigger error in building the op because of missing
+ // operands.
+ result.addOperands({input});
+ }
+ result.addAttribute("acc_type", accType);
+ result.types.push_back(outputType);
+}
+
/// This builder is called on single-parameter negate operator
/// to construct input and output zero points based on their
/// types.
@@ -2765,6 +2876,8 @@ ZERO_POINT_HELPER(TransposeConv2DOp, Input, true)
ZERO_POINT_HELPER(TransposeConv2DOp, Weight, true)
ZERO_POINT_HELPER(AvgPool2dOp, Input, true)
ZERO_POINT_HELPER(AvgPool2dOp, Output, true)
+ZERO_POINT_HELPER(AvgPool2dAdaptiveOp, Input, true)
+ZERO_POINT_HELPER(AvgPool2dAdaptiveOp, Output, true)
ZERO_POINT_HELPER(MatMulOp, A, true)
ZERO_POINT_HELPER(MatMulOp, B, true)
ZERO_POINT_HELPER(NegateOp, Input1, true)
@@ -3935,6 +4048,35 @@ LogicalResult AvgPool2dOp::inferReturnTypeComponents(
inferredReturnShapes);
}
+LogicalResult AvgPool2dAdaptiveOp::inferReturnTypeComponents(
+ MLIRContext *context, ::std::optional<Location> location,
+ AvgPool2dAdaptiveOp::Adaptor adaptor,
+ SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
+ ShapeAdaptor inputShape(adaptor.getInput().getType());
+
+ llvm::SmallVector<int64_t> kernelValues;
+ llvm::SmallVector<int64_t> strideValues;
+ llvm::SmallVector<int64_t> padValues;
+ if (tosa::getConstShapeValues(adaptor.getKernel().getDefiningOp(),
+ kernelValues) &&
+ tosa::getConstShapeValues(adaptor.getStride().getDefiningOp(),
+ strideValues) &&
+ tosa::getConstShapeValues(adaptor.getPad().getDefiningOp(), padValues)) {
+ return poolingInferReturnTypes(inputShape, kernelValues, strideValues,
+ padValues, inferredReturnShapes);
+ }
+
+ llvm::SmallVector<int64_t> outputShape(4, ShapedType::kDynamic);
+ if (inputShape.hasRank()) {
+ // Keep N & C as pooling only changes H & W.
+ outputShape[0] = inputShape.getDimSize(0);
+ outputShape[3] = inputShape.getDimSize(3);
+ }
+
+ inferredReturnShapes.push_back(ShapedTypeComponents(outputShape));
+ return success();
+}
+
LogicalResult MaxPool2dOp::inferReturnTypeComponents(
MLIRContext *context, ::std::optional<Location> location,
MaxPool2dOp::Adaptor adaptor,
diff --git a/mlir/lib/Dialect/Tosa/Transforms/TosaProfileCompliance.cpp b/mlir/lib/Dialect/Tosa/Transforms/TosaProfileCompliance.cpp
index 3368e70af2209..78bf700597c3c 100644
--- a/mlir/lib/Dialect/Tosa/Transforms/TosaProfileCompliance.cpp
+++ b/mlir/lib/Dialect/Tosa/Transforms/TosaProfileCompliance.cpp
@@ -77,6 +77,17 @@ LogicalResult ProfileInfoDepot::populateProfileInfo(tosa::AvgPool2dOp op) {
return success();
}
+template <>
+LogicalResult
+ProfileInfoDepot::populateProfileInfo(tosa::AvgPool2dAdaptiveOp op) {
+ addValue(op.getInput());
+ addValue(op.getInputZp());
+ addValue(op.getOutputZp());
+ addType(op.getAccType());
+ addValue(op.getOutput());
+ return success();
+}
+
template <typename T>
LogicalResult ProfileInfoDepot::populateProfileInfoConv(T op) {
addValue(op.getInput());
@@ -255,6 +266,7 @@ LogicalResult ProfileInfoDepot::populatationDispatch(Operation *op) {
// Skip irrelevant operands when they are independent and not tied to any
// specific profile/extension.
POPULATE_PROFILE_INFO_CUSTOM(AvgPool2d)
+ POPULATE_PROFILE_INFO_CUSTOM(AvgPool2dAdaptive)
POPULATE_PROFILE_INFO_CUSTOM(TransposeConv2D)
POPULATE_PROFILE_INFO_CUSTOM(Conv2D)
POPULATE_PROFILE_INFO_CUSTOM(Conv2DBlockScaled)
diff --git a/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp b/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
index 35b4b862dbff7..6169003881487 100644
--- a/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
+++ b/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
@@ -16,6 +16,7 @@
#include "mlir/Dialect/Tosa/Transforms/Passes.h"
#include <string>
+#include <type_traits>
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/Dialect/Tosa/IR/TosaOps.h"
@@ -122,6 +123,17 @@ static LogicalResult checkConstantOperandAvgPool2d(Operation *op,
return success();
}
+static LogicalResult
+checkConstantOperandAvgPool2dAdaptive(Operation *op, const TargetEnv &env) {
+ if (!env.allows(Extension::dynamic) && isa<tosa::AvgPool2dAdaptiveOp>(op)) {
+ // Check 'input_zp' and 'output_zp'.
+ // Note: 'kernel', 'stride', and 'pad' (operands 3, 4, 5) are not checked
+ // as they are tosa.shape types.
+ return checkConstantOperands(op, {1, 2});
+ }
+ return success();
+}
+
static LogicalResult checkConstantOperandNegate(Operation *op,
const TargetEnv &env) {
if (!env.allows(Extension::dynamic) && isa<tosa::NegateOp>(op)) {
@@ -187,6 +199,7 @@ struct TosaValidation : public tosa::impl::TosaValidationBase<TosaValidation> {
checkConstantOperandConvOps<tosa::TransposeConv2DOp>);
constCheckers.emplace_back(checkConstantOperandMatMul);
constCheckers.emplace_back(checkConstantOperandAvgPool2d);
+ constCheckers.emplace_back(checkConstantOperandAvgPool2dAdaptive);
constCheckers.emplace_back(checkConstantOperandNegate);
constCheckers.emplace_back(checkConstantOperandSilceShape);
}
@@ -344,6 +357,45 @@ struct TosaValidation : public tosa::impl::TosaValidationBase<TosaValidation> {
return success();
}
+ template <typename T>
+ static constexpr bool IsSupportedAdaptivePoolOp =
+ std::is_same_v<T, tosa::AvgPool2dAdaptiveOp>
+ // || std::is_same_v<T, tosa::MaxPool2dAdaptiveOp>
+ ;
+
+ template <typename T, typename std::enable_if<IsSupportedAdaptivePoolOp<T>,
+ int>::type = 0>
+ LogicalResult levelCheckAdaptivePool(Operation *op) {
+ auto poolOp = dyn_cast<T>(op);
+ if (!poolOp)
+ return success();
+
+ SmallVector<int64_t> kernelValues;
+ if (tosa::getConstShapeValues(poolOp.getKernel().getDefiningOp(),
+ kernelValues)) {
+ for (const auto k : kernelValues)
+ if (failed(levelCheckKernel(op, k, "kernel")))
+ return failure();
+ }
+
+ SmallVector<int64_t> strideValues;
+ if (tosa::getConstShapeValues(poolOp.getStride().getDefiningOp(),
+ strideValues)) {
+ for (const auto s : strideValues)
+ if (failed(levelCheckStride(op, s, "stride")))
+ return failure();
+ }
+
+ SmallVector<int64_t> padValues;
+ if (tosa::getConstShapeValues(poolOp.getPad().getDefiningOp(), padValues)) {
+ for (const auto p : padValues)
+ if (failed(levelCheckKernel(op, p, "pad")))
+ return failure();
+ }
+
+ return success();
+ }
+
// Conv Op: level check dilation/stride/pad values
template <typename T>
LogicalResult levelCheckConv(Operation *op) {
@@ -755,6 +807,7 @@ LogicalResult TosaValidation::levelCheckRanksAndSizes(Operation *op) {
// Tensor Operators
CHECK_SIZES(AvgPool2d);
+ CHECK_SIZES(AvgPool2dAdaptive);
CHECK_SIZES(Conv2D);
CHECK_SIZES(Conv2DBlockScaled);
CHECK_SIZES(Conv3D);
@@ -859,6 +912,7 @@ LogicalResult TosaValidation::applyLevelCheck(Operation *op) {
return failure();
if (failed(levelCheckPool<tosa::AvgPool2dOp>(op)) ||
+ failed(levelCheckAdaptivePool<tosa::AvgPool2dAdaptiveOp>(op)) ||
failed(levelCheckConv<tosa::Conv2DOp>(op)) ||
failed(levelCheckConv<tosa::Conv3DOp>(op)) ||
failed(levelCheckConv<tosa::DepthwiseConv2DOp>(op)) ||
diff --git a/mlir/test/Dialect/Tosa/availability.mlir b/mlir/test/Dialect/Tosa/availability.mlir
index 8f44ca06d804a..34de532639994 100644
--- a/mlir/test/Dialect/Tosa/availability.mlir
+++ b/mlir/test/Dialect/Tosa/availability.mlir
@@ -25,6 +25,20 @@ func.func @test_avg_pool2d(%arg0: tensor<1x7x7x9xf32>) -> tensor<1x7x7x9xf32> {
return %0 : tensor<1x7x7x9xf32>
}
+// -----
+// CHECK-LABEL: avg_pool2d_adaptive
+func.func @test_avg_pool2d_adaptive(%arg0: tensor<1x7x7x9xf32>) -> tensor<1x7x7x9xf32> {
+ // CHECK: profiles: [ [pro_int, pro_fp] ]
+ // CHECK: extensions: [ [int16, fp8e4m3, fp8e5m2, bf16] ]
+ %input_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %output_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %kernel = tosa.const_shape {values = dense<[2, 2]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 1, 0, 1]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ %0 = tosa.avg_pool2d_adaptive %arg0, %input_zp, %output_zp, %kernel, %stride, %pad {acc_type = f32} : (tensor<1x7x7x9xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x7x7x9xf32>
+ return %0 : tensor<1x7x7x9xf32>
+}
+
// -----
// CHECK-LABEL: conv2d
func.func @test_conv2d(%arg0: tensor<1x4x4x4xf32>, %arg1: tensor<8x1x1x4xf32>, %arg2: tensor<8xf32>) -> tensor<1x4x4x8xf32> {
diff --git a/mlir/test/Dialect/Tosa/dynamic_extension.mlir b/mlir/test/Dialect/Tosa/dynamic_extension.mlir
index a1329afc3bb03..4d4c000946bf5 100644
--- a/mlir/test/Dialect/Tosa/dynamic_extension.mlir
+++ b/mlir/test/Dialect/Tosa/dynamic_extension.mlir
@@ -88,6 +88,17 @@ func.func @test_avg_pool2d_non_const_zps(%arg0: tensor<1x32x32x8xf32>, %input_zp
// -----
+func.func @test_avg_pool2d_adaptive_non_const_zps(%arg0: tensor<1x32x32x8xf32>, %input_zp: tensor<1xf32>, %output_zp: tensor<1xf32>) -> tensor<1x32x32x8xf32> {
+ %kernel = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 0, 0, 0]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ %0 = "tosa.avg_pool2d_adaptive"(%arg0, %input_zp, %output_zp, %kernel, %stride, %pad) {acc_type = f32} :
+ (tensor<1x32x32x8xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x32x32x8xf32>
+ return %0 : tensor<1x32x32x8xf32>
+}
+
+// -----
+
func.func @test_slice_shape_non_const_start_size(%arg0: tensor<1xi32>, %arg1: tensor<1xi32>) -> !tosa.shape<3> {
%0 = tosa.const_shape {values = dense<[4, 5, 6, 7, 8, 9]> : tensor<6xindex>} : () -> !tosa.shape<6>
%3 = tosa.slice_shape %0, %arg0, %arg1 : (!tosa.shape<6>, tensor<1xi32>, tensor<1xi32>) -> !tosa.shape<3>
diff --git a/mlir/test/Dialect/Tosa/invalid.mlir b/mlir/test/Dialect/Tosa/invalid.mlir
index b7334fb4246a7..79e5b4688bda1 100644
--- a/mlir/test/Dialect/Tosa/invalid.mlir
+++ b/mlir/test/Dialect/Tosa/invalid.mlir
@@ -1885,6 +1885,199 @@ func.func @test_avgpool2d_unexpected_output_width(%arg0: tensor<1x32x32x8xf32>,
// -----
+func.func @test_avgpool2d_adaptive_non_const_shape_operands(%arg0: tensor<1x32x32x8xf32>, %kernel: !tosa.shape<2>, %stride: !tosa.shape<2>, %pad: !tosa.shape<4>) -> tensor<1x32x32x8xf32> {
+ %input_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %output_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ // expected-error at +1 {{'tosa.avg_pool2d_adaptive' op shape operand is not compile time resolvable}}
+ %0 = "tosa.avg_pool2d_adaptive"(%arg0, %input_zp, %output_zp, %kernel, %stride, %pad) {acc_type = f32} :
+ (tensor<1x32x32x8xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x32x32x8xf32>
+ return %0 : tensor<1x32x32x8xf32>
+}
+
+// -----
+
+func.func @test_avgpool2d_adaptive_invalid_kernel(%arg0: tensor<1x32x32x8xf32>) -> tensor<1x32x32x8xf32> {
+ %input_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %output_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %kernel = tosa.const_shape {values = dense<[0, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 0, 0, 0]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ // expected-error at +1 {{'tosa.avg_pool2d_adaptive' op expect all kernel values to be >= 1, got 0, 1}}
+ %0 = "tosa.avg_pool2d_adaptive"(%arg0, %input_zp, %output_zp, %kernel, %stride, %pad) {acc_type = f32} :
+ (tensor<1x32x32x8xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x32x32x8xf32>
+ return %0 : tensor<1x32x32x8xf32>
+}
+
+// -----
+
+func.func @test_avgpool2d_adaptive_invalid_stride(%arg0: tensor<1x32x32x8xf32>) -> tensor<1x32x32x8xf32> {
+ %input_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %output_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %kernel = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 0]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 0, 0, 0]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ // expected-error at +1 {{'tosa.avg_pool2d_adaptive' op expect all stride values to be >= 1, got 1, 0}}
+ %0 = "tosa.avg_pool2d_adaptive"(%arg0, %input_zp, %output_zp, %kernel, %stride, %pad) {acc_type = f32} :
+ (tensor<1x32x32x8xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x32x32x8xf32>
+ return %0 : tensor<1x32x32x8xf32>
+}
+
+// -----
+
+func.func @test_avgpool2d_adaptive_invalid_pad(%arg0: tensor<1x32x32x8xf32>) -> tensor<1x32x32x8xf32> {
+ %input_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %output_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %kernel = tosa.const_shape {values = dense<[2, 2]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 0, 2, 0]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ // expected-error at +1 {{'tosa.avg_pool2d_adaptive' op expected left/right padding to be less than the width of the kernel}}
+ %0 = "tosa.avg_pool2d_adaptive"(%arg0, %input_zp, %output_zp, %kernel, %stride, %pad) {acc_type = f32} :
+ (tensor<1x32x32x8xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x32x32x8xf32>
+ return %0 : tensor<1x32x32x8xf32>
+}
+
+// -----
+
+func.func @test_avgpool2d_adaptive_unexpected_output_height(%arg0: tensor<1x32x32x8xf32>) -> tensor<1x33x32x8xf32> {
+ %input_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %output_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %kernel = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 0, 0, 0]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ // expected-error at +1 {{'tosa.avg_pool2d_adaptive' op calculated output height did not match expected: calculated=32, expected=33}}
+ %0 = "tosa.avg_pool2d_adaptive"(%arg0, %input_zp, %output_zp, %kernel, %stride, %pad) {acc_type = f32} :
+ (tensor<1x32x32x8xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x33x32x8xf32>
+ return %0 : tensor<1x33x32x8xf32>
+}
+
+// -----
+
+func.func @test_avgpool2d_adaptive_padding_not_less_than_kernel_x(%arg0: tensor<1x32x32x8xf32>) -> tensor<1x32x32x8xf32> {
+ %input_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %output_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %kernel = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 0, 0, 1]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ // expected-error at +1 {{'tosa.avg_pool2d_adaptive' op expected left/right padding to be less than the width of the kernel, got pad_left=0, pad_right=1, kernel_x=1}}
+ %0 = "tosa.avg_pool2d_adaptive"(%arg0, %input_zp, %output_zp, %kernel, %stride, %pad) {acc_type = f32} :
+ (tensor<1x32x32x8xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x32x32x8xf32>
+ return %0 : tensor<1x32x32x8xf32>
+}
+
+// -----
+
+func.func @test_avgpool2d_adaptive_padding_not_less_than_kernel_y(%arg0: tensor<1x32x32x8xf32>) -> tensor<1x32x32x8xf32> {
+ %input_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %output_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %kernel = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[2, 0, 0, 0]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ // expected-error at +1 {{'tosa.avg_pool2d_adaptive' op expected top/bottom padding to be less than the height of the kernel, got pad_top=2, pad_bottom=0, kernel_y=1}}
+ %0 = "tosa.avg_pool2d_adaptive"(%arg0, %input_zp, %output_zp, %kernel, %stride, %pad) {acc_type = f32} :
+ (tensor<1x32x32x8xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x32x32x8xf32>
+ return %0 : tensor<1x32x32x8xf32>
+}
+
+// -----
+
+func.func @test_avgpool2d_adaptive_wholly_divisible_height(%arg0: tensor<1x32x32x8xf32>) -> tensor<1x32x32x8xf32> {
+ %input_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %output_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %kernel = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[2, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 0, 0, 0]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ // expected-error at +1 {{'tosa.avg_pool2d_adaptive' op expected input_height + pad_top + pad_bottom - kernel_y to be wholly divisible by stride_y, got (32 + 0 + 0 - 1) / 2}}
+ %0 = "tosa.avg_pool2d_adaptive"(%arg0, %input_zp, %output_zp, %kernel, %stride, %pad) {acc_type = f32} :
+ (tensor<1x32x32x8xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x32x32x8xf32>
+ return %0 : tensor<1x32x32x8xf32>
+}
+
+// -----
+
+func.func @test_avgpool2d_adaptive_wholly_divisible_width(%arg0: tensor<1x32x32x8xf32>) -> tensor<1x32x32x8xf32> {
+ %input_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %output_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %kernel = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 2]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 0, 0, 0]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ // expected-error at +1 {{'tosa.avg_pool2d_adaptive' op expected input_width + pad_left + pad_right - kernel_x to be wholly divisible by stride_x, got (32 + 0 + 0 - 1) / 2}}
+ %0 = "tosa.avg_pool2d_adaptive"(%arg0, %input_zp, %output_zp, %kernel, %stride, %pad) {acc_type = f32} :
+ (tensor<1x32x32x8xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x32x32x8xf32>
+ return %0 : tensor<1x32x32x8xf32>
+}
+
+// -----
+
+func.func @test_avgpool2d_adaptive_invalid_acc_type(%arg0: tensor<1x32x32x8xi8>) -> tensor<1x32x32x8xi8> {
+ %input_zp = "tosa.const"() <{values = dense<0> : tensor<1xi8>}> : () -> tensor<1xi8>
+ %output_zp = "tosa.const"() <{values = dense<0> : tensor<1xi8>}> : () -> tensor<1xi8>
+ %kernel = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 0, 0, 0]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ // expected-error at +1 {{'tosa.avg_pool2d_adaptive' op accumulator type for integer tensor is not i32}}
+ %0 = "tosa.avg_pool2d_adaptive"(%arg0, %input_zp, %output_zp, %kernel, %stride, %pad) {acc_type = f32} :
+ (tensor<1x32x32x8xi8>, tensor<1xi8>, tensor<1xi8>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x32x32x8xi8>
+ return %0 : tensor<1x32x32x8xi8>
+}
+
+// -----
+
+func.func @test_avgpool2d_adaptive_input_zp_type_mismatch(%arg0: tensor<1x32x32x8xf32>) -> tensor<1x32x32x8xf32> {
+ %input_zp = "tosa.const"() <{values = dense<0> : tensor<1xi32>}> : () -> tensor<1xi32>
+ %output_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %kernel = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 0, 0, 0]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ // expected-error at +1 {{'tosa.avg_pool2d_adaptive' op expect both input and its zero point are the same element type, got 'f32' and 'i32'}}
+ %0 = "tosa.avg_pool2d_adaptive"(%arg0, %input_zp, %output_zp, %kernel, %stride, %pad) {acc_type = f32} :
+ (tensor<1x32x32x8xf32>, tensor<1xi32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x32x32x8xf32>
+ return %0 : tensor<1x32x32x8xf32>
+}
+
+// -----
+
+func.func @test_avgpool2d_adaptive_output_zp_type_mismatch(%arg0: tensor<1x32x32x8xf32>) -> tensor<1x32x32x8xf32> {
+ %input_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %output_zp = "tosa.const"() <{values = dense<0> : tensor<1xi32>}> : () -> tensor<1xi32>
+ %kernel = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 0, 0, 0]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ // expected-error at +1 {{'tosa.avg_pool2d_adaptive' op expect both output and its zero point are the same element type, got 'f32' and 'i32'}}
+ %0 = "tosa.avg_pool2d_adaptive"(%arg0, %input_zp, %output_zp, %kernel, %stride, %pad) {acc_type = f32} :
+ (tensor<1x32x32x8xf32>, tensor<1xf32>, tensor<1xi32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x32x32x8xf32>
+ return %0 : tensor<1x32x32x8xf32>
+}
+
+// -----
+
+func.func @test_avgpool2d_adaptive_input_zp_non_zero(%arg0: tensor<1x32x32x8xf32>) -> tensor<1x32x32x8xf32> {
+ %input_zp = "tosa.const"() <{values = dense<-1.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %output_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %kernel = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 0, 0, 0]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ // expected-error at +1 {{'tosa.avg_pool2d_adaptive' op input zero point must be zero for non-int8 integer types}}
+ %0 = "tosa.avg_pool2d_adaptive"(%arg0, %input_zp, %output_zp, %kernel, %stride, %pad) {acc_type = f32} :
+ (tensor<1x32x32x8xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x32x32x8xf32>
+ return %0 : tensor<1x32x32x8xf32>
+}
+
+// -----
+
+func.func @test_avgpool2d_adaptive_output_zp_non_zero(%arg0: tensor<1x32x32x8xf32>) -> tensor<1x32x32x8xf32> {
+ %input_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %output_zp = "tosa.const"() <{values = dense<-1.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %kernel = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 0, 0, 0]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ // expected-error at +1 {{'tosa.avg_pool2d_adaptive' op output zero point must be zero for non-int8 integer types}}
+ %0 = "tosa.avg_pool2d_adaptive"(%arg0, %input_zp, %output_zp, %kernel, %stride, %pad) {acc_type = f32} :
+ (tensor<1x32x32x8xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x32x32x8xf32>
+ return %0 : tensor<1x32x32x8xf32>
+}
+
+// -----
+
func.func @test_maxpool2d_invalid_kernel(%arg0: tensor<1x32x32x8xf32>) -> tensor<1x2x32x8xf32> {
// expected-error at +1 {{'tosa.max_pool2d' op expect all kernel values to be >= 1, got 0, 1}}
%0 = "tosa.max_pool2d"(%arg0) {kernel = array<i64: 0, 1>, pad = array<i64: 0, 0, 0, 0>, stride = array<i64: 1, 1>} :
diff --git a/mlir/test/Dialect/Tosa/invalid_extension.mlir b/mlir/test/Dialect/Tosa/invalid_extension.mlir
index 901d865f4caeb..1519b6845dd7e 100644
--- a/mlir/test/Dialect/Tosa/invalid_extension.mlir
+++ b/mlir/test/Dialect/Tosa/invalid_extension.mlir
@@ -2,7 +2,7 @@
// Enable all supported profiles to focus the verification of expected extension requirement errors.
//--------------------------------------------------------------------------------------------------
-// RUN: mlir-opt %s -split-input-file -verify-diagnostics -tosa-attach-target="profiles=pro_int,pro_fp" -tosa-validate="strict-op-spec-alignment"
+// RUN: mlir-opt %s -split-input-file -verify-diagnostics -tosa-attach-target="specification_version=1.1.draft profiles=pro_int,pro_fp" -tosa-validate="strict-op-spec-alignment"
// -----
func.func @test_argmax(%arg0: tensor<14x19xbf16>) -> tensor<14xi32> {
@@ -548,41 +548,14 @@ func.func @test_avg_pool2d_non_const_output_zp(%arg0: tensor<1x32x32x8xf32>, %ou
// -----
-func.func @test_matmul_t_block_scaled(%arg0: tensor<4x8x32xf8E4M3FN>, %arg1: tensor<4x8x1xf8E8M0FNU>, %arg2: tensor<4x16x32xf8E4M3FN>, %arg3: tensor<4x16x1xf8E8M0FNU>) -> tensor<4x8x16xf32> {
- // expected-error at +1 {{'tosa.matmul_t_block_scaled' op illegal: requires specification version compatible with 1.1 (got 1.0) and requires any of [mxfp] profiles/extensions to be specified in the target environment}}
- %0 = tosa.matmul_t_block_scaled %arg0, %arg1, %arg2, %arg3 {block_size = #tosa.block_size<BLOCK_SIZE_32>} : (tensor<4x8x32xf8E4M3FN>, tensor<4x8x1xf8E8M0FNU>, tensor<4x16x32xf8E4M3FN>, tensor<4x16x1xf8E8M0FNU>) -> tensor<4x8x16xf32>
- return %0 : tensor<4x8x16xf32>
-}
-
-// -----
-
-func.func @test_argmax_int64(%arg0: tensor<1x13x13x5xf32>) -> tensor<1x13x13xi64> {
- // expected-error at +1 {{'tosa.argmax' op illegal: requires specification version compatible with 1.1 (got 1.0) and requires any of [int64] profiles/extensions to be specified in the target environment}}
- %0 = tosa.argmax %arg0 {axis = 3 : i32} : (tensor<1x13x13x5xf32>) -> tensor<1x13x13xi64>
- return %0 : tensor<1x13x13xi64>
-}
-
-// -----
-func.func @test_const_fp6e3m2(%arg0 : index) -> tensor<4xf6E3M2FN> {
- // expected-error at +1 {{'tosa.const' op illegal: requires specification version compatible with 1.1 (got 1.0) and requires any of [mxfp] profiles/extensions to be specified in the target environment}}
- %0 = "tosa.const"() {values = dense<[0.0, 0.0, 0.0, 0.0]> : tensor<4xf6E3M2FN>} : () -> tensor<4xf6E3M2FN>
- return %0 : tensor<4xf6E3M2FN>
-}
-
-// -----
-
-func.func @test_cast_from_block_scaled(%arg0: tensor<4x32xf8E5M2>, %arg1: tensor<4x1xf8E8M0FNU>) -> tensor<4x32xf32> {
- // expected-error at +1 {{'tosa.cast_from_block_scaled' op illegal: requires specification version compatible with 1.1 (got 1.0) and requires any of [mxfp] profiles/extensions to be specified in the target environment}}
- %0 = tosa.cast_from_block_scaled %arg0, %arg1 {block_size = #tosa.block_size<BLOCK_SIZE_32> : i32} : (tensor<4x32xf8E5M2>, tensor<4x1xf8E8M0FNU>) -> tensor<4x32xf32>
- return %0 : tensor<4x32xf32>
-}
-
-// -----
-
-func.func @test_cast_to_block_scaled(%arg0: tensor<4x32xf32>) -> (tensor<4x32xf6E3M2FN>, tensor<4x1xf8E8M0FNU>) {
- // expected-error at +1 {{'tosa.cast_to_block_scaled' op illegal: requires specification version compatible with 1.1 (got 1.0) and requires any of [mxfp] profiles/extensions to be specified in the target environment}}
- %0:2 = tosa.cast_to_block_scaled %arg0 {block_size = #tosa.block_size<BLOCK_SIZE_32>} : (tensor<4x32xf32>) -> (tensor<4x32xf6E3M2FN>, tensor<4x1xf8E8M0FNU>)
- return %0#0, %0#1 : tensor<4x32xf6E3M2FN>, tensor<4x1xf8E8M0FNU>
+func.func @test_avg_pool2d_adaptive_missing_bf16_extension(%arg0: tensor<1x7x7x9xbf16>, %arg1: tensor<1xbf16>, %arg2: tensor<1xbf16>) -> tensor<1x7x7x9xbf16> {
+ %kernel = tosa.const_shape {values = dense<[2, 2]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 1, 0, 1]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ // expected-error at +1 {{'tosa.avg_pool2d_adaptive' op illegal: requires any of [bf16] profiles/extensions to be specified in the target environment}}
+ %0 = tosa.avg_pool2d_adaptive %arg0, %arg1, %arg2, %kernel, %stride, %pad {acc_type = f32} :
+ (tensor<1x7x7x9xbf16>, tensor<1xbf16>, tensor<1xbf16>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x7x7x9xbf16>
+ return %0 : tensor<1x7x7x9xbf16>
}
// -----
@@ -614,14 +587,3 @@ func.func @test_min_shape() -> !tosa.shape<4> {
%c = tosa.min_shape %a, %b : (!tosa.shape<4>, !tosa.shape<4>) -> !tosa.shape<4>
return %c : !tosa.shape<4>
}
-
-// -----
-
-func.func @test_conv2d_block_scaled(%arg0: tensor<*xf4E2M1FN>, %arg1: tensor<*xf8E8M0FNU>, %arg2: tensor<*xf4E2M1FN>, %arg3: tensor<*xf8E8M0FNU>, %arg4: tensor<*xf32>) -> tensor<*xf32> {
- %0 = tosa.const_shape {values = dense<[0, 0, 0, 0]> : tensor<4xindex>} : () -> !tosa.shape<4>
- %1 = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
- %2 = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
- // expected-error at +1 {{'tosa.conv2d_block_scaled' op illegal: requires specification version compatible with 1.1 (got 1.0) and requires any of [mxfp_conv] profiles/extensions to be specified in the target environment}}
- %3 = tosa.conv2d_block_scaled %arg0, %arg1, %arg2, %arg3, %arg4, %0, %1, %2 {block_size = BLOCK_SIZE_32} : (tensor<*xf4E2M1FN>, tensor<*xf8E8M0FNU>, tensor<*xf4E2M1FN>, tensor<*xf8E8M0FNU>, tensor<*xf32>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<*xf32>
- return %3 : tensor<*xf32>
-}
diff --git a/mlir/test/Dialect/Tosa/level_check.mlir b/mlir/test/Dialect/Tosa/level_check.mlir
index d061da14bb109..b3bdb02c20103 100644
--- a/mlir/test/Dialect/Tosa/level_check.mlir
+++ b/mlir/test/Dialect/Tosa/level_check.mlir
@@ -556,6 +556,54 @@ func.func @test_avgpool2d_stride_x(%arg0: tensor<1x32x8194x8xf32>, %arg1: tensor
// -----
+func.func @test_avgpool2d_adaptive_kernel_y(%arg0: tensor<1x8194x32x8xf32>, %arg1: tensor<1xf32>, %arg2: tensor<1xf32>) -> tensor<1x2x32x8xf32> {
+ %kernel = tosa.const_shape {values = dense<[8193, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 0, 0, 0]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ // expected-error at +1 {{'tosa.avg_pool2d_adaptive' op failed level check: kernel <= MAX_KERNEL (8192), got 8193}}
+ %0 = "tosa.avg_pool2d_adaptive"(%arg0, %arg1, %arg2, %kernel, %stride, %pad) {acc_type = f32} :
+ (tensor<1x8194x32x8xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x2x32x8xf32>
+ return %0 : tensor<1x2x32x8xf32>
+}
+
+// -----
+
+func.func @test_avgpool2d_adaptive_kernel_x(%arg0: tensor<1x32x8194x8xf32>, %arg1: tensor<1xf32>, %arg2: tensor<1xf32>) -> tensor<1x32x2x8xf32> {
+ %kernel = tosa.const_shape {values = dense<[1, 8193]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 0, 0, 0]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ // expected-error at +1 {{'tosa.avg_pool2d_adaptive' op failed level check: kernel <= MAX_KERNEL (8192), got 8193}}
+ %0 = "tosa.avg_pool2d_adaptive"(%arg0, %arg1, %arg2, %kernel, %stride, %pad) {acc_type = f32} :
+ (tensor<1x32x8194x8xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x32x2x8xf32>
+ return %0 : tensor<1x32x2x8xf32>
+}
+
+// -----
+
+func.func @test_avgpool2d_adaptive_stride_y(%arg0: tensor<1x8194x32x8xf32>, %arg1: tensor<1xf32>, %arg2: tensor<1xf32>) -> tensor<1x2x32x8xf32> {
+ %kernel = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[8193, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 0, 0, 0]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ // expected-error at +1 {{'tosa.avg_pool2d_adaptive' op failed level check: stride <= MAX_STRIDE (8192), got 8193}}
+ %0 = "tosa.avg_pool2d_adaptive"(%arg0, %arg1, %arg2, %kernel, %stride, %pad) {acc_type = f32} :
+ (tensor<1x8194x32x8xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x2x32x8xf32>
+ return %0 : tensor<1x2x32x8xf32>
+}
+
+// -----
+
+func.func @test_avgpool2d_adaptive_stride_x(%arg0: tensor<1x32x8194x8xf32>, %arg1: tensor<1xf32>, %arg2: tensor<1xf32>) -> tensor<1x32x2x8xf32> {
+ %kernel = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 8193]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 0, 0, 0]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ // expected-error at +1 {{'tosa.avg_pool2d_adaptive' op failed level check: stride <= MAX_STRIDE (8192), got 8193}}
+ %0 = "tosa.avg_pool2d_adaptive"(%arg0, %arg1, %arg2, %kernel, %stride, %pad) {acc_type = f32} :
+ (tensor<1x32x8194x8xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x32x2x8xf32>
+ return %0 : tensor<1x32x2x8xf32>
+}
+
+// -----
+
func.func @test_conv2d_dilation_y(%arg0: tensor<1x8192x8192x1xf32>, %arg1: tensor<16x1025x1024x1xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>) -> tensor<1x1x7170x16xf32> {
// expected-error at +1 {{'tosa.conv2d' op failed level check: dilation_y * KH <= MAX_KERNEL (8192), got 8200}}
%0 = tosa.conv2d %arg0, %arg1, %arg2, %arg3, %arg3 {acc_type = f32, dilation = array<i64: 8, 1>, pad = array<i64: 0, 1, 0, 1>, stride = array<i64: 1, 1>} :
@@ -1032,6 +1080,18 @@ func.func @test_avg_pool2d_tensor_size_invalid(%arg0: tensor<1x23178x23178x9xf32
// -----
+func.func @test_avg_pool2d_adaptive_tensor_size_invalid(%arg0: tensor<1x23178x23178x9xf32>, %arg1: tensor<1xf32>, %arg2: tensor<1xf32>) -> tensor<1x23178x23178x9xf32> {
+ %kernel = tosa.const_shape {values = dense<[2, 2]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 1, 0, 1]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ // expected-error at +1 {{'tosa.avg_pool2d_adaptive' op failed level check: operand tensor size (in bytes) <= (1 << MAX_LOG2_SIZE - 1)}}
+ %0 = "tosa.avg_pool2d_adaptive"(%arg0, %arg1, %arg2, %kernel, %stride, %pad) {acc_type = f32} :
+ (tensor<1x23178x23178x9xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x23178x23178x9xf32>
+ return %0 : tensor<1x23178x23178x9xf32>
+}
+
+// -----
+
func.func @test_conv2d_tensor_size_invalid(%arg0: tensor<1x23178x23178x4xf32>, %arg1: tensor<8x1x1x4xf32>, %arg2: tensor<8xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<1x23178x23178x8xf32> {
// expected-error at +1 {{'tosa.conv2d' op failed level check: operand tensor size (in bytes) <= (1 << MAX_LOG2_SIZE - 1)}}
%0 = tosa.conv2d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 1, 1>, pad = array<i64: 0, 0, 0, 0>, stride = array<i64: 1, 1>, local_bound = true} : (tensor<1x23178x23178x4xf32>, tensor<8x1x1x4xf32>, tensor<8xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<1x23178x23178x8xf32>
diff --git a/mlir/test/Dialect/Tosa/ops.mlir b/mlir/test/Dialect/Tosa/ops.mlir
index 1a5eed735294a..e80d3d84a8105 100644
--- a/mlir/test/Dialect/Tosa/ops.mlir
+++ b/mlir/test/Dialect/Tosa/ops.mlir
@@ -63,6 +63,78 @@ func.func @test_avg_pool2d_q8(%arg0: tensor<1x7x7x9x!quant.uniform<i8:f32, 0.01>
return %0 : tensor<1x7x7x9x!quant.uniform<i8:f32, 0.01>>
}
+// -----
+// CHECK-LABEL: avg_pool2d_adaptive_f32
+func.func @test_avg_pool2d_adaptive_f32(%arg0: tensor<1x7x7x9xf32>) -> tensor<1x7x7x9xf32> {
+ %input_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %output_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %kernel = tosa.const_shape {values = dense<[2, 2]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 1, 0, 1]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ %0 = tosa.avg_pool2d_adaptive %arg0, %input_zp, %output_zp, %kernel, %stride, %pad {acc_type = f32} : (tensor<1x7x7x9xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x7x7x9xf32>
+ return %0 : tensor<1x7x7x9xf32>
+}
+
+// -----
+// CHECK-LABEL: avg_pool2d_adaptive_f16
+func.func @test_avg_pool2d_adaptive_f16(%arg0: tensor<1x7x7x9xf16>) -> tensor<1x7x7x9xf16> {
+ %input_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf16>}> : () -> tensor<1xf16>
+ %output_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf16>}> : () -> tensor<1xf16>
+ %kernel = tosa.const_shape {values = dense<[2, 2]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 1, 0, 1]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ %0 = tosa.avg_pool2d_adaptive %arg0, %input_zp, %output_zp, %kernel, %stride, %pad {acc_type = f16} : (tensor<1x7x7x9xf16>, tensor<1xf16>, tensor<1xf16>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x7x7x9xf16>
+ return %0 : tensor<1x7x7x9xf16>
+}
+
+// -----
+// CHECK-LABEL: avg_pool2d_adaptive_f16_accumf32
+func.func @test_avg_pool2d_adaptive_f16_accumf32(%arg0: tensor<1x7x7x9xf16>) -> tensor<1x7x7x9xf16> {
+ %input_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf16>}> : () -> tensor<1xf16>
+ %output_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf16>}> : () -> tensor<1xf16>
+ %kernel = tosa.const_shape {values = dense<[2, 2]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 1, 0, 1]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ %0 = tosa.avg_pool2d_adaptive %arg0, %input_zp, %output_zp, %kernel, %stride, %pad {acc_type = f32} : (tensor<1x7x7x9xf16>, tensor<1xf16>, tensor<1xf16>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x7x7x9xf16>
+ return %0 : tensor<1x7x7x9xf16>
+}
+
+// -----
+// CHECK-LABEL: avg_pool2d_adaptive_i8
+func.func @test_avg_pool2d_adaptive_i8(%arg0: tensor<1x7x7x9xi8>) -> tensor<1x7x7x9xi8> {
+ %input_zp = "tosa.const"() <{values = dense<0> : tensor<1xi8>}> : () -> tensor<1xi8>
+ %output_zp = "tosa.const"() <{values = dense<0> : tensor<1xi8>}> : () -> tensor<1xi8>
+ %kernel = tosa.const_shape {values = dense<[2, 2]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 1, 0, 1]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ %0 = tosa.avg_pool2d_adaptive %arg0, %input_zp, %output_zp, %kernel, %stride, %pad {acc_type = i32} : (tensor<1x7x7x9xi8>, tensor<1xi8>, tensor<1xi8>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x7x7x9xi8>
+ return %0 : tensor<1x7x7x9xi8>
+}
+
+// -----
+// CHECK-LABEL: avg_pool2d_adaptive_i16
+func.func @test_avg_pool2d_adaptive_i16(%arg0: tensor<1x7x7x9xi16>) -> tensor<1x7x7x9xi16> {
+ %input_zp = "tosa.const"() <{values = dense<0> : tensor<1xi16>}> : () -> tensor<1xi16>
+ %output_zp = "tosa.const"() <{values = dense<0> : tensor<1xi16>}> : () -> tensor<1xi16>
+ %kernel = tosa.const_shape {values = dense<[2, 2]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 1, 0, 1]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ %0 = tosa.avg_pool2d_adaptive %arg0, %input_zp, %output_zp, %kernel, %stride, %pad {acc_type = i32} : (tensor<1x7x7x9xi16>, tensor<1xi16>, tensor<1xi16>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x7x7x9xi16>
+ return %0 : tensor<1x7x7x9xi16>
+}
+
+// -----
+// CHECK-LABEL: avg_pool2d_adaptive_q8
+func.func @test_avg_pool2d_adaptive_q8(%arg0: tensor<1x7x7x9x!quant.uniform<i8:f32, 0.01>>) -> tensor<1x7x7x9x!quant.uniform<i8:f32, 0.01>> {
+ %input_zp = "tosa.const"() <{values = dense<0> : tensor<1xi8>}> : () -> tensor<1xi8>
+ %output_zp = "tosa.const"() <{values = dense<0> : tensor<1xi8>}> : () -> tensor<1xi8>
+ %kernel = tosa.const_shape {values = dense<[2, 2]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 1, 0, 1]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ %0 = tosa.avg_pool2d_adaptive %arg0, %input_zp, %output_zp, %kernel, %stride, %pad {acc_type = i32} : (tensor<1x7x7x9x!quant.uniform<i8:f32, 0.01>>, tensor<1xi8>, tensor<1xi8>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x7x7x9x!quant.uniform<i8:f32, 0.01>>
+ return %0 : tensor<1x7x7x9x!quant.uniform<i8:f32, 0.01>>
+}
+
// -----
// CHECK-LABEL: conv2d
func.func @test_conv2d(%arg0: tensor<1x4x4x4xf32>, %arg1: tensor<8x1x1x4xf32>, %arg2: tensor<8xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<1x4x4x8xf32> {
diff --git a/mlir/test/Dialect/Tosa/profile_pro_fp_unsupported.mlir b/mlir/test/Dialect/Tosa/profile_pro_fp_unsupported.mlir
index 17095a309bb66..052271776770e 100644
--- a/mlir/test/Dialect/Tosa/profile_pro_fp_unsupported.mlir
+++ b/mlir/test/Dialect/Tosa/profile_pro_fp_unsupported.mlir
@@ -25,6 +25,17 @@ func.func @test_avg_pool2d(%arg0: tensor<1x7x7x9xf32>, %arg1: tensor<1xf32>, %ar
return %0 : tensor<1x7x7x9xf32>
}
+// -----
+func.func @test_avg_pool2d_adaptive(%arg0: tensor<1x7x7x9xf32>, %arg1: tensor<1xf32>, %arg2: tensor<1xf32>) -> tensor<1x7x7x9xf32> {
+ %kernel = tosa.const_shape {values = dense<[2, 2]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 1, 0, 1]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ // expected-error at +1 {{'tosa.avg_pool2d_adaptive' op illegal: requires any of [pro_fp] profiles/extensions to be specified in the target environment}}
+ %0 = tosa.avg_pool2d_adaptive %arg0, %arg1, %arg2, %kernel, %stride, %pad {acc_type = f32} :
+ (tensor<1x7x7x9xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x7x7x9xf32>
+ return %0 : tensor<1x7x7x9xf32>
+}
+
// -----
func.func @test_conv2d(%arg0: tensor<1x4x4x4xf32>, %arg1: tensor<8x1x1x4xf32>, %arg2: tensor<8xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<1x4x4x8xf32> {
// expected-error at +1 {{'tosa.conv2d' op illegal: requires any of [pro_fp] profiles/extensions to be specified in the target environment}}
diff --git a/mlir/test/Dialect/Tosa/profile_pro_int_unsupported.mlir b/mlir/test/Dialect/Tosa/profile_pro_int_unsupported.mlir
index f646be6d4a43b..c6239d1bba72b 100644
--- a/mlir/test/Dialect/Tosa/profile_pro_int_unsupported.mlir
+++ b/mlir/test/Dialect/Tosa/profile_pro_int_unsupported.mlir
@@ -2,7 +2,7 @@
// Check operations fail to validation when pro_int is not provided in the target.
//--------------------------------------------------------------------------------
-// RUN: mlir-opt %s -split-input-file -verify-diagnostics -tosa-attach-target="profiles=pro_fp" -tosa-validate="strict-op-spec-alignment"
+// RUN: mlir-opt %s -split-input-file -verify-diagnostics -tosa-attach-target="specification_version=1.1.draft profiles=pro_fp" -tosa-validate="strict-op-spec-alignment"
// -----
func.func @test_const_i1() -> tensor<3x11x11x3xi1> {
@@ -23,6 +23,17 @@ func.func @test_argmax(%arg0: tensor<14x19xi8>) -> tensor<14xi32> {
return %0 : tensor<14xi32>
}
+// -----
+func.func @test_avg_pool2d_adaptive_missing_pro_int(%arg0: tensor<1x7x7x9xi8>, %arg1: tensor<1xi8>, %arg2: tensor<1xi8>) -> tensor<1x7x7x9xi8> {
+ %kernel = tosa.const_shape {values = dense<[2, 2]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 1, 0, 1]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ // expected-error at +1 {{'tosa.avg_pool2d_adaptive' op illegal: requires any of [pro_int] profiles/extensions to be specified in the target environment}}
+ %0 = tosa.avg_pool2d_adaptive %arg0, %arg1, %arg2, %kernel, %stride, %pad {acc_type = i32} :
+ (tensor<1x7x7x9xi8>, tensor<1xi8>, tensor<1xi8>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x7x7x9xi8>
+ return %0 : tensor<1x7x7x9xi8>
+}
+
// -----
func.func @test_avg_pool2d(%arg0: tensor<1x7x7x9xi8>, %arg1: tensor<1xi8>, %arg2: tensor<1xi8>) -> tensor<1x7x7x9xi8> {
// expected-error at +1 {{'tosa.avg_pool2d' op illegal: requires any of [pro_int] profiles/extensions to be specified in the target environment}}
@@ -227,20 +238,6 @@ func.func @test_transpose(%arg0: tensor<13x21x3xi8>, %arg1: tensor<3xi32>) -> te
return %1 : tensor<3x13x21xi8>
}
-// -----
-func.func @test_gather(%arg0: tensor<13x21x3xi32>, %arg1: tensor<13x26xi32>) -> tensor<13x26x3xi32> {
- // expected-error at +1 {{'tosa.gather' op illegal: requires any of [pro_int] profiles/extensions OR requires specification version compatible with 1.1 (got 1.0) to be specified in the target environment}}
- %0 = tosa.gather %arg0, %arg1 : (tensor<13x21x3xi32>, tensor<13x26xi32>) -> tensor<13x26x3xi32>
- return %0 : tensor<13x26x3xi32>
-}
-
-// -----
-func.func @test_scatter(%arg0: tensor<13x27x3xi32>, %arg1: tensor<13x26xi32>, %arg2: tensor<13x26x3xi32>) -> tensor<13x27x3xi32> {
- // expected-error at +1 {{'tosa.scatter' op illegal: requires any of [pro_int] profiles/extensions OR requires specification version compatible with 1.1 (got 1.0) to be specified in the target environment}}
- %0 = tosa.scatter %arg0, %arg1, %arg2 : (tensor<13x27x3xi32>, tensor<13x26xi32>, tensor<13x26x3xi32>) -> tensor<13x27x3xi32>
- return %0 : tensor<13x27x3xi32>
-}
-
// -----
func.func @test_resize(%arg0: tensor<1x32x32x8xi8>) -> tensor<1x64x64x8xi32> {
%scale = tosa.const_shape { values = dense<[4, 2, 4, 2]> : tensor<4xindex> } : () -> !tosa.shape<4>
diff --git a/mlir/test/Dialect/Tosa/tosa-infer-shapes.mlir b/mlir/test/Dialect/Tosa/tosa-infer-shapes.mlir
index 8069877a0dfd2..408300fa7034b 100644
--- a/mlir/test/Dialect/Tosa/tosa-infer-shapes.mlir
+++ b/mlir/test/Dialect/Tosa/tosa-infer-shapes.mlir
@@ -815,6 +815,89 @@ func.func @test_pool_stride(%arg0: tensor<3x14x12x7xf32>) {
// -----
+// CHECK-LABEL: @test_avg_pool2d_adaptive_static
+func.func @test_avg_pool2d_adaptive_static(%arg0: tensor<3x5x6x7xf32>) {
+ %input_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %output_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %kernel = tosa.const_shape { values = dense<[4, 3]> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %stride = tosa.const_shape { values = dense<[1, 1]> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %pad = tosa.const_shape { values = dense<[0, 0, 0, 0]> : tensor<4xindex> } : () -> !tosa.shape<4>
+
+ // CHECK: -> tensor<3x2x4x7xf32>
+ %0 = tosa.avg_pool2d_adaptive %arg0, %input_zp, %output_zp, %kernel, %stride, %pad {acc_type = f32} : (tensor<3x5x6x7xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<?x?x?x?xf32>
+ return
+}
+
+// -----
+
+// CHECK-LABEL: @test_avg_pool2d_adaptive_dynamic_input
+func.func @test_avg_pool2d_adaptive_dynamic_input(%arg0: tensor<?x?x?x?xf32>) {
+ %input_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %output_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %kernel = tosa.const_shape { values = dense<[4, 3]> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %stride = tosa.const_shape { values = dense<[1, 1]> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %pad = tosa.const_shape { values = dense<[0, 0, 0, 0]> : tensor<4xindex> } : () -> !tosa.shape<4>
+
+ // CHECK: -> tensor<?x?x?x?xf32>
+ %0 = tosa.avg_pool2d_adaptive %arg0, %input_zp, %output_zp, %kernel, %stride, %pad {acc_type = f32} : (tensor<?x?x?x?xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<?x?x?x?xf32>
+ return
+}
+
+// -----
+
+// CHECK-LABEL: @test_avg_pool2d_adaptive_padded
+func.func @test_avg_pool2d_adaptive_padded(%arg0: tensor<3x5x6x7xf32>) {
+ %input_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %output_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %kernel = tosa.const_shape { values = dense<[4, 3]> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %stride = tosa.const_shape { values = dense<[1, 1]> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %pad = tosa.const_shape { values = dense<[3, 2, 1, 0]> : tensor<4xindex> } : () -> !tosa.shape<4>
+
+ // CHECK: -> tensor<3x7x5x7xf32>
+ %0 = tosa.avg_pool2d_adaptive %arg0, %input_zp, %output_zp, %kernel, %stride, %pad {acc_type = f32} : (tensor<3x5x6x7xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<?x?x?x?xf32>
+ return
+}
+
+// -----
+
+// CHECK-LABEL: @test_avg_pool2d_adaptive_stride
+func.func @test_avg_pool2d_adaptive_stride(%arg0: tensor<3x14x12x7xf32>) {
+ %input_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %output_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %kernel = tosa.const_shape { values = dense<[4, 3]> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %stride = tosa.const_shape { values = dense<[2, 3]> : tensor<2xindex> } : () -> !tosa.shape<2>
+ %pad = tosa.const_shape { values = dense<[0, 0, 0, 0]> : tensor<4xindex> } : () -> !tosa.shape<4>
+
+ // CHECK: -> tensor<3x6x4x7xf32>
+ %0 = tosa.avg_pool2d_adaptive %arg0, %input_zp, %output_zp, %kernel, %stride, %pad {acc_type = f32} : (tensor<3x14x12x7xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<?x?x?x?xf32>
+ return
+}
+
+// -----
+
+// CHECK-LABEL: @test_avg_pool2d_adaptive_non_constshape_operands
+func.func @test_avg_pool2d_adaptive_non_constshape_operands(%arg0: tensor<3x5x6x7xf32>) {
+ %input_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %output_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
+ %k0 = tosa.const_shape { values = dense<[4]> : tensor<1xindex> } : () -> !tosa.shape<1>
+ %k1 = tosa.const_shape { values = dense<[3]> : tensor<1xindex> } : () -> !tosa.shape<1>
+ %kernel = tosa.concat_shape %k0, %k1 : (!tosa.shape<1>, !tosa.shape<1>) -> !tosa.shape<2>
+ %s0 = tosa.const_shape { values = dense<[2]> : tensor<1xindex> } : () -> !tosa.shape<1>
+ %s1 = tosa.const_shape { values = dense<[3]> : tensor<1xindex> } : () -> !tosa.shape<1>
+ %stride = tosa.concat_shape %s0, %s1 : (!tosa.shape<1>, !tosa.shape<1>) -> !tosa.shape<2>
+ %p0 = tosa.const_shape { values = dense<[0]> : tensor<1xindex> } : () -> !tosa.shape<1>
+ %pad = tosa.concat_shape %p0, %p0, %p0, %p0 : (!tosa.shape<1>, !tosa.shape<1>, !tosa.shape<1>, !tosa.shape<1>) -> !tosa.shape<4>
+
+ // Use concat_shape to build resolvable shape operands that are not direct
+ // const_shape producers. This exercises the adaptive pooling fallback path
+ // where only N and C are inferred, while H and W remain dynamic.
+ // CHECK: -> tensor<3x?x?x7xf32>
+ %0 = tosa.avg_pool2d_adaptive %arg0, %input_zp, %output_zp, %kernel, %stride, %pad {acc_type = f32} : (tensor<3x5x6x7xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<?x?x?x?xf32>
+ return
+}
+
+// -----
+
// CHECK-LABEL: @conv2d_padded
func.func @conv2d_padded(%input: tensor<2x8x9x3xf32>, %weights: tensor<5x3x6x3xf32>, %bias: tensor<5xf32>, %input_zp: tensor<1xf32>, %weight_zp: tensor<1xf32>) -> () {
// CHECK: -> tensor<2x9x11x5xf32>
diff --git a/mlir/test/Dialect/Tosa/tosa-validation-version-1p0-invalid.mlir b/mlir/test/Dialect/Tosa/tosa-validation-version-1p0-invalid.mlir
index 7ad45f53135cf..889955ffeab00 100644
--- a/mlir/test/Dialect/Tosa/tosa-validation-version-1p0-invalid.mlir
+++ b/mlir/test/Dialect/Tosa/tosa-validation-version-1p0-invalid.mlir
@@ -131,3 +131,53 @@ func.func @test_dyanmic_dims(%arg0: tensor<?x8x16xi8>) -> tensor<?x16xi32> {
%0 = tosa.argmax %arg0 { axis = 1 : i32 } : (tensor<?x8x16xi8>) -> tensor<?x16xi32>
return %0 : tensor<?x16xi32>
}
+
+// -----
+
+func.func @test_matmul_t_block_scaled(%arg0: tensor<4x8x32xf8E4M3FN>, %arg1: tensor<4x8x1xf8E8M0FNU>, %arg2: tensor<4x16x32xf8E4M3FN>, %arg3: tensor<4x16x1xf8E8M0FNU>) -> tensor<4x8x16xf32> {
+ // expected-error at +1 {{'tosa.matmul_t_block_scaled' op illegal: requires specification version compatible with 1.1 (got 1.0) and requires any of [mxfp] profiles/extensions to be specified in the target environment}}
+ %0 = tosa.matmul_t_block_scaled %arg0, %arg1, %arg2, %arg3 {block_size = #tosa.block_size<BLOCK_SIZE_32>} : (tensor<4x8x32xf8E4M3FN>, tensor<4x8x1xf8E8M0FNU>, tensor<4x16x32xf8E4M3FN>, tensor<4x16x1xf8E8M0FNU>) -> tensor<4x8x16xf32>
+ return %0 : tensor<4x8x16xf32>
+}
+
+// -----
+
+func.func @test_argmax_int64(%arg0: tensor<1x13x13x5xf32>) -> tensor<1x13x13xi64> {
+ // expected-error at +1 {{'tosa.argmax' op illegal: requires specification version compatible with 1.1 (got 1.0) and requires any of [int64] profiles/extensions to be specified in the target environment}}
+ %0 = tosa.argmax %arg0 {axis = 3 : i32} : (tensor<1x13x13x5xf32>) -> tensor<1x13x13xi64>
+ return %0 : tensor<1x13x13xi64>
+}
+
+// -----
+func.func @test_const_fp6e3m2(%arg0 : index) -> tensor<4xf6E3M2FN> {
+ // expected-error at +1 {{'tosa.const' op illegal: requires specification version compatible with 1.1 (got 1.0) and requires any of [mxfp] profiles/extensions to be specified in the target environment}}
+ %0 = "tosa.const"() {values = dense<[0.0, 0.0, 0.0, 0.0]> : tensor<4xf6E3M2FN>} : () -> tensor<4xf6E3M2FN>
+ return %0 : tensor<4xf6E3M2FN>
+}
+
+// -----
+
+func.func @test_cast_from_block_scaled(%arg0: tensor<4x32xf8E5M2>, %arg1: tensor<4x1xf8E8M0FNU>) -> tensor<4x32xf32> {
+ // expected-error at +1 {{'tosa.cast_from_block_scaled' op illegal: requires specification version compatible with 1.1 (got 1.0) and requires any of [mxfp] profiles/extensions to be specified in the target environment}}
+ %0 = tosa.cast_from_block_scaled %arg0, %arg1 {block_size = #tosa.block_size<BLOCK_SIZE_32> : i32} : (tensor<4x32xf8E5M2>, tensor<4x1xf8E8M0FNU>) -> tensor<4x32xf32>
+ return %0 : tensor<4x32xf32>
+}
+
+// -----
+
+func.func @test_cast_to_block_scaled(%arg0: tensor<4x32xf32>) -> (tensor<4x32xf6E3M2FN>, tensor<4x1xf8E8M0FNU>) {
+ // expected-error at +1 {{'tosa.cast_to_block_scaled' op illegal: requires specification version compatible with 1.1 (got 1.0) and requires any of [mxfp] profiles/extensions to be specified in the target environment}}
+ %0:2 = tosa.cast_to_block_scaled %arg0 {block_size = #tosa.block_size<BLOCK_SIZE_32>} : (tensor<4x32xf32>) -> (tensor<4x32xf6E3M2FN>, tensor<4x1xf8E8M0FNU>)
+ return %0#0, %0#1 : tensor<4x32xf6E3M2FN>, tensor<4x1xf8E8M0FNU>
+}
+
+// -----
+
+func.func @test_conv2d_block_scaled(%arg0: tensor<*xf4E2M1FN>, %arg1: tensor<*xf8E8M0FNU>, %arg2: tensor<*xf4E2M1FN>, %arg3: tensor<*xf8E8M0FNU>, %arg4: tensor<*xf32>) -> tensor<*xf32> {
+ %0 = tosa.const_shape {values = dense<[0, 0, 0, 0]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ %1 = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %2 = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ // expected-error at +1 {{'tosa.conv2d_block_scaled' op illegal: requires specification version compatible with 1.1 (got 1.0) and requires any of [mxfp_conv] profiles/extensions to be specified in the target environment}}
+ %3 = tosa.conv2d_block_scaled %arg0, %arg1, %arg2, %arg3, %arg4, %0, %1, %2 {block_size = BLOCK_SIZE_32} : (tensor<*xf4E2M1FN>, tensor<*xf8E8M0FNU>, tensor<*xf4E2M1FN>, tensor<*xf8E8M0FNU>, tensor<*xf32>, !tosa.shape<4>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<*xf32>
+ return %3 : tensor<*xf32>
+}
\ No newline at end of file
diff --git a/mlir/test/Dialect/Tosa/tosa-validation-version-1p1-invalid.mlir b/mlir/test/Dialect/Tosa/tosa-validation-version-1p1-invalid.mlir
new file mode 100644
index 0000000000000..5ce54980c8d61
--- /dev/null
+++ b/mlir/test/Dialect/Tosa/tosa-validation-version-1p1-invalid.mlir
@@ -0,0 +1,27 @@
+// RUN: mlir-opt %s -split-input-file -verify-diagnostics -tosa-attach-target="specification_version=1.1.draft profiles=pro_fp" -tosa-validate="strict-op-spec-alignment"
+
+// -----
+
+func.func @test_avg_pool2d_adaptive_non_const_input_zp(%arg0: tensor<1x32x32x8xf32>, %input_zp: tensor<1xf32>) -> tensor<1x32x32x8xf32> {
+ %output_zp = "tosa.const"() {values = dense<0.0> : tensor<1xf32>} : () -> tensor<1xf32>
+ %kernel = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 0, 0, 0]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ // expected-error at +1 {{'tosa.avg_pool2d_adaptive' op expected compile time resolvable constant, but got variable value for operand #1}}
+ %0 = "tosa.avg_pool2d_adaptive"(%arg0, %input_zp, %output_zp, %kernel, %stride, %pad) {acc_type = f32} :
+ (tensor<1x32x32x8xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x32x32x8xf32>
+ return %0 : tensor<1x32x32x8xf32>
+}
+
+// -----
+
+func.func @test_avg_pool2d_adaptive_non_const_output_zp(%arg0: tensor<1x32x32x8xf32>, %output_zp: tensor<1xf32>) -> tensor<1x32x32x8xf32> {
+ %input_zp = "tosa.const"() {values = dense<0.0> : tensor<1xf32>} : () -> tensor<1xf32>
+ %kernel = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %stride = tosa.const_shape {values = dense<[1, 1]> : tensor<2xindex>} : () -> !tosa.shape<2>
+ %pad = tosa.const_shape {values = dense<[0, 0, 0, 0]> : tensor<4xindex>} : () -> !tosa.shape<4>
+ // expected-error at +1 {{'tosa.avg_pool2d_adaptive' op expected compile time resolvable constant, but got variable value for operand #2}}
+ %0 = "tosa.avg_pool2d_adaptive"(%arg0, %input_zp, %output_zp, %kernel, %stride, %pad) {acc_type = f32} :
+ (tensor<1x32x32x8xf32>, tensor<1xf32>, tensor<1xf32>, !tosa.shape<2>, !tosa.shape<2>, !tosa.shape<4>) -> tensor<1x32x32x8xf32>
+ return %0 : tensor<1x32x32x8xf32>
+}
More information about the Mlir-commits
mailing list