[Mlir-commits] [mlir] 658b3a9 - [mlir][tosa] Add more informative error messages to block scaled types (#211569)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Fri Aug 7 02:27:34 PDT 2026
Author: Luke Hutton
Date: 2026-08-07T10:27:29+01:00
New Revision: 658b3a9aa098fa8a03561ed9a5c56db1962b9b23
URL: https://github.com/llvm/llvm-project/commit/658b3a9aa098fa8a03561ed9a5c56db1962b9b23
DIFF: https://github.com/llvm/llvm-project/commit/658b3a9aa098fa8a03561ed9a5c56db1962b9b23.diff
LOG: [mlir][tosa] Add more informative error messages to block scaled types (#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.
Added:
Modified:
mlir/include/mlir/Dialect/Tosa/IR/TosaOps.h
mlir/include/mlir/Dialect/Tosa/IR/TosaTypesBase.td
mlir/include/mlir/IR/CommonTypeConstraints.td
mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
mlir/test/Dialect/Tosa/verifier.mlir
Removed:
################################################################################
diff --git a/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.h b/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.h
index 240988f8beb21..db16c74e659cc 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.
//===----------------------------------------------------------------------===//
@@ -135,9 +137,15 @@ 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);
+
+// Returns a diagnostic suffix string for a type verification failure, or
+// empty string if the type is valid
+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..b5701853aaf68 100644
--- a/mlir/include/mlir/Dialect/Tosa/IR/TosaTypesBase.td
+++ b/mlir/include/mlir/Dialect/Tosa/IR/TosaTypesBase.td
@@ -172,7 +172,13 @@ 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))">;
+
+// Add 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"> :
+ ShapedContainerType<allowedTypes, containerPred, descr, cppType, "{{::mlir::tosa::getTosaTensorTypeErrorMessage($_self)}}">;
// 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 +187,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/include/mlir/IR/CommonTypeConstraints.td b/mlir/include/mlir/IR/CommonTypeConstraints.td
index af57542fde847..8dbd7ac4b9760 100644
--- a/mlir/include/mlir/IR/CommonTypeConstraints.td
+++ b/mlir/include/mlir/IR/CommonTypeConstraints.td
@@ -426,13 +426,14 @@ class ContainerType<Type etype, Pred containerPred, code elementTypeCall,
class ShapedContainerType<list<Type> allowedTypes,
Pred containerPred, string descr,
- string cppType = "::mlir::Type"> :
+ string cppType = "::mlir::Type",
+ string summary = ""> :
Type<And<[containerPred,
Concat<"[](::mlir::Type elementType) { return ",
SubstLeaves<"$_self", "elementType",
AnyTypeOf<allowedTypes>.predicate>,
"; }(::llvm::cast<::mlir::ShapedType>($_self).getElementType())">]>,
- descr # " of " # AnyTypeOf<allowedTypes>.summary # " values", cppType>;
+ descr # " of " # AnyTypeOf<allowedTypes>.summary # " values" # summary, cppType>;
// Whether a shaped type is ranked.
def HasRankPred : CPred<"::llvm::cast<::mlir::ShapedType>($_self).hasRank()">;
diff --git a/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp b/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
index d8420909b2844..6b76acb2752da 100644
--- a/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
+++ b/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
@@ -739,22 +739,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 =
@@ -763,19 +772,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) {
@@ -962,9 +999,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 0e3cdbcb7149d..061ea403a40b5 100644
--- a/mlir/test/Dialect/Tosa/verifier.mlir
+++ b/mlir/test/Dialect/Tosa/verifier.mlir
@@ -1716,7 +1716,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>
}
@@ -1724,7 +1724,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>
}
@@ -2357,7 +2357,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>
}
@@ -2365,7 +2365,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>>
}
@@ -2373,7 +2373,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