[Mlir-commits] [mlir] [mlir][tosa] Add more informative error messages to block scaled types (PR #211569)
Luke Hutton
llvmlistbot at llvm.org
Thu Jul 23 07:38:38 PDT 2026
https://github.com/lhutton1 created https://github.com/llvm/llvm-project/pull/211569
This commit improves block scaled tensor type verification to provide a specific reason about why type verification failed. Previously the error message was a very generic "must be tosa-conformant tensor of number values".
This commit restores previous functionality that was reverted by https://github.com/llvm/llvm-project/pull/207995, but uses the ODS string interpolation mechanism instead to prevent incompatibility with PDLL.
>From 13ca3e97bb22a18e4fa06550dbfd75cf0e86d2be Mon Sep 17 00:00:00 2001
From: Luke Hutton <luke.hutton at arm.com>
Date: Wed, 15 Jul 2026 11:31:41 +0100
Subject: [PATCH] [mlir][tosa] Add more informative error messages to block
scaled types
This commit improves block scaled tensor type verification to provide
a specific reason about why type verification failed. Previously the
error message was a very generic
"must be tosa-conformant tensor of number values".
This commit resores previous functionality that was reverted by
https://github.com/llvm/llvm-project/pull/207995, but uses the ODS
string interpolation mechanism instead to prevent incompatibility
with PDLL.
Change-Id: I07f74efe8da9b3bdbae46fd14704d47ab96ec174
---
mlir/include/mlir/Dialect/Tosa/IR/TosaOps.h | 13 ++++-
.../mlir/Dialect/Tosa/IR/TosaTypesBase.td | 22 +++++--
mlir/lib/Dialect/Tosa/IR/TosaOps.cpp | 58 ++++++++++++++++---
mlir/test/Dialect/Tosa/verifier.mlir | 10 ++--
4 files changed, 81 insertions(+), 22 deletions(-)
diff --git a/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.h b/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.h
index b1404d9c700ae..2c4d3b7446544 100644
--- a/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.h
+++ b/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.h
@@ -25,6 +25,8 @@
#include "mlir/Interfaces/SideEffectInterfaces.h"
#include "mlir/Interfaces/VectorInterfaces.h"
+#include <string>
+
//===----------------------------------------------------------------------===//
// TOSA dialect and structs includes.
//===----------------------------------------------------------------------===//
@@ -141,9 +143,14 @@ Type getStorageElementTypeOrSelf(Type type);
// Returns the storage element type for a given value
Type getStorageElementTypeOrSelf(Value value);
-// Verify a block scaled tensor type is valid
-LogicalResult verifyBlockScaledTensorType(mlir::Type type,
- bool allowScaleValues);
+// Verify that a given type is a valid block scaled tensor type
+LogicalResult verifyBlockScaledTensorType(
+ mlir::Type type,
+ llvm::function_ref<mlir::InFlightDiagnostic()> emitError = nullptr,
+ bool allowScaleValues = false);
+
+// Collect error messages for a given type
+std::string getTosaTensorTypeErrorMessage(mlir::Type type);
} // namespace tosa
} // namespace mlir
diff --git a/mlir/include/mlir/Dialect/Tosa/IR/TosaTypesBase.td b/mlir/include/mlir/Dialect/Tosa/IR/TosaTypesBase.td
index 2ab135befaa96..9252223cadb3c 100644
--- a/mlir/include/mlir/Dialect/Tosa/IR/TosaTypesBase.td
+++ b/mlir/include/mlir/Dialect/Tosa/IR/TosaTypesBase.td
@@ -172,7 +172,19 @@ def AtLeastRankOne : And<[
CPred<"::llvm::cast<::mlir::RankedTensorType>($_self).getRank() >= 1">]>;
def IsValidBlockScaledTensorType
- : CPred<"::mlir::succeeded(::mlir::tosa::verifyBlockScaledTensorType($_self, false))">;
+ : CPred<"::mlir::succeeded(::mlir::tosa::"
+ "verifyBlockScaledTensorType($_self))">;
+
+// Analogous to ShapedContainerType, but with additional 'summary' information.
+// This is used to provide more informative error messages when a type predicate
+// is false.
+class TosaShapedContainerType<list<Type> allowedTypes, Pred containerPred, string descr, string cppType = "::mlir::Type"> :
+ Type<And<[containerPred,
+ Concat<"[](::mlir::Type elementType) { return ",
+ SubstLeaves<"$_self", "elementType",
+ AnyTypeOf<allowedTypes>.predicate>,
+ "; }(getElementTypeOrSelf($_self))">]>,
+ descr # " of " # AnyTypeOf<allowedTypes>.summary # " values" # "{{::mlir::tosa::getTosaTensorTypeErrorMessage($_self)}}", cppType>;
// We include unranked tensors as a supported type for all possible tosa
// Tensors as unranked does not guarantee invalid. If unranked tensors exist
@@ -181,13 +193,13 @@ def IsValidBlockScaledTensorType
class TosaTensorOf<list<Type> allowedTypes,
list<Pred> extraRankedTensorPreds = [],
string summary = "tosa-conformant tensor">
- : TensorOf<allowedTypes,
- [Or<[
+ : TosaShapedContainerType<allowedTypes,
+ And<[Or<[
IsUnrankedTensorTypePred,
And<!listconcat([IsRankedTensorTypePred, HasNo0Dimensions], extraRankedTensorPreds)>
]>,
- IsValidBlockScaledTensorType],
- summary>;
+ IsValidBlockScaledTensorType]>,
+ summary, "::mlir::TensorType">;
class TosaTensorRankOf<list<Type> allowedTypes, list<int> ranks>
: TosaTensorOf<allowedTypes,
diff --git a/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp b/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
index 0dfcd23504019..7bfc3de98d08c 100644
--- a/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
+++ b/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
@@ -741,22 +741,31 @@ LogicalResult mlir::tosa::mxint8Type::convertFromAttribute(
// TOSA block scaling utilities.
//===----------------------------------------------------------------------===//
-LogicalResult mlir::tosa::verifyBlockScaledTensorType(mlir::Type type,
- bool allowScaleValues) {
+LogicalResult mlir::tosa::verifyBlockScaledTensorType(
+ mlir::Type type, llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
+ bool allowScaleValues) {
const auto tensorType = llvm::cast<ShapedType>(type);
const BlockScaledType elemType =
llvm::dyn_cast<BlockScaledType>(tensorType.getElementType());
if (!elemType)
return success();
- if (!allowScaleValues && elemType.hasScaleValues())
+ if (!allowScaleValues && elemType.hasScaleValues()) {
+ if (emitError)
+ emitError()
+ << "block scaled tensor type with scale values is not allowed";
return failure();
+ }
if (!tensorType.hasRank())
return success();
- if (tensorType.getRank() == 0)
+ if (tensorType.getRank() == 0) {
+ if (emitError)
+ emitError() << "block scaled tensor type must have rank greater than "
+ "zero";
return failure();
+ }
const ArrayRef<int64_t> tensorShape = tensorType.getShape();
const uint32_t blockSize =
@@ -765,19 +774,47 @@ LogicalResult mlir::tosa::verifyBlockScaledTensorType(mlir::Type type,
if (allowScaleValues && elemType.hasScaleValues() &&
tensorType.hasStaticShape()) {
const size_t numBlocks = tensorType.getNumElements() / blockSize;
- if (elemType.getScaleValues().size() != numBlocks)
+ if (elemType.getScaleValues().size() != numBlocks) {
+ if (emitError)
+ emitError() << "block scaled tensor type with scale values must have "
+ "scale values for each block, expected "
+ << numBlocks << ", got "
+ << elemType.getScaleValues().size();
return failure();
+ }
}
const int64_t blockedDimension = tensorShape.back();
if (ShapedType::isDynamic(blockedDimension))
return success();
- if (blockedDimension % blockSize != 0)
+
+ if (blockedDimension % blockSize != 0) {
+ if (emitError)
+ emitError() << "last dimension of block scaled tensor type ("
+ << blockedDimension << ") must be divisible by block size ("
+ << blockSize << ")";
+
return failure();
+ }
return success();
}
+std::string mlir::tosa::getTosaTensorTypeErrorMessage(mlir::Type type) {
+ MLIRContext *ctx = type.getContext();
+ std::string message;
+ ScopedDiagnosticHandler handler(
+ ctx, [&](Diagnostic &diag) { message = diag.str(); });
+
+ if (failed(verifyBlockScaledTensorType(
+ type, [ctx] { return emitError(UnknownLoc::get(ctx)); })) &&
+ !message.empty()) {
+ return ": " + message;
+ }
+
+ return "";
+}
+
static ParseResult parseScaleValues(AsmParser &parser,
SmallVector<Attribute> &scaleValues,
Type scaleType) {
@@ -964,9 +1001,12 @@ LogicalResult tosa::ConstOp::verify() {
return op.emitOpError(
"attribute block scaled type must have scale values");
- if (failed(verifyBlockScaledTensorType(attrType, true)))
- return op.emitOpError("block scaled attribute type is not valid, got ")
- << attrType;
+ const auto emitAttributeError = [&op]() {
+ return op.emitOpError("attribute block scaled type is invalid: ");
+ };
+
+ if (failed(verifyBlockScaledTensorType(attrType, emitAttributeError, true)))
+ return failure();
const BlockScaledType resultBlockScaledType =
llvm::dyn_cast<mlir::tosa::BlockScaledType>(resultElemType);
diff --git a/mlir/test/Dialect/Tosa/verifier.mlir b/mlir/test/Dialect/Tosa/verifier.mlir
index ba69e4aba632e..f23f822546bb4 100644
--- a/mlir/test/Dialect/Tosa/verifier.mlir
+++ b/mlir/test/Dialect/Tosa/verifier.mlir
@@ -1705,7 +1705,7 @@ func.func @test_cast_between_block_scaled(%arg0: tensor<4x32x!tosa.block_scaled<
// -----
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 +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>>'}}
+ // expected-error at +1 {{'tosa.cast' op operand #0 must be tosa-conformant tensor of number values: last dimension of block scaled tensor type (31) must be divisible by block size (32), 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>
}
@@ -1713,7 +1713,7 @@ func.func @test_block_scaled_cast_invalid_block_shape(%arg0: tensor<1x16x31x!tos
// -----
func.func @test_block_scaled_cast_scalar(%arg0: tensor<!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN>>) -> tensor<f32> {
- // 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>>'}}
+ // expected-error at +1 {{'tosa.cast' op operand #0 must be tosa-conformant tensor of number values: block scaled tensor type must have rank greater than zero, 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>
}
@@ -2346,7 +2346,7 @@ func.func @test_block_scaled_const_scale_value_non_float_explicit_type() -> tens
!mxint8_scale = !tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:!tosa.mxint8, {1.0, 2.0, 4.0}>
func.func @test_block_scaled_const_invalid_num_scales() -> tensor<2x32x!mxint8> {
- // expected-error at +1 {{'tosa.const' op block scaled attribute type is not valid, got 'tensor<2x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:!tosa.mxint8, {1.000000e+00, 2.000000e+00, 4.000000e+00}>>'}}
+ // expected-error at +1 {{'tosa.const' op attribute block scaled type is invalid: block scaled tensor type with scale values must have scale values for each block, expected 2, got 3}}
%0 = "tosa.const"() <{values = dense<tensor<2x32x!mxint8_scale> : 0 : i8>}> : () -> tensor<2x32x!mxint8>
return %0 : tensor<2x32x!mxint8>
}
@@ -2354,7 +2354,7 @@ func.func @test_block_scaled_const_invalid_num_scales() -> tensor<2x32x!mxint8>
// -----
func.func @test_block_scaled_const_invalid_num_scales_wide_inner_dim() -> tensor<2x64x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:!tosa.mxint8>> {
- // expected-error at +1 {{'tosa.const' op block scaled attribute type is not valid, got 'tensor<2x64x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:!tosa.mxint8, {1.000000e+00, 2.000000e+00}>>'}}
+ // expected-error at +1 {{'tosa.const' op attribute block scaled type is invalid: block scaled tensor type with scale values must have scale values for each block, expected 4, got 2}}
%0 = "tosa.const"() <{values = dense<tensor<2x64x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:!tosa.mxint8, {1.0, 2.0}>> : 0 : i8>}> : () -> tensor<2x64x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:!tosa.mxint8>>
return %0 : tensor<2x64x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:!tosa.mxint8>>
}
@@ -2362,7 +2362,7 @@ func.func @test_block_scaled_const_invalid_num_scales_wide_inner_dim() -> tensor
// -----
func.func @test_block_scaled_const_cast_scale_values_propagate() -> tensor<2x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN, {2.0, 4.0}>> {
- // expected-error at +1 {{'tosa.const' op result #0 must be tosa-conformant tensor of number values, but got 'tensor<2x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN, {2.000000e+00, 4.000000e+00}>>'}}
+ // expected-error at +1 {{'tosa.const' op result #0 must be tosa-conformant tensor of number values: block scaled tensor type with scale values is not allowed, but got 'tensor<2x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN, {2.000000e+00, 4.000000e+00}>>'}}
%0 = "tosa.const"() <{values = dense<tensor<2x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN, {2.0, 4.0}>> : 0.0 : f8E4M3FN>}> : () -> tensor<2x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN, {2.0, 4.0}>>
return %0 : tensor<2x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN, {2.0, 4.0}>>
}
More information about the Mlir-commits
mailing list