[Mlir-commits] [mlir] [mlir][tosa] Remove NegateOp to SubOp and 48-bit promotion in TosaToLinalg (PR #170622)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Tue Dec 9 21:50:15 PST 2025
https://github.com/ShivaChen updated https://github.com/llvm/llvm-project/pull/170622
>From 0c4a7be57f4800cd9eff5af2c0a1c22e5110d4cb Mon Sep 17 00:00:00 2001
From: Shiva Chen <shiva.chen at imgtec.com>
Date: Thu, 4 Dec 2025 06:38:52 +0000
Subject: [PATCH 1/2] [RFC][mlir][tosa] Remove NegateOp to SubOp and promotion
to 48-bit in TosaToLinalg
The patch motivated by Tosa Conformance test negate_32x45x49_i16_full failure.
TosaToLinalg pass has an optimization to transfer Tosa Negate to Sub if the zero
points are zeros. However, when the input value is minimized negative number,
the transformation will cause the underflow. By removing the transformation,
if zp = 0 it would do the promotion to avoid the underflow.
Promotion types could be from int32 to int48. TOSA negate specification
does not mention support for int48. Should we consider removing the promotion
to int48 to stay aligned with the TOSA spec?
---
mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp | 12 +-----------
.../test/Conversion/TosaToLinalg/tosa-to-linalg.mlir | 7 +++----
2 files changed, 4 insertions(+), 15 deletions(-)
diff --git a/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp b/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp
index 29afdc240c9f8..99b5a2cb0a501 100644
--- a/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp
+++ b/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp
@@ -200,13 +200,6 @@ static Value createLinalgBodyCalculationForElementwiseOp(
return arith::NegFOp::create(rewriter, loc, resultTypes, args[0]);
if (isa<IntegerType>(elementTy)) {
- if (hasInZp && hasOutZp && !inZp && !outZp) {
- auto constant = arith::ConstantOp::create(
- rewriter, loc, IntegerAttr::get(elementTy, 0));
- return arith::SubIOp::create(rewriter, loc, resultTypes, constant,
- args[0]);
- }
-
Value zpAddValue;
Type intermediateType;
// Compute the maximum value that can occur in the intermediate buffer.
@@ -221,14 +214,11 @@ static Value createLinalgBodyCalculationForElementwiseOp(
std::abs(zpAdd) + 1;
// Convert that maximum value into the maximum bitwidth needed to
- // represent it. We assume 48-bit numbers may be supported further in
- // the pipeline.
+ // represent it.
if (maxValue <= APInt::getSignedMaxValue(16).getSExtValue()) {
intermediateBitWidth = 16;
} else if (maxValue <= APInt::getSignedMaxValue(32).getSExtValue()) {
intermediateBitWidth = 32;
- } else if (maxValue <= APInt::getSignedMaxValue(48).getSExtValue()) {
- intermediateBitWidth = 48;
}
intermediateType = rewriter.getIntegerType(intermediateBitWidth);
diff --git a/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg.mlir b/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg.mlir
index 780c25a9445a0..97c93991bb9f0 100644
--- a/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg.mlir
+++ b/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg.mlir
@@ -666,7 +666,7 @@ func.func @test_simple_i32(%arg0: tensor<1xi32>, %unsigned: tensor<1xui32>, %uns
// CHECK: linalg.generic
// CHECK: ^bb0(%[[ARG1:.*]]: i32, %[[ARG2:.*]]: i32):
// CHECK: [[ZERO:%.+]] = arith.constant 0
- // CHECK: arith.subi [[ZERO]], %[[ARG1]]
+ // CHECK: arith.extsi %[[IN:.*]] : i32 to i64
%in_zp = "tosa.const"() <{values = dense<0> : tensor<1xi32>}> : () -> tensor<1xi32>
%out_zp = "tosa.const"() <{values = dense<0> : tensor<1xi32>}> : () -> tensor<1xi32>
%5 = tosa.negate %arg0, %in_zp, %out_zp : (tensor<1xi32>, tensor<1xi32>, tensor<1xi32>) -> tensor<1xi32>
@@ -889,8 +889,7 @@ func.func @test_negate_quantized(%arg0: tensor<1xi8>) -> () {
// CHECK: linalg.generic
// CHECK: ^bb0(%[[BBARG0:.+]]: i8,
// CHECK: [[ZERO:%.+]] = arith.constant 0
- // CHECK: [[SUB:%.+]] = arith.subi [[ZERO]],
- // CHECK: linalg.yield [[SUB]]
+ // CHECK: arith.extsi %[[IN:.*]] : i8 to i16
%in_zp4 = "tosa.const"() <{values = dense<0> : tensor<1xi8>}> : () -> tensor<1xi8>
%out_zp4 = "tosa.const"() <{values = dense<0> : tensor<1xi8>}> : () -> tensor<1xi8>
%4 = tosa.negate %arg0, %in_zp4, %out_zp4 : (tensor<1xi8>, tensor<1xi8>, tensor<1xi8>) -> tensor<1xi8>
@@ -2610,7 +2609,7 @@ func.func @test_0d_input(%arg0: tensor<i32>) -> () {
// CHECK: linalg.generic
// CHECK: ^bb0(%[[ARG1:.*]]: i32, %[[ARG2:.*]]: i32):
// CHECK: [[ZERO:%.+]] = arith.constant 0
- // CHECK: arith.subi [[ZERO]], %[[ARG1]]
+ // CHECK: arith.extsi %[[IN:.*]] : i32 to i64
%in_zp = "tosa.const"() <{values = dense<0> : tensor<1xi32>}> : () -> tensor<1xi32>
%out_zp = "tosa.const"() <{values = dense<0> : tensor<1xi32>}> : () -> tensor<1xi32>
%5 = tosa.negate %arg0, %in_zp, %out_zp : (tensor<i32>, tensor<1xi32>, tensor<1xi32>) -> tensor<i32>
>From 48f47abcac2e49007932b020d4619503eafaaee0 Mon Sep 17 00:00:00 2001
From: Shiva Chen <shiva.chen at imgtec.com>
Date: Wed, 10 Dec 2025 05:30:31 +0000
Subject: [PATCH 2/2] Add lowering operations in the test case
---
.../TosaToLinalg/tosa-to-linalg.mlir | 24 ++++++++++++++++---
1 file changed, 21 insertions(+), 3 deletions(-)
diff --git a/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg.mlir b/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg.mlir
index 97c93991bb9f0..e84ed80f173b0 100644
--- a/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg.mlir
+++ b/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg.mlir
@@ -666,7 +666,13 @@ func.func @test_simple_i32(%arg0: tensor<1xi32>, %unsigned: tensor<1xui32>, %uns
// CHECK: linalg.generic
// CHECK: ^bb0(%[[ARG1:.*]]: i32, %[[ARG2:.*]]: i32):
// CHECK: [[ZERO:%.+]] = arith.constant 0
- // CHECK: arith.extsi %[[IN:.*]] : i32 to i64
+ // CHECK: [[EXT:%.+]] = arith.extsi %[[IN:.*]] : i32 to i64
+ // CHECK: [[SUB:%.+]] = arith.subi [[ZERO]], [[EXT]]
+ // CHECK: [[MIN:%.+]] = arith.constant -2147483648
+ // CHECK: [[MAX:%.+]] = arith.constant 2147483647
+ // CHECK: [[LBOUND:%.+]] = arith.maxsi [[MIN]], [[SUB]]
+ // CHECK: [[UBOUND:%.+]] = arith.minsi [[MAX]], [[LBOUND]]
+ // CHECK: [[TRUNC:%.+]] = arith.trunci [[UBOUND]]
%in_zp = "tosa.const"() <{values = dense<0> : tensor<1xi32>}> : () -> tensor<1xi32>
%out_zp = "tosa.const"() <{values = dense<0> : tensor<1xi32>}> : () -> tensor<1xi32>
%5 = tosa.negate %arg0, %in_zp, %out_zp : (tensor<1xi32>, tensor<1xi32>, tensor<1xi32>) -> tensor<1xi32>
@@ -889,7 +895,13 @@ func.func @test_negate_quantized(%arg0: tensor<1xi8>) -> () {
// CHECK: linalg.generic
// CHECK: ^bb0(%[[BBARG0:.+]]: i8,
// CHECK: [[ZERO:%.+]] = arith.constant 0
- // CHECK: arith.extsi %[[IN:.*]] : i8 to i16
+ // CHECK: [[EXT:%.+]] = arith.extsi %[[IN:.*]] : i8 to i16
+ // CHECK: [[SUB:%.+]] = arith.subi [[ZERO]], [[EXT]]
+ // CHECK: [[MIN:%.+]] = arith.constant -128
+ // CHECK: [[MAX:%.+]] = arith.constant 127
+ // CHECK: [[LBOUND:%.+]] = arith.maxsi [[MIN]], [[SUB]]
+ // CHECK: [[UBOUND:%.+]] = arith.minsi [[MAX]], [[LBOUND]]
+ // CHECK: [[TRUNC:%.+]] = arith.trunci [[UBOUND]]
%in_zp4 = "tosa.const"() <{values = dense<0> : tensor<1xi8>}> : () -> tensor<1xi8>
%out_zp4 = "tosa.const"() <{values = dense<0> : tensor<1xi8>}> : () -> tensor<1xi8>
%4 = tosa.negate %arg0, %in_zp4, %out_zp4 : (tensor<1xi8>, tensor<1xi8>, tensor<1xi8>) -> tensor<1xi8>
@@ -2609,7 +2621,13 @@ func.func @test_0d_input(%arg0: tensor<i32>) -> () {
// CHECK: linalg.generic
// CHECK: ^bb0(%[[ARG1:.*]]: i32, %[[ARG2:.*]]: i32):
// CHECK: [[ZERO:%.+]] = arith.constant 0
- // CHECK: arith.extsi %[[IN:.*]] : i32 to i64
+ // CHECK: [[EXT:%.+]] = arith.extsi %[[IN:.*]] : i32 to i64
+ // CHECK: [[SUB:%.+]] = arith.subi [[ZERO]], [[EXT]]
+ // CHECK: [[MIN:%.+]] = arith.constant -2147483648
+ // CHECK: [[MAX:%.+]] = arith.constant 2147483647
+ // CHECK: [[LBOUND:%.+]] = arith.maxsi [[MIN]], [[SUB]]
+ // CHECK: [[UBOUND:%.+]] = arith.minsi [[MAX]], [[LBOUND]]
+ // CHECK: [[TRUNC:%.+]] = arith.trunci [[UBOUND]]
%in_zp = "tosa.const"() <{values = dense<0> : tensor<1xi32>}> : () -> tensor<1xi32>
%out_zp = "tosa.const"() <{values = dense<0> : tensor<1xi32>}> : () -> tensor<1xi32>
%5 = tosa.negate %arg0, %in_zp, %out_zp : (tensor<i32>, tensor<1xi32>, tensor<1xi32>) -> tensor<i32>
More information about the Mlir-commits
mailing list