[Mlir-commits] [mlir] ed2b1d7 - [mlir][tosa] Add new block-scaled tensor type and support for MXFP CAST (#203583)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Mon Jul 6 05:56:41 PDT 2026
Author: Luke Hutton
Date: 2026-07-06T13:56:36+01:00
New Revision: ed2b1d7920365a59e2f6c01f732157f1144d0a00
URL: https://github.com/llvm/llvm-project/commit/ed2b1d7920365a59e2f6c01f732157f1144d0a00
DIFF: https://github.com/llvm/llvm-project/commit/ed2b1d7920365a59e2f6c01f732157f1144d0a00.diff
LOG: [mlir][tosa] Add new block-scaled tensor type and support for MXFP CAST (#203583)
This commit adds a new compound-block scaled tensor type and uses this
type to implement support for MXFP in the CAST operation, as per the
following specification changes:
https://github.com/arm/tosa-specification/pull/50,
https://github.com/arm/tosa-specification/pull/53.
The new block-scaled type is closely modelled after the `quant` dialect
type and supports the following parameters:
- block shape - The size and axis of each block. Support for specifying
constant scale values has not been added in this commit, but will be
added in a later one.
- scale type - The type of the scale value associated with each block.
- value type - The type of the data values in each block.
Example syntax for the new block-scaled type:
```
tensor<160x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E5M2>>
```
As a pre-requisite for supporting MXFP CAST, the commit also adds new
extensions intended to split the existing EXT-MXFP extension into
separate extensions for each block-scaled type. This allows for more
fine-grained control over which block-scaled types are supported by a
given target. See specification change
https://github.com/arm/tosa-specification/pull/26 for details.
Finally, support for casting to/from the new block-scaled type has been
added, aligning with the behaviour specified in the CAST operation
specification.
Added:
Modified:
mlir/include/mlir/Dialect/Tosa/IR/TosaComplianceData.h.inc
mlir/include/mlir/Dialect/Tosa/IR/TosaOpBase.td
mlir/include/mlir/Dialect/Tosa/IR/TosaOps.h
mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td
mlir/include/mlir/Dialect/Tosa/IR/TosaProfileCompliance.h
mlir/include/mlir/Dialect/Tosa/IR/TosaTypesBase.td
mlir/lib/Dialect/Tosa/IR/TargetEnv.cpp
mlir/lib/Dialect/Tosa/IR/TosaCanonicalizations.cpp
mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
mlir/lib/Dialect/Tosa/Transforms/TosaProfileCompliance.cpp
mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
mlir/test/Dialect/Tosa/availability.mlir
mlir/test/Dialect/Tosa/canonicalize.mlir
mlir/test/Dialect/Tosa/invalid.mlir
mlir/test/Dialect/Tosa/invalid_extension.mlir
mlir/test/Dialect/Tosa/ops.mlir
mlir/test/Dialect/Tosa/tosa-attach-target.mlir
mlir/test/Dialect/Tosa/tosa-validation-version-1p0-invalid.mlir
mlir/test/Dialect/Tosa/tosa-validation-version-1p1-valid.mlir
mlir/test/Dialect/Tosa/verifier.mlir
Removed:
################################################################################
diff --git a/mlir/include/mlir/Dialect/Tosa/IR/TosaComplianceData.h.inc b/mlir/include/mlir/Dialect/Tosa/IR/TosaComplianceData.h.inc
index 45d56416fdba0..ef644845ed937 100644
--- a/mlir/include/mlir/Dialect/Tosa/IR/TosaComplianceData.h.inc
+++ b/mlir/include/mlir/Dialect/Tosa/IR/TosaComplianceData.h.inc
@@ -1137,7 +1137,125 @@ extensionComplianceMap = {
{{{fp8e5m2T, fp16T}, SpecificationVersion::V_1_0},
{{fp8e5m2T, fp32T}, SpecificationVersion::V_1_0},
{{fp16T, fp8e5m2T}, SpecificationVersion::V_1_0},
- {{fp32T, fp8e5m2T}, SpecificationVersion::V_1_0}}}}},
+ {{fp32T, fp8e5m2T}, SpecificationVersion::V_1_0}}},
+ {{Extension::fp8e4m3, Extension::mx_common, Extension::mx_fp8e4m3},
+ {{{fp8e4m3T, bs32_fp8ue8m0_fp8e4m3T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_fp8e4m3T, fp8e4m3T},
+ SpecificationVersion::V_1_1_DRAFT}},
+ allOf},
+ {{Extension::fp8e4m3, Extension::mx_common, Extension::mx_fp8e5m2},
+ {{{fp8e4m3T, bs32_fp8ue8m0_fp8e5m2T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_fp8e5m2T, fp8e4m3T},
+ SpecificationVersion::V_1_1_DRAFT}},
+ allOf},
+ {{Extension::fp8e4m3, Extension::mx_common, Extension::mx_fp6e3m2},
+ {{{fp8e4m3T, bs32_fp8ue8m0_fp6e3m2T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_fp6e3m2T, fp8e4m3T},
+ SpecificationVersion::V_1_1_DRAFT}},
+ allOf},
+ {{Extension::fp8e4m3, Extension::mx_common, Extension::mx_fp6e2m3},
+ {{{fp8e4m3T, bs32_fp8ue8m0_fp6e2m3T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_fp6e2m3T, fp8e4m3T},
+ SpecificationVersion::V_1_1_DRAFT}},
+ allOf},
+ {{Extension::fp8e4m3, Extension::mx_common, Extension::mx_fp4e2m1},
+ {{{fp8e4m3T, bs32_fp8ue8m0_fp4e2m1T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_fp4e2m1T, fp8e4m3T},
+ SpecificationVersion::V_1_1_DRAFT}},
+ allOf},
+ {{Extension::fp8e4m3, Extension::mx_common, Extension::mx_int8},
+ {{{fp8e4m3T, bs32_fp8ue8m0_mxint8T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_mxint8T, fp8e4m3T}, SpecificationVersion::V_1_1_DRAFT}},
+ allOf},
+ {{Extension::fp8e5m2, Extension::mx_common, Extension::mx_fp8e4m3},
+ {{{fp8e5m2T, bs32_fp8ue8m0_fp8e4m3T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_fp8e4m3T, fp8e5m2T},
+ SpecificationVersion::V_1_1_DRAFT}},
+ allOf},
+ {{Extension::fp8e5m2, Extension::mx_common, Extension::mx_fp8e5m2},
+ {{{fp8e5m2T, bs32_fp8ue8m0_fp8e5m2T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_fp8e5m2T, fp8e5m2T},
+ SpecificationVersion::V_1_1_DRAFT}},
+ allOf},
+ {{Extension::fp8e5m2, Extension::mx_common, Extension::mx_fp6e3m2},
+ {{{fp8e5m2T, bs32_fp8ue8m0_fp6e3m2T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_fp6e3m2T, fp8e5m2T},
+ SpecificationVersion::V_1_1_DRAFT}},
+ allOf},
+ {{Extension::fp8e5m2, Extension::mx_common, Extension::mx_fp6e2m3},
+ {{{fp8e5m2T, bs32_fp8ue8m0_fp6e2m3T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_fp6e2m3T, fp8e5m2T},
+ SpecificationVersion::V_1_1_DRAFT}},
+ allOf},
+ {{Extension::fp8e5m2, Extension::mx_common, Extension::mx_fp4e2m1},
+ {{{fp8e5m2T, bs32_fp8ue8m0_fp4e2m1T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_fp4e2m1T, fp8e5m2T},
+ SpecificationVersion::V_1_1_DRAFT}},
+ allOf},
+ {{Extension::fp8e5m2, Extension::mx_common, Extension::mx_int8},
+ {{{fp8e5m2T, bs32_fp8ue8m0_mxint8T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_mxint8T, fp8e5m2T}, SpecificationVersion::V_1_1_DRAFT}},
+ allOf},
+ {{Extension::mx_common, Extension::mx_fp8e4m3},
+ {{{fp16T, bs32_fp8ue8m0_fp8e4m3T}, SpecificationVersion::V_1_1_DRAFT},
+ {{fp32T, bs32_fp8ue8m0_fp8e4m3T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_fp8e4m3T, fp16T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_fp8e4m3T, fp32T}, SpecificationVersion::V_1_1_DRAFT}},
+ allOf},
+ {{Extension::mx_common, Extension::mx_fp8e5m2},
+ {{{fp16T, bs32_fp8ue8m0_fp8e5m2T}, SpecificationVersion::V_1_1_DRAFT},
+ {{fp32T, bs32_fp8ue8m0_fp8e5m2T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_fp8e5m2T, fp16T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_fp8e5m2T, fp32T}, SpecificationVersion::V_1_1_DRAFT}},
+ allOf},
+ {{Extension::mx_common, Extension::mx_fp6e3m2},
+ {{{fp16T, bs32_fp8ue8m0_fp6e3m2T}, SpecificationVersion::V_1_1_DRAFT},
+ {{fp32T, bs32_fp8ue8m0_fp6e3m2T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_fp6e3m2T, fp16T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_fp6e3m2T, fp32T}, SpecificationVersion::V_1_1_DRAFT}},
+ allOf},
+ {{Extension::mx_common, Extension::mx_fp6e2m3},
+ {{{fp16T, bs32_fp8ue8m0_fp6e2m3T}, SpecificationVersion::V_1_1_DRAFT},
+ {{fp32T, bs32_fp8ue8m0_fp6e2m3T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_fp6e2m3T, fp16T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_fp6e2m3T, fp32T}, SpecificationVersion::V_1_1_DRAFT}},
+ allOf},
+ {{Extension::mx_common, Extension::mx_fp4e2m1},
+ {{{fp16T, bs32_fp8ue8m0_fp4e2m1T}, SpecificationVersion::V_1_1_DRAFT},
+ {{fp32T, bs32_fp8ue8m0_fp4e2m1T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_fp4e2m1T, fp16T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_fp4e2m1T, fp32T}, SpecificationVersion::V_1_1_DRAFT}},
+ allOf},
+ {{Extension::mx_common, Extension::mx_int8},
+ {{{fp16T, bs32_fp8ue8m0_mxint8T}, SpecificationVersion::V_1_1_DRAFT},
+ {{fp32T, bs32_fp8ue8m0_mxint8T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_mxint8T, fp16T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_mxint8T, fp32T}, SpecificationVersion::V_1_1_DRAFT}},
+ allOf},
+ {{Extension::bf16, Extension::mx_common, Extension::mx_fp8e4m3},
+ {{{bf16T, bs32_fp8ue8m0_fp8e4m3T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_fp8e4m3T, bf16T}, SpecificationVersion::V_1_1_DRAFT}},
+ allOf},
+ {{Extension::bf16, Extension::mx_common, Extension::mx_fp8e5m2},
+ {{{bf16T, bs32_fp8ue8m0_fp8e5m2T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_fp8e5m2T, bf16T}, SpecificationVersion::V_1_1_DRAFT}},
+ allOf},
+ {{Extension::bf16, Extension::mx_common, Extension::mx_fp6e3m2},
+ {{{bf16T, bs32_fp8ue8m0_fp6e3m2T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_fp6e3m2T, bf16T}, SpecificationVersion::V_1_1_DRAFT}},
+ allOf},
+ {{Extension::bf16, Extension::mx_common, Extension::mx_fp6e2m3},
+ {{{bf16T, bs32_fp8ue8m0_fp6e2m3T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_fp6e2m3T, bf16T}, SpecificationVersion::V_1_1_DRAFT}},
+ allOf},
+ {{Extension::bf16, Extension::mx_common, Extension::mx_fp4e2m1},
+ {{{bf16T, bs32_fp8ue8m0_fp4e2m1T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_fp4e2m1T, bf16T}, SpecificationVersion::V_1_1_DRAFT}},
+ allOf},
+ {{Extension::bf16, Extension::mx_common, Extension::mx_int8},
+ {{{bf16T, bs32_fp8ue8m0_mxint8T}, SpecificationVersion::V_1_1_DRAFT},
+ {{bs32_fp8ue8m0_mxint8T, bf16T}, SpecificationVersion::V_1_1_DRAFT}},
+ allOf}}},
{"tosa.cast_from_block_scaled",
{{{Extension::bf16, Extension::mxfp},
{{{fp4e2m1T, fp8ue8m0T, bf16T}, SpecificationVersion::V_1_1_DRAFT},
diff --git a/mlir/include/mlir/Dialect/Tosa/IR/TosaOpBase.td b/mlir/include/mlir/Dialect/Tosa/IR/TosaOpBase.td
index 3c7d870a44879..d527bde997a7d 100644
--- a/mlir/include/mlir/Dialect/Tosa/IR/TosaOpBase.td
+++ b/mlir/include/mlir/Dialect/Tosa/IR/TosaOpBase.td
@@ -257,9 +257,16 @@ class Tosa_I32EnumAttr<string name, string description, string mnemonic,
// DOUBLEROUND : Adds double rounding support to the RESCALE operator.
// INEXACTROUND : Adds inexact rounding support to the RESCALE operator.
// DYNAMIC : Removes all Compile Time Constant state for CTC inputs.
-// MXFP : Microscaling formats.
-// MXFP_CONV : Microscaling format convolution.
+// MXFP : Microscaling formats. (Deprecated, this extension will be removed in the future.)
+// MXFP_CONV : Microscaling format convolution. (Deprecated, this extension will be removed in the future.)
// SHAPE : Shape calcuation operators.
+// MX_COMMON : Base for MXFP microscaling formats.
+// MX_FP4E2M1 : Microscaling format FP4E2M1.
+// MX_FP6E2M3 : Microscaling format FP6E2M3.
+// MX_FP6E3M2 : Microscaling format FP6E3M2.
+// MX_FP8E4M3 : Microscaling format FP8E4M3.
+// MX_FP8E5M2 : Microscaling format FP8E5M2.
+// MX_INT8 : Microscaling format INT8.
//===----------------------------------------------------------------------===//
def Tosa_NONE : I32EnumAttrCase<"none", 0>;
@@ -295,23 +302,35 @@ def Tosa_EXT_MXFP : I32EnumAttrCase<"mxfp", 12>;
def Tosa_EXT_INT64 : I32EnumAttrCase<"int64", 13>;
def Tosa_EXT_MXFP_CONV : I32EnumAttrCase<"mxfp_conv", 14>;
def Tosa_EXT_SHAPE : I32EnumAttrCase<"shape", 15>;
+def Tosa_EXT_MX_COMMON : I32EnumAttrCase<"mx_common", 16>;
+def Tosa_EXT_MX_FP4E2M1 : I32EnumAttrCase<"mx_fp4e2m1", 17>;
+def Tosa_EXT_MX_FP6E2M3 : I32EnumAttrCase<"mx_fp6e2m3", 18>;
+def Tosa_EXT_MX_FP6E3M2 : I32EnumAttrCase<"mx_fp6e3m2", 19>;
+def Tosa_EXT_MX_FP8E4M3 : I32EnumAttrCase<"mx_fp8e4m3", 20>;
+def Tosa_EXT_MX_FP8E5M2 : I32EnumAttrCase<"mx_fp8e5m2", 21>;
+def Tosa_EXT_MX_INT8 : I32EnumAttrCase<"mx_int8", 22>;
def Tosa_ExtensionAttr
- : Tosa_I32EnumAttr<"Extension", "supported TOSA extensions", "ext", [
- Tosa_EXT_NONE, Tosa_EXT_INT16, Tosa_EXT_INT4, Tosa_EXT_BF16,
- Tosa_EXT_FP8E4M3, Tosa_EXT_FP8E5M2, Tosa_EXT_FFT, Tosa_EXT_VARIABLE,
- Tosa_EXT_CONTROLFLOW, Tosa_EXT_DOUBLEROUND, Tosa_EXT_INEXACTROUND,
- Tosa_EXT_DYNAMIC, Tosa_EXT_MXFP, Tosa_EXT_INT64, Tosa_EXT_MXFP_CONV,
- Tosa_EXT_SHAPE,
- ]> {
+ : Tosa_I32EnumAttr<
+ "Extension", "supported TOSA extensions", "ext",
+ [Tosa_EXT_NONE, Tosa_EXT_INT16, Tosa_EXT_INT4, Tosa_EXT_BF16,
+ Tosa_EXT_FP8E4M3, Tosa_EXT_FP8E5M2, Tosa_EXT_FFT, Tosa_EXT_VARIABLE,
+ Tosa_EXT_CONTROLFLOW, Tosa_EXT_DOUBLEROUND, Tosa_EXT_INEXACTROUND,
+ Tosa_EXT_DYNAMIC, Tosa_EXT_MXFP, Tosa_EXT_INT64, Tosa_EXT_MXFP_CONV,
+ Tosa_EXT_SHAPE, Tosa_EXT_MX_COMMON, Tosa_EXT_MX_FP4E2M1,
+ Tosa_EXT_MX_FP6E2M3, Tosa_EXT_MX_FP6E3M2, Tosa_EXT_MX_FP8E4M3,
+ Tosa_EXT_MX_FP8E5M2, Tosa_EXT_MX_INT8]> {
let extraClassDeclaration = [{
- static llvm::SmallVector<Extension, 14> getAllValues() {
+ static llvm::SmallVector<Extension, 22> getAllValues() {
return {
Extension::int16, Extension::int4, Extension::bf16,
Extension::fp8e4m3, Extension::fp8e5m2, Extension::fft,
Extension::variable, Extension::controlflow, Extension::doubleround,
Extension::inexactround, Extension::dynamic, Extension::mxfp,
- Extension::int64, Extension::mxfp_conv, Extension::shape
+ Extension::int64, Extension::mxfp_conv, Extension::shape,
+ Extension::mx_common, Extension::mx_fp4e2m1, Extension::mx_fp6e2m3,
+ Extension::mx_fp6e3m2, Extension::mx_fp8e4m3, Extension::mx_fp8e5m2,
+ Extension::mx_int8
};
}
}];
@@ -490,6 +509,7 @@ def Tosa_RoundingModeAttr
: Tosa_I32EnumAttr<"RoundingMode", "Supported rounding modes", "rounding_mode",
[Tosa_ROUNDING_SINGLE_ROUND, Tosa_ROUNDING_INEXACT_ROUND, Tosa_ROUNDING_DOUBLE_ROUND]>;
+// Block_size attr is deprecated and will be removed in the future
def Tosa_BLOCK_SIZE_1 : I32EnumAttrCase<"BLOCK_SIZE_1", 1>;
def Tosa_BLOCK_SIZE_32 : I32EnumAttrCase<"BLOCK_SIZE_32", 32>;
@@ -503,6 +523,29 @@ def Tosa_BlockSizeAttr
}];
}
+def Tosa_BLOCK_SHAPE_32 : I32EnumAttrCase<"BLOCK_SHAPE_32", 32>;
+
+def Tosa_BlockShape
+ : Tosa_I32Enum<
+ "BlockShape",
+ "Block shape for the block_scaled formats."
+ "The names follow the convention of BLOCK_SHAPE_M where M "
+ "is the block size of the innermost dimension. Similarly, "
+ "BLOCK_SHAPE_MxN indicates block size of N in the innermost "
+ "dimension and block size of M in the next innermost dimension. "
+ "As of now, only 1 dimension (innermost) is supported for "
+ "block-scaling.",
+ [Tosa_BLOCK_SHAPE_32]>;
+
+def Tosa_BlockShapeAttr
+ : EnumAttr<Tosa_Dialect, Tosa_BlockShape, "block_shape"> {
+ let extraClassDeclaration = [{
+ static uint32_t getBlockShapeValue(BlockShape blockShape) {
+ return static_cast<uint32_t>(blockShape);
+ }
+ }];
+}
+
//===----------------------------------------------------------------------===//
// TOSA Interfaces.
//===----------------------------------------------------------------------===//
diff --git a/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.h b/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.h
index 2d96fb6891139..66c3753899124 100644
--- a/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.h
+++ b/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.h
@@ -92,6 +92,8 @@ class TosaShapeOperatorWithSameRanks
}
};
+LogicalResult verifyBlockScaledTensorType(Operation &op, mlir::Type type);
+
} // namespace tosa
} // namespace OpTrait
diff --git a/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td b/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td
index 8b065a4794c43..3518a62800963 100644
--- a/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td
+++ b/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td
@@ -2764,57 +2764,6 @@ def Tosa_CastOp: Tosa_Op<"cast", [Pure, SameOperandsAndResultShape,
let description = [{
Casts a tensor from one data type to another.
- * This table is showing the supported conversions from the TOSA Specification.
- * The MLIR dialect here can be used to represent other conversions.
-
- | Mode | Input | Output |
- |--------------------------|---------|---------|
- | fp16 to fp32 | float16 | float32 |
- | fp16 to int 16 | float16 | int16 |
- | fp16 to int 32 | float16 | int32 |
- | fp16 to int 8 | float16 | int8 |
- | fp32 to fp16 | float32 | float16 |
- | fp32 to int 16 | float32 | int16 |
- | fp32 to int 32 | float32 | int32 |
- | fp32 to int 8 | float32 | int8 |
- | int 16 to fp16 | int16 | float16 |
- | int 16 to fp32 | int16 | float32 |
- | int 32 to fp16 | int32 | float16 |
- | int 32 to fp32 | int32 | float32 |
- | int 8 to fp16 | int8 | float16 |
- | int 8 to fp32 | int8 | float32 |
- | bool to int 16 | Boolean | int16 |
- | bool to int 32 | Boolean | int32 |
- | bool to int 8 | Boolean | int8 |
- | int 16 to bool | int16 | Boolean |
- | int 16 to int 32 | int16 | int32 |
- | int 16 to int 8 | int16 | int8 |
- | int 32 to bool | int32 | Boolean |
- | int 32 to int 16 | int32 | int16 |
- | int 32 to int 8 | int32 | int8 |
- | int 8 to bool | int8 | Boolean |
- | int 8 to int 16 | int8 | int16 |
- | int 8 to int 32 | int8 | int32 |
- | bf16 to fp32 | bf16 | float32 |
- | bf16 to int 16 | bf16 | int16 |
- | bf16 to int 32 | bf16 | int32 |
- | bf16 to int 8 | bf16 | int8 |
- | fp32 to bf16 | float32 | bf16 |
- | int 16 to bf16 | int16 | bf16 |
- | int 32 to bf16 | int32 | bf16 |
- | int 8 to bf16 | int8 | bf16 |
- | bf16 to fp8e4m3 | bf16 | fp8e4m3 |
- | fp8e4m3 to bf16 | fp8e4m3 | bf16 |
- | bf16 to fp8e5m2 | bf16 | fp8e5m2 |
- | fp8e5m2 to bf16 | fp8e5m2 | bf16 |
- | fp16 to fp8e4m3 | float16 | fp8e4m3 |
- | fp32 to fp8e4m3 | float32 | fp8e4m3 |
- | fp8e4m3 to fp16 | fp8e4m3 | float16 |
- | fp8e4m3 to fp32 | fp8e4m3 | float32 |
- | fp16 to fp8e5m2 | float16 | fp8e5m2 |
- | fp32 to fp8e5m2 | float32 | fp8e5m2 |
- | fp8e5m2 to fp16 | fp8e5m2 | float16 |
- | fp8e5m2 to fp32 | fp8e5m2 | float32 |
}];
let arguments = (ins
@@ -2825,19 +2774,25 @@ def Tosa_CastOp: Tosa_Op<"cast", [Pure, SameOperandsAndResultShape,
Tosa_Tensor:$output
);
- list<Availability> availability = [
- Profile<[Tosa_PRO_INT, Tosa_PRO_FP]>,
- Extension<[Tosa_EXT_FP8E4M3, Tosa_EXT_FP8E5M2, Tosa_EXT_BF16, Tosa_EXT_INT64]>,
+ list<Availability> availability =
+ [Profile<[Tosa_PRO_INT, Tosa_PRO_FP]>,
+ Extension<[Tosa_EXT_FP8E4M3, Tosa_EXT_FP8E5M2, Tosa_EXT_BF16,
+ Tosa_EXT_INT64, Tosa_EXT_MX_COMMON, Tosa_EXT_MX_FP4E2M1,
+ Tosa_EXT_MX_FP6E2M3, Tosa_EXT_MX_FP6E3M2, Tosa_EXT_MX_FP8E4M3,
+ Tosa_EXT_MX_FP8E5M2, Tosa_EXT_MX_INT8]>,
];
let assemblyFormat = "operands attr-dict `:` functional-type(operands, results)";
let hasFolder = 1;
let hasCanonicalizer = 1;
+ let hasVerifier = 1;
}
//===----------------------------------------------------------------------===//
// Operator: cast_from_block_scaled
+//
+// Note: This operation is deprecated. It will be removed in the future.
//===----------------------------------------------------------------------===//
def Tosa_CastFromBlockScaledOp: Tosa_InferShapedTypeOp<"cast_from_block_scaled", [Pure]> {
let summary = "Apply scales from a scale tensor to the values in a value tensor";
@@ -2846,6 +2801,8 @@ def Tosa_CastFromBlockScaledOp: Tosa_InferShapedTypeOp<"cast_from_block_scaled",
Apply the scales from a scale tensor to the values in a value tensor, casting
the result to the output type. The block dimension must be the last dimension
of the tensor.
+
+ Note: This operation is deprecated. It will be removed in the future.
}];
let arguments = (ins
@@ -2869,6 +2826,8 @@ def Tosa_CastFromBlockScaledOp: Tosa_InferShapedTypeOp<"cast_from_block_scaled",
//===----------------------------------------------------------------------===//
// Operator: cast_to_block_scaled
+//
+// Note: This operation is deprecated. It will be removed in the future.
//===----------------------------------------------------------------------===//
def Tosa_CastToBlockScaledOp : Tosa_InferShapedTypeOp<"cast_to_block_scaled", [Pure]> {
let summary = "Calculate scale tensor values per block, output to separate scale and data tensors.";
@@ -2878,6 +2837,8 @@ def Tosa_CastToBlockScaledOp : Tosa_InferShapedTypeOp<"cast_to_block_scaled", [P
scaled data values from an input tensor. The output tensors are cast to the
specified scale and value types. The block dimension will be the last dimension
of the tensor.
+
+ Note: This operation is deprecated. It will be removed in the future.
}];
let arguments = (ins
diff --git a/mlir/include/mlir/Dialect/Tosa/IR/TosaProfileCompliance.h b/mlir/include/mlir/Dialect/Tosa/IR/TosaProfileCompliance.h
index 0135a651be481..34ccc675c8243 100644
--- a/mlir/include/mlir/Dialect/Tosa/IR/TosaProfileCompliance.h
+++ b/mlir/include/mlir/Dialect/Tosa/IR/TosaProfileCompliance.h
@@ -23,10 +23,22 @@ using namespace mlir::tosa;
// Type Compilance Definition
//===----------------------------------------------------------------------===//
-typedef struct {
+struct TypeInfo {
+ TypeInfo(mlir::TypeID typeID, uint32_t bitWidth)
+ : typeID(typeID), bitWidth(bitWidth), valueTypeID(mlir::TypeID()),
+ scaleTypeID(mlir::TypeID()), blockShape(std::nullopt) {}
+
+ TypeInfo(mlir::TypeID typeID, uint32_t bitWidth, mlir::TypeID valueTypeID,
+ mlir::TypeID scaleTypeID, tosa::BlockShape blockShape)
+ : typeID(typeID), bitWidth(bitWidth), valueTypeID(valueTypeID),
+ scaleTypeID(scaleTypeID), blockShape(blockShape) {}
+
mlir::TypeID typeID;
uint32_t bitWidth;
-} TypeInfo;
+ mlir::TypeID valueTypeID;
+ mlir::TypeID scaleTypeID;
+ std::optional<tosa::BlockShape> blockShape;
+};
enum CheckCondition {
invalid,
@@ -70,6 +82,12 @@ class ProfileInfoDepot {
private:
TypeInfo convertTypeToInfo(Type type) {
+ if (auto blockScaledTy = dyn_cast<tosa::BlockScaledType>(type)) {
+ Type valueTy = blockScaledTy.getValueType();
+ Type scaleTy = blockScaledTy.getScaleType();
+ return {type.getTypeID(), tosa::getBitWidth(valueTy), valueTy.getTypeID(),
+ scaleTy.getTypeID(), blockScaledTy.getBlockShape()};
+ }
return {type.getTypeID(), tosa::getBitWidth(type)};
}
@@ -128,7 +146,9 @@ class TosaProfileCompliance {
const SmallVector<ArrayRef<T>> &specDefinedProfileSet);
bool isSameTypeInfo(TypeInfo a, TypeInfo b) {
- return a.typeID == b.typeID && a.bitWidth == b.bitWidth;
+ return a.typeID == b.typeID && a.bitWidth == b.bitWidth &&
+ a.valueTypeID == b.valueTypeID && a.scaleTypeID == b.scaleTypeID &&
+ a.blockShape == b.blockShape;
}
// Find the required profiles or extensions from the compliance info according
@@ -145,7 +165,7 @@ class TosaProfileCompliance {
SmallVector<StringRef>
stringifyProfile(const SmallVector<ArrayRef<T>> &profileSet);
- static llvm::SmallString<7> stringifyTypeInfo(const TypeInfo &typeInfo);
+ static llvm::SmallString<32> stringifyTypeInfo(const TypeInfo &typeInfo);
private:
template <typename T>
diff --git a/mlir/include/mlir/Dialect/Tosa/IR/TosaTypesBase.td b/mlir/include/mlir/Dialect/Tosa/IR/TosaTypesBase.td
index b7d9ed45f3a03..69f836cf1b9d3 100644
--- a/mlir/include/mlir/Dialect/Tosa/IR/TosaTypesBase.td
+++ b/mlir/include/mlir/Dialect/Tosa/IR/TosaTypesBase.td
@@ -103,15 +103,43 @@ def Tosa_MXInt8
}];
}
+def Tosa_MXFPValue
+ : AnyTypeOf<[F8E4M3FN, F8E5M2, F4E2M1FN, F6E2M3FN, F6E3M2FN, Tosa_MXInt8],
+ "micro-scaling format number">;
+def Tosa_MXFPScale
+ : AnyTypeOf<[F8E8M0FNU], "micro-scaling format scale number">;
+
+def Tosa_BlockScaled : Tosa_Type<"BlockScaled", "block_scaled"> {
+ let summary = "Block scaled tensor element type.";
+
+ let description = [{
+ This does not specify an implementation type. A tensor of this type is a
+ tensor which has block-scaled quantization applied.
+
+ This compound type is made up of 3 components:
+ `block_shape` - The size and axis of each block. Currently only supports
+ specifying the block size along the innermost dimension.
+ `scale_type` - The type of the scale value associated with each block.
+ `value_type` - The type of the data values in each block.
+
+ }];
+
+ let parameters = (ins
+ EnumParameter<Tosa_BlockShape>:$block_shape,
+ Tosa_MXFPScale:$scale_type,
+ Tosa_MXFPValue:$value_type
+ );
+
+ let assemblyFormat =
+ "`<` $block_shape```:```$scale_type```:```$value_type `>`";
+}
+
//===----------------------------------------------------------------------===//
// Multi-category types.
//===----------------------------------------------------------------------===//
-def Tosa_AnyNumber : AnyTypeOf<[Tosa_Int, Tosa_QuantizedInt, AnyFloat, Tosa_MXInt8],
- "number">;
-
-def Tosa_MXFPNumber : AnyTypeOf<[F8E4M3FN, F8E5M2, F4E2M1FN, F6E2M3FN, F6E3M2FN, Tosa_MXInt8],
- "micro-scaling format number">;
-def Tosa_MXFPScaleNumber : AnyTypeOf<[F8E8M0FNU], "micro-scaling format scale number">;
+def Tosa_AnyNumber : AnyTypeOf<[Tosa_Int, Tosa_QuantizedInt, AnyFloat,
+ Tosa_MXInt8, Tosa_BlockScaled],
+ "number">;
//===----------------------------------------------------------------------===//
// TOSA Tensor Conformance
@@ -129,16 +157,29 @@ def AtLeastRankOne : And<[
IsRankedTensorTypePred,
CPred<"::llvm::cast<::mlir::RankedTensorType>($_self).getRank() >= 1">]>;
-class TosaTensorOf<
- list<Type> allowedTypes, string summary = "tosa-conformant tensor">
- : TensorOf<allowedTypes, [Or<[HasNo0Dimensions, IsUnrankedTensorTypePred]>], summary>;
-
-class TosaRankedTensorOf<
- list<Type> allowedTypes, list<Pred> preds = [], string summary = "tosa-conformant ranked tensor">
- : RankedTensorOf<allowedTypes, !listconcat([HasNo0Dimensions], preds), summary>;
-
-class TosaUnrankedTensorOf<list<Type> allowedTypes, list<Pred> preds = [], string summary = "tosa-conformant unranked tensor">
- : UnrankedTensorOf<allowedTypes, preds, summary>;
+def IsValidBlockScaledTensorType
+ : CPred<"::mlir::succeeded(::mlir::OpTrait::tosa::"
+ "verifyBlockScaledTensorType($_op, $_self))">;
+
+class TosaTensorOf<list<Type> allowedTypes,
+ string summary = "tosa-conformant tensor">
+ : TensorOf<allowedTypes,
+ [Or<[HasNo0Dimensions, IsUnrankedTensorTypePred]>,
+ IsValidBlockScaledTensorType],
+ summary>;
+
+class TosaRankedTensorOf<list<Type> allowedTypes, list<Pred> preds = [],
+ string summary = "tosa-conformant ranked tensor">
+ : RankedTensorOf<
+ allowedTypes,
+ !listconcat([HasNo0Dimensions, IsValidBlockScaledTensorType], preds),
+ summary>;
+
+class TosaUnrankedTensorOf<list<Type> allowedTypes, list<Pred> preds = [],
+ string summary = "tosa-conformant unranked tensor">
+ : UnrankedTensorOf<allowedTypes,
+ !listconcat([IsValidBlockScaledTensorType], preds),
+ summary>;
class TosaTensorRankOf<list<Type> allowedTypes, list<int> ranks>
: TosaRankedTensorOf<allowedTypes,
@@ -217,32 +258,28 @@ def Tosa_IndexTensor2D : AnyTypeOf<[
def Tosa_TensorAtLeast1D : AnyTypeOf<[
Tosa_UnrankedTensor, TosaRankedTensorOf<[Tosa_AnyNumber], [AtLeastRankOne]>], "tosa-conformant tensor of at least rank 1", "::mlir::TensorType">;
-def Tosa_MXFPDataTensor3D : AnyTypeOf<[
- TosaUnrankedTensorOf<[Tosa_MXFPNumber]>,
- TosaTensorRankOf<[Tosa_MXFPNumber], [3]>
-]>;
-def Tosa_MXFPScaleTensor3D : AnyTypeOf<[
- TosaUnrankedTensorOf<[Tosa_MXFPScaleNumber]>,
- TosaTensorRankOf<[Tosa_MXFPScaleNumber], [3]>
-]>;
-def Tosa_MXFPDataTensor4D : AnyTypeOf<[
- TosaUnrankedTensorOf<[Tosa_MXFPNumber]>,
- TosaTensorRankOf<[Tosa_MXFPNumber], [4]>
-]>;
-def Tosa_MXFPScaleTensor4D : AnyTypeOf<[
- TosaUnrankedTensorOf<[Tosa_MXFPScaleNumber]>,
- TosaTensorRankOf<[Tosa_MXFPScaleNumber], [4]>
-]>;
-def Tosa_MXFPDataTensorAtLeast1D : AnyTypeOf<[
- TosaUnrankedTensorOf<[Tosa_MXFPNumber]>,
- TosaRankedTensorOf<[Tosa_MXFPNumber], [AtLeastRankOne]>],
- "tosa-conformant tensor of at least rank 1", "::mlir::TensorType"
->;
-def Tosa_MXFPScaleTensorAtLeast1D : AnyTypeOf<[
- TosaUnrankedTensorOf<[Tosa_MXFPScaleNumber]>,
- TosaRankedTensorOf<[Tosa_MXFPScaleNumber], [AtLeastRankOne]>],
- "tosa-conformant tensor of at least rank 1", "::mlir::TensorType"
->;
+def Tosa_MXFPDataTensor3D
+ : AnyTypeOf<[TosaUnrankedTensorOf<[Tosa_MXFPValue]>,
+ TosaTensorRankOf<[Tosa_MXFPValue], [3]>]>;
+def Tosa_MXFPScaleTensor3D
+ : AnyTypeOf<[TosaUnrankedTensorOf<[Tosa_MXFPScale]>,
+ TosaTensorRankOf<[Tosa_MXFPScale], [3]>]>;
+def Tosa_MXFPDataTensor4D
+ : AnyTypeOf<[TosaUnrankedTensorOf<[Tosa_MXFPValue]>,
+ TosaTensorRankOf<[Tosa_MXFPValue], [4]>]>;
+def Tosa_MXFPScaleTensor4D
+ : AnyTypeOf<[TosaUnrankedTensorOf<[Tosa_MXFPScale]>,
+ TosaTensorRankOf<[Tosa_MXFPScale], [4]>]>;
+def Tosa_MXFPDataTensorAtLeast1D
+ : AnyTypeOf<[TosaUnrankedTensorOf<[Tosa_MXFPValue]>,
+ TosaRankedTensorOf<[Tosa_MXFPValue], [AtLeastRankOne]>],
+ "tosa-conformant tensor of at least rank 1",
+ "::mlir::TensorType">;
+def Tosa_MXFPScaleTensorAtLeast1D
+ : AnyTypeOf<[TosaUnrankedTensorOf<[Tosa_MXFPScale]>,
+ TosaRankedTensorOf<[Tosa_MXFPScale], [AtLeastRankOne]>],
+ "tosa-conformant tensor of at least rank 1",
+ "::mlir::TensorType">;
//===----------------------------------------------------------------------===//
// Generic scalar, vector, or tensor of a particular type.
diff --git a/mlir/lib/Dialect/Tosa/IR/TargetEnv.cpp b/mlir/lib/Dialect/Tosa/IR/TargetEnv.cpp
index dc18fcaa04c8a..56e4901811dcb 100644
--- a/mlir/lib/Dialect/Tosa/IR/TargetEnv.cpp
+++ b/mlir/lib/Dialect/Tosa/IR/TargetEnv.cpp
@@ -56,6 +56,13 @@ TosaSpecificationVersion getMinVersion(const Extension &extension) {
case Extension::int64:
case Extension::mxfp_conv:
case Extension::shape:
+ case Extension::mx_common:
+ case Extension::mx_fp4e2m1:
+ case Extension::mx_fp6e2m3:
+ case Extension::mx_fp6e3m2:
+ case Extension::mx_fp8e4m3:
+ case Extension::mx_fp8e5m2:
+ case Extension::mx_int8:
return TosaSpecificationVersion(1, 1, true);
case Extension::none:
return TosaSpecificationVersion(0, 0);
@@ -76,6 +83,13 @@ SmallVector<Profile, 2> getCooperativeProfiles(Extension ext) {
case Extension::fft:
case Extension::mxfp:
case Extension::mxfp_conv:
+ case Extension::mx_common:
+ case Extension::mx_fp4e2m1:
+ case Extension::mx_fp6e2m3:
+ case Extension::mx_fp6e3m2:
+ case Extension::mx_fp8e4m3:
+ case Extension::mx_fp8e5m2:
+ case Extension::mx_int8:
return {Profile::pro_fp};
case Extension::variable:
case Extension::controlflow:
diff --git a/mlir/lib/Dialect/Tosa/IR/TosaCanonicalizations.cpp b/mlir/lib/Dialect/Tosa/IR/TosaCanonicalizations.cpp
index b2c6540aa74e2..4c98aca0ee8d7 100644
--- a/mlir/lib/Dialect/Tosa/IR/TosaCanonicalizations.cpp
+++ b/mlir/lib/Dialect/Tosa/IR/TosaCanonicalizations.cpp
@@ -1235,12 +1235,50 @@ struct NonNarrowingCastsOptimization : public OpRewritePattern<tosa::CastOp> {
}
};
+struct CancellingBlockScaledCastsOptimization
+ : public OpRewritePattern<tosa::CastOp> {
+ using OpRewritePattern<tosa::CastOp>::OpRewritePattern;
+
+ LogicalResult matchAndRewrite(tosa::CastOp castOp,
+ PatternRewriter &rewriter) const override {
+ const Value outerInput = castOp.getInput();
+ auto innerCastOp = outerInput.getDefiningOp<tosa::CastOp>();
+ if (!innerCastOp)
+ return rewriter.notifyMatchFailure(castOp,
+ "input must be a cast operation");
+
+ const Value innerInput = innerCastOp.getInput();
+ const auto innerInputTy = llvm::cast<ShapedType>(innerInput.getType());
+ const auto innerOutputTy = llvm::cast<ShapedType>(innerCastOp.getType());
+ const auto outerOutputTy = llvm::cast<ShapedType>(castOp.getType());
+
+ if (!llvm::isa<tosa::BlockScaledType>(innerInputTy.getElementType()))
+ return rewriter.notifyMatchFailure(
+ castOp, "inner cast input must have block scaled element type");
+
+ if (innerInputTy != outerOutputTy)
+ return rewriter.notifyMatchFailure(
+ castOp, "inner input type must match outer output type");
+
+ const Type innerOutputElemType = innerOutputTy.getElementType();
+ const bool isLosslessCast = isa<Float32Type>(innerOutputElemType);
+ if (!isLosslessCast)
+ return rewriter.notifyMatchFailure(
+ castOp, "avoid cancelling casts that should be lossy");
+
+ rewriter.replaceOp(castOp, innerInput);
+
+ return success();
+ }
+};
+
void CastOp::getCanonicalizationPatterns(RewritePatternSet &results,
MLIRContext *context) {
- results.add<NonNarrowingCastsOptimization>(context);
+ results.add<NonNarrowingCastsOptimization,
+ CancellingBlockScaledCastsOptimization>(context);
}
-struct CancellingBlockScaledCastsOptimization
+struct CancellingCastToFromBlockScaledOptimization
: public OpRewritePattern<tosa::CastToBlockScaledOp> {
using OpRewritePattern<tosa::CastToBlockScaledOp>::OpRewritePattern;
@@ -1286,7 +1324,7 @@ struct CancellingBlockScaledCastsOptimization
void CastToBlockScaledOp::getCanonicalizationPatterns(
RewritePatternSet &results, MLIRContext *context) {
- results.add<CancellingBlockScaledCastsOptimization>(context);
+ results.add<CancellingCastToFromBlockScaledOptimization>(context);
}
struct RowGatherToGather : public OpRewritePattern<tosa::RowGatherOp> {
diff --git a/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp b/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
index c4705c8080069..e25774856f59d 100644
--- a/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
+++ b/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
@@ -628,6 +628,8 @@ Value mlir::tosa::createPadConstTensor(OpBuilder &builder, Location loc,
}
unsigned mlir::tosa::getBitWidth(Type type) {
+ if (auto blockScaledTy = dyn_cast<tosa::BlockScaledType>(type))
+ return getBitWidth(blockScaledTy.getValueType());
if (dyn_cast<tosa::mxint8Type>(type))
return 8;
return type.getIntOrFloatBitWidth();
@@ -734,6 +736,41 @@ LogicalResult mlir::tosa::mxint8Type::convertFromAttribute(
return cast<IntegerType>(attrType).convertFromAttribute(attr, result);
}
+//===----------------------------------------------------------------------===//
+// TOSA block scaling utilities.
+//===----------------------------------------------------------------------===//
+
+LogicalResult OpTrait::tosa::verifyBlockScaledTensorType(Operation &op,
+ mlir::Type type) {
+ const auto tensorType = llvm::cast<ShapedType>(type);
+ const BlockScaledType elemType =
+ llvm::dyn_cast<BlockScaledType>(tensorType.getElementType());
+ if (!elemType)
+ return success();
+
+ if (!tensorType.hasRank())
+ return success();
+
+ if (tensorType.getRank() == 0)
+ return op.emitError()
+ << "tensor type " << type
+ << " does not support block scaling on scalar tensors";
+
+ const int64_t blockedDimension = tensorType.getShape().back();
+ if (ShapedType::isDynamic(blockedDimension))
+ return success();
+
+ const uint32_t blockSize =
+ BlockShapeAttr::getBlockShapeValue(elemType.getBlockShape());
+ if (blockedDimension % blockSize != 0)
+ return op.emitError()
+ << "tensor type " << type
+ << " blocked dimension must be a multiple of block size, got "
+ << blockedDimension << " and block size " << blockSize;
+
+ return success();
+}
+
//===----------------------------------------------------------------------===//
// TOSA Operator Verifiers.
//===----------------------------------------------------------------------===//
@@ -5187,6 +5224,34 @@ LogicalResult RescaleOp::inferReturnTypeComponents(
return success();
}
+LogicalResult CastOp::verify() {
+ const ShapedType inputType = llvm::cast<ShapedType>(getInput().getType());
+ const ShapedType outputType = llvm::cast<ShapedType>(getType());
+ const Type inputElementType = inputType.getElementType();
+ const Type outputElementType = outputType.getElementType();
+
+ const bool inputIsBlockScaled = llvm::isa<BlockScaledType>(inputElementType);
+ const bool outputIsBlockScaled =
+ llvm::isa<BlockScaledType>(outputElementType);
+ if (!inputIsBlockScaled && !outputIsBlockScaled)
+ return success();
+
+ if (inputIsBlockScaled && outputIsBlockScaled)
+ return emitOpError()
+ << "requires exactly one of input or output to have block scaled "
+ "element type";
+
+ const Type scalarElementType =
+ inputIsBlockScaled ? outputElementType : inputElementType;
+ if (!llvm::isa<FloatType>(scalarElementType))
+ return emitOpError()
+ << "requires non-block-scaled element type to be floating-point "
+ "when casting to or from block scaled element type, got "
+ << scalarElementType;
+
+ return success();
+}
+
LogicalResult CastFromBlockScaledOp::inferReturnTypeComponents(
MLIRContext *context, ::std::optional<Location> location,
CastFromBlockScaledOp::Adaptor adaptor,
diff --git a/mlir/lib/Dialect/Tosa/Transforms/TosaProfileCompliance.cpp b/mlir/lib/Dialect/Tosa/Transforms/TosaProfileCompliance.cpp
index 0b4983bea4bc6..348e4ec0ad44c 100644
--- a/mlir/lib/Dialect/Tosa/Transforms/TosaProfileCompliance.cpp
+++ b/mlir/lib/Dialect/Tosa/Transforms/TosaProfileCompliance.cpp
@@ -8,6 +8,7 @@
#include "mlir/Dialect/Tosa/IR/TosaProfileCompliance.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/raw_ostream.h"
using namespace mlir;
using namespace mlir::tosa;
@@ -27,12 +28,42 @@ TosaProfileCompliance::TosaProfileCompliance() {
const TypeInfo fp8e5m2T = {mlir::Float8E5M2Type::getTypeID(), 8};
// micro-scaling formats
+ // Note: these types exist to suppport the deprecated block_scaled operations
+ // and can be removed once those operations are removed.
const TypeInfo fp6e2m3T = {mlir::Float6E2M3FNType::getTypeID(), 6};
const TypeInfo fp6e3m2T = {mlir::Float6E3M2FNType::getTypeID(), 6};
const TypeInfo fp4e2m1T = {mlir::Float4E2M1FNType::getTypeID(), 4};
const TypeInfo fp8ue8m0T = {mlir::Float8E8M0FNUType::getTypeID(), 8};
const TypeInfo mxint8T = {mlir::tosa::mxint8Type::getTypeID(), 8};
+ // Block scaled formats
+ const TypeID blockScaledID = mlir::tosa::BlockScaledType::getTypeID();
+ const TypeID fp4e2m1ID = mlir::Float4E2M1FNType::getTypeID();
+ const TypeID fp6e2m3ID = mlir::Float6E2M3FNType::getTypeID();
+ const TypeID fp6e3m2ID = mlir::Float6E3M2FNType::getTypeID();
+ const TypeID fp8e4m3ID = mlir::Float8E4M3FNType::getTypeID();
+ const TypeID fp8e5m2ID = mlir::Float8E5M2Type::getTypeID();
+ const TypeID fp8ue8m0ID = mlir::Float8E8M0FNUType::getTypeID();
+ const TypeID mxint8ID = mlir::tosa::mxint8Type::getTypeID();
+
+ const TypeInfo bs32_fp8ue8m0_fp4e2m1T = {blockScaledID, 4, fp4e2m1ID,
+ fp8ue8m0ID,
+ tosa::BlockShape::BLOCK_SHAPE_32};
+ const TypeInfo bs32_fp8ue8m0_fp6e2m3T = {blockScaledID, 6, fp6e2m3ID,
+ fp8ue8m0ID,
+ tosa::BlockShape::BLOCK_SHAPE_32};
+ const TypeInfo bs32_fp8ue8m0_fp6e3m2T = {blockScaledID, 6, fp6e3m2ID,
+ fp8ue8m0ID,
+ tosa::BlockShape::BLOCK_SHAPE_32};
+ const TypeInfo bs32_fp8ue8m0_fp8e4m3T = {blockScaledID, 8, fp8e4m3ID,
+ fp8ue8m0ID,
+ tosa::BlockShape::BLOCK_SHAPE_32};
+ const TypeInfo bs32_fp8ue8m0_fp8e5m2T = {blockScaledID, 8, fp8e5m2ID,
+ fp8ue8m0ID,
+ tosa::BlockShape::BLOCK_SHAPE_32};
+ const TypeInfo bs32_fp8ue8m0_mxint8T = {
+ blockScaledID, 8, mxint8ID, fp8ue8m0ID, tosa::BlockShape::BLOCK_SHAPE_32};
+
// The profile-based compliance content below is auto-generated by a script
// in https://github.com/arm/tosa-specification
#include "mlir/Dialect/Tosa/IR/TosaComplianceData.h.inc"
@@ -687,31 +718,48 @@ SmallVector<StringRef> TosaProfileCompliance::stringifyProfile(
return debugStrings;
}
-llvm::SmallString<7>
+llvm::SmallString<32>
TosaProfileCompliance::stringifyTypeInfo(const TypeInfo &typeInfo) {
- if (typeInfo.typeID == mlir::IntegerType::getTypeID()) {
- return {"i" + llvm::utostr(typeInfo.bitWidth)};
- }
- if (typeInfo.typeID == mlir::Float16Type::getTypeID()) {
- return {"f16"};
- } else if (typeInfo.typeID == mlir::Float32Type::getTypeID()) {
- return {"f32"};
- } else if (typeInfo.typeID == mlir::BFloat16Type::getTypeID()) {
- return {"bf16"};
- } else if (typeInfo.typeID == mlir::Float8E4M3FNType::getTypeID()) {
- return {"fp8e4m3"};
- } else if (typeInfo.typeID == mlir::Float8E5M2Type::getTypeID()) {
- return {"fp8e5m2"};
- } else if (typeInfo.typeID == mlir::Float6E2M3FNType::getTypeID()) {
- return {"fp6e2m3"};
- } else if (typeInfo.typeID == mlir::Float6E3M2FNType::getTypeID()) {
- return {"fp6e3m2"};
- } else if (typeInfo.typeID == mlir::Float4E2M1FNType::getTypeID()) {
- return {"fp4e2m1"};
- } else if (typeInfo.typeID == mlir::Float8E8M0FNUType::getTypeID()) {
- return {"fp8e8m0"};
- } else if (typeInfo.typeID == tosa::mxint8Type::getTypeID()) {
- return {"mxint8"};
+ const auto stringifyScalarTypeInfo =
+ [](const TypeInfo &typeInfo) -> llvm::SmallString<32> {
+ if (typeInfo.typeID == mlir::IntegerType::getTypeID()) {
+ return {"i" + llvm::utostr(typeInfo.bitWidth)};
+ }
+ if (typeInfo.typeID == mlir::Float16Type::getTypeID()) {
+ return {"f16"};
+ } else if (typeInfo.typeID == mlir::Float32Type::getTypeID()) {
+ return {"f32"};
+ } else if (typeInfo.typeID == mlir::BFloat16Type::getTypeID()) {
+ return {"bf16"};
+ } else if (typeInfo.typeID == mlir::Float8E4M3FNType::getTypeID()) {
+ return {"fp8e4m3"};
+ } else if (typeInfo.typeID == mlir::Float8E5M2Type::getTypeID()) {
+ return {"fp8e5m2"};
+ } else if (typeInfo.typeID == mlir::Float6E2M3FNType::getTypeID()) {
+ return {"fp6e2m3"};
+ } else if (typeInfo.typeID == mlir::Float6E3M2FNType::getTypeID()) {
+ return {"fp6e3m2"};
+ } else if (typeInfo.typeID == mlir::Float4E2M1FNType::getTypeID()) {
+ return {"fp4e2m1"};
+ } else if (typeInfo.typeID == mlir::Float8E8M0FNUType::getTypeID()) {
+ return {"fp8e8m0"};
+ } else if (typeInfo.typeID == tosa::mxint8Type::getTypeID()) {
+ return {"mxint8"};
+ }
+ llvm_unreachable("unknown type");
+ };
+
+ if (typeInfo.typeID == tosa::BlockScaledType::getTypeID()) {
+ TypeInfo valueInfo = {typeInfo.valueTypeID, typeInfo.bitWidth};
+ TypeInfo scaleInfo = {typeInfo.scaleTypeID, 8};
+ llvm::SmallString<32> result;
+ llvm::raw_svector_ostream os(result);
+ os << "bs"
+ << tosa::BlockShapeAttr::getBlockShapeValue(typeInfo.blockShape.value())
+ << "_" << stringifyScalarTypeInfo(scaleInfo) << "_"
+ << stringifyScalarTypeInfo(valueInfo);
+ return result;
}
- llvm_unreachable("unknown type");
+
+ return stringifyScalarTypeInfo(typeInfo);
}
diff --git a/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp b/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
index 5d4a2affbd7cd..a3d5d21294b0d 100644
--- a/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
+++ b/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
@@ -1495,7 +1495,7 @@ bool TosaValidation::isValidElementType(Type type, const bool allowUnsigned) {
}
} else if (isa<tosa::shapeType>(type))
return true;
- else if (isa<tosa::mxint8Type>(type))
+ else if (isa<tosa::mxint8Type, tosa::BlockScaledType>(type))
return true;
return false;
}
diff --git a/mlir/test/Dialect/Tosa/availability.mlir b/mlir/test/Dialect/Tosa/availability.mlir
index f4f31d3f476e8..c358460bbc662 100644
--- a/mlir/test/Dialect/Tosa/availability.mlir
+++ b/mlir/test/Dialect/Tosa/availability.mlir
@@ -637,10 +637,10 @@ func.func @test_resize(%arg0: tensor<1x32x32x8xf32>) -> tensor<1x64x64x8xf32> {
}
// -----
-// CHECK-LABEL: cast
-func.func @test_cast1(%arg0: tensor<13x21x3xi32>) -> tensor<13x21x3xf32> {
+// CHECK-LABEL: test_cast
+func.func @test_cast(%arg0: tensor<13x21x3xi32>) -> tensor<13x21x3xf32> {
// CHECK: profiles: [ [pro_int, pro_fp] ]
- // CHECK: extensions: [ [fp8e4m3, fp8e5m2, bf16, int64] ]
+ // CHECK: extensions: [ [fp8e4m3, fp8e5m2, bf16, int64, mx_common, mx_fp4e2m1, mx_fp6e2m3, mx_fp6e3m2, mx_fp8e4m3, mx_fp8e5m2, mx_int8] ]
%0 = tosa.cast %arg0 : (tensor<13x21x3xi32>) -> tensor<13x21x3xf32>
return %0 : tensor<13x21x3xf32>
}
diff --git a/mlir/test/Dialect/Tosa/canonicalize.mlir b/mlir/test/Dialect/Tosa/canonicalize.mlir
index 992059e06e541..6a3d84e8d133b 100644
--- a/mlir/test/Dialect/Tosa/canonicalize.mlir
+++ b/mlir/test/Dialect/Tosa/canonicalize.mlir
@@ -1681,6 +1681,73 @@ func.func @test_canonicalize_non_narrowing_cast_i8_to_f8E4M3FN_unsupported(%arg0
// -----
+// CHECK-LABEL: @test_canonicalize_cast_from_cast_to_block_scaled_type_f4E2M1
+// CHECK: return %arg0 : tensor<15x3x2x256x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>
+func.func @test_canonicalize_cast_from_cast_to_block_scaled_type_f4E2M1(%arg0: tensor<15x3x2x256x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>) -> tensor<15x3x2x256x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>> {
+ %0 = tosa.cast %arg0 : (tensor<15x3x2x256x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>) -> tensor<15x3x2x256xf32>
+ %1 = tosa.cast %0 : (tensor<15x3x2x256xf32>) -> tensor<15x3x2x256x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>
+ return %1 : tensor<15x3x2x256x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>
+}
+
+// -----
+
+// CHECK-LABEL: @test_canonicalize_cast_from_cast_to_block_scaled_type_f8E5M2
+// CHECK: return %arg0 : tensor<160x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E5M2>>
+func.func @test_canonicalize_cast_from_cast_to_block_scaled_type_f8E5M2(%arg0: tensor<160x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E5M2>>) -> tensor<160x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E5M2>> {
+ %0 = tosa.cast %arg0 : (tensor<160x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E5M2>>) -> tensor<160xf32>
+ %1 = tosa.cast %0 : (tensor<160xf32>) -> tensor<160x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E5M2>>
+ return %1 : tensor<160x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E5M2>>
+}
+
+// -----
+
+// CHECK-LABEL: @test_do_not_canonicalize_cast_from_cast_to_block_scaled_type_
diff erent_types_f8E5M2_f6E2M3
+// CHECK: %[[values:.+]] = tosa.cast %arg0
+// CHECK: %[[block_scaled:.+]] = tosa.cast %[[values]]
+// CHECK: return %[[block_scaled]] : tensor<160x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E2M3FN>>
+func.func @test_do_not_canonicalize_cast_from_cast_to_block_scaled_type_
diff erent_types_f8E5M2_f6E2M3(%arg0: tensor<160x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E5M2>>) -> tensor<160x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E2M3FN>> {
+ %0 = tosa.cast %arg0 : (tensor<160x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E5M2>>) -> tensor<160xf32>
+ %1 = tosa.cast %0 : (tensor<160xf32>) -> tensor<160x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E2M3FN>>
+ return %1 : tensor<160x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E2M3FN>>
+}
+
+// -----
+
+// CHECK-LABEL: @test_do_not_canonicalize_cast_from_cast_to_block_scaled_type_
diff erent_types_f6E2M3_f6E3M2
+// CHECK: %[[values:.+]] = tosa.cast %arg0
+// CHECK: %[[block_scaled:.+]] = tosa.cast %[[values]]
+// CHECK: return %[[block_scaled]] : tensor<32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E3M2FN>>
+func.func @test_do_not_canonicalize_cast_from_cast_to_block_scaled_type_
diff erent_types_f6E2M3_f6E3M2(%arg0: tensor<32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E2M3FN>>) -> tensor<32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E3M2FN>> {
+ %0 = tosa.cast %arg0 : (tensor<32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E2M3FN>>) -> tensor<32xf32>
+ %1 = tosa.cast %0 : (tensor<32xf32>) -> tensor<32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E3M2FN>>
+ return %1 : tensor<32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E3M2FN>>
+}
+
+// -----
+
+// CHECK-LABEL: @test_do_not_canonicalize_cast_from_cast_to_block_scaled_type_unranked
+// CHECK: %[[values:.+]] = tosa.cast %arg0
+// CHECK: %[[block_scaled:.+]] = tosa.cast %[[values]]
+// CHECK: return %[[block_scaled]] : tensor<*x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E2M3FN>>
+func.func @test_do_not_canonicalize_cast_from_cast_to_block_scaled_type_unranked(%arg0: tensor<3x64x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E2M3FN>>) -> tensor<*x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E2M3FN>> {
+ %0 = tosa.cast %arg0 : (tensor<3x64x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E2M3FN>>) -> tensor<*xf32>
+ %1 = tosa.cast %0 : (tensor<*xf32>) -> tensor<*x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E2M3FN>>
+ return %1 : tensor<*x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E2M3FN>>
+}
+
+// -----
+
+// CHECK-LABEL: @test_do_not_canonicalize_cast_from_cast_to_block_scaled_type_f8E5M2_f8E4M3
+// CHECK: tosa.cast
+// CHECK: tosa.cast
+func.func @test_do_not_canonicalize_cast_from_cast_to_block_scaled_type_f8E5M2_f8E4M3(%arg0: tensor<15x3x2x256x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E5M2>>) -> tensor<15x3x2x256x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E5M2>> {
+ %0 = tosa.cast %arg0 : (tensor<15x3x2x256x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E5M2>>) -> tensor<15x3x2x256xf8E4M3FN>
+ %1 = tosa.cast %0 : (tensor<15x3x2x256xf8E4M3FN>) -> tensor<15x3x2x256x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E5M2>>
+ return %1 : tensor<15x3x2x256x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E5M2>>
+}
+
+// -----
+
// CHECK-LABEL: @test_canonicalize_cast_from_cast_to_block_scaled_f4E2M1
// CHECK: return %arg0, %arg1 : tensor<15x3x2x256xf4E2M1FN>, tensor<15x3x2x8xf8E8M0FNU>
func.func @test_canonicalize_cast_from_cast_to_block_scaled_f4E2M1(%arg0: tensor<15x3x2x256xf4E2M1FN>, %arg1: tensor<15x3x2x8xf8E8M0FNU>) -> (tensor<15x3x2x256xf4E2M1FN>, tensor<15x3x2x8xf8E8M0FNU>) {
diff --git a/mlir/test/Dialect/Tosa/invalid.mlir b/mlir/test/Dialect/Tosa/invalid.mlir
index 5e8111061cb3a..d0336da15cee8 100644
--- a/mlir/test/Dialect/Tosa/invalid.mlir
+++ b/mlir/test/Dialect/Tosa/invalid.mlir
@@ -2266,3 +2266,35 @@ func.func @test_shape_func_output() -> !tosa.shape<4> {
%cst = tosa.const_shape {values = dense<[1, 2, 3, 4]> : tensor<4xindex>} : () -> !tosa.shape<4>
return %cst : !tosa.shape<4>
}
+
+// -----
+
+func.func @test_cast_f32_plain_fp4(%arg0: tensor<4x32xf32>) -> tensor<4x32xf4E2M1FN> {
+ // expected-error at +1 {{'tosa.cast' op illegal: operation operand/result data types did not align with any profile or extension, got (f32,fp4e2m1)}}
+ %0 = tosa.cast %arg0 : (tensor<4x32xf32>) -> tensor<4x32xf4E2M1FN>
+ return %0 : tensor<4x32xf4E2M1FN>
+}
+
+// -----
+
+func.func @test_cast_fp4_block_scaled(%arg0: tensor<4x32xf4E2M1FN>) -> tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>> {
+ // expected-error at +1 {{'tosa.cast' op illegal: operation operand/result data types did not align with any profile or extension, got (fp4e2m1,bs32_fp8e8m0_fp4e2m1), did you mean (fp8e4m3,bs32_fp8e8m0_fp4e2m1)? Otherwise, please refer to the 'supported data types' for 'tosa.cast' in the specification.}}
+ %0 = tosa.cast %arg0 : (tensor<4x32xf4E2M1FN>) -> tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>
+ return %0 : tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>
+}
+
+// -----
+
+func.func @test_cast_block_scaled_fp6e2m3(%arg0: tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>) -> tensor<4x32xf6E2M3FN> {
+ // expected-error at +1 {{'tosa.cast' op illegal: operation operand/result data types did not align with any profile or extension, got (bs32_fp8e8m0_fp4e2m1,fp6e2m3), did you mean (bs32_fp8e8m0_fp4e2m1,fp8e4m3)? Otherwise, please refer to the 'supported data types' for 'tosa.cast' in the specification.}}
+ %0 = tosa.cast %arg0 : (tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>) -> tensor<4x32xf6E2M3FN>
+ return %0 : tensor<4x32xf6E2M3FN>
+}
+
+// -----
+
+func.func @test_cast_fp6e3m2_block_scaled(%arg0: tensor<4x32xf6E3M2FN>) -> tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:!tosa.mxint8>> {
+ // expected-error at +1 {{'tosa.cast' op illegal: operation operand/result data types did not align with any profile or extension, got (fp6e3m2,bs32_fp8e8m0_mxint8), did you mean (fp8e4m3,bs32_fp8e8m0_mxint8)? Otherwise, please refer to the 'supported data types' for 'tosa.cast' in the specification.}}
+ %0 = tosa.cast %arg0 : (tensor<4x32xf6E3M2FN>) -> tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:!tosa.mxint8>>
+ return %0 : tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:!tosa.mxint8>>
+}
diff --git a/mlir/test/Dialect/Tosa/invalid_extension.mlir b/mlir/test/Dialect/Tosa/invalid_extension.mlir
index c69ea83f5ef36..5e4dd17b24090 100644
--- a/mlir/test/Dialect/Tosa/invalid_extension.mlir
+++ b/mlir/test/Dialect/Tosa/invalid_extension.mlir
@@ -303,6 +303,34 @@ func.func @test_cast_f32_bf16(%arg0: tensor<13x21x3xf32>) -> tensor<13x21x3xbf16
return %0 : tensor<13x21x3xbf16>
}
+// -----
+func.func @test_cast_f32_block_scaled(%arg0: tensor<4x32xf32>) -> tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>> {
+ // expected-error at +1 {{'tosa.cast' op illegal: requires all of [mx_common, mx_fp4e2m1] profiles/extensions to be specified in the target environment}}
+ %0 = tosa.cast %arg0 : (tensor<4x32xf32>) -> tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>
+ return %0 : tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>
+}
+
+// -----
+func.func @test_cast_block_scaled_f32(%arg0: tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>) -> tensor<4x32xf32> {
+ // expected-error at +1 {{'tosa.cast' op illegal: requires all of [mx_common, mx_fp4e2m1] profiles/extensions to be specified in the target environment}}
+ %0 = tosa.cast %arg0 : (tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>) -> tensor<4x32xf32>
+ return %0 : tensor<4x32xf32>
+}
+
+// -----
+func.func @test_cast_bf16_block_scaled(%arg0: tensor<4x32xbf16>) -> tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>> {
+ // expected-error at +1 {{'tosa.cast' op illegal: requires all of [bf16, mx_common, mx_fp4e2m1] profiles/extensions to be specified in the target environment}}
+ %0 = tosa.cast %arg0 : (tensor<4x32xbf16>) -> tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>
+ return %0 : tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>
+}
+
+// -----
+func.func @test_cast_fp8_block_scaled(%arg0: tensor<4x32xf8E4M3FN>) -> tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:!tosa.mxint8>> {
+ // expected-error at +1 {{'tosa.cast' op illegal: requires all of [fp8e4m3, mx_common, mx_int8] profiles/extensions to be specified in the target environment}}
+ %0 = tosa.cast %arg0 : (tensor<4x32xf8E4M3FN>) -> tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:!tosa.mxint8>>
+ return %0 : tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:!tosa.mxint8>>
+}
+
// -----
func.func @test_fft2d(%arg0: tensor<1x4x8xf32>, %arg1: tensor<1x4x8xf32>) -> (tensor<1x4x8xf32>, tensor<1x4x8xf32>) {
// expected-error at +1 {{'tosa.fft2d' op illegal: requires any of [fft] profiles/extensions to be specified in the target environment}}
diff --git a/mlir/test/Dialect/Tosa/ops.mlir b/mlir/test/Dialect/Tosa/ops.mlir
index 262b8aa548506..ec3d0c881d857 100644
--- a/mlir/test/Dialect/Tosa/ops.mlir
+++ b/mlir/test/Dialect/Tosa/ops.mlir
@@ -1179,6 +1179,32 @@ func.func @test_cast3(%arg0: tensor<13x21x3xi32>) -> tensor<13x21x3x!quant.unifo
return %0 : tensor<13x21x3x!quant.uniform<i16:f32, 0.078431375324726104:128>>
}
+// -----
+// CHECK-LABEL: test_cast_to_block_scaled
+func.func @test_cast_to_block_scaled(%arg0: tensor<4x32xf32>, %arg1: tensor<4x32xbf16>, %arg2: tensor<4x32xf8E4M3FN>) -> (tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>, tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E3M2FN>>, tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:!tosa.mxint8>>) {
+ %0 = tosa.cast %arg0 : (tensor<4x32xf32>) -> tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>
+ %1 = tosa.cast %arg1 : (tensor<4x32xbf16>) -> tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E3M2FN>>
+ %2 = tosa.cast %arg2 : (tensor<4x32xf8E4M3FN>) -> tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:!tosa.mxint8>>
+ return %0, %1, %2 : tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>, tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E3M2FN>>, tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:!tosa.mxint8>>
+}
+
+// -----
+// CHECK-LABEL: test_cast_from_block_scaled
+func.func @test_cast_from_block_scaled(%arg0: tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E5M2>>, %arg1: tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E2M3FN>>, %arg2: tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:!tosa.mxint8>>) -> (tensor<4x32xf32>, tensor<4x32xbf16>, tensor<4x32xf8E5M2>) {
+ %0 = tosa.cast %arg0 : (tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E5M2>>) -> tensor<4x32xf32>
+ %1 = tosa.cast %arg1 : (tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E2M3FN>>) -> tensor<4x32xbf16>
+ %2 = tosa.cast %arg2 : (tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:!tosa.mxint8>>) -> tensor<4x32xf8E5M2>
+ return %0, %1, %2 : tensor<4x32xf32>, tensor<4x32xbf16>, tensor<4x32xf8E5M2>
+}
+
+// -----
+// CHECK-LABEL: test_cast_block_scaled_dynamic
+func.func @test_cast_block_scaled_dynamic(%arg0: tensor<?x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E5M2>>, %arg1: tensor<4x?x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E5M2>>) -> (tensor<?x32xf32>, tensor<4x?xf32>) {
+ %0 = tosa.cast %arg0 : (tensor<?x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E5M2>>) -> tensor<?x32xf32>
+ %1 = tosa.cast %arg1 : (tensor<4x?x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E5M2>>) -> tensor<4x?xf32>
+ return %0, %1 : tensor<?x32xf32>, tensor<4x?xf32>
+}
+
// -----
// CHECK-LABEL: rescale
func.func @test_rescale(%arg0: tensor<13x21x3x!quant.uniform<u8:f32, 0.015655439347028732:127>>) -> tensor<13x21x3x!quant.uniform<i8:f32, 0.015655439347028732:-1>> {
diff --git a/mlir/test/Dialect/Tosa/tosa-attach-target.mlir b/mlir/test/Dialect/Tosa/tosa-attach-target.mlir
index a0c59c0c4bb3b..558a599fbbc1e 100644
--- a/mlir/test/Dialect/Tosa/tosa-attach-target.mlir
+++ b/mlir/test/Dialect/Tosa/tosa-attach-target.mlir
@@ -1,11 +1,26 @@
-// RUN: mlir-opt %s -split-input-file -tosa-attach-target="profiles=pro_int,pro_fp extensions=int16,int4,bf16,fp8e4m3,fp8e5m2,fft,variable,controlflow,doubleround,inexactround,dynamic level=none" | FileCheck %s --check-prefix=CHECK-ALL
+// DEFINE: %{core_extensions} = int16,int4,bf16,fp8e4m3,fp8e5m2,fft,variable
+// DEFINE: %{rounding_extensions} = controlflow,doubleround,inexactround,dynamic
+// DEFINE: %{mx_float_extensions} = mx_common,mx_fp4e2m1,mx_fp6e2m3,mx_fp6e3m2
+// DEFINE: %{mx_int_extensions} = mx_fp8e4m3,mx_fp8e5m2,mx_int8
+// DEFINE: %{all_extensions} = %{core_extensions},%{rounding_extensions},%{mx_float_extensions},%{mx_int_extensions}
+// DEFINE: %{all_target} = specification_version=1.1.draft level=none \
+// DEFINE: profiles=pro_int,pro_fp extensions=%{all_extensions}
+
+// RUN: mlir-opt %s -split-input-file -tosa-attach-target="%{all_target}" | FileCheck %s --check-prefix=CHECK-ALL
// RUN: mlir-opt %s -split-input-file -tosa-attach-target="level=8k" | FileCheck %s --check-prefix=CHECK-LVL-8K
// RUN: mlir-opt %s -split-input-file -tosa-attach-target | FileCheck %s --check-prefix=CHECK-DEFAULT
// RUN: mlir-opt %s -split-input-file -tosa-attach-target="specification_version=1.1.draft" | FileCheck %s --check-prefix=CHECK-VERSION-1P1
// -----
-// CHECK-ALL: module attributes {tosa.target_env = #tosa.target_env<specification_version = "1.0", level = none, profiles = [pro_int, pro_fp], extensions = [int16, int4, bf16, fp8e4m3, fp8e5m2, fft, variable, controlflow, doubleround, inexactround, dynamic]>}
+// CHECK-ALL: module attributes {
+// CHECK-ALL-SAME: tosa.target_env = #tosa.target_env<specification_version = "1.1.draft",
+// CHECK-ALL-SAME: level = none,
+// CHECK-ALL-SAME: profiles = [pro_int, pro_fp],
+// CHECK-ALL-SAME: extensions = [int16, int4, bf16, fp8e4m3, fp8e5m2, fft,
+// CHECK-ALL-SAME: variable, controlflow, doubleround, inexactround, dynamic,
+// CHECK-ALL-SAME: mx_common, mx_fp4e2m1, mx_fp6e2m3, mx_fp6e3m2,
+// CHECK-ALL-SAME: mx_fp8e4m3, mx_fp8e5m2, mx_int8]>}
// CHECK-LVL-8K: module attributes {tosa.target_env = #tosa.target_env<specification_version = "1.0", level = "8k", profiles = [], extensions = []>}
// CHECK-DEFAULT: module attributes {tosa.target_env = #tosa.target_env<specification_version = "1.0", level = "8k", profiles = [], extensions = []>}
// CHECK-VERSION-1P1: module attributes {tosa.target_env = #tosa.target_env<specification_version = "1.1.draft", level = "8k", profiles = [], extensions = []>}
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 cbff768ec1ecb..a5e4d4397f290 100644
--- a/mlir/test/Dialect/Tosa/tosa-validation-version-1p0-invalid.mlir
+++ b/mlir/test/Dialect/Tosa/tosa-validation-version-1p0-invalid.mlir
@@ -154,6 +154,14 @@ func.func @test_cast_i64_bool(%arg0: tensor<13x21x3xi64>) -> tensor<13x21x3xi1>
// -----
+func.func @test_cast_fp32_block_scaled(%arg0: tensor<4x32xf32>) -> tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>> {
+ // expected-error at +1 {{'tosa.cast' op illegal: requires specification version compatible with 1.1.draft (got 1.0)}}
+ %0 = tosa.cast %arg0 : (tensor<4x32xf32>) -> tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>
+ return %0 : tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>
+}
+
+// -----
+
func.func @test_dyanmic_dims(%arg0: tensor<?x8x16xi8>) -> tensor<?x16xi32> {
// expected-error at +1 {{'tosa.argmax' op failed level check: operand shape dimension cannot be dynamic when targeting TOSA specification version 1.0 or below}}
%0 = tosa.argmax %arg0 { axis = 1 : i32 } : (tensor<?x8x16xi8>) -> tensor<?x16xi32>
diff --git a/mlir/test/Dialect/Tosa/tosa-validation-version-1p1-valid.mlir b/mlir/test/Dialect/Tosa/tosa-validation-version-1p1-valid.mlir
index f4b5ab5dd11fd..e7a4fe6735457 100644
--- a/mlir/test/Dialect/Tosa/tosa-validation-version-1p1-valid.mlir
+++ b/mlir/test/Dialect/Tosa/tosa-validation-version-1p1-valid.mlir
@@ -1,4 +1,4 @@
-// RUN: mlir-opt %s -split-input-file -verify-diagnostics -tosa-attach-target="specification_version=1.1.draft profiles=pro_int,pro_fp extensions=int16,int4,bf16,fp8e4m3,fp8e5m2,fft,variable,controlflow,doubleround,inexactround,mxfp,int64,mxfp_conv,shape" -tosa-validate="strict-op-spec-alignment" | FileCheck %s
+// RUN: mlir-opt %s -split-input-file -verify-diagnostics -tosa-attach-target="specification_version=1.1.draft profiles=pro_int,pro_fp extensions=int16,int4,bf16,fp8e4m3,fp8e5m2,fft,variable,controlflow,doubleround,inexactround,mxfp,int64,mxfp_conv,shape,mx_common,mx_fp4e2m1,mx_fp6e2m3,mx_fp6e3m2,mx_fp8e4m3,mx_fp8e5m2,mx_int8" -tosa-validate="strict-op-spec-alignment" | FileCheck %s
// -----
@@ -389,6 +389,34 @@ func.func @test_cast_i64_bool(%arg0: tensor<13x21x3xi64>) -> tensor<13x21x3xi1>
// -----
+// CHECK-LABEL: test_cast_to_block_scaled_types
+func.func @test_cast_to_block_scaled_types(%fp16: tensor<4x32xf16>, %fp32: tensor<4x32xf32>, %bf16: tensor<4x32xbf16>, %fp8e4m3: tensor<4x32xf8E4M3FN>, %fp8e5m2: tensor<4x32xf8E5M2>) -> (tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>, tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E2M3FN>>, tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E3M2FN>>, tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN>>, tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E5M2>>, tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:!tosa.mxint8>>) {
+ %0 = tosa.cast %fp32 : (tensor<4x32xf32>) -> tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>
+ %1 = tosa.cast %fp32 : (tensor<4x32xf32>) -> tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E2M3FN>>
+ %2 = tosa.cast %fp32 : (tensor<4x32xf32>) -> tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E3M2FN>>
+ %3 = tosa.cast %fp16 : (tensor<4x32xf16>) -> tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN>>
+ %4 = tosa.cast %bf16 : (tensor<4x32xbf16>) -> tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E5M2>>
+ %5 = tosa.cast %fp8e4m3 : (tensor<4x32xf8E4M3FN>) -> tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:!tosa.mxint8>>
+ %6 = tosa.cast %fp8e5m2 : (tensor<4x32xf8E5M2>) -> tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E2M3FN>>
+ return %0, %1, %2, %3, %4, %5 : tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>, tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E2M3FN>>, tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E3M2FN>>, tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN>>, tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E5M2>>, tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:!tosa.mxint8>>
+}
+
+// -----
+
+// CHECK-LABEL: test_cast_from_block_scaled_types
+func.func @test_cast_from_block_scaled_types(%fp4: tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>, %fp6e2m3: tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E2M3FN>>, %fp6e3m2: tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E3M2FN>>, %fp8e4m3: tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN>>, %fp8e5m2: tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E5M2>>, %mxint8: tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:!tosa.mxint8>>) -> (tensor<4x32xf32>, tensor<4x32xf16>, tensor<4x32xbf16>, tensor<4x32xf8E4M3FN>, tensor<4x32xf8E5M2>) {
+ %0 = tosa.cast %fp4 : (tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>) -> tensor<4x32xf32>
+ %1 = tosa.cast %fp6e2m3 : (tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E2M3FN>>) -> tensor<4x32xf32>
+ %2 = tosa.cast %fp6e3m2 : (tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f6E3M2FN>>) -> tensor<4x32xf32>
+ %3 = tosa.cast %fp8e4m3 : (tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN>>) -> tensor<4x32xf16>
+ %4 = tosa.cast %fp8e5m2 : (tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E5M2>>) -> tensor<4x32xbf16>
+ %5 = tosa.cast %mxint8 : (tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:!tosa.mxint8>>) -> tensor<4x32xf8E4M3FN>
+ %6 = tosa.cast %fp4 : (tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>) -> tensor<4x32xf8E5M2>
+ return %0, %3, %4, %5, %6 : tensor<4x32xf32>, tensor<4x32xf16>, tensor<4x32xbf16>, tensor<4x32xf8E4M3FN>, tensor<4x32xf8E5M2>
+}
+
+// -----
+
// CHECK-LABEL: test_dynamic_dims
func.func @test_dynamic_dims(%arg0: tensor<?x8x16xi8>) -> tensor<?x16xi32> {
%0 = tosa.argmax %arg0 { axis = 1 : i32 } : (tensor<?x8x16xi8>) -> tensor<?x16xi32>
diff --git a/mlir/test/Dialect/Tosa/verifier.mlir b/mlir/test/Dialect/Tosa/verifier.mlir
index 0eb679ca7ced3..20c0dfd2a094c 100644
--- a/mlir/test/Dialect/Tosa/verifier.mlir
+++ b/mlir/test/Dialect/Tosa/verifier.mlir
@@ -1650,6 +1650,48 @@ func.func @test_cast_to_block_scaled_block_size_mismatch(%arg0: tensor<4x32xf32>
// -----
+func.func @test_cast_i8_block_scaled(%arg0: tensor<4x32xi8>) -> tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>> {
+ // expected-error at +1 {{'tosa.cast' op requires non-block-scaled element type to be floating-point when casting to or from block scaled element type, got 'i8'}}
+ %0 = tosa.cast %arg0 : (tensor<4x32xi8>) -> tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>
+ return %0 : tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>
+}
+
+// -----
+
+func.func @test_cast_block_scaled_i32(%arg0: tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>) -> tensor<4x32xi32> {
+ // expected-error at +1 {{'tosa.cast' op requires non-block-scaled element type to be floating-point when casting to or from block scaled element type, got 'i32'}}
+ %0 = tosa.cast %arg0 : (tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>) -> tensor<4x32xi32>
+ return %0 : tensor<4x32xi32>
+}
+
+// -----
+
+func.func @test_cast_between_block_scaled(%arg0: tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>) -> tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN>> {
+ // expected-error at +1 {{'tosa.cast' op requires exactly one of input or output to have block scaled element type}}
+ %0 = tosa.cast %arg0 : (tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>) -> tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN>>
+ return %0 : tensor<4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN>>
+}
+
+// -----
+
+func.func @test_block_scaled_cast_invalid_block_shape(%arg0: tensor<1x16x31x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN>>) -> tensor<1x16x31xf32> {
+ // expected-error at +2 {{tensor type 'tensor<1x16x31x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN>>' blocked dimension must be a multiple of block size, got 31 and block size 32}}
+ // expected-error at +1 {{'tosa.cast' op operand #0 must be tosa-conformant tensor of number values, but got 'tensor<1x16x31x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN>>'}}
+ %0 = tosa.cast %arg0 : (tensor<1x16x31x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN>>) -> tensor<1x16x31xf32>
+ return %0 : tensor<1x16x31xf32>
+}
+
+// -----
+
+func.func @test_block_scaled_cast_scalar(%arg0: tensor<!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN>>) -> tensor<f32> {
+ // expected-error at +2 {{tensor type 'tensor<!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN>>' does not support block scaling on scalar tensors}}
+ // expected-error at +1 {{'tosa.cast' op operand #0 must be tosa-conformant tensor of number values, but got 'tensor<!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN>>'}}
+ %0 = tosa.cast %arg0 : (tensor<!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN>>) -> tensor<f32>
+ return %0 : tensor<f32>
+}
+
+// -----
+
func.func @test_clamp_quantized(%arg0:tensor<?x112x112x32x!quant.uniform<u8:f32, 0.023529412224888802:-128>>) -> (tensor<?x112x112x32x!quant.uniform<u8:f32, 0.023529412224888802:-128>>) {
// expected-error at +1 {{'tosa.clamp' op min/max attributes types are incompatible with input/output element types.}}
%0 = tosa.clamp %arg0 {max_val = 127 : i8, min_val = -128 : i8} : (tensor<?x112x112x32x!quant.uniform<u8:f32, 0.023529412224888802:-128>>) -> tensor<?x112x112x32x!quant.uniform<u8:f32, 0.023529412224888802:-128>>
More information about the Mlir-commits
mailing list