[Mlir-commits] [mlir] bc4ffe8 - [mlir][spirv] Improve verification for SPIR-V TOSA ops (#195624)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Wed May 6 06:31:28 PDT 2026
Author: Davide Grohmann
Date: 2026-05-06T15:31:23+02:00
New Revision: bc4ffe8ac06dc106d591e0ac2e0edea9d45f9dc1
URL: https://github.com/llvm/llvm-project/commit/bc4ffe8ac06dc106d591e0ac2e0edea9d45f9dc1
DIFF: https://github.com/llvm/llvm-project/commit/bc4ffe8ac06dc106d591e0ac2e0edea9d45f9dc1.diff
LOG: [mlir][spirv] Improve verification for SPIR-V TOSA ops (#195624)
Add shape and attribute verification for several SPIR-V TOSA ops:
reductions, FFT2D, RFFT2D, MatMul, Clamp, Concat, and Resize.
Add negative parser/verification tests for the new checks.
Signed-off-by: Davide Grohmann <davide.grohmann at arm.com>
Added:
Modified:
mlir/include/mlir/Dialect/SPIRV/IR/SPIRVTosaOps.td
mlir/include/mlir/Dialect/SPIRV/IR/SPIRVTosaTypes.td
mlir/lib/Dialect/SPIRV/IR/SPIRVTosaOps.cpp
mlir/test/Dialect/SPIRV/IR/tosa-ops-verification.mlir
Removed:
################################################################################
diff --git a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVTosaOps.td b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVTosaOps.td
index e6336bf011e9d..bc3e55f9dfb42 100644
--- a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVTosaOps.td
+++ b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVTosaOps.td
@@ -223,7 +223,8 @@ class SPIRV_TosaReductionOp<string mnemonic, int opcode, list<Trait> traits = []
SPIRV_TosaOpWithResult<mnemonic, opcode, !listconcat(traits, [
AllElementTypesMatch<["input", "output"]>,
AllRanksMatch<["input", "output"]>,
- AxisValueLessThanRankOf<"input">])> {
+ AxisValueLessThanRankOf<"input">,
+ ReductionOutputShapeMatchesInputAndAxis<"input", "output">])> {
let extraClassDeclaration = extraBaseClassDeclaration#[{
::mlir::spirv::TensorArmType getInputType() {
@@ -522,7 +523,10 @@ def SPIRV_TosaDepthwiseConv2DOp : SPIRV_TosaConvolutionOp<"DepthwiseConv2D", 4,
}
-def SPIRV_TosaFFT2DOp : SPIRV_TosaOpWithComplexResult<"FFT2D", 5, [Pure]> {
+def SPIRV_TosaFFT2DOp : SPIRV_TosaOpWithComplexResult<"FFT2D", 5, [Pure,
+ AllShapesMatch<["input_real", "input_imag"]>,
+ Struct2TensorArmShapesMatchInput<"input_real">,
+ TensorDimsArePowerOfTwo<"input_real", [1, 2]>]> {
let summary = "Performs FFT2D operation on the input.";
let description = [{
@@ -575,6 +579,7 @@ def SPIRV_TosaFFT2DOp : SPIRV_TosaOpWithComplexResult<"FFT2D", 5, [Pure]> {
def SPIRV_TosaMatMulOp : SPIRV_TosaOpWithResult<"MatMul", 6, [NoMemoryEffect,
+ MatMulShapesMatch<"A", "B", "output">,
TypeConstraintImplicationOn<"A", I8, "output", [I32]>,
TypeConstraintImplicationOn<"A", I16, "output", [I64]>,
TypeConstraintImplicationOn<"A", BF16, "output", [F32]>,
@@ -687,7 +692,9 @@ def SPIRV_TosaMaxPool2DOp : SPIRV_TosaOpWithResult<"MaxPool2D", 7, [Pure,
}
-def SPIRV_TosaRFFT2DOp : SPIRV_TosaOpWithComplexResult<"RFFT2D", 8, [Pure]> {
+def SPIRV_TosaRFFT2DOp : SPIRV_TosaOpWithComplexResult<"RFFT2D", 8, [Pure,
+ Struct2TensorArmRFFT2DShapesMatchInput<"input_real">,
+ TensorDimsArePowerOfTwo<"input_real", [1, 2]>]> {
let summary = "Performs RFFT2D operation on the input.";
let description = [{
@@ -794,7 +801,9 @@ def SPIRV_TosaTransposeConv2DOp : SPIRV_TosaConvolutionOp<"TransposeConv2D", 9,
def SPIRV_TosaClampOp : SPIRV_TosaOpWithResult<"Clamp", 10, [Pure,
AllTypesMatch<["input", "output"]>,
- AllElementTypesMatch<["input", "output", "min_val", "max_val"]>]> {
+ AllElementTypesMatch<["input", "output", "min_val", "max_val"]>,
+ ClampBoundsAreNotNaN<"min_val", "max_val">,
+ ClampMinValLessThanOrEqualToMaxVal<"min_val", "max_val">]> {
let summary = "Computes Clamp(min, max).";
let description = [{
@@ -2217,6 +2226,8 @@ def SPIRV_TosaConcatOp : SPIRV_TosaOpWithResult<"Concat", 54, [Pure,
return getInput1().getTypes();
}
}];
+
+ let hasVerifier = 1;
}
@@ -2633,7 +2644,8 @@ def SPIRV_TosaResizeOp : SPIRV_TosaOpWithResult<"Resize", 63, [Pure,
TypeConstraintImplicationOn<"input", F32, "output", [F32]>,
TypeConstraintImplicationOn<"input", BF16, "output", [BF16]>,
TypeConstraintImplicationOn<"input", I8, "output", [I8, I32]>,
- TypeConstraintImplicationOn<"input", I16, "output", [I16, I64]>]> {
+ TypeConstraintImplicationOn<"input", I16, "output", [I16, I64]>,
+ NHWCInputOutputShapeMatch<"input", "output">]> {
let summary = "Resize operation, supports various resize/upsample modes.";
let description = [{
diff --git a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVTosaTypes.td b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVTosaTypes.td
index bc981d8bf95cf..8497f4f0c4b46 100644
--- a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVTosaTypes.td
+++ b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVTosaTypes.td
@@ -186,39 +186,33 @@ PredOpTrait<output # " rank must be equal to max(1, rank(" # input # "))",
And<[CPred<HasRank<input>.result>, CPred<HasRank<input>.result>]>,
[CPred<"std::max(int64_t(1), " # Rank<input>.result # " - int64_t(1)) == " # Rank<output>.result>]>>;
-class AccTypeIn<list<string> allowedValues> :
- CPred<"llvm::is_contained({" # !interleave(!foreach(value, allowedValues, "::mlir::spirv::TosaExtAccType::" # value), ",") # "}, getAccType())">;
+class DimOfType<string type, int dim> :
+ StrFunc<type # ".getDimSize(" # dim # ")">;
-class TypeImpliesAccType<string input, Type type, list<string> allowedAccTypes>:
- PredOpTrait<"acc_type must be one in [" # !interleave(allowedAccTypes, ",") # "] when type has value " # type.summary,
- Implies<ElementTypeIsPred<input, type>, [AccTypeIn<allowedAccTypes>]>>;
-
-class MatchBroadcastableShapes<string input1, string input2, string output>:
- PredOpTrait<"the shape of " # input1 # " and " # input2 # " are compatible for broadcasting and the broadcast shape is equal to the " # output # " shape",
- Implies<And<[CPred<HasRank<input1>.result>, CPred<HasRank<input2>.result>, CPred<HasRank<output>.result>,
- CPred<Rank<input1>.result # " == " # Rank<input2>.result # " && " # Rank<input1>.result # " == " # Rank<output>.result>]>,
- [CPred<"llvm::all_of_zip(" # Shape<input1>.result # ", " # Shape<input2>.result # ", " # Shape<output>.result # ", " #
- "[](int64_t input1Dim, int64_t input2Dim, int64_t outputDim) { " #
- " bool dynamic = ShapedType::isDynamic(input1Dim) || ShapedType::isDynamic(input2Dim) || ShapedType::isDynamic(outputDim);"
- " bool broadcastableInputs = input1Dim == input2Dim || input1Dim == 1 || input2Dim == 1;" #
- " bool broacastDimMatchesOutputDim = std::max(input1Dim, input2Dim) == outputDim;"
- " return dynamic || (broadcastableInputs && broacastDimMatchesOutputDim);" #
- "})">]>
- >;
+class ShapedTypeOf<string input> :
+ StrFunc<"::llvm::cast<::mlir::ShapedType>($" # input # ".getType())">;
class DimOf<string input, int dim> :
- StrFunc<"::llvm::cast<::mlir::ShapedType>($" # input #
- ".getType()).getDimSize(" # dim # ")">;
+ DimOfType<ShapedTypeOf<input>.result, dim>;
class DimIsDynamic<string input, int dim> :
CPred<"::mlir::ShapedType::isDynamic(" # DimOf<input, dim>.result # ")">;
+class DimOfTypeIsDynamic<string type, int dim> :
+ CPred<"::mlir::ShapedType::isDynamic(" #
+ DimOfType<type, dim>.result # ")">;
+
class DimIsOne<string input, int dim> :
CPred<DimOf<input, dim>.result # " == 1">;
class DimsMatch<string lhs, int lhsDim, string rhs, int rhsDim> :
CPred<DimOf<lhs, lhsDim>.result # " == " # DimOf<rhs, rhsDim>.result>;
+class DimsOfTypeMatch<string lhsType, int lhsDim, string rhsType,
+ int rhsDim> :
+ CPred<DimOfType<lhsType, lhsDim>.result # " == " #
+ DimOfType<rhsType, rhsDim>.result>;
+
class ProductDimsMatch<string lhs, int lhsDim, string rhs, int rhsDim,
string output, int outputDim> :
CPred<DimOf<lhs, lhsDim>.result # " * " # DimOf<rhs, rhsDim>.result #
@@ -247,6 +241,65 @@ class ProductDimOrOneOrDynamicPred<string lhs, int lhsDim, string rhs,
DimIsOne<output, outputDim>
]>;
+class AttrIsFloat<string attr> :
+ CPred<"::llvm::isa<::mlir::FloatAttr>(get" #
+ snakeCaseToCamelCase<attr>.ret # "())">;
+
+class AttrIsInteger<string attr> :
+ CPred<"::llvm::isa<::mlir::IntegerAttr>(get" #
+ snakeCaseToCamelCase<attr>.ret # "())">;
+
+class IntegerAttrValue<string attr> :
+ StrFunc<"::llvm::cast<::mlir::IntegerAttr>(get" #
+ snakeCaseToCamelCase<attr>.ret # "()).getValue()">;
+
+class FloatAttrValue<string attr> :
+ StrFunc<"::llvm::cast<::mlir::FloatAttr>(get" #
+ snakeCaseToCamelCase<attr>.ret # "()).getValue()">;
+
+class FloatAttrIsNaN<string attr> :
+ And<[AttrIsFloat<attr>,
+ CPred<FloatAttrValue<attr>.result # ".isNaN()">]>;
+
+class ReductionDimMatchPred<string input, string output, int dim> :
+ Or<[
+ DimIsDynamic<input, dim>,
+ DimIsDynamic<output, dim>,
+ And<[CPred<"getAxis() == " # dim>, DimIsOne<output, dim>]>,
+ And<[CPred<"getAxis() != " # dim>, DimsMatch<input, dim, output, dim>]>
+ ]>;
+
+class ReductionOutputShapeMatchesInputAndAxis<string input, string output>:
+PredOpTrait<"shape of " # output # " must match the shape of " # input #
+ " with the dimension at axis replaced by 1",
+ And<!foreach(dim, [0, 1, 2, 3, 4, 5],
+ Implies<
+ And<[CPred<HasRank<input>.result>,
+ CPred<HasRank<output>.result>,
+ CPred<Rank<input>.result # " == " # Rank<output>.result>,
+ CPred<Rank<input>.result # " > " # dim>]>,
+ [ReductionDimMatchPred<input, output, dim>]>)>>;
+
+class AccTypeIn<list<string> allowedValues> :
+ CPred<"llvm::is_contained({" # !interleave(!foreach(value, allowedValues, "::mlir::spirv::TosaExtAccType::" # value), ",") # "}, getAccType())">;
+
+class TypeImpliesAccType<string input, Type type, list<string> allowedAccTypes>:
+ PredOpTrait<"acc_type must be one in [" # !interleave(allowedAccTypes, ",") # "] when type has value " # type.summary,
+ Implies<ElementTypeIsPred<input, type>, [AccTypeIn<allowedAccTypes>]>>;
+
+class MatchBroadcastableShapes<string input1, string input2, string output>:
+ PredOpTrait<"the shape of " # input1 # " and " # input2 # " are compatible for broadcasting and the broadcast shape is equal to the " # output # " shape",
+ Implies<And<[CPred<HasRank<input1>.result>, CPred<HasRank<input2>.result>, CPred<HasRank<output>.result>,
+ CPred<Rank<input1>.result # " == " # Rank<input2>.result # " && " # Rank<input1>.result # " == " # Rank<output>.result>]>,
+ [CPred<"llvm::all_of_zip(" # Shape<input1>.result # ", " # Shape<input2>.result # ", " # Shape<output>.result # ", " #
+ "[](int64_t input1Dim, int64_t input2Dim, int64_t outputDim) { " #
+ " bool dynamic = ShapedType::isDynamic(input1Dim) || ShapedType::isDynamic(input2Dim) || ShapedType::isDynamic(outputDim);"
+ " bool broadcastableInputs = input1Dim == input2Dim || input1Dim == 1 || input2Dim == 1;" #
+ " bool broacastDimMatchesOutputDim = std::max(input1Dim, input2Dim) == outputDim;"
+ " return dynamic || (broadcastableInputs && broacastDimMatchesOutputDim);" #
+ "})">]>
+ >;
+
class ValuesIndicesShapesMatch<string values, string indices, string tensor>:
PredOpTrait<"shapes of " # values # ", " # indices # ", and " # tensor #
" must satisfy [N,K,C], [N,W], [N,W,C]",
@@ -316,6 +369,85 @@ class Pool2DPadValuesLessThanKernel<string padAttr, string kernelAttr> :
ElementsAttrValueLessThan<padAttr, 3, kernelAttr, 1>]
>>;
+class MatMulShapesMatch<string lhs, string rhs, string output> : PredOpTrait<
+ "shapes of " # lhs # ", " # rhs # ", and " # output #
+ " must satisfy [N,H,C], [N,C,W], [N,H,W]",
+ And<[
+ SameDimsOrDynamicPred<lhs, 0, rhs, 0>,
+ SameDimsOrDynamicPred<lhs, 0, output, 0>,
+ SameDimsOrDynamicPred<lhs, 1, output, 1>,
+ SameDimsOrDynamicPred<lhs, 2, rhs, 1>,
+ SameDimsOrDynamicPred<rhs, 2, output, 2>
+ ]>>;
+
+class DimsOfTypeAllMatchOrDynamic<string lhsType, string rhsType,
+ string otherType, int dim> :
+ Or<[
+ DimOfTypeIsDynamic<lhsType, dim>,
+ DimOfTypeIsDynamic<rhsType, dim>,
+ DimOfTypeIsDynamic<otherType, dim>,
+ And<[DimsOfTypeMatch<lhsType, dim, rhsType, dim>,
+ DimsOfTypeMatch<lhsType, dim, otherType, dim>]>
+ ]>;
+
+class DimOfTypeMatchesHalfPlusOne<string inputType, int inputDim,
+ string outputType, int outputDim> :
+ Or<[
+ DimOfTypeIsDynamic<inputType, inputDim>,
+ DimOfTypeIsDynamic<outputType, outputDim>,
+ CPred<DimOfType<outputType, outputDim>.result # " == " #
+ DimOfType<inputType, inputDim>.result # " / 2 + 1">
+ ]>;
+
+class Struct2TensorArmShapesMatchInput<string input> : PredOpTrait<
+ "shapes of output_real and output_imag must match the shape of " # input,
+ And<!foreach(dim, [0, 1, 2],
+ DimsOfTypeAllMatchOrDynamic<
+ ShapedTypeOf<input>.result,
+ "getResultRealType()", "getResultImagType()", dim>)>>;
+
+class Struct2TensorArmRFFT2DShapesMatchInput<string input> : PredOpTrait<
+ "shapes of output_real and output_imag must satisfy [N,H,W/2 + 1] when " #
+ input # " has shape [N,H,W]",
+ And<[
+ DimsOfTypeAllMatchOrDynamic<ShapedTypeOf<input>.result,
+ "getResultRealType()", "getResultImagType()", 0>,
+ DimsOfTypeAllMatchOrDynamic<ShapedTypeOf<input>.result,
+ "getResultRealType()", "getResultImagType()", 1>,
+ DimOfTypeMatchesHalfPlusOne<ShapedTypeOf<input>.result,
+ 2, "getResultRealType()", 2>,
+ DimOfTypeMatchesHalfPlusOne<ShapedTypeOf<input>.result,
+ 2, "getResultImagType()", 2>
+ ]>>;
+
+class DimIsPowerOfTwo<string input, int dim> :
+ Or<[DimIsDynamic<input, dim>,
+ CPred<"llvm::isPowerOf2_64(static_cast<uint64_t>(" # DimOf<input, dim>.result # "))">]>;
+
+class TensorDimsArePowerOfTwo<string input, list<int> dims> : PredOpTrait<
+ "dimensions " # !interleave(dims, ", ") # " of " # input # " must be powers of two",
+ And<!foreach(dim, dims, DimIsPowerOfTwo<input, dim>)>>;
+
+class ClampBoundsAreNotNaN<string minVal, string maxVal>:
+ PredOpTrait<minVal # " and " # maxVal # " must not be NaN",
+ Neg<Or<[FloatAttrIsNaN<minVal>, FloatAttrIsNaN<maxVal>]>>>;
+
+class IntegerAttrLessThanOrEqual<string minVal, string maxVal> :
+ Implies<AttrIsInteger<minVal>,
+ [CPred<IntegerAttrValue<minVal>.result # ".sle(" #
+ IntegerAttrValue<maxVal>.result # ")">]>;
+
+class FloatAttrLessThanOrEqual<string minVal, string maxVal> :
+ Implies<AttrIsFloat<minVal>,
+ [CPred<FloatAttrValue<minVal>.result # ".compare(" #
+ FloatAttrValue<maxVal>.result #
+ ") != ::llvm::APFloat::cmpGreaterThan">]>;
+
+class ClampMinValLessThanOrEqualToMaxVal<string minVal, string maxVal>:
+ PredOpTrait<minVal # " must be <= " # maxVal,
+ And<[IntegerAttrLessThanOrEqual<minVal, maxVal>,
+ FloatAttrLessThanOrEqual<minVal, maxVal>]>>;
+
class TableSizeConstraint<string input, Type type, int size>:
PredOpTrait<"table must have size " # size # " if " # input # " has element type " # type.summary,
Implies<ElementTypeIsPred<input, type>, [CPred<"::llvm::cast<::mlir::ShapedType>(getTable().getType()).getShape()[0] == " # size>]>
diff --git a/mlir/lib/Dialect/SPIRV/IR/SPIRVTosaOps.cpp b/mlir/lib/Dialect/SPIRV/IR/SPIRVTosaOps.cpp
index 0a559202556d5..c927ef8c48d58 100644
--- a/mlir/lib/Dialect/SPIRV/IR/SPIRVTosaOps.cpp
+++ b/mlir/lib/Dialect/SPIRV/IR/SPIRVTosaOps.cpp
@@ -281,6 +281,50 @@ LogicalResult verifyTransposeConv2DOutputShape(Operation *op,
return success();
}
+LogicalResult verifyConcatOutputShape(Operation *op, TypeRange inputTypes,
+ TensorArmType outputType, int32_t axis) {
+ constexpr StringLiteral errorMessage =
+ "failed to verify that shape of output must match the concatenation of "
+ "input1 along axis";
+ if (!outputType.hasRank())
+ return success();
+
+ if (llvm::any_of(inputTypes, [](Type type) {
+ return !cast<TensorArmType>(type).hasRank();
+ }))
+ return success();
+
+ for (int64_t dim = 0, rank = outputType.getRank(); dim < rank; ++dim) {
+ int64_t outputDim = outputType.getDimSize(dim);
+ if (ShapedType::isDynamic(outputDim))
+ continue;
+
+ if (dim != axis) {
+ for (Type type : inputTypes) {
+ int64_t inputDim = cast<TensorArmType>(type).getDimSize(dim);
+ if (ShapedType::isStatic(inputDim) && inputDim != outputDim)
+ return op->emitOpError(errorMessage);
+ }
+ continue;
+ }
+
+ int64_t concatDim = 0;
+ for (Type type : inputTypes) {
+ int64_t inputDim = cast<TensorArmType>(type).getDimSize(dim);
+ if (ShapedType::isDynamic(inputDim)) {
+ concatDim = ShapedType::kDynamic;
+ break;
+ }
+ concatDim += inputDim;
+ }
+
+ if (ShapedType::isStatic(concatDim) && concatDim != outputDim)
+ return op->emitOpError(errorMessage);
+ }
+
+ return success();
+}
+
} // namespace
LogicalResult TosaAvgPool2DOp::verify() {
@@ -317,6 +361,11 @@ LogicalResult TosaTransposeConv2DOp::verify() {
getWeightType(), getResultType());
}
+LogicalResult TosaConcatOp::verify() {
+ return verifyConcatOutputShape(getOperation(), getInput1Types(),
+ getResultType(), getAxis());
+}
+
LogicalResult TosaSelectOp::verify() {
TensorArmType condType = getConditionType();
TensorArmType trueValType = getTrueValueType();
diff --git a/mlir/test/Dialect/SPIRV/IR/tosa-ops-verification.mlir b/mlir/test/Dialect/SPIRV/IR/tosa-ops-verification.mlir
index fa3edbb3760e6..ca15b69303361 100644
--- a/mlir/test/Dialect/SPIRV/IR/tosa-ops-verification.mlir
+++ b/mlir/test/Dialect/SPIRV/IR/tosa-ops-verification.mlir
@@ -615,6 +615,34 @@ spirv.ARM.Graph @depthwise_conv2d_input_output_height_width_mismatch(%arg0: !spi
spirv.ARM.GraphOutputs %7 : !spirv.arm.tensor<1x4x32761x4xi32>
}
+//===----------------------------------------------------------------------===//
+// spirv.TOSA.FFT2D
+//===----------------------------------------------------------------------===//
+
+spirv.ARM.Graph @fft2d_input_shapes_must_match(%arg0: !spirv.arm.tensor<1x32x32xf32>, %arg1: !spirv.arm.tensor<1x32x16xf32>) -> (!spirv.arm.tensor<1x32x32xf32>) {
+ // expected-error @+1 {{op failed to verify that all of {input_real, input_imag} have same shape}}
+ %0 = spirv.Tosa.FFT2D inverse = true, local_bound = false, %arg0, %arg1 : !spirv.arm.tensor<1x32x32xf32>, !spirv.arm.tensor<1x32x16xf32> -> !spirv.struct<(!spirv.arm.tensor<1x32x32xf32>, !spirv.arm.tensor<1x32x32xf32>)>
+ spirv.ARM.GraphOutputs %arg0 : !spirv.arm.tensor<1x32x32xf32>
+}
+
+spirv.ARM.Graph @fft2d_output_shapes_must_match_inputs(%arg0: !spirv.arm.tensor<1x32x32xf32>, %arg1: !spirv.arm.tensor<1x32x32xf32>) -> (!spirv.arm.tensor<1x32x32xf32>) {
+ // expected-error @+1 {{op failed to verify that shapes of output_real and output_imag must match the shape of input_real}}
+ %0 = spirv.Tosa.FFT2D inverse = true, local_bound = false, %arg0, %arg1 : !spirv.arm.tensor<1x32x32xf32>, !spirv.arm.tensor<1x32x32xf32> -> !spirv.struct<(!spirv.arm.tensor<1x16x32xf32>, !spirv.arm.tensor<1x32x32xf32>)>
+ spirv.ARM.GraphOutputs %arg0 : !spirv.arm.tensor<1x32x32xf32>
+}
+
+spirv.ARM.Graph @fft2d_height_and_width_must_be_powers_of_two(%arg0: !spirv.arm.tensor<1x30x32xf32>, %arg1: !spirv.arm.tensor<1x30x32xf32>) -> (!spirv.arm.tensor<1x30x32xf32>) {
+ // expected-error @+1 {{op failed to verify that dimensions 1, 2 of input_real must be powers of two}}
+ %0 = spirv.Tosa.FFT2D inverse = true, local_bound = false, %arg0, %arg1 : !spirv.arm.tensor<1x30x32xf32>, !spirv.arm.tensor<1x30x32xf32> -> !spirv.struct<(!spirv.arm.tensor<1x30x32xf32>, !spirv.arm.tensor<1x30x32xf32>)>
+ spirv.ARM.GraphOutputs %arg0 : !spirv.arm.tensor<1x30x32xf32>
+}
+
+spirv.ARM.Graph @fft2d_width_must_be_power_of_two(%arg0: !spirv.arm.tensor<1x32x30xf32>, %arg1: !spirv.arm.tensor<1x32x30xf32>) -> (!spirv.arm.tensor<1x32x30xf32>) {
+ // expected-error @+1 {{op failed to verify that dimensions 1, 2 of input_real must be powers of two}}
+ %0 = spirv.Tosa.FFT2D inverse = true, local_bound = false, %arg0, %arg1 : !spirv.arm.tensor<1x32x30xf32>, !spirv.arm.tensor<1x32x30xf32> -> !spirv.struct<(!spirv.arm.tensor<1x32x30xf32>, !spirv.arm.tensor<1x32x30xf32>)>
+ spirv.ARM.GraphOutputs %arg0 : !spirv.arm.tensor<1x32x30xf32>
+}
+
//===----------------------------------------------------------------------===//
// spirv.TOSA.MatMul
//===----------------------------------------------------------------------===//
@@ -679,6 +707,46 @@ spirv.ARM.Graph @matmul_mismatch_result_element_type_f8e5m2_input(%arg0: !spirv.
spirv.ARM.GraphOutputs %0 : !spirv.arm.tensor<1x4x4xf32>
}
+spirv.ARM.Graph @matmul_batch_dimensions_must_match(%arg0: !spirv.arm.tensor<2x4x3xi8>, %arg1: !spirv.arm.tensor<1x3x8xi8>, %arg2: !spirv.arm.tensor<1xi8>, %arg3: !spirv.arm.tensor<1xi8>) -> (!spirv.arm.tensor<2x4x8xi32>) {
+ // expected-error @+1 {{op failed to verify that shapes of A, B, and output must satisfy [N,H,C], [N,C,W], [N,H,W]}}
+ %0 = spirv.Tosa.MatMul %arg0, %arg1, %arg2, %arg3 : !spirv.arm.tensor<2x4x3xi8>, !spirv.arm.tensor<1x3x8xi8>, !spirv.arm.tensor<1xi8>, !spirv.arm.tensor<1xi8> -> !spirv.arm.tensor<2x4x8xi32>
+ spirv.ARM.GraphOutputs %0 : !spirv.arm.tensor<2x4x8xi32>
+}
+
+spirv.ARM.Graph @matmul_contraction_dimension_must_match(%arg0: !spirv.arm.tensor<1x4x3xi8>, %arg1: !spirv.arm.tensor<1x2x8xi8>, %arg2: !spirv.arm.tensor<1xi8>, %arg3: !spirv.arm.tensor<1xi8>) -> (!spirv.arm.tensor<1x4x8xi32>) {
+ // expected-error @+1 {{op failed to verify that shapes of A, B, and output must satisfy [N,H,C], [N,C,W], [N,H,W]}}
+ %0 = spirv.Tosa.MatMul %arg0, %arg1, %arg2, %arg3 : !spirv.arm.tensor<1x4x3xi8>, !spirv.arm.tensor<1x2x8xi8>, !spirv.arm.tensor<1xi8>, !spirv.arm.tensor<1xi8> -> !spirv.arm.tensor<1x4x8xi32>
+ spirv.ARM.GraphOutputs %0 : !spirv.arm.tensor<1x4x8xi32>
+}
+
+spirv.ARM.Graph @matmul_output_shape_must_match_inputs(%arg0: !spirv.arm.tensor<1x4x3xi8>, %arg1: !spirv.arm.tensor<1x3x8xi8>, %arg2: !spirv.arm.tensor<1xi8>, %arg3: !spirv.arm.tensor<1xi8>) -> (!spirv.arm.tensor<1x5x8xi32>) {
+ // expected-error @+1 {{op failed to verify that shapes of A, B, and output must satisfy [N,H,C], [N,C,W], [N,H,W]}}
+ %0 = spirv.Tosa.MatMul %arg0, %arg1, %arg2, %arg3 : !spirv.arm.tensor<1x4x3xi8>, !spirv.arm.tensor<1x3x8xi8>, !spirv.arm.tensor<1xi8>, !spirv.arm.tensor<1xi8> -> !spirv.arm.tensor<1x5x8xi32>
+ spirv.ARM.GraphOutputs %0 : !spirv.arm.tensor<1x5x8xi32>
+}
+
+//===----------------------------------------------------------------------===//
+// spirv.TOSA.RFFT2D
+//===----------------------------------------------------------------------===//
+
+spirv.ARM.Graph @rfft2d_output_shapes_must_match_input(%arg0: !spirv.arm.tensor<1x32x32xf32>) -> (!spirv.arm.tensor<1x32x32xf32>) {
+ // expected-error @+1 {{op failed to verify that shapes of output_real and output_imag must satisfy [N,H,W/2 + 1] when input_real has shape [N,H,W]}}
+ %0 = spirv.Tosa.RFFT2D local_bound = false, %arg0 : !spirv.arm.tensor<1x32x32xf32> -> !spirv.struct<(!spirv.arm.tensor<1x16x17xf32>, !spirv.arm.tensor<1x32x17xf32>)>
+ spirv.ARM.GraphOutputs %arg0 : !spirv.arm.tensor<1x32x32xf32>
+}
+
+spirv.ARM.Graph @rfft2d_height_and_width_must_be_powers_of_two(%arg0: !spirv.arm.tensor<1x30x32xf32>) -> (!spirv.arm.tensor<1x30x32xf32>) {
+ // expected-error @+1 {{op failed to verify that dimensions 1, 2 of input_real must be powers of two}}
+ %0 = spirv.Tosa.RFFT2D local_bound = false, %arg0 : !spirv.arm.tensor<1x30x32xf32> -> !spirv.struct<(!spirv.arm.tensor<1x30x17xf32>, !spirv.arm.tensor<1x30x17xf32>)>
+ spirv.ARM.GraphOutputs %arg0 : !spirv.arm.tensor<1x30x32xf32>
+}
+
+spirv.ARM.Graph @rfft2d_width_must_be_power_of_two(%arg0: !spirv.arm.tensor<1x32x30xf32>) -> (!spirv.arm.tensor<1x32x30xf32>) {
+ // expected-error @+1 {{op failed to verify that dimensions 1, 2 of input_real must be powers of two}}
+ %0 = spirv.Tosa.RFFT2D local_bound = false, %arg0 : !spirv.arm.tensor<1x32x30xf32> -> !spirv.struct<(!spirv.arm.tensor<1x32x16xf32>, !spirv.arm.tensor<1x32x16xf32>)>
+ spirv.ARM.GraphOutputs %arg0 : !spirv.arm.tensor<1x32x30xf32>
+}
+
//===----------------------------------------------------------------------===//
// spirv.TOSA.MaxPool2D
//===----------------------------------------------------------------------===//
@@ -901,6 +969,18 @@ spirv.ARM.Graph @clamp_max_val_
diff erent_element_type_wrt_input_output(%arg0: !s
spirv.ARM.GraphOutputs %3 : !spirv.arm.tensor<27x44x55xi8>
}
+spirv.ARM.Graph @clamp_min_val_must_be_less_than_or_equal_to_max_val(%arg0: !spirv.arm.tensor<27x44x55xi8>) -> (!spirv.arm.tensor<27x44x55xi8>) {
+ // expected-error @+1 {{op failed to verify that min_val must be <= max_val}}
+ %3 = spirv.Tosa.Clamp min_val = 7 : i8, max_val = 3 : i8, nan_mode = <Propagate>, %arg0 : !spirv.arm.tensor<27x44x55xi8> -> !spirv.arm.tensor<27x44x55xi8>
+ spirv.ARM.GraphOutputs %3 : !spirv.arm.tensor<27x44x55xi8>
+}
+
+spirv.ARM.Graph @clamp_min_val_and_max_val_must_not_be_nan(%arg0: !spirv.arm.tensor<18x5x17x6xf32>) -> (!spirv.arm.tensor<18x5x17x6xf32>) {
+ // expected-error @+1 {{op failed to verify that min_val and max_val must not be NaN}}
+ %3 = spirv.Tosa.Clamp min_val = 0x7FC00000 : f32, max_val = 2.38255944E+38 : f32, nan_mode = <Ignore>, %arg0 : !spirv.arm.tensor<18x5x17x6xf32> -> !spirv.arm.tensor<18x5x17x6xf32>
+ spirv.ARM.GraphOutputs %3 : !spirv.arm.tensor<18x5x17x6xf32>
+}
+
//===----------------------------------------------------------------------===//
// spirv.TOSA.Erf
//===----------------------------------------------------------------------===//
@@ -1939,6 +2019,12 @@ spirv.ARM.Graph @reduceall_axis_value_not_in_input_rank_range(%arg0: !spirv.arm.
spirv.ARM.GraphOutputs %0 : !spirv.arm.tensor<18x22x23x12xi1>
}
+spirv.ARM.Graph @reduceall_output_shape_must_match_input_and_axis(%arg0: !spirv.arm.tensor<18x22x23x12xi1>) -> (!spirv.arm.tensor<18x22x23x13xi1>) {
+ // expected-error @+1 {{op failed to verify that shape of output must match the shape of input with the dimension at axis replaced by 1}}
+ %0 = spirv.Tosa.ReduceAll axis = 2, %arg0 : !spirv.arm.tensor<18x22x23x12xi1> -> !spirv.arm.tensor<18x22x23x13xi1>
+ spirv.ARM.GraphOutputs %0 : !spirv.arm.tensor<18x22x23x13xi1>
+}
+
//===----------------------------------------------------------------------===//
// spirv.TOSA.ReduceAny
//===----------------------------------------------------------------------===//
@@ -1955,6 +2041,12 @@ spirv.ARM.Graph @reduceany_axis_value_not_in_input_rank_range(%arg0: !spirv.arm.
spirv.ARM.GraphOutputs %0 : !spirv.arm.tensor<25x13x30x8xi1>
}
+spirv.ARM.Graph @reduceany_output_shape_must_match_input_and_axis(%arg0: !spirv.arm.tensor<25x13x30x8xi1>) -> (!spirv.arm.tensor<25x13x2x8xi1>) {
+ // expected-error @+1 {{op failed to verify that shape of output must match the shape of input with the dimension at axis replaced by 1}}
+ %0 = spirv.Tosa.ReduceAny axis = 2, %arg0 : !spirv.arm.tensor<25x13x30x8xi1> -> !spirv.arm.tensor<25x13x2x8xi1>
+ spirv.ARM.GraphOutputs %0 : !spirv.arm.tensor<25x13x2x8xi1>
+}
+
//===----------------------------------------------------------------------===//
// spirv.TOSA.ReduceMax
//===----------------------------------------------------------------------===//
@@ -1977,6 +2069,12 @@ spirv.ARM.Graph @reducemax_axis_value_not_in_input_rank_range(%arg0: !spirv.arm.
spirv.ARM.GraphOutputs %0 : !spirv.arm.tensor<8x30x12x3xi8>
}
+spirv.ARM.Graph @reducemax_output_shape_must_match_input_and_axis(%arg0: !spirv.arm.tensor<8x30x12x3xi8>) -> (!spirv.arm.tensor<8x30x2x3xi8>) {
+ // expected-error @+1 {{op failed to verify that shape of output must match the shape of input with the dimension at axis replaced by 1}}
+ %0 = spirv.Tosa.ReduceMax axis = 2, nan_mode = <Propagate>, %arg0 : !spirv.arm.tensor<8x30x12x3xi8> -> !spirv.arm.tensor<8x30x2x3xi8>
+ spirv.ARM.GraphOutputs %0 : !spirv.arm.tensor<8x30x2x3xi8>
+}
+
//===----------------------------------------------------------------------===//
// spirv.TOSA.ReduceMin
//===----------------------------------------------------------------------===//
@@ -1999,6 +2097,12 @@ spirv.ARM.Graph @reducemin_axis_value_not_in_input_rank_range(%arg0: !spirv.arm.
spirv.ARM.GraphOutputs %0 : !spirv.arm.tensor<27x10x25x9xf16>
}
+spirv.ARM.Graph @reducemin_output_shape_must_match_input_and_axis(%arg0: !spirv.arm.tensor<27x10x25x9xf16>) -> (!spirv.arm.tensor<27x10x2x9xf16>) {
+ // expected-error @+1 {{op failed to verify that shape of output must match the shape of input with the dimension at axis replaced by 1}}
+ %0 = spirv.Tosa.ReduceMin axis = 2, nan_mode = <Propagate>, %arg0 : !spirv.arm.tensor<27x10x25x9xf16> -> !spirv.arm.tensor<27x10x2x9xf16>
+ spirv.ARM.GraphOutputs %0 : !spirv.arm.tensor<27x10x2x9xf16>
+}
+
//===----------------------------------------------------------------------===//
// spirv.TOSA.ReduceProduct
//===----------------------------------------------------------------------===//
@@ -2021,6 +2125,12 @@ spirv.ARM.Graph @reduceproduct_axis_value_not_in_input_rank_range(%arg0: !spirv.
spirv.ARM.GraphOutputs %0 : !spirv.arm.tensor<2x16x25xf16>
}
+spirv.ARM.Graph @reduceproduct_output_shape_must_match_input_and_axis(%arg0: !spirv.arm.tensor<2x16x25xf16>) -> (!spirv.arm.tensor<2x17x25xf16>) {
+ // expected-error @+1 {{op failed to verify that shape of output must match the shape of input with the dimension at axis replaced by 1}}
+ %0 = spirv.Tosa.ReduceProduct axis = 1, %arg0 : !spirv.arm.tensor<2x16x25xf16> -> !spirv.arm.tensor<2x17x25xf16>
+ spirv.ARM.GraphOutputs %0 : !spirv.arm.tensor<2x17x25xf16>
+}
+
//===----------------------------------------------------------------------===//
// spirv.TOSA.ReduceSum
//===----------------------------------------------------------------------===//
@@ -2043,6 +2153,12 @@ spirv.ARM.Graph @reducesum_axis_value_not_in_input_rank_range(%arg0: !spirv.arm.
spirv.ARM.GraphOutputs %0 : !spirv.arm.tensor<20x24x22xi32>
}
+spirv.ARM.Graph @reducesum_output_shape_must_match_input_and_axis(%arg0: !spirv.arm.tensor<20x24x22xi32>) -> (!spirv.arm.tensor<20x25x22xi32>) {
+ // expected-error @+1 {{op failed to verify that shape of output must match the shape of input with the dimension at axis replaced by 1}}
+ %0 = spirv.Tosa.ReduceSum axis = 1, %arg0 : !spirv.arm.tensor<20x24x22xi32> -> !spirv.arm.tensor<20x25x22xi32>
+ spirv.ARM.GraphOutputs %0 : !spirv.arm.tensor<20x25x22xi32>
+}
+
//===----------------------------------------------------------------------===//
// spirv.TOSA.Concat
//===----------------------------------------------------------------------===//
@@ -2071,6 +2187,18 @@ spirv.ARM.Graph @concat_axis_value_not_in_output_rank_range(%arg0: !spirv.arm.te
spirv.ARM.GraphOutputs %0 : !spirv.arm.tensor<4x12xi8>
}
+spirv.ARM.Graph @concat_non_axis_dimensions_must_match_output(%arg0: !spirv.arm.tensor<4x5xi8>, %arg1: !spirv.arm.tensor<3x7xi8>) -> (!spirv.arm.tensor<4x12xi8>) {
+ // expected-error @+1 {{op failed to verify that shape of output must match the concatenation of input1 along axis}}
+ %0 = spirv.Tosa.Concat axis = 1, %arg0, %arg1 : !spirv.arm.tensor<4x5xi8>, !spirv.arm.tensor<3x7xi8> -> !spirv.arm.tensor<4x12xi8>
+ spirv.ARM.GraphOutputs %0 : !spirv.arm.tensor<4x12xi8>
+}
+
+spirv.ARM.Graph @concat_axis_dimension_must_match_sum_of_inputs(%arg0: !spirv.arm.tensor<4x5xi8>, %arg1: !spirv.arm.tensor<4x7xi8>) -> (!spirv.arm.tensor<4x11xi8>) {
+ // expected-error @+1 {{op failed to verify that shape of output must match the concatenation of input1 along axis}}
+ %0 = spirv.Tosa.Concat axis = 1, %arg0, %arg1 : !spirv.arm.tensor<4x5xi8>, !spirv.arm.tensor<4x7xi8> -> !spirv.arm.tensor<4x11xi8>
+ spirv.ARM.GraphOutputs %0 : !spirv.arm.tensor<4x11xi8>
+}
+
//===----------------------------------------------------------------------===//
// spirv.TOSA.Pad
//===----------------------------------------------------------------------===//
@@ -2299,6 +2427,15 @@ spirv.ARM.Graph @resize_bf16_input_output_element_type_must_be_bf16(%arg0: !spir
spirv.ARM.GraphOutputs %4 : !spirv.arm.tensor<1x753x297x63xf32>
}
+spirv.ARM.Graph @resize_input_output_batch_or_channel_mismatch(%arg0: !spirv.arm.tensor<1x48x33x63xf32>) -> (!spirv.arm.tensor<2x753x297x62xf32>) {
+ %1 = spirv.Constant dense<[16, 1, 9, 1]> : !spirv.arm.tensor<4xi32>
+ %2 = spirv.Constant dense<0> : !spirv.arm.tensor<2xi32>
+ %3 = spirv.Constant dense<[0, 8]> : !spirv.arm.tensor<2xi32>
+ // expected-error @+1 {{op failed to verify that shapes of input and output must satisfy [N,*,*,C] and [N,*,*,C]}}
+ %4 = spirv.Tosa.Resize mode = <Bilinear>, %arg0, %1, %2, %3 : !spirv.arm.tensor<1x48x33x63xf32>, !spirv.arm.tensor<4xi32>, !spirv.arm.tensor<2xi32>, !spirv.arm.tensor<2xi32> -> !spirv.arm.tensor<2x753x297x62xf32>
+ spirv.ARM.GraphOutputs %4 : !spirv.arm.tensor<2x753x297x62xf32>
+}
+
//===----------------------------------------------------------------------===//
// spirv.TOSA.Cast
//===----------------------------------------------------------------------===//
More information about the Mlir-commits
mailing list