[Mlir-commits] [mlir] [mlir][tosa] Emit a runtime assertion when lowering `tosa.pad` with negative padding (PR #232221)
Federico Bruzzone
llvmlistbot at llvm.org
Wed Oct 21 03:00:32 PDT 2026
https://github.com/FedericoBruzzone updated https://github.com/llvm/llvm-project/pull/232221
>From 413d96659bd2593e54e7e868e7e9cd0241cc0e9e Mon Sep 17 00:00:00 2001
From: Federico Bruzzone <federico.bruzzone.i at gmail.com>
Date: Wed, 14 Oct 2026 17:45:50 +0200
Subject: [PATCH 1/4] [mlir][tosa] Fail lowering of `tosa.pad` -> `tensor.pad`
with -1 padding
Signed-off-by: Federico Bruzzone <federico.bruzzone.i at gmail.com>
---
.../Conversion/TosaToTensor/TosaToTensor.cpp | 7 +++++++
.../TosaToTensor/tosa-to-tensor-invalid.mlir | 10 ++++++++++
.../Conversion/TosaToTensor/tosa-to-tensor.mlir | 17 -----------------
3 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/mlir/lib/Conversion/TosaToTensor/TosaToTensor.cpp b/mlir/lib/Conversion/TosaToTensor/TosaToTensor.cpp
index 622f8a6f13a198..3e3d05d6cfc37b 100644
--- a/mlir/lib/Conversion/TosaToTensor/TosaToTensor.cpp
+++ b/mlir/lib/Conversion/TosaToTensor/TosaToTensor.cpp
@@ -353,6 +353,13 @@ class PadConverter : public OpConversionPattern<tosa::PadOp> {
paddingVals.push_back(static_cast<int64_t>(idx.getInt()));
}
+ // A padding of -1 means that the amount is not known, so it cannot be
+ // lowered to a `tensor.pad`, which requires non-negative padding.
+ if (llvm::is_contained(paddingVals, -1)) {
+ return rewriter.notifyMatchFailure(
+ padOp, "padding must not contain -1 (unknown amount)");
+ }
+
ShapedType inputTy = cast<ShapedType>(input.getType());
int64_t rank = inputTy.getRank();
diff --git a/mlir/test/Conversion/TosaToTensor/tosa-to-tensor-invalid.mlir b/mlir/test/Conversion/TosaToTensor/tosa-to-tensor-invalid.mlir
index 5e33ce2a2fcced..8741ea07431ec1 100644
--- a/mlir/test/Conversion/TosaToTensor/tosa-to-tensor-invalid.mlir
+++ b/mlir/test/Conversion/TosaToTensor/tosa-to-tensor-invalid.mlir
@@ -8,3 +8,13 @@ func.func @slice_resultType_unranked(%arg0: tensor<?xf32>) -> (tensor<*xf32>) {
%2 = tosa.slice %arg0, %start, %size : (tensor<?xf32>, !tosa.shape<1>, !tosa.shape<1>) -> tensor<*xf32>
return %2 : tensor<*xf32>
}
+
+// -----
+
+func.func @pad_unknown_padding(%arg0: tensor<1x2xf32>) -> tensor<?x9xf32> {
+ %padding = tosa.const_shape values(dense<[-1, 2, 3, 4]> : tensor<4xindex>) : () -> !tosa.shape<4>
+ %pad_const = "tosa.const"() <{values = dense<3.14> : tensor<1xf32>}> : () -> tensor<1xf32>
+ // expected-error at +1 {{failed to legalize operation 'tosa.pad'}}
+ %0 = "tosa.pad"(%arg0, %padding, %pad_const) : (tensor<1x2xf32>, !tosa.shape<4>, tensor<1xf32>) -> tensor<?x9xf32>
+ return %0 : tensor<?x9xf32>
+}
diff --git a/mlir/test/Conversion/TosaToTensor/tosa-to-tensor.mlir b/mlir/test/Conversion/TosaToTensor/tosa-to-tensor.mlir
index c60d340e8a7da1..232fec10b5bf6c 100644
--- a/mlir/test/Conversion/TosaToTensor/tosa-to-tensor.mlir
+++ b/mlir/test/Conversion/TosaToTensor/tosa-to-tensor.mlir
@@ -568,23 +568,6 @@ func.func @pad_dyn_input(%arg0 : tensor<?x2xf32>) -> (tensor<?x9xf32>) {
}
// -----
-func.func @pad_dyn_padding(%arg0 : tensor<1x2xf32>) -> (tensor<?x9xf32>) {
- %0 = tosa.const_shape values(dense<[-1, 2, 3, 4]> : tensor<4xindex>) : () -> !tosa.shape<4>
- %pad_const = "tosa.const"() <{values = dense<3.14> : tensor<1xf32>}> : () -> tensor<1xf32>
- // CHECK-DAG: [[INDEX1:%.+]] = arith.constant -1 : index
- // CHECK-DAG: [[INDEX2:%.+]] = arith.constant 2 : index
- // CHECK-DAG: [[INDEX3:%.+]] = arith.constant 3 : index
- // CHECK-DAG: [[INDEX4:%.+]] = arith.constant 4 : index
- // CHECK-DAG: [[CST:%.+]] = arith.constant 3.140000e+00 : f32
- // CHECK: tensor.pad %[[ARG0]] low{{\[}}[[INDEX1]], [[INDEX3]]] high{{\[}}[[INDEX2]], [[INDEX4]]] {
- // CHECK: tensor.yield [[CST]]
- // CHECK: } : tensor<1x2xf32> to tensor<?x9xf32>
- %1 = "tosa.pad"(%arg0, %0, %pad_const) : (tensor<1x2xf32>, !tosa.shape<4>, tensor<1xf32>) -> (tensor<?x9xf32>)
- return %1 : tensor<?x9xf32>
-}
-
-// -----
-
// CHECK-LABEL: @concat
// CHECK-SAME: %[[ARG0:.+]]: tensor<5x1xf32>
// CHECK-SAME: %[[ARG1:.+]]: tensor<6x1xf32>
>From fede2eb21ba1e79774bd174ae57444f760307140 Mon Sep 17 00:00:00 2001
From: Federico Bruzzone <federico.bruzzone.i at gmail.com>
Date: Thu, 15 Oct 2026 17:19:08 +0200
Subject: [PATCH 2/4] Implement the assert option
Signed-off-by: Federico Bruzzone <federico.bruzzone.i at gmail.com>
---
mlir/include/mlir/Conversion/Passes.td | 1 +
mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td | 10 ++++++++++
.../Conversion/TosaToTensor/CMakeLists.txt | 1 +
.../Conversion/TosaToTensor/TosaToTensor.cpp | 16 +++++++++++-----
.../TosaToTensor/TosaToTensorPass.cpp | 2 ++
.../TosaToTensor/tosa-to-tensor-invalid.mlir | 10 ----------
.../TosaToTensor/tosa-to-tensor.mlir | 19 +++++++++++++++++++
7 files changed, 44 insertions(+), 15 deletions(-)
diff --git a/mlir/include/mlir/Conversion/Passes.td b/mlir/include/mlir/Conversion/Passes.td
index 8562cbc11bd452..ac467f0611de55 100644
--- a/mlir/include/mlir/Conversion/Passes.td
+++ b/mlir/include/mlir/Conversion/Passes.td
@@ -1568,6 +1568,7 @@ def TosaToSPIRVTosa : Pass<"tosa-to-spirv-tosa"> {
def TosaToTensorPass : Pass<"tosa-to-tensor"> {
let summary = "Lower TOSA to the Tensor dialect";
let dependentDialects = [
+ "cf::ControlFlowDialect",
"tensor::TensorDialect",
];
let description = [{
diff --git a/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td b/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td
index 6936578f63d364..9fccff3544f2a5 100644
--- a/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td
+++ b/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td
@@ -2108,6 +2108,16 @@ def Tosa_PadOp : Tosa_InferShapedTypeOp<"pad", [Pure]> {
Returns a new tensor with the padding included. The pad_const value includes
the zero point if the tensor uses a zero point.
+ The padding amounts must be non-negative. A negative padding is not valid
+ for execution. For a constant padding, the verifier accepts -1 as a
+ placeholder for an amount that is not known at compile time, in which case
+ the corresponding output dimension is dynamic.
+
+ The TOSA specification requires a negative padding to be diagnosed
+ (`ERROR_IF`). The `tosa-validate` pass reports it, and the lowering to the
+ Tensor dialect emits a runtime assertion. It is recommended to run
+ `tosa-validate` before lowering.
+
Example:
```mlir
diff --git a/mlir/lib/Conversion/TosaToTensor/CMakeLists.txt b/mlir/lib/Conversion/TosaToTensor/CMakeLists.txt
index 2870baa20757b5..9220d76339b22f 100644
--- a/mlir/lib/Conversion/TosaToTensor/CMakeLists.txt
+++ b/mlir/lib/Conversion/TosaToTensor/CMakeLists.txt
@@ -10,6 +10,7 @@ add_mlir_conversion_library(MLIRTosaToTensor
MLIRConversionPassIncGen
LINK_LIBS PUBLIC
+ MLIRControlFlowDialect
MLIRTensorDialect
MLIRTensorUtils
MLIRIR
diff --git a/mlir/lib/Conversion/TosaToTensor/TosaToTensor.cpp b/mlir/lib/Conversion/TosaToTensor/TosaToTensor.cpp
index 3e3d05d6cfc37b..1f02c5f3aca365 100644
--- a/mlir/lib/Conversion/TosaToTensor/TosaToTensor.cpp
+++ b/mlir/lib/Conversion/TosaToTensor/TosaToTensor.cpp
@@ -12,6 +12,8 @@
#include "mlir/Conversion/TosaToTensor/TosaToTensor.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
+#include "mlir/Dialect/Arith/Utils/Utils.h"
+#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
#include "mlir/Dialect/Tensor/IR/Tensor.h"
#include "mlir/Dialect/Tosa/IR/TosaOps.h"
#include "mlir/Dialect/Tosa/Utils/ConversionUtils.h"
@@ -353,11 +355,15 @@ class PadConverter : public OpConversionPattern<tosa::PadOp> {
paddingVals.push_back(static_cast<int64_t>(idx.getInt()));
}
- // A padding of -1 means that the amount is not known, so it cannot be
- // lowered to a `tensor.pad`, which requires non-negative padding.
- if (llvm::is_contained(paddingVals, -1)) {
- return rewriter.notifyMatchFailure(
- padOp, "padding must not contain -1 (unknown amount)");
+ // The TOSA specification requires a negative padding (-1 stands for an
+ // amount that is not known) to be diagnosed.
+ if (llvm::any_of(paddingVals, [](int64_t val) { return val < 0; })) {
+ Value fail =
+ arith::ConstantOp::create(rewriter, loc, rewriter.getBoolAttr(false));
+ cf::AssertOp::create(
+ rewriter, loc, fail,
+ rewriter.getStringAttr("tosa.pad: padding must be non-negative, run "
+ "tosa-validate to diagnose it statically"));
}
ShapedType inputTy = cast<ShapedType>(input.getType());
diff --git a/mlir/lib/Conversion/TosaToTensor/TosaToTensorPass.cpp b/mlir/lib/Conversion/TosaToTensor/TosaToTensorPass.cpp
index a7f415c574843e..5633b655d68065 100644
--- a/mlir/lib/Conversion/TosaToTensor/TosaToTensorPass.cpp
+++ b/mlir/lib/Conversion/TosaToTensor/TosaToTensorPass.cpp
@@ -13,6 +13,7 @@
#include "mlir/Conversion/TosaToTensor/TosaToTensor.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
+#include "mlir/Dialect/ControlFlow/IR/ControlFlow.h"
#include "mlir/Dialect/Tensor/IR/Tensor.h"
#include "mlir/Dialect/Tosa/IR/TosaOps.h"
#include "mlir/Dialect/Tosa/Transforms/Passes.h"
@@ -38,6 +39,7 @@ struct TosaToTensor : public impl::TosaToTensorPassBase<TosaToTensor> {
target.addIllegalOp<tosa::SliceOp>();
target.addIllegalOp<tosa::PadOp>();
target.addLegalDialect<arith::ArithDialect>();
+ target.addLegalDialect<cf::ControlFlowDialect>();
target.addLegalDialect<tensor::TensorDialect>();
TypeConverter converter;
diff --git a/mlir/test/Conversion/TosaToTensor/tosa-to-tensor-invalid.mlir b/mlir/test/Conversion/TosaToTensor/tosa-to-tensor-invalid.mlir
index 8741ea07431ec1..5e33ce2a2fcced 100644
--- a/mlir/test/Conversion/TosaToTensor/tosa-to-tensor-invalid.mlir
+++ b/mlir/test/Conversion/TosaToTensor/tosa-to-tensor-invalid.mlir
@@ -8,13 +8,3 @@ func.func @slice_resultType_unranked(%arg0: tensor<?xf32>) -> (tensor<*xf32>) {
%2 = tosa.slice %arg0, %start, %size : (tensor<?xf32>, !tosa.shape<1>, !tosa.shape<1>) -> tensor<*xf32>
return %2 : tensor<*xf32>
}
-
-// -----
-
-func.func @pad_unknown_padding(%arg0: tensor<1x2xf32>) -> tensor<?x9xf32> {
- %padding = tosa.const_shape values(dense<[-1, 2, 3, 4]> : tensor<4xindex>) : () -> !tosa.shape<4>
- %pad_const = "tosa.const"() <{values = dense<3.14> : tensor<1xf32>}> : () -> tensor<1xf32>
- // expected-error at +1 {{failed to legalize operation 'tosa.pad'}}
- %0 = "tosa.pad"(%arg0, %padding, %pad_const) : (tensor<1x2xf32>, !tosa.shape<4>, tensor<1xf32>) -> tensor<?x9xf32>
- return %0 : tensor<?x9xf32>
-}
diff --git a/mlir/test/Conversion/TosaToTensor/tosa-to-tensor.mlir b/mlir/test/Conversion/TosaToTensor/tosa-to-tensor.mlir
index 232fec10b5bf6c..8d43a9f3ee94c2 100644
--- a/mlir/test/Conversion/TosaToTensor/tosa-to-tensor.mlir
+++ b/mlir/test/Conversion/TosaToTensor/tosa-to-tensor.mlir
@@ -568,6 +568,25 @@ func.func @pad_dyn_input(%arg0 : tensor<?x2xf32>) -> (tensor<?x9xf32>) {
}
// -----
+func.func @pad_dyn_padding(%arg0 : tensor<1x2xf32>) -> (tensor<?x9xf32>) {
+ %0 = tosa.const_shape values(dense<[-1, 2, 3, 4]> : tensor<4xindex>) : () -> !tosa.shape<4>
+ %pad_const = "tosa.const"() <{values = dense<3.14> : tensor<1xf32>}> : () -> tensor<1xf32>
+ // CHECK: [[FALSE:%.+]] = arith.constant false
+ // CHECK: cf.assert [[FALSE]], "tosa.pad: padding must be non-negative, run tosa-validate to diagnose it statically"
+ // CHECK-DAG: [[INDEX1:%.+]] = arith.constant -1 : index
+ // CHECK-DAG: [[INDEX2:%.+]] = arith.constant 2 : index
+ // CHECK-DAG: [[INDEX3:%.+]] = arith.constant 3 : index
+ // CHECK-DAG: [[INDEX4:%.+]] = arith.constant 4 : index
+ // CHECK-DAG: [[CST:%.+]] = arith.constant 3.140000e+00 : f32
+ // CHECK: tensor.pad %[[ARG0]] low{{\[}}[[INDEX1]], [[INDEX3]]] high{{\[}}[[INDEX2]], [[INDEX4]]] {
+ // CHECK: tensor.yield [[CST]]
+ // CHECK: } : tensor<1x2xf32> to tensor<?x9xf32>
+ %1 = "tosa.pad"(%arg0, %0, %pad_const) : (tensor<1x2xf32>, !tosa.shape<4>, tensor<1xf32>) -> (tensor<?x9xf32>)
+ return %1 : tensor<?x9xf32>
+}
+
+// -----
+
// CHECK-LABEL: @concat
// CHECK-SAME: %[[ARG0:.+]]: tensor<5x1xf32>
// CHECK-SAME: %[[ARG1:.+]]: tensor<6x1xf32>
>From 7c2390ed484ce837b68dc83d941448ec99ba07f8 Mon Sep 17 00:00:00 2001
From: Federico Bruzzone <federico.bruzzone.i at gmail.com>
Date: Sat, 17 Oct 2026 12:10:44 +0200
Subject: [PATCH 3/4] Address comments
Signed-off-by: Federico Bruzzone <federico.bruzzone.i at gmail.com>
---
mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td | 4 +---
mlir/lib/Conversion/TosaToTensor/TosaToTensor.cpp | 7 +++----
mlir/test/Conversion/TosaToTensor/tosa-to-tensor.mlir | 2 +-
3 files changed, 5 insertions(+), 8 deletions(-)
diff --git a/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td b/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td
index 9fccff3544f2a5..d9b01adf6bce59 100644
--- a/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td
+++ b/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td
@@ -2114,9 +2114,7 @@ def Tosa_PadOp : Tosa_InferShapedTypeOp<"pad", [Pure]> {
the corresponding output dimension is dynamic.
The TOSA specification requires a negative padding to be diagnosed
- (`ERROR_IF`). The `tosa-validate` pass reports it, and the lowering to the
- Tensor dialect emits a runtime assertion. It is recommended to run
- `tosa-validate` before lowering.
+ (`ERROR_IF`). The lowering to the Tensor dialect emits a runtime assertion.
Example:
diff --git a/mlir/lib/Conversion/TosaToTensor/TosaToTensor.cpp b/mlir/lib/Conversion/TosaToTensor/TosaToTensor.cpp
index 1f02c5f3aca365..ad0d01ffbce825 100644
--- a/mlir/lib/Conversion/TosaToTensor/TosaToTensor.cpp
+++ b/mlir/lib/Conversion/TosaToTensor/TosaToTensor.cpp
@@ -355,15 +355,14 @@ class PadConverter : public OpConversionPattern<tosa::PadOp> {
paddingVals.push_back(static_cast<int64_t>(idx.getInt()));
}
- // The TOSA specification requires a negative padding (-1 stands for an
- // amount that is not known) to be diagnosed.
+ // The TOSA specification requires a negative padding to be diagnosed.
+ // We emit a runtime assertion, as this could be dead or unreachable code.
if (llvm::any_of(paddingVals, [](int64_t val) { return val < 0; })) {
Value fail =
arith::ConstantOp::create(rewriter, loc, rewriter.getBoolAttr(false));
cf::AssertOp::create(
rewriter, loc, fail,
- rewriter.getStringAttr("tosa.pad: padding must be non-negative, run "
- "tosa-validate to diagnose it statically"));
+ rewriter.getStringAttr("tosa.pad: padding must be non-negative"));
}
ShapedType inputTy = cast<ShapedType>(input.getType());
diff --git a/mlir/test/Conversion/TosaToTensor/tosa-to-tensor.mlir b/mlir/test/Conversion/TosaToTensor/tosa-to-tensor.mlir
index 8d43a9f3ee94c2..e9348c53e3e074 100644
--- a/mlir/test/Conversion/TosaToTensor/tosa-to-tensor.mlir
+++ b/mlir/test/Conversion/TosaToTensor/tosa-to-tensor.mlir
@@ -572,7 +572,7 @@ func.func @pad_dyn_padding(%arg0 : tensor<1x2xf32>) -> (tensor<?x9xf32>) {
%0 = tosa.const_shape values(dense<[-1, 2, 3, 4]> : tensor<4xindex>) : () -> !tosa.shape<4>
%pad_const = "tosa.const"() <{values = dense<3.14> : tensor<1xf32>}> : () -> tensor<1xf32>
// CHECK: [[FALSE:%.+]] = arith.constant false
- // CHECK: cf.assert [[FALSE]], "tosa.pad: padding must be non-negative, run tosa-validate to diagnose it statically"
+ // CHECK: cf.assert [[FALSE]], "tosa.pad: padding must be non-negative
// CHECK-DAG: [[INDEX1:%.+]] = arith.constant -1 : index
// CHECK-DAG: [[INDEX2:%.+]] = arith.constant 2 : index
// CHECK-DAG: [[INDEX3:%.+]] = arith.constant 3 : index
>From c7d890e151783ce2191e64d8d5d668c8b9f46b42 Mon Sep 17 00:00:00 2001
From: Federico Bruzzone <federico.bruzzone.i at gmail.com>
Date: Mon, 19 Oct 2026 19:27:00 +0200
Subject: [PATCH 4/4] Address comments
Signed-off-by: Federico Bruzzone <federico.bruzzone.i at gmail.com>
---
mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td b/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td
index d9b01adf6bce59..c4cf5dd4be2649 100644
--- a/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td
+++ b/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td
@@ -2108,13 +2108,8 @@ def Tosa_PadOp : Tosa_InferShapedTypeOp<"pad", [Pure]> {
Returns a new tensor with the padding included. The pad_const value includes
the zero point if the tensor uses a zero point.
- The padding amounts must be non-negative. A negative padding is not valid
- for execution. For a constant padding, the verifier accepts -1 as a
- placeholder for an amount that is not known at compile time, in which case
- the corresponding output dimension is dynamic.
-
- The TOSA specification requires a negative padding to be diagnosed
- (`ERROR_IF`). The lowering to the Tensor dialect emits a runtime assertion.
+ The padding amounts must be non-negative. The TOSA specification requires
+ a negative padding to be diagnosed (`ERROR_IF`).
Example:
More information about the Mlir-commits
mailing list