[Mlir-commits] [mlir] [mlir][tosa] Move SLICE constant-operand checks to tosa-validate (PR #234584)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Thu Oct 22 04:21:37 PDT 2026
https://github.com/Wijkqwe created https://github.com/llvm/llvm-project/pull/234584
Part of #233457.
`SliceOp::verify()` reads start/size from their tosa.const_shape producers
and checks their values, which is not local to the operation. Move the
ERROR_IF conditions to checkErrorIfSlice():
- ERROR_IF(any(start < 0))
- ERROR_IF(any(size <= 0))
- ERROR_IF(is_block_scale && start[rank - 1] % innermost_block_size != 0)
Drop the two MLIR-specific consistency checks (output shape matching the
size values, start + size within input bounds), following #233064.
This also fixes a latent out-of-bounds access: the block-scaled alignment
check called startValues.back() without guarding against a non-constant
start, which left startValues empty. tosa.dim satisfies the
TosaResolvableShapeOperands trait but does not resolve to constants, so
this was reachable and aborted the verifier. A regression test covers it.
Assisted-by: AI.
>From 1613f369f99b074b93ff782c25c1d90b22756ce8 Mon Sep 17 00:00:00 2001
From: wzy <WZYqwe2004 at outlook.com>
Date: Thu, 22 Oct 2026 17:08:01 +0800
Subject: [PATCH 1/3] it just works
---
mlir/lib/Dialect/Tosa/IR/TosaOps.cpp | 62 -------------------
.../Tosa/Transforms/TosaValidation.cpp | 28 +++++++++
2 files changed, 28 insertions(+), 62 deletions(-)
diff --git a/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp b/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
index 99c352ab8ed3c3..7bb798c2397fb1 100644
--- a/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
+++ b/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
@@ -2452,68 +2452,6 @@ LogicalResult tosa::SliceOp::verify() {
return emitOpError("length of size is not equal to rank of input shape");
}
- SmallVector<int64_t> startValues;
- tosa::getConstShapeValues(start.getDefiningOp(), startValues);
- if (startValues.size()) {
- if (llvm::any_of(startValues, [](const int64_t v) {
- return v < 0 && v != kInferableDimSize;
- }))
- return emitOpError("start values must be non-negative, got [")
- << startValues << "]";
- }
-
- // ERROR_IF(is_block_scale<in_out_t>() && start[rank(shape1) - 1] %
- // get_innermost_block_size<in_out_t>() != 0);
- const auto elemType = getElementTypeOrSelf(input.getType());
- if (const auto blockScaledType = llvm::dyn_cast<BlockScaledType>(elemType)) {
- const auto startBlock = startValues.back();
- const auto scaleBlock =
- BlockShapeAttr::getBlockShapeValue(blockScaledType.getBlockShape());
- if (startBlock % scaleBlock != 0) {
- return emitOpError(
- "expected start innermost block size to match data type "
- "for block scaled input, got start block=")
- << startBlock << ", scale block=" << scaleBlock;
- }
- }
-
- SmallVector<int64_t> sizeValues;
- if (!tosa::getConstShapeValues(size.getDefiningOp(), sizeValues))
- return success();
-
- if (llvm::any_of(sizeValues, [](const int64_t v) {
- return v <= 0 && v != kInferableDimSize;
- }))
- return emitOpError("size values must be > 0, got [") << sizeValues << "]";
- if (outputShape.hasRank()) {
- SmallVector<int64_t> outputDims;
- outputShape.getDims(outputDims);
- const bool hasNoInferableDims = llvm::all_of(
- sizeValues, [](const int64_t v) { return v != kInferableDimSize; });
- if (hasNoInferableDims &&
- failed(verifyCompatibleShape(outputDims, sizeValues)))
- return emitOpError("expected output shape to match size values, got ")
- << output.getType() << " vs [" << sizeValues << "]";
- }
-
- if (inputShape.hasRank() && startValues.size()) {
- SmallVector<int64_t> inputDims;
- inputShape.getDims(inputDims);
- for (const auto &[index, vals] :
- llvm::enumerate(llvm::zip_equal(startValues, sizeValues, inputDims))) {
- const auto &[start, size, inputDim] = vals;
- if (start == kInferableDimSize || size == kInferableDimSize ||
- ShapedType::isDynamic(inputDim))
- continue;
- if (start + size > inputDim)
- return emitOpError("start + size must be less than or equal to input "
- "dimension size, got start=")
- << start << ", size=" << size
- << " vs input dim size=" << inputDim << " at dimension "
- << index;
- }
- }
-
return success();
}
diff --git a/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp b/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
index 5d465065497abf..3615a6078790a8 100644
--- a/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
+++ b/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
@@ -1408,6 +1408,34 @@ LogicalResult checkErrorIfSlice(Operation *op) {
<< ") which "
"does not conform to the TOSA specification";
+ // ERROR_IF(any(start < 0))
+ if (hasStartValues &&
+ llvm::any_of(startValues, [](int64_t v) { return v < 0; }))
+ return op->emitOpError("start values must be non-negative, got [")
+ << startValues << "]";
+
+ // ERROR_IF(any(size <= 0))
+ if (hasSizeValues &&
+ llvm::any_of(sizeValues, [](int64_t v) { return v <= 0; }))
+ return op->emitOpError("size values must be > 0, got [") << sizeValues
+ << "]";
+
+ // ERROR_IF(is_block_scale<in_out_t>() && start[rank(shape1) - 1] %
+ // get_innermost_block_size<in_out_t>() != 0)
+ if (hasStartValues) {
+ auto elemType = getElementTypeOrSelf(sliceOp.getInput1().getType());
+ if (auto blockScaledType = dyn_cast<BlockScaledType>(elemType)) {
+ const int64_t startBlock = startValues.back();
+ const int64_t scaleBlock =
+ BlockShapeAttr::getBlockShapeValue(blockScaledType.getBlockShape());
+ if (startBlock % scaleBlock != 0)
+ return op->emitOpError(
+ "expected start innermost block size to match data type "
+ "for block scaled input, got start block=")
+ << startBlock << ", scale block=" << scaleBlock;
+ }
+ }
+
return success();
}
>From e186821de847cabcb9f2b4d078941fab2674d8ea Mon Sep 17 00:00:00 2001
From: wzy <WZYqwe2004 at outlook.com>
Date: Thu, 22 Oct 2026 17:08:13 +0800
Subject: [PATCH 2/3] tests
---
mlir/test/Dialect/Tosa/error_if_check.mlir | 20 +++++
.../tosa-validation-version-1p1-invalid.mlir | 13 +++-
mlir/test/Dialect/Tosa/verifier.mlir | 76 ++++---------------
3 files changed, 48 insertions(+), 61 deletions(-)
diff --git a/mlir/test/Dialect/Tosa/error_if_check.mlir b/mlir/test/Dialect/Tosa/error_if_check.mlir
index b87f124f64ac27..2149e1d00ea29d 100644
--- a/mlir/test/Dialect/Tosa/error_if_check.mlir
+++ b/mlir/test/Dialect/Tosa/error_if_check.mlir
@@ -356,3 +356,23 @@ func.func @test_matmul_rank3_rhs_broadcast_dynamic_lhs(%arg0: tensor<?x4x7xf32>,
%0 = tosa.matmul %arg0, %arg1, %azp0, %bzp0 : (tensor<?x4x7xf32>, tensor<1x7x5xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<2x4x5xf32>
return %0 : tensor<2x4x5xf32>
}
+
+// -----
+
+func.func @test_slice_invalid_start_values(%arg0: tensor<4x31x31xf32>) {
+ %start = tosa.const_shape values(dense<[-2, 0, 0]> : tensor<3xindex>) : () -> !tosa.shape<3>
+ %size = tosa.const_shape values(dense<[1, 1, 1]> : tensor<3xindex>) : () -> !tosa.shape<3>
+ // expected-error at +1 {{'tosa.slice' op start values must be non-negative, got [-2, 0, 0]}}
+ %1 = tosa.slice %arg0, %start, %size : (tensor<4x31x31xf32>, !tosa.shape<3>, !tosa.shape<3>) -> tensor<1x1x1xf32>
+ return
+}
+
+// -----
+
+func.func @test_slice_invalid_size_values(%arg0: tensor<4x31x31xf32>) {
+ %start = tosa.const_shape values(dense<[0, 0, 0]> : tensor<3xindex>) : () -> !tosa.shape<3>
+ %size = tosa.const_shape values(dense<[1, 0, 1]> : tensor<3xindex>) : () -> !tosa.shape<3>
+ // expected-error at +1 {{'tosa.slice' op size values must be > 0, got [1, 0, 1]}}
+ %1 = tosa.slice %arg0, %start, %size : (tensor<4x31x31xf32>, !tosa.shape<3>, !tosa.shape<3>) -> tensor<?x?x?xf32>
+ return
+}
diff --git a/mlir/test/Dialect/Tosa/tosa-validation-version-1p1-invalid.mlir b/mlir/test/Dialect/Tosa/tosa-validation-version-1p1-invalid.mlir
index a68807fa7bb2fb..ee5a1b2ee0132f 100644
--- a/mlir/test/Dialect/Tosa/tosa-validation-version-1p1-invalid.mlir
+++ b/mlir/test/Dialect/Tosa/tosa-validation-version-1p1-invalid.mlir
@@ -1,4 +1,4 @@
-// RUN: mlir-opt %s -split-input-file -verify-diagnostics -tosa-attach-target="specification_version=1.1.draft profiles=pro_fp" -tosa-validate="strict-op-spec-alignment"
+// RUN: mlir-opt %s -split-input-file -verify-diagnostics -tosa-attach-target="specification_version=1.1.draft profiles=pro_fp extensions=mx_common,mx_fp4e2m1" -tosa-validate="strict-op-spec-alignment"
// -----
@@ -32,3 +32,14 @@ module {
// expected-error at +1 {{'tosa.variable' op is not profile-aligned: element type 'f64' is not legal}}
tosa.variable @dynamic_var : tensor<2x?xf64>
}
+
+// -----
+
+func.func @test_slice_block_scaled_invalid_block_size(%arg0: tensor<4x4x64x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>) -> tensor<1x1x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>> {
+ %start = tosa.const_shape values(dense<[0, 0, 1]> : tensor<3xindex>) : () -> !tosa.shape<3>
+ %size = tosa.const_shape values(dense<[1, 1, 32]> : tensor<3xindex>) : () -> !tosa.shape<3>
+ // expected-error at +1 {{'tosa.slice' op expected start innermost block size to match data type for block scaled input, got start block=1, scale block=32}}
+ %0 = tosa.slice %arg0, %start, %size {input_unsigned = false} : (tensor<4x4x64x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>, !tosa.shape<3>, !tosa.shape<3>) -> tensor<1x1x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>
+ return %0 : tensor<1x1x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>
+}
+
diff --git a/mlir/test/Dialect/Tosa/verifier.mlir b/mlir/test/Dialect/Tosa/verifier.mlir
index 4eb15048e7d80f..8a907da90f1035 100644
--- a/mlir/test/Dialect/Tosa/verifier.mlir
+++ b/mlir/test/Dialect/Tosa/verifier.mlir
@@ -205,56 +205,6 @@ func.func @test_scalar_slice(%arg0: tensor<f32>) -> tensor<f32> {
// -----
-func.func @test_slice_invalid_start_values(%arg0: tensor<4x31x31xf32>) {
- %start = tosa.const_shape values(dense<[-2, 0, 0]> : tensor<3xindex>) : () -> !tosa.shape<3>
- %size = tosa.const_shape values(dense<[1, 1, 1]> : tensor<3xindex>) : () -> !tosa.shape<3>
- // expected-error at +1 {{'tosa.slice' op start values must be non-negative, got [-2, 0, 0]}}
- %1 = tosa.slice %arg0, %start, %size : (tensor<4x31x31xf32>, !tosa.shape<3>, !tosa.shape<3>) -> tensor<1x1x1xf32>
- return
-}
-
-// -----
-
-func.func @test_slice_invalid_size_values(%arg0: tensor<4x31x31xf32>) {
- %start = tosa.const_shape values(dense<[0, 0, 0]> : tensor<3xindex>) : () -> !tosa.shape<3>
- %size = tosa.const_shape values(dense<[1, 0, 1]> : tensor<3xindex>) : () -> !tosa.shape<3>
- // expected-error at +1 {{'tosa.slice' op size values must be > 0, got [1, 0, 1]}}
- %1 = tosa.slice %arg0, %start, %size : (tensor<4x31x31xf32>, !tosa.shape<3>, !tosa.shape<3>) -> tensor<?x?x?xf32>
- return
-}
-
-// -----
-
-func.func @test_slice_output_shape_mismatch(%arg0: tensor<4x5x6xf32>) {
- %start = tosa.const_shape values(dense<[0, 0, 0]> : tensor<3xindex>) : () -> !tosa.shape<3>
- %size = tosa.const_shape values(dense<[1, 2, 3]> : tensor<3xindex>) : () -> !tosa.shape<3>
- // expected-error at +1 {{'tosa.slice' op expected output shape to match size values, got 'tensor<1x2x4xf32>' vs [1, 2, 3]}}
- %1 = tosa.slice %arg0, %start, %size : (tensor<4x5x6xf32>, !tosa.shape<3>, !tosa.shape<3>) -> tensor<1x2x4xf32>
- return
-}
-
-// -----
-
-func.func @test_slice_invalid_start_plus_size(%arg0: tensor<?x2xf32>) {
- %start = tosa.const_shape values(dense<[-1, 1]> : tensor<2xindex>) : () -> !tosa.shape<2>
- %size = tosa.const_shape values(dense<[3, 2]> : tensor<2xindex>) : () -> !tosa.shape<2>
- // expected-error at +1 {{'tosa.slice' op start + size must be less than or equal to input dimension size, got start=1, size=2 vs input dim size=2 at dimension 1}}
- %1 = tosa.slice %arg0, %start, %size : (tensor<?x2xf32>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<?x2xf32>
- return
-}
-
-// -----
-
-func.func @test_slice_output_shape_mismatch_dynamic(%arg0: tensor<?x5x6xf32>) {
- %start = tosa.const_shape values(dense<[0, 0, 0]> : tensor<3xindex>) : () -> !tosa.shape<3>
- %size = tosa.const_shape values(dense<[1, 2, 3]> : tensor<3xindex>) : () -> !tosa.shape<3>
- // expected-error at +1 {{'tosa.slice' op expected output shape to match size values, got 'tensor<?x2x4xf32>' vs [1, 2, 3]}}
- %1 = tosa.slice %arg0, %start, %size : (tensor<?x5x6xf32>, !tosa.shape<3>, !tosa.shape<3>) -> tensor<?x2x4xf32>
- return
-}
-
-// -----
-
func.func @test_conv2d_mxfp_invalid_weight_zp(%arg0: tensor<1x4x4x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>, %arg1: tensor<8x1x1x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>, %arg2: tensor<8xf16>) -> tensor<1x4x4x8xf16> {
%input_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf32>}> : () -> tensor<1xf32>
%weight_zp = "tosa.const"() <{values = dense<0.0> : tensor<1xf16>}> : () -> tensor<1xf16>
@@ -2534,16 +2484,6 @@ func.func @test_transpose_block_scaled_illegal_perms(%input: tensor<29x12x32x96x
// -----
-func.func @test_slice_block_scaled_invalid_block_size(%arg0: tensor<4x4x64x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>) -> tensor<1x1x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>> {
- %start = tosa.const_shape values(dense<[0, 0, 1]> : tensor<3xindex>) : () -> !tosa.shape<3>
- %size = tosa.const_shape values(dense<[1, 1, 32]> : tensor<3xindex>) : () -> !tosa.shape<3>
- // expected-error at +1 {{'tosa.slice' op expected start innermost block size to match data type for block scaled input, got start block=1, scale block=32}}
- %0 = tosa.slice %arg0, %start, %size {input_unsigned = false} : (tensor<4x4x64x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>, !tosa.shape<3>, !tosa.shape<3>) -> tensor<1x1x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>
- return %0 : tensor<1x1x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>
-}
-
-// -----
-
func.func @test_reverse_block_scaled_negative_axis(%arg0: tensor<2x64x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN>>) -> tensor<2x64x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN>> {
// expected-error at +1 {{'tosa.reverse' op expected non-negative reverse axis}}
%0 = tosa.reverse %arg0 axis(-1) : (tensor<2x64x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN>>) -> tensor<2x64x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN>>
@@ -2573,3 +2513,19 @@ func.func @test_reverse_block_scaled_rank_zero(%arg0: tensor<!tosa.block_scaled<
%0 = tosa.reverse %arg0 axis(0) : (tensor<!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN>>) -> tensor<!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN>>
return %0 : tensor<!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f8E4M3FN>>
}
+
+// -----
+
+// Regression test: a block-scaled slice whose start comes from tosa.dim must
+// not crash the verifier. The start values are not compile-time constants, so
+// the block-alignment ERROR_IF can only be reported by tosa-validate when the
+// values are resolvable (see checkErrorIfSlice).
+func.func @test_slice_block_scaled_dynamic_start(%arg0: tensor<4x4x64x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>) -> tensor<1x1x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>> {
+ %s0 = tosa.dim %arg0 axis(0) : (tensor<4x4x64x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>) -> !tosa.shape<1>
+ %s1 = tosa.dim %arg0 axis(1) : (tensor<4x4x64x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>) -> !tosa.shape<1>
+ %s2 = tosa.dim %arg0 axis(2) : (tensor<4x4x64x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>) -> !tosa.shape<1>
+ %start = tosa.concat_shape %s0, %s1, %s2 : (!tosa.shape<1>, !tosa.shape<1>, !tosa.shape<1>) -> !tosa.shape<3>
+ %size = tosa.const_shape values(dense<[1, 1, 32]> : tensor<3xindex>) : () -> !tosa.shape<3>
+ %0 = tosa.slice %arg0, %start, %size : (tensor<4x4x64x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>, !tosa.shape<3>, !tosa.shape<3>) -> tensor<1x1x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>
+ return %0 : tensor<1x1x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>
+}
>From b926e6fe4f8e0f39835eee8561e40e110af93989 Mon Sep 17 00:00:00 2001
From: wzy <WZYqwe2004 at outlook.com>
Date: Thu, 22 Oct 2026 19:16:12 +0800
Subject: [PATCH 3/3] format
---
mlir/test/Dialect/Tosa/tosa-validation-version-1p1-invalid.mlir | 1 -
1 file changed, 1 deletion(-)
diff --git a/mlir/test/Dialect/Tosa/tosa-validation-version-1p1-invalid.mlir b/mlir/test/Dialect/Tosa/tosa-validation-version-1p1-invalid.mlir
index ee5a1b2ee0132f..b07eda0d1f3d4e 100644
--- a/mlir/test/Dialect/Tosa/tosa-validation-version-1p1-invalid.mlir
+++ b/mlir/test/Dialect/Tosa/tosa-validation-version-1p1-invalid.mlir
@@ -42,4 +42,3 @@ func.func @test_slice_block_scaled_invalid_block_size(%arg0: tensor<4x4x64x!tosa
%0 = tosa.slice %arg0, %start, %size {input_unsigned = false} : (tensor<4x4x64x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>, !tosa.shape<3>, !tosa.shape<3>) -> tensor<1x1x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>
return %0 : tensor<1x1x32x!tosa.block_scaled<BLOCK_SHAPE_32:f8E8M0FNU:f4E2M1FN>>
}
-
More information about the Mlir-commits
mailing list