chore: import upstream snapshot with attribution
cffconvert / validate (push) Has been skipped
License Check / license-check (push) Failing after 2s

This commit is contained in:
wehub-resource-sync
2026-07-13 12:14:16 +08:00
commit 8a852e4b4e
36502 changed files with 9277225 additions and 0 deletions
+29
View File
@@ -0,0 +1,29 @@
load("//tensorflow:tensorflow.default.bzl", "filegroup")
load("//tensorflow/compiler/mlir/tosa:glob_lit_test.bzl", "glob_lit_tests")
package(
# copybara:uncomment default_applicable_licenses = ["//tensorflow:license"],
licenses = ["notice"],
)
glob_lit_tests(
name = "all_tests",
data = [":test_utilities"],
default_tags = ["tf_tosa"],
driver = "@llvm-project//mlir:run_lit.sh",
size_override = {
"tf-to-tosa-pipeline.mlir": "medium",
},
test_file_exts = ["mlir"],
)
# Bundle together all of the test utilities that are used by tests.
filegroup(
name = "test_utilities",
testonly = True,
data = [
"//tensorflow/compiler/mlir/tosa:tf-tosa-opt",
"@llvm-project//llvm:FileCheck",
"@llvm-project//llvm:not",
],
)
@@ -0,0 +1,100 @@
// RUN: tf-tosa-opt --tosa-convert-tfl-uint-to-int --verify-diagnostics --verify-each %s | FileCheck %s
// Operations for testing --tosa-convert-tfl-uint-to-int
// -----
// CHECK-LABEL: test_add_u8
// CHECK: tosa.rescale
// CHECK: tosa.rescale
// CHECK: tfl.add
// CHECK: tosa.rescale
func.func @test_add_u8(%arg0: tensor<14x19x!quant.uniform<u8:f32, 0.015603500418365002:128>>, %arg1: tensor<14x19x!quant.uniform<u8:f32, 0.015612985007464886:127>>) -> tensor<14x19x!quant.uniform<u8:f32, 0.028094837442040443:127>> {
%0 = "tfl.add"(%arg0, %arg1) {fused_activation_function = "NONE"} : (tensor<14x19x!quant.uniform<u8:f32, 0.015603500418365002:128>>, tensor<14x19x!quant.uniform<u8:f32, 0.015612985007464886:127>>) -> tensor<14x19x!quant.uniform<u8:f32, 0.028094837442040443:127>>
func.return %0 : tensor<14x19x!quant.uniform<u8:f32, 0.028094837442040443:127>>
}
// -----
// CHECK-LABEL: test_cast_ui8
// CHECK-DAG: %[[multiplier:.+]] = "tosa.const"() <{values = dense<1073741824> : tensor<1xi32>}> : () -> tensor<1xi32>
// CHECK-DAG: %[[shift:.+]] = "tosa.const"() <{values = dense<30> : tensor<1xi8>}> : () -> tensor<1xi8>
// CHECK-DAG: %[[input_zp:.+]] = "tosa.const"() <{values = dense<-128> : tensor<1xi8>}> : () -> tensor<1xi8>
// CHECK-DAG: %[[output_zp:.+]] = "tosa.const"() <{values = dense<0> : tensor<1xi8>}> : () -> tensor<1xi8>
// CHECK-DAG: tosa.rescale %arg0, %[[multiplier]], %[[shift]], %[[input_zp]], %[[output_zp]] {input_unsigned = true, output_unsigned = false, per_channel = false, rounding_mode = SINGLE_ROUND, scale32 = true}
// CHECK: tfl.cast
func.func @test_cast_ui8(%arg0: tensor<1x256x256x3x!quant.uniform<u8:f32, 0.015603500418365002:128>>) -> tensor<1x256x256x3xf32> {
%0 = "tfl.cast"(%arg0) : (tensor<1x256x256x3x!quant.uniform<u8:f32, 0.015603500418365002:128>>) -> tensor<1x256x256x3xf32>
func.return %0 : tensor<1x256x256x3xf32>
}
// -----
// CHECK-LABEL: test_error_tosa_ops
func.func @test_error_tosa_ops(%arg0: tensor<5x10xi8>) -> (tensor<5x10xi8>, none) {
// Dummy use to TFL dialect to load TFL dialect in MLIR context
%0 = "tfl.no_value"() <{value}> : () -> none
// expected-error @+1 {{tosa operations are not expected in this pass. Run tosa-convert-tfl-uint-to-int before tosa-legalize-tfl}}
%cst1 = "tosa.const"() <{values = dense<1> : tensor<5x10xi8>}> : () -> tensor<5x10xi8>
// expected-error @+1 {{tosa operations are not expected in this pass. Run tosa-convert-tfl-uint-to-int before tosa-legalize-tfl}}
%1 = "tosa.add"(%arg0, %cst1) : (tensor<5x10xi8>, tensor<5x10xi8>) -> tensor<5x10xi8>
func.return %1, %0 : tensor<5x10xi8>, none
}
// -----
// CHECK-LABEL: test_cast_ui32_with_zp
// expected-error @+1 {{Input argument has unsigned quantized type with zero point 128 which is not supported by TOSA for bitwidth 32.}}
func.func @test_cast_ui32_with_zp(%arg0: tensor<1x256x256x3x!quant.uniform<u32:f32, 0.015603500418365002:128>>) -> tensor<1x256x256x3xf32> {
%0 = "tfl.cast"(%arg0) : (tensor<1x256x256x3x!quant.uniform<u32:f32, 0.015603500418365002:128>>) -> tensor<1x256x256x3xf32>
func.return %0 : tensor<1x256x256x3xf32>
}
// -----
// CHECK-LABEL: func.func @test_cast_ui32(
// CHECK-SAME: %[[ARG0:.*]]: tensor<1x256x256x3x!quant.uniform<u32:f32, 0.015603500418365002>>) -> tensor<1x256x256x3xf32> {
// CHECK: %[[VAL_0:.*]] = "tosa.const"() <{values = dense<1073741824> : tensor<1xi32>}> : () -> tensor<1xi32>
// CHECK: %[[VAL_1:.*]] = "tosa.const"() <{values = dense<30> : tensor<1xi8>}> : () -> tensor<1xi8>
// CHECK: %[[VAL_2:.*]] = "tosa.const"() <{values = dense<0> : tensor<1xi32>}> : () -> tensor<1xi32>
// CHECK: %[[VAL_3:.*]] = "tosa.const"() <{values = dense<0> : tensor<1xi32>}> : () -> tensor<1xi32>
// CHECK: %[[RESCALE_0:.*]] = tosa.rescale %[[ARG0]], %[[VAL_0]], %[[VAL_1]], %[[VAL_2]], %[[VAL_3]] {input_unsigned = true, output_unsigned = false, per_channel = false, rounding_mode = SINGLE_ROUND, scale32 = true} : (tensor<1x256x256x3x!quant.uniform<u32:f32, 0.015603500418365002>>, tensor<1xi32>, tensor<1xi8>, tensor<1xi32>, tensor<1xi32>) -> tensor<1x256x256x3x!quant.uniform<i32:f32, 0.031207000843995952>>
// CHECK: %[[VAL_4:.*]] = "tfl.cast"(%[[RESCALE_0]]) : (tensor<1x256x256x3x!quant.uniform<i32:f32, 0.031207000843995952>>) -> tensor<1x256x256x3xf32>
// CHECK: return %[[VAL_4]]
func.func @test_cast_ui32(%arg0: tensor<1x256x256x3x!quant.uniform<u32:f32, 0.015603500418365002:0>>) -> tensor<1x256x256x3xf32> {
%0 = "tfl.cast"(%arg0) : (tensor<1x256x256x3x!quant.uniform<u32:f32, 0.015603500418365002:0>>) -> tensor<1x256x256x3xf32>
func.return %0 : tensor<1x256x256x3xf32>
}
// -----
// CHECK-LABEL: func.func @test_cast_ui8_small_range(
// CHECK-SAME: %[[ARG0:.*]]: tensor<1x256x256x3x!quant.uniform<u8<10:150>:f32, 0.015603500418365002:50>>) -> tensor<1x256x256x3xf32> {
// CHECK: %[[VAL_0:.*]] = "tosa.const"() <{values = dense<1073741824> : tensor<1xi32>}> : () -> tensor<1xi32>
// CHECK: %[[VAL_1:.*]] = "tosa.const"() <{values = dense<30> : tensor<1xi8>}> : () -> tensor<1xi8>
// CHECK: %[[VAL_2:.*]] = "tosa.const"() <{values = dense<50> : tensor<1xi8>}> : () -> tensor<1xi8>
// CHECK: %[[VAL_3:.*]] = "tosa.const"() <{values = dense<-55> : tensor<1xi8>}> : () -> tensor<1xi8>
// CHECK: %[[RESCALE_0:.*]] = tosa.rescale %[[ARG0]], %[[VAL_0]], %[[VAL_1]], %[[VAL_2]], %[[VAL_3]] {input_unsigned = true, output_unsigned = false, per_channel = false, rounding_mode = SINGLE_ROUND, scale32 = true} : (tensor<1x256x256x3x!quant.uniform<u8<10:150>:f32, 0.015603500418365002:50>>, tensor<1xi32>, tensor<1xi8>, tensor<1xi8>, tensor<1xi8>) -> tensor<1x256x256x3x!quant.uniform<i8:f32, 0.0085666276806709817:-55>>
// CHECK: %[[VAL_4:.*]] = "tfl.cast"(%[[RESCALE_0]]) : (tensor<1x256x256x3x!quant.uniform<i8:f32, 0.0085666276806709817:-55>>) -> tensor<1x256x256x3xf32>
// CHECK: return %[[VAL_4]]
func.func @test_cast_ui8_small_range(%arg0: tensor<1x256x256x3x!quant.uniform<u8<10:150>:f32, 0.015603500418365002:50>>) -> tensor<1x256x256x3xf32> {
%0 = "tfl.cast"(%arg0) : (tensor<1x256x256x3x!quant.uniform<u8<10:150>:f32, 0.015603500418365002:50>>) -> tensor<1x256x256x3xf32>
func.return %0 : tensor<1x256x256x3xf32>
}
// -----
// CHECK-LABEL: func.func @test_cast_ui8_narrow_range(
// CHECK-SAME: %[[ARG0:.*]]: tensor<1x256x256x3x!quant.uniform<u8<1:150>:f32, 0.015603500418365002:50>>) -> tensor<1x256x256x3xf32> {
// CHECK: %[[VAL_0:.*]] = "tosa.const"() <{values = dense<1073741824> : tensor<1xi32>}> : () -> tensor<1xi32>
// CHECK: %[[VAL_1:.*]] = "tosa.const"() <{values = dense<30> : tensor<1xi8>}> : () -> tensor<1xi8>
// CHECK: %[[VAL_2:.*]] = "tosa.const"() <{values = dense<50> : tensor<1xi8>}> : () -> tensor<1xi8>
// CHECK: %[[VAL_3:.*]] = "tosa.const"() <{values = dense<-43> : tensor<1xi8>}> : () -> tensor<1xi8>
// CHECK: %[[RESCALE_0:.*]] = tosa.rescale %[[ARG0]], %[[VAL_0]], %[[VAL_1]], %[[VAL_2]], %[[VAL_3]] {input_unsigned = true, output_unsigned = false, per_channel = false, rounding_mode = SINGLE_ROUND, scale32 = true} : (tensor<1x256x256x3x!quant.uniform<u8<1:150>:f32, 0.015603500418365002:50>>, tensor<1xi32>, tensor<1xi8>, tensor<1xi8>, tensor<1xi8>) -> tensor<1x256x256x3x!quant.uniform<i8<-127:127>:f32, 0.0091532344973873428:-43>>
// CHECK: %[[VAL_4:.*]] = "tfl.cast"(%[[RESCALE_0]]) : (tensor<1x256x256x3x!quant.uniform<i8<-127:127>:f32, 0.0091532344973873428:-43>>) -> tensor<1x256x256x3xf32>
// CHECK: return %[[VAL_4]]
func.func @test_cast_ui8_narrow_range(%arg0: tensor<1x256x256x3x!quant.uniform<u8<1:150>:f32, 0.015603500418365002:50>>) -> tensor<1x256x256x3xf32> {
%0 = "tfl.cast"(%arg0) : (tensor<1x256x256x3x!quant.uniform<u8<1:150>:f32, 0.015603500418365002:50>>) -> tensor<1x256x256x3xf32>
func.return %0 : tensor<1x256x256x3xf32>
}
@@ -0,0 +1,26 @@
// RUN: tf-tosa-opt --split-input-file --pass-pipeline='builtin.module(func.func(tosa-tflite-convert-function-metadata))' %s | FileCheck %s
module attributes {tfl.schema_version = 3 : i32} {
// CHECK: func.func @main(
// CHECK-SAME: %arg0: tensor<?xf32> {ml_program.identifier = "input0"},
// CHECK-SAME: %arg1: tensor<?xf32> {ml_program.identifier = "input1"}
// CHECK-SAME: ) -> (
// CHECK-SAME: tensor<?xf32> {ml_program.identifier = "output0"},
// CHECK-SAME: tensor<?xf32> {ml_program.identifier = "output1"})
func.func @main(%arg0: tensor<?xf32>, %arg1: tensor<?xf32>) -> (tensor<?xf32>, tensor<?xf32>) attributes {
tf.entry_function = {inputs = "input0,input1", outputs = "output0,output1"}
} {
return %arg0, %arg1 : tensor<?xf32>, tensor<?xf32>
}
// CHECK: func.func @no_input(
// CHECK-SAME: ) -> (
// CHECK-SAME: tensor<1xf32> {ml_program.identifier = "output0"})
func.func @no_input() -> (tensor<1xf32>) attributes {
tf.entry_function = {outputs = "output0"}
} {
%0 = "tfl.pseudo_const"() {value = dense<0.000000e+00> : tensor<1xf32>} : () -> tensor<1xf32>
return %0 : tensor<1xf32>
}
}
@@ -0,0 +1,16 @@
// RUN: tf-tosa-opt --tosa-fuse-bias-tf --verify-each %s | FileCheck %s
// Operations for testing --tosa-fuse-bias-tf
// ----
// CHECK-LABEL: test_conv2d_bias
// CHECK: tosa.transpose
// CHECK: tosa.conv2d
func.func @test_conv2d_bias(%arg0: tensor<1x4x4x4xf32>, %arg1: tensor<3x3x4x8xf32>, %arg2: tensor<8xf32>) -> tensor<1x4x4x8xf32> {
%0 = "tf.Conv2D"(%arg0, %arg1) {data_format = "NHWC", device = "", dilations = [1, 1, 1, 1], explicit_paddings = [], padding = "SAME", strides = [1, 1, 1, 1], use_cudnn_on_gpu = true} : (tensor<1x4x4x4xf32>, tensor<3x3x4x8xf32>) -> tensor<1x4x4x8xf32>
%1 = "tf.BiasAdd"(%0, %arg2) {data_format = "NHWC"} : (tensor<1x4x4x8xf32>, tensor<8xf32>) -> tensor<1x4x4x8xf32>
func.return %1 : tensor<1x4x4x8xf32>
}
@@ -0,0 +1,43 @@
// RUN: tf-tosa-opt --split-input-file --tosa-lower-complex-types --verify-each %s | FileCheck %s
// CHECK-LABEL: test_complex_input
// CHECK-SAME: %[[VAL_0:.*]]: tensor<1x4x4x2xf32>
// CHECK: return %[[VAL_0]] : tensor<1x4x4x2xf32>
func.func @test_complex_input(%arg0: tensor<1x4x4xcomplex<f32>>) -> (tensor<1x4x4x2xf32>) {
%0 = builtin.unrealized_conversion_cast %arg0 : tensor<1x4x4xcomplex<f32>> to tensor<1x4x4x2xf32>
return %0 : tensor<1x4x4x2xf32>
}
// -----
// CHECK-LABEL: test_complex_output
// CHECK-SAME: %[[VAL_0:.*]]: tensor<1x4x4x2xf32>
// CHECK: return %[[VAL_0]] : tensor<1x4x4x2xf32>
func.func @test_complex_output(%arg0: tensor<1x4x4x2xf32>) -> (tensor<1x4x4xcomplex<f32>>) {
%0 = builtin.unrealized_conversion_cast %arg0 : tensor<1x4x4x2xf32> to tensor<1x4x4xcomplex<f32>>
return %0 : tensor<1x4x4xcomplex<f32>>
}
// -----
// CHECK-LABEL: test_mixed_input
// CHECK-SAME: %[[VAL_0:.*]]: tensor<1x4x4x2xf32>, %[[VAL_1:.*]]: tensor<1x4x4x2xf32>, %[[VAL_2:.*]]: tensor<1x4x4xf32>
// CHECK: return %[[VAL_0]], %[[VAL_1]], %[[VAL_2]] : tensor<1x4x4x2xf32>, tensor<1x4x4x2xf32>, tensor<1x4x4xf32>
func.func @test_mixed_input(%arg0: tensor<1x4x4xcomplex<f32>>, %arg1: tensor<1x4x4xcomplex<f32>>, %arg2: tensor<1x4x4xf32>)
-> (tensor<1x4x4x2xf32>, tensor<1x4x4x2xf32>, tensor<1x4x4xf32>) {
%0 = builtin.unrealized_conversion_cast %arg0 : tensor<1x4x4xcomplex<f32>> to tensor<1x4x4x2xf32>
%1 = builtin.unrealized_conversion_cast %arg1 : tensor<1x4x4xcomplex<f32>> to tensor<1x4x4x2xf32>
return %0, %1, %arg2 : tensor<1x4x4x2xf32>, tensor<1x4x4x2xf32>, tensor<1x4x4xf32>
}
// -----
// CHECK-LABEL: test_mixed_output
// CHECK-SAME: %[[VAL_0:.*]]: tensor<1x4x4x2xf32>, %[[VAL_1:.*]]: tensor<1x4x4xf32>
// CHECK: return %[[VAL_0]], %[[VAL_1]] : tensor<1x4x4x2xf32>, tensor<1x4x4xf32>
func.func @test_mixed_output(%arg0: tensor<1x4x4x2xf32>, %arg1: tensor<1x4x4xf32>)
-> (tensor<1x4x4xcomplex<f32>>, tensor<1x4x4xf32>) {
%0 = builtin.unrealized_conversion_cast %arg0 : tensor<1x4x4x2xf32> to tensor<1x4x4xcomplex<f32>>
return %0, %arg1 : tensor<1x4x4xcomplex<f32>>, tensor<1x4x4xf32>
}
@@ -0,0 +1,17 @@
// RUN: tf-tosa-opt --tfl-to-tosa-pipeline=target-compilation-backend %s | FileCheck %s
// CHECK: tensor<1x8x8x3xf32> {ml_program.identifier = "a"}
// CHECK-SAME: tensor<1x8x8x3xf32> {ml_program.identifier = "b"}
// CHECK-SAME: tensor<1x8x8x3xf32> {ml_program.identifier = "c"}
// CHECK-SAME: tensor<1x8x8x3xf32> {ml_program.identifier = "d"}
// CHECK-SAME: -> (tensor<1x8x8x3xf32> {ml_program.identifier = "x"}, tensor<1x8x8x3xf32> {ml_program.identifier = "y"})
module attributes {tfl.schema_version = 3 : i32} {
func.func @main(%arg0: tensor<1x8x8x3xf32>, %arg1: tensor<1x8x8x3xf32>, %arg2: tensor<1x8x8x3xf32>, %arg3: tensor<1x8x8x3xf32>) -> (tensor<1x8x8x3xf32>, tensor<1x8x8x3xf32>) attributes {tf.entry_function = {inputs = "a,b,c,d", outputs = "x,y"}} {
%0 = tfl.add %arg1, %arg2 {fused_activation_function = "NONE"} : tensor<1x8x8x3xf32>
%1 = tfl.add %arg0, %0 {fused_activation_function = "NONE"} : tensor<1x8x8x3xf32>
%2 = tfl.add %arg3, %0 {fused_activation_function = "NONE"} : tensor<1x8x8x3xf32>
return %1, %2 : tensor<1x8x8x3xf32>, tensor<1x8x8x3xf32>
}
}
@@ -0,0 +1,22 @@
// RUN: tf-tosa-opt --split-input-file --pass-pipeline='builtin.module(tflite-retain-call-once-funcs)' %s | FileCheck %s
// CHECK-LABEL: module {
module {
// CHECK-LABEL: @main
func.func @main(%arg0: tensor<16x16xf32>) -> (tensor<16x16xf32>) {
// CHECK: "tfl.call_once"() <{session_init_function = "NoOp"}> {session_init_function_symbol = @NoOp} : () -> ()
"tfl.call_once"() {session_init_function = "NoOp"} : () -> ()
%0 = "tfl.var_handle"() {container = "", shared_name = "Variable"} : () -> tensor<*x!tf_type.resource>
%1 = "tfl.read_variable"(%0) : (tensor<*x!tf_type.resource>) -> tensor<16x16xf32>
%2 = tfl.add %1, %arg0 {fused_activation_function = "NONE"} : tensor<16x16xf32>
"tfl.assign_variable"(%0, %2) : (tensor<*x!tf_type.resource>, tensor<16x16xf32>) -> ()
return %2 : tensor<16x16xf32>
}
func.func private @NoOp() {
%0 = "tfl.var_handle"() {container = "", shared_name = "Variable"} : () -> tensor<*x!tf_type.resource>
%1 = "tfl.pseudo_const"() {value = dense<0.000000e+00> : tensor<16x16xf32>} : () -> tensor<16x16xf32>
"tfl.assign_variable"(%0, %1) : (tensor<*x!tf_type.resource>, tensor<16x16xf32>) -> ()
return
}
}
@@ -0,0 +1,26 @@
// RUN: tf-tosa-opt --split-input-file --tosa-strip-quant-types --verify-each %s | FileCheck %s
// -----
// CHECK-LABEL: @test_max_pool2d_qi8
// CHECK-SAME: %arg0: tensor<1x4x4x4xi8>) -> tensor<1x4x4x4xi8>
func.func @test_max_pool2d_qi8(%arg0: tensor<1x4x4x4x!quant.uniform<i8:f32, 0.1:1>>) -> tensor<1x4x4x4x!quant.uniform<i8:f32, 0.1:1>> {
%0 = "tosa.max_pool2d"(%arg0) {kernel = array<i64: 1, 1>, pad = array<i64: 0, 0, 0, 0>, stride = array<i64: 1, 1>} : (tensor<1x4x4x4x!quant.uniform<i8:f32, 0.1:1>>) -> tensor<1x4x4x4x!quant.uniform<i8:f32, 0.1:1>>
// CHECK: %[[VAR0:.+]] = tosa.max_pool2d %arg0 {kernel = array<i64: 1, 1>, pad = array<i64: 0, 0, 0, 0>, stride = array<i64: 1, 1>} : (tensor<1x4x4x4xi8>) -> tensor<1x4x4x4xi8>
// CHECK: return %[[VAR0]] : tensor<1x4x4x4xi8>
func.return %0 : tensor<1x4x4x4x!quant.uniform<i8:f32, 0.1:1>>
}
// -----
// CHECK-LABEL: @test_bitwise_not_qu8
// CHECK-SAME: %arg0: tensor<ui8>) -> tensor<ui8>
func.func @test_bitwise_not_qu8(%arg0: tensor<!quant.uniform<u8:f32, 0.1:1>>) -> tensor<!quant.uniform<u8:f32, 0.1:1>> {
%0 = "tosa.bitwise_not"(%arg0) : (tensor<!quant.uniform<u8:f32, 0.1:1>>) -> tensor<!quant.uniform<u8:f32, 0.1:1>>
// CHECK: %[[VAR0:.+]] = tosa.bitwise_not %arg0 : (tensor<ui8>) -> tensor<ui8>
// CHECK: return %[[VAR0]] : tensor<ui8>
func.return %0 : tensor<!quant.uniform<u8:f32, 0.1:1>>
}
@@ -0,0 +1,15 @@
// RUN: tf-tosa-opt --pass-pipeline='builtin.module(tosa-tflite-strip-module-metadata,func.func(tosa-tflite-strip-function-metadata))' %s | FileCheck %s
// CHECK-LABEL: module {
// CHECK-NOT: tf.schema_version
module attributes {tfl.schema_version = 3 : i32} {
// CHECK: func.func @main
// CHECK-NOT: tf.entry_function
func.func @main(%arg0: tensor<1x8x8x3xf32>) -> tensor<1x8x8x3xf32> attributes {tf.entry_function = {inputs = "input", outputs = "output"}} {
// CHECK-NEXT: tfl.add
%0 = tfl.add %arg0, %arg0 {fused_activation_function = "NONE"} : tensor<1x8x8x3xf32>
%1 = tfl.add %0, %arg0 {fused_activation_function = "NONE"} : tensor<1x8x8x3xf32>
return %1 : tensor<1x8x8x3xf32>
}
}
@@ -0,0 +1,21 @@
// RUN: tf-tosa-opt --split-input-file --tf-tfl-to-tosa-pipeline --verify-each %s | FileCheck %s
// These tests focus on TensorFlow and TensorFlow Lite hybrid lowering and focus
// on tfl.custom operations that are Flex ops.
// This test demonstrates how legalize and shape inference can be performed
// using the flex op legalization, and tensorflow-to-tosa legalization. The
// resulting cast is to maintain the function contract.
//
// To add a Flex op test you will need to compile a TF model with a flex op,
// then import the model. The opaque data is a serialize TF Node proto so not
// feasible to hand edit.
// CHECK-LABEL: func @test_flex_shape
// CHECK-SAME: tensor<?x2x64xf32>
func.func @test_flex_shape(%arg0: tensor<?x2x64xf32>, %arg1: tensor<1x1x64xf32>) -> tensor<*xf32> {
// CHECK: %[[ADD:.+]] = tosa.add %arg0, %arg1 : (tensor<?x2x64xf32>, tensor<1x1x64xf32>) -> tensor<?x2x64xf32>
// CHECK: return %[[ADD]]
%0 = "tfl.custom"(%arg0, %arg1) {custom_code = "FlexAddV2", custom_option = #tfl<const_bytes : "0x054164645632002E120541646456321A001A002A070A01541202300132180A16726573696475616C5F626C6F636B5F2E5F302F616464000237311414042801">} : (tensor<?x2x64xf32>, tensor<1x1x64xf32>) -> tensor<*xf32>
func.return %0: tensor<*xf32>
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,186 @@
// RUN: tf-tosa-opt --split-input-file --tf-to-tosa-pipeline --verify-each %s | FileCheck %s
// Test tf legalization that produce TOSA ResultsBroadcastableShape operators with unequal ranks
// -----
// CHECK-LABEL: test_add
func.func @test_add(%arg0: tensor<13x21x1xf32>, %arg1: tensor<1x13x21x3xf32>) -> tensor<*xf32> {
// CHECK: tosa.add
%2 = "tf.Add"(%arg0, %arg1) : (tensor<13x21x1xf32>, tensor<1x13x21x3xf32>) -> tensor<*xf32>
func.return %2 : tensor<*xf32>
}
// -----
// CHECK-LABEL: test_add
func.func @test_addn(%arg0: tensor<13x21x1xf32>, %arg1: tensor<1x13x21x3xf32>, %arg2: tensor<21x3xf32>, %arg3: tensor<3xf32>) -> tensor<*xf32> {
// CHECK: tosa.add
// CHECK: tosa.add
// CHECK: tosa.add
%2 = "tf.AddN"(%arg0, %arg1, %arg2, %arg3) : (tensor<13x21x1xf32>, tensor<1x13x21x3xf32>, tensor<21x3xf32>, tensor<3xf32>) -> tensor<*xf32>
func.return %2 : tensor<*xf32>
}
// -----
// CHECK-LABEL: test_bitwise_and
func.func @test_bitwise_and(%arg0: tensor<8x13x21x3xi32>, %arg1: tensor<13x21x1xi32>) -> tensor<8x13x21x3xi32> {
// CHECK: tosa.bitwise_and
%2 = "tf.BitwiseAnd"(%arg0, %arg1) : (tensor<8x13x21x3xi32>, tensor<13x21x1xi32>) -> tensor<8x13x21x3xi32>
func.return %2 : tensor<8x13x21x3xi32>
}
// -----
// CHECK-LABEL: test_sub
func.func @test_sub(%arg0: tensor<13x21x1xf32>, %arg1: tensor<1x13x21x3xf32>) -> tensor<*xf32> {
// CHECK: tosa.sub
%2 = "tf.Sub"(%arg0, %arg1) : (tensor<13x21x1xf32>, tensor<1x13x21x3xf32>) -> tensor<*xf32>
func.return %2 : tensor<*xf32>
}
// -----
// CHECK-LABEL: test_bitwise_or
func.func @test_bitwise_or(%arg0: tensor<8x13x21x3xi32>, %arg1: tensor<13x21x1xi32>) -> tensor<8x13x21x3xi32> {
// CHECK: tosa.bitwise_or
%2 = "tf.BitwiseOr"(%arg0, %arg1) : (tensor<8x13x21x3xi32>, tensor<13x21x1xi32>) -> tensor<8x13x21x3xi32>
func.return %2 : tensor<8x13x21x3xi32>
}
// -----
// CHECK-LABEL: test_bitwise_xor
func.func @test_bitwise_xor(%arg0: tensor<8x13x21x3xi32>, %arg1: tensor<13x21x1xi32>) -> tensor<8x13x21x3xi32> {
// CHECK: tosa.bitwise_xor
%2 = "tf.BitwiseXor"(%arg0, %arg1) : (tensor<8x13x21x3xi32>, tensor<13x21x1xi32>) -> tensor<8x13x21x3xi32>
func.return %2 : tensor<8x13x21x3xi32>
}
// -----
// CHECK-LABEL: test_logical_and
func.func @test_logical_and(%arg0: tensor<8x13x21x3xi1>, %arg1: tensor<13x21x1xi1>) -> tensor<8x13x21x3xi1> {
// CHECK: tosa.logical_and
%2 = "tf.LogicalAnd"(%arg0, %arg1) : (tensor<8x13x21x3xi1>, tensor<13x21x1xi1>) -> tensor<8x13x21x3xi1>
func.return %2 : tensor<8x13x21x3xi1>
}
// -----
// CHECK-LABEL: test_logical_or
func.func @test_logical_or(%arg0: tensor<8x13x21x3xi1>, %arg1: tensor<13x21x1xi1>) -> tensor<8x13x21x3xi1> {
// CHECK: tosa.logical_or
%2 = "tf.LogicalOr"(%arg0, %arg1) : (tensor<8x13x21x3xi1>, tensor<13x21x1xi1>) -> tensor<8x13x21x3xi1>
func.return %2 : tensor<8x13x21x3xi1>
}
// -----
// CHECK-LABEL: test_floor_div
// CHECK: tosa.intdiv
// CHECK: tosa.select
func.func @test_floor_div(%arg0: tensor<13x21x3xi32>, %arg1: tensor<1x13x1x3xi32>) -> tensor<1x13x21x3xi32> {
%2 = "tf.FloorDiv"(%arg0, %arg1) : (tensor<13x21x3xi32>, tensor<1x13x1x3xi32>) -> tensor<1x13x21x3xi32>
func.return %2 : tensor<1x13x21x3xi32>
}
// -----
// CHECK-LABEL: test_real_div
// CHECK: tosa.intdiv
func.func @test_real_div(%arg0: tensor<13x21x3xi32>, %arg1: tensor<1x13x1x3xi32>) -> tensor<1x13x21x3xi32> {
%2 = "tf.RealDiv"(%arg0, %arg1) : (tensor<13x21x3xi32>, tensor<1x13x1x3xi32>) -> tensor<1x13x21x3xi32>
func.return %2 : tensor<1x13x21x3xi32>
}
// -----
// CHECK-LABEL: test_left_shift
func.func @test_left_shift(%arg0: tensor<4x4xi32>, %arg1: tensor<1x1x1xi32>) -> tensor<1x4x4xi32> {
// CHECK: tosa.logical_left_shift
%0 = "tf.LeftShift"(%arg0, %arg1) : (tensor<4x4xi32>, tensor<1x1x1xi32>) -> tensor<1x4x4xi32>
func.return %0 : tensor<1x4x4xi32>
}
// -----
// CHECK-LABEL: test_right_shift
func.func @test_right_shift(%arg0: tensor<4x4xi32>, %arg1: tensor<1x1x1xi32>) -> tensor<1x4x4xi32> {
// CHECK: tosa.arithmetic_right_shift
%0 = "tf.RightShift"(%arg0, %arg1) : (tensor<4x4xi32>, tensor<1x1x1xi32>) -> tensor<1x4x4xi32>
func.return %0 : tensor<1x4x4xi32>
}
// -----
// CHECK-LABEL: test_max
func.func @test_max(%arg0: tensor<13x21x3xf32>, %arg1: tensor<1x13x21x1xf32>) -> tensor<1x13x21x3xf32> {
// CHECK: tosa.maximum
%2 = "tf.Maximum"(%arg0, %arg1) : (tensor<13x21x3xf32>, tensor<1x13x21x1xf32>) -> tensor<1x13x21x3xf32>
func.return %2 : tensor<1x13x21x3xf32>
}
// -----
// CHECK-LABEL: test_min
func.func @test_min(%arg0: tensor<13x21x3xf32>, %arg1: tensor<1x13x21x1xf32>) -> tensor<1x13x21x3xf32> {
// CHECK: tosa.minimum
%2 = "tf.Minimum"(%arg0, %arg1) : (tensor<13x21x3xf32>, tensor<1x13x21x1xf32>) -> tensor<1x13x21x3xf32>
func.return %2 : tensor<1x13x21x3xf32>
}
// -----
// CHECK-LABEL: test_power
func.func @test_power(%arg0: tensor<8x13x21x3xi32>, %arg1: tensor<13x21x1xi32>) -> tensor<8x13x21x3xi32> {
// CHECK: tosa.pow
%2 = "tf.Pow"(%arg0, %arg1) : (tensor<8x13x21x3xi32>, tensor<13x21x1xi32>) -> tensor<8x13x21x3xi32>
func.return %2 : tensor<8x13x21x3xi32>
}
// -----
// CHECK-LABEL: test_equal
// CHECK: tosa.equal
func.func @test_equal(%arg0: tensor<13x21x3xf32>, %arg1: tensor<1x13x1x3xf32>) -> tensor<1x13x21x3xi1> {
%2 = "tf.Equal"(%arg0, %arg1) {incompatible_shape_error = true} : (tensor<13x21x3xf32>, tensor<1x13x1x3xf32>) -> tensor<1x13x21x3xi1>
func.return %2 : tensor<1x13x21x3xi1>
}
// -----
// CHECK-LABEL: test_greater_equal
// CHECK: tosa.greater_equal
func.func @test_greater_equal(%arg0: tensor<13x1x3xf32>, %arg1: tensor<1x13x21x3xf32>) -> tensor<1x13x21x3xi1> {
%2 = "tf.GreaterEqual"(%arg0, %arg1) : (tensor<13x1x3xf32>, tensor<1x13x21x3xf32>) -> tensor<1x13x21x3xi1>
func.return %2 : tensor<1x13x21x3xi1>
}
// -----
// CHECK-LABEL: test_greater
// CHECK: tosa.greater
func.func @test_greater(%arg0: tensor<13x21x1xf32>, %arg1: tensor<1x13x21x3xf32>) -> tensor<1x13x21x3xi1> {
%2 = "tf.Greater"(%arg0, %arg1) : (tensor<13x21x1xf32>, tensor<1x13x21x3xf32>) -> tensor<1x13x21x3xi1>
func.return %2 : tensor<1x13x21x3xi1>
}
// -----
// CHECK-LABEL: test_less
// CHECK: tosa.greater_equal
// CHECK: tosa.logical_not
func.func @test_less(%arg0: tensor<13x21x1xf32>, %arg1: tensor<1x13x21x3xf32>) -> tensor<1x13x21x3xi1> {
%2 = "tf.Less"(%arg0, %arg1) : (tensor<13x21x1xf32>, tensor<1x13x21x3xf32>) -> tensor<1x13x21x3xi1>
func.return %2 : tensor<1x13x21x3xi1>
}
// -----
// CHECK-LABEL: test_select
// CHECK: tosa.select
func.func @test_select(%arg0: tensor<13x21x3xf32>, %arg1: tensor<1x13x21x3xf32>, %arg2: tensor<1xi1>) -> tensor<1x13x21x3xf32> {
%2 = "tf.SelectV2"(%arg2, %arg0, %arg1) : (tensor<1xi1>, tensor<13x21x3xf32>, tensor<1x13x21x3xf32>) -> tensor<1x13x21x3xf32>
func.return %2 : tensor<1x13x21x3xf32>
}
@@ -0,0 +1,17 @@
// RUN: tf-tosa-opt --tosa-dequantize-tfl-softmax %s | FileCheck %s
// -----
// CHECK-LABEL: test_softmax_qi8
// CHECK-SAME: %[[INPUT:.*]]: tensor<8x!quant.uniform<i8:f32, {{.*}}>>
// CHECK: %[[DEQUANTIZED_INPUT:.*]] = "tfl.dequantize"(%[[INPUT]])
// CHECK: %[[FLOAT_SOFTMAX:.*]] = "tfl.softmax"(%[[DEQUANTIZED_INPUT]])
// CHECK: %[[QUANTIZED_FLOAT_SOFTMAX:.*]] = "tfl.quantize"(%[[FLOAT_SOFTMAX]])
// CHECK: return %[[QUANTIZED_FLOAT_SOFTMAX]]
func.func @test_softmax_qi8(%arg0: tensor<8x!quant.uniform<i8:f32, 0.015>>) -> tensor<8x!quant.uniform<i8:f32, 3.9e-03:-128>> {
%0 = "tfl.softmax"(%arg0) {beta = 1.2 : f32} : (tensor<8x!quant.uniform<i8:f32, 0.015>>) -> tensor<8x!quant.uniform<i8:f32, 3.9e-03:-128>>
func.return %0 : tensor<8x!quant.uniform<i8:f32, 3.9e-03:-128>>
}
// -----
@@ -0,0 +1,46 @@
// RUN: tf-tosa-opt --pass-pipeline='builtin.module(func.func(tosa-legalize-tfl{disable-patterns=TFLConv2D,TFLSoftmax, enable-patterns=TFLFullyConnected,TFLTranspose}))' %s | FileCheck %s
// -----
// CHECK-LABEL: test_conv2d
// CHECK-DAG: %[[VAR0:.*]] = arith.constant dense<0.000000e+00> : tensor<16xf32>
// CHECK: %[[VAR1:.*]] = "tfl.conv_2d"(%arg0, %arg1, %[[VAR0]]) <{dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32}>
func.func @test_conv2d(%arg0: tensor<1x32x32x8xf32>, %arg1: tensor<16x2x2x8xf32>) -> tensor<*xf32> {
%cst = arith.constant dense<0.000000e+00> : tensor<16xf32>
%0 = "tfl.conv_2d"(%arg0, %arg1, %cst) {dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32} : (tensor<1x32x32x8xf32>, tensor<16x2x2x8xf32>, tensor<16xf32>) -> tensor<*xf32>
func.return %0 : tensor<*xf32>
}
// -----
// CHECK-LABEL: func @test_softmax(
// CHECK-SAME:%[[VAR0:.*]]: tensor<13x21x3xf32>) -> tensor<13x21x3xf32> {
// CHECK: %[[VAR1:.*]] = "tfl.softmax"(%[[VAR0]]) <{beta = 1.000000e+00 : f32}> : (tensor<13x21x3xf32>) -> tensor<13x21x3xf32>
// CHECK: return %[[VAR1]] : tensor<13x21x3xf32>
func.func @test_softmax(%arg0: tensor<13x21x3xf32>) -> tensor<13x21x3xf32> {
%0 = "tfl.softmax"(%arg0) {beta = 1.000000e+00 : f32} : (tensor<13x21x3xf32>) -> tensor<13x21x3xf32>
func.return %0 : tensor<13x21x3xf32>
}
// -----
// CHECK-LABEL: test_matmul
// CHECK-DAG: %[[CONST0:.*]] = tosa.const_shape {values = dense<[14, 1, 1, 19]> : tensor<4xindex>}
// CHECK-DAG: %[[CONST1:.*]] = tosa.const_shape {values = dense<[28, 1, 1, 19]> : tensor<4xindex>}
// CHECK-DAG: %[[CONST2:.*]] = tosa.const_shape {values = dense<[14, 28]> : tensor<2xindex>}
// CHECK-DAG: %[[CONST3:.*]] = "tosa.const"() <{values = dense<0.000000e+00> : tensor<1xf32>}>
// CHECK: %[[VAR1:.*]] = tosa.transpose %arg1 {perms = array<i32: 1, 0>}
// CHECK-DAG: %[[VAR2:.*]] = tosa.reshape %arg0, %[[CONST0]]
// CHECK-DAG: %[[VAR3:.*]] = tosa.reshape %[[VAR1]], %[[CONST1]]
// CHECK-DAG: %[[VAR4:.*]] = tosa.conv2d %[[VAR2]], %[[VAR3]], %[[CONST3]], %[[CONST3]], %[[CONST3]] {acc_type = f32, dilation = array<i64: 1, 1>, pad = array<i64: 0, 0, 0, 0>, stride = array<i64: 1, 1>}
// CHECK: %[[VAR5:.*]] = tosa.reshape %[[VAR4]], %[[CONST2]]
func.func @test_matmul(%arg0: tensor<14x19xf32>, %arg1: tensor<19x28xf32>) -> tensor<*xf32> {
%cst = arith.constant dense<[1, 0]> : tensor<2xi32>
%cst_0 = "tfl.no_value"() {value = unit} : () -> none
%0 = "tfl.transpose"(%arg1, %cst) : (tensor<19x28xf32>, tensor<2xi32>) -> tensor<*xf32>
%1 = "tfl.fully_connected"(%arg0, %0, %cst_0) {fused_activation_function = "NONE", keep_num_dims = false, weights_format = "DEFAULT"} : (tensor<14x19xf32>, tensor<*xf32>, none) -> tensor<*xf32>
func.return %1 : tensor<*xf32>
}
// -----
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,93 @@
// RUN: tf-tosa-opt --split-input-file --tfl-to-tosa-pipeline --verify-each %s | FileCheck %s
// RUN: tf-tosa-opt --split-input-file --tf-tfl-to-tosa-pipeline --verify-each %s | FileCheck %s
// Operations for testing tfl-to-tosa-pipeline
// -----
// CHECK-LABEL: tosa.variable @var_x = dense<7.000000e+00> : tensor<1xf32>
// CHECK-LABEL: test_stateful_ops(
// CHECK-SAME: %[[VAL_0:.*]]: tensor<1xf32>
// CHECK: tosa.variable_write @var_x, %[[VAL_0]] : tensor<1xf32>
// CHECK: %[[VAL_1:.*]] = tosa.variable_read @var_x : tensor<1xf32>
// CHECK: return %[[VAL_1]] : tensor<1xf32>
module attributes {tf_saved_model.semantics, tfl.description = "Test.", tfl.schema_version = 3 : i32} {
func.func @test_stateful_ops(%arg0: tensor<1xf32> {tf_saved_model.index_path = ["placeholder_0"]})
-> (tensor<1xf32> {tf_saved_model.index_path = ["output_0"]})
attributes {tf_saved_model.exported_names = ["serving_default"]} {
"tfl.call_once"() {session_init_function = "InitializeX"} : () -> ()
%0 = "tfl.var_handle"() {container = "", shared_name = "var_x"} : () -> tensor<!tf_type.resource>
"tfl.assign_variable"(%0, %arg0) : (tensor<!tf_type.resource>, tensor<1xf32>) -> ()
%1 = "tfl.read_variable"(%0) : (tensor<!tf_type.resource>) -> tensor<1xf32>
return %1 : tensor<1xf32>
}
// initialize variable var_x to 7.0
func.func private @InitializeX() {
%0 = "tfl.var_handle"() {container = "", shared_name = "var_x"} : () -> tensor<!tf_type.resource>
%1 = "tfl.pseudo_const"() {value = dense<7.000000e+00> : tensor<1xf32>} : () -> tensor<1xf32>
"tfl.assign_variable"(%0, %1) : (tensor<!tf_type.resource>, tensor<1xf32>) -> ()
return
}
}
// -----
// CHECK-LABEL: tosa.variable @Variable = dense<42> : tensor<2x3xi8>
// CHECK-LABEL: readAssignQuant
// CHECK-SAME: %[[VAL_0:.*]]: tensor<2x3x!quant.uniform<i8:f32, 1.000000e-01:2>>
// CHECK: %[[VAL_1:.*]] = "tosa.const"() <{values = dense<49> : tensor<1xi8>}> : () -> tensor<1xi8>
// CHECK: %[[VAL_2:.*]] = "tosa.const"() <{values = dense<0> : tensor<1xi32>}> : () -> tensor<1xi32>
// CHECK: %[[VAL_3:.*]] = "tosa.const"() <{values = dense<2> : tensor<1xi8>}> : () -> tensor<1xi8>
// CHECK: %[[VAL_4:.*]] = "tosa.const"() <{values = dense<11> : tensor<1xi8>}> : () -> tensor<1xi8>
// CHECK: %[[VAL_5:.*]] = "tosa.const"() <{values = dense<1073741824> : tensor<1xi32>}> : () -> tensor<1xi32>
// CHECK: %[[VAL_6:.*]] = tosa.variable_read @Variable : tensor<2x3xi8>
// CHECK: %[[VAL_7:.*]] = builtin.unrealized_conversion_cast %[[VAL_6]] : tensor<2x3xi8> to tensor<2x3x!quant.uniform<i8:f32, 1.000000e-01:2>>
// CHECK: %[[VAL_8:.*]] = tosa.rescale %[[VAL_7]], %[[VAL_5]], %[[VAL_4]], %[[VAL_3]], %[[VAL_2]] {input_unsigned = false, output_unsigned = false, per_channel = false, rounding_mode = DOUBLE_ROUND, scale32 = true} : (tensor<2x3x!quant.uniform<i8:f32, 1.000000e-01:2>>, tensor<1xi32>, tensor<1xi8>, tensor<1xi8>, tensor<1xi32>) -> tensor<2x3xi32>
// CHECK: %[[VAL_9:.*]] = tosa.rescale %[[VAL_0]], %[[VAL_5]], %[[VAL_4]], %[[VAL_3]], %[[VAL_2]] {input_unsigned = false, output_unsigned = false, per_channel = false, rounding_mode = DOUBLE_ROUND, scale32 = true} : (tensor<2x3x!quant.uniform<i8:f32, 1.000000e-01:2>>, tensor<1xi32>, tensor<1xi8>, tensor<1xi8>, tensor<1xi32>) -> tensor<2x3xi32>
// CHECK: %[[VAL_10:.*]] = tosa.add %[[VAL_8]], %[[VAL_9]] : (tensor<2x3xi32>, tensor<2x3xi32>) -> tensor<2x3xi32>
// CHECK: %[[VAL_11:.*]] = tosa.rescale %[[VAL_10]], %[[VAL_5]], %[[VAL_1]], %[[VAL_2]], %[[VAL_3]] {input_unsigned = false, output_unsigned = false, per_channel = false, rounding_mode = DOUBLE_ROUND, scale32 = true} : (tensor<2x3xi32>, tensor<1xi32>, tensor<1xi8>, tensor<1xi32>, tensor<1xi8>) -> tensor<2x3x!quant.uniform<i8:f32, 1.000000e-01:2>>
// CHECK: %[[VAL_12:.*]] = builtin.unrealized_conversion_cast %[[VAL_11]] : tensor<2x3x!quant.uniform<i8:f32, 1.000000e-01:2>> to tensor<2x3xi8>
// CHECK: tosa.variable_write @Variable, %[[VAL_12]] : tensor<2x3xi8>
// CHECK: return %[[VAL_11]] : tensor<2x3x!quant.uniform<i8:f32, 1.000000e-01:2>>
module {
func.func @readAssignQuant(%arg0: tensor<2x3x!quant.uniform<i8:f32, 0.1:2>>) -> (tensor<2x3x!quant.uniform<i8:f32, 0.1:2>>) {
"tfl.call_once"() {session_init_function = "ReadAssignInit"} : () -> ()
%0 = "tfl.var_handle"() {container = "", shared_name = "Variable"} : () -> tensor<*x!tf_type.resource>
%1 = "tfl.read_variable"(%0) : (tensor<*x!tf_type.resource>) -> tensor<2x3x!quant.uniform<i8:f32, 0.1:2>>
%2 = tfl.add %1, %arg0 {fused_activation_function = "NONE"} : tensor<2x3x!quant.uniform<i8:f32, 0.1:2>>
"tfl.assign_variable"(%0, %2) : (tensor<*x!tf_type.resource>, tensor<2x3x!quant.uniform<i8:f32, 0.1:2>>) -> ()
return %2 : tensor<2x3x!quant.uniform<i8:f32, 0.1:2>>
}
func.func private @ReadAssignInit() {
%0 = "tfl.var_handle"() {container = "", shared_name = "Variable"} : () -> tensor<*x!tf_type.resource>
%1 = "tfl.pseudo_const"() {qtype = tensor<2x3x!quant.uniform<i8:f32, 0.1:2>>, value = dense<42> : tensor<2x3xi8>} : () -> tensor<2x3x!quant.uniform<i8:f32, 0.1:2>>
"tfl.assign_variable"(%0, %1) : (tensor<*x!tf_type.resource>, tensor<2x3x!quant.uniform<i8:f32, 0.1:2>>) -> ()
return
}
}
// -----
module {
// CHECK-LABEL: @nostate
// CHECK: %[[VAL_0:.*]]: tensor<16x16xf32>) -> tensor<16x16xf32> {
// CHECK: %[[VAL_1:.*]] = "tfl.var_handle"() <{container = "", shared_name = "Variable"}> : () -> tensor<*x!tf_type.resource>
// CHECK: %[[VAL_2:.*]] = "tfl.read_variable"(%[[VAL_1]]) : (tensor<*x!tf_type.resource>) -> tensor<16x16xf32>
// CHECK: %[[VAL_3:.*]] = tosa.add %[[VAL_2]], %[[VAL_0]] : (tensor<16x16xf32>, tensor<16x16xf32>) -> tensor<16x16xf32>
// CHECK: "tfl.assign_variable"(%[[VAL_1]], %[[VAL_3]]) : (tensor<*x!tf_type.resource>, tensor<16x16xf32>) -> ()
// CHECK: return %[[VAL_3]] : tensor<16x16xf32>
func.func @nostate(%arg0: tensor<16x16xf32>) -> (tensor<16x16xf32>) {
"tfl.call_once"() {session_init_function = "NoStateInit"} : () -> ()
%0 = "tfl.var_handle"() {container = "", shared_name = "Variable"} : () -> tensor<*x!tf_type.resource>
%1 = "tfl.read_variable"(%0) : (tensor<*x!tf_type.resource>) -> tensor<16x16xf32>
%2 = tfl.add %1, %arg0 {fused_activation_function = "NONE"} : tensor<16x16xf32>
"tfl.assign_variable"(%0, %2) : (tensor<*x!tf_type.resource>, tensor<16x16xf32>) -> ()
return %2 : tensor<16x16xf32>
}
func.func private @NoStateInit() {
return
}
}
@@ -0,0 +1,192 @@
// RUN: tf-tosa-opt --split-input-file --tfl-to-tosa-pipeline --verify-each %s | FileCheck %s
// Test tf legalization that produce TOSA ResultsBroadcastableShape operators with unequal ranks
// -----
// CHECK-LABEL: test_add
func.func @test_add(%arg0: tensor<192x192x3xf32>, %arg1: tensor<16x192x192x3xf32>) -> tensor<16x192x192x3xf32> {
// CHECK: tosa.add
%1 = tfl.add(%arg0, %arg1) {fused_activation_function = "NONE"} : (tensor<192x192x3xf32>, tensor<16x192x192x3xf32>) -> tensor<16x192x192x3xf32>
func.return %1 : tensor<16x192x192x3xf32>
}
// -----
// CHECK-LABEL: test_add_dynamic
func.func @test_add_dynamic(%arg0: tensor<?x?x?xf32>, %arg1: tensor<5xf32>) -> tensor<?x?x5xf32> {
// CHECK: tosa.add
%1 = tfl.add(%arg0, %arg1) {fused_activation_function = "NONE"} : (tensor<?x?x?xf32>, tensor<5xf32>) -> tensor<?x?x5xf32>
func.return %1 : tensor<?x?x5xf32>
}
// -----
// CHECK-LABEL: test_add_qi8
func.func @test_add_qi8(%arg0: tensor<13x21x1x!quant.uniform<i8:f32, 0.01568480022251606:-1>>, %arg1: tensor<1x13x21x3x!quant.uniform<i8:f32, 0.015686055645346642:-1>>) -> tensor<1x13x21x3x!quant.uniform<i8:f32, 0.031318482011556625:-1>> {
// CHECK: tosa.add
%0 = tfl.add(%arg0, %arg1) {fused_activation_function = "NONE"} : (tensor<13x21x1x!quant.uniform<i8:f32, 0.01568480022251606:-1>>, tensor<1x13x21x3x!quant.uniform<i8:f32, 0.015686055645346642:-1>>) -> tensor<1x13x21x3x!quant.uniform<i8:f32, 0.031318482011556625:-1>>
func.return %0 : tensor<1x13x21x3x!quant.uniform<i8:f32, 0.031318482011556625:-1>>
}
// -----
// CHECK-LABEL: test_sub
func.func @test_sub(%arg0: tensor<192x192x3xf32>, %arg1: tensor<16x192x192x3xf32>) -> tensor<16x192x192x3xf32> {
// CHECK: tosa.sub
%1 = tfl.sub(%arg0, %arg1) {fused_activation_function = "NONE"} : (tensor<192x192x3xf32>, tensor<16x192x192x3xf32>) -> tensor<16x192x192x3xf32>
func.return %1 : tensor<16x192x192x3xf32>
}
// -----
// CHECK-LABEL: test_sub_qi8
func.func @test_sub_qi8(%arg0: tensor<13x21x1x!quant.uniform<i8:f32, 0.01568480022251606:-1>>, %arg1: tensor<1x13x21x3x!quant.uniform<i8:f32, 0.015686055645346642:-1>>) -> tensor<1x13x21x3x!quant.uniform<i8:f32, 0.031318482011556625:-1>> {
// CHECK: tosa.sub
%0 = tfl.sub(%arg0, %arg1) {fused_activation_function = "NONE"} : (tensor<13x21x1x!quant.uniform<i8:f32, 0.01568480022251606:-1>>, tensor<1x13x21x3x!quant.uniform<i8:f32, 0.015686055645346642:-1>>) -> tensor<1x13x21x3x!quant.uniform<i8:f32, 0.031318482011556625:-1>>
func.return %0 : tensor<1x13x21x3x!quant.uniform<i8:f32, 0.031318482011556625:-1>>
}
// -----
// CHECK-LABEL: test_equal
// CHECK: tosa.equal
func.func @test_equal(%arg0: tensor<13x21x3xf32>, %arg1: tensor<1x13x1x3xf32>) -> tensor<1x13x21x3xi1> {
%2 = "tfl.equal"(%arg0, %arg1) : (tensor<13x21x3xf32>, tensor<1x13x1x3xf32>) -> tensor<1x13x21x3xi1>
func.return %2 : tensor<1x13x21x3xi1>
}
// -----
// CHECK-LABEL: test_not_equal
// CHECK: tosa.equal
// CHECK: tosa.logical_not
func.func @test_not_equal(%arg0: tensor<13x21x3xf32>, %arg1: tensor<1x13x1x3xf32>) -> tensor<1x13x21x3xi1> {
%2 = "tfl.not_equal"(%arg0, %arg1) : (tensor<13x21x3xf32>, tensor<1x13x1x3xf32>) -> tensor<1x13x21x3xi1>
func.return %2 : tensor<1x13x21x3xi1>
}
// -----
// CHECK-LABEL: test_greater_equal
// CHECK: tosa.greater_equal
func.func @test_greater_equal(%arg0: tensor<13x1x3xf32>, %arg1: tensor<1x13x21x3xf32>) -> tensor<1x13x21x3xi1> {
%2 = "tfl.greater_equal"(%arg0, %arg1) : (tensor<13x1x3xf32>, tensor<1x13x21x3xf32>) -> tensor<1x13x21x3xi1>
func.return %2 : tensor<1x13x21x3xi1>
}
// -----
// CHECK-LABEL: test_greater
// CHECK: tosa.greater
func.func @test_greater(%arg0: tensor<13x21x1xf32>, %arg1: tensor<1x13x21x3xf32>) -> tensor<1x13x21x3xi1> {
%2 = "tfl.greater"(%arg0, %arg1) : (tensor<13x21x1xf32>, tensor<1x13x21x3xf32>) -> tensor<1x13x21x3xi1>
func.return %2 : tensor<1x13x21x3xi1>
}
// -----
// CHECK-LABEL: test_less
// CHECK: tosa.greater
func.func @test_less(%arg0: tensor<13x21x1xf32>, %arg1: tensor<1x13x21x3xf32>) -> tensor<1x13x21x3xi1> {
%2 = "tfl.less"(%arg0, %arg1) : (tensor<13x21x1xf32>, tensor<1x13x21x3xf32>) -> tensor<1x13x21x3xi1>
func.return %2 : tensor<1x13x21x3xi1>
}
// -----
// CHECK-LABEL: test_less_equal
// CHECK: tosa.greater_equal
func.func @test_less_equal(%arg0: tensor<13x21x1xf32>, %arg1: tensor<1x13x21x3xf32>) -> tensor<1x13x21x3xi1> {
%2 = "tfl.less_equal"(%arg0, %arg1) : (tensor<13x21x1xf32>, tensor<1x13x21x3xf32>) -> tensor<1x13x21x3xi1>
func.return %2 : tensor<1x13x21x3xi1>
}
// -----
// CHECK-LABEL: test_select
// CHECK: tosa.select
func.func @test_select(%arg0: tensor<13x21x3xf32>, %arg1: tensor<1x13x21x3xf32>, %arg2: tensor<1xi1>) -> tensor<1x13x21x3xf32> {
%2 = "tfl.select_v2"(%arg2, %arg0, %arg1) : (tensor<1xi1>, tensor<13x21x3xf32>, tensor<1x13x21x3xf32>) -> tensor<1x13x21x3xf32>
func.return %2 : tensor<1x13x21x3xf32>
}
// -----
// CHECK-LABEL: test_mul_qi8
// CHECK: tosa.mul
func.func @test_mul_qi8(%arg0: tensor<13x21x3x!quant.uniform<i8:f32, 0.015681236982345581>>, %arg1: tensor<1x13x21x3x!quant.uniform<i8:f32, 0.015647144988179207:-1>>) -> tensor<*x!quant.uniform<i8:f32, 0.0078376950696110725>> {
%0 = "tfl.mul"(%arg0, %arg1) {fused_activation_function = "NONE"} : (tensor<13x21x3x!quant.uniform<i8:f32, 0.015681236982345581>>, tensor<1x13x21x3x!quant.uniform<i8:f32, 0.015647144988179207:-1>>) -> tensor<*x!quant.uniform<i8:f32, 0.0078376950696110725>>
func.return %0 : tensor<*x!quant.uniform<i8:f32, 0.0078376950696110725>>
}
// -----
// CHECK-LABEL: test_floor_div
// CHECK: tosa.intdiv
// CHECK: tosa.select
func.func @test_floor_div(%arg0: tensor<13x21x3xi32>, %arg1: tensor<1x13x1x3xi32>) -> tensor<1x13x21x3xi32> {
%0 = "tfl.floor_div"(%arg0, %arg1) {fused_activation_function = "NONE"} : (tensor<13x21x3xi32>, tensor<1x13x1x3xi32>) -> tensor<1x13x21x3xi32>
func.return %0 : tensor<1x13x21x3xi32>
}
// -----
// CHECK-LABEL: test_div
// CHECK: tosa.intdiv
func.func @test_div(%arg0: tensor<13x21x3xi32>, %arg1: tensor<i32>) -> tensor<*xi32> {
%0 = "tfl.div"(%arg0, %arg1) {fused_activation_function = "NONE"} : (tensor<13x21x3xi32>, tensor<i32>) -> tensor<*xi32>
func.return %0 : tensor<*xi32>
}
// -----
// CHECK-LABEL: test_max
// CHECK: tosa.maximum
func.func @test_max(%arg0: tensor<13x21x3xf32>, %arg1: tensor<1x13x21x1xf32>) -> tensor<*xf32> {
%0 = "tfl.maximum"(%arg0, %arg1) : (tensor<13x21x3xf32>, tensor<1x13x21x1xf32>) -> tensor<*xf32>
func.return %0 : tensor<*xf32>
}
// -----
// CHECK-LABEL: test_min
// CHECK: tosa.minimum
func.func @test_min(%arg0: tensor<13x21x3xf32>, %arg1: tensor<1x13x21x1xf32>) -> tensor<*xf32> {
%0 = "tfl.minimum"(%arg0, %arg1) : (tensor<13x21x3xf32>, tensor<1x13x21x1xf32>) -> tensor<*xf32>
func.return %0 : tensor<*xf32>
}
// -----
// CHECK-LABEL: test_add
func.func @test_addn(%arg0: tensor<13x21x1xf32>, %arg1: tensor<1x13x21x3xf32>, %arg2: tensor<21x3xf32>, %arg3: tensor<3xf32>) -> tensor<*xf32> {
// CHECK: tosa.add
// CHECK: tosa.add
// CHECK: tosa.add
%2 = "tfl.add_n"(%arg0, %arg1, %arg2, %arg3) : (tensor<13x21x1xf32>, tensor<1x13x21x3xf32>, tensor<21x3xf32>, tensor<3xf32>) -> tensor<*xf32>
func.return %2 : tensor<*xf32>
}
// -----
// CHECK-LABEL: test_logical_and
func.func @test_logical_and(%arg0: tensor<8x13x21x3xi1>, %arg1: tensor<13x21x1xi1>) -> tensor<8x13x21x3xi1> {
// CHECK: tosa.logical_and
%2 = "tfl.logical_and"(%arg0, %arg1) : (tensor<8x13x21x3xi1>, tensor<13x21x1xi1>) -> tensor<8x13x21x3xi1>
func.return %2 : tensor<8x13x21x3xi1>
}
// -----
// CHECK-LABEL: test_logical_or
func.func @test_logical_or(%arg0: tensor<8x13x21x3xi1>, %arg1: tensor<13x21x1xi1>) -> tensor<8x13x21x3xi1> {
// CHECK: tosa.logical_or
%2 = "tfl.logical_or"(%arg0, %arg1) : (tensor<8x13x21x3xi1>, tensor<13x21x1xi1>) -> tensor<8x13x21x3xi1>
func.return %2 : tensor<8x13x21x3xi1>
}
// -----
// CHECK-LABEL: test_power
func.func @test_power(%arg0: tensor<8x13x21x3xi32>, %arg1: tensor<13x21x1xi32>) -> tensor<8x13x21x3xi32> {
// CHECK: tosa.pow
%2 = "tfl.pow"(%arg0, %arg1) : (tensor<8x13x21x3xi32>, tensor<13x21x1xi32>) -> tensor<8x13x21x3xi32>
func.return %2 : tensor<8x13x21x3xi32>
}
@@ -0,0 +1,42 @@
// RUN: tf-tosa-opt --split-input-file --tosa-legalize-tfl --verify-diagnostics %s | FileCheck %s
// -----
// CHECK-LABEL: max_pool_same_padding_dyn
// CHECK: tfl.max_pool_2d
func.func @max_pool_same_padding_dyn(%arg0: tensor<?x1x?x23xf32>) -> (tensor<?x1x?x23xf32>) {
%0 = "tfl.max_pool_2d"(%arg0) <{filter_height = 1 : i32, filter_width = 4 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 1 : i32, stride_w = 4 : i32}> : (tensor<?x1x?x23xf32>) -> tensor<?x1x?x23xf32>
return %0 : tensor<?x1x?x23xf32>
}
// -----
// CHECK-LABEL: avg_pool_same_padding_dyn
// CHECK: tfl.average_pool_2d
func.func @avg_pool_same_padding_dyn(%arg0: tensor<?x1x?x23xf32>) -> (tensor<?x1x?x23xf32>) {
%0 = "tfl.average_pool_2d"(%arg0) <{filter_height = 1 : i32, filter_width = 4 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 1 : i32, stride_w = 4 : i32}> : (tensor<?x1x?x23xf32>) -> tensor<?x1x?x23xf32>
return %0 : tensor<?x1x?x23xf32>
}
// -----
// CHECK-LABEL: conv2d_same_padding_dyn
// CHECK: tfl.conv_2d
func.func @conv2d_same_padding_dyn(%input: tensor<1x?x32x8xf32>, %filter: tensor<5x3x3x8xf32>, %bias: tensor<5xf32>) -> tensor<1x32x32x5xf32> {
%0 = "tfl.conv_2d"(%input, %filter, %bias) {dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 4 : i32, stride_w = 1 : i32} : (tensor<1x?x32x8xf32>, tensor<5x3x3x8xf32>, tensor<5xf32>) -> tensor<1x32x32x5xf32>
return %0 : tensor<1x32x32x5xf32>
}
// -----
// CHECK-LABEL: conv3d_same_padding_dyn
// CHECK: tfl.conv_3d
func.func @conv3d_same_padding_dyn(%arg0: tensor<2x2x7x?x2xf32>, %arg1: tensor<2x3x3x2x4xf32>) -> tensor<2x2x7x7x4xf32> {
%cst = "tfl.no_value"() {value} : () -> none
%0 = "tfl.conv_3d"(%arg0, %arg1, %cst) {dilation_d_factor = 1 : i32, dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_d = 1 : i32, stride_h = 1 : i32, stride_w = 4 : i32} : (tensor<2x2x7x?x2xf32>, tensor<2x3x3x2x4xf32>, none) -> tensor<2x2x7x7x4xf32>
func.return %0 : tensor<2x2x7x7x4xf32>
}
// -----
// CHECK-LABEL: depthwise_conv2d_same_padding_dyn
// CHECK: tfl.depthwise_conv_2d
func.func @depthwise_conv2d_same_padding_dyn(%arg0: tensor<?x32x?x8xf32>, %arg1 : tensor<1x1x1x16xf32>, %arg2 : tensor<16xf32>) -> tensor<?x?x?x?xf32> {
%2 = "tfl.depthwise_conv_2d"(%arg0, %arg1, %arg2) {depth_multiplier = 2 : i32, dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 1 : i32, stride_w = 3 : i32} : (tensor<?x32x?x8xf32>, tensor<1x1x1x16xf32>, tensor<16xf32>) -> tensor<?x?x?x?xf32>
func.return %2 : tensor<?x?x?x?xf32>
}
@@ -0,0 +1,20 @@
// RUN: tf-tosa-opt %s --tosa-tflite-verify-fully-converted --split-input-file -verify-diagnostics
// CHECK-LABEL: func.func @main
func.func @main(%arg0: tensor<2xf32>) -> (tensor<2xf32>) {
// CHECK: "tosa.add"
%0 = "tosa.add"(%arg0, %arg0) : (tensor<2xf32>, tensor<2xf32>) -> tensor<2xf32>
return %0 : tensor<2xf32>
}
// -----
// expected-error@below {{The following illegal operations still remain}}
func.func @main(%arg0: tensor<1x8x8x3xf32>) -> tensor<1x8x8x3xf32> attributes {tf.entry_function = {inputs = "input", outputs = "output"}} {
// expected-error@+1 {{'tfl.add' op : illegal op still exists}}
%0 = tfl.add %arg0, %arg0 {fused_activation_function = "NONE"} : tensor<1x8x8x3xf32>
// expected-error@+1 {{'tfl.sub' op : illegal op still exists}}
%1 = tfl.sub %0, %arg0 {fused_activation_function = "NONE"} : tensor<1x8x8x3xf32>
return %1 : tensor<1x8x8x3xf32>
}