Remove ReluN conversion and implementation (#324)
The ReluN operator was removed from the TOSA spec and the MLIR op is
removed with llvm/llvm-project@9dec80b. This patch therefore drops the
conversion to EmitC as well as the reference implementation. The latter
already relied on clamp. Hence, tests are moved instead of dropped.
diff --git a/docs/tosa-op-coverage.md b/docs/tosa-op-coverage.md
index 9d49dd4..4f4e822 100644
--- a/docs/tosa-op-coverage.md
+++ b/docs/tosa-op-coverage.md
@@ -17,7 +17,6 @@
| log | :heavy_check_mark: | |
| negate | :heavy_check_mark: | |
| reciprocal | :heavy_check_mark: | |
-| reluN | :heavy_check_mark: | |
| rescale | :heavy_check_mark: | |
| rsqrt | :heavy_check_mark: | |
| tanh | :heavy_check_mark: | |
diff --git a/lib/Dialect/EmitC/Conversion/TosaToEmitC.cpp b/lib/Dialect/EmitC/Conversion/TosaToEmitC.cpp
index 847767b..9a9db8f 100644
--- a/lib/Dialect/EmitC/Conversion/TosaToEmitC.cpp
+++ b/lib/Dialect/EmitC/Conversion/TosaToEmitC.cpp
@@ -361,54 +361,6 @@
}
};
-/// Convert `tosa.reluN` into an `emitc.call` operation.
-class ReluNOpConversion : public OpConversionPattern<tosa::ReluNOp> {
- using OpConversionPattern<tosa::ReluNOp>::OpConversionPattern;
-
-public:
- ReluNOpConversion(MLIRContext *ctx)
- : OpConversionPattern<tosa::ReluNOp>(ctx) {}
-
-private:
- LogicalResult
- matchAndRewrite(tosa::ReluNOp reluNOp, OpAdaptor adaptor,
- ConversionPatternRewriter &rewriter) const override {
-
- StringRef funcName = "emitc::tosa::reluN";
- StringAttr callee = rewriter.getStringAttr(funcName);
-
- SmallVector<Attribute, 2> arguments;
- arguments.push_back(rewriter.getIndexAttr(0));
-
- // TOSA specifies the max attributes to be either exact i64 or f32,
- // regardless of the operand's element type. So we need to make sure that
- // the max attribute type match the operand's element type and it's bit
- // width.
- auto elementType =
- adaptor.getInput().getType().cast<RankedTensorType>().getElementType();
- if (elementType.isa<IntegerType>()) {
- // Change the max_int type to the element type of the operand.
- auto maxInt = reluNOp.getMaxInt();
- arguments.push_back(IntegerAttr::get(elementType, maxInt));
- } else if (elementType.isa<FloatType>()) {
- // Change the max_fp type to the element type of the operand.
- auto maxFp = reluNOp.getMaxFpAttr().getValueAsDouble();
- arguments.push_back(FloatAttr::get(elementType, maxFp));
- } else {
- return reluNOp.emitError(
- "Operand of tosa.reluN has to be tensor of integer or float values.");
- }
- ArrayAttr args = rewriter.getArrayAttr(arguments);
- ArrayAttr templateArgs;
-
- rewriter.replaceOpWithNewOp<emitc::CallOp>(reluNOp, reluNOp.getType(),
- callee, args, templateArgs,
- adaptor.getOperands());
-
- return success();
- }
-};
-
/// Convert `tosa.rsqrt` into an `emitc.call` operation.
class RsqrtOpConversion : public OpConversionPattern<tosa::RsqrtOp> {
using OpConversionPattern<tosa::RsqrtOp>::OpConversionPattern;
@@ -807,7 +759,6 @@
patterns.add<NegateOpConversion>(ctx);
patterns.add<CallOpConversion<tosa::ReciprocalOp>>(ctx,
"emitc::tosa::reciprocal");
- patterns.add<ReluNOpConversion>(ctx);
patterns.add<RescaleOpConversion>(ctx);
patterns.add<RsqrtOpConversion>(ctx);
patterns.add<CallOpConversion<tosa::TanhOp>>(ctx, "emitc::tosa::tanh");
@@ -886,7 +837,6 @@
tosa::LogOp,
tosa::NegateOp,
tosa::ReciprocalOp,
- tosa::ReluNOp,
tosa::RescaleOp,
tosa::RsqrtOp,
tosa::TanhOp>();
diff --git a/reference-implementation/include/emitc/tosa.h b/reference-implementation/include/emitc/tosa.h
index 5a5bb68..8a1b46f 100644
--- a/reference-implementation/include/emitc/tosa.h
+++ b/reference-implementation/include/emitc/tosa.h
@@ -108,14 +108,6 @@
return unary<Src>(x, f);
}
-// ReluNOp
-template <typename Src>
-inline Src reluN(Src operand, typename Src::value_type max_value) {
- Tensor<typename Src::value_type> min{0};
- Tensor<typename Src::value_type> max{max_value};
- return emitc::clamp(min, operand, max);
-}
-
// RescaleOp
template <typename Dest, size_t Dim, typename Src>
inline Dest rescale(Src x, typename get_element_type<Src>::type in_zp,
diff --git a/reference-implementation/unittests/tosa.cpp b/reference-implementation/unittests/tosa.cpp
index 201c168..89357f9 100644
--- a/reference-implementation/unittests/tosa.cpp
+++ b/reference-implementation/unittests/tosa.cpp
@@ -80,6 +80,60 @@
EXPECT_THAT(result, Pointwise(FloatEq(), expected_result));
}
+
+ // These are the tests of the former ReluN operation, which has been removed
+ // from the TOSA specification. clamp with min_value=0 can be used instead.
+ {
+ Tensor0D<int32_t> operand{0};
+ int32_t max_value = 0;
+ Tensor0D<int32_t> expected_result{0};
+ Tensor0D<int32_t> result = tosa::clamp(operand, {0}, max_value);
+
+ EXPECT_THAT(result, Pointwise(Eq(), expected_result));
+ }
+ {
+ Tensor0D<int32_t> operand{0};
+ int32_t max_value = 0;
+ Tensor0D<int32_t> expected_result{0};
+ Tensor0D<int32_t> result = tosa::clamp(operand, {0}, max_value);
+
+ EXPECT_THAT(result, Pointwise(Eq(), expected_result));
+ }
+ {
+ Tensor1D<double, 2> operand{-4.7, 1.3};
+ double max_value = 1.4;
+ Tensor1D<double, 2> expected_result{0, 1.3};
+ Tensor1D<double, 2> result = tosa::clamp(operand, {0}, max_value);
+
+ EXPECT_THAT(result, Pointwise(DoubleEq(), expected_result));
+ }
+ {
+ Tensor2D<float, 2, 2> operand{0.0f, -9.9f, 4.4f, 8.8f};
+ float max_value = 5.5f;
+ Tensor2D<float, 2, 2> expected_result{0.0f, 0.0f, 4.4f, 5.5f};
+ Tensor2D<float, 2, 2> result = tosa::clamp(operand, {0}, max_value);
+
+ EXPECT_THAT(result, Pointwise(FloatEq(), expected_result));
+ }
+ {
+ Tensor3D<int64_t, 3, 2, 1> operand{4, 1, -1, 3, 0, 2};
+ int64_t max_value = 3;
+ Tensor3D<int64_t, 3, 2, 1> expected_result{3, 1, 0, 3, 0, 2};
+ Tensor3D<int64_t, 3, 2, 1> result = tosa::clamp(operand, {0}, max_value);
+
+ EXPECT_THAT(result, Pointwise(Eq(), expected_result));
+ }
+ {
+ Tensor4D<int16_t, 1, 2, 3, 2> operand{7812, 15481, -30284, 30996,
+ 18736, 6699, 31903, 26229,
+ 15931, -18954, -27643, 19133};
+ int16_t max_value = 20000;
+ Tensor4D<int16_t, 1, 2, 3, 2> expected_result{
+ 7812, 15481, 0, 20000, 18736, 6699, 20000, 20000, 15931, 0, 0, 19133};
+ Tensor4D<int16_t, 1, 2, 3, 2> result = tosa::clamp(operand, {0}, max_value);
+
+ EXPECT_THAT(result, Pointwise(FloatEq(), expected_result));
+ }
}
TEST(tosa, clz) {
@@ -245,52 +299,6 @@
}
}
-TEST(tosa, reluN) {
- {
- Tensor0D<int32_t> operand{0};
- int32_t max_value = 0;
- Tensor0D<int32_t> expected_result{0};
- Tensor0D<int32_t> result = tosa::reluN(operand, max_value);
-
- EXPECT_THAT(result, Pointwise(Eq(), expected_result));
- }
- {
- Tensor1D<double, 2> operand{-4.7, 1.3};
- double max_value = 1.4;
- Tensor1D<double, 2> expected_result{0, 1.3};
- Tensor1D<double, 2> result = tosa::reluN(operand, max_value);
-
- EXPECT_THAT(result, Pointwise(DoubleEq(), expected_result));
- }
- {
- Tensor2D<float, 2, 2> operand{0.0f, -9.9f, 4.4f, 8.8f};
- float max_value = 5.5f;
- Tensor2D<float, 2, 2> expected_result{0.0f, 0.0f, 4.4f, 5.5f};
- Tensor2D<float, 2, 2> result = tosa::reluN(operand, max_value);
-
- EXPECT_THAT(result, Pointwise(FloatEq(), expected_result));
- }
- {
- Tensor3D<int64_t, 3, 2, 1> operand{4, 1, -1, 3, 0, 2};
- int64_t max_value = 3;
- Tensor3D<int64_t, 3, 2, 1> expected_result{3, 1, 0, 3, 0, 2};
- Tensor3D<int64_t, 3, 2, 1> result = tosa::reluN(operand, max_value);
-
- EXPECT_THAT(result, Pointwise(Eq(), expected_result));
- }
- {
- Tensor4D<int16_t, 1, 2, 3, 2> operand{7812, 15481, -30284, 30996,
- 18736, 6699, 31903, 26229,
- 15931, -18954, -27643, 19133};
- int16_t max_value = 20000;
- Tensor4D<int16_t, 1, 2, 3, 2> expected_result{
- 7812, 15481, 0, 20000, 18736, 6699, 20000, 20000, 15931, 0, 0, 19133};
- Tensor4D<int16_t, 1, 2, 3, 2> result = tosa::reluN(operand, max_value);
-
- EXPECT_THAT(result, Pointwise(FloatEq(), expected_result));
- }
-}
-
// Binary elementwise ops
TEST(tosa, arithmetic_right_shift) {
{
diff --git a/test/Conversion/tosa-to-emitc.mlir b/test/Conversion/tosa-to-emitc.mlir
index 9554201..0a9e2d4 100644
--- a/test/Conversion/tosa-to-emitc.mlir
+++ b/test/Conversion/tosa-to-emitc.mlir
@@ -326,27 +326,3 @@
%1 = "tosa.transpose"(%arg0, %0) : (tensor<13x21x3xf32>, tensor<3xi32>) -> tensor<3x13x21xf32>
return %1 : tensor<3x13x21xf32>
}
-
-func.func @test_relu0(%arg0: tensor<13x21x3xf32>) -> tensor<13x21x3xf32> {
- // CHECK: %0 = emitc.call "emitc::tosa::reluN"(%arg0) {args = [0 : index, 3.40282347E+38 : f32]} : (tensor<13x21x3xf32>) -> tensor<13x21x3xf32>
- %0 = "tosa.reluN"(%arg0) {max_fp = 3.40282347E+38 : f32, max_int = 0 : i64} : (tensor<13x21x3xf32>) -> tensor<13x21x3xf32>
- return %0 : tensor<13x21x3xf32>
-}
-
-func.func @test_relu1(%arg0: tensor<13x21x3xi64>) -> tensor<13x21x3xi64> {
- // CHECK: %0 = emitc.call "emitc::tosa::reluN"(%arg0) {args = [0 : index, 255]} : (tensor<13x21x3xi64>) -> tensor<13x21x3xi64>
- %0 = "tosa.reluN"(%arg0) {max_fp = 0.0 : f32, max_int = 255 : i64} : (tensor<13x21x3xi64>) -> tensor<13x21x3xi64>
- return %0 : tensor<13x21x3xi64>
-}
-
-func.func @test_relu2(%arg0: tensor<13x21x3xi32>) -> tensor<13x21x3xi32> {
- // CHECK: %0 = emitc.call "emitc::tosa::reluN"(%arg0) {args = [0 : index, 255 : i32]} : (tensor<13x21x3xi32>) -> tensor<13x21x3xi32>
- %0 = "tosa.reluN"(%arg0) {max_fp = 0.0 : f32, max_int = 255 : i64} : (tensor<13x21x3xi32>) -> tensor<13x21x3xi32>
- return %0 : tensor<13x21x3xi32>
-}
-
-func.func @test_relu3(%arg0: tensor<13x21x3xf16>) -> tensor<13x21x3xf16> {
- // CHECK: %0 = emitc.call "emitc::tosa::reluN"(%arg0) {args = [0 : index, 1.500000e+00 : f16]} : (tensor<13x21x3xf16>) -> tensor<13x21x3xf16>
- %0 = "tosa.reluN"(%arg0) {max_fp = 1.5 : f32, max_int = 0 : i64} : (tensor<13x21x3xf16>) -> tensor<13x21x3xf16>
- return %0 : tensor<13x21x3xf16>
-}