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
+46
View File
@@ -0,0 +1,46 @@
load("//tensorflow:tensorflow.default.bzl", "filegroup")
load("//tensorflow/compiler/mlir: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"],
driver = "@llvm-project//mlir:run_lit.sh",
exclude = [
"load-quantization-recipe.mlir",
# TODO(b/493282789): Enable DenseResourceElementsAttr constant folding with
# more peformant folder implementations.
"const-fold-unary-resource.mlir",
],
size_override = {
"gpu_compatibility.mlir": "small",
"optimize.mlir": "large",
"prepare-tf.mlir": "medium",
"prepare-tf-fake-quant.mlir": "medium",
"prepare-tf-fake-quant-4bit.mlir": "medium",
"raise-custom-ops.mlir": "medium",
"rank_reduction.mlir": "small",
},
tags_override = {
"legalize-tf.mlir": ["no_rocm"],
"optimize.mlir": ["no_rocm"],
"prepare-tf.mlir": ["no_rocm"],
"const-fold.mlir": ["no_mac_arm64"],
},
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/lite:litert-opt",
"@llvm-project//llvm:FileCheck",
"@llvm-project//llvm:not",
],
)
@@ -0,0 +1,142 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: litert-opt %s -split-input-file -tfl-analyze-variables-pass --cse | FileCheck %s
// CHECK: module attributes {tfl._legalize_tfl_variables = true}
module {
func.func @f() -> tensor<*xi32> {
%0 = "tf.VarHandleOp"() {container = "c", shared_name = "v"} : () -> tensor<*x!tf_type.resource<tensor<*xi32>>>
%2 = "tf.ReadVariableOp"(%0) {dtype = i32} : (tensor<*x!tf_type.resource<tensor<*xi32>>>) -> tensor<*xi32>
func.return %2 : tensor<*xi32>
}
}
// -----
// CHECK: module attributes {tfl._legalize_tfl_variables = true}
module {
func.func @main() -> tensor<*xi32> {
%0 = "tf.PartitionedCall"() {f = @f, config = "", config_proto = "", executor_type = ""}
: () -> tensor<*xi32>
func.return %0 : tensor<*xi32>
}
func.func @f() -> tensor<*xi32> {
%0 = "tf.VarHandleOp"() {container = "c", shared_name = "v"} : () -> tensor<*x!tf_type.resource<tensor<*xi32>>>
%1 = "tf.ReadVariableOp"(%0) {dtype = i32} : (tensor<*x!tf_type.resource<tensor<*xi32>>>) -> tensor<*xi32>
func.return %1 : tensor<*xi32>
}
}
// -----
// CHECK: module attributes {tfl._legalize_tfl_variables = false}
module {
func.func @main() -> tensor<*xi32> {
%0 = "tf.VarHandleOp"() {container = "c", shared_name = "v"} : () -> tensor<*x!tf_type.resource<tensor<*xi32>>>
%1 = "tf.PartitionedCall"(%0) {f = @f, config = "", config_proto = "", executor_type = ""}
: (tensor<*x!tf_type.resource<tensor<*xi32>>>) -> tensor<*xi32>
func.return %1 : tensor<*xi32>
}
func.func @f(%arg0 : tensor<*x!tf_type.resource<tensor<*xi32>>>) -> tensor<*xi32> {
%0 = "tf.ReadVariableOp"(%arg0) {dtype = i32} : (tensor<*x!tf_type.resource<tensor<*xi32>>>) -> tensor<*xi32>
func.return %0 : tensor<*xi32>
}
}
// -----
// CHECK: module attributes {tfl._legalize_tfl_variables = false}
module {
func.func @main() -> tensor<*xi32> {
%0 = "tf.VarHandleOp"() {container = "c", shared_name = "v"} : () -> tensor<*x!tf_type.resource<tensor<*xi32>>>
%cst = arith.constant dense<2> : tensor<4xi32>
"tf.AssignAddVariableOp"(%0, %cst) {} : (tensor<*x!tf_type.resource<tensor<*xi32>>>, tensor<4xi32>) -> ()
%1 = "tf.ReadVariableOp"(%0) {dtype = i32} : (tensor<*x!tf_type.resource<tensor<*xi32>>>) -> tensor<*xi32>
func.return %1 : tensor<*xi32>
}
}
// -----
// CHECK: module attributes {tfl._legalize_tfl_variables = true}
module {
func.func @main() -> tensor<i32> {
%0 = "tf.VarHandleOp"() {container = "c", shared_name = "v"} : () -> tensor<*x!tf_type.resource<tensor<*xi32>>>
%cst = arith.constant dense<1> : tensor<i32>
%1:2 = "tfl.while"(%cst, %0) ({
^bb0(%arg1: tensor<*xi32>, %arg2: tensor<*x!tf_type.resource<tensor<*xi32>>>):
%2 = "tf.ReadVariableOp"(%arg2) {dtype = i32} : (tensor<*x!tf_type.resource<tensor<*xi32>>>) -> tensor<*xi32>
%3 = "tfl.greater"(%arg1, %2) : (tensor<*xi32>, tensor<*xi32>) -> tensor<i1>
"tfl.yield"(%3) : (tensor<i1>) -> ()
}, {
^bb0(%arg3: tensor<*xi32>, %arg4: tensor<i32>):
%4 = "tfl.sub"(%arg3, %arg4) {fused_activation_function = "NONE"} :
(tensor<*xi32>, tensor<i32>) -> tensor<*xi32>
"tfl.yield"(%4) : (tensor<*xi32>) -> ()
}) : (tensor<i32>, tensor<*x!tf_type.resource<tensor<*xi32>>>) -> (tensor<i32>, tensor<*x!tf_type.resource<tensor<*xi32>>>)
func.return %1#0 : tensor<i32>
}
}
// -----
// CHECK: module attributes {tfl._legalize_tfl_variables = false}
module {
func.func @main() -> tensor<i32> {
%0 = "tf.VarHandleOp"() {container = "c", shared_name = "v"} : () -> tensor<*x!tf_type.resource<tensor<*xi32>>>
%cst = arith.constant dense<1> : tensor<i32>
%1:2 = "tfl.while"(%cst, %0) ({
^bb0(%arg1: tensor<*xi32>, %arg2: tensor<*x!tf_type.resource<tensor<*xi32>>>):
%2 = "tf.ReadVariableOp"(%arg2) {dtype = i32} : (tensor<*x!tf_type.resource<tensor<*xi32>>>) -> tensor<*xi32>
%3 = "tfl.greater"(%arg1, %2) : (tensor<*xi32>, tensor<*xi32>) -> tensor<i1>
"tfl.yield"(%3) : (tensor<i1>) -> ()
}, {
^bb0(%arg3: tensor<*xi32>, %arg4: tensor<*x!tf_type.resource<tensor<*xi32>>>):
%cst1 = arith.constant dense<2> : tensor<4xi32>
"tf.AssignAddVariableOp"(%arg4, %cst1) {} : (tensor<*x!tf_type.resource<tensor<*xi32>>>, tensor<4xi32>) -> ()
%4 = "tf.ReadVariableOp"(%arg4) {dtype = i32} : (tensor<*x!tf_type.resource<tensor<*xi32>>>) -> tensor<*xi32>
"tfl.yield"(%4) : (tensor<*xi32>) -> ()
}) : (tensor<i32>, tensor<*x!tf_type.resource<tensor<*xi32>>>) -> (tensor<i32>, tensor<*x!tf_type.resource<tensor<*xi32>>>)
func.return %1#0 : tensor<i32>
}
}
// -----
// CHECK: module attributes {tfl._legalize_tfl_variables = true}
module {
func.func @main(%arg0 : tensor<!tf_type.resource<tensor<4096xf32>>>,
%arg1 : tensor<*x!tf_type.variant>) {
%cst_0 = arith.constant dense<2> : tensor<i64>
%cst_1 = arith.constant dense<0> : tensor<i32>
%0 = "tf.RepeatDataset"(%arg1, %cst_0) {device = "",
output_shapes = [#tf_type.shape<?>],
output_types = [!tf_type.string]} : (tensor<*x!tf_type.variant>, tensor<i64>) -> tensor<!tf_type.variant>
%1 = "tf.ReduceDataset"(%0, %cst_1, %arg0) {
Targuments = [!tf_type.resource],
Tstate = [i32], device = "",
f = @__reduce_func, f._tf_data_function = true,
output_shapes = [#tf_type.shape<>],
output_types = [i32], use_inter_op_parallelism = true} : (tensor<!tf_type.variant>, tensor<i32>, tensor<!tf_type.resource<tensor<4096xf32>>>) -> (tensor<*xi32>)
func.return
}
func.func private @__reduce_func(%arg0: tensor<i32> {tf._user_specified_name = "args_0"}) -> (tensor<i32>) attributes {tf._tf_data_function = true, tf.signature.is_stateful} {
%0 = "tf.JustPretend"() : () -> (tensor<i32>)
func.return %0: tensor<i32>
}
}
@@ -0,0 +1,237 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: litert-opt %s -tfl-bias-quantizer | FileCheck %s
// CHECK-LABEL: QuantizeConv2DPerChannel
func.func @QuantizeConv2DPerChannel(%arg0: tensor<1x224x224x3x!quant.uniform<u8:f32, 1.5>>,
%arg1: tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32:3, {1.0,2.0,3.0}>>) -> tensor<1x112x112x32xf32> {
%bias = arith.constant dense<1.0> : tensor<32xf32>
%input = "tfl.dequantize"(%arg0) : (tensor<1x224x224x3x!quant.uniform<u8:f32, 1.5>>) -> tensor<1x224x224x3xf32>
%weight = "tfl.dequantize"(%arg1) : (tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32:3, {1.0,2.0,3.0}>>) -> tensor<32x3x3x3xf32>
%conv = "tfl.conv_2d"(%input, %weight, %bias) {dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32,
fused_activation_function = "NONE", padding = "SAME", stride_h = 2 : i32, stride_w = 2 : i32}
: (tensor<1x224x224x3xf32>, tensor<32x3x3x3xf32>, tensor<32xf32>) -> tensor<1x112x112x32xf32>
func.return %conv : tensor<1x112x112x32xf32>
// CHECK-NEXT: %[[cst:.*]] = arith.constant dense<1.000000e+00> : tensor<32xf32>
// CHECK-NEXT: %[[qbias:.*]] = "tfl.quantize"(%[[cst]]) <{qtype = tensor<32x!quant.uniform<i32:f32:0, {1.500000e+00,3.000000e+00,4.500000e+00}>>}> {propagated}
// CHECK-NEXT: %[[bias:.*]] = "tfl.dequantize"(%[[qbias]])
// CHECK-NEXT: %[[in:.*]] = "tfl.dequantize"(%arg0)
// CHECK-NEXT: %[[w:.*]] = "tfl.dequantize"(%arg1)
// CHECK-NEXT: %[[conv:.*]] = "tfl.conv_2d"(%[[in]], %[[w]], %[[bias]])
// CHECK-NEXT: return %[[conv]]
}
// -----
// CHECK-LABEL: QuantizeConv2DPerChannelConst
func.func @QuantizeConv2DPerChannelConst(%arg0: tensor<1x224x224x3x!quant.uniform<u8:f32, 1.5>>,
%arg1: tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32:3, {1.0,2.0,3.0}>>) -> tensor<1x112x112x32xf32> {
%bias = "tfl.pseudo_const"() {value = dense<1.000000e+00> : tensor<32xf32>} : () -> tensor<32xf32>
%input = "tfl.dequantize"(%arg0) : (tensor<1x224x224x3x!quant.uniform<u8:f32, 1.5>>) -> tensor<1x224x224x3xf32>
%weight = "tfl.dequantize"(%arg1) : (tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32:3, {1.0,2.0,3.0}>>) -> tensor<32x3x3x3xf32>
%conv = "tfl.conv_2d"(%input, %weight, %bias) {dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32,
fused_activation_function = "NONE", padding = "SAME", stride_h = 2 : i32, stride_w = 2 : i32}
: (tensor<1x224x224x3xf32>, tensor<32x3x3x3xf32>, tensor<32xf32>) -> tensor<1x112x112x32xf32>
func.return %conv : tensor<1x112x112x32xf32>
// CHECK-NEXT: %[[cst:.*]] = "tfl.pseudo_const"() <{value = dense<1.000000e+00> : tensor<32xf32>}> : () -> tensor<32xf32>
// CHECK-NEXT: %[[qbias:.*]] = "tfl.quantize"(%[[cst]]) <{qtype = tensor<32x!quant.uniform<i32:f32:0, {1.500000e+00,3.000000e+00,4.500000e+00}>>}> {propagated}
// CHECK-NEXT: %[[bias:.*]] = "tfl.dequantize"(%[[qbias]])
// CHECK-NEXT: %[[in:.*]] = "tfl.dequantize"(%arg0)
// CHECK-NEXT: %[[w:.*]] = "tfl.dequantize"(%arg1)
// CHECK-NEXT: %[[conv:.*]] = "tfl.conv_2d"(%[[in]], %[[w]], %[[bias]])
// CHECK-NEXT: return %[[conv]]
}
// -----
// CHECK-LABEL: QuantizeConv2DPerChannels
func.func @QuantizeConv2DPerChannels(%arg0: tensor<1x224x224x3x!quant.uniform<u8:f32:3, {1.0,2.0,3.0}>>,
%arg1: tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32:3, {1.0,2.0,3.0}>>) -> tensor<1x112x112x32xf32> {
%bias = arith.constant dense<1.0> : tensor<32xf32>
%input = "tfl.dequantize"(%arg0) : (tensor<1x224x224x3x!quant.uniform<u8:f32:3, {1.0,2.0,3.0}>>) -> tensor<1x224x224x3xf32>
%weight = "tfl.dequantize"(%arg1) : (tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32:3, {1.0,2.0,3.0}>>) -> tensor<32x3x3x3xf32>
%conv = "tfl.conv_2d"(%input, %weight, %bias) {dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32,
fused_activation_function = "NONE", padding = "SAME", stride_h = 2 : i32, stride_w = 2 : i32}
: (tensor<1x224x224x3xf32>, tensor<32x3x3x3xf32>, tensor<32xf32>) -> tensor<1x112x112x32xf32>
func.return %conv : tensor<1x112x112x32xf32>
// CHECK-NEXT: %[[cst:.*]] = arith.constant dense<1.000000e+00> : tensor<32xf32>
// CHECK-NEXT: %[[qbias:.*]] = "tfl.quantize"(%[[cst]]) <{qtype = tensor<32x!quant.uniform<i32:f32:0, {1.000000e+00,4.000000e+00,9.000000e+00}>>}> {propagated}
// CHECK-NEXT: %[[bias:.*]] = "tfl.dequantize"(%[[qbias]])
// CHECK-NEXT: %[[in:.*]] = "tfl.dequantize"(%arg0)
// CHECK-NEXT: %[[w:.*]] = "tfl.dequantize"(%arg1)
// CHECK-NEXT: %[[conv:.*]] = "tfl.conv_2d"(%[[in]], %[[w]], %[[bias]])
// CHECK-NEXT: return %[[conv]]
}
// -----
// CHECK-LABEL: QuantizeConv2D
func.func @QuantizeConv2D(tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>> {
^bb0(%arg0: tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>):
%cst = arith.constant dense<-1.23697901> : tensor<32xf32>
%2 = "tfl.dequantize"(%arg0) : (tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x224x224x3xf32>
%3 = "tfl.pseudo_qconst"() {qtype = tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 0.021826678373682216:151>>, value = dense<-76> : tensor<32x3x3x3xi8>} : () -> tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 0.021826678373682216:151>>
%4 = "tfl.dequantize"(%3) : (tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 0.021826678373682216:151>>) -> tensor<32x3x3x3xf32>
%5 = "tfl.conv_2d"(%2, %4, %cst) {dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 2 : i32, stride_w = 2 : i32} : (tensor<1x224x224x3xf32>, tensor<32x3x3x3xf32>, tensor<32xf32>) -> tensor<1x112x112x32xf32>
%6 = "tfl.quantize"(%5) {qtype = tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>} : (tensor<1x112x112x32xf32>) -> tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>
func.return %6 : tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>
// CHECK: %cst = arith.constant dense<-1.23697901> : tensor<32xf32>
// CHECK: %0 = "tfl.quantize"(%cst) <{qtype = tensor<32x!quant.uniform<i32:f32, 1.7052092479439231E-4>>}> {propagated}
// CHECK: %1 = "tfl.dequantize"(%0) : (tensor<32x!quant.uniform<i32:f32, 1.7052092479439231E-4>>)
// CHECK: %2 = "tfl.dequantize"(%arg0)
// CHECK: %3 = "tfl.pseudo_qconst"()
// CHECK: %4 = "tfl.dequantize"(%3)
// CHECK: %5 = "tfl.conv_2d"(%2, %4, %1)
// CHECK: %6 = "tfl.quantize"(%5)
// CHECK: return %6
}
// -----
// CHECK-LABEL: QuantizeFullyConnected
func.func @QuantizeFullyConnected(tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>> {
^bb0(%arg0: tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>):
%cst = arith.constant dense<-1.23697901> : tensor<32xf32>
%2 = "tfl.dequantize"(%arg0) : (tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x224x224x3xf32>
%3 = "tfl.pseudo_qconst"() {qtype = tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 0.021826678373682216:151>>, value = dense<-76> : tensor<32x12xi8>} : () -> tensor<32x12x!quant.uniform<u8<1:255>:f32, 0.021826678373682216:151>>
%4 = "tfl.dequantize"(%3) : (tensor<32x12x!quant.uniform<u8<1:255>:f32, 0.021826678373682216:151>>) -> tensor<32x12xf32>
%5 = "tfl.fully_connected"(%2, %4, %cst) {fused_activation_function = "NONE", keep_num_dims = false, weights_format = "DEFAULT"} : (tensor<1x224x224x3xf32>, tensor<32x12xf32>, tensor<32xf32>) -> tensor<1x112x112x32xf32>
%6 = "tfl.quantize"(%5) {qtype = tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>} : (tensor<1x112x112x32xf32>) -> tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>
func.return %6 : tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>
// CHECK: %cst = arith.constant dense<-1.23697901> : tensor<32xf32>
// CHECK: %0 = "tfl.quantize"(%cst) <{qtype = tensor<32x!quant.uniform<i32:f32, 1.7052092479439231E-4>>}> {propagated}
// CHECK: %1 = "tfl.dequantize"(%0) : (tensor<32x!quant.uniform<i32:f32, 1.7052092479439231E-4>>)
// CHECK: %2 = "tfl.dequantize"(%arg0)
// CHECK: %3 = "tfl.pseudo_qconst"()
// CHECK: %4 = "tfl.dequantize"(%3)
// CHECK: %5 = "tfl.fully_connected"(%2, %4, %1)
// CHECK: %6 = "tfl.quantize"(%5)
// CHECK: return %6
}
// -----
// CHECK-LABEL: QuantizeDepthwiseConv2D
func.func @QuantizeDepthwiseConv2D(tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>> {
^bb0(%arg0: tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>):
%cst = arith.constant dense<-1.23697901> : tensor<32xf32>
%2 = "tfl.dequantize"(%arg0) : (tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x224x224x3xf32>
%3 = "tfl.pseudo_qconst"() {qtype = tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 0.021826678373682216:151>>, value = dense<-76> : tensor<32x3x3x3xi8>} : () -> tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 0.021826678373682216:151>>
%4 = "tfl.dequantize"(%3) : (tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 0.021826678373682216:151>>) -> tensor<32x3x3x3xf32>
%5 = "tfl.depthwise_conv_2d"(%2, %4, %cst) {depth_multiplier = 4 : i32, dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "VALID", stride_h = 4 : i32, stride_w = 5 : i32} : (tensor<1x224x224x3xf32>, tensor<32x3x3x3xf32>, tensor<32xf32>) -> tensor<1x112x112x32xf32>
%6 = "tfl.quantize"(%5) {qtype = tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>} : (tensor<1x112x112x32xf32>) -> tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>
func.return %6 : tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>
// CHECK: %cst = arith.constant dense<-1.23697901> : tensor<32xf32>
// CHECK: %0 = "tfl.quantize"(%cst) <{qtype = tensor<32x!quant.uniform<i32:f32, 1.7052092479439231E-4>>}> {propagated}
// CHECK: %1 = "tfl.dequantize"(%0) : (tensor<32x!quant.uniform<i32:f32, 1.7052092479439231E-4>>)
// CHECK: %2 = "tfl.dequantize"(%arg0)
// CHECK: %3 = "tfl.pseudo_qconst"()
// CHECK: %4 = "tfl.dequantize"(%3)
// CHECK: %5 = "tfl.depthwise_conv_2d"(%2, %4, %1)
// CHECK: %6 = "tfl.quantize"(%5)
// CHECK: return %6
}
// -----
// CHECK-LABEL: QuantizeSharedBiases
func.func @QuantizeSharedBiases(
%arg0: tensor<1x224x224x3x!quant.uniform<u8:f32, 1.0>>,
%arg1: tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 1.0>>,
%arg2: tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 2.0>>) -> (tensor<1x56x56x32x!quant.uniform<u8:f32, 1.0>>) {
%cst = arith.constant dense<1.0> : tensor<32xf32>
%1 = "tfl.dequantize"(%arg0) : (tensor<1x224x224x3x!quant.uniform<u8:f32, 1.0>>) -> tensor<1x224x224x3xf32>
%2 = "tfl.dequantize"(%arg1) : (tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 1.0>>) -> tensor<32x3x3x3xf32>
%conv1 = "tfl.conv_2d"(%1, %2, %cst) {dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 2 : i32, stride_w = 2 : i32} : (tensor<1x224x224x3xf32>, tensor<32x3x3x3xf32>, tensor<32xf32>) -> tensor<1x112x112x32xf32>
%3 = "tfl.quantize"(%conv1) {qtype = tensor<1x112x112x32xf32>} : (tensor<1x112x112x32xf32>) -> tensor<1x112x112x32x!quant.uniform<u8:f32, 1.0>>
%4 = "tfl.dequantize"(%3) : (tensor<1x112x112x32x!quant.uniform<u8:f32, 1.0>>) -> tensor<1x112x112x32xf32>
%5 = "tfl.dequantize"(%arg2) : (tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 2.0>>) -> tensor<32x3x3x3xf32>
%conv2 = "tfl.conv_2d"(%4, %5, %cst) {dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 2 : i32, stride_w = 2 : i32} : (tensor<1x112x112x32xf32>, tensor<32x3x3x3xf32>, tensor<32xf32>) -> tensor<1x56x56x32xf32>
%6 = "tfl.quantize"(%conv2) {qtype = tensor<1x56x56x32x!quant.uniform<u8:f32, 1.0>>} : (tensor<1x56x56x32xf32>) -> tensor<1x56x56x32x!quant.uniform<u8:f32, 1.0>>
func.return %6 : tensor<1x56x56x32x!quant.uniform<u8:f32, 1.0>>
// CHECK: %[[CST:.*]] = arith.constant dense<1.000000e+00> : tensor<32xf32>
// CHECK-DAG: %[[Q1:.*]] = "tfl.quantize"(%[[CST]])
// CHECK-DAG: %[[DQ1:.*]] = "tfl.dequantize"(%[[Q1]]) : (tensor<32x!quant.uniform<i32:f32, 1.000000e+00>>)
// CHECK-DAG: %[[Q2:.*]] = "tfl.quantize"(%[[CST]])
// CHECK-DAG: %[[DQ2:.*]] = "tfl.dequantize"(%[[Q2]]) : (tensor<32x!quant.uniform<i32:f32, 2.000000e+00>>)
// CHECK-DAG: %{{.*}} = "tfl.conv_2d"(%{{.*}}, %{{.*}}, %[[DQ1]])
// CHECK-DAG: %{{.*}} = "tfl.conv_2d"(%{{.*}}, %{{.*}}, %[[DQ2]])
}
// -----
// CHECK-LABEL: QuantizeSharedBiases2
func.func @QuantizeSharedBiases2(
%arg0: tensor<32x!quant.uniform<u8:f32, 1.0>>,
%arg1: tensor<1x112x112x32x!quant.uniform<u8:f32, 1.0>>,
%arg2: tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 2.0>>) -> (tensor<32x!quant.uniform<u8:f32, 1.0>>, tensor<1x56x56x32x!quant.uniform<u8:f32, 1.0>>) {
%cst = arith.constant dense<1.0> : tensor<32xf32>
%1 = "tfl.dequantize"(%arg0) : (tensor<32x!quant.uniform<u8:f32, 1.0>>) -> tensor<32xf32>
%add = "tfl.add"(%1, %cst) {fused_activation_function = "NONE"} : (tensor<32xf32>, tensor<32xf32>) -> tensor<32xf32>
%3 = "tfl.quantize"(%add) {qtype = tensor<32xf32>} : (tensor<32xf32>) -> tensor<32x!quant.uniform<u8:f32, 1.0>>
%5 = "tfl.dequantize"(%arg1) : (tensor<1x112x112x32x!quant.uniform<u8:f32, 1.0>>) -> tensor<1x112x112x32xf32>
%6 = "tfl.dequantize"(%arg2) : (tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 2.0>>) -> tensor<32x3x3x3xf32>
%conv2 = "tfl.conv_2d"(%5, %6, %cst) {dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 2 : i32, stride_w = 2 : i32} : (tensor<1x112x112x32xf32>, tensor<32x3x3x3xf32>, tensor<32xf32>) -> tensor<1x56x56x32xf32>
%7 = "tfl.quantize"(%conv2) {qtype = tensor<1x56x56x32x!quant.uniform<u8:f32, 1.0>>} : (tensor<1x56x56x32xf32>) -> tensor<1x56x56x32x!quant.uniform<u8:f32, 1.0>>
func.return %3, %7 : tensor<32x!quant.uniform<u8:f32, 1.0>>, tensor<1x56x56x32x!quant.uniform<u8:f32, 1.0>>
// CHECK: %[[CST:.*]] = arith.constant dense<1.000000e+00> : tensor<32xf32>
// CHECK: %[[Q_BIAS:.*]] = "tfl.quantize"(%[[CST]]) <{qtype = tensor<32x!quant.uniform<i32:f32, 2.000000e+00>>}> {propagated} : (tensor<32xf32>) -> tensor<32x!quant.uniform<i32:f32, 2.000000e+00>>
// CHECK: %[[DQ_BIAS:.*]] = "tfl.dequantize"(%[[Q_BIAS]])
// CHECK-DAG: tfl.add {{.*}}, %[[CST]]
// CHECK-DAG: "tfl.conv_2d"({{.*}}, {{.*}}, %[[DQ_BIAS]])
}
// -----
// Make sure biases are not shared.
// CHECK-LABEL: QuantizeSharedBiases3
func.func @QuantizeSharedBiases3(
%arg0: tensor<32x!quant.uniform<u8:f32, 1.0>>,
%arg1: tensor<1x112x112x32x!quant.uniform<u8:f32, 1.0>>,
%arg2: tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 2.0>>) -> (tensor<32x!quant.uniform<u8:f32, 1.0>>, tensor<1x56x56x32x!quant.uniform<u8:f32, 1.0>>) {
%cst = arith.constant dense<1.0> : tensor<32xf32>
%5 = "tfl.dequantize"(%arg1) : (tensor<1x112x112x32x!quant.uniform<u8:f32, 1.0>>) -> tensor<1x112x112x32xf32>
%6 = "tfl.dequantize"(%arg2) : (tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 2.0>>) -> tensor<32x3x3x3xf32>
%conv2 = "tfl.conv_2d"(%5, %6, %cst) {dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 2 : i32, stride_w = 2 : i32} : (tensor<1x112x112x32xf32>, tensor<32x3x3x3xf32>, tensor<32xf32>) -> tensor<1x56x56x32xf32>
%7 = "tfl.quantize"(%conv2) {qtype = tensor<1x56x56x32x!quant.uniform<u8:f32, 1.0>>} : (tensor<1x56x56x32xf32>) -> tensor<1x56x56x32x!quant.uniform<u8:f32, 1.0>>
%1 = "tfl.dequantize"(%arg0) : (tensor<32x!quant.uniform<u8:f32, 1.0>>) -> tensor<32xf32>
%add = "tfl.add"(%1, %cst) {fused_activation_function = "NONE"} : (tensor<32xf32>, tensor<32xf32>) -> tensor<32xf32>
%3 = "tfl.quantize"(%add) {qtype = tensor<32xf32>} : (tensor<32xf32>) -> tensor<32x!quant.uniform<u8:f32, 1.0>>
func.return %3, %7 : tensor<32x!quant.uniform<u8:f32, 1.0>>, tensor<1x56x56x32x!quant.uniform<u8:f32, 1.0>>
// CHECK: %[[CST:.*]] = arith.constant dense<1.000000e+00> : tensor<32xf32>
// CHECK: %[[Q_BIAS:.*]] = "tfl.quantize"(%[[CST]]) <{qtype = tensor<32x!quant.uniform<i32:f32, 2.000000e+00>>}>
// CHECK: %[[DQ_BIAS:.*]] = "tfl.dequantize"(%[[Q_BIAS]])
// CHECK-DAG: "tfl.conv_2d"({{.*}}, {{.*}}, %[[DQ_BIAS]])
// CHECK-DAG: tfl.add {{.*}}, %[[CST]]
}
@@ -0,0 +1,406 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: litert-opt -canonicalize=test-convergence -tfl-runtime-verify -split-input-file -verify-diagnostics %s | FileCheck %s
// CHECK-LABEL: @squeeze_folder
func.func @squeeze_folder(%arg0 : tensor<?x?xf32>) -> tensor<?x?xf32> {
%0 = "tfl.squeeze"(%arg0) : (tensor<?x?xf32>) -> tensor<?x?xf32>
// CHECK: return %arg0
func.return %0 : tensor<?x?xf32>
}
// -----
// CHECK-LABEL: @squeeze_folder
func.func @squeeze_folder(%arg0 : tensor<?x?xf32>) -> tensor<*xf32> {
%0 = "tfl.squeeze"(%arg0) : (tensor<?x?xf32>) -> tensor<*xf32>
// CHECK: "tfl.squeeze"
func.return %0 : tensor<*xf32>
}
// -----
// Checks that tfl.reshape shape operand is converted to a vector if it is possible
func.func @reshape_vector_shape(tensor<4x4x4xf32>) -> tensor<16x4xf32> {
^bb0(%arg0: tensor<4x4x4xf32>) :
%shape0 = arith.constant dense<[[16, 4]]> : tensor<1x2xi32>
// expected-error @+1 {{'tfl.reshape' op requires 'shape' to be rank 1, but got 2}}
%1 = "tfl.reshape"(%arg0, %shape0) : (tensor<4x4x4xf32>, tensor<1x2xi32>) -> tensor<16x4xf32>
func.return %1 : tensor<16x4xf32>
}
// -----
// Checks that tfl.reshape should be removed if its output's only user is
// another tfl.reshape
func.func @reshape_removeAdjacent(tensor<4x4x4xf32>) -> tensor<64xf32> {
^bb0(%arg0: tensor<4x4x4xf32>) :
%shape0 = arith.constant dense<[16, 4]> : tensor<2xi32>
%shape1 = arith.constant dense<[64]> : tensor<1xi32>
%0 = "tfl.reshape"(%arg0, %shape0) : (tensor<4x4x4xf32>, tensor<2xi32>) -> tensor<16x4xf32>
%1 = "tfl.reshape"(%0, %shape1) : (tensor<16x4xf32>, tensor<1xi32>) -> tensor<64xf32>
func.return %1 : tensor<64xf32>
// CHECK-LABEL: func @reshape_removeAdjacent
// CHECK: %[[CST:.*]] = arith.constant dense<64> : tensor<1xi32>
// CHECK: %[[RESHAPE:.*]] = "tfl.reshape"(%arg0, %[[CST]]) : (tensor<4x4x4xf32>, tensor<1xi32>) -> tensor<64xf32>
// CHECK: return %[[RESHAPE]]
}
// Checks that tfl.reshape should be removed if its output has more than one
// user but all users are tfl.reshape
func.func @reshape_removeAdjacentWithMultipleUse(tensor<4x4x4xf32>) -> tensor<64xf32> {
^bb0(%arg0: tensor<4x4x4xf32>) :
%shape0 = arith.constant dense<[16, 4]> : tensor<2xi32>
%shape1 = arith.constant dense<[64]> : tensor<1xi32>
%0 = "tfl.reshape"(%arg0, %shape0) : (tensor<4x4x4xf32>, tensor<2xi32>) -> tensor<16x4xf32>
%1 = "tfl.reshape"(%0, %shape1) : (tensor<16x4xf32>, tensor<1xi32>) -> tensor<64xf32>
%2 = "tfl.reshape"(%0, %shape1) : (tensor<16x4xf32>, tensor<1xi32>) -> tensor<64xf32>
%3 = arith.addf %1, %2 : tensor<64xf32>
func.return %3 : tensor<64xf32>
// CHECK-LABEL: func @reshape_removeAdjacentWithMultipleUse
// CHECK: %[[CST:.*]] = arith.constant dense<64> : tensor<1xi32>
// CHECK: %[[RESHAPE_1:.*]] = "tfl.reshape"(%arg0, %[[CST]]) : (tensor<4x4x4xf32>, tensor<1xi32>) -> tensor<64xf32>
// CHECK: %[[RESHAPE_2:.*]] = "tfl.reshape"(%arg0, %[[CST]]) : (tensor<4x4x4xf32>, tensor<1xi32>) -> tensor<64xf32>
// CHECK: %[[RESULT:.*]] = arith.addf %[[RESHAPE_1]], %[[RESHAPE_2]]
// CHECK: return %[[RESULT]]
}
// Checks that tfl.reshape should be kept if its output has more than one
// user and not all users are tfl.reshape
func.func @reshape_keepAdjacentWithMultipleUse(tensor<4x4x4xf32>) -> (tensor<16x4xf32>, tensor<64xf32>) {
^bb0(%arg0: tensor<4x4x4xf32>) :
%shape0 = arith.constant dense<[16, 4]> : tensor<2xi32>
%shape1 = arith.constant dense<[64]> : tensor<1xi32>
%0 = "tfl.reshape"(%arg0, %shape0) : (tensor<4x4x4xf32>, tensor<2xi32>) -> tensor<16x4xf32>
%1 = "tfl.reshape"(%0, %shape1) : (tensor<16x4xf32>, tensor<1xi32>) -> tensor<64xf32>
func.return %0, %1 : tensor<16x4xf32>, tensor<64xf32>
// CHECK-LABEL: func @reshape_keepAdjacentWithMultipleUse
// CHECK-DAG: %[[CST:.*]] = arith.constant dense<[16, 4]> : tensor<2xi32>
// CHECK-DAG: %[[CST_0:.*]] = arith.constant dense<64> : tensor<1xi32>
// CHECK: %[[RESHAPE_1:.*]] = "tfl.reshape"(%arg0, %[[CST]]) : (tensor<4x4x4xf32>, tensor<2xi32>) -> tensor<16x4xf32>
// CHECK: %[[RESHAPE_2:.*]] = "tfl.reshape"(%arg0, %[[CST_0]]) : (tensor<4x4x4xf32>, tensor<1xi32>) -> tensor<64xf32>
// CHECK: return %[[RESHAPE_1]], %[[RESHAPE_2]]
}
// Checks that tfl.reshape should be removed if its output type is the same
// as its input type and both are static.
func.func @reshape_removeIdentity(tensor<4x4x4xf32>) -> tensor<4x4x4xf32> {
^bb0(%arg0: tensor<4x4x4xf32>) :
%cst = arith.constant dense<[4, 4, 4]> : tensor<3xi32>
%0 = "tfl.reshape"(%arg0, %cst) : (tensor<4x4x4xf32>, tensor<3xi32>) -> tensor<4x4x4xf32>
func.return %0 : tensor<4x4x4xf32>
// CHECK-LABEL: func @reshape_removeIdentity
// CHECK: return %arg0 : tensor<4x4x4xf32>
}
// Checks that tfl.reshape shouldn't be removed if either output type or input
// type are dynamic.
func.func @reshape_not_removeIdentity(%arg0: tensor<?xf32>, %arg1: tensor<3xi32>) -> tensor<?x?x?xf32> {
%0 = "tfl.reshape"(%arg0, %arg1) : (tensor<?xf32>, tensor<3xi32>) -> tensor<?x?x?xf32>
func.return %0 : tensor<?x?x?xf32>
// CHECK-LABEL: func @reshape_not_removeIdentity
// CHECK-NEXT: "tfl.reshape"
}
// -----
// CHECK-LABEL: @RemoveRedundantUnpackPack
func.func @RemoveRedundantUnpackPack(%arg0: tensor<2x5xf32>) -> tensor<2x5xf32> {
%0:2 = "tfl.unpack"(%arg0) {axis = 0 : i32, num = 2 : i32} : (tensor<2x5xf32>) -> (tensor<5xf32>, tensor<5xf32>)
%1 = "tfl.pack"(%0#0, %0#1) {axis = 0 : i32, values_count = 2 : i32} : (tensor<5xf32>, tensor<5xf32>) -> (tensor<2x5xf32>)
func.return %1: tensor<2x5xf32>
// CHECK-NOT: pack
// CHECK: return %arg0 : tensor<2x5xf32>
}
// -----
// CHECK-LABEL: @RemoveRedundantPack
func.func @RemoveRedundantPack(%arg0: tensor<2x5xf32>) -> (tensor<2x5xf32>, tensor<5xf32>) {
%0:2 = "tfl.unpack"(%arg0) {axis = 0 : i32, num = 2 : i32} : (tensor<2x5xf32>) -> (tensor<5xf32>, tensor<5xf32>)
%1 = "tfl.pack"(%0#0, %0#1) {axis = 0 : i32, values_count = 2 : i32} : (tensor<5xf32>, tensor<5xf32>) -> (tensor<2x5xf32>)
func.return %1, %0#0: tensor<2x5xf32>, tensor<5xf32>
// CHECK: %[[UNPACK:.*]]:2 = "tfl.unpack"
// CHECK-NOT: pack
// CHECK: return %arg0, %[[UNPACK]]#0 : tensor<2x5xf32>, tensor<5xf32>
}
// -----
// CHECK-LABEL: @ReplacePackWithReshape
func.func @ReplacePackWithReshape(%arg0: tensor<5xf32>) -> tensor<1x5xf32> {
%1 = "tfl.pack"(%arg0) {axis = 0 : i32, values_count = 1 : i32} : (tensor<5xf32>) -> (tensor<1x5xf32>)
// CHECK: reshape
// CHECK-NOT: pack
func.return %1: tensor<1x5xf32>
}
// -----
func.func @Int64SliceBeginSize(%arg0: tensor<4x128x32xf32>) -> tensor<1x128x32xf32> {
%0 = "tfl.pseudo_const"() {value = dense<0> : tensor<3xi64>} : () -> tensor<3xi64>
%1 = "tfl.pseudo_const"() {value = dense<[1, 128, 32]> : tensor<3xi64>} : () -> tensor<3xi64>
%2 = "tfl.slice"(%arg0, %0, %1) : (tensor<4x128x32xf32>, tensor<3xi64>, tensor<3xi64>) -> tensor<1x128x32xf32>
func.return %2 : tensor<1x128x32xf32>
// CHECK-DAG: [[VAL_1:%.*]] = arith.constant dense<0> : tensor<3xi32>
// CHECK-DAG: [[VAL_2:%.*]] = arith.constant dense<[1, 128, 32]> : tensor<3xi32>
// CHECK: [[VAL_3:%.*]] = "tfl.slice"(%arg0, [[VAL_1]], [[VAL_2]]) : (tensor<4x128x32xf32>, tensor<3xi32>, tensor<3xi32>) -> tensor<1x128x32xf32>
}
// -----
// CHECK-LABEL: @WhileCanonicalizeBug
// Make sure that second output of the tf.while is not incorrectly inferred as
// pass through just because the corresponding input is not used in either
// condition or body. The tensor<f32> result of the loop can be either %arg1
// (if the body never executes, or 22.0 if the body executes at least once).
func.func @WhileCanonicalizeBug(%arg0: tensor<i32>, %arg1: tensor<f32>) -> tensor<f32> {
%0:2 = "tfl.while"(%arg0, %arg1) ({
^bb0(%arg2: tensor<i32>, %arg3: tensor<f32>):
%limit = arith.constant dense<100> : tensor<i32>
%test = "tfl.less"(%arg0, %limit) : (tensor<i32>, tensor<i32>) -> tensor<i1>
"tfl.yield"(%test) : (tensor<i1>) -> ()
}, {
^bb0(%arg2: tensor<i32>, %arg3: tensor<f32>):
%cst = arith.constant dense<22.0> : tensor<f32>
%stride = arith.constant dense<1> : tensor<i32>
%inc = tfl.add %arg2, %stride {fused_activation_function = "NONE"} : tensor<i32>
"tfl.yield"(%inc, %cst) : (tensor<i32>, tensor<f32>) -> ()
}) : (tensor<i32>, tensor<f32>) -> (tensor<i32>, tensor<f32>)
// CHECK: return %0#1 : tensor<f32>
func.return %0#1 : tensor<f32>
}
// -----
// Test case to test bug due to checking
// `while_op.getResult(arg_index).use_empty()` instead of
// `while_op.getResult(while_index).use_empty()` in the tfl.while
// canonicalization.
// arg0 is a pass through. After first iteration, arg_index = 0
// and while_index = 1. Make arg1 use empty in block and condition, but not in
// result. Canonicalize will think it can remove both slot#0 and slot#1 and do
// so without replacing all operands, and in assert builds it will fail an
// assert failure ( op->use_empty() && "expected 'op' to have no uses")
// CHECK-LABEL: WhileCanonicalizeBug1
func.func @WhileCanonicalizeBug1(%arg0: tensor<f32>, %arg1: tensor<f32>) -> tensor<f32> {
%0:2 = "tfl.while"(%arg0, %arg1) ({
^bb0(%carg0: tensor<f32>, %carg1: tensor<f32>):
%limit = arith.constant dense<100> : tensor<i32>
%test = "tfl.less"(%limit, %limit) : (tensor<i32>, tensor<i32>) -> tensor<i1>
"tfl.yield"(%test) : (tensor<i1>) -> ()
}, {
^bb0(%barg0: tensor<f32>, %barg1: tensor<f32>):
%cst = arith.constant dense<22.0> : tensor<f32>
"tfl.yield"(%barg0, %cst) : (tensor<f32>, tensor<f32>) -> ()
}) : (tensor<f32>, tensor<f32>) -> (tensor<f32>, tensor<f32>)
func.return %0#1 : tensor<f32>
}
// -----
// Test case to test While op with resources that are not read-only variables.
// Do not remove resource arugments if they are not read-only variables to keep
// the graph's control dependency.
// CHECK-LABEL: WhileWithNonReadOnlyVariableResources
func.func @WhileWithNonReadOnlyVariableResources(%arg0: tensor<i32>) -> tensor<!tf_type.resource> {
%0 = "tf.Const"() {value = dense<0.0> : tensor<f32>} : () -> tensor<f32>
%1 = "tf.Const"() {value = dense<1.0> : tensor<f32>} : () -> tensor<f32>
%2 = "tf.Const"() {value = dense<1> : tensor<i32>} : () -> tensor<i32>
%3 = "tf.Const"() {value = dense<2> : tensor<i32>} : () -> tensor<i32>
%4 = "tf.StackV2"(%3) {elem_type = f32, stack_name = "s"} : (tensor<i32>) -> tensor<!tf_type.resource>
%5:5 = "tfl.while"(%2, %3, %2, %4, %0) ({
^bb0(%arg1: tensor<i32>, %arg2: tensor<i32>, %arg3: tensor<i32>, %arg4: tensor<!tf_type.resource>, %arg5: tensor<f32>):
%9 = "tf.Const"() {value = dense<10> : tensor<i32>} : () -> tensor<i32>
%10 = "tf.Less"(%arg3, %9) {device = ""} : (tensor<i32>, tensor<i32>) -> tensor<i1>
"tfl.yield"(%10) : (tensor<i1>) -> ()
}, {
^bb0(%arg1: tensor<i32>, %arg2: tensor<i32>, %arg3: tensor<i32>, %arg4: tensor<!tf_type.resource>, %arg5: tensor<f32>):
%9 = "tf.Const"() {value = dense<1> : tensor<i32>} : () -> tensor<i32>
%10 = "tf.Cast"(%arg3) {Truncate = false, device = ""} : (tensor<i32>) -> tensor<f32>
%11 = "tf.AddV2"(%arg3, %9) {device = ""} : (tensor<i32>, tensor<i32>) -> tensor<i32>
%12 = "tf.StackPushV2"(%arg4, %10) {device = "", swap_memory = false} : (tensor<!tf_type.resource>, tensor<f32>) -> tensor<f32>
%13 = "tf.AddV2"(%arg1, %9) {device = ""} : (tensor<i32>, tensor<i32>) -> tensor<i32>
"tfl.yield"(%13, %arg2, %11, %arg4, %12) : (tensor<i32>, tensor<i32>, tensor<i32>, tensor<!tf_type.resource>, tensor<f32>) -> ()
}) {is_stateless = false} : (tensor<i32>, tensor<i32>, tensor<i32>, tensor<!tf_type.resource>, tensor<f32>) -> (tensor<i32>, tensor<i32>, tensor<i32>, tensor<!tf_type.resource>, tensor<f32>)
func.return %5#3 : tensor<!tf_type.resource>
// CHECK: "tfl.while"
// CHECK: (tensor<i32>, tensor<i32>, tensor<!tf_type.resource>) -> (tensor<i32>, tensor<i32>, tensor<!tf_type.resource>)
}
// CHECK-LABEL: @RemoveFcZeroBias
func.func @RemoveFcZeroBias(%arg0: tensor<1x37xf32>, %arg1: tensor<40x37xf32>) -> tensor<1x40xf32> {
%0 = "tfl.pseudo_const"() {value = dense<0.0> : tensor<40xf32>} : () -> tensor<40xf32>
%1 = "tfl.fully_connected"(%arg0, %arg1, %0) {fused_activation_function = "NONE", keep_num_dims = false, weights_format = "DEFAULT"} : (tensor<1x37xf32>, tensor<40x37xf32>, tensor<40xf32>) -> tensor<1x40xf32>
// CHECK: "tfl.fully_connected"
// CHECK-SAME: (tensor<1x37xf32>, tensor<40x37xf32>, none) -> tensor<1x40xf32>
func.return %1 : tensor<1x40xf32>
}
// CHECK-LABEL: RemoveLstmQuantZeroBias
func.func @RemoveLstmQuantZeroBias(
%arg0: tensor<1x528xf32>,
%arg1: tensor<2048x528xf32>,
%arg2: tensor<2048x528xf32>,
%arg3: tensor<2048x528xf32>,
%arg4: tensor<2048x528xf32>,
%arg5: tensor<2048x640xf32>,
%arg6: tensor<2048x640xf32>,
%arg7: tensor<2048x640xf32>,
%arg8: tensor<2048x640xf32>,
%arg9: tensor<2048xf32>,
%arg10: tensor<2048xf32>,
%arg11: tensor<2048xf32>,
%arg12: tensor<2048xf32>,
%arg13: tensor<640x2048xf32>,
%arg14: tensor<640xf32>,
%arg15: tensor<2048xf32>,
%arg16: tensor<2048xf32>,
%arg17: tensor<2048xf32>,
%arg18: tensor<2048xf32>,
%arg19: tensor<1x640xf32>,
%arg20: tensor<1x2048xf32>
) -> tensor<1x640xf32> {
%cst = "tfl.no_value"() {value = unit} : () -> none
%zero = "tfl.pseudo_const"() {value = dense<0.0> : tensor<640xf32>} : () -> tensor<640xf32>
%0 = "tfl.lstm"(%arg0, %arg1, %arg2, %arg3, %arg4, %arg5, %arg6, %arg7, %arg8, %cst, %cst, %cst, %arg9, %arg10, %arg11, %arg12, %arg13, %zero, %arg19, %arg20, %arg15, %arg16, %arg17, %arg18) ({}) {
cell_clip = 1.000000e+01 : f32, fused_activation_function = "TANH", kernel_type = #tfl<lstm_kernel_type_attr FULL>, proj_clip = 0.01 : f32
} : (tensor<1x528xf32>, tensor<2048x528xf32>, tensor<2048x528xf32>, tensor<2048x528xf32>, tensor<2048x528xf32>, tensor<2048x640xf32>, tensor<2048x640xf32>, tensor<2048x640xf32>, tensor<2048x640xf32>, none, none, none, tensor<2048xf32>, tensor<2048xf32>, tensor<2048xf32>, tensor<2048xf32>, tensor<640x2048xf32>, tensor<640xf32>, tensor<1x640xf32>, tensor<1x2048xf32>, tensor<2048xf32>, tensor<2048xf32>, tensor<2048xf32>, tensor<2048xf32>) -> tensor<1x640xf32>
func.return %0 : tensor<1x640xf32>
// CHECK: %[[NONE:.+]] = "tfl.no_value"() <{value}> : () -> none
// CHECK: "tfl.lstm"(%arg0, %arg1, %arg2, %arg3, %arg4, %arg5, %arg6, %arg7, %arg8, %[[NONE]], %[[NONE]], %[[NONE]], %arg9, %arg10, %arg11, %arg12, %arg13, %[[NONE]], %arg19, %arg20, %arg15, %arg16, %arg17, %arg18)
}
func.func @keepCustomFlexOps(%arg0: tensor<1x10xf32>) -> tensor<1x10xf32> {
%0 = "tfl.custom"() {custom_code = "FlexVarHandleOp", custom_option = #tfl<const_bytes : "0x0B56617248616E646C654F700074120B56617248616E646C654F702A190A0B7368617265645F6E616D65120A12085661726961626C652A0F0A09636F6E7461696E6572120212002A0B0A056474797065120230012A150A0F616C6C6F7765645F6465766963657312020A002A130A057368617065120A3A08120208011202080A3200000283771414042801">} : () -> tensor<!tf_type.resource<tensor<1x10xf32>>>
%1 = "tfl.custom"(%0) {custom_code = "FlexReadVariableOp", custom_option = #tfl<const_bytes : "0x0E526561645661726961626C654F700021120E526561645661726961626C654F701A002A0B0A056474797065120230013200000233241414042801">} : (tensor<!tf_type.resource<tensor<1x10xf32>>>) -> tensor<1x10xf32>
%2 = "tfl.custom"(%1, %arg0) {custom_code = "FlexAddV2", custom_option = #tfl<const_bytes : "0x0541646456320016120541646456321A001A002A070A015412023001320000021F191414042801">} : (tensor<1x10xf32>, tensor<1x10xf32>) -> tensor<1x10xf32>
"tfl.custom"(%0, %2) {custom_code = "FlexAssignVariableOp", custom_option = #tfl<const_bytes : "0x1041737369676E5661726961626C654F70003B121041737369676E5661726961626C654F701A001A002A0B0A056474797065120230012A140A0E76616C69646174655F736861706512022800320000024F3E1414042801">} : (tensor<!tf_type.resource<tensor<1x10xf32>>>, tensor<1x10xf32>) -> ()
%3 = "tfl.custom"(%0) {custom_code = "FlexReadVariableOp", custom_option = #tfl<const_bytes : "0x0E526561645661726961626C654F700021120E526561645661726961626C654F701A002A0B0A056474797065120230013200000233241414042801">} : (tensor<!tf_type.resource<tensor<1x10xf32>>>) -> tensor<1x10xf32>
// CHECK: %0 = "tfl.custom"() <{custom_code = "FlexVarHandleOp"
// CHECK-NEXT: %1 = "tfl.custom"(%0) <{custom_code = "FlexReadVariableOp"
// CHECK-NEXT: %2 = "tfl.custom"(%1, %arg0) <{custom_code = "FlexAddV2"
// CHECK-NEXT: "tfl.custom"(%0, %2) <{custom_code = "FlexAssignVariableOp"
// CHECK-NEXT: %3 = "tfl.custom"(%0) <{custom_code = "FlexReadVariableOp"
func.return %3 : tensor<1x10xf32>
}
// -----
// Converts tfl.broadcast_to to tfl.reshape if input and output have the same
// number of elements.
// CHECK-LABEL: broadcast_to_to_reshape
func.func @broadcast_to_to_reshape(%arg0: tensor<4x4x4xf32>, %arg1 : tensor<4xi32>) -> tensor<1x4x4x4xf32> {
%0 = "tfl.broadcast_to"(%arg0, %arg1) : (tensor<4x4x4xf32>, tensor<4xi32>) -> tensor<1x4x4x4xf32>
// CHECK: "tfl.reshape"
// CHECK-SAME: (tensor<4x4x4xf32>, tensor<4xi32>) -> tensor<1x4x4x4xf32>
func.return %0 : tensor<1x4x4x4xf32>
}
// Converts tfl.broadcast_to to tfl.reshape if input and output have the same
// number of elements.
// CHECK-LABEL: @broadcast_to_to_reshape_i64
func.func @broadcast_to_to_reshape_i64(%arg0: tensor<4x4x4xf32>, %arg1 : tensor<4xi64>) -> tensor<1x4x4x4xf32> {
%0 = "tfl.broadcast_to"(%arg0, %arg1) : (tensor<4x4x4xf32>, tensor<4xi64>) -> tensor<1x4x4x4xf32>
// CHECK: "tfl.cast"
// CHECK-SAME: (tensor<4xi64>) -> tensor<4xi32>
// CHECK-NEXT: "tfl.reshape"
// CHECK-SAME: (tensor<4x4x4xf32>, tensor<4xi32>) -> tensor<1x4x4x4xf32>
func.return %0 : tensor<1x4x4x4xf32>
}
// Converts tfl.broadcast_to to tfl.reshape if input and output have the same
// number of elements.
// CHECK-LABEL: @broadcast_to_to_reshape_i64_const
func.func @broadcast_to_to_reshape_i64_const(%arg0: tensor<4x4x4xf32>) -> tensor<1x4x4x4xf32> {
%cst = arith.constant dense<[1, 4, 4, 4]> : tensor<4xi64>
%0 = "tfl.broadcast_to"(%arg0, %cst) : (tensor<4x4x4xf32>, tensor<4xi64>) -> tensor<1x4x4x4xf32>
// CHECK: arith.constant dense<[1, 4, 4, 4]> : tensor<4xi32>
// CHECK-NEXT: "tfl.reshape"
// CHECK-SAME: (tensor<4x4x4xf32>, tensor<4xi32>) -> tensor<1x4x4x4xf32>
func.return %0 : tensor<1x4x4x4xf32>
}
// -----
// CHECK-LABEL: @trivial_dynamic_update_slice
func.func @trivial_dynamic_update_slice(%arg0: tensor<2x7x14xf32>, %arg1: tensor<2x7x14xf32>) -> tensor<2x7x14xf32> {
%0 = arith.constant dense<0> : tensor<3xi32>
%1 = "tfl.dynamic_update_slice"(%arg0, %arg1, %0) : (tensor<2x7x14xf32>, tensor<2x7x14xf32>, tensor<3xi32>) -> tensor<2x7x14xf32>
// CHECK: return %arg1
func.return %1 : tensor<2x7x14xf32>
}
// -----
// CHECK-LABEL: @trivial_dynamic_update_slice_wrong_update_shape
func.func @trivial_dynamic_update_slice_wrong_update_shape(%arg0: tensor<2x7x14xf32>, %arg1: tensor<2x7x7xf32>) -> tensor<2x7x14xf32> {
%0 = arith.constant dense<0> : tensor<3xi32>
%1 = "tfl.dynamic_update_slice"(%arg0, %arg1, %0) : (tensor<2x7x14xf32>, tensor<2x7x7xf32>, tensor<3xi32>) -> tensor<2x7x14xf32>
// CHECK: "tfl.dynamic_update_slice"
func.return %1 : tensor<2x7x14xf32>
}
// CHECK-LABEL: OptimizeTranposeWithRank7orMoreEffectiveRank6
func.func @OptimizeTranposeWithRank7orMoreEffectiveRank6(%arg0: tensor<7x6x5x4x3x2x1xf32> ) -> (tensor<1x2x3x4x5x6x7xf32>) {
%cst = arith.constant dense<[6, 5, 4, 3, 2, 1, 0]> : tensor<7xi32>
%0 = "tfl.transpose"(%arg0, %cst) : (tensor<7x6x5x4x3x2x1xf32>, tensor<7xi32>) -> tensor<1x2x3x4x5x6x7xf32>
return %0 : tensor<1x2x3x4x5x6x7xf32>
// CHECK-DAG: %[[cst:.*]] = arith.constant dense<[7, 6, 5, 4, 3, 2]> : tensor<6xi32>
// CHECK-DAG: %[[cst_0:.*]] = arith.constant dense<[5, 4, 3, 2, 1, 0]> : tensor<6xi32>
// CHECK-DAG: %[[cst_1:.*]] = arith.constant dense<[1, 2, 3, 4, 5, 6, 7]> : tensor<7xi32>
// CHECK: %0 = "tfl.reshape"(%arg0, %[[cst]]) : (tensor<7x6x5x4x3x2x1xf32>, tensor<6xi32>) -> tensor<7x6x5x4x3x2xf32>
// CHECK: %1 = "tfl.transpose"(%0, %[[cst_0]]) : (tensor<7x6x5x4x3x2xf32>, tensor<6xi32>) -> tensor<2x3x4x5x6x7xf32>
// CHECK: %2 = "tfl.reshape"(%1, %[[cst_1]]) : (tensor<2x3x4x5x6x7xf32>, tensor<7xi32>) -> tensor<1x2x3x4x5x6x7xf32>
// CHECK: return %2
}
// CHECK-LABEL: OptimizeTranposeWithRank7orMoreEffectiveRank4
func.func @OptimizeTranposeWithRank7orMoreEffectiveRank4(%arg0: tensor<56x8x56x1x1x1x7xf32> ) -> (tensor<1x1x8x56x56x7x1xf32>) {
%cst = arith.constant dense<[4, 5, 1, 2, 0, 6, 3]> : tensor<7xi32>
%0 = "tfl.transpose"(%arg0, %cst) : (tensor<56x8x56x1x1x1x7xf32>, tensor<7xi32>) -> tensor<1x1x8x56x56x7x1xf32>
return %0 : tensor<1x1x8x56x56x7x1xf32>
// CHECK-DAG: %[[cst:.*]] = arith.constant dense<[56, 8, 56, 7]> : tensor<4xi32>
// CHECK-DAG: %[[cst_0:.*]] = arith.constant dense<[1, 2, 0, 3]> : tensor<4xi32>
// CHECK-DAG: %[[cst_1:.*]] = arith.constant dense<[1, 1, 8, 56, 56, 7, 1]> : tensor<7xi32>
// CHECK: %0 = "tfl.reshape"(%arg0, %[[cst]]) : (tensor<56x8x56x1x1x1x7xf32>, tensor<4xi32>) -> tensor<56x8x56x7xf32>
// CHECK: %1 = "tfl.transpose"(%0, %[[cst_0]]) : (tensor<56x8x56x7xf32>, tensor<4xi32>) -> tensor<8x56x56x7xf32>
// CHECK: %2 = "tfl.reshape"(%1, %[[cst_1]]) : (tensor<8x56x56x7xf32>, tensor<7xi32>) -> tensor<1x1x8x56x56x7x1xf32>
// CHECK: return %2
}
// CHECK-LABEL: @ConstPadToI32
func.func @ConstPadToI32(%arg0: tensor<15600xf32>) -> tensor<15602xf32> {
%0 = "tfl.pseudo_const"() {value = dense<1> : tensor<1x2xi64>} : () -> tensor<1x2xi64>
%1 = "tfl.pad"(%arg0, %0) : (tensor<15600xf32>, tensor<1x2xi64>) -> tensor<15602xf32>
func.return %1 : tensor<15602xf32>
// CHECK: "tfl.pad"(%arg0, %cst) : (tensor<15600xf32>, tensor<1x2xi32>) -> tensor<15602xf32>
}
// CHECK-LABEL: @RemoveNoopTranspose
func.func @RemoveNoopTranspose(%arg0: tensor<1x2x3x4xf32>) -> tensor<1x2x3x4xf32> {
%cst = arith.constant dense<[0, 1, 2, 3]> : tensor<4xi32>
%0 = "tfl.transpose"(%arg0, %cst) : (tensor<1x2x3x4xf32>, tensor<4xi32>) -> tensor<1x2x3x4xf32>
func.return %0 : tensor<1x2x3x4xf32>
// CHECK: return %arg0
}
@@ -0,0 +1,105 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: litert-opt %s --tfl-canonicalize-boundary-value --split-input-file | FileCheck %s
// CHECK-LABEL: func.func @clamp_neg_inf_f32() -> tensor<f32> {
// CHECK: %[[CONST:.*]] = stablehlo.constant dense<-3.40282347E+38> : tensor<f32>
// CHECK: return %[[CONST]] : tensor<f32>
func.func @clamp_neg_inf_f32() -> tensor<f32> {
%ret = stablehlo.constant dense<0xFF800000> : tensor<f32>
return %ret : tensor<f32>
}
// -----
// CHECK-LABEL: func.func @clamp_pos_inf_f32() -> tensor<f32> {
// CHECK: %[[CONST:.*]] = stablehlo.constant dense<3.40282347E+38> : tensor<f32>
// CHECK: return %[[CONST]] : tensor<f32>
func.func @clamp_pos_inf_f32() -> tensor<f32> {
%ret = stablehlo.constant dense<0x7F800000> : tensor<f32>
return %ret : tensor<f32>
}
// -----
// CHECK-LABEL: func.func @clamp_pos_inf_f32_tensor() -> tensor<1x4xf32> {
// CHECK: %[[CONST:.*]] = stablehlo.constant dense<{{\[\[}}3.40282347E+38, 1.000000e+01, 2.000000e+01, -3.40282347E+38]]> : tensor<1x4xf32>
// CHECK: return %[[CONST]] : tensor<1x4xf32>
func.func @clamp_pos_inf_f32_tensor() -> tensor<1x4xf32> {
%ret = stablehlo.constant dense<[[0x7F800000, 10.0, 20.0, 0xFF800000]]> : tensor<1x4xf32>
return %ret : tensor<1x4xf32>
}
// -----
// CHECK-LABEL: func.func @clamp_neg_inf_f16() -> tensor<f16> {
// CHECK: %[[CONST:.*]] = stablehlo.constant dense<-6.550400e+04> : tensor<f16>
// CHECK: return %[[CONST]] : tensor<f16>
func.func @clamp_neg_inf_f16() -> tensor<f16> {
%ret = stablehlo.constant dense<0xFC00> : tensor<f16>
return %ret : tensor<f16>
}
// -----
// CHECK-LABEL: func.func @clamp_neg_inf_bf16() -> tensor<bf16> {
// CHECK: %[[CONST:.*]] = stablehlo.constant dense<-1.038460e+34> : tensor<bf16>
// CHECK: return %[[CONST]] : tensor<bf16>
func.func @clamp_neg_inf_bf16() -> tensor<bf16> {
%ret = stablehlo.constant dense<0xF800> : tensor<bf16>
return %ret : tensor<bf16>
}
// -----
// CHECK-LABEL: func.func @clamp_pos_inf_f16() -> tensor<f16> {
// CHECK: %[[CONST:.*]] = stablehlo.constant dense<6.550400e+04> : tensor<f16>
// CHECK: return %[[CONST]] : tensor<f16>
func.func @clamp_pos_inf_f16() -> tensor<f16> {
%ret = stablehlo.constant dense<0x7C00> : tensor<f16>
return %ret : tensor<f16>
}
// -----
// CHECK-LABEL: func.func @clamp_pos_inf_f16_tensor() -> tensor<1x4xf16> {
// CHECK: %[[CONST:.*]] = stablehlo.constant dense<{{\[\[}}6.550400e+04, 1.000000e+01, 2.000000e+01, -6.550400e+04]]> : tensor<1x4xf16>
// CHECK: return %[[CONST]] : tensor<1x4xf16>
func.func @clamp_pos_inf_f16_tensor() -> tensor<1x4xf16> {
%ret = stablehlo.constant dense<[[0x7C00, 10.0, 20.0, 0xFC00]]> : tensor<1x4xf16>
return %ret : tensor<1x4xf16>
}
// -----
// CHECK-LABEL: func.func @clamp_pos_inf_f16_tensor_tf_const() -> tensor<3xf16> {
// CHECK: %[[CONST:.*]] = "tf.Const"() <{value = dense<6.550400e+04> : tensor<3xf16>}> : () -> tensor<3xf16>
// CHECK: return %[[CONST]] : tensor<3xf16>
func.func @clamp_pos_inf_f16_tensor_tf_const() -> tensor<3xf16> {
%ret = "tf.Const"() <{value = dense<0x7C00> : tensor<3xf16>}> : () -> tensor<3xf16>
return %ret : tensor<3xf16>
}
// -----
// CHECK-LABEL: func.func @clamp_pos_inf_f16_arith_op() -> f16 {
// CHECK: %[[CONST:.*]] = arith.constant 6.550400e+04 : f16
// CHECK: return %[[CONST]] : f16
func.func @clamp_pos_inf_f16_arith_op() -> f16 {
%ret = arith.constant 0x7C00 : f16
return %ret : f16
}
@@ -0,0 +1,28 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: litert-opt %s --tfl-cleanup-optimization-barrier --split-input-file | FileCheck %s
// CHECK-LABEL: func.func @cleanup_barrier(%arg0: tensor<2x2xf32>) -> tensor<2x2xf32> {
// CHECK: %0 = tfl.add(%arg0, %cst) <{fused_activation_function = "NONE"}> : (tensor<2x2xf32>, tensor<f32>) -> tensor<2x2xf32>
// CHECK: %1 = tfl.add(%0, %cst) <{fused_activation_function = "NONE"}> : (tensor<2x2xf32>, tensor<f32>) -> tensor<2x2xf32>
// CHECK: return %1 : tensor<2x2xf32>
func.func @cleanup_barrier(%arg0: tensor<2x2xf32>) -> tensor<2x2xf32> {
%cst = arith.constant dense<5.000000e+00> : tensor<f32>
%0 = tfl.add(%arg0, %cst) <{fused_activation_function = "NONE"}> : (tensor<2x2xf32>, tensor<f32>) -> tensor<2x2xf32>
%1 = stablehlo.optimization_barrier %0 : tensor<2x2xf32>
%2 = tfl.add(%1, %cst) <{fused_activation_function = "NONE"}> : (tensor<2x2xf32>, tensor<f32>) -> tensor<2x2xf32>
return %2 : tensor<2x2xf32>
}
@@ -0,0 +1,778 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: litert-opt %s -canonicalize | env FILECHECK_OPTS="" FileCheck %s
// TODO(b/493282789): Enable DenseResourceElementsAttr constant folding with
// more peformant folder implementations.
// CHECK-LABEL: @add_float
func.func @add_float() -> (tensor<f32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>) {
%0 = arith.constant dense<4.5> : tensor<f32>
%1 = arith.constant dense<1.5> : tensor<f32>
%2 = arith.constant dense< 3.5> : tensor<4xf32>
%3 = arith.constant dense<-0.5> : tensor<4xf32>
// CHECK-DAG: %[[CST:.*]] = arith.constant dense<3.500000e+00> : tensor<4xf32>
// CHECK-DAG: %[[CST_0:.*]] = arith.constant dense<-5.000000e-01> : tensor<4xf32>
// CHECK-DAG: %[[CST_1:.*]] = arith.constant dense<6.000000e+00> : tensor<f32>
// CHECK-DAG: %[[CST_2:.*]] = arith.constant dense<4.000000e+00> : tensor<4xf32>
// CHECK-DAG: %[[CST_3:.*]] = arith.constant dense<5.000000e+00> : tensor<4xf32>
// CHECK-DAG: %[[CST_4:.*]] = arith.constant dense<3.000000e+00> : tensor<4xf32>
// CHECK: %0 = tfl.add %[[CST]], %[[CST_0]] {fused_activation_function = "SIGN_BIT"} : tensor<4xf32>
%5 = "tfl.add"(%0, %1) {fused_activation_function = "NONE"} : (tensor< f32>, tensor< f32>) -> tensor< f32>
%6 = "tfl.add"(%0, %3) {fused_activation_function = "NONE"} : (tensor< f32>, tensor<4xf32>) -> tensor<4xf32>
%7 = "tfl.add"(%2, %1) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor< f32>) -> tensor<4xf32>
%8 = "tfl.add"(%2, %3) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32>
%9 = "tfl.add"(%2, %3) {fused_activation_function = "SIGN_BIT"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32>
func.return %5, %6, %7, %8, %9 : tensor<f32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>
}
// CHECK-LABEL: @add_int
func.func @add_int() -> (tensor<i32>, tensor<4xi32>, tensor<4xi32>, tensor<4xi32>) {
%0 = arith.constant dense<8> : tensor<i32>
%1 = arith.constant dense<1> : tensor<i32>
%2 = arith.constant dense< 4> : tensor<4xi32>
%3 = arith.constant dense<-2> : tensor<4xi32>
// CHECK-DAG: %[[CST:.*]] = arith.constant dense<9> : tensor<i32>
// CHECK-DAG: %[[CST_0:.*]] = arith.constant dense<6> : tensor<4xi32>
// CHECK-DAG: %[[CST_1:.*]] = arith.constant dense<5> : tensor<4xi32>
// CHECK-DAG: %[[CST_2:.*]] = arith.constant dense<2> : tensor<4xi32>
%5 = "tfl.add"(%0, %1) {fused_activation_function = "NONE"} : (tensor< i32>, tensor< i32>) -> tensor< i32>
%6 = "tfl.add"(%0, %3) {fused_activation_function = "NONE"} : (tensor< i32>, tensor<4xi32>) -> tensor<4xi32>
%7 = "tfl.add"(%2, %1) {fused_activation_function = "NONE"} : (tensor<4xi32>, tensor< i32>) -> tensor<4xi32>
%8 = "tfl.add"(%2, %3) {fused_activation_function = "NONE"} : (tensor<4xi32>, tensor<4xi32>) -> tensor<4xi32>
func.return %5, %6, %7, %8 : tensor<i32>, tensor<4xi32>, tensor<4xi32>, tensor<4xi32>
}
// CHECK-LABEL: @sub_float
func.func @sub_float() -> (tensor<f32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>) {
%0 = arith.constant dense<4.5> : tensor<f32>
%1 = arith.constant dense<1.5> : tensor<f32>
%2 = arith.constant dense< 3.5> : tensor<4xf32>
%3 = arith.constant dense<-0.5> : tensor<4xf32>
// CHECK-DAG: %[[CST:.*]] = arith.constant dense<3.000000e+00> : tensor<f32>
// CHECK-DAG: %[[CST_0:.*]] = arith.constant dense<5.000000e+00> : tensor<4xf32>
// CHECK-DAG: %[[CST_1:.*]] = arith.constant dense<2.000000e+00> : tensor<4xf32>
// CHECK-DAG: %[[CST_2:.*]] = arith.constant dense<4.000000e+00> : tensor<4xf32>
%5 = "tfl.sub"(%0, %1) {fused_activation_function = "NONE"} : (tensor< f32>, tensor< f32>) -> tensor< f32>
%6 = "tfl.sub"(%0, %3) {fused_activation_function = "NONE"} : (tensor< f32>, tensor<4xf32>) -> tensor<4xf32>
%7 = "tfl.sub"(%2, %1) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor< f32>) -> tensor<4xf32>
%8 = "tfl.sub"(%2, %3) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32>
func.return %5, %6, %7, %8 : tensor<f32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>
}
// CHECK-LABEL: @sub_int
func.func @sub_int() -> (tensor<i32>, tensor<4xi32>, tensor<4xi32>, tensor<4xi32>) {
%0 = arith.constant dense<8> : tensor<i32>
%1 = arith.constant dense<1> : tensor<i32>
%2 = arith.constant dense< 4> : tensor<4xi32>
%3 = arith.constant dense<-2> : tensor<4xi32>
// CHECK-DAG: %[[CST:.*]] = arith.constant dense<7> : tensor<i32>
// CHECK-DAG: %[[CST_0:.*]] = arith.constant dense<10> : tensor<4xi32>
// CHECK-DAG: %[[CST_1:.*]] = arith.constant dense<3> : tensor<4xi32>
// CHECK-DAG: %[[CST_2:.*]] = arith.constant dense<6> : tensor<4xi32>
%5 = "tfl.sub"(%0, %1) {fused_activation_function = "NONE"} : (tensor< i32>, tensor< i32>) -> tensor< i32>
%6 = "tfl.sub"(%0, %3) {fused_activation_function = "NONE"} : (tensor< i32>, tensor<4xi32>) -> tensor<4xi32>
%7 = "tfl.sub"(%2, %1) {fused_activation_function = "NONE"} : (tensor<4xi32>, tensor< i32>) -> tensor<4xi32>
%8 = "tfl.sub"(%2, %3) {fused_activation_function = "NONE"} : (tensor<4xi32>, tensor<4xi32>) -> tensor<4xi32>
func.return %5, %6, %7, %8 : tensor<i32>, tensor<4xi32>, tensor<4xi32>, tensor<4xi32>
}
// CHECK-LABEL: @sub_zero
func.func @sub_zero(%arg0: tensor<4xi32>, %arg1: tensor<4xf32>) -> (tensor<4xi32>, tensor<4xf32>) {
%zero_int = arith.constant dense<0> : tensor<4xi32>
%zero_float = arith.constant dense<0.0> : tensor<4xf32>
// CHECK-NOT: tfl.sub
// CHECK: return %arg0, %arg1
%0 = "tfl.sub"(%arg0, %zero_int) {fused_activation_function = "NONE"} : (tensor<4xi32>, tensor<4xi32>) -> tensor<4xi32>
%1 = "tfl.sub"(%arg1, %zero_float) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32>
func.return %0, %1 : tensor<4xi32>, tensor<4xf32>
}
// CHECK-LABEL: @sub_zero_lhs
func.func @sub_zero_lhs(%arg0: tensor<4xi32>, %arg1: tensor<4xf32>) -> (tensor<4xi32>, tensor<4xf32>) {
%zero_int = arith.constant dense<0> : tensor<4xi32>
%zero_float = arith.constant dense<0.0> : tensor<4xf32>
// CHECK: tfl.sub
// CHECK: return %0, %1
%0 = "tfl.sub"(%zero_int, %arg0) {fused_activation_function = "NONE"} : (tensor<4xi32>, tensor<4xi32>) -> tensor<4xi32>
%1 = "tfl.sub"(%zero_float, %arg1) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32>
func.return %0, %1 : tensor<4xi32>, tensor<4xf32>
}
// CHECK-LABEL: @sub_zero_quant
func.func @sub_zero_quant(%arg0: tensor<32x!quant.uniform<u8:f32, 1.0>>) -> tensor<32x!quant.uniform<u8:f32, 1.0>> {
%zero = "tfl.pseudo_qconst"() {qtype = tensor<32x!quant.uniform<u8:f32, 1.0>>, value = dense<0> : tensor<32xi8>} : () -> tensor<32x!quant.uniform<u8:f32, 1.0>>
// CHECK: %[[SUB:.*]] = tfl.sub
// CHECK: return %[[SUB]]
%0 = "tfl.sub"(%arg0, %zero) {fused_activation_function = "NONE"} : (tensor<32x!quant.uniform<u8:f32, 1.0>>, tensor<32x!quant.uniform<u8:f32, 1.0>>) -> tensor<32x!quant.uniform<u8:f32, 1.0>>
func.return %0 : tensor<32x!quant.uniform<u8:f32, 1.0>>
}
// CHECK-LABEL: @mul_float
func.func @mul_float() -> (tensor<f32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>) {
%0 = arith.constant dense<4.5> : tensor<f32>
%1 = arith.constant dense<1.5> : tensor<f32>
%2 = arith.constant dense< 3.5> : tensor<4xf32>
%3 = arith.constant dense<-0.5> : tensor<4xf32>
// CHECK-DAG: %[[CST:.*]] = arith.constant dense<6.750000e+00> : tensor<f32>
// CHECK-DAG: %[[CST_0:.*]] = arith.constant dense<-2.250000e+00> : tensor<4xf32>
// CHECK-DAG: %[[CST_1:.*]] = arith.constant dense<5.250000e+00> : tensor<4xf32>
// CHECK-DAG: %[[CST_2:.*]] = arith.constant dense<-1.750000e+00> : tensor<4xf32>
%5 = "tfl.mul"(%0, %1) {fused_activation_function = "NONE"} : (tensor< f32>, tensor< f32>) -> tensor< f32>
%6 = "tfl.mul"(%0, %3) {fused_activation_function = "NONE"} : (tensor< f32>, tensor<4xf32>) -> tensor<4xf32>
%7 = "tfl.mul"(%2, %1) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor< f32>) -> tensor<4xf32>
%8 = "tfl.mul"(%2, %3) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32>
func.return %5, %6, %7, %8 : tensor<f32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>
}
// CHECK-LABEL: @mul_bf16
func.func @mul_bf16() -> (tensor<bf16>, tensor<4xbf16>, tensor<4xbf16>, tensor<4xbf16>) {
%0 = arith.constant dense<4.5> : tensor<bf16>
%1 = arith.constant dense<1.5> : tensor<bf16>
%2 = arith.constant dense< 3.5> : tensor<4xbf16>
%3 = arith.constant dense<-0.5> : tensor<4xbf16>
// CHECK-DAG: %[[CST:.*]] = arith.constant dense<6.750000e+00> : tensor<bf16>
// CHECK-DAG: %[[CST_0:.*]] = arith.constant dense<-2.250000e+00> : tensor<4xbf16>
// CHECK-DAG: %[[CST_1:.*]] = arith.constant dense<5.250000e+00> : tensor<4xbf16>
// CHECK-DAG: %[[CST_2:.*]] = arith.constant dense<-1.750000e+00> : tensor<4xbf16>
%5 = "tfl.mul"(%0, %1) {fused_activation_function = "NONE"} : (tensor< bf16>, tensor< bf16>) -> tensor< bf16>
%6 = "tfl.mul"(%0, %3) {fused_activation_function = "NONE"} : (tensor< bf16>, tensor<4xbf16>) -> tensor<4xbf16>
%7 = "tfl.mul"(%2, %1) {fused_activation_function = "NONE"} : (tensor<4xbf16>, tensor< bf16>) -> tensor<4xbf16>
%8 = "tfl.mul"(%2, %3) {fused_activation_function = "NONE"} : (tensor<4xbf16>, tensor<4xbf16>) -> tensor<4xbf16>
func.return %5, %6, %7, %8 : tensor<bf16>, tensor<4xbf16>, tensor<4xbf16>, tensor<4xbf16>
}
// CHECK-LABEL: @mul_f16
func.func @mul_f16() -> (tensor<f16>, tensor<4xf16>, tensor<4xf16>, tensor<4xf16>) {
%0 = arith.constant dense<4.5> : tensor<f16>
%1 = arith.constant dense<1.5> : tensor<f16>
%2 = arith.constant dense< 3.5> : tensor<4xf16>
%3 = arith.constant dense<-0.5> : tensor<4xf16>
// CHECK-DAG: %[[CST:.*]] = arith.constant dense<6.750000e+00> : tensor<f16>
// CHECK-DAG: %[[CST_0:.*]] = arith.constant dense<-2.250000e+00> : tensor<4xf16>
// CHECK-DAG: %[[CST_1:.*]] = arith.constant dense<5.250000e+00> : tensor<4xf16>
// CHECK-DAG: %[[CST_2:.*]] = arith.constant dense<-1.750000e+00> : tensor<4xf16>
%5 = "tfl.mul"(%0, %1) {fused_activation_function = "NONE"} : (tensor< f16>, tensor< f16>) -> tensor< f16>
%6 = "tfl.mul"(%0, %3) {fused_activation_function = "NONE"} : (tensor< f16>, tensor<4xf16>) -> tensor<4xf16>
%7 = "tfl.mul"(%2, %1) {fused_activation_function = "NONE"} : (tensor<4xf16>, tensor< f16>) -> tensor<4xf16>
%8 = "tfl.mul"(%2, %3) {fused_activation_function = "NONE"} : (tensor<4xf16>, tensor<4xf16>) -> tensor<4xf16>
func.return %5, %6, %7, %8 : tensor<f16>, tensor<4xf16>, tensor<4xf16>, tensor<4xf16>
}
// CHECK-LABEL: @mul_zero
func.func @mul_zero(%arg0: tensor<4xi32>, %arg1: tensor<4xf32>) -> (tensor<4xi32>, tensor<4xf32>) {
%zero_int = arith.constant dense<0> : tensor<4xi32>
%zero_float = arith.constant dense<0.0> : tensor<4xf32>
// CHECK-NOT: tfl.mul
// CHECK: return %cst, %cst_0
%0 = "tfl.mul"(%arg0, %zero_int) {fused_activation_function = "NONE"} : (tensor<4xi32>, tensor<4xi32>) -> tensor<4xi32>
%1 = "tfl.mul"(%arg1, %zero_float) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32>
func.return %0, %1 : tensor<4xi32>, tensor<4xf32>
}
// CHECK-LABEL: @mul_zero_lhs
func.func @mul_zero_lhs(%arg0: tensor<4xi32>, %arg1: tensor<4xf32>) -> (tensor<4xi32>, tensor<4xf32>) {
%zero_int = arith.constant dense<0> : tensor<4xi32>
%zero_float = arith.constant dense<0.0> : tensor<4xf32>
// CHECK-NOT: tfl.mul
// CHECK: return %cst, %cst_0
%0 = "tfl.mul"(%zero_int, %arg0) {fused_activation_function = "NONE"} : (tensor<4xi32>, tensor<4xi32>) -> tensor<4xi32>
%1 = "tfl.mul"(%zero_float, %arg1) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32>
func.return %0, %1 : tensor<4xi32>, tensor<4xf32>
}
// CHECK-LABEL: @mul_one
func.func @mul_one(%arg0: tensor<4xi32>, %arg1: tensor<4xf32>) -> (tensor<4xi32>, tensor<4xf32>) {
%one_int = arith.constant dense<1> : tensor<4xi32>
%one_float = arith.constant dense<1.0> : tensor<4xf32>
// CHECK-NOT: tfl.mul
// CHECK: return %arg0, %arg1
%0 = "tfl.mul"(%arg0, %one_int) {fused_activation_function = "NONE"} : (tensor<4xi32>, tensor<4xi32>) -> tensor<4xi32>
%1 = "tfl.mul"(%arg1, %one_float) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32>
func.return %0, %1 : tensor<4xi32>, tensor<4xf32>
}
// CHECK-LABEL: @mul_one_lhs
func.func @mul_one_lhs(%arg0: tensor<4xi32>, %arg1: tensor<4xf32>) -> (tensor<4xi32>, tensor<4xf32>) {
%one_int = arith.constant dense<1> : tensor<4xi32>
%one_float = arith.constant dense<1.0> : tensor<4xf32>
// CHECK-NOT: tfl.mul
// CHECK: return %arg0, %arg1
%0 = "tfl.mul"(%one_int, %arg0) {fused_activation_function = "NONE"} : (tensor<4xi32>, tensor<4xi32>) -> tensor<4xi32>
%1 = "tfl.mul"(%one_float, %arg1) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32>
func.return %0, %1 : tensor<4xi32>, tensor<4xf32>
}
// CHECK-LABEL: @mul_one_quant
func.func @mul_one_quant(%arg0: tensor<32x!quant.uniform<u8:f32, 1.0>>) -> tensor<32x!quant.uniform<u8:f32, 1.0>> {
%one = "tfl.pseudo_qconst"() {qtype = tensor<32x!quant.uniform<u8:f32, 1.0>>, value = dense<1> : tensor<32xi8>} : () -> tensor<32x!quant.uniform<u8:f32, 1.0>>
// CHECK: %[[MUL:.*]] = tfl.mul
// CHECK: return %[[MUL]]
%0 = "tfl.mul"(%one, %arg0) {fused_activation_function = "NONE"} : (tensor<32x!quant.uniform<u8:f32, 1.0>>, tensor<32x!quant.uniform<u8:f32, 1.0>>) -> tensor<32x!quant.uniform<u8:f32, 1.0>>
func.return %0 : tensor<32x!quant.uniform<u8:f32, 1.0>>
}
// CHECK-LABEL: @max_with_neg_f32_max_val
// CHECK-SAME: (%[[ARG0:.+]]: tensor<f32>)
func.func @max_with_neg_f32_max_val(%arg0 : tensor<f32>) -> (tensor<f32>, tensor<f32>) {
%neg_f32_max = arith.constant dense<-3.40282347E+38> : tensor<f32>
%0 = "tfl.maximum"(%arg0, %neg_f32_max) : (tensor<f32>, tensor<f32>) -> tensor<f32>
%1 = "tfl.maximum"(%neg_f32_max, %arg0) : (tensor<f32>, tensor<f32>) -> tensor<f32>
func.return %0, %1 : tensor<f32>, tensor<f32>
// CHECK: return %[[ARG0]], %[[ARG0]]
}
// CHECK-LABEL: @max_with_neg_inf
func.func @max_with_neg_inf(%arg0 : tensor<f32>) -> (tensor<f32>, tensor<f32>) {
%neg_inf = arith.constant dense<0xFF800000> : tensor<f32>
%0 = "tfl.maximum"(%arg0, %neg_inf) : (tensor<f32>, tensor<f32>) -> tensor<f32>
%1 = "tfl.maximum"(%neg_inf, %arg0) : (tensor<f32>, tensor<f32>) -> tensor<f32>
func.return %0, %1 : tensor<f32>, tensor<f32>
// CHECK: return %[[ARG0]], %[[ARG0]]
}
// CHECK-LABEL: @min_with_f32_max_val
// CHECK-SAME: (%[[ARG0:.+]]: tensor<f32>)
func.func @min_with_f32_max_val(%arg0 : tensor<f32>) -> (tensor<f32>, tensor<f32>) {
%f32_max = arith.constant dense<3.40282347E+38> : tensor<f32>
%0 = "tfl.minimum"(%arg0, %f32_max) : (tensor<f32>, tensor<f32>) -> tensor<f32>
%1 = "tfl.minimum"(%f32_max, %arg0) : (tensor<f32>, tensor<f32>) -> tensor<f32>
func.return %0, %1 : tensor<f32>, tensor<f32>
// CHECK: return %[[ARG0]], %[[ARG0]]
}
// CHECK-LABEL: @min_with_inf
func.func @min_with_inf(%arg0 : tensor<f32>) -> (tensor<f32>, tensor<f32>) {
%inf = arith.constant dense<0x7F800000> : tensor<f32>
%0 = "tfl.minimum"(%arg0, %inf) : (tensor<f32>, tensor<f32>) -> tensor<f32>
%1 = "tfl.minimum"(%inf, %arg0) : (tensor<f32>, tensor<f32>) -> tensor<f32>
func.return %0, %1 : tensor<f32>, tensor<f32>
// CHECK: return %[[ARG0]], %[[ARG0]]
}
// CHECK-LABEL: @max_with_neg_f64_max_val
// CHECK-SAME: (%[[ARG0:.+]]: tensor<f64>)
func.func @max_with_neg_f64_max_val(%arg0 : tensor<f64>) -> (tensor<f64>, tensor<f64>) {
%neg_f64_max = arith.constant dense<-1.7976931348623157E+308> : tensor<f64>
%0 = "tfl.maximum"(%arg0, %neg_f64_max) : (tensor<f64>, tensor<f64>) -> tensor<f64>
%1 = "tfl.maximum"(%neg_f64_max, %arg0) : (tensor<f64>, tensor<f64>) -> tensor<f64>
func.return %0, %1 : tensor<f64>, tensor<f64>
// CHECK: return %[[ARG0]], %[[ARG0]]
}
// CHECK-LABEL: @min_with_f64_max_val
// CHECK-SAME: (%[[ARG0:.+]]: tensor<f64>)
func.func @min_with_f64_max_val(%arg0 : tensor<f64>) -> (tensor<f64>, tensor<f64>) {
%f64_max = arith.constant dense<1.7976931348623157E+308> : tensor<f64>
%0 = "tfl.minimum"(%arg0, %f64_max) : (tensor<f64>, tensor<f64>) -> tensor<f64>
%1 = "tfl.minimum"(%f64_max, %arg0) : (tensor<f64>, tensor<f64>) -> tensor<f64>
func.return %0, %1 : tensor<f64>, tensor<f64>
// CHECK: return %[[ARG0]], %[[ARG0]]
}
// CHECK-LABEL: @min_dense_splat_int
func.func @min_dense_splat_int() -> tensor<4xi32> {
%0 = arith.constant dense<[-10, -1, 42, 100]> : tensor<4xi32>
%1 = arith.constant dense<5> : tensor<4xi32>
%2 = "tfl.minimum"(%0, %1) {fused_activation_function = "NONE"} : (tensor<4xi32>, tensor<4xi32>) -> tensor<4xi32>
func.return %2 : tensor<4xi32>
}
// CHECK: arith.constant dense<[-10, -1, 5, 5]> : tensor<4xi32>
// CHECK-LABEL: @min_dense_splat_float
func.func @min_dense_splat_float() -> tensor<4xf32> {
%0 = arith.constant dense<[-10.0, -1.0, 42.0, 100.0]> : tensor<4xf32>
%1 = arith.constant dense<5.0> : tensor<4xf32>
%2 = "tfl.minimum"(%0, %1) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32>
func.return %2 : tensor<4xf32>
}
// CHECK: arith.constant dense<[-1.000000e+01, -1.000000e+00, 5.000000e+00, 5.000000e+00]> : tensor<4xf32>
// CHECK-LABEL: @min_dense_float
func.func @min_dense_float() -> tensor<2xf32> {
%0 = arith.constant dense<[-10.0, 10.0]> : tensor<2xf32>
%1 = arith.constant dense<[5.0, 5.0]> : tensor<2xf32>
%2 = "tfl.minimum"(%0, %1) {fused_activation_function = "NONE"} : (tensor<2xf32>, tensor<2xf32>) -> tensor<2xf32>
func.return %2 : tensor<2xf32>
}
// CHECK: arith.constant dense<[-1.000000e+01, 5.000000e+00]> : tensor<2xf32>
// CHECK-LABEL: @max_dense_splat_int
func.func @max_dense_splat_int() -> tensor<4xi32> {
%0 = arith.constant dense<[-10, -1, 42, 100]> : tensor<4xi32>
%1 = arith.constant dense<5> : tensor<4xi32>
%2 = "tfl.maximum"(%0, %1) {fused_activation_function = "NONE"} : (tensor<4xi32>, tensor<4xi32>) -> tensor<4xi32>
func.return %2 : tensor<4xi32>
}
// CHECK: arith.constant dense<[5, 5, 42, 100]> : tensor<4xi32>
// CHECK-LABEL: @max_dense_splat_float
func.func @max_dense_splat_float() -> tensor<4xf32> {
%0 = arith.constant dense<[-10.0, -1.0, 42.0, 100.0]> : tensor<4xf32>
%1 = arith.constant dense<5.0> : tensor<4xf32>
%2 = "tfl.maximum"(%0, %1) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32>
func.return %2 : tensor<4xf32>
}
// CHECK: arith.constant dense<[5.000000e+00, 5.000000e+00, 4.200000e+01, 1.000000e+02]> : tensor<4xf32>
// CHECK-LABEL: @max_dense_float
func.func @max_dense_float() -> tensor<2xf32> {
%0 = arith.constant dense<[-10.0, 10.0]> : tensor<2xf32>
%1 = arith.constant dense<[5.0, 5.0]> : tensor<2xf32>
%2 = "tfl.maximum"(%0, %1) {fused_activation_function = "NONE"} : (tensor<2xf32>, tensor<2xf32>) -> tensor<2xf32>
func.return %2 : tensor<2xf32>
}
// CHECK: arith.constant dense<[5.000000e+00, 1.000000e+01]> : tensor<2xf32>
// CHECK-LABEL: @mul_int
func.func @mul_int() -> (tensor<i32>, tensor<4xi32>, tensor<4xi32>, tensor<4xi32>) {
%0 = arith.constant dense<8> : tensor<i32>
%1 = arith.constant dense<1> : tensor<i32>
%2 = arith.constant dense< 4> : tensor<4xi32>
%3 = arith.constant dense<-2> : tensor<4xi32>
// CHECK-DAG: [[cst0:%.*]] = arith.constant dense<8> : tensor<i32>
// CHECK-DAG: [[cst1:%.*]] = arith.constant dense<-16> : tensor<4xi32>
// CHECK-DAG: [[cst2:%.*]] = arith.constant dense<4> : tensor<4xi32>
// CHECK-DAG: [[cst3:%.*]] = arith.constant dense<-8> : tensor<4xi32>
// CHECK: return [[cst0]], [[cst1]], [[cst2]], [[cst3]]
%5 = "tfl.mul"(%0, %1) {fused_activation_function = "NONE"} : (tensor< i32>, tensor< i32>) -> tensor< i32>
%6 = "tfl.mul"(%0, %3) {fused_activation_function = "NONE"} : (tensor< i32>, tensor<4xi32>) -> tensor<4xi32>
%7 = "tfl.mul"(%2, %1) {fused_activation_function = "NONE"} : (tensor<4xi32>, tensor< i32>) -> tensor<4xi32>
%8 = "tfl.mul"(%2, %3) {fused_activation_function = "NONE"} : (tensor<4xi32>, tensor<4xi32>) -> tensor<4xi32>
func.return %5, %6, %7, %8 : tensor<i32>, tensor<4xi32>, tensor<4xi32>, tensor<4xi32>
}
// CHECK-LABEL: @add_dense_splat_int
func.func @add_dense_splat_int() -> tensor<4xi32> {
%0 = arith.constant dense<[-10, -1, 42, 100]> : tensor<4xi32>
%1 = arith.constant dense< 5> : tensor<4xi32>
%2 = "tfl.add"(%0, %1) {fused_activation_function = "NONE"} : (tensor<4xi32>, tensor<4xi32>) -> tensor<4xi32>
func.return %2 : tensor<4xi32>
// CHECK: %[[CST:.*]] = arith.constant dense<[-5, 4, 47, 105]> : tensor<4xi32>
// CHECK: return %[[CST]]
}
// CHECK-LABEL: @add_splat_dense_int
func.func @add_splat_dense_int() -> tensor<4xi32> {
%0 = arith.constant dense< 5> : tensor<4xi32>
%1 = arith.constant dense<[-10, -1, 42, 100]> : tensor<4xi32>
%2 = "tfl.add"(%0, %1) {fused_activation_function = "NONE"} : (tensor<4xi32>, tensor<4xi32>) -> tensor<4xi32>
func.return %2 : tensor<4xi32>
// CHECK: %[[CST:.*]] = arith.constant dense<[-5, 4, 47, 105]> : tensor<4xi32>
// CHECK: return %[[CST]]
}
// CHECK-LABEL: @add_dense_dense_int_same_shape
func.func @add_dense_dense_int_same_shape() -> tensor<4xi32> {
%0 = arith.constant dense<[15, 23, -44, -2]> : tensor<4xi32>
%1 = arith.constant dense<[-10, -1, 42, 100]> : tensor<4xi32>
%2 = "tfl.add"(%0, %1) {fused_activation_function = "NONE"} : (tensor<4xi32>, tensor<4xi32>) -> tensor<4xi32>
func.return %2 : tensor<4xi32>
// CHECK: %[[CST:.*]] = arith.constant dense<[5, 22, -2, 98]> : tensor<4xi32>
// CHECK: return %[[CST]]
}
// CHECK-LABEL: @add_dense_dense_int_trailing_dim
func.func @add_dense_dense_int_trailing_dim() -> (tensor<2x2xi32>, tensor<2x2x2xi32>, tensor<2x2x2xi32>) {
%cst_0 = arith.constant dense<[10, 20]> : tensor<2xi32>
%cst_1 = arith.constant dense<[[1, 2], [3, 4]]> : tensor<2x2xi32>
%cst_2 = arith.constant dense<[[[1, 1], [2, 2]], [[3, 3], [4, 4]]]> : tensor<2x2x2xi32>
%0 = "tfl.add"(%cst_0, %cst_1) {fused_activation_function = "NONE"} : (tensor< 2xi32>, tensor< 2x2xi32>) -> tensor< 2x2xi32>
%1 = "tfl.add"(%cst_2, %cst_1) {fused_activation_function = "NONE"} : (tensor<2x2x2xi32>, tensor< 2x2xi32>) -> tensor<2x2x2xi32>
%2 = "tfl.add"(%cst_0, %cst_2) {fused_activation_function = "NONE"} : (tensor< 2xi32>, tensor<2x2x2xi32>) -> tensor<2x2x2xi32>
func.return %0, %1, %2 : tensor<2x2xi32>, tensor<2x2x2xi32>, tensor<2x2x2xi32>
// CHECK-DAG: %[[CST:.*]] = arith.constant dense<{{\[\[}}11, 22], [13, 24]]> : tensor<2x2xi32>
// CHECK-DAG: %[[CST_0:.*]] = arith.constant dense<{{\[\[\[}}2, 3], [5, 6]], {{\[\[}}4, 5], [7, 8]]]> : tensor<2x2x2xi32>
// CHECK-DAG: %[[CST_1:.*]] = arith.constant dense<{{\[\[\[}}11, 21], [12, 22]], {{\[\[}}13, 23], [14, 24]]]> : tensor<2x2x2xi32>
// CHECK: return %[[CST]], %[[CST_0]], %[[CST_1]]
}
// CHECK-LABEL: @add_dense_dense_int_mixing_1_n
func.func @add_dense_dense_int_mixing_1_n() -> tensor<2x2xi32> {
%cst_0 = arith.constant dense<[[1, 2]]> : tensor<1x2xi32>
%cst_1 = arith.constant dense<[[3], [4]]> : tensor<2x1xi32>
%0 = "tfl.add"(%cst_0, %cst_1) {fused_activation_function = "NONE"} : (tensor<1x2xi32>, tensor<2x1xi32>) -> tensor<2x2xi32>
func.return %0 : tensor<2x2xi32>
// CHECK: %[[CST:.*]] = arith.constant dense<{{\[\[}}4, 5], [5, 6]]> : tensor<2x2xi32>
// CHECK: return %[[CST]]
}
// CHECK-LABEL: @add_dense_splat_float
func.func @add_dense_splat_float() -> tensor<4xf32> {
%0 = arith.constant dense<[-10.0, -1.5, 42.0, 7.25]> : tensor<4xf32>
%1 = arith.constant dense< 3.5> : tensor<4xf32>
%2 = "tfl.add"(%0, %1) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32>
func.return %2 : tensor<4xf32>
// CHECK: %[[CST:.*]] = arith.constant dense<[-6.500000e+00, 2.000000e+00, 4.550000e+01, 1.075000e+01]> : tensor<4xf32>
// CHECK: return %[[CST]]
}
// CHECK-LABEL: @add_splat_dense_float
func.func @add_splat_dense_float() -> tensor<4xf32> {
%0 = arith.constant dense< 3.5> : tensor<4xf32>
%1 = arith.constant dense<[-10.0, -1.5, 42.0, 7.25]> : tensor<4xf32>
%2 = "tfl.add"(%0, %1) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32>
func.return %2 : tensor<4xf32>
// CHECK: %[[CST:.*]] = arith.constant dense<[-6.500000e+00, 2.000000e+00, 4.550000e+01, 1.075000e+01]> : tensor<4xf32>
// CHECK: return %[[CST]]
}
// CHECK-LABEL: @add_dense_dense_float_same_shape
func.func @add_dense_dense_float_same_shape() -> (tensor<4xf32>) {
%0 = arith.constant dense<[1.5, 2.3, -4.4, -2.0]> : tensor<4xf32>
%1 = arith.constant dense<[-10.4, -1.3, 42.4, 100.0]> : tensor<4xf32>
%2 = "tfl.add"(%0, %1) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32>
func.return %2 : tensor<4xf32>
// CHECK: %[[CST:.*]] = arith.constant dense<[-8.89999961, 1.000000e+00, 3.800000e+01, 9.800000e+01]> : tensor<4xf32>
// CHECK: return %[[CST]]
}
// CHECK-LABEL: @add_dense_dense_float_trailing_dim
func.func @add_dense_dense_float_trailing_dim() -> (tensor<2x2xf32>, tensor<2x2x2xf32>, tensor<2x2x2xf32>) {
%cst_0 = arith.constant dense<[1., -4.]> : tensor<2xf32>
%cst_1 = arith.constant dense<[[-5.5, 1.5], [7.5, -4.5]]> : tensor<2x2xf32>
%cst_2 = arith.constant dense<[[[1., 1.], [2., 2.]], [[3., 3.], [4., 4.]]]> : tensor<2x2x2xf32>
%0 = "tfl.add"(%cst_0, %cst_1) {fused_activation_function = "NONE"} : (tensor< 2xf32>, tensor< 2x2xf32>) -> tensor< 2x2xf32>
%1 = "tfl.add"(%cst_2, %cst_1) {fused_activation_function = "NONE"} : (tensor<2x2x2xf32>, tensor< 2x2xf32>) -> tensor<2x2x2xf32>
%2 = "tfl.add"(%cst_0, %cst_2) {fused_activation_function = "NONE"} : (tensor< 2xf32>, tensor<2x2x2xf32>) -> tensor<2x2x2xf32>
func.return %0, %1, %2 : tensor<2x2xf32>, tensor<2x2x2xf32>, tensor<2x2x2xf32>
// CHECK-DAG: %[[CST:.*]] = arith.constant dense<{{\[\[}}-4.500000e+00, -2.500000e+00], [8.500000e+00, -8.500000e+00]]> : tensor<2x2xf32>
// CHECK-DAG: %[[CST_0:.*]] = arith.constant dense<{{\[\[\[}}-4.500000e+00, 2.500000e+00], [9.500000e+00, -2.500000e+00]], {{\[\[}}-2.500000e+00, 4.500000e+00], [1.150000e+01, -5.000000e-01]]]> : tensor<2x2x2xf32>
// CHECK-DAG: %[[CST_1:.*]] = arith.constant dense<{{\[\[\[}}2.000000e+00, -3.000000e+00], [3.000000e+00, -2.000000e+00]], {{\[\[}}4.000000e+00, -1.000000e+00], [5.000000e+00, 0.000000e+00]]]> : tensor<2x2x2xf32>
// CHECK: return %[[CST]], %[[CST_0]], %[[CST_1]]
}
// CHECK-LABEL: @add_dense_dense_float_mixfng_1_n
func.func @add_dense_dense_float_mixfng_1_n() -> tensor<2x2xf32> {
%cst_0 = arith.constant dense<[[1.5, -2.5]]> : tensor<1x2xf32>
%cst_1 = arith.constant dense<[[-3.], [4.]]> : tensor<2x1xf32>
%0 = "tfl.add"(%cst_0, %cst_1) {fused_activation_function = "NONE"} : (tensor<1x2xf32>, tensor<2x1xf32>) -> tensor<2x2xf32>
func.return %0 : tensor<2x2xf32>
// CHECK: %[[CST:.*]] = arith.constant dense<{{\[\[}}-1.500000e+00, -5.500000e+00], [5.500000e+00, 1.500000e+00]]> : tensor<2x2xf32>
// CHECK: return %[[CST]]
}
// CHECK-LABEL: @add_zero
func.func @add_zero(%arg0: tensor<4xi32>, %arg1: tensor<4xf32>) -> (tensor<4xi32>, tensor<4xf32>) {
%zero_int = arith.constant dense<0> : tensor<4xi32>
%zero_float = arith.constant dense<0.0> : tensor<4xf32>
// CHECK-NOT: tfl.add
// CHECK: return %arg0, %arg1
%0 = "tfl.add"(%arg0, %zero_int) {fused_activation_function = "NONE"} : (tensor<4xi32>, tensor<4xi32>) -> tensor<4xi32>
%1 = "tfl.add"(%arg1, %zero_float) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32>
func.return %0, %1 : tensor<4xi32>, tensor<4xf32>
}
// CHECK-LABEL: @add_zero_broadcast
func.func @add_zero_broadcast(%arg0: tensor<4xi32>, %arg1: tensor<4xf32>) -> (tensor<4xi32>, tensor<4xf32>) {
%zero_int = arith.constant dense<0> : tensor<1xi32>
%zero_float = arith.constant dense<0.0> : tensor<1xf32>
// CHECK-NOT: tfl.add
// CHECK: return %arg0, %arg1
%0 = "tfl.add"(%arg0, %zero_int) {fused_activation_function = "NONE"} : (tensor<4xi32>, tensor<1xi32>) -> tensor<4xi32>
%1 = "tfl.add"(%arg1, %zero_float) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<1xf32>) -> tensor<4xf32>
func.return %0, %1 : tensor<4xi32>, tensor<4xf32>
}
// CHECK-LABEL: @add_zero_dynamic
func.func @add_zero_dynamic(%arg0: tensor<?xi32>, %arg1: tensor<?xf32>) -> (tensor<?xi32>, tensor<?xf32>) {
%zero_int = arith.constant dense<0> : tensor<1xi32>
%zero_float = arith.constant dense<0.0> : tensor<1xf32>
// CHECK-NOT: tfl.add
// CHECK: return %arg0, %arg1
%0 = "tfl.add"(%arg0, %zero_int) {fused_activation_function = "NONE"} : (tensor<?xi32>, tensor<1xi32>) -> tensor<?xi32>
%1 = "tfl.add"(%arg1, %zero_float) {fused_activation_function = "NONE"} : (tensor<?xf32>, tensor<1xf32>) -> tensor<?xf32>
func.return %0, %1 : tensor<?xi32>, tensor<?xf32>
}
// CHECK-LABEL: @add_zero_lhs
func.func @add_zero_lhs(%arg0: tensor<4xi32>, %arg1: tensor<4xf32>) -> (tensor<4xi32>, tensor<4xf32>) {
%zero_int = arith.constant dense<0> : tensor<4xi32>
%zero_float = arith.constant dense<0.0> : tensor<4xf32>
// CHECK-NOT: tfl.add
// CHECK: return %arg0, %arg1
%0 = "tfl.add"(%zero_int, %arg0) {fused_activation_function = "NONE"} : (tensor<4xi32>, tensor<4xi32>) -> tensor<4xi32>
%1 = "tfl.add"(%zero_float, %arg1) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32>
func.return %0, %1 : tensor<4xi32>, tensor<4xf32>
}
// CHECK-LABEL: @add_zero_quant
func.func @add_zero_quant(%arg0: tensor<32x!quant.uniform<u8:f32, 1.0>>) -> tensor<32x!quant.uniform<u8:f32, 1.0>> {
%zero = "tfl.pseudo_qconst"() {qtype = tensor<32x!quant.uniform<u8:f32, 1.0>>, value = dense<0> : tensor<32xi8>} : () -> tensor<32x!quant.uniform<u8:f32, 1.0>>
// CHECK: %[[ADD:.*]] = tfl.add
// CHECK: return %[[ADD]]
%0 = "tfl.add"(%zero, %arg0) {fused_activation_function = "NONE"} : (tensor<32x!quant.uniform<u8:f32, 1.0>>, tensor<32x!quant.uniform<u8:f32, 1.0>>) -> tensor<32x!quant.uniform<u8:f32, 1.0>>
func.return %0 : tensor<32x!quant.uniform<u8:f32, 1.0>>
}
// CHECK-LABEL: @reshape
func.func @reshape() -> tensor<4xi32> {
%input = arith.constant dense<[[1, 2], [3, 4]]> : tensor<2x2xi32>
%shape = arith.constant dense<[4]> : tensor<1xi32>
// CHECK: %[[CST:.*]] = arith.constant dense<[1, 2, 3, 4]> : tensor<4xi32>
// CHECK: return %[[CST]]
%0 = "tfl.reshape"(%input, %shape) : (tensor<2x2xi32>, tensor<1xi32>) -> tensor<4xi32>
func.return %0 : tensor<4xi32>
}
// CHECK-LABEL: @transpose_no_fold
func.func @transpose_no_fold(%arg0 : tensor<2xi32>) -> tensor<2x2xi32> {
%cst = arith.constant dense<[[0, 1], [2, 3]]> : tensor<2x2xi32>
// CHECK: tfl.transpose
%0 = "tfl.transpose"(%cst, %arg0) : (tensor<2x2xi32>, tensor<2xi32>) -> tensor<2x2xi32>
func.return %0 : tensor<2x2xi32>
}
// CHECK-LABEL: @transpose_1d
// Basic 1D identity
func.func @transpose_1d() -> tensor<3xi32> {
%cst = arith.constant dense<[1, 2, 3]> : tensor<3xi32>
%cst_perm = arith.constant dense<0> : tensor<1xi32>
// CHECK: %[[CST:.*]] = arith.constant dense<{{\[}}1, 2, 3]> : tensor<3xi32>
// CHECK: return %[[CST]]
%0 = "tfl.transpose"(%cst, %cst_perm) : (tensor<3xi32>, tensor<1xi32>) -> tensor<3xi32>
func.return %0 : tensor<3xi32>
}
// CHECK-LABEL: @transpose_2d
func.func @transpose_2d() -> tensor<2x2xi32> {
%cst = arith.constant dense<[[0, 1], [2, 3]]> : tensor<2x2xi32>
%cst_perm = arith.constant dense<[1, 0]> : tensor<2xi32>
// CHECK: %[[CST:.*]] = arith.constant dense<{{\[\[}}0, 2], {{\[}}1, 3]]> : tensor<2x2xi32>
// CHECK: return %[[CST]]
%0 = "tfl.transpose"(%cst, %cst_perm) : (tensor<2x2xi32>, tensor<2xi32>) -> tensor<2x2xi32>
func.return %0 : tensor<2x2xi32>
}
// CHECK-LABEL: @transpose_2d_splat
func.func @transpose_2d_splat() -> tensor<3x2xi32> {
%cst = arith.constant dense<0> : tensor<2x3xi32>
%cst_perm = arith.constant dense<[1, 0]> : tensor<2xi32>
// CHECK: %[[CST:.*]] = arith.constant dense<0> : tensor<3x2xi32>
// CHECK: return %[[CST]]
%0 = "tfl.transpose"(%cst, %cst_perm) : (tensor<2x3xi32>, tensor<2xi32>) -> tensor<3x2xi32>
func.return %0 : tensor<3x2xi32>
}
// CHECK-LABEL: @transpose_2d_identity
func.func @transpose_2d_identity() -> tensor<2x2xi32> {
%cst = arith.constant dense<[[0, 1], [2, 3]]> : tensor<2x2xi32>
%cst_perm = arith.constant dense<[0, 1]> : tensor<2xi32>
// CHECK: %[[CST:.*]] = arith.constant dense<{{\[\[}}0, 1], {{\[}}2, 3]]> : tensor<2x2xi32>
// CHECK: return %[[CST]]
%0 = "tfl.transpose"(%cst, %cst_perm) : (tensor<2x2xi32>, tensor<2xi32>) -> tensor<2x2xi32>
func.return %0 : tensor<2x2xi32>
}
// CHECK-LABEL: @transpose_3d
// A test case adopted from TransposeTest.Test3DInputConstTensor in
// tensorflow/lite/kernels/transpose_test.cc
func.func @transpose_3d() -> tensor<4x2x3xi32> {
%cst = arith.constant dense<[[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]], [[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]]]> : tensor<2x3x4xi32>
%cst_perm = arith.constant dense<[2, 0, 1]> : tensor<3xi32>
// CHECK: %[[CST:.*]] = arith.constant dense<{{\[\[\[}}0, 4, 8], {{\[}}12, 16, 20]], {{\[\[}}1, 5, 9], {{\[}}13, 17, 21]], {{\[\[}}2, 6, 10], {{\[}}14, 18, 22]], {{\[\[}}3, 7, 11], {{\[}}15, 19, 23]]]> : tensor<4x2x3xi32>
// CHECK: return %[[CST]]
%0 = "tfl.transpose"(%cst, %cst_perm) : (tensor<2x3x4xi32>, tensor<3xi32>) -> tensor<4x2x3xi32>
func.return %0 : tensor<4x2x3xi32>
}
// CHECK-LABEL: @ConstantFoldBinaryOpDynamicOutput
func.func @ConstantFoldBinaryOpDynamicOutput() -> tensor<?xi32> {
%cst = arith.constant dense<10> : tensor<i32>
%cst_0 = "tfl.pseudo_const"() {value = dense<[5, 10]> : tensor<2xi32>} : () -> tensor<?xi32>
%87 = "tfl.sub"(%cst_0, %cst) {fused_activation_function = "NONE"} : (tensor<?xi32>, tensor<i32>) -> tensor<?xi32>
func.return %87 : tensor<?xi32>
// CHECK: %[[CST:.*]] = "tfl.pseudo_const"() <{value = dense<[-5, 0]> : tensor<2xi32>}> : () -> tensor<?xi32>
// CHECK: return %[[CST]]
}
// CHECK-LABEL: @div_dense_dense_float_mixfng_1_n
func.func @div_dense_dense_float_mixfng_1_n() -> tensor<2x2xf32> {
%cst_0 = arith.constant dense<[[1.5, -2.5]]> : tensor<1x2xf32>
%cst_1 = arith.constant dense<[[-3.], [4.]]> : tensor<2x1xf32>
%0 = "tfl.div"(%cst_0, %cst_1) {fused_activation_function = "NONE"} : (tensor<1x2xf32>, tensor<2x1xf32>) -> tensor<2x2xf32>
func.return %0 : tensor<2x2xf32>
// CHECK: %[[CST:.*]] = arith.constant dense<{{\[\[}}-5.000000e-01, 0.833333313], [3.750000e-01, -6.250000e-01]]> : tensor<2x2xf32>
// CHECK: return %[[CST]]
}
// CHECK-LABEL: @div_dense_different_rank
func.func @div_dense_different_rank() -> tensor<1x2x2xf32> {
%cst_0 = arith.constant dense<[[[1.0],[2.0]]]> : tensor<1x2x1xf32>
%cst_1 = arith.constant dense<[[2.0, 3.0]]> : tensor<1x2xf32>
%0 = "tfl.div"(%cst_0, %cst_1) {fused_activation_function = "NONE"} : (tensor<1x2x1xf32>, tensor<1x2xf32>) -> tensor<1x2x2xf32>
func.return %0 : tensor<1x2x2xf32>
// CHECK: %[[CST:.*]] = arith.constant dense<[{{\[}}{{\[}}5.000000e-01, 0.333333343], [1.000000e+00, 0.666666686]]]> : tensor<1x2x2xf32>
// CHECK: return %[[CST]]
}
// CHECK-LABEL: @div_one
func.func @div_one(%arg0: tensor<4xi32>, %arg1: tensor<4xf32>) -> (tensor<4xi32>, tensor<4xf32>) {
%one_int = arith.constant dense<1> : tensor<4xi32>
%one_float = arith.constant dense<1.0> : tensor<4xf32>
// CHECK-NOT: tfl.div
// CHECK: return %arg0, %arg1
%0 = "tfl.div"(%arg0, %one_int) {fused_activation_function = "NONE"} : (tensor<4xi32>, tensor<4xi32>) -> tensor<4xi32>
%1 = "tfl.div"(%arg1, %one_float) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32>
func.return %0, %1 : tensor<4xi32>, tensor<4xf32>
}
// CHECK-LABEL: @div_one_quant
func.func @div_one_quant(%arg0: tensor<32x!quant.uniform<u8:f32, 1.0>>) -> tensor<32x!quant.uniform<u8:f32, 1.0>> {
%one = "tfl.pseudo_qconst"() {qtype = tensor<32x!quant.uniform<u8:f32, 1.0>>, value = dense<1> : tensor<32xi8>} : () -> tensor<32x!quant.uniform<u8:f32, 1.0>>
// CHECK: %[[DIV:.*]] = tfl.div
// CHECK: return %[[DIV]]
%0 = "tfl.div"(%arg0, %one) {fused_activation_function = "NONE"} : (tensor<32x!quant.uniform<u8:f32, 1.0>>, tensor<32x!quant.uniform<u8:f32, 1.0>>) -> tensor<32x!quant.uniform<u8:f32, 1.0>>
func.return %0 : tensor<32x!quant.uniform<u8:f32, 1.0>>
}
@@ -0,0 +1,136 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: litert-opt %s -canonicalize | FILECHECK_OPTS="" FileCheck %s
// RUN: litert-opt %s --tfl-dense-to-dense-resource-elements -canonicalize | litert-opt --tfl-dense-resource-to-dense-elements | FILECHECK_OPTS="" FileCheck %s
// CHECK-LABEL: @test_logical_not_i1
func.func @test_logical_not_i1() -> tensor<4xi1> {
// CHECK: arith.constant dense<[false, true, false, true]> : tensor<4xi1>
%0 = arith.constant dense<[true, false, true, false]> : tensor<4xi1>
%1 = "tfl.logical_not"(%0) : (tensor<4xi1>) -> tensor<4xi1>
func.return %1 : tensor<4xi1>
}
// CHECK-LABEL: @test_relu_i32
func.func @test_relu_i32() -> tensor<4xi32> {
// CHECK: arith.constant dense<[0, 2, 0, 4]> : tensor<4xi32>
%0 = arith.constant dense<[-1, 2, -3, 4]> : tensor<4xi32>
%1 = "tfl.relu"(%0) : (tensor<4xi32>) -> tensor<4xi32>
func.return %1 : tensor<4xi32>
}
// CHECK-LABEL: @test_relu_f32
func.func @test_relu_f32() -> tensor<4xf32> {
// CHECK: arith.constant dense<[0.000000e+00, 2.000000e+00, 0.000000e+00, 4.000000e+00]> : tensor<4xf32>
%0 = arith.constant dense<[-1.0, 2.0, -3.0, 4.0]> : tensor<4xf32>
%1 = "tfl.relu"(%0) : (tensor<4xf32>) -> tensor<4xf32>
func.return %1 : tensor<4xf32>
}
// CHECK-LABEL: @test_abs_f32
func.func @test_abs_f32() -> tensor<4xf32> {
// CHECK: arith.constant dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00]> : tensor<4xf32>
%0 = arith.constant dense<[-1.0, 2.0, -3.0, 4.0]> : tensor<4xf32>
%1 = "tfl.abs"(%0) : (tensor<4xf32>) -> tensor<4xf32>
func.return %1 : tensor<4xf32>
}
// CHECK-LABEL: @test_ceil_f32
func.func @test_ceil_f32() -> tensor<4xf32> {
// CHECK: arith.constant dense<[-1.000000e+00, 2.000000e+00, -3.000000e+00, 4.000000e+00]> : tensor<4xf32>
%0 = arith.constant dense<[-1.5, 1.5, -3.5, 3.5]> : tensor<4xf32>
%1 = "tfl.ceil"(%0) : (tensor<4xf32>) -> tensor<4xf32>
func.return %1 : tensor<4xf32>
}
// CHECK-LABEL: @test_floor_f32
func.func @test_floor_f32() -> tensor<4xf32> {
// CHECK: arith.constant dense<[-2.000000e+00, 1.000000e+00, -4.000000e+00, 3.000000e+00]> : tensor<4xf32>
%0 = arith.constant dense<[-1.5, 1.5, -3.5, 3.5]> : tensor<4xf32>
%1 = "tfl.floor"(%0) : (tensor<4xf32>) -> tensor<4xf32>
func.return %1 : tensor<4xf32>
}
// CHECK-LABEL: @test_neg_f32
func.func @test_neg_f32() -> tensor<4xf32> {
// CHECK: arith.constant dense<[1.000000e+00, -2.000000e+00, 3.000000e+00, -4.000000e+00]> : tensor<4xf32>
%0 = arith.constant dense<[-1.0, 2.0, -3.0, 4.0]> : tensor<4xf32>
%1 = "tfl.neg"(%0) : (tensor<4xf32>) -> tensor<4xf32>
func.return %1 : tensor<4xf32>
}
// CHECK-LABEL: @test_sin_f32
func.func @test_sin_f32() -> tensor<1xf32> {
// CHECK: arith.constant dense<0.000000e+00> : tensor<1xf32>
%0 = arith.constant dense<[0.0]> : tensor<1xf32>
%1 = "tfl.sin"(%0) : (tensor<1xf32>) -> tensor<1xf32>
func.return %1 : tensor<1xf32>
}
// CHECK-LABEL: @test_cos_f32
func.func @test_cos_f32() -> tensor<1xf32> {
// CHECK: arith.constant dense<1.000000e+00> : tensor<1xf32>
%0 = arith.constant dense<[0.0]> : tensor<1xf32>
%1 = "tfl.cos"(%0) : (tensor<1xf32>) -> tensor<1xf32>
func.return %1 : tensor<1xf32>
}
// CHECK-LABEL: @test_log_f32
func.func @test_log_f32() -> tensor<1xf32> {
// CHECK: arith.constant dense<0.000000e+00> : tensor<1xf32>
%0 = arith.constant dense<[1.0]> : tensor<1xf32>
%1 = "tfl.log"(%0) : (tensor<1xf32>) -> tensor<1xf32>
func.return %1 : tensor<1xf32>
}
// CHECK-LABEL: @test_sqrt_f32
func.func @test_sqrt_f32() -> tensor<1xf32> {
// CHECK: arith.constant dense<2.000000e+00> : tensor<1xf32>
%0 = arith.constant dense<[4.0]> : tensor<1xf32>
%1 = "tfl.sqrt"(%0) : (tensor<1xf32>) -> tensor<1xf32>
func.return %1 : tensor<1xf32>
}
// CHECK-LABEL: @test_rsqrt_f32
func.func @test_rsqrt_f32() -> tensor<1xf32> {
// CHECK: arith.constant dense<5.000000e-01> : tensor<1xf32>
%0 = arith.constant dense<[4.0]> : tensor<1xf32>
%1 = "tfl.rsqrt"(%0) : (tensor<1xf32>) -> tensor<1xf32>
func.return %1 : tensor<1xf32>
}
// CHECK-LABEL: @test_square_f32
func.func @test_square_f32() -> tensor<1xf32> {
// CHECK: arith.constant dense<1.600000e+01> : tensor<1xf32>
%0 = arith.constant dense<[4.0]> : tensor<1xf32>
%1 = "tfl.square"(%0) : (tensor<1xf32>) -> tensor<1xf32>
func.return %1 : tensor<1xf32>
}
// CHECK-LABEL: @test_tanh_f32
func.func @test_tanh_f32() -> tensor<1xf32> {
// CHECK: arith.constant dense<0.000000e+00> : tensor<1xf32>
%0 = arith.constant dense<[0.0]> : tensor<1xf32>
%1 = "tfl.tanh"(%0) : (tensor<1xf32>) -> tensor<1xf32>
func.return %1 : tensor<1xf32>
}
// CHECK-LABEL: @test_exp_f32
func.func @test_exp_f32() -> tensor<1xf32> {
// CHECK: arith.constant dense<1.000000e+00> : tensor<1xf32>
%0 = arith.constant dense<[0.0]> : tensor<1xf32>
%1 = "tfl.exp"(%0) : (tensor<1xf32>) -> tensor<1xf32>
func.return %1 : tensor<1xf32>
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,79 @@
load("@xla//third_party/rules_python/python:py_binary.bzl", "py_binary")
load("//tensorflow:tensorflow.bzl", "if_oss")
load("//tensorflow:tensorflow.default.bzl", "filegroup")
load("//tensorflow/compiler/mlir:glob_lit_test.bzl", "glob_lit_tests")
# copybara:uncomment package(default_applicable_licenses = ["//tensorflow:LICENSE"])
licenses(["notice"])
glob_lit_tests(
name = "all_tests",
data = [
":debug_info_files",
":test_utilities",
],
driver = "@llvm-project//mlir:run_lit.sh",
test_file_exts = [
"pbtxt",
# "py", TODO(b/150304798)
],
)
# Bundle together all the debug info files that are used by the tests.
filegroup(
name = "debug_info_files",
srcs = glob(
["**/*.debug"],
),
)
# Bundle together all of the test utilities that are used by tests.
filegroup(
name = "test_utilities",
testonly = True,
data = [
":concrete_function_error",
":saved_model_error",
"//tensorflow/compiler/mlir/lite:flatbuffer_to_string",
"//tensorflow/compiler/mlir/lite:tf_tfl_translate",
"@llvm-project//llvm:FileCheck",
"@llvm-project//llvm:not",
],
)
py_binary(
name = "saved_model_error",
srcs = ["saved_model_error.py"],
exec_properties = if_oss(
None,
select({
"@bazel_tools//tools/cpp:asan_build": {"cpp_link.mem": "20g"},
"//conditions:default": None,
}),
),
main = "saved_model_error.py",
strict_deps = True,
deps = [
"//tensorflow:tensorflow_py",
"@absl_py//absl:app",
],
)
py_binary(
name = "concrete_function_error",
srcs = ["concrete_function_error.py"],
exec_properties = if_oss(
None,
select({
"@bazel_tools//tools/cpp:asan_build": {"cpp_link.mem": "20g"},
"//conditions:default": None,
}),
),
main = "concrete_function_error.py",
strict_deps = True,
deps = [
"//tensorflow:tensorflow_py",
"@absl_py//absl:app",
],
)
@@ -0,0 +1,72 @@
# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Test file to display the error message and verify it with FileCheck."""
# RUN: %p/concrete_function_error | FileCheck %s
import sys
from absl import app
import tensorflow.compat.v2 as tf
if hasattr(tf, 'enable_v2_behavior'):
tf.enable_v2_behavior()
class TestGraphDebugInfo(object):
"""Test stack trace can be displayed."""
def testConcreteFunctionDebugInfo(self):
"""Create a concrete func with unsupported ops, and convert it."""
@tf.function(
input_signature=[tf.TensorSpec(shape=[3, 3], dtype=tf.float32)])
def model(x):
y = tf.math.betainc(x, 0.5, 1.0) # Not supported
return y + y
func = model.get_concrete_function()
converter = tf.lite.TFLiteConverter.from_concrete_functions([func], model)
converter.convert()
# pylint: disable=line-too-long
# CHECK-LABEL: testConcreteFunctionDebugInfo
# CHECK: error: 'tf.Betainc' op is neither a custom op nor a flex op
# CHECK: attrs=attr_protos, op_def=op_def)
# CHECK: ^
# CHECK: {{.*tensorflow/python/ops/gen_math_ops.py:[0-9]+:[0-9]+: note: called from}}
# CHECK: "Betainc", a=a, b=b, x=x, name=name)
# CHECK: ^
# CHECK: {{.*tensorflow/compiler/mlir/lite/tests/debuginfo/concrete_function_error.py:[0-9]+:[0-9]+: note: called from}}
# CHECK: y = tf.math.betainc(x, 0.5, 1.0) # Not supported
# CHECK: ^
# CHECK: <unknown>:0: error: failed while converting: 'main'
# pylint: enable=line-too-long
def main(argv):
if len(argv) > 1:
raise app.UsageError('Too many command-line arguments.')
try:
TestGraphDebugInfo().testConcreteFunctionDebugInfo()
except Exception as e: # pylint: disable=broad-except
sys.stdout.write('testConcreteFunctionDebugInfo')
sys.stdout.write(str(e))
if __name__ == '__main__':
app.run(main)
@@ -0,0 +1,82 @@
# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Test file to display the error message and verify it with FileCheck."""
# RUN: %p/saved_model_error | FileCheck %s
import sys
from absl import app
import tensorflow.compat.v2 as tf
if hasattr(tf, 'enable_v2_behavior'):
tf.enable_v2_behavior()
class TestModule(tf.Module):
"""The test model has unsupported op."""
@tf.function(input_signature=[tf.TensorSpec(shape=[3, 3], dtype=tf.float32)])
def model(self, x):
y = tf.math.betainc(x, 0.5, 1.0) # Not supported
return y + y
class TestGraphDebugInfo(object):
"""Test stack trace can be displayed."""
def testSavedModelDebugInfo(self):
"""Save a saved model with unsupported ops, and then load and convert it."""
# saved the model
test_model = TestModule()
saved_model_path = '/tmp/test.saved_model'
save_options = tf.saved_model.SaveOptions(save_debug_info=True)
tf.saved_model.save(test_model, saved_model_path, options=save_options)
# load the model and convert
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_path)
converter.convert()
# pylint: disable=line-too-long
# CHECK-LABEL: testSavedModelDebugInfo
# CHECK: error: 'tf.Betainc' op is neither a custom op nor a flex op
# CHECK: attrs=attr_protos, op_def=op_def)
# CHECK: ^
# CHECK: {{.*tensorflow/python/ops/gen_math_ops.py:[0-9]+:[0-9]+: note: called from}}
# CHECK: "Betainc", a=a, b=b, x=x, name=name)
# CHECK: ^
# CHECK: {{.*tensorflow/compiler/mlir/lite/tests/debuginfo/saved_model_error.py:[0-9]+:[0-9]+: note: called from}}
# CHECK: y = tf.math.betainc(x, 0.5, 1.0) # Not supported
# CHECK: ^
# CHECK: <unknown>:0: error: failed while converting: 'main'
# pylint: enable=line-too-long
def main(argv):
"""test driver method writes the error message to stdout."""
if len(argv) > 1:
raise app.UsageError('Too many command-line arguments.')
try:
TestGraphDebugInfo().testSavedModelDebugInfo()
except Exception as e: # pylint: disable=broad-except
sys.stdout.write('testSavedModelDebugInfo')
sys.stdout.write(str(e))
if __name__ == '__main__':
app.run(main)
File diff suppressed because one or more lines are too long
@@ -0,0 +1,175 @@
files: "fake/user/code/file_A.py"
files: "fake/user/code/file_B.py"
files: "fake/user/code/file_C.py"
files: "fake/user/code/file_D.py"
files: "fake/user/code/file_E.py"
files: "fake/user/code/file_F.py"
files: "fake/user/code/file_G.py"
files: "fake/user/code/file_H.py"
files: "fake/user/code/file_I.py"
files: "fake/user/code/file_J.py"
files: "fake/user/code/file_K.py"
files: "fake/user/code/file_L.py"
files: "fake/user/code/file_M.py"
files: "fake/user/code/file_N.py"
files: "fake/user/code/file_O.py"
files: "fake/user/code/file_P.py"
files: "fake/user/code/file_Q.py"
files: "fake/user/code/file_R.py"
files: "fake/user/code/file_S.py"
files: "fake/user/code/file_T.py"
files: "fake/user/code/file_U.py"
files: "fake/user/code/file_V.py"
files: "fake/user/code/file_W.py"
files: "fake/user/code/file_X.py"
files: "fake/user/code/file_Y.py"
files: "fake/user/code/file_Z.py"
files: "fake/user/code/file_1.py"
files: "fake/user/code/file_2.py"
files: "fake/user/code/file_3.py"
files: "fake/user/code/file_4.py"
files: "fake/user/code/file_5.py"
files: "fake/user/code/file_6.py"
files: "fake/user/code/file_a.py"
files: "fake/user/code/file_b.py"
files: "fake/user/code/file_c.py"
files: "fake/user/code/file_d.py"
files: "fake/user/code/file_e.py"
files: "fake/user/code/file_f.py"
files: "fake/user/code/file_g.py"
files: "fake/user/code/file_h.py"
files: "fake/user/code/file_i.py"
files: "fake/user/code/file_j.py"
files: "fake/user/code/file_k.py"
files: "fake/user/code/file_l.py"
files: "fake/user/code/file_m.py"
files: "fake/user/code/file_n.py"
files: "fake/user/code/file_o.py"
files: "fake/user/code/file_p.py"
files: "fake/user/code/file_q.py"
files: "fake/user/code/file_r.py"
files: "fake/user/code/file_s.py"
files: "fake/user/code/file_t.py"
files: "fake/user/code/file_u.py"
files: "fake/user/code/file_v.py"
files: "fake/user/code/file_w.py"
files: "fake/user/code/file_x.py"
files: "fake/user/code/file_y.py"
files: "fake/user/code/file_z.py"
traces {
key: "MobilenetV1/Conv2d_0/BatchNorm/beta@"
value {
file_line_cols {
file_index: 33
line: 383
}
}
}
traces {
key: "MobilenetV1/Conv2d_0/BatchNorm/beta/read@"
value {
file_line_cols {
file_index: 49
line: 886
}
}
}
traces {
key: "MobilenetV1/Conv2d_0/BatchNorm/gamma@"
value {
file_line_cols {
file_index: 38
line: 777
}
}
}
traces {
key: "MobilenetV1/Conv2d_0/BatchNorm/gamma/read@"
value {
file_line_cols {
file_index: 49
line: 915
}
}
}
traces {
key: "MobilenetV1/Conv2d_0/BatchNorm/moving_mean@"
value {
file_line_cols {
file_index: 44
line: 793
}
}
}
traces {
key: "MobilenetV1/Conv2d_0/BatchNorm/moving_mean/read@"
value {
file_line_cols {
file_index: 49
line: 335
}
}
}
traces {
key: "MobilenetV1/Conv2d_0/BatchNorm/moving_variance@"
value {
file_line_cols {
file_index: 44
line: 386
}
}
}
traces {
key: "MobilenetV1/Conv2d_0/BatchNorm/moving_variance/read@"
value {
file_line_cols {
file_index: 49
line: 492
}
}
}
traces {
key: "MobilenetV1/Conv2d_0/weights@"
value {
file_line_cols {
file_index: 54
line: 649
}
}
}
traces {
key: "MobilenetV1/Conv2d_0/weights/read@"
value {
file_line_cols {
file_index: 49
line: 421
}
}
}
traces {
key: "MobilenetV1/MobilenetV1/Conv2d_0/BatchNorm/FusedBatchNorm@"
value {
file_line_cols {
file_index: 5
line: 362
}
}
}
traces {
key: "MobilenetV1/MobilenetV1/Conv2d_0/Conv2D@"
value {
file_line_cols {
file_index: 2
line: 27
}
}
}
traces {
key: "input@"
value {
file_line_cols {
file_index: 40
line: 690
}
}
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,187 @@
files: "fake/user/code/file_A.py"
files: "fake/user/code/file_B.py"
files: "fake/user/code/file_C.py"
files: "fake/user/code/file_D.py"
files: "fake/user/code/file_E.py"
files: "fake/user/code/file_F.py"
files: "fake/user/code/file_G.py"
files: "fake/user/code/file_H.py"
files: "fake/user/code/file_I.py"
files: "fake/user/code/file_J.py"
files: "fake/user/code/file_K.py"
files: "fake/user/code/file_L.py"
files: "fake/user/code/file_M.py"
files: "fake/user/code/file_N.py"
files: "fake/user/code/file_O.py"
files: "fake/user/code/file_P.py"
files: "fake/user/code/file_Q.py"
files: "fake/user/code/file_R.py"
files: "fake/user/code/file_S.py"
files: "fake/user/code/file_T.py"
files: "fake/user/code/file_U.py"
files: "fake/user/code/file_V.py"
files: "fake/user/code/file_W.py"
files: "fake/user/code/file_X.py"
files: "fake/user/code/file_Y.py"
files: "fake/user/code/file_Z.py"
files: "fake/user/code/file_1.py"
files: "fake/user/code/file_2.py"
files: "fake/user/code/file_3.py"
files: "fake/user/code/file_4.py"
files: "fake/user/code/file_5.py"
files: "fake/user/code/file_6.py"
files: "fake/user/code/file_a.py"
files: "fake/user/code/file_b.py"
files: "fake/user/code/file_c.py"
files: "fake/user/code/file_d.py"
files: "fake/user/code/file_e.py"
files: "fake/user/code/file_f.py"
files: "fake/user/code/file_g.py"
files: "fake/user/code/file_h.py"
files: "fake/user/code/file_i.py"
files: "fake/user/code/file_j.py"
files: "fake/user/code/file_k.py"
files: "fake/user/code/file_l.py"
files: "fake/user/code/file_m.py"
files: "fake/user/code/file_n.py"
files: "fake/user/code/file_o.py"
files: "fake/user/code/file_p.py"
files: "fake/user/code/file_q.py"
files: "fake/user/code/file_r.py"
files: "fake/user/code/file_s.py"
files: "fake/user/code/file_t.py"
files: "fake/user/code/file_u.py"
files: "fake/user/code/file_v.py"
files: "fake/user/code/file_w.py"
files: "fake/user/code/file_x.py"
files: "fake/user/code/file_y.py"
files: "fake/user/code/file_z.py"
traces {
key: "MobilenetV1/Conv2d_0/BatchNorm/beta@"
value {
file_line_cols {
file_index: 33
line: 383
}
}
}
traces {
key: "MobilenetV1/Conv2d_0/BatchNorm/beta/read@"
value {
file_line_cols {
file_index: 49
line: 886
}
}
}
traces {
key: "MobilenetV1/Conv2d_0/BatchNorm/gamma@"
value {
file_line_cols {
file_index: 38
line: 777
}
}
}
traces {
key: "MobilenetV1/Conv2d_0/BatchNorm/gamma/read@"
value {
file_line_cols {
file_index: 49
line: 915
}
}
}
traces {
key: "MobilenetV1/Conv2d_0/BatchNorm/moving_mean@"
value {
file_line_cols {
file_index: 44
line: 793
}
}
}
traces {
key: "MobilenetV1/Conv2d_0/BatchNorm/moving_mean/read@"
value {
file_line_cols {
file_index: 49
line: 335
}
}
}
traces {
key: "MobilenetV1/Conv2d_0/BatchNorm/moving_variance@"
value {
file_line_cols {
file_index: 44
line: 386
}
}
}
traces {
key: "MobilenetV1/Conv2d_0/BatchNorm/moving_variance/read@"
value {
file_line_cols {
file_index: 49
line: 492
}
}
}
traces {
key: "MobilenetV1/Conv2d_0/weights@"
value {
file_line_cols {
file_index: 54
line: 649
}
}
}
traces {
key: "MobilenetV1/Conv2d_0/weights/read@"
value {
file_line_cols {
file_index: 49
line: 421
}
}
}
traces {
key: "MobilenetV1/MobilenetV1/Conv2d_0/BatchNorm/FusedBatchNorm@"
value {
file_line_cols {
file_index: 5
line: 362
}
}
}
traces {
key: "MobilenetV1/MobilenetV1/Conv2d_0/Conv2D@"
value {
file_line_cols {
file_index: 2
line: 27
}
file_line_cols {
file_index: 3
line: 28
}
file_line_cols {
file_index: 4
line: 29
}
file_line_cols {
file_index: 5
line: 30
}
}
}
traces {
key: "input@"
value {
file_line_cols {
file_index: 40
line: 690
}
}
}
@@ -0,0 +1,153 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: litert-opt --tfl-decompose-hybrid-quantization --verify-each %s | FileCheck %s
// CHECK-LABEL: @test_conv2d_float
func.func @test_conv2d_float(%arg0: tensor<1x32x32x8xf32>) -> tensor<1x32x32x16xf32> {
// CHECK-DAG: %[[VAL0:.+]] = "tfl.pseudo_const"() <{value = dense<42> : tensor<16x1x1x8xi8>}>
// CHECK-DAG: %[[VAL1:.+]] = "tfl.pseudo_const"() <{value = dense<1> : tensor<16x1x1x8xi8>}>
// CHECK-DAG: %[[VAL2:.+]] = "tfl.conv_2d"(%arg0, %[[VAL0]], %[[VAL1]]) <{dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32}>
// CHECK: return %[[VAL2]]
%0 = "tfl.pseudo_const"() {value = dense<42> : tensor<16x1x1x8xi8>} : () -> tensor<16x1x1x8xf32>
%1 = "tfl.pseudo_const"() {value = dense<1> : tensor<16x1x1x8xi8>} : () -> tensor<16xf32>
%2 = "tfl.conv_2d"(%arg0, %0, %1) {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<16x1x1x8xf32>, tensor<16xf32>) -> tensor<1x32x32x16xf32>
func.return %2 : tensor<1x32x32x16xf32>
}
// -----
// CHECK-LABEL: @test_conv2d_qi8
func.func @test_conv2d_qi8(%arg0: tensor<1x32x32x8x!quant.uniform<i8:f32, 1.0>>) -> tensor<1x32x32x16x!quant.uniform<i8:f32, 1.0>> {
// CHECK-DAG: %[[VAL0:.+]] = "tfl.pseudo_qconst"() <{qtype = tensor<{{.+}}>, value = dense<42> : tensor<16x1x1x8xi8>}>
// CHECK-DAG: %[[VAL1:.+]] = "tfl.pseudo_qconst"() <{qtype = tensor<{{.+}}>, value = dense<0> : tensor<16xi32>}>
// CHECK-DAG: %[[VAL2:.+]] = "tfl.conv_2d"(%arg0, %0, %1) <{dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32}>
// CHECK: return %[[VAL2]]
%0 = "tfl.pseudo_qconst"() {qtype = tensor<16x1x1x8x!quant.uniform<i8:f32, 1.0>>, value = dense<42> : tensor<16x1x1x8xi8>} : () -> tensor<16x1x1x8x!quant.uniform<i8:f32, 1.0>>
%1 = "tfl.pseudo_qconst"() {qtype = tensor<16x!quant.uniform<i32:f32, 1.0>>, value = dense<0> : tensor<16xi32>} : () -> tensor<16x!quant.uniform<i32:f32, 1.0>>
%2 = "tfl.conv_2d"(%arg0, %0, %1) {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<1x32x32x8x!quant.uniform<i8:f32, 1.0>>, tensor<16x1x1x8x!quant.uniform<i8:f32, 1.0>>, tensor<16x!quant.uniform<i32:f32, 1.0>>) -> tensor<1x32x32x16x!quant.uniform<i8:f32, 1.0>>
func.return %2 : tensor<1x32x32x16x!quant.uniform<i8:f32, 1.0>>
}
// -----
// CHECK-LABEL: @test_conv2d_qi16
func.func @test_conv2d_qi16(%arg0: tensor<1x32x32x8x!quant.uniform<i16:f32, 1.0>>) -> tensor<1x32x32x16x!quant.uniform<i16:f32, 1.0>> {
// CHECK-DAG: %[[BIAS:.+]] = arith.constant dense<0> : tensor<16xi64>
// CHECK-DAG: %[[VAL0:.+]] = "tfl.pseudo_qconst"() <{qtype = tensor<{{.+}}>, value = dense<42> : tensor<16x1x1x8xi8>}>
// CHECK-DAG: %[[VAL1:.+]] = "tfl.conv_2d"(%arg0, %[[VAL0]], %[[BIAS]]) <{dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32}>
// CHECK: return %[[VAL1]]
%0 = "tfl.pseudo_qconst"() {qtype = tensor<16x1x1x8x!quant.uniform<i8:f32, 1.0>>, value = dense<42> : tensor<16x1x1x8xi8>} : () -> tensor<16x1x1x8x!quant.uniform<i8:f32, 1.0>>
%1 = "arith.constant"() {value = dense<0> : tensor<16xi64>} : () -> tensor<16xi64>
%2 = "tfl.conv_2d"(%arg0, %0, %1) {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<1x32x32x8x!quant.uniform<i16:f32, 1.0>>, tensor<16x1x1x8x!quant.uniform<i8:f32, 1.0>>, tensor<16xi64>) -> tensor<1x32x32x16x!quant.uniform<i16:f32, 1.0>>
func.return %2 : tensor<1x32x32x16x!quant.uniform<i16:f32, 1.0>>
}
// -----
// CHECK-LABEL: @test_conv2d_replace_qi8
func.func @test_conv2d_replace_qi8(%arg0: tensor<1x32x32x8xf32>) -> tensor<1x32x32x16x!quant.uniform<i8:f32, 1.0>> {
// CHECK-DAG: %[[VAL0:.+]] = "tfl.pseudo_qconst"() <{qtype = tensor<{{.+}}>, value = dense<42> : tensor<16x1x1x8xi8>}>
// CHECK-DAG: %[[VAL1:.+]] = "tfl.pseudo_qconst"() <{qtype = tensor<{{.+}}>, value = dense<0> : tensor<16xi32>}>
// CHECK-DAG: %[[VAL2:.+]] = "tfl.dequantize"(%[[VAL0]])
// CHECK-DAG: %[[VAL3:.+]] = "tfl.dequantize"(%[[VAL1]])
// CHECK-DAG: %[[VAL4:.+]] = "tfl.conv_2d"(%arg0, %[[VAL2]], %[[VAL3]]) <{dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32}>
// CHECK-DAG: %[[VAL5:.+]] = "tfl.quantize"(%4) <{qtype = tensor<1x32x32x16x!quant.uniform<i8:f32, 1.000000e+00>>}>
// CHECK: return %[[VAL5]]
%0 = "tfl.pseudo_qconst"() {qtype = tensor<16x1x1x8x!quant.uniform<i8:f32, 1.0>>, value = dense<42> : tensor<16x1x1x8xi8>} : () -> tensor<16x1x1x8x!quant.uniform<i8:f32, 1.0>>
%1 = "tfl.pseudo_qconst"() {qtype = tensor<16x!quant.uniform<i32:f32, 1.0>>, value = dense<0> : tensor<16xi32>} : () -> tensor<16x!quant.uniform<i32:f32, 1.0>>
%2 = "tfl.conv_2d"(%arg0, %0, %1) {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<16x1x1x8x!quant.uniform<i8:f32, 1.0>>, tensor<16x!quant.uniform<i32:f32, 1.0>>) -> tensor<1x32x32x16x!quant.uniform<i8:f32, 1.0>>
func.return %2 : tensor<1x32x32x16x!quant.uniform<i8:f32, 1.0>>
}
// -----
// CHECK-LABEL: @test_conv2d_replace_float
func.func @test_conv2d_replace_float(%arg0: tensor<1x32x32x8xf32>) -> tensor<1x32x32x16xf32> {
// CHECK-DAG: %[[VAL0:.+]] = "tfl.pseudo_qconst"() <{qtype = tensor<16x1x1x8x{{.+}}>, value = dense<42> : tensor<16x1x1x8xi8>}> : () -> tensor<16x1x1x8x!quant.uniform<{{.+}}>>
// CHECK-DAG: %[[VAL1:.+]] = "tfl.pseudo_qconst"() <{qtype = tensor<16x{{.+}}>, value = dense<0> : tensor<16xi32>}> : () -> tensor<16x!quant.uniform<{{.+}}>>
// CHECK-DAG: %[[VAL2:.+]] = "tfl.dequantize"(%[[VAL0]])
// CHECK-DAG: %[[VAL3:.+]] = "tfl.dequantize"(%[[VAL1]])
// CHECK-DAG: %[[VAL4:.+]] = "tfl.conv_2d"(%arg0, %[[VAL2]], %[[VAL3]]) <{dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32}>
// CHECK: return %[[VAL4]]
%0 = "tfl.pseudo_qconst"() {qtype = tensor<16x1x1x8x!quant.uniform<i8:f32, 1.0>>, value = dense<42> : tensor<16x1x1x8xi8>} : () -> tensor<16x1x1x8x!quant.uniform<i8:f32, 1.0>>
%1 = "tfl.pseudo_qconst"() {qtype = tensor<16x!quant.uniform<i32:f32, 1.0>>, value = dense<0> : tensor<16xi32>} : () -> tensor<16x!quant.uniform<i32:f32, 1.0>>
%2 = "tfl.conv_2d"(%arg0, %0, %1) {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<16x1x1x8x!quant.uniform<i8:f32, 1.0>>, tensor<16x!quant.uniform<i32:f32, 1.0>>) -> tensor<1x32x32x16xf32>
func.return %2 : tensor<1x32x32x16xf32>
}
// -----
// CHECK-LABEL: @test_conv3d_float
func.func @test_conv3d_float(%arg0: tensor<1x32x32x32x8xf32>) -> tensor<1x32x32x32x16xf32> {
// CHECK-DAG: %[[VAL0:.+]] = "tfl.pseudo_const"() <{value = dense<1.000000e+00> : tensor<16xf32>
// CHECK-DAG: %[[VAL1:.+]] = "tfl.pseudo_qconst"() <{qtype = tensor<1x1x8x16x!quant.uniform<{{.+}}>>, value = dense<42> : tensor<1x1x1x8x16xi8>}>
// CHECK: %[[VAL2:.+]] = "tfl.dequantize"(%[[VAL1]]) : (tensor<1x1x1x8x16x!quant.uniform<{{.+}}>>) -> tensor<1x1x1x8x16xf32>
// CHECK: %[[VAL3:.+]] = "tfl.conv_3d"(%arg0, %[[VAL2]], %[[VAL0]]) <{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 = 1 : i32}>
// CHECK: return %[[VAL3]]
%0 = "tfl.pseudo_qconst"() {qtype = tensor<1x1x8x16x!quant.uniform<i8:f32, 1.0>>, value = dense<42> : tensor<1x1x1x8x16xi8>} : () -> tensor<1x1x1x8x16x!quant.uniform<i8:f32, 1.0>>
%1 = "tfl.pseudo_const"() { value = dense<1.0> : tensor<16xf32>} : () -> tensor<16xf32>
%2 = "tfl.conv_3d"(%arg0, %0, %1) {dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, dilation_d_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32, stride_d = 1 : i32} : (tensor<1x32x32x32x8xf32>, tensor<1x1x1x8x16x!quant.uniform<i8:f32, 1.0>>, tensor<16xf32>) -> tensor<1x32x32x32x16xf32>
func.return %2 : tensor<1x32x32x32x16xf32>
}
// -----
// CHECK-LABEL: @test_transpose_conv2d
func.func @test_transpose_conv2d(%arg0: tensor<1x32x32x8xf32>) -> tensor<1x32x32x16xf32> {
// CHECK-DAG: %[[SHAPE:.+]] = "tfl.pseudo_const"() <{value = dense<[1, 32, 32, 16]>
// CHECK-DAG: %[[VAL0:.+]] = "tfl.pseudo_qconst"() <{qtype = tensor<16x{{.+}}>, value = dense<1> : tensor<16xi32>}>
// CHECK-DAG: %[[VAL1:.+]] = "tfl.pseudo_qconst"() <{qtype = tensor<16x{{.+}}>, value = dense<2> : tensor<16xi32>}>
// CHECK-DAG: %[[VAL2:.+]] = "tfl.dequantize"(%[[VAL0]])
// CHECK-DAG: %[[VAL3:.+]] = "tfl.dequantize"(%[[VAL1]])
// CHECK-DAG: %[[VAL4:.+]] = "tfl.transpose_conv"(%[[SHAPE]], %[[VAL2]], %arg0, %[[VAL3]]) <{fused_activation_function = "NONE", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32}>
// CHECK: return %[[VAL4]]
%0 = "tfl.pseudo_const"() { value = dense<[1, 32, 32, 16]> : tensor<4xi32> } : () -> tensor<4xi32>
%1 = "tfl.pseudo_qconst"() {qtype = tensor<16x!quant.uniform<i32:f32, 1.0>>, value = dense<1> : tensor<16xi32>} : () -> tensor<16x1x1x8x!quant.uniform<i32:f32, 1.0>>
%2 = "tfl.pseudo_qconst"() {qtype = tensor<16x!quant.uniform<i32:f32, 1.0>>, value = dense<2> : tensor<16xi32>} : () -> tensor<16x!quant.uniform<i32:f32, 1.0>>
%3 = "tfl.transpose_conv"(%0, %1, %arg0, %2) {fused_activation_function = "NONE", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32} : (tensor<4xi32>, tensor<16x1x1x8x!quant.uniform<i32:f32, 1.0>>, tensor<1x32x32x8xf32>, tensor<16x!quant.uniform<i32:f32, 1.0>>) -> tensor<1x32x32x16xf32>
func.return %3 : tensor<1x32x32x16xf32>
}
// -----
// CHECK-LABEL: @test_depthwise_conv2d_replace_float
func.func @test_depthwise_conv2d_replace_float(%arg0: tensor<1x224x224x3xf32>) -> tensor<1x112x112x32xf32> {
// CHECK-DAG: %[[VAL0:.+]] = "tfl.pseudo_qconst"() <{qtype = tensor<32x3x3x3x!quant.uniform<{{.+}}>>, value = dense<42> : tensor<32x3x3x3xi8>}>
// CHECK-DAG: %[[VAL1:.+]] = "tfl.pseudo_qconst"() <{qtype = tensor<32x!quant.uniform<{{.+}}>>, value = dense<0> : tensor<32xi32>}>
// CHECK-DAG: %[[VAL2:.+]] = "tfl.dequantize"(%[[VAL0]]) : (tensor<32x3x3x3x!quant.uniform<{{.+}}>>)
// CHECK-DAG: %[[VAL3:.+]] = "tfl.dequantize"(%[[VAL1]]) : (tensor<32x!quant.uniform<{{.+}})
// CHECK-DAG: %[[VAL4:.+]] = "tfl.depthwise_conv_2d"(%arg0, %[[VAL2]], %[[VAL3]]) <{depth_multiplier = 4 : i32, dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "VALID", stride_h = 4 : i32, stride_w = 5 : i32}>
// CHECK: return %[[VAL4]]
%0 = "tfl.pseudo_qconst"() {qtype = tensor<32x3x3x3x!quant.uniform<i8:f32, 1.0>>, value = dense<42> : tensor<32x3x3x3xi8>} : () -> tensor<32x3x3x3x!quant.uniform<i8:f32, 1.0>>
%1 = "tfl.pseudo_qconst"() {qtype = tensor<32x!quant.uniform<i32:f32, 1.0>>, value = dense<0> : tensor<32xi32>} : () -> tensor<32x!quant.uniform<i32:f32, 1.0>>
%2 = "tfl.depthwise_conv_2d"(%arg0, %0, %1) {depth_multiplier = 4 : i32, dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "VALID", stride_h = 4 : i32, stride_w = 5 : i32} : (tensor<1x224x224x3xf32>, tensor<32x3x3x3x!quant.uniform<i8:f32, 1.0>>, tensor<32x!quant.uniform<i32:f32, 1.0>>) -> tensor<1x112x112x32xf32>
func.return %2 : tensor<1x112x112x32xf32>
}
// -----
// CHECK-LABEL: @test_fullyconnected_replace_float
func.func @test_fullyconnected_replace_float(%arg0: tensor<4x256x6x6xf32>) -> tensor<4x256x36xf32> {
// CHECK-DAG: %[[VAL0:.+]] = "tfl.pseudo_qconst"() <{qtype = tensor<36x36x!quant.uniform<{{.+}}>>, value = dense<42> : tensor<36x36xi8>}>
// CHECK-DAG: %[[VAL1:.+]] = "tfl.pseudo_qconst"() <{qtype = tensor<36x!quant.uniform<{{.+}}>>, value = dense<0> : tensor<36xi32>}>
// CHECK-DAG: %[[VAL2:.+]] = "tfl.dequantize"(%[[VAL0]]) : (tensor<36x36x!quant.uniform<i8:f32, 1.000000e+00>>)
// CHECK-DAG: %[[VAL3:.+]] = "tfl.dequantize"(%[[VAL1]]) : (tensor<36x!quant.uniform<i32:f32, 1.000000e+00>>)
// CHECK: %[[VAL4:.+]] = "tfl.fully_connected"(%arg0, %[[VAL2]], %[[VAL3]]) <{fused_activation_function = "NONE", keep_num_dims = false, weights_format = "DEFAULT"}>
// CHECK: return %[[VAL4]]
%0 = "tfl.pseudo_qconst"() {qtype = tensor<36x36x!quant.uniform<i8:f32, 1.0>>, value = dense<42> : tensor<36x36xi8>} : () -> tensor<36x36x!quant.uniform<i8:f32, 1.0>>
%1 = "tfl.pseudo_qconst"() {qtype = tensor<36x!quant.uniform<i32:f32, 1.0>>, value = dense<0> : tensor<36xi32>} : () -> tensor<36x!quant.uniform<i32:f32, 1.0>>
%2 = "tfl.fully_connected"(%arg0, %0, %1) {fused_activation_function = "NONE", keep_num_dims = false, weights_format = "DEFAULT"} : (tensor<4x256x6x6xf32>, tensor<36x36x!quant.uniform<i8:f32, 1.0>>, tensor<36x!quant.uniform<i32:f32, 1.0>>) -> tensor<4x256x36xf32>
func.return %2 : tensor<4x256x36xf32>
}
@@ -0,0 +1,127 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: litert-opt %s --tfl-default-quant --tfl-quantize | FileCheck %s
// CHECK-LABEL: hardcode_all
func.func @hardcode_all(%arg0: tensor<2x2xf32>, %arg1: tensor<2x1xf32>) -> tensor<2x2xf32> {
%0 = "tfl.add"(%arg0, %arg1) {fused_activation_function="NONE"}: (tensor<2x2xf32>, tensor<2x1xf32>) -> tensor<2x2xf32>
func.return %0 : tensor<2x2xf32>
// CHECK: %[[q0:.*]] = "tfl.quantize"(%arg1) <{qtype = tensor<2x1x!quant.uniform<u8:f32, 0.0078431372549019607:128>>}>
// CHECK: %[[q1:.*]] = "tfl.quantize"(%arg0) <{qtype = tensor<2x2x!quant.uniform<u8:f32, 0.0078431372549019607:128>>}>
// Quantized tfl.add
// CHECK: %[[add:.*]] = tfl.add(%[[q1]], %[[q0]]) <{fused_activation_function = "NONE"}> : (tensor<2x2x!quant.uniform<u8:f32, 0.0078431372549019607:128>>
// CHECK: %[[dq:.*]] = "tfl.dequantize"(%[[add]]) : (tensor<2x2x!quant.uniform<u8:f32, 0.0078431372549019607:128>>)
// CHECK: return %[[dq]]
}
// CHECK-LABEL: hardcode_input
func.func @hardcode_input(%arg0: tensor<2x2xf32>, %arg1: tensor<2x1xf32>) -> tensor<2x2xf32> {
%0 = "tfl.quantize"(%arg0) {qtype = tensor<2x2x!quant.uniform<u8:f32, 1.0:128>>}: (tensor<2x2xf32>) -> tensor<2x2x!quant.uniform<u8:f32, 1.0:128>>
%1 = "tfl.dequantize"(%0) : (tensor<2x2x!quant.uniform<u8:f32, 1.0:128>>) -> tensor<2x2xf32>
%4 = "tfl.add"(%1, %arg1) {fused_activation_function="NONE"}: (tensor<2x2xf32>, tensor<2x1xf32>) -> tensor<2x2xf32>
func.return %4 : tensor<2x2xf32>
// CHECK: %[[q0:.*]] = "tfl.quantize"(%arg1) <{qtype = tensor<2x1x!quant.uniform<u8:f32, 0.0078431372549019607:128>>}>
// CHECK: %[[q1:.*]] = "tfl.quantize"(%arg0) <{qtype = tensor<2x2x!quant.uniform<u8:f32, 1.000000e+00:128>>}>
// CHECK: %[[add:.*]] = tfl.add(%[[q1]], %[[q0]]) <{fused_activation_function = "NONE"}> : (tensor<2x2x!quant.uniform<u8:f32, 1.000000e+00:128>>
// CHECK: %[[dq:.*]] = "tfl.dequantize"(%[[add]]) : (tensor<2x2x!quant.uniform<u8:f32, 0.0078431372549019607:128>>)
// CHECK: return %[[dq]]
}
// CHECK-LABEL: hardcode_input_deq
func.func @hardcode_input_deq(%arg0: tensor<2x2x!quant.uniform<u8:f32, 1.0>>, %arg1: tensor<2x1xf32>) -> tensor<2x2xf32> {
%1 = "tfl.dequantize"(%arg0) : (tensor<2x2x!quant.uniform<u8:f32, 1.0>>) -> tensor<2x2xf32>
%4 = "tfl.add"(%1, %arg1) {fused_activation_function="NONE"}: (tensor<2x2xf32>, tensor<2x1xf32>) -> tensor<2x2xf32>
func.return %4 : tensor<2x2xf32>
// CHECK: %[[q:.*]] = "tfl.quantize"(%arg1) <{qtype = tensor<2x1x!quant.uniform<u8:f32, 0.0078431372549019607:128>>}>
// CHECK: %[[add:.*]] = tfl.add(%arg0, %[[q]]) <{fused_activation_function = "NONE"}> : (tensor<2x2x!quant.uniform<u8:f32, 1.000000e+00>>
// CHECK: %[[dq:.*]] = "tfl.dequantize"(%[[add]]) : (tensor<2x2x!quant.uniform<u8:f32, 0.0078431372549019607:128>>)
// CHECK: return %[[dq]]
}
// CHECK-LABEL: hardcode_output
func.func @hardcode_output(%arg0: tensor<2x2xf32>, %arg1: tensor<2x1xf32>) -> tensor<2x2xf32> {
%0 = "tfl.quantize"(%arg0) {qtype = tensor<2x2x!quant.uniform<u8:f32, 1.0:128>>}: (tensor<2x2xf32>) -> tensor<2x2x!quant.uniform<u8:f32, 1.0:128>>
%1 = "tfl.quantize"(%arg1) {qtype = tensor<2x1x!quant.uniform<u8:f32, 1.0:128>>}: (tensor<2x1xf32>) -> tensor<2x1x!quant.uniform<u8:f32, 1.0:128>>
%2 = "tfl.dequantize"(%0) : (tensor<2x2x!quant.uniform<u8:f32, 1.0:128>>) -> tensor<2x2xf32>
%3 = "tfl.dequantize"(%1) : (tensor<2x1x!quant.uniform<u8:f32, 1.0:128>>) -> tensor<2x1xf32>
%4 = "tfl.add"(%2, %3) {fused_activation_function="NONE"}: (tensor<2x2xf32>, tensor<2x1xf32>) -> tensor<2x2xf32>
func.return %4 : tensor<2x2xf32>
// CHECK: %[[q0:.*]] = "tfl.quantize"(%arg0) <{qtype = tensor<2x2x!quant.uniform<u8:f32, 1.000000e+00:128>>}>
// CHECK: %[[q1:.*]] = "tfl.quantize"(%arg1) <{qtype = tensor<2x1x!quant.uniform<u8:f32, 1.000000e+00:128>>}>
// CHECK: %[[add:.*]] = tfl.add(%[[q0]], %[[q1]]) <{fused_activation_function = "NONE"}> : (tensor<2x2x!quant.uniform<u8:f32, 1.000000e+00:128>>
// CHECK: %[[dq:.*]] = "tfl.dequantize"(%[[add]]) : (tensor<2x2x!quant.uniform<u8:f32, 0.0078431372549019607:128>>)
// CHECK: return %[[dq]]
}
// CHECK-LABEL: test_conv_2d_add
func.func @test_conv_2d_add(%arg0: tensor<1x224x224x3x!quant.uniform<u8:f32, 1.0>>, %arg1: tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 1.0>>, %arg2: tensor<32x!quant.uniform<i32:f32, 1.0>>) -> tensor<1x112x112x32x!quant.uniform<u8:f32, 1.0>> {
%0 = "tfl.dequantize"(%arg0) : (tensor<1x224x224x3x!quant.uniform<u8:f32, 1.0>>) -> tensor<1x224x224x3xf32>
%1 = "tfl.dequantize"(%arg1) : (tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 1.0>>) -> tensor<32x3x3x3xf32>
%2 = "tfl.dequantize"(%arg2) : (tensor<32x!quant.uniform<i32:f32, 1.0>>) -> tensor<32xf32>
%3 = "tfl.conv_2d"(%0, %1, %2) {dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 2 : i32, stride_w = 2 : i32} : (tensor<1x224x224x3xf32>, tensor<32x3x3x3xf32>, tensor<32xf32>) -> tensor<1x112x112x32xf32>
%4 = "tfl.pseudo_qconst"() {qtype = tensor<1x112x112x32x!quant.uniform<u8:f32, 1.0>>, value = dense<1> : tensor<1x112x112x32xi8>} : () -> tensor<1x112x112x32x!quant.uniform<u8:f32, 1.0>>
%5 = "tfl.dequantize"(%4) : (tensor<1x112x112x32x!quant.uniform<u8:f32, 1.0>>) -> tensor<1x112x112x32xf32>
%6 = "tfl.add"(%3, %5) {fused_activation_function="NONE"}: (tensor<1x112x112x32xf32>, tensor<1x112x112x32xf32>) -> tensor<1x112x112x32xf32>
%7 = "tfl.quantize"(%6) {qtype = tensor<1x112x112x32x!quant.uniform<u8:f32, 1.0>>} : (tensor<1x112x112x32xf32>) -> tensor<1x112x112x32x!quant.uniform<u8:f32, 1.0>>
func.return %7 : tensor<1x112x112x32x!quant.uniform<u8:f32, 1.0>>
// CHECK: %[[conv:.*]] = "tfl.conv_2d"(%arg0, %arg1, %arg2)
// CHECK-SAME: -> tensor<1x112x112x32x!quant.uniform<u8:f32, 0.0078431372549019607:128>>
// CHECK: %[[cst:.*]] = "tfl.pseudo_qconst"()
// CHECK: %[[add:.*]] = tfl.add(%[[conv]], %[[cst]])
// CHECK-SAME: -> tensor<1x112x112x32x!quant.uniform<u8:f32, 1.000000e+00>>
// CHECK: return %[[add]]
}
// CHECK-LABEL: test_conv_2d_activation_and_bias
func.func @test_conv_2d_activation_and_bias(%arg0: tensor<1x224x224x3xf32>, %arg1: tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 1.0>>, %arg2: tensor<32xf32>) -> tensor<1x112x112x32xf32> {
%0 = "tfl.dequantize"(%arg1) : (tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 1.0>>) -> tensor<32x3x3x3xf32>
%1 = "tfl.conv_2d"(%arg0, %0, %arg2) {dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 2 : i32, stride_w = 2 : i32} : (tensor<1x224x224x3xf32>, tensor<32x3x3x3xf32>, tensor<32xf32>) -> tensor<1x112x112x32xf32>
func.return %1 : tensor<1x112x112x32xf32>
// CHECK: %[[q0:.*]] = "tfl.quantize"(%arg2) <{qtype = tensor<32x!quant.uniform<i32:f32, 0.0078431372549019607>>}>
// CHECK: %[[q1:.*]] = "tfl.quantize"(%arg0) <{qtype = tensor<1x224x224x3x!quant.uniform<u8:f32, 0.0078431372549019607:128>>}>
// CHECK: %[[conv:.*]] = "tfl.conv_2d"(%[[q1]], %arg1, %[[q0]])
// CHECK: %[[dq:.*]] = "tfl.dequantize"(%[[conv]]) : (tensor<1x112x112x32x!quant.uniform<u8:f32, 0.0078431372549019607:128>>)
// CHECK: return %[[dq]]
}
// CHECK-LABEL: test_region
func.func @test_region(%arg0: tensor<128x128x!quant.uniform<u8:f32, 0.1:127>>,
%arg1: tensor<1x!quant.uniform<u8:f32, 0.2:127>>, %arg2: tensor<1x!quant.uniform<u8:f32, 0.4:127>>,
%arg3: tensor<1xi32>) -> (tensor<128x128x!quant.uniform<u8:f32, 0.2:125>>) {
%0 = "tfl.dequantize"(%arg0) : (tensor<128x128x!quant.uniform<u8:f32, 0.1:127>>) -> tensor<128x128xf32>
%1 = "tfl.dequantize"(%arg1) : (tensor<1x!quant.uniform<u8:f32, 0.2:127>>) -> tensor<1xf32>
%2 = "tfl.dequantize"(%arg2) : (tensor<1x!quant.uniform<u8:f32, 0.4:127>>) -> tensor<1xf32>
%3 = "tfl.custom_tf"(%0, %1, %2, %arg3) ({
^bb0(%a1: tensor<128x128xf32>, %a2: tensor<1xf32>, %a3: tensor<1xf32>, %a4: tensor<1xi32>):
%4 = "tf.LayerNorm"(%a1, %a2, %a3, %a4) {_tfl_quant_trait = "fully_quantizable", device = ""} : (tensor<128x128xf32>, tensor<1xf32>, tensor<1xf32>, tensor<1xi32>) -> tensor<128x128xf32>
"tfl.yield"(%4) : (tensor<128x128xf32>) -> ()
}) {_tfl_quant_trait = "fully_quantizable", device = ""} : (tensor<128x128xf32>, tensor<1xf32>, tensor<1xf32>, tensor<1xi32>) -> tensor<128x128xf32>
%4 = "tfl.quantize"(%3) {qtype = tensor<128x128x!quant.uniform<u8:f32, 0.2:125>>} : (tensor<128x128xf32>) -> tensor<128x128x!quant.uniform<u8:f32, 0.2:125>>
func.return %4 : tensor<128x128x!quant.uniform<u8:f32, 0.2:125>>
// CHECK: "tfl.custom_tf"
// CHECK-NEXT: ^bb0(%arg4: tensor<128x128xf32>, %arg5: tensor<1xf32>, %arg6: tensor<1xf32>, %arg7: tensor<1xi32>):
// CHECK-NEXT: "tf.LayerNorm"(%arg4, %arg5, %arg6, %arg7) {_tfl_quant_trait = "fully_quantizable", device = ""} : (tensor<128x128xf32>, tensor<1xf32>, tensor<1xf32>, tensor<1xi32>) -> tensor<128x128xf32>
// CHECK-NEXT: "tfl.yield"
// CHECK-NEXT: }) {_tfl_quant_trait = "fully_quantizable", device = ""} :
// CHECK-SAME: (tensor<128x128xf32>, tensor<1xf32>, tensor<1xf32>, tensor<1xi32>) -> tensor<128x128xf32>
}
@@ -0,0 +1,559 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: litert-opt %s -tfl-identify-dilated-conv | FileCheck %s
func.func @testDilatedConv(%arg0: tensor<1x128x128x3xf32>, %arg1: tensor<5x5x3x8xf32>) -> tensor<1x120x120x8xf32> {
%cst = arith.constant dense<[2, 2]> : tensor<2xi32>
%cst_0 = arith.constant dense<4> : tensor<2x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %cst, %cst_0) : (tensor<1x128x128x3xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<4x68x68x3xf32>
%1 = "tf.Conv2D"(%0, %arg1) {padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<4x68x68x3xf32>, tensor<5x5x3x8xf32>) -> tensor<4x64x64x8xf32>
%2 = "tf.BatchToSpaceND"(%1, %cst, %cst_0) : (tensor<4x64x64x8xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<1x120x120x8xf32>
func.return %2 : tensor<1x120x120x8xf32>
// CHECK-LABEL: testDilatedConv
// CHECK-SAME: ([[INPUT:%.*]]: tensor<1x128x128x3xf32>, [[FILTER:%.*]]: tensor<5x5x3x8xf32>)
// CHECK-NEXT: [[RESULT:%.*]] = "tf.Conv2D"([[INPUT]], [[FILTER]]) <{dilations = [1, 2, 2, 1], padding = "VALID", strides = [1, 1, 1, 1]}> : (tensor<1x128x128x3xf32>, tensor<5x5x3x8xf32>) -> tensor<1x120x120x8xf32>
// CHECK-NEXT: return [[RESULT]] : tensor<1x120x120x8xf32>
}
func.func @testDilatedConvWithNonConstantPadAndCrops(%arg0: tensor<1x128x128x3xf32>, %arg1: tensor<5x5x3x8xf32>) -> tensor<1x120x120x8xf32> {
%cst = arith.constant dense<[2, 2]> : tensor<2xi32>
%cst_1 = arith.constant dense<0> : tensor<2x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %cst, %cst_1) : (tensor<1x128x128x3xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<4x64x64x3xf32>
%1 = "tf.Conv2D"(%0, %arg1) {padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<4x64x64x3xf32>, tensor<5x5x3x8xf32>) -> tensor<4x60x60x8xf32>
%2 = "tf.BatchToSpaceND"(%1, %cst, %cst_1) : (tensor<4x60x60x8xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<1x120x120x8xf32>
func.return %2 : tensor<1x120x120x8xf32>
// CHECK-LABEL: testDilatedConvWithNonConstantPadAndCrops
// CHECK-SAME: ([[INPUT:%.*]]: tensor<1x128x128x3xf32>, [[FILTER:%.*]]: tensor<5x5x3x8xf32>)
// CHECK-NEXT: [[RESULT:%.*]] = "tf.Conv2D"([[INPUT]], [[FILTER]]) <{dilations = [1, 2, 2, 1], padding = "VALID", strides = [1, 1, 1, 1]}> : (tensor<1x128x128x3xf32>, tensor<5x5x3x8xf32>) -> tensor<1x120x120x8xf32>
// CHECK-NEXT: return [[RESULT]] : tensor<1x120x120x8xf32>
}
func.func @testDilatedConvWithNonZeroBasePadding(%arg0: tensor<1x128x128x3xf32>, %arg1: tensor<5x5x3x8xf32>) -> tensor<1x128x128x8xf32> {
%cst = arith.constant dense<[2, 2]> : tensor<2xi32>
%cst_0 = arith.constant dense<4> : tensor<2x2xi32>
%cst_1 = arith.constant dense<0> : tensor<2x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %cst, %cst_0) : (tensor<1x128x128x3xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<4x68x68x3xf32>
%1 = "tf.Conv2D"(%0, %arg1) {padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<4x68x68x3xf32>, tensor<5x5x3x8xf32>) -> tensor<4x64x64x8xf32>
%2 = "tf.BatchToSpaceND"(%1, %cst, %cst_1) : (tensor<4x64x64x8xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<1x128x128x8xf32>
func.return %2 : tensor<1x128x128x8xf32>
// CHECK-LABEL: testDilatedConvWithNonZeroBasePadding
// CHECK-SAME: ([[INPUT:%.*]]: tensor<1x128x128x3xf32>, [[FILTER:%.*]]: tensor<5x5x3x8xf32>)
// CHECK-NEXT: [[RESULT:%.*]] = "tf.Conv2D"([[INPUT]], [[FILTER]]) <{dilations = [1, 2, 2, 1], padding = "SAME", strides = [1, 1, 1, 1]}> : (tensor<1x128x128x3xf32>, tensor<5x5x3x8xf32>) -> tensor<1x128x128x8xf32>
// CHECK-NEXT: return [[RESULT]] : tensor<1x128x128x8xf32>
}
func.func @testDilatedConvWithFp16(%arg0 : tensor<1x20x30x40xf16>, %arg1: tensor<5x5x40x32xf16>) -> tensor<1x20x30x32xf16> {
%block_shape = arith.constant dense<2> : tensor<2xi32>
%paddings = arith.constant dense<4> : tensor<2x2xi32>
%crops = arith.constant dense<0> : tensor<2x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %block_shape, %paddings) : (tensor<1x20x30x40xf16>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<4x14x19x40xf16>
%1 = "tf.Conv2D"(%0, %arg1) {data_format = "NHWC", dilations = [1, 1, 1, 1], explicit_paddings = [], padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<4x14x19x40xf16>, tensor<5x5x40x32xf16>) -> tensor<4x10x15x32xf16>
%2 = "tf.BatchToSpaceND"(%1, %block_shape, %crops) : (tensor<4x10x15x32xf16>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<1x20x30x32xf16>
func.return %2 : tensor<1x20x30x32xf16>
// CHECK-LABEL: testDilatedConvWithFp16
// CHECK-SAME: ([[INPUT:%.*]]: tensor<1x20x30x40xf16>, [[FILTER:%.*]]: tensor<5x5x40x32xf16>)
// CHECK-NEXT: [[RESULT:%.*]] = "tf.Conv2D"([[INPUT]], [[FILTER]]) <{data_format = "NHWC", dilations = [1, 2, 2, 1], explicit_paddings = [], padding = "SAME", strides = [1, 1, 1, 1]}> : (tensor<1x20x30x40xf16>, tensor<5x5x40x32xf16>) -> tensor<1x20x30x32xf16>
// CHECK-NEXT: return [[RESULT]] : tensor<1x20x30x32xf16>
}
func.func @testDilatedConvWithNonTrivialDilations(%arg0: tensor<1x128x128x3xf32>, %arg1: tensor<5x5x3x8xf32>) -> tensor<1x128x128x8xf32> {
%cst = arith.constant dense<[2, 2]> : tensor<2xi32>
%cst_0 = arith.constant dense<4> : tensor<2x2xi32>
%cst_1 = arith.constant dense<0> : tensor<2x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %cst, %cst_0) : (tensor<1x128x128x3xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<4x68x68x3xf32>
%1 = "tf.Conv2D"(%0, %arg1) {padding = "VALID", dilations = [1, 2, 2, 1], strides = [1, 1, 1, 1]} : (tensor<4x68x68x3xf32>, tensor<5x5x3x8xf32>) -> tensor<4x60x60x8xf32>
%2 = "tf.BatchToSpaceND"(%1, %cst, %cst_1) : (tensor<4x60x60x8xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<1x128x128x8xf32>
func.return %2 : tensor<1x128x128x8xf32>
// CHECK-LABEL: testDilatedConvWithNonTrivialDilations
// CHECK: [[STB:%.*]] = "tf.SpaceToBatchND"
// CHECK-NEXT: [[CONV:%.*]] = "tf.Conv2D"
// CHECK-NEXT: [[RESULT:%.*]] = "tf.BatchToSpaceND"
// CHECK-NEXT: return [[RESULT]]
}
func.func @testDilatedDepthWiseConv(%arg0: tensor<1x128x128x3xf32>, %arg1: tensor<5x5x3x8xf32>) -> tensor<1x128x128x8xf32> {
%cst = arith.constant dense<[2, 2]> : tensor<2xi32>
%cst_0 = arith.constant dense<4> : tensor<2x2xi32>
%cst_1 = arith.constant dense<0> : tensor<2x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %cst, %cst_0) : (tensor<1x128x128x3xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<4x68x68x3xf32>
%1 = "tf.DepthwiseConv2dNative"(%0, %arg1) {padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<4x68x68x3xf32>, tensor<5x5x3x8xf32>) -> tensor<4x64x64x8xf32>
%2 = "tf.BatchToSpaceND"(%1, %cst, %cst_1) : (tensor<4x64x64x8xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<1x128x128x8xf32>
func.return %2 : tensor<1x128x128x8xf32>
// CHECK-LABEL: testDilatedDepthWiseConv
// CHECK-SAME: ([[INPUT:%.*]]: tensor<1x128x128x3xf32>, [[FILTER:%.*]]: tensor<5x5x3x8xf32>)
// CHECK-NEXT: [[RESULT:%.*]] = "tf.DepthwiseConv2dNative"([[INPUT]], [[FILTER]]) <{dilations = [1, 2, 2, 1], padding = "SAME", strides = [1, 1, 1, 1]}> : (tensor<1x128x128x3xf32>, tensor<5x5x3x8xf32>) -> tensor<1x128x128x8xf32>
// CHECK-NEXT: return [[RESULT]] : tensor<1x128x128x8xf32>
}
func.func @testDilatedConvWithPad(%arg0: tensor<1x128x128x3xf32>, %arg1: tensor<5x5x3x8xf32>, %arg2: tensor<8xf32>) -> tensor<1x128x128x8xf32> {
%cst = arith.constant dense<[2, 2]> : tensor<2xi32>
%cst_0 = arith.constant dense<4> : tensor<2x2xi32>
%cst_1 = arith.constant dense<0> : tensor<2x2xi32>
%cst_2 = arith.constant dense<0> : tensor<4x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %cst, %cst_0) : (tensor<1x128x128x3xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<4x68x68x3xf32>
%1 = "tf.Conv2D"(%0, %arg1) {padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<4x68x68x3xf32>, tensor<5x5x3x8xf32>) -> tensor<4x64x64x8xf32>
%2 = "tf.Pad"(%1, %cst_2) : (tensor<4x64x64x8xf32>, tensor<4x2xi32>) -> tensor<4x64x64x8xf32>
%3 = "tf.BatchToSpaceND"(%2, %cst, %cst_1) : (tensor<4x64x64x8xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<1x128x128x8xf32>
%4 = "tf.BiasAdd"(%3, %arg2) : (tensor<1x128x128x8xf32>, tensor<8xf32>) -> tensor<1x128x128x8xf32>
func.return %4 : tensor<1x128x128x8xf32>
// CHECK-LABEL: testDilatedConvWithPad
// CHECK-SAME: ([[INPUT:%.*]]: tensor<1x128x128x3xf32>, [[FILTER:%.*]]: tensor<5x5x3x8xf32>, [[BIAS:%.*]]: tensor<8xf32>)
// CHECK-NEXT: [[CONV:%.*]] = "tf.Conv2D"([[INPUT]], [[FILTER]]) <{dilations = [1, 2, 2, 1], padding = "SAME", strides = [1, 1, 1, 1]}> : (tensor<1x128x128x3xf32>, tensor<5x5x3x8xf32>) -> tensor<1x128x128x8xf32>
// CHECK-NEXT: [[RESULT:%.*]] = "tf.BiasAdd"([[CONV]], [[BIAS]]) : (tensor<1x128x128x8xf32>, tensor<8xf32>) -> tensor<1x128x128x8xf32>
// CHECK-NEXT: return [[RESULT]] : tensor<1x128x128x8xf32>
}
func.func @testDilatedDepthWiseConvWithPad(%arg0: tensor<1x128x128x3xf32>, %arg1: tensor<5x5x3x8xf32>, %arg2: tensor<8xf32>) -> tensor<1x128x128x8xf32> {
%cst = arith.constant dense<[2, 2]> : tensor<2xi32>
%cst_0 = arith.constant dense<4> : tensor<2x2xi32>
%cst_1 = arith.constant dense<0> : tensor<2x2xi32>
%cst_2 = arith.constant dense<0> : tensor<4x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %cst, %cst_0) : (tensor<1x128x128x3xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<4x68x68x3xf32>
%1 = "tf.DepthwiseConv2dNative"(%0, %arg1) {padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<4x68x68x3xf32>, tensor<5x5x3x8xf32>) -> tensor<4x64x64x8xf32>
%2 = "tf.Pad"(%1, %cst_2) : (tensor<4x64x64x8xf32>, tensor<4x2xi32>) -> tensor<4x64x64x8xf32>
%3 = "tf.BatchToSpaceND"(%2, %cst, %cst_1) : (tensor<4x64x64x8xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<1x128x128x8xf32>
%4 = "tf.BiasAdd"(%3, %arg2) : (tensor<1x128x128x8xf32>, tensor<8xf32>) -> tensor<1x128x128x8xf32>
func.return %4 : tensor<1x128x128x8xf32>
// CHECK-LABEL: testDilatedDepthWiseConvWithPad
// CHECK-SAME: ([[INPUT:%.*]]: tensor<1x128x128x3xf32>, [[FILTER:%.*]]: tensor<5x5x3x8xf32>, [[BIAS:%.*]]: tensor<8xf32>)
// CHECK-NEXT: [[CONV:%.*]] = "tf.DepthwiseConv2dNative"([[INPUT]], [[FILTER]]) <{dilations = [1, 2, 2, 1], padding = "SAME", strides = [1, 1, 1, 1]}> : (tensor<1x128x128x3xf32>, tensor<5x5x3x8xf32>) -> tensor<1x128x128x8xf32>
// CHECK-NEXT: [[RESULT:%.*]] = "tf.BiasAdd"([[CONV]], [[BIAS]]) : (tensor<1x128x128x8xf32>, tensor<8xf32>) -> tensor<1x128x128x8xf32>
// CHECK-NEXT: return [[RESULT]] : tensor<1x128x128x8xf32>
}
func.func @testDilatedConvWithBiasAdd(%arg0: tensor<1x128x128x3xf32>, %arg1: tensor<5x5x3x8xf32>, %arg2: tensor<8xf32>) -> tensor<1x128x128x8xf32> {
%cst = arith.constant dense<[2, 2]> : tensor<2xi32>
%cst_0 = arith.constant dense<4> : tensor<2x2xi32>
%cst_1 = arith.constant dense<0> : tensor<2x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %cst, %cst_0) : (tensor<1x128x128x3xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<4x68x68x3xf32>
%1 = "tf.Conv2D"(%0, %arg1) {padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<4x68x68x3xf32>, tensor<5x5x3x8xf32>) -> tensor<4x64x64x8xf32>
%2 = "tf.BatchToSpaceND"(%1, %cst, %cst_1) : (tensor<4x64x64x8xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<1x128x128x8xf32>
%3 = "tf.BiasAdd"(%2, %arg2) : (tensor<1x128x128x8xf32>, tensor<8xf32>) -> tensor<1x128x128x8xf32>
func.return %3 : tensor<1x128x128x8xf32>
// CHECK-LABEL: testDilatedConvWithBiasAdd
// CHECK-SAME: ([[INPUT:%.*]]: tensor<1x128x128x3xf32>, [[FILTER:%.*]]: tensor<5x5x3x8xf32>, [[BIAS:%.*]]: tensor<8xf32>)
// CHECK-NEXT: [[CONV:%.*]] = "tf.Conv2D"([[INPUT]], [[FILTER]]) <{dilations = [1, 2, 2, 1], padding = "SAME", strides = [1, 1, 1, 1]}> : (tensor<1x128x128x3xf32>, tensor<5x5x3x8xf32>) -> tensor<1x128x128x8xf32>
// CHECK-NEXT: [[RESULT:%.*]] = "tf.BiasAdd"([[CONV]], [[BIAS]]) : (tensor<1x128x128x8xf32>, tensor<8xf32>) -> tensor<1x128x128x8xf32>
// CHECK-NEXT: return [[RESULT]] : tensor<1x128x128x8xf32>
}
func.func @testDilatedDepthWiseConvWithBiasAdd(%arg0: tensor<1x128x128x3xf32>, %arg1: tensor<5x5x3x8xf32>, %arg2: tensor<8xf32>) -> tensor<1x128x128x8xf32> {
%cst = arith.constant dense<[2, 2]> : tensor<2xi32>
%cst_0 = arith.constant dense<4> : tensor<2x2xi32>
%cst_1 = arith.constant dense<0> : tensor<2x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %cst, %cst_0) : (tensor<1x128x128x3xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<4x68x68x3xf32>
%1 = "tf.DepthwiseConv2dNative"(%0, %arg1) {padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<4x68x68x3xf32>, tensor<5x5x3x8xf32>) -> tensor<4x64x64x8xf32>
%2 = "tf.BatchToSpaceND"(%1, %cst, %cst_1) : (tensor<4x64x64x8xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<1x128x128x8xf32>
%3 = "tf.BiasAdd"(%2, %arg2) : (tensor<1x128x128x8xf32>, tensor<8xf32>) -> tensor<1x128x128x8xf32>
func.return %3 : tensor<1x128x128x8xf32>
// CHECK-LABEL: testDilatedDepthWiseConvWithBiasAdd
// CHECK-SAME: ([[INPUT:%.*]]: tensor<1x128x128x3xf32>, [[FILTER:%.*]]: tensor<5x5x3x8xf32>, [[BIAS:%.*]]: tensor<8xf32>)
// CHECK-NEXT: [[CONV:%.*]] = "tf.DepthwiseConv2dNative"([[INPUT]], [[FILTER]]) <{dilations = [1, 2, 2, 1], padding = "SAME", strides = [1, 1, 1, 1]}> : (tensor<1x128x128x3xf32>, tensor<5x5x3x8xf32>) -> tensor<1x128x128x8xf32>
// CHECK-NEXT: [[RESULT:%.*]] = "tf.BiasAdd"([[CONV]], [[BIAS]]) : (tensor<1x128x128x8xf32>, tensor<8xf32>) -> tensor<1x128x128x8xf32>
// CHECK-NEXT: return [[RESULT]] : tensor<1x128x128x8xf32>
}
func.func @testDilatedConvWithExpandSqueeze1(%arg0: tensor<1x128x128xf32>, %arg1: tensor<5x5x1x1xf32>, %arg2: tensor<128xf32>) -> tensor<1x128x128xf32> {
%cst = arith.constant dense<[2, 2]> : tensor<2xi32>
%cst_0 = "tf.Const"() { value = dense<3> : tensor<i32> } : () -> tensor<i32>
%cst_1 = arith.constant dense<4> : tensor<2x2xi32>
%cst_2 = arith.constant dense<0> : tensor<2x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %cst, %cst_1) : (tensor<1x128x128xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<4x68x68xf32>
%1 = "tf.ExpandDims"(%0, %cst_0) : (tensor<4x68x68xf32>, tensor<i32>) -> tensor<4x68x68x1xf32>
%2 = "tf.Conv2D"(%1, %arg1) {padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<4x68x68x1xf32>, tensor<5x5x1x1xf32>) -> tensor<4x64x64x1xf32>
%3 = "tf.Squeeze"(%2) {squeeze_dims = [3]} : (tensor<4x64x64x1xf32>) -> tensor<4x64x64xf32>
%4 = "tf.BatchToSpaceND"(%3, %cst, %cst_2) : (tensor<4x64x64xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<1x128x128xf32>
%5 = "tf.BiasAdd"(%4, %arg2) : (tensor<1x128x128xf32>, tensor<128xf32>) -> tensor<1x128x128xf32>
func.return %5 : tensor<1x128x128xf32>
// CHECK-LABEL: testDilatedConvWithExpandSqueeze1
// CHECK-SAME: ([[INPUT:%.*]]: tensor<1x128x128xf32>, [[FILTER:%.*]]: tensor<5x5x1x1xf32>, [[BIAS:%.*]]: tensor<128xf32>)
// CHECK-NEXT: [[AXIS:%.*]] = "tf.Const"() <{value = dense<3> : tensor<i32>}> : () -> tensor<i32>
// CHECK-NEXT: [[EXPAND:%.*]] = "tf.ExpandDims"([[INPUT]], [[AXIS]]) : (tensor<1x128x128xf32>, tensor<i32>) -> tensor<1x128x128x1xf32>
// CHECK-NEXT: [[CONV:%.*]] = "tf.Conv2D"([[EXPAND]], [[FILTER]]) <{dilations = [1, 2, 2, 1], padding = "SAME", strides = [1, 1, 1, 1]}> : (tensor<1x128x128x1xf32>, tensor<5x5x1x1xf32>) -> tensor<1x128x128x1xf32>
// CHECK-NEXT: [[SQUEEZE:%.*]] = "tf.Squeeze"([[CONV]]) <{squeeze_dims = [3]}> : (tensor<1x128x128x1xf32>) -> tensor<1x128x128xf32>
// CHECK-NEXT: [[RESULT:%.*]] = "tf.BiasAdd"([[SQUEEZE]], [[BIAS]]) : (tensor<1x128x128xf32>, tensor<128xf32>) -> tensor<1x128x128xf32>
// CHECK-NEXT: return [[RESULT]] : tensor<1x128x128xf32>
}
func.func @testDilatedDepthWiseConvWithExpandSqueeze1(%arg0: tensor<1x128x128xf32>, %arg1: tensor<5x5x1x1xf32>, %arg2: tensor<128xf32>) -> tensor<1x128x128xf32> {
%cst = arith.constant dense<[2, 2]> : tensor<2xi32>
%cst_0 = "tf.Const"() { value = dense<3> : tensor<i32> } : () -> tensor<i32>
%cst_1 = arith.constant dense<4> : tensor<2x2xi32>
%cst_2 = arith.constant dense<0> : tensor<2x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %cst, %cst_1) : (tensor<1x128x128xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<4x68x68xf32>
%1 = "tf.ExpandDims"(%0, %cst_0) : (tensor<4x68x68xf32>, tensor<i32>) -> tensor<4x68x68x1xf32>
%2 = "tf.DepthwiseConv2dNative"(%1, %arg1) {padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<4x68x68x1xf32>, tensor<5x5x1x1xf32>) -> tensor<4x64x64x1xf32>
%3 = "tf.Squeeze"(%2) {squeeze_dims = [3]} : (tensor<4x64x64x1xf32>) -> tensor<4x64x64xf32>
%4 = "tf.BatchToSpaceND"(%3, %cst, %cst_2) : (tensor<4x64x64xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<1x128x128xf32>
%5 = "tf.BiasAdd"(%4, %arg2) : (tensor<1x128x128xf32>, tensor<128xf32>) -> tensor<1x128x128xf32>
func.return %5 : tensor<1x128x128xf32>
// CHECK-LABEL: testDilatedDepthWiseConvWithExpandSqueeze1
// CHECK-SAME: ([[INPUT:%.*]]: tensor<1x128x128xf32>, [[FILTER:%.*]]: tensor<5x5x1x1xf32>, [[BIAS:%.*]]: tensor<128xf32>)
// CHECK-NEXT: [[AXIS:%.*]] = "tf.Const"() <{value = dense<3> : tensor<i32>}> : () -> tensor<i32>
// CHECK-NEXT: [[EXPAND:%.*]] = "tf.ExpandDims"([[INPUT]], [[AXIS]]) : (tensor<1x128x128xf32>, tensor<i32>) -> tensor<1x128x128x1xf32>
// CHECK-NEXT: [[CONV:%.*]] = "tf.DepthwiseConv2dNative"([[EXPAND]], [[FILTER]]) <{dilations = [1, 2, 2, 1], padding = "SAME", strides = [1, 1, 1, 1]}> : (tensor<1x128x128x1xf32>, tensor<5x5x1x1xf32>) -> tensor<1x128x128x1xf32>
// CHECK-NEXT: [[SQUEEZE:%.*]] = "tf.Squeeze"([[CONV]]) <{squeeze_dims = [3]}> : (tensor<1x128x128x1xf32>) -> tensor<1x128x128xf32>
// CHECK-NEXT: [[RESULT:%.*]] = "tf.BiasAdd"([[SQUEEZE]], [[BIAS]]) : (tensor<1x128x128xf32>, tensor<128xf32>) -> tensor<1x128x128xf32>
// CHECK-NEXT: return [[RESULT]] : tensor<1x128x128xf32>
}
func.func @testDilatedConvWithExpandSqueeze2(%arg0: tensor<1x128x128xf32>, %arg1: tensor<5x5x1x1xf32>, %arg2: tensor<?xf32>) -> tensor<1x128x128xf32> {
%cst = arith.constant dense<[2, 2]> : tensor<2xi32>
%cst_0 = "tf.Const"() { value = dense<3> : tensor<i32> } : () -> tensor<i32>
%cst_1 = arith.constant dense<4> : tensor<2x2xi32>
%cst_2 = arith.constant dense<0> : tensor<2x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %cst, %cst_1) : (tensor<1x128x128xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<4x?x?xf32>
%1 = "tf.ExpandDims"(%0, %cst_0) : (tensor<4x?x?xf32>, tensor<i32>) -> tensor<4x?x?x1xf32>
%2 = "tf.Conv2D"(%1, %arg1) {padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<4x?x?x1xf32>, tensor<5x5x1x1xf32>) -> tensor<4x?x?x1xf32>
%3 = "tf.Squeeze"(%2) {squeeze_dims = [3]} : (tensor<4x?x?x1xf32>) -> tensor<4x?x?xf32>
%4 = "tf.BiasAdd"(%3, %arg2) : (tensor<4x?x?xf32>, tensor<?xf32>) -> tensor<4x?x?xf32>
%5 = "tf.BatchToSpaceND"(%4, %cst, %cst_2) : (tensor<4x?x?xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<1x128x128xf32>
func.return %5 : tensor<1x128x128xf32>
// CHECK-LABEL: testDilatedConvWithExpandSqueeze2
// CHECK-SAME: ([[INPUT:%.*]]: tensor<1x128x128xf32>, [[FILTER:%.*]]: tensor<5x5x1x1xf32>, [[BIAS:%.*]]: tensor<?xf32>)
// CHECK-NEXT: [[AXIS:%.*]] = "tf.Const"() <{value = dense<3> : tensor<i32>}> : () -> tensor<i32>
// CHECK-NEXT: [[EXPAND:%.*]] = "tf.ExpandDims"([[INPUT]], [[AXIS]]) : (tensor<1x128x128xf32>, tensor<i32>) -> tensor<1x128x128x1xf32>
// CHECK-NEXT: [[CONV:%.*]] = "tf.Conv2D"([[EXPAND]], [[FILTER]]) <{dilations = [1, 2, 2, 1], padding = "SAME", strides = [1, 1, 1, 1]}> : (tensor<1x128x128x1xf32>, tensor<5x5x1x1xf32>) -> tensor<1x128x128x1xf32>
// CHECK-NEXT: [[SQUEEZE:%.*]] = "tf.Squeeze"([[CONV]]) <{squeeze_dims = [3]}> : (tensor<1x128x128x1xf32>) -> tensor<1x128x128xf32>
// CHECK-NEXT: [[RESULT:%.*]] = "tf.BiasAdd"([[SQUEEZE]], [[BIAS]]) : (tensor<1x128x128xf32>, tensor<?xf32>) -> tensor<1x128x128xf32>
// CHECK-NEXT: return [[RESULT]] : tensor<1x128x128xf32>
}
func.func @testDilatedDepthWiseConvWithExpandSqueeze2(%arg0: tensor<1x128x128xf32>, %arg1: tensor<5x5x1x1xf32>, %arg2: tensor<?xf32>) -> tensor<1x128x128xf32> {
%cst = arith.constant dense<[2, 2]> : tensor<2xi32>
%cst_0 = "tf.Const"() { value = dense<3> : tensor<i32> } : () -> tensor<i32>
%cst_1 = arith.constant dense<4> : tensor<2x2xi32>
%cst_2 = arith.constant dense<0> : tensor<2x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %cst, %cst_1) : (tensor<1x128x128xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<4x?x?xf32>
%1 = "tf.ExpandDims"(%0, %cst_0) : (tensor<4x?x?xf32>, tensor<i32>) -> tensor<4x?x?x1xf32>
%2 = "tf.DepthwiseConv2dNative"(%1, %arg1) {padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<4x?x?x1xf32>, tensor<5x5x1x1xf32>) -> tensor<4x?x?x1xf32>
%3 = "tf.Squeeze"(%2) {squeeze_dims = [3]} : (tensor<4x?x?x1xf32>) -> tensor<4x?x?xf32>
%4 = "tf.BiasAdd"(%3, %arg2) : (tensor<4x?x?xf32>, tensor<?xf32>) -> tensor<4x?x?xf32>
%5 = "tf.BatchToSpaceND"(%4, %cst, %cst_2) : (tensor<4x?x?xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<1x128x128xf32>
func.return %5 : tensor<1x128x128xf32>
// CHECK-LABEL: testDilatedDepthWiseConvWithExpandSqueeze2
// CHECK-SAME: ([[INPUT:%.*]]: tensor<1x128x128xf32>, [[FILTER:%.*]]: tensor<5x5x1x1xf32>, [[BIAS:%.*]]: tensor<?xf32>)
// CHECK-NEXT: [[AXIS:%.*]] = "tf.Const"() <{value = dense<3> : tensor<i32>}> : () -> tensor<i32>
// CHECK-NEXT: [[EXPAND:%.*]] = "tf.ExpandDims"([[INPUT]], [[AXIS]]) : (tensor<1x128x128xf32>, tensor<i32>) -> tensor<1x128x128x1xf32>
// CHECK-NEXT: [[CONV:%.*]] = "tf.DepthwiseConv2dNative"([[EXPAND]], [[FILTER]]) <{dilations = [1, 2, 2, 1], padding = "SAME", strides = [1, 1, 1, 1]}> : (tensor<1x128x128x1xf32>, tensor<5x5x1x1xf32>) -> tensor<1x128x128x1xf32>
// CHECK-NEXT: [[SQUEEZE:%.*]] = "tf.Squeeze"([[CONV]]) <{squeeze_dims = [3]}> : (tensor<1x128x128x1xf32>) -> tensor<1x128x128xf32>
// CHECK-NEXT: [[RESULT:%.*]] = "tf.BiasAdd"([[SQUEEZE]], [[BIAS]]) : (tensor<1x128x128xf32>, tensor<?xf32>) -> tensor<1x128x128xf32>
// CHECK-NEXT: return [[RESULT]] : tensor<1x128x128xf32>
}
func.func @testDilatedConvWithExpandSqueeze3(%arg0: tensor<1x128x128xf32>, %arg1: tensor<5x5x1x1xf32>, %arg2: tensor<128xf32>) -> tensor<1x128x128xf32> {
%cst = arith.constant dense<[2, 2]> : tensor<2xi32>
%cst_0 = "tf.Const"() { value = dense<3> : tensor<i32> } : () -> tensor<i32>
%cst_1 = arith.constant dense<4> : tensor<2x2xi32>
%cst_2 = arith.constant dense<0> : tensor<2x2xi32>
%cst_3 = arith.constant dense<0> : tensor<3x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %cst, %cst_1) : (tensor<1x128x128xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<4x68x68xf32>
%1 = "tf.ExpandDims"(%0, %cst_0) : (tensor<4x68x68xf32>, tensor<i32>) -> tensor<4x68x68x1xf32>
%2 = "tf.Conv2D"(%1, %arg1) {padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<4x68x68x1xf32>, tensor<5x5x1x1xf32>) -> tensor<4x64x64x1xf32>
%3 = "tf.Squeeze"(%2) {squeeze_dims = [3]} : (tensor<4x64x64x1xf32>) -> tensor<4x64x64xf32>
%4 = "tf.Pad"(%3, %cst_3) : (tensor<4x64x64xf32>, tensor<3x2xi32>) -> tensor<4x64x64xf32>
%5 = "tf.BatchToSpaceND"(%4, %cst, %cst_2) : (tensor<4x64x64xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<1x128x128xf32>
%6 = "tf.BiasAdd"(%5, %arg2) : (tensor<1x128x128xf32>, tensor<128xf32>) -> tensor<1x128x128xf32>
func.return %6 : tensor<1x128x128xf32>
// CHECK-LABEL: testDilatedConvWithExpandSqueeze3
// CHECK-SAME: ([[INPUT:%.*]]: tensor<1x128x128xf32>, [[FILTER:%.*]]: tensor<5x5x1x1xf32>, [[BIAS:%.*]]: tensor<128xf32>)
// CHECK-NEXT: [[AXIS:%.*]] = "tf.Const"() <{value = dense<3> : tensor<i32>}> : () -> tensor<i32>
// CHECK-NEXT: [[EXPAND:%.*]] = "tf.ExpandDims"([[INPUT]], [[AXIS]]) : (tensor<1x128x128xf32>, tensor<i32>) -> tensor<1x128x128x1xf32>
// CHECK-NEXT: [[CONV:%.*]] = "tf.Conv2D"([[EXPAND]], [[FILTER]]) <{dilations = [1, 2, 2, 1], padding = "SAME", strides = [1, 1, 1, 1]}> : (tensor<1x128x128x1xf32>, tensor<5x5x1x1xf32>) -> tensor<1x128x128x1xf32>
// CHECK-NEXT: [[SQUEEZE:%.*]] = "tf.Squeeze"([[CONV]]) <{squeeze_dims = [3]}> : (tensor<1x128x128x1xf32>) -> tensor<1x128x128xf32>
// CHECK-NEXT: [[RESULT:%.*]] = "tf.BiasAdd"([[SQUEEZE]], [[BIAS]]) : (tensor<1x128x128xf32>, tensor<128xf32>) -> tensor<1x128x128xf32>
// CHECK-NEXT: return [[RESULT]] : tensor<1x128x128xf32>
}
func.func @testDilatedDepthWiseConvWithExpandSqueeze3(%arg0: tensor<1x128x128xf32>, %arg1: tensor<5x5x1x1xf32>, %arg2: tensor<128xf32>) -> tensor<1x128x128xf32> {
%cst = arith.constant dense<[2, 2]> : tensor<2xi32>
%cst_0 = "tf.Const"() { value = dense<3> : tensor<i32> } : () -> tensor<i32>
%cst_1 = arith.constant dense<4> : tensor<2x2xi32>
%cst_2 = arith.constant dense<0> : tensor<2x2xi32>
%cst_3 = arith.constant dense<0> : tensor<3x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %cst, %cst_1) : (tensor<1x128x128xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<4x68x68xf32>
%1 = "tf.ExpandDims"(%0, %cst_0) : (tensor<4x68x68xf32>, tensor<i32>) -> tensor<4x68x68x1xf32>
%2 = "tf.DepthwiseConv2dNative"(%1, %arg1) {padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<4x68x68x1xf32>, tensor<5x5x1x1xf32>) -> tensor<4x64x64x1xf32>
%3 = "tf.Squeeze"(%2) {squeeze_dims = [3]} : (tensor<4x64x64x1xf32>) -> tensor<4x64x64xf32>
%4 = "tf.Pad"(%3, %cst_3) : (tensor<4x64x64xf32>, tensor<3x2xi32>) -> tensor<4x64x64xf32>
%5 = "tf.BatchToSpaceND"(%4, %cst, %cst_2) : (tensor<4x64x64xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<1x128x128xf32>
%6 = "tf.BiasAdd"(%5, %arg2) : (tensor<1x128x128xf32>, tensor<128xf32>) -> tensor<1x128x128xf32>
func.return %6 : tensor<1x128x128xf32>
// CHECK-LABEL: testDilatedDepthWiseConvWithExpandSqueeze3
// CHECK-SAME: ([[INPUT:%.*]]: tensor<1x128x128xf32>, [[FILTER:%.*]]: tensor<5x5x1x1xf32>, [[BIAS:%.*]]: tensor<128xf32>)
// CHECK-NEXT: [[AXIS:%.*]] = "tf.Const"() <{value = dense<3> : tensor<i32>}> : () -> tensor<i32>
// CHECK-NEXT: [[EXPAND:%.*]] = "tf.ExpandDims"([[INPUT]], [[AXIS]]) : (tensor<1x128x128xf32>, tensor<i32>) -> tensor<1x128x128x1xf32>
// CHECK-NEXT: [[CONV:%.*]] = "tf.DepthwiseConv2dNative"([[EXPAND]], [[FILTER]]) <{dilations = [1, 2, 2, 1], padding = "SAME", strides = [1, 1, 1, 1]}> : (tensor<1x128x128x1xf32>, tensor<5x5x1x1xf32>) -> tensor<1x128x128x1xf32>
// CHECK-NEXT: [[SQUEEZE:%.*]] = "tf.Squeeze"([[CONV]]) <{squeeze_dims = [3]}> : (tensor<1x128x128x1xf32>) -> tensor<1x128x128xf32>
// CHECK-NEXT: [[RESULT:%.*]] = "tf.BiasAdd"([[SQUEEZE]], [[BIAS]]) : (tensor<1x128x128xf32>, tensor<128xf32>) -> tensor<1x128x128xf32>
// CHECK-NEXT: return [[RESULT]] : tensor<1x128x128xf32>
}
func.func @testAvoidDilatedConvWithExpand(%arg0: tensor<*xf32>, %arg1: tensor<5x5x1x1xf32>, %arg2: tensor<128xf32>) -> tensor<1x128x128xf32> {
%cst = arith.constant dense<[2, 2]> : tensor<2xi32>
%cst_0 = "tf.Const"() { value = dense<3> : tensor<i32> } : () -> tensor<i32>
%cst_1 = arith.constant dense<4> : tensor<2x2xi32>
%cst_2 = arith.constant dense<0> : tensor<2x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %cst, %cst_1) : (tensor<*xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<4x68x68xf32>
%1 = "tf.ExpandDims"(%0, %cst_0) : (tensor<4x68x68xf32>, tensor<i32>) -> tensor<4x68x68x1xf32>
%2 = "tf.Conv2D"(%1, %arg1) {padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<4x68x68x1xf32>, tensor<5x5x1x1xf32>) -> tensor<4x64x64x1xf32>
%3 = "tf.Squeeze"(%2) {squeeze_dims = [3]} : (tensor<4x64x64x1xf32>) -> tensor<4x64x64xf32>
%4 = "tf.BatchToSpaceND"(%3, %cst, %cst_2) : (tensor<4x64x64xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<1x128x128xf32>
%5 = "tf.BiasAdd"(%4, %arg2) : (tensor<1x128x128xf32>, tensor<128xf32>) -> tensor<1x128x128xf32>
func.return %5 : tensor<1x128x128xf32>
// CHECK-LABEL: testAvoidDilatedConvWithExpand
// CHECK: "tf.SpaceToBatchND"
// CHECK: "tf.ExpandDims"
// CHECK: "tf.Conv2D"
// CHECK: "tf.Squeeze"
// CHECK: "tf.BatchToSpaceND"
// CHECK: "tf.BiasAdd"
}
func.func @testDilatedConvWithDifferentExpandSqueezeAxis(%arg0: tensor<1x128x128xf32>, %arg1: tensor<5x5x1x1xf32>) -> tensor<1x128x128x1xf32> {
%cst = arith.constant dense<[2, 2]> : tensor<2xi32>
%cst_0 = "tf.Const"() { value = dense<3> : tensor<i32> } : () -> tensor<i32>
%cst_1 = arith.constant dense<4> : tensor<2x2xi32>
%cst_2 = arith.constant dense<0> : tensor<2x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %cst, %cst_1) : (tensor<1x128x128xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<4x68x68xf32>
%1 = "tf.ExpandDims"(%0, %cst_0) : (tensor<4x68x68xf32>, tensor<i32>) -> tensor<4x68x68x1xf32>
%2 = "tf.Conv2D"(%1, %arg1) {padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<4x68x68x1xf32>, tensor<5x5x1x1xf32>) -> tensor<4x64x64x1xf32>
%3 = "tf.Squeeze"(%2) {squeeze_dims = [2]} : (tensor<4x64x64x1xf32>) -> tensor<4x64x64x1xf32>
%4 = "tf.BatchToSpaceND"(%3, %cst, %cst_2) : (tensor<4x64x64x1xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<1x128x128x1xf32>
func.return %4 : tensor<1x128x128x1xf32>
// CHECK-LABEL: testDilatedConvWithDifferentExpandSqueezeAxis
// CHECK: [[STB:%.*]] = "tf.SpaceToBatchND"
// CHECK-NEXT: [[EXPAND:%.*]] = "tf.ExpandDims"
// CHECK-NEXT: [[CONV:%.*]] = "tf.Conv2D"
// CHECK-NEXT: [[SQUEEZE:%.*]] = "tf.Squeeze"
// CHECK-NEXT: [[RESULT:%.*]] = "tf.BatchToSpaceND"
// CHECK-NEXT: return [[RESULT]]
}
func.func @testNoDilatedConvWhenFirstDimIsDynamic(%arg0: tensor<?x128x128x3xf32>, %arg1: tensor<5x5x3x8xf32>) -> tensor<?x128x128x8xf32> {
%cst = arith.constant dense<[2, 2]> : tensor<2xi32>
%cst_0 = arith.constant dense<4> : tensor<2x2xi32>
%cst_1 = arith.constant dense<0> : tensor<2x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %cst, %cst_0) : (tensor<?x128x128x3xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<?x68x68x3xf32>
%1 = "tf.Conv2D"(%0, %arg1) {padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<?x68x68x3xf32>, tensor<5x5x3x8xf32>) -> tensor<?x64x64x8xf32>
%2 = "tf.BatchToSpaceND"(%1, %cst, %cst_1) : (tensor<?x64x64x8xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<?x128x128x8xf32>
func.return %2 : tensor<?x128x128x8xf32>
// CHECK-LABEL: testNoDilatedConvWhenFirstDimIsDynamic
// CHECK: [[STB:%.*]] = "tf.SpaceToBatchND"
// CHECK-NEXT: [[CONV:%.*]] = "tf.Conv2D"
// CHECK-NEXT: [[RESULT:%.*]] = "tf.BatchToSpaceND"
// CHECK-NEXT: return [[RESULT]]
}
func.func @testNoDilatedConvWhenLastDimIsDynamic(%arg0: tensor<1x128x128x?xf32>, %arg1: tensor<5x5x3x8xf32>) -> tensor<1x128x128x?xf32> {
%cst = arith.constant dense<[2, 2]> : tensor<2xi32>
%cst_0 = arith.constant dense<4> : tensor<2x2xi32>
%cst_1 = arith.constant dense<0> : tensor<2x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %cst, %cst_0) : (tensor<1x128x128x?xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<4x68x68x?xf32>
%1 = "tf.Conv2D"(%0, %arg1) {padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<4x68x68x?xf32>, tensor<5x5x3x8xf32>) -> tensor<4x64x64x?xf32>
%2 = "tf.BatchToSpaceND"(%1, %cst, %cst_1) : (tensor<4x64x64x?xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<1x128x128x?xf32>
func.return %2 : tensor<1x128x128x?xf32>
// CHECK-LABEL: testNoDilatedConvWhenLastDimIsDynamic
// CHECK: [[STB:%.*]] = "tf.SpaceToBatchND"
// CHECK-NEXT: [[CONV:%.*]] = "tf.Conv2D"
// CHECK-NEXT: [[RESULT:%.*]] = "tf.BatchToSpaceND"
// CHECK-NEXT: return [[RESULT]]
}
func.func @testNoDilatedConvWhenGivenInputIsNonFloatType(%arg0: tensor<1x128x128x3xi32>, %arg1: tensor<5x5x3x8xi32>) -> tensor<1x120x120x8xi32> {
%cst = arith.constant dense<[2, 2]> : tensor<2xi32>
%cst_0 = arith.constant dense<4> : tensor<2x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %cst, %cst_0) : (tensor<1x128x128x3xi32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<4x68x68x3xi32>
%1 = "tf.Conv2D"(%0, %arg1) {padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<4x68x68x3xi32>, tensor<5x5x3x8xi32>) -> tensor<4x64x64x8xi32>
%2 = "tf.BatchToSpaceND"(%1, %cst, %cst_0) : (tensor<4x64x64x8xi32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<1x120x120x8xi32>
func.return %2 : tensor<1x120x120x8xi32>
// CHECK-LABEL: testNoDilatedConvWhenGivenInputIsNonFloatType
// CHECK: [[STB:%.*]] = "tf.SpaceToBatchND"
// CHECK-NEXT: [[CONV:%.*]] = "tf.Conv2D"
// CHECK-NEXT: [[RESULT:%.*]] = "tf.BatchToSpaceND"
// CHECK-NEXT: return [[RESULT]]
}
func.func @testDilatedConv1DExpandH(%arg0: tensor<1x128x3xf32>, %arg1: tensor<1x5x3x8xf32>) -> tensor<1x128x8xf32> {
%cst = "tf.Const"() {value = dense<0> : tensor<1x2xi32>} : () -> tensor<1x2xi32>
%cst_0 = "tf.Const"() {value = dense<-3> : tensor<i32>} : () -> tensor<i32>
%cst_1 = "tf.Const"() {value = dense<2> : tensor<1xi32>} : () -> tensor<1xi32>
%cst_2 = "tf.Const"() {value = dense<4> : tensor<1x2xi32>} : () -> tensor<1x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %cst_1, %cst_2) : (tensor<1x128x3xf32>, tensor<1xi32>, tensor<1x2xi32>) -> tensor<2x68x3xf32>
%1 = "tf.ExpandDims"(%0, %cst_0) : (tensor<2x68x3xf32>, tensor<i32>) -> tensor<2x1x68x3xf32>
%2 = "tf.Conv2D"(%1, %arg1) {padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<2x1x68x3xf32>, tensor<1x5x3x8xf32>) -> tensor<2x1x64x8xf32>
%3 = "tf.Squeeze"(%2) {squeeze_dims = [-3]} : (tensor<2x1x64x8xf32>) -> tensor<2x64x8xf32>
%4 = "tf.BatchToSpaceND"(%3, %cst_1, %cst) : (tensor<2x64x8xf32>, tensor<1xi32>, tensor<1x2xi32>) -> tensor<1x128x8xf32>
func.return %4 : tensor<1x128x8xf32>
// CHECK-LABEL: testDilatedConv1DExpandH
// CHECK-SAME: ([[INPUT:%.*]]: tensor<1x128x3xf32>, [[FILTER:%.*]]: tensor<1x5x3x8xf32>)
// CHECK-NEXT: [[AXIS:%.*]] = "tf.Const"() <{value = dense<-3> : tensor<i32>}> : () -> tensor<i32>
// CHECK-NEXT: [[EXPAND:%.*]] = "tf.ExpandDims"([[INPUT]], [[AXIS]]) : (tensor<1x128x3xf32>, tensor<i32>) -> tensor<1x1x128x3xf32>
// CHECK-NEXT: [[CONV:%.*]] = "tf.Conv2D"([[EXPAND]], [[FILTER]]) <{dilations = [1, 1, 2, 1], padding = "SAME", strides = [1, 1, 1, 1]}> : (tensor<1x1x128x3xf32>, tensor<1x5x3x8xf32>) -> tensor<1x1x128x8xf32>
// CHECK-NEXT: [[RESULT:%.*]] = "tf.Squeeze"([[CONV]]) <{squeeze_dims = [-3]}> : (tensor<1x1x128x8xf32>) -> tensor<1x128x8xf32>
// CHECK-NEXT: return [[RESULT]] : tensor<1x128x8xf32>
}
func.func @testDilatedConv1DExpandHWithBiasAdd(%arg0: tensor<1x128x3xf32>, %arg1: tensor<1x5x3x8xf32>, %arg2: tensor<8xf32>) -> tensor<1x128x8xf32> {
%cst = "tf.Const"() {value = dense<0> : tensor<1x2xi32>} : () -> tensor<1x2xi32>
%cst_0 = "tf.Const"() {value = dense<-3> : tensor<i32>} : () -> tensor<i32>
%cst_1 = "tf.Const"() {value = dense<2> : tensor<1xi32>} : () -> tensor<1xi32>
%cst_2 = "tf.Const"() {value = dense<4> : tensor<1x2xi32>} : () -> tensor<1x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %cst_1, %cst_2) : (tensor<1x128x3xf32>, tensor<1xi32>, tensor<1x2xi32>) -> tensor<2x68x3xf32>
%1 = "tf.ExpandDims"(%0, %cst_0) : (tensor<2x68x3xf32>, tensor<i32>) -> tensor<2x1x68x3xf32>
%2 = "tf.Conv2D"(%1, %arg1) {padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<2x1x68x3xf32>, tensor<1x5x3x8xf32>) -> tensor<2x1x64x8xf32>
%3 = "tf.Squeeze"(%2) {squeeze_dims = [-3]} : (tensor<2x1x64x8xf32>) -> tensor<2x64x8xf32>
%4 = "tf.BatchToSpaceND"(%3, %cst_1, %cst) : (tensor<2x64x8xf32>, tensor<1xi32>, tensor<1x2xi32>) -> tensor<1x128x8xf32>
%5 = "tf.BiasAdd"(%4, %arg2) : (tensor<1x128x8xf32>, tensor<8xf32>) -> tensor<1x128x8xf32>
func.return %5 : tensor<1x128x8xf32>
// CHECK-LABEL: testDilatedConv1DExpandHWithBiasAdd
// CHECK-SAME: ([[INPUT:%.*]]: tensor<1x128x3xf32>, [[FILTER:%.*]]: tensor<1x5x3x8xf32>, [[BIAS:%.*]]: tensor<8xf32>)
// CHECK-NEXT: [[AXIS:%.*]] = "tf.Const"() <{value = dense<-3> : tensor<i32>}> : () -> tensor<i32>
// CHECK-NEXT: [[EXPAND:%.*]] = "tf.ExpandDims"([[INPUT]], [[AXIS]]) : (tensor<1x128x3xf32>, tensor<i32>) -> tensor<1x1x128x3xf32>
// CHECK-NEXT: [[CONV:%.*]] = "tf.Conv2D"([[EXPAND]], [[FILTER]]) <{dilations = [1, 1, 2, 1], padding = "SAME", strides = [1, 1, 1, 1]}> : (tensor<1x1x128x3xf32>, tensor<1x5x3x8xf32>) -> tensor<1x1x128x8xf32>
// CHECK-NEXT: [[SQUEEZE:%.*]] = "tf.Squeeze"([[CONV]]) <{squeeze_dims = [-3]}> : (tensor<1x1x128x8xf32>) -> tensor<1x128x8xf32>
// CHECK-NEXT: [[RESULT:%.*]] = "tf.BiasAdd"([[SQUEEZE]], [[BIAS]]) : (tensor<1x128x8xf32>, tensor<8xf32>) -> tensor<1x128x8xf32>
// CHECK-NEXT: return [[RESULT]] : tensor<1x128x8xf32>
}
func.func @testDilatedConv1DExpandW(%arg0: tensor<1x128x3xf32>, %arg1: tensor<5x1x3x8xf32>) -> tensor<1x128x8xf32> {
%cst = "tf.Const"() {value = dense<0> : tensor<1x2xi32>} : () -> tensor<1x2xi32>
%cst_0 = "tf.Const"() {value = dense<-2> : tensor<i32>} : () -> tensor<i32>
%cst_1 = "tf.Const"() {value = dense<2> : tensor<1xi32>} : () -> tensor<1xi32>
%cst_2 = "tf.Const"() {value = dense<4> : tensor<1x2xi32>} : () -> tensor<1x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %cst_1, %cst_2) : (tensor<1x128x3xf32>, tensor<1xi32>, tensor<1x2xi32>) -> tensor<2x68x3xf32>
%1 = "tf.ExpandDims"(%0, %cst_0) : (tensor<2x68x3xf32>, tensor<i32>) -> tensor<2x68x1x3xf32>
%2 = "tf.Conv2D"(%1, %arg1) {padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<2x68x1x3xf32>, tensor<5x1x3x8xf32>) -> tensor<2x64x1x8xf32>
%3 = "tf.Squeeze"(%2) {squeeze_dims = [-2]} : (tensor<2x64x1x8xf32>) -> tensor<2x64x8xf32>
%4 = "tf.BatchToSpaceND"(%3, %cst_1, %cst) : (tensor<2x64x8xf32>, tensor<1xi32>, tensor<1x2xi32>) -> tensor<1x128x8xf32>
func.return %4 : tensor<1x128x8xf32>
// CHECK-LABEL: testDilatedConv1DExpandW
// CHECK-SAME: ([[INPUT:%.*]]: tensor<1x128x3xf32>, [[FILTER:%.*]]: tensor<5x1x3x8xf32>)
// CHECK-NEXT: [[AXIS:%.*]] = "tf.Const"() <{value = dense<-2> : tensor<i32>}> : () -> tensor<i32>
// CHECK-NEXT: [[EXPAND:%.*]] = "tf.ExpandDims"([[INPUT]], [[AXIS]]) : (tensor<1x128x3xf32>, tensor<i32>) -> tensor<1x128x1x3xf32>
// CHECK-NEXT: [[CONV:%.*]] = "tf.Conv2D"([[EXPAND]], [[FILTER]]) <{dilations = [1, 2, 1, 1], padding = "SAME", strides = [1, 1, 1, 1]}> : (tensor<1x128x1x3xf32>, tensor<5x1x3x8xf32>) -> tensor<1x128x1x8xf32>
// CHECK-NEXT: [[RESULT:%.*]] = "tf.Squeeze"([[CONV]]) <{squeeze_dims = [-2]}> : (tensor<1x128x1x8xf32>) -> tensor<1x128x8xf32>
// CHECK-NEXT: return [[RESULT]] : tensor<1x128x8xf32>
}
func.func @testDilatedConv1DExpandWWithBiasAdd(%arg0: tensor<1x128x3xf32>, %arg1: tensor<5x1x3x8xf32>, %arg2: tensor<8xf32>) -> tensor<1x128x8xf32> {
%cst = "tf.Const"() {value = dense<0> : tensor<1x2xi32>} : () -> tensor<1x2xi32>
%cst_0 = "tf.Const"() {value = dense<-2> : tensor<i32>} : () -> tensor<i32>
%cst_1 = "tf.Const"() {value = dense<2> : tensor<1xi32>} : () -> tensor<1xi32>
%cst_2 = "tf.Const"() {value = dense<4> : tensor<1x2xi32>} : () -> tensor<1x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %cst_1, %cst_2) : (tensor<1x128x3xf32>, tensor<1xi32>, tensor<1x2xi32>) -> tensor<2x68x3xf32>
%1 = "tf.ExpandDims"(%0, %cst_0) : (tensor<2x68x3xf32>, tensor<i32>) -> tensor<2x68x1x3xf32>
%2 = "tf.Conv2D"(%1, %arg1) {padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<2x68x1x3xf32>, tensor<5x1x3x8xf32>) -> tensor<2x64x1x8xf32>
%3 = "tf.Squeeze"(%2) {squeeze_dims = [-2]} : (tensor<2x64x1x8xf32>) -> tensor<2x64x8xf32>
%4 = "tf.BatchToSpaceND"(%3, %cst_1, %cst) : (tensor<2x64x8xf32>, tensor<1xi32>, tensor<1x2xi32>) -> tensor<1x128x8xf32>
%5 = "tf.BiasAdd"(%4, %arg2) : (tensor<1x128x8xf32>, tensor<8xf32>) -> tensor<1x128x8xf32>
func.return %5 : tensor<1x128x8xf32>
// CHECK-LABEL: testDilatedConv1DExpandWWithBiasAdd
// CHECK-SAME: ([[INPUT:%.*]]: tensor<1x128x3xf32>, [[FILTER:%.*]]: tensor<5x1x3x8xf32>, [[BIAS:%.*]]: tensor<8xf32>)
// CHECK-NEXT: [[AXIS:%.*]] = "tf.Const"() <{value = dense<-2> : tensor<i32>}> : () -> tensor<i32>
// CHECK-NEXT: [[EXPAND:%.*]] = "tf.ExpandDims"([[INPUT]], [[AXIS]]) : (tensor<1x128x3xf32>, tensor<i32>) -> tensor<1x128x1x3xf32>
// CHECK-NEXT: [[CONV:%.*]] = "tf.Conv2D"([[EXPAND]], [[FILTER]]) <{dilations = [1, 2, 1, 1], padding = "SAME", strides = [1, 1, 1, 1]}> : (tensor<1x128x1x3xf32>, tensor<5x1x3x8xf32>) -> tensor<1x128x1x8xf32>
// CHECK-NEXT: [[SQUEEZE:%.*]] = "tf.Squeeze"([[CONV]]) <{squeeze_dims = [-2]}> : (tensor<1x128x1x8xf32>) -> tensor<1x128x8xf32>
// CHECK-NEXT: [[RESULT:%.*]] = "tf.BiasAdd"([[SQUEEZE]], [[BIAS]]) : (tensor<1x128x8xf32>, tensor<8xf32>) -> tensor<1x128x8xf32>
// CHECK-NEXT: return [[RESULT]] : tensor<1x128x8xf32>
}
func.func @testDilatedConv1DWithMixedPostiveAndNegativeAxis(%arg0: tensor<1x128x3xf32>, %arg1: tensor<1x5x3x8xf32>) -> tensor<1x128x8xf32> {
%cst = "tf.Const"() {value = dense<0> : tensor<1x2xi32>} : () -> tensor<1x2xi32>
%cst_0 = "tf.Const"() {value = dense<1> : tensor<i32>} : () -> tensor<i32>
%cst_1 = "tf.Const"() {value = dense<2> : tensor<1xi32>} : () -> tensor<1xi32>
%cst_2 = "tf.Const"() {value = dense<4> : tensor<1x2xi32>} : () -> tensor<1x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %cst_1, %cst_2) : (tensor<1x128x3xf32>, tensor<1xi32>, tensor<1x2xi32>) -> tensor<2x68x3xf32>
%1 = "tf.ExpandDims"(%0, %cst_0) : (tensor<2x68x3xf32>, tensor<i32>) -> tensor<2x1x68x3xf32>
%2 = "tf.Conv2D"(%1, %arg1) {padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<2x1x68x3xf32>, tensor<1x5x3x8xf32>) -> tensor<2x1x64x8xf32>
%3 = "tf.Squeeze"(%2) {squeeze_dims = [-3]} : (tensor<2x1x64x8xf32>) -> tensor<2x64x8xf32>
%4 = "tf.BatchToSpaceND"(%3, %cst_1, %cst) : (tensor<2x64x8xf32>, tensor<1xi32>, tensor<1x2xi32>) -> tensor<1x128x8xf32>
func.return %4 : tensor<1x128x8xf32>
// CHECK-LABEL: testDilatedConv1DWithMixedPostiveAndNegativeAxis
// CHECK-SAME: ([[INPUT:%.*]]: tensor<1x128x3xf32>, [[FILTER:%.*]]: tensor<1x5x3x8xf32>)
// CHECK-NEXT: [[AXIS:%.*]] = "tf.Const"() <{value = dense<1> : tensor<i32>}> : () -> tensor<i32>
// CHECK-NEXT: [[EXPAND:%.*]] = "tf.ExpandDims"([[INPUT]], [[AXIS]]) : (tensor<1x128x3xf32>, tensor<i32>) -> tensor<1x1x128x3xf32>
// CHECK-NEXT: [[CONV:%.*]] = "tf.Conv2D"([[EXPAND]], [[FILTER]]) <{dilations = [1, 1, 2, 1], padding = "SAME", strides = [1, 1, 1, 1]}> : (tensor<1x1x128x3xf32>, tensor<1x5x3x8xf32>) -> tensor<1x1x128x8xf32>
// CHECK-NEXT: [[RESULT:%.*]] = "tf.Squeeze"([[CONV]]) <{squeeze_dims = [-3]}> : (tensor<1x1x128x8xf32>) -> tensor<1x128x8xf32>
// CHECK-NEXT: return [[RESULT]] : tensor<1x128x8xf32>
}
func.func @testPaddedDilatedConv(%arg0 : tensor<2x1920x64xf32>) -> tensor<2x1920x128xf32> {
%0 = "tf.Const"() {value = dense<[[0, 0], [2, 0], [0, 0]]> : tensor<3x2xi32>} : () -> tensor<3x2xi32>
%1 = "tf.Const"() {value = dense<2> : tensor<1xi32>} : () -> tensor<1xi32>
%2 = "tf.Const"() {value = dense<2> : tensor<i32>} : () -> tensor<i32>
%3 = "tf.Const"() {value = dense<0> : tensor<1x2xi32>} : () -> tensor<1x2xi32>
%4 = "tf.Const"() {value = dense<0.0> : tensor<3x1x64x128xf32>} : () -> tensor<3x1x64x128xf32>
%5 = "tf.SpaceToBatchND"(%arg0, %1, %3) {device = ""} : (tensor<2x1920x64xf32>, tensor<1xi32>, tensor<1x2xi32>) -> tensor<4x960x64xf32>
%6 = "tf.ExpandDims"(%5, %2) {device = ""} : (tensor<4x960x64xf32>, tensor<i32>) -> tensor<4x960x1x64xf32>
%7 = "tf.Conv2D"(%6, %4) {data_format = "NHWC", device = "", dilations = [1, 1, 1, 1], explicit_paddings = [], padding = "VALID", strides = [1, 1, 1, 1], use_cudnn_on_gpu = true} : (tensor<4x960x1x64xf32>, tensor<3x1x64x128xf32>) -> tensor<4x958x1x128xf32>
%8 = "tf.Squeeze"(%7) {device = "", squeeze_dims = [2]} : (tensor<4x958x1x128xf32>) -> tensor<4x958x128xf32>
%9 = "tf.Pad"(%8, %0) {device = ""} : (tensor<4x958x128xf32>, tensor<3x2xi32>) -> tensor<4x960x128xf32>
%10 = "tf.BatchToSpaceND"(%9, %1, %3) {device = ""} : (tensor<4x960x128xf32>, tensor<1xi32>, tensor<1x2xi32>) -> tensor<2x1920x128xf32>
func.return %10 : tensor<2x1920x128xf32>
// CHECK-LABEL: testPaddedDilatedConv
// CHECK-SAME: ([[INPUT:%.*]]: tensor<2x1920x64xf32>)
// CHECK-NEXT: [[AXIS:%.*]] = "tf.Const"() <{value = dense<2> : tensor<i32>}> : () -> tensor<i32>
// CHECK-NEXT: [[FILTER:%.*]] = "tf.Const"() <{value = dense<0.000000e+00> : tensor<3x1x64x128xf32>}> : () -> tensor<3x1x64x128xf32>
// CHECK-NEXT: [[EXPAND:%.*]] = "tf.ExpandDims"([[INPUT]], [[AXIS]]) {device = ""} : (tensor<2x1920x64xf32>, tensor<i32>) -> tensor<2x1920x1x64xf32>
// CHECK-NEXT: [[CONV:%.*]] = "tf.Conv2D"([[EXPAND]], [[FILTER]]) <{data_format = "NHWC", dilations = [1, 2, 1, 1], explicit_paddings = [], padding = "SAME", strides = [1, 1, 1, 1], use_cudnn_on_gpu = true}> {device = ""} : (tensor<2x1920x1x64xf32>, tensor<3x1x64x128xf32>) -> tensor<2x1920x1x128xf32>
// CHECK-NEXT: [[RESULT:%.*]] = "tf.Squeeze"([[CONV]]) <{squeeze_dims = [2]}> {device = ""} : (tensor<2x1920x1x128xf32>) -> tensor<2x1920x128xf32>
// CHECK-NEXT: return [[RESULT]] : tensor<2x1920x128xf32>
}
func.func @testDilatedConvInterleaved(%arg0: tensor<1x128x128x3xf32>, %arg1: tensor<5x5x3x8xf32>) -> (tensor<1x120x120x8xf32>, tensor<1x120x120x8xf32>) {
%cst = arith.constant dense<[2, 2]> : tensor<2xi32>
%cst_0 = arith.constant dense<4> : tensor<2x2xi32>
%0 = "tf.SpaceToBatchND"(%arg0, %cst, %cst_0) : (tensor<1x128x128x3xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<4x68x68x3xf32>
%1 = "tf.SpaceToBatchND"(%arg0, %cst, %cst_0) : (tensor<1x128x128x3xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<4x68x68x3xf32>
%2 = "tf.Conv2D"(%0, %arg1) {padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<4x68x68x3xf32>, tensor<5x5x3x8xf32>) -> tensor<4x64x64x8xf32>
%3 = "tf.Conv2D"(%1, %arg1) {padding = "VALID", strides = [1, 1, 1, 1]} : (tensor<4x68x68x3xf32>, tensor<5x5x3x8xf32>) -> tensor<4x64x64x8xf32>
%4 = "tf.BatchToSpaceND"(%2, %cst, %cst_0) : (tensor<4x64x64x8xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<1x120x120x8xf32>
%5 = "tf.BatchToSpaceND"(%3, %cst, %cst_0) : (tensor<4x64x64x8xf32>, tensor<2xi32>, tensor<2x2xi32>) -> tensor<1x120x120x8xf32>
func.return %4, %5: tensor<1x120x120x8xf32>, tensor<1x120x120x8xf32>
// CHECK-LABEL: testDilatedConvInterleaved
// CHECK-SAME: ([[INPUT:%.*]]: tensor<1x128x128x3xf32>, [[FILTER:%.*]]: tensor<5x5x3x8xf32>)
// CHECK-NEXT: [[RESULT0:%.*]] = "tf.Conv2D"([[INPUT]], [[FILTER]]) <{dilations = [1, 2, 2, 1], padding = "VALID", strides = [1, 1, 1, 1]}> : (tensor<1x128x128x3xf32>, tensor<5x5x3x8xf32>) -> tensor<1x120x120x8xf32>
// CHECK-NEXT: [[RESULT1:%.*]] = "tf.Conv2D"([[INPUT]], [[FILTER]]) <{dilations = [1, 2, 2, 1], padding = "VALID", strides = [1, 1, 1, 1]}> : (tensor<1x128x128x3xf32>, tensor<5x5x3x8xf32>) -> tensor<1x120x120x8xf32>
// CHECK-NEXT: return [[RESULT0]], [[RESULT1]] : tensor<1x120x120x8xf32>, tensor<1x120x120x8xf32>
}
@@ -0,0 +1,46 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: litert-opt %s --tfl-downcast-x64 --canonicalize | FileCheck %s
// CHECK-LABEL: testFuncSignature
// CHECK: (%arg0: tensor<4xi32>, %arg1: tensor<2x2xf32>) -> tensor<2x2xf32>
func.func @testFuncSignature(%arg0: tensor<4xi64>, %arg1: tensor<2x2xf64>) -> tensor<2x2xf64> {
// CHECK: return %arg1 : tensor<2x2xf32>
func.return %arg1 : tensor<2x2xf64>
}
// CHECK-LABEL: testConstantDowncast
func.func @testConstantDowncast() -> tensor<2xf64> {
// CHECK: %[[CST:.*]] = arith.constant dense<[1.000000e+00, 2.000000e+00]> : tensor<2xf32>
// CHECK: return %[[CST]]
%0 = arith.constant dense<[1.0, 2.0]> : tensor<2xf64>
func.return %0 : tensor<2xf64>
}
// CHECK-LABEL: testI64ConstantDowncast
func.func @testI64ConstantDowncast() -> tensor<i64> {
// CHECK: %[[CST:.*]] = arith.constant dense<42> : tensor<i32>
// CHECK: return %[[CST]]
%0 = arith.constant dense<42> : tensor<i64>
func.return %0 : tensor<i64>
}
// CHECK-LABEL: testGeneralOpForceConvert
func.func @testGeneralOpForceConvert(%arg0: tensor<2xf64>) -> tensor<2xf64> {
// CHECK: %[[ADD:.*]] = tfl.add %arg0, %arg0 {fused_activation_function = "NONE"} : tensor<2xf32>
// CHECK: return %[[ADD]]
%0 = "tfl.add"(%arg0, %arg0) {fused_activation_function = "NONE"} : (tensor<2xf64>, tensor<2xf64>) -> tensor<2xf64>
func.return %0 : tensor<2xf64>
}
@@ -0,0 +1,61 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: litert-opt %s --tfl-dense-to-dense-resource-elements | env FILECHECK_OPTS="" FileCheck %s
// RUN: litert-opt %s --tfl-dense-to-dense-resource-elements | litert-opt --tfl-dense-resource-to-dense-elements | env FILECHECK_OPTS="" FileCheck %s --check-prefix=ROUNDTRIP
// CHECK-LABEL: @test_f32
// ROUNDTRIP-LABEL: @test_f32
func.func @test_f32() -> tensor<4xf32> {
// CHECK: arith.constant dense_resource<dense_elements_f32> : tensor<4xf32>
// ROUNDTRIP: arith.constant dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00]> : tensor<4xf32>
%0 = arith.constant dense<[1.0, 2.0, 3.0, 4.0]> : tensor<4xf32>
func.return %0 : tensor<4xf32>
}
// CHECK-LABEL: @test_i32
// ROUNDTRIP-LABEL: @test_i32
func.func @test_i32() -> tensor<4xi32> {
// CHECK: arith.constant dense_resource<dense_elements_i32> : tensor<4xi32>
// ROUNDTRIP: arith.constant dense<[1, 2, 3, 4]> : tensor<4xi32>
%0 = arith.constant dense<[1, 2, 3, 4]> : tensor<4xi32>
func.return %0 : tensor<4xi32>
}
// CHECK-LABEL: @test_i1
// ROUNDTRIP-LABEL: @test_i1
func.func @test_i1() -> tensor<4xi1> {
// CHECK: arith.constant dense_resource<dense_elements_i1> : tensor<4xi1>
// ROUNDTRIP: arith.constant dense<[true, false, true, false]> : tensor<4xi1>
%0 = arith.constant dense<[true, false, true, false]> : tensor<4xi1>
func.return %0 : tensor<4xi1>
}
// CHECK-LABEL: @test_i64
// ROUNDTRIP-LABEL: @test_i64
func.func @test_i64() -> tensor<2xi64> {
// CHECK: arith.constant dense_resource<dense_elements_i64> : tensor<2xi64>
// ROUNDTRIP: arith.constant dense<[9223372036854775807, -9223372036854775808]> : tensor<2xi64>
%0 = arith.constant dense<[9223372036854775807, -9223372036854775808]> : tensor<2xi64>
func.return %0 : tensor<2xi64>
}
// CHECK-LABEL: @test_f64
// ROUNDTRIP-LABEL: @test_f64
func.func @test_f64() -> tensor<2xf64> {
// CHECK: arith.constant dense_resource<dense_elements_f64> : tensor<2xf64>
// ROUNDTRIP: arith.constant dense<[1.234567, 0.89101112000000005]> : tensor<2xf64>
%0 = arith.constant dense<[1.234567, 0.89101112]> : tensor<2xf64>
func.return %0 : tensor<2xf64>
}
@@ -0,0 +1,45 @@
load("//tensorflow:tensorflow.default.bzl", "filegroup")
load("//tensorflow/compiler/mlir:glob_lit_test.bzl", "glob_lit_tests")
# copybara:uncomment package(default_applicable_licenses = ["//tensorflow:LICENSE"])
licenses(["notice"])
glob_lit_tests(
name = "all_tests",
data = [
":quant_stats_files",
":test_utilities",
],
driver = "@llvm-project//mlir:run_lit.sh",
size_override = {
"quant_stats.pbtxt": "medium",
},
tags_override = {
"add.pbtxt": ["no_rocm"],
"fake_quant_per_channel.pbtxt": ["no_rocm"],
},
test_file_exts = [
"pbtxt",
],
)
# Bundle together all of the test utilities that are used by tests.
filegroup(
name = "test_utilities",
testonly = True,
data = [
"//tensorflow/compiler/mlir/lite:flatbuffer_to_string",
"//tensorflow/compiler/mlir/lite:tf_tfl_translate",
"@llvm-project//llvm:FileCheck",
"@llvm-project//llvm:not",
],
)
# Bundle together all the quant stats files that are used by the tests.
filegroup(
name = "quant_stats_files",
srcs = glob(
["**/*.stats"],
),
)
@@ -0,0 +1,104 @@
# RUN: tf_tfl_translate -tf-input-arrays=input0,input1 -tf-input-shapes=4:4 -tf-input-data-types=DT_INT32,DT_INT32 -tf-output-arrays=Add %s -o - | flatbuffer_to_string - | FileCheck %s
# Add two tensor<4xi32> inputs and return the result
node {
name: "Add"
op: "Add"
input: "input0"
input: "input1"
attr {
key: "T"
value {
type: DT_INT32
}
}
}
node {
name: "input0"
op: "Placeholder"
attr {
key: "dtype"
value {
type: DT_INT32
}
}
}
node {
name: "input1"
op: "Placeholder"
attr {
key: "dtype"
value {
type: DT_INT32
}
}
}
versions {
producer: 27
}
# CHECK: {
# CHECK-NEXT: version: 3,
# CHECK-NEXT: operator_codes: [ {
# CHECK-NEXT: version: 1
# CHECK-NEXT: } ],
# CHECK-NEXT: subgraphs: [ {
# CHECK-NEXT: tensors: [ {
# CHECK-NEXT: shape: [ 4 ],
# CHECK-NEXT: type: INT32,
# CHECK-NEXT: buffer: 1,
# CHECK-NEXT: name: "input0",
# CHECK-NEXT: quantization: {
# CHECK-EMPTY:
# CHECK-NEXT: },
# CHECK-NEXT: has_rank: true
# CHECK-NEXT: }, {
# CHECK-NEXT: shape: [ 4 ],
# CHECK-NEXT: type: INT32,
# CHECK-NEXT: buffer: 2,
# CHECK-NEXT: name: "input1",
# CHECK-NEXT: quantization: {
# CHECK-EMPTY:
# CHECK-NEXT: },
# CHECK-NEXT: has_rank: true
# CHECK-NEXT: }, {
# CHECK-NEXT: shape: [ 4 ],
# CHECK-NEXT: type: INT32,
# CHECK-NEXT: buffer: 3,
# CHECK-NEXT: name: "Add",
# CHECK-NEXT: quantization: {
# CHECK-EMPTY:
# CHECK-NEXT: },
# CHECK-NEXT: has_rank: true
# CHECK-NEXT: } ],
# CHECK-NEXT: inputs: [ 0, 1 ],
# CHECK-NEXT: outputs: [ 2 ],
# CHECK-NEXT: operators: [ {
# CHECK-NEXT: inputs: [ 0, 1 ],
# CHECK-NEXT: outputs: [ 2 ],
# CHECK-NEXT: builtin_options_type: AddOptions,
# CHECK-NEXT: builtin_options: {
# CHECK-EMPTY:
# CHECK-NEXT: }
# CHECK-NEXT: } ]
# CHECK-NEXT: name: "main"
# CHECK-NEXT: } ],
# CHECK-NEXT: description: "MLIR Converted.",
# CHECK-NEXT: buffers: [ {
# CHECK-EMPTY:
# CHECK-NEXT: }, {
# CHECK-EMPTY:
# CHECK-NEXT: }, {
# CHECK-EMPTY:
# CHECK-NEXT: }, {
# CHECK-EMPTY:
# CHECK-NEXT: }, {
# CHECK-NEXT: data: [ 49, 46, 53, 46, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
# CHECK-NEXT: } ],
# CHECK-NEXT: metadata: [ {
# CHECK-NEXT: name: "min_runtime_version",
# CHECK-NEXT: buffer: 4
# CHECK-NEXT: } ],
# CHECK-NEXT: signature_defs: [ ]
# CHECK-NEXT: }
@@ -0,0 +1,257 @@
# RUN: not tf_tfl_translate -tf-upgrade-legacy=false -tf-input-arrays=Placeholder,Placeholder_1 -tf-input-shapes=1,2:1 -tf-output-arrays=cond/Merge -tf-enable-shape-inference-on-import=false -mlir-print-debuginfo -output-mlir %s -o - 2>&1 | FileCheck %s
# CHECK: error: The graph has Control Flow V1 ops. TFLite converter doesn't support Control Flow V1 ops. Consider using Control Flow V2 ops instead.
node {
name: "Const"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
dim {
size: 2
}
dim {
size: 2
}
}
tensor_content: "\315\314\314=\315\314L>\232\231\231>\315\314\314>"
}
}
}
}
node {
name: "Placeholder"
op: "Placeholder"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "shape"
value {
shape {
dim {
size: -1
}
dim {
size: 2
}
}
}
}
}
node {
name: "Placeholder_1"
op: "Placeholder"
attr {
key: "dtype"
value {
type: DT_BOOL
}
}
attr {
key: "shape"
value {
shape {
}
}
}
}
node {
name: "cond/Switch"
op: "Switch"
input: "Placeholder_1"
input: "Placeholder_1"
attr {
key: "T"
value {
type: DT_BOOL
}
}
}
node {
name: "cond/switch_t"
op: "Identity"
input: "cond/Switch:1"
attr {
key: "T"
value {
type: DT_BOOL
}
}
}
node {
name: "cond/switch_f"
op: "Identity"
input: "cond/Switch"
attr {
key: "T"
value {
type: DT_BOOL
}
}
}
node {
name: "cond/pred_id"
op: "Identity"
input: "Placeholder_1"
attr {
key: "T"
value {
type: DT_BOOL
}
}
}
node {
name: "cond/MatMul"
op: "MatMul"
input: "cond/MatMul/Switch:1"
input: "cond/MatMul/Switch_1:1"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "transpose_a"
value {
b: false
}
}
attr {
key: "transpose_b"
value {
b: false
}
}
}
node {
name: "cond/MatMul/Switch"
op: "Switch"
input: "Placeholder"
input: "cond/pred_id"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@Placeholder"
}
}
}
}
node {
name: "cond/MatMul/Switch_1"
op: "Switch"
input: "Const"
input: "cond/pred_id"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@Const"
}
}
}
}
node {
name: "cond/Add"
op: "Add"
input: "cond/Add/Switch"
input: "cond/Add/Switch_1"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
}
node {
name: "cond/Add/Switch"
op: "Switch"
input: "Placeholder"
input: "cond/pred_id"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@Placeholder"
}
}
}
}
node {
name: "cond/Add/Switch_1"
op: "Switch"
input: "Const"
input: "cond/pred_id"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@Const"
}
}
}
}
node {
name: "cond/Merge"
op: "Merge"
input: "cond/Add"
input: "cond/MatMul"
attr {
key: "N"
value {
i: 2
}
}
attr {
key: "T"
value {
type: DT_FLOAT
}
}
}
node {
name: "init"
op: "NoOp"
}
versions {
producer: 134
}
@@ -0,0 +1,47 @@
# RUN: tf_tfl_translate -tf-input-arrays=input0,input1 -tf-input-shapes=4:4 -tf-input-data-types=DT_INT32,DT_INT32 -tf-output-arrays=output %s -o - --output-mlir -tf-custom-opdefs="name: 'BannaPotatoSaladWithColeslaw' input_arg: { name: 'a' type: DT_INT32 } input_arg: { name: 'b' type: DT_INT32 } output_arg: { name: 'c' type: DT_INT32 }" | FileCheck %s
node {
name: "output"
op: "BannaPotatoSaladWithColeslaw"
input: "input0"
input: "input1"
attr {
key: "T"
value {
type: DT_INT32
}
}
}
node {
name: "input0"
op: "Placeholder"
attr {
key: "dtype"
value {
type: DT_INT32
}
}
}
node {
name: "input1"
op: "Placeholder"
attr {
key: "dtype"
value {
type: DT_INT32
}
}
}
versions {
producer: 27
}
# CHECK-LABEL: func @main(%arg0: tensor<4xi32>, %arg1: tensor<4xi32>) -> tensor<*xi32>
# CHECK: attributes {tf.entry_function = {control_outputs = "", inputs = "input0,input1", outputs = "output"}} {
# CHECK-NEXT: %[[CUSTOM:.*]] = "tfl.custom_tf"(%arg0, %arg1) ({
# CHECK-NEXT: ^bb0(%arg2: tensor<4xi32>, %arg3: tensor<4xi32>):
# CHECK-NEXT: %[[OUTPUTS:.*]] = "tf.BannaPotatoSaladWithColeslaw"(%arg2, %arg3) {T = i32, device = ""} : (tensor<4xi32>, tensor<4xi32>) -> tensor<*xi32>
# CHECK-NEXT: "tfl.yield"(%[[OUTPUTS]]) : (tensor<*xi32>) -> ()
# CHECK-NEXT: }) {T = i32, device = ""} : (tensor<4xi32>, tensor<4xi32>) -> tensor<*xi32>
# CHECK-NEXT: return %[[CUSTOM]] : tensor<*xi32>
# CHECK-NEXT: }
@@ -0,0 +1,195 @@
# RUN: not tf_tfl_translate -tf-input-arrays=input0 -tf-input-shapes=-1 -tf-input-data-types=DT_FLOAT -tf-output-arrays=add %s 2>&1 | FileCheck %s
# CHECK: error: The Graph contains unsupported `StatefulPartionedCallOp`(s)
node {
name: "input0"
op: "Placeholder"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
}
node {
name: "args_0"
op: "_Arg"
attr {
key: "T"
value {
type: DT_RESOURCE
}
}
attr {
key: "index"
value {
i: 0
}
}
}
node {
name: "spc1"
op: "StatefulPartitionedCall"
input: "input0"
input: "args_0"
attr {
key: "Tin"
value {
list {
type: DT_FLOAT
type: DT_RESOURCE
}
}
}
attr {
key: "Tout"
value {
list {
type: DT_FLOAT
type: DT_RESOURCE
}
}
}
attr {
key: "config"
value {
s: ""
}
}
attr {
key: "config_proto"
value {
s: ""
}
}
attr {
key: "executor_type"
value {
s: ""
}
}
attr {
key: "f"
value {
func {
name: "function"
}
}
}
}
node {
name: "spc2"
op: "StatefulPartitionedCall"
input: "input0"
input: "args_0"
attr {
key: "Tin"
value {
list {
type: DT_FLOAT
type: DT_RESOURCE
}
}
}
attr {
key: "Tout"
value {
list {
type: DT_FLOAT
type: DT_RESOURCE
}
}
}
attr {
key: "config"
value {
s: ""
}
}
attr {
key: "config_proto"
value {
s: ""
}
}
attr {
key: "executor_type"
value {
s: ""
}
}
attr {
key: "f"
value {
func {
name: "function"
}
}
}
}
node {
name: "add"
op: "Add"
input: "spc1"
input: "spc2"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
}
library {
function {
signature {
name: "function"
input_arg {
name: "inputs"
type: DT_FLOAT
}
input_arg {
name: "statefulpartitionedcall_args_1"
type: DT_RESOURCE
}
output_arg {
name: "identity"
type: DT_FLOAT
}
is_stateful: true
}
node_def {
name: "Identity"
op: "Identity"
input: "inputs"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
}
ret {
key: "identity"
value: "Identity:output:0"
}
arg_attr {
key: 0
value {
attr {
key: "_user_specified_name"
value {
s: "inputs"
}
}
}
}
arg_attr {
key: 1
value {
}
}
}
}
versions {
producer: 121
}
@@ -0,0 +1,559 @@
# RUN: tf_tfl_translate -tf-input-arrays=input -tf-input-shapes=1,1,1,256 -tf-input-data-types=DT_FLOAT -tf-inference-type=DT_QINT8 -tf-input-min-values='-33.614346' -tf-input-max-values='21.54917' -tf-output-arrays=output %s -o - --output-mlir 2>&1 | FileCheck --check-prefix=MLIR %s
# TODO(fengliuai): Figure out what to do here. A "golden" end-to-end test is overly fragile.
# DISABLED_RUN: true || tf_tfl_translate -tf-input-arrays=input -tf-input-shapes=1,1,1,256 -tf-input-data-types=DT_FLOAT -tf-inference-type=DT_QINT8 -tf-input-min-values='-33.614346' -tf-input-max-values='21.54917' -tf-output-arrays=output %s -o - | flatbuffer_to_string - | FileCheck %s
node {
name: "input"
op: "Placeholder"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "shape"
value {
shape {
dim {
size: 1
}
dim {
size: 1
}
dim {
size: 1
}
dim {
size: 256
}
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/weights"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
dim {
size: 1
}
dim {
size: 1
}
dim {
size: 256
}
dim {
size: 186
}
}
float_val: 1.0
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/weights/read"
op: "Identity"
input: "BoxPredictor_4/ClassPredictor/weights"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@BoxPredictor_4/ClassPredictor/weights"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/weights_quant/min"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
dim {
size: 186
}
}
tensor_content: "\217\245\177\301\005@d\276C\030x\276S\320\177\276.\227q\277\260]\223\276j\016\250\276\305\017\202\276\200+\201\276\275\377\177\276\310&\202\276\314\210k\276\3178W\277\335\356_\276\332GG\276`\200>\276o_c\276\312\224k\2767\033S\276M=\376\300y-\271\276\225\021g\276\272lZ\276\353r\251\276\025\354G\276\357\220\\\2765j0\2765Q(\276\013>0\276Y\r\'\276\224\013\"\276G=\377\300\022\211E\276\344\035O\276\242\220l\276w\307\020\2773`\376\276\331\377\202\276\374\016Y\276\224\273^\2767`~\276V\016>\276\226\333g\276*\241K\276\224g\177\276\320\315(\276t\376\177\276B\025B\276@\214\226\276\377s\376\276\373\365\377\277\343\211~\276\205\320b\276\213\236\377\2763\0136\276u\237:\276\325\373~\276\344\r\037\276>\035(\276\247\364!\276\2613%\276\207]!\276\320S\376\301\354 _\276\337PT\276\342\226[\276\304\307\177\276\360\"x\276\312\023\200\276Wfp\2768$W\276\235\014\202\276\230\210m\2761\342L\276b\234\013\277\362XM\276QPL\276\006Va\276\3168>\276\262\367t\276x\252k\276\266\225\231\276z@B\276\244\340?\276>8]\276\214v\206\276\316\210Z\276\275\343U\276\366\0321\276b\2128\276\310\2611\276\340n/\276\312\272\'\276\207\274\207\276tl\034\276\214[\357\275\020\345@\276\1778\376\275\264~#\276\326U*\276\374g\003\276\377\013\000\276\361\375T\276\246\330\007\276\365\203~\276\311\367\033\276\261\240\177\2768`\"\276i\364 \276\321\365\363\275\0241~\276\005\365\376\275S\303\035\277\203\003\020\276\264\322\377\276$\241\177\276\264d\t\276H\000C\276\360/~\276\352\301\377\275\037\300\n\276\0000\033\276r|\377\275\025\004\002\276\276\021\262\276\343\245M\2763\302\351\276LE\005\276\n\"~\276\341q\341\276\265\022~\276\322^\036\276\206\216\031\276\306\n\310\276\322_T\276\367\037w\276\374\227A\276\010\272G\276T&\022\276y\217>\276\275H\033\276\002=\376\276\232x0\276\322C~\276\032\350\212\276\234\322\036\2762%\376\276\266\345#\276.1\021\276\302,\351\276\025x&\276\354\363.\276\362\210\025\276\035\032\036\276\267X\014\276zc\177\300\336L_\276\274,k\276{\266\203\276\366\266~\277\225F\211\276\302~\243\276\253.\214\2765\241l\276g\021\214\276\347\376\177\276H\026T\276\305\220\377\276\000\\Y\276\334\332>\276\224\2459\276\334ja\276\260\313p\276\024\026\\\2769\334\177\301\334\330\222\276\347\376e\276\014\230W\276\253P\252\276i\300C\276\340\261Y\276721\276#k)\276\035.#\276R(0\276\224\336!\276"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/weights_quant/min/read"
op: "Identity"
input: "BoxPredictor_4/ClassPredictor/weights_quant/min"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@BoxPredictor_4/ClassPredictor/weights_quant/min"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/weights_quant/max"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
dim {
size: 186
}
}
tensor_content: "\217\245\177A\005@d>C\030x>S\320\177>.\227q?\260]\223>j\016\250>\305\017\202>\200+\201>\275\377\177>\310&\202>\314\210k>\3178W?\335\356_>\332GG>`\200>>o_c>\312\224k>7\033S>M=\376@y-\271>\225\021g>\272lZ>\353r\251>\025\354G>\357\220\\>5j0>5Q(>\013>0>Y\r\'>\224\013\">G=\377@\022\211E>\344\035O>\242\220l>w\307\020?3`\376>\331\377\202>\374\016Y>\224\273^>7`~>V\016>>\226\333g>*\241K>\224g\177>\320\315(>t\376\177>B\025B>@\214\226>\377s\376>\373\365\377?\343\211~>\205\320b>\213\236\377>3\0136>u\237:>\325\373~>\344\r\037>>\035(>\247\364!>\2613%>\207]!>\320S\376A\354 _>\337PT>\342\226[>\304\307\177>\360\"x>\312\023\200>Wfp>8$W>\235\014\202>\230\210m>1\342L>b\234\013?\362XM>QPL>\006Va>\3168>>\262\367t>x\252k>\266\225\231>z@B>\244\340?>>8]>\214v\206>\316\210Z>\275\343U>\366\0321>b\2128>\310\2611>\340n/>\312\272\'>\207\274\207>tl\034>\214[\357=\020\345@>\1778\376=\264~#>\326U*>\374g\003>\377\013\000>\361\375T>\246\330\007>\365\203~>\311\367\033>\261\240\177>8`\">i\364 >\321\365\363=\0241~>\005\365\376=S\303\035?\203\003\020>\264\322\377>$\241\177>\264d\t>H\000C>\360/~>\352\301\377=\037\300\n>\0000\033>r|\377=\025\004\002>\276\021\262>\343\245M>3\302\351>LE\005>\n\"~>\341q\341>\265\022~>\322^\036>\206\216\031>\306\n\310>\322_T>\367\037w>\374\227A>\010\272G>T&\022>y\217>>\275H\033>\002=\376>\232x0>\322C~>\032\350\212>\234\322\036>2%\376>\266\345#>.1\021>\302,\351>\025x&>\354\363.>\362\210\025>\035\032\036>\267X\014>zc\177@\336L_>\274,k>{\266\203>\366\266~?\225F\211>\302~\243>\253.\214>5\241l>g\021\214>\347\376\177>H\026T>\305\220\377>\000\\Y>\334\332>>\224\2459>\334ja>\260\313p>\024\026\\>9\334\177A\334\330\222>\347\376e>\014\230W>\253P\252>i\300C>\340\261Y>721>#k)>\035.#>R(0>\224\336!>"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/weights_quant/max/read"
op: "Identity"
input: "BoxPredictor_4/ClassPredictor/weights_quant/max"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@BoxPredictor_4/ClassPredictor/weights_quant/max"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/weights_quant/FakeQuantWithMinMaxVarsPerChannel"
op: "FakeQuantWithMinMaxVarsPerChannel"
input: "BoxPredictor_4/ClassPredictor/weights/read"
input: "BoxPredictor_4/ClassPredictor/weights_quant/min/read"
input: "BoxPredictor_4/ClassPredictor/weights_quant/max/read"
attr {
key: "narrow_range"
value {
b: true
}
}
attr {
key: "num_bits"
value {
i: 8
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/Conv2D"
op: "Conv2D"
input: "input"
input: "BoxPredictor_4/ClassPredictor/weights_quant/FakeQuantWithMinMaxVarsPerChannel"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "data_format"
value {
s: "NHWC"
}
}
attr {
key: "dilations"
value {
list {
i: 1
i: 1
i: 1
i: 1
}
}
}
attr {
key: "explicit_paddings"
value {
list {
}
}
}
attr {
key: "padding"
value {
s: "SAME"
}
}
attr {
key: "strides"
value {
list {
i: 1
i: 1
i: 1
i: 1
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/biases"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
dim {
size: 186
}
}
tensor_content: "\324\202\223\276\337\210\375\275\351\212\374\275p@\346\275HD\364\275W\236\362\275i\222\001\276\'\370\365\275:\250\345\275\244\214\373\275}\373\025\276^\351\000\2767_\017\276\362\t\322\2751%\376\275\364\020\324\275,\352\323\275\233\350\365\275\3777\014\276\371\022\277\2745{\366\275\270\207\366\275b\215\010\276\332\252\"\276\273\313\332\275\354\237\361\275\365W9\276o\364B\276\236HD\276$\250B\276CRC\276K\265\246\275f5\016\276[I\017\276\206\346\r\276\306\307\032\276\267\323\375\275\222\377\002\276\037\231\030\276\346W\001\2762F\004\276\021/\034\276\273\215\357\275\014m5\276\307[\021\276K\r\022\276Xv\365\275\312L\372\275A4\026\276\210[\024\276\254\242\003\276\207f\000\276\\C\023\276\322\233\000\276\266\0018\276\233\225\370\275\243\030\004\276]\201C\276\374j:\276\361\257@\276\017z<\276P?A\276a:\375\276\023\220\342\275W\026\377\275qD\005\276\'\271\371\275\342\207\n\276\273\221\003\276\372\205\363\275Ok\334\275\306\233\023\276y\271\"\276\313\345\n\276UH\"\276\233j\366\275\0026\377\275O\263\341\275\005\340\365\275,$\n\276\222\030\010\276\243\020\346\275\301\322\007\276n\252\374\275\325\251\007\276\325\033,\276\352\217\345\275\234\334\t\276\024\241@\276\256\365H\276zbA\276\262\361A\276\275C>\276\353Z\005>\2050&\276\035\222&\276\2457%\276\377/\'\276^\263\037\276\202\341%\276}\312\034\276&\2520\276Y\313,\276\232C*\276\233\375\032\276\212\250%\276\020\362\034\276\212\213-\276\211\211\030\276P\256\"\276\260\307\027\276?\332$\276\213\326\025\2761\243\023\276L\335\034\276\375\034\035\276L\2112\276\016\3571\276\224]\036\276\r\3165\276\232\340&\276?\2315\276^\342,\276\360{2\276\314\031\274=s\363\r\276C\227\035\276\332`\037\276\236\332\031\276Kj0\276$\034\035\276\227\262\033\276\231\260\033\2764\213\035\276\021\363$\276y\372&\276m`/\276<\272\027\276\267l\025\276\034x\031\276\202\313\034\276\026\363\027\276\307(\014\276<\332\005\276\231\316!\276\022\355\027\276-\251\037\2764\203+\276c \032\276\006#\036\276\22064\276\27450\2768O3\276\013\2321\276\31143\276a\367\n\2763\347\362\275?\037\003\276\241\375\001\276\340\003\332\275e\342\357\275\022\226\376\275\214\206\366\275\220\303\311\275\360\342\374\275\246\361\016\276\234\227\351\275\227\306\023\276\234\252\325\275\200\002\001\276\\\243\317\275\302\233\311\275\177\024\002\276\325\027\002\276\'\351\236=\316q\366\275\243>\010\276\203\204\373\275\365F/\276\225\323\346\275\250,\375\275E\0048\276\306\340?\276[/<\276\212\025B\276\251\264?\276"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/biases/read"
op: "Identity"
input: "BoxPredictor_4/ClassPredictor/biases"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@BoxPredictor_4/ClassPredictor/biases"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/BiasAdd"
op: "BiasAdd"
input: "BoxPredictor_4/ClassPredictor/Conv2D"
input: "BoxPredictor_4/ClassPredictor/biases/read"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "data_format"
value {
s: "NHWC"
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/act_quant/min"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
}
float_val: -14.066669
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/act_quant/min/read"
op: "Identity"
input: "BoxPredictor_4/ClassPredictor/act_quant/min"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@BoxPredictor_4/ClassPredictor/act_quant/min"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/act_quant/max"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
}
float_val: 9.810242
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/act_quant/max/read"
op: "Identity"
input: "BoxPredictor_4/ClassPredictor/act_quant/max"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@BoxPredictor_4/ClassPredictor/act_quant/max"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/act_quant/FakeQuantWithMinMaxVars"
op: "FakeQuantWithMinMaxVars"
input: "BoxPredictor_4/ClassPredictor/BiasAdd"
input: "BoxPredictor_4/ClassPredictor/act_quant/min/read"
input: "BoxPredictor_4/ClassPredictor/act_quant/max/read"
attr {
key: "narrow_range"
value {
b: false
}
}
attr {
key: "num_bits"
value {
i: 8
}
}
}
node {
name: "BoxPredictor_4/Reshape_1/shape"
op: "Const"
attr {
key: "dtype"
value {
type: DT_INT32
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_INT32
tensor_shape {
dim {
size: 3
}
}
tensor_content: "\001\000\000\000\377\377\377\377\037\000\000\000"
}
}
}
}
node {
name: "output"
op: "Reshape"
input: "BoxPredictor_4/ClassPredictor/act_quant/FakeQuantWithMinMaxVars"
input: "BoxPredictor_4/Reshape_1/shape"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "Tshape"
value {
type: DT_INT32
}
}
}
# MLIR-LABEL: func @main
# MLIR-SAME: (%[[ARG_0:[a-z0-9]+]]: tensor<1x1x1x256x!quant.uniform<i8:f32, 0.21632751372549019:27>>) -> tensor<1x6x31x!quant.uniform<i8:f32, 0.09363494573854933:22>>
# MLIR-SAME: control_outputs = ""
# MLIR-SAME: inputs = "input"
# MLIR-SAME: outputs = "output"
# MLIR: %[[shape:.*]] = arith.constant dense<[1, -1, 31]> : tensor<3xi32>
# MLIR: %[[bias:.*]] = "tfl.pseudo_qconst"() <{qtype = tensor<186x!quant.uniform<i32:f32:0
# MLIR: %[[weight:.*]] = "tfl.pseudo_qconst"() <{qtype = tensor<186x1x1x256x!quant.uniform<i8<-127:127>:f32:0, {0.12581039038230116,
# MLIR: %[[conv:.*]] = "tfl.conv_2d"(%[[ARG_0]], %[[weight]], %[[bias]]) <{dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32}
# MLIR: %[[reshape:.*]] = "tfl.reshape"(%[[conv]], %[[shape]]) : (tensor<1x1x1x186x!quant.uniform<i8:f32, 0.09363494573854933:22>>, tensor<3xi32>)
# MLIR: return %[[reshape]] : tensor<1x6x31x!quant.uniform<i8:f32, 0.09363494573854933:22>>
# MLIR: }
# CHECK-LABEL: {
# CHECK: version: 3,
# CHECK: operator_codes: [ {
# CHECK: deprecated_builtin_code: 3,
# CHECK: version: 3,
# CHECK: builtin_code: CONV_2D
# CHECK: }, {
# CHECK: deprecated_builtin_code: 22,
# CHECK: version: 1
# CHECK: builtin_code: RESHAPE
# CHECK: } ],
# CHECK: subgraphs: [ {
# CHECK: tensors: [ {
# CHECK: shape: [ 1, 1, 1, 256 ],
# CHECK: type: INT8,
# CHECK: buffer: 1,
# CHECK: name: "input",
# CHECK: quantization: {
# CHECK: scale: [ 0.216328 ],
# CHECK: zero_point: [ 27 ]
# CHECK: }
# CHECK: }, {
# CHECK: shape: [ 3 ],
# CHECK: type: INT32,
# CHECK: buffer: 2,
# CHECK: name: "BoxPredictor_4/Reshape_1/shape",
# CHECK: quantization: {
# CHECK-EMPTY
# CHECK: }
# CHECK: }, {
# CHECK: shape: [ 186 ],
# CHECK: type: INT32,
# CHECK: buffer: 3,
# CHECK: name: "BoxPredictor_4/ClassPredictor/BiasAdd;BoxPredictor_4/ClassPredictor/Conv2D;BoxPredictor_4/ClassPredictor/biases",
# CHECK: quantization: {
# CHECK: scale: [ 0.027216, 0.00038, 0.000413, 0.000426, 0.001607,
# CHECK: zero_point: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# CHECK: }
# CHECK: }, {
# CHECK: shape: [ 186, 1, 1, 256 ],
# CHECK: type: INT8,
# CHECK: buffer: 4,
# CHECK: name: "BoxPredictor_4/ClassPredictor/Conv2D;BoxPredictor_4/ClassPredictor/weights_quant/FakeQuantWithMinMaxVarsPerChannel",
# CHECK: quantization: {
# CHECK: scale: [ 0.12581, 0.001755, 0.001908, 0.001967, 0.007431,
# CHECK: zero_point: [ 0, 0, 0, 0, 0, 0, 0, 0, 0,
# CHECK: }
# CHECK: }, {
# CHECK: shape: [ 1, 1, 1, 186 ],
# CHECK: type: INT8,
# CHECK: buffer: 5,
# CHECK: name: "BoxPredictor_4/ClassPredictor/BiasAdd;BoxPredictor_4/ClassPredictor/Conv2D;BoxPredictor_4/ClassPredictor/biases1",
# CHECK: quantization: {
# CHECK: scale: [ 0.093635 ],
# CHECK: zero_point: [ 22 ]
# CHECK: }
# CHECK: }, {
# CHECK: shape: [ 1, 6, 31 ],
# CHECK: type: INT8,
# CHECK: buffer: 6,
# CHECK: name: "output",
# CHECK: quantization: {
# CHECK: scale: [ 0.093635 ],
# CHECK: zero_point: [ 22 ]
# CHECK: }
# CHECK: } ],
# CHECK: inputs: [ 0 ],
# CHECK: outputs: [ 5 ],
# CHECK: operators: [ {
# CHECK: inputs: [ 0, 3, 2 ],
# CHECK: outputs: [ 4 ],
# CHECK: builtin_options_type: Conv2DOptions,
# CHECK: builtin_options: {
# CHECK: stride_w: 1,
# CHECK: stride_h: 1
# CHECK: }
# CHECK: }, {
# CHECK: opcode_index: 1,
# CHECK: inputs: [ 4, 1 ],
# CHECK: outputs: [ 5 ]
# CHECK: } ],
# CHECK: name: "main"
# CHECK: } ],
# CHECK: description: "MLIR Converted.",
# CHECK: buffers: [ {
# CHECK-EMPTY
# CHECK: }, {
# CHECK-EMPTY
# CHECK: }, {
# CHECK: data: [ 1, 0, 0, 0, 255, 255, 255, 255, 31, 0, 0, 0 ]
# CHECK: }, {
# CHECK: data: [ 245, 255, 255, 255, 186, 254, 255, 255, 213, 254, 255, 255,
# CHECK: }, {
# CHECK: data: [ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
# CHECK: }, {
# CHECK-EMPTY
# CHECK: }, {
# CHECK-EMPTY
# CHECK: } ]
# CHECK: }
@@ -0,0 +1,559 @@
# RUN: tf_tfl_translate -tf-input-arrays=input -tf-input-shapes=1,1,1,256 -tf-input-data-types=DT_FLOAT -tf-inference-type=DT_QINT8 -tf-input-min-values='-33.614346' -tf-input-max-values='21.54917' -tf-output-arrays=output %s -o - --output-mlir 2>&1 | FileCheck --check-prefix=MLIR %s
# TODO(fengliuai): Figure out what to do here. A "golden" end-to-end test is overly fragile.
# DISABLED_RUN: true || tf_tfl_translate -tf-input-arrays=input -tf-input-shapes=1,1,1,256 -tf-input-data-types=DT_FLOAT -tf-inference-type=DT_QINT8 -tf-input-min-values='-33.614346' -tf-input-max-values='21.54917' -tf-output-arrays=output %s -o - | flatbuffer_to_string - | FileCheck %s
node {
name: "input"
op: "Placeholder"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "shape"
value {
shape {
dim {
size: 1
}
dim {
size: 1
}
dim {
size: 1
}
dim {
size: 256
}
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/weights"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
dim {
size: 1
}
dim {
size: 1
}
dim {
size: 256
}
dim {
size: 186
}
}
float_val: 1.0
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/weights/read"
op: "Identity"
input: "BoxPredictor_4/ClassPredictor/weights"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@BoxPredictor_4/ClassPredictor/weights"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/weights_quant/min"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
dim {
size: 186
}
}
tensor_content: "\217\245\177\301\005@d\276C\030x\276S\320\177\276.\227q\277\260]\223\276j\016\250\276\305\017\202\276\200+\201\276\275\377\177\276\310&\202\276\314\210k\276\3178W\277\335\356_\276\332GG\276`\200>\276o_c\276\312\224k\2767\033S\276M=\376\300y-\271\276\225\021g\276\272lZ\276\353r\251\276\025\354G\276\357\220\\\2765j0\2765Q(\276\013>0\276Y\r\'\276\224\013\"\276G=\377\300\022\211E\276\344\035O\276\242\220l\276w\307\020\2773`\376\276\331\377\202\276\374\016Y\276\224\273^\2767`~\276V\016>\276\226\333g\276*\241K\276\224g\177\276\320\315(\276t\376\177\276B\025B\276@\214\226\276\377s\376\276\373\365\377\277\343\211~\276\205\320b\276\213\236\377\2763\0136\276u\237:\276\325\373~\276\344\r\037\276>\035(\276\247\364!\276\2613%\276\207]!\276\320S\376\301\354 _\276\337PT\276\342\226[\276\304\307\177\276\360\"x\276\312\023\200\276Wfp\2768$W\276\235\014\202\276\230\210m\2761\342L\276b\234\013\277\362XM\276QPL\276\006Va\276\3168>\276\262\367t\276x\252k\276\266\225\231\276z@B\276\244\340?\276>8]\276\214v\206\276\316\210Z\276\275\343U\276\366\0321\276b\2128\276\310\2611\276\340n/\276\312\272\'\276\207\274\207\276tl\034\276\214[\357\275\020\345@\276\1778\376\275\264~#\276\326U*\276\374g\003\276\377\013\000\276\361\375T\276\246\330\007\276\365\203~\276\311\367\033\276\261\240\177\2768`\"\276i\364 \276\321\365\363\275\0241~\276\005\365\376\275S\303\035\277\203\003\020\276\264\322\377\276$\241\177\276\264d\t\276H\000C\276\360/~\276\352\301\377\275\037\300\n\276\0000\033\276r|\377\275\025\004\002\276\276\021\262\276\343\245M\2763\302\351\276LE\005\276\n\"~\276\341q\341\276\265\022~\276\322^\036\276\206\216\031\276\306\n\310\276\322_T\276\367\037w\276\374\227A\276\010\272G\276T&\022\276y\217>\276\275H\033\276\002=\376\276\232x0\276\322C~\276\032\350\212\276\234\322\036\2762%\376\276\266\345#\276.1\021\276\302,\351\276\025x&\276\354\363.\276\362\210\025\276\035\032\036\276\267X\014\276zc\177\300\336L_\276\274,k\276{\266\203\276\366\266~\277\225F\211\276\302~\243\276\253.\214\2765\241l\276g\021\214\276\347\376\177\276H\026T\276\305\220\377\276\000\\Y\276\334\332>\276\224\2459\276\334ja\276\260\313p\276\024\026\\\2769\334\177\301\334\330\222\276\347\376e\276\014\230W\276\253P\252\276i\300C\276\340\261Y\276721\276#k)\276\035.#\276R(0\276\224\336!\276"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/weights_quant/min/read"
op: "Identity"
input: "BoxPredictor_4/ClassPredictor/weights_quant/min"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@BoxPredictor_4/ClassPredictor/weights_quant/min"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/weights_quant/max"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
dim {
size: 186
}
}
tensor_content: "\217\245\177A\005@d>C\030x>S\320\177>.\227q?\260]\223>j\016\250>\305\017\202>\200+\201>\275\377\177>\310&\202>\314\210k>\3178W?\335\356_>\332GG>`\200>>o_c>\312\224k>7\033S>M=\376@y-\271>\225\021g>\272lZ>\353r\251>\025\354G>\357\220\\>5j0>5Q(>\013>0>Y\r\'>\224\013\">G=\377@\022\211E>\344\035O>\242\220l>w\307\020?3`\376>\331\377\202>\374\016Y>\224\273^>7`~>V\016>>\226\333g>*\241K>\224g\177>\320\315(>t\376\177>B\025B>@\214\226>\377s\376>\373\365\377?\343\211~>\205\320b>\213\236\377>3\0136>u\237:>\325\373~>\344\r\037>>\035(>\247\364!>\2613%>\207]!>\320S\376A\354 _>\337PT>\342\226[>\304\307\177>\360\"x>\312\023\200>Wfp>8$W>\235\014\202>\230\210m>1\342L>b\234\013?\362XM>QPL>\006Va>\3168>>\262\367t>x\252k>\266\225\231>z@B>\244\340?>>8]>\214v\206>\316\210Z>\275\343U>\366\0321>b\2128>\310\2611>\340n/>\312\272\'>\207\274\207>tl\034>\214[\357=\020\345@>\1778\376=\264~#>\326U*>\374g\003>\377\013\000>\361\375T>\246\330\007>\365\203~>\311\367\033>\261\240\177>8`\">i\364 >\321\365\363=\0241~>\005\365\376=S\303\035?\203\003\020>\264\322\377>$\241\177>\264d\t>H\000C>\360/~>\352\301\377=\037\300\n>\0000\033>r|\377=\025\004\002>\276\021\262>\343\245M>3\302\351>LE\005>\n\"~>\341q\341>\265\022~>\322^\036>\206\216\031>\306\n\310>\322_T>\367\037w>\374\227A>\010\272G>T&\022>y\217>>\275H\033>\002=\376>\232x0>\322C~>\032\350\212>\234\322\036>2%\376>\266\345#>.1\021>\302,\351>\025x&>\354\363.>\362\210\025>\035\032\036>\267X\014>zc\177@\336L_>\274,k>{\266\203>\366\266~?\225F\211>\302~\243>\253.\214>5\241l>g\021\214>\347\376\177>H\026T>\305\220\377>\000\\Y>\334\332>>\224\2459>\334ja>\260\313p>\024\026\\>9\334\177A\334\330\222>\347\376e>\014\230W>\253P\252>i\300C>\340\261Y>721>#k)>\035.#>R(0>\224\336!>"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/weights_quant/max/read"
op: "Identity"
input: "BoxPredictor_4/ClassPredictor/weights_quant/max"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@BoxPredictor_4/ClassPredictor/weights_quant/max"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/weights_quant/FakeQuantWithMinMaxVarsPerChannel"
op: "FakeQuantWithMinMaxVarsPerChannel"
input: "BoxPredictor_4/ClassPredictor/weights/read"
input: "BoxPredictor_4/ClassPredictor/weights_quant/min/read"
input: "BoxPredictor_4/ClassPredictor/weights_quant/max/read"
attr {
key: "narrow_range"
value {
b: true
}
}
attr {
key: "num_bits"
value {
i: 4
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/Conv2D"
op: "Conv2D"
input: "input"
input: "BoxPredictor_4/ClassPredictor/weights_quant/FakeQuantWithMinMaxVarsPerChannel"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "data_format"
value {
s: "NHWC"
}
}
attr {
key: "dilations"
value {
list {
i: 1
i: 1
i: 1
i: 1
}
}
}
attr {
key: "explicit_paddings"
value {
list {
}
}
}
attr {
key: "padding"
value {
s: "SAME"
}
}
attr {
key: "strides"
value {
list {
i: 1
i: 1
i: 1
i: 1
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/biases"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
dim {
size: 186
}
}
tensor_content: "\324\202\223\276\337\210\375\275\351\212\374\275p@\346\275HD\364\275W\236\362\275i\222\001\276\'\370\365\275:\250\345\275\244\214\373\275}\373\025\276^\351\000\2767_\017\276\362\t\322\2751%\376\275\364\020\324\275,\352\323\275\233\350\365\275\3777\014\276\371\022\277\2745{\366\275\270\207\366\275b\215\010\276\332\252\"\276\273\313\332\275\354\237\361\275\365W9\276o\364B\276\236HD\276$\250B\276CRC\276K\265\246\275f5\016\276[I\017\276\206\346\r\276\306\307\032\276\267\323\375\275\222\377\002\276\037\231\030\276\346W\001\2762F\004\276\021/\034\276\273\215\357\275\014m5\276\307[\021\276K\r\022\276Xv\365\275\312L\372\275A4\026\276\210[\024\276\254\242\003\276\207f\000\276\\C\023\276\322\233\000\276\266\0018\276\233\225\370\275\243\030\004\276]\201C\276\374j:\276\361\257@\276\017z<\276P?A\276a:\375\276\023\220\342\275W\026\377\275qD\005\276\'\271\371\275\342\207\n\276\273\221\003\276\372\205\363\275Ok\334\275\306\233\023\276y\271\"\276\313\345\n\276UH\"\276\233j\366\275\0026\377\275O\263\341\275\005\340\365\275,$\n\276\222\030\010\276\243\020\346\275\301\322\007\276n\252\374\275\325\251\007\276\325\033,\276\352\217\345\275\234\334\t\276\024\241@\276\256\365H\276zbA\276\262\361A\276\275C>\276\353Z\005>\2050&\276\035\222&\276\2457%\276\377/\'\276^\263\037\276\202\341%\276}\312\034\276&\2520\276Y\313,\276\232C*\276\233\375\032\276\212\250%\276\020\362\034\276\212\213-\276\211\211\030\276P\256\"\276\260\307\027\276?\332$\276\213\326\025\2761\243\023\276L\335\034\276\375\034\035\276L\2112\276\016\3571\276\224]\036\276\r\3165\276\232\340&\276?\2315\276^\342,\276\360{2\276\314\031\274=s\363\r\276C\227\035\276\332`\037\276\236\332\031\276Kj0\276$\034\035\276\227\262\033\276\231\260\033\2764\213\035\276\021\363$\276y\372&\276m`/\276<\272\027\276\267l\025\276\034x\031\276\202\313\034\276\026\363\027\276\307(\014\276<\332\005\276\231\316!\276\022\355\027\276-\251\037\2764\203+\276c \032\276\006#\036\276\22064\276\27450\2768O3\276\013\2321\276\31143\276a\367\n\2763\347\362\275?\037\003\276\241\375\001\276\340\003\332\275e\342\357\275\022\226\376\275\214\206\366\275\220\303\311\275\360\342\374\275\246\361\016\276\234\227\351\275\227\306\023\276\234\252\325\275\200\002\001\276\\\243\317\275\302\233\311\275\177\024\002\276\325\027\002\276\'\351\236=\316q\366\275\243>\010\276\203\204\373\275\365F/\276\225\323\346\275\250,\375\275E\0048\276\306\340?\276[/<\276\212\025B\276\251\264?\276"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/biases/read"
op: "Identity"
input: "BoxPredictor_4/ClassPredictor/biases"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@BoxPredictor_4/ClassPredictor/biases"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/BiasAdd"
op: "BiasAdd"
input: "BoxPredictor_4/ClassPredictor/Conv2D"
input: "BoxPredictor_4/ClassPredictor/biases/read"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "data_format"
value {
s: "NHWC"
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/act_quant/min"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
}
float_val: -14.066669
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/act_quant/min/read"
op: "Identity"
input: "BoxPredictor_4/ClassPredictor/act_quant/min"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@BoxPredictor_4/ClassPredictor/act_quant/min"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/act_quant/max"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
}
float_val: 9.810242
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/act_quant/max/read"
op: "Identity"
input: "BoxPredictor_4/ClassPredictor/act_quant/max"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@BoxPredictor_4/ClassPredictor/act_quant/max"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/act_quant/FakeQuantWithMinMaxVars"
op: "FakeQuantWithMinMaxVars"
input: "BoxPredictor_4/ClassPredictor/BiasAdd"
input: "BoxPredictor_4/ClassPredictor/act_quant/min/read"
input: "BoxPredictor_4/ClassPredictor/act_quant/max/read"
attr {
key: "narrow_range"
value {
b: false
}
}
attr {
key: "num_bits"
value {
i: 8
}
}
}
node {
name: "BoxPredictor_4/Reshape_1/shape"
op: "Const"
attr {
key: "dtype"
value {
type: DT_INT32
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_INT32
tensor_shape {
dim {
size: 3
}
}
tensor_content: "\001\000\000\000\377\377\377\377\037\000\000\000"
}
}
}
}
node {
name: "output"
op: "Reshape"
input: "BoxPredictor_4/ClassPredictor/act_quant/FakeQuantWithMinMaxVars"
input: "BoxPredictor_4/Reshape_1/shape"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "Tshape"
value {
type: DT_INT32
}
}
}
# MLIR-LABEL: func @main
# MLIR-SAME: (%[[ARG_0:[a-z0-9]+]]: tensor<1x1x1x256x!quant.uniform<i8:f32, 0.21632751372549019:27>>) -> tensor<1x6x31x!quant.uniform<i8:f32, 0.09363494573854933:22>>
# MLIR-SAME: control_outputs = ""
# MLIR-SAME: inputs = "input"
# MLIR-SAME: outputs = "output"
# MLIR: %[[shape:.*]] = arith.constant dense<[1, -1, 31]> : tensor<3xi32>
# MLIR: %[[bias:.*]] = "tfl.pseudo_qconst"() <{qtype = tensor<186x!quant.uniform<i32:f32:0
# MLIR: %[[weight:.*]] = "tfl.pseudo_qconst"() <{qtype = tensor<186x1x1x256x!quant.uniform<i4<-7:7>:f32:0, {2.2825599397931779,
# MLIR: %[[conv:.*]] = "tfl.conv_2d"(%[[ARG_0]], %[[weight]], %[[bias]]) <{dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32}
# MLIR: %[[reshape:.*]] = "tfl.reshape"(%[[conv]], %[[shape]]) : (tensor<1x1x1x186x!quant.uniform<i8:f32, 0.09363494573854933:22>>, tensor<3xi32>)
# MLIR: return %[[reshape]] : tensor<1x6x31x!quant.uniform<i8:f32, 0.09363494573854933:22>>
# MLIR: }
# CHECK-LABEL: {
# CHECK: version: 3,
# CHECK: operator_codes: [ {
# CHECK: deprecated_builtin_code: 3,
# CHECK: version: 3,
# CHECK: builtin_code: CONV_2D
# CHECK: }, {
# CHECK: deprecated_builtin_code: 22,
# CHECK: version: 1
# CHECK: builtin_code: RESHAPE
# CHECK: } ],
# CHECK: subgraphs: [ {
# CHECK: tensors: [ {
# CHECK: shape: [ 1, 1, 1, 256 ],
# CHECK: type: INT8,
# CHECK: buffer: 1,
# CHECK: name: "input",
# CHECK: quantization: {
# CHECK: scale: [ 0.216328 ],
# CHECK: zero_point: [ 27 ]
# CHECK: }
# CHECK: }, {
# CHECK: shape: [ 3 ],
# CHECK: type: INT32,
# CHECK: buffer: 2,
# CHECK: name: "BoxPredictor_4/Reshape_1/shape",
# CHECK: quantization: {
# CHECK-EMPTY
# CHECK: }
# CHECK: }, {
# CHECK: shape: [ 186 ],
# CHECK: type: INT32,
# CHECK: buffer: 3,
# CHECK: name: "BoxPredictor_4/ClassPredictor/BiasAdd;BoxPredictor_4/ClassPredictor/Conv2D;BoxPredictor_4/ClassPredictor/biases",
# CHECK: quantization: {
# CHECK: scale: [ 0.027216, 0.00038, 0.000413, 0.000426, 0.001607,
# CHECK: zero_point: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# CHECK: }
# CHECK: }, {
# CHECK: shape: [ 186, 1, 1, 256 ],
# CHECK: type: INT8,
# CHECK: buffer: 4,
# CHECK: name: "BoxPredictor_4/ClassPredictor/Conv2D;BoxPredictor_4/ClassPredictor/weights_quant/FakeQuantWithMinMaxVarsPerChannel",
# CHECK: quantization: {
# CHECK: scale: [ 0.12581, 0.001755, 0.001908, 0.001967, 0.007431,
# CHECK: zero_point: [ 0, 0, 0, 0, 0, 0, 0, 0, 0,
# CHECK: }
# CHECK: }, {
# CHECK: shape: [ 1, 1, 1, 186 ],
# CHECK: type: INT8,
# CHECK: buffer: 5,
# CHECK: name: "BoxPredictor_4/ClassPredictor/BiasAdd;BoxPredictor_4/ClassPredictor/Conv2D;BoxPredictor_4/ClassPredictor/biases1",
# CHECK: quantization: {
# CHECK: scale: [ 0.093635 ],
# CHECK: zero_point: [ 22 ]
# CHECK: }
# CHECK: }, {
# CHECK: shape: [ 1, 6, 31 ],
# CHECK: type: INT8,
# CHECK: buffer: 6,
# CHECK: name: "output",
# CHECK: quantization: {
# CHECK: scale: [ 0.093635 ],
# CHECK: zero_point: [ 22 ]
# CHECK: }
# CHECK: } ],
# CHECK: inputs: [ 0 ],
# CHECK: outputs: [ 5 ],
# CHECK: operators: [ {
# CHECK: inputs: [ 0, 3, 2 ],
# CHECK: outputs: [ 4 ],
# CHECK: builtin_options_type: Conv2DOptions,
# CHECK: builtin_options: {
# CHECK: stride_w: 1,
# CHECK: stride_h: 1
# CHECK: }
# CHECK: }, {
# CHECK: opcode_index: 1,
# CHECK: inputs: [ 4, 1 ],
# CHECK: outputs: [ 5 ]
# CHECK: } ],
# CHECK: name: "main"
# CHECK: } ],
# CHECK: description: "MLIR Converted.",
# CHECK: buffers: [ {
# CHECK-EMPTY
# CHECK: }, {
# CHECK-EMPTY
# CHECK: }, {
# CHECK: data: [ 1, 0, 0, 0, 255, 255, 255, 255, 31, 0, 0, 0 ]
# CHECK: }, {
# CHECK: data: [ 245, 255, 255, 255, 186, 254, 255, 255, 213, 254, 255, 255,
# CHECK: }, {
# CHECK: data: [ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
# CHECK: }, {
# CHECK-EMPTY
# CHECK: }, {
# CHECK-EMPTY
# CHECK: } ]
# CHECK: }
@@ -0,0 +1,418 @@
# RUN: tf_tfl_translate -tf-input-arrays=input -tf-input-shapes=1,1,1,256 -tf-input-data-types=DT_FLOAT -tf-inference-type=DT_QINT8 -tf-input-min-values='-33.614346' -tf-input-max-values='21.54917' -tf-output-arrays=output %s -o - --output-mlir 2>&1 | FileCheck --check-prefix=MLIR %s
node {
name: "input"
op: "Placeholder"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "shape"
value {
shape {
dim {
size: 1
}
dim {
size: 1
}
dim {
size: 1
}
dim {
size: 256
}
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/weights"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
dim {
size: 1
}
dim {
size: 1
}
dim {
size: 256
}
dim {
size: 186
}
}
float_val: 1.0
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/weights/read"
op: "Identity"
input: "BoxPredictor_4/ClassPredictor/weights"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@BoxPredictor_4/ClassPredictor/weights"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/weights_quant/min"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
dim {
size: 186
}
}
tensor_content: "\217\245\177\301\005@d\276C\030x\276S\320\177\276.\227q\277\260]\223\276j\016\250\276\305\017\202\276\200+\201\276\275\377\177\276\310&\202\276\314\210k\276\3178W\277\335\356_\276\332GG\276`\200>\276o_c\276\312\224k\2767\033S\276M=\376\300y-\271\276\225\021g\276\272lZ\276\353r\251\276\025\354G\276\357\220\\\2765j0\2765Q(\276\013>0\276Y\r\'\276\224\013\"\276G=\377\300\022\211E\276\344\035O\276\242\220l\276w\307\020\2773`\376\276\331\377\202\276\374\016Y\276\224\273^\2767`~\276V\016>\276\226\333g\276*\241K\276\224g\177\276\320\315(\276t\376\177\276B\025B\276@\214\226\276\377s\376\276\373\365\377\277\343\211~\276\205\320b\276\213\236\377\2763\0136\276u\237:\276\325\373~\276\344\r\037\276>\035(\276\247\364!\276\2613%\276\207]!\276\320S\376\301\354 _\276\337PT\276\342\226[\276\304\307\177\276\360\"x\276\312\023\200\276Wfp\2768$W\276\235\014\202\276\230\210m\2761\342L\276b\234\013\277\362XM\276QPL\276\006Va\276\3168>\276\262\367t\276x\252k\276\266\225\231\276z@B\276\244\340?\276>8]\276\214v\206\276\316\210Z\276\275\343U\276\366\0321\276b\2128\276\310\2611\276\340n/\276\312\272\'\276\207\274\207\276tl\034\276\214[\357\275\020\345@\276\1778\376\275\264~#\276\326U*\276\374g\003\276\377\013\000\276\361\375T\276\246\330\007\276\365\203~\276\311\367\033\276\261\240\177\2768`\"\276i\364 \276\321\365\363\275\0241~\276\005\365\376\275S\303\035\277\203\003\020\276\264\322\377\276$\241\177\276\264d\t\276H\000C\276\360/~\276\352\301\377\275\037\300\n\276\0000\033\276r|\377\275\025\004\002\276\276\021\262\276\343\245M\2763\302\351\276LE\005\276\n\"~\276\341q\341\276\265\022~\276\322^\036\276\206\216\031\276\306\n\310\276\322_T\276\367\037w\276\374\227A\276\010\272G\276T&\022\276y\217>\276\275H\033\276\002=\376\276\232x0\276\322C~\276\032\350\212\276\234\322\036\2762%\376\276\266\345#\276.1\021\276\302,\351\276\025x&\276\354\363.\276\362\210\025\276\035\032\036\276\267X\014\276zc\177\300\336L_\276\274,k\276{\266\203\276\366\266~\277\225F\211\276\302~\243\276\253.\214\2765\241l\276g\021\214\276\347\376\177\276H\026T\276\305\220\377\276\000\\Y\276\334\332>\276\224\2459\276\334ja\276\260\313p\276\024\026\\\2769\334\177\301\334\330\222\276\347\376e\276\014\230W\276\253P\252\276i\300C\276\340\261Y\276721\276#k)\276\035.#\276R(0\276\224\336!\276"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/weights_quant/max"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
dim {
size: 186
}
}
tensor_content: "\217\245\177A\005@d>C\030x>S\320\177>.\227q?\260]\223>j\016\250>\305\017\202>\200+\201>\275\377\177>\310&\202>\314\210k>\3178W?\335\356_>\332GG>`\200>>o_c>\312\224k>7\033S>M=\376@y-\271>\225\021g>\272lZ>\353r\251>\025\354G>\357\220\\>5j0>5Q(>\013>0>Y\r\'>\224\013\">G=\377@\022\211E>\344\035O>\242\220l>w\307\020?3`\376>\331\377\202>\374\016Y>\224\273^>7`~>V\016>>\226\333g>*\241K>\224g\177>\320\315(>t\376\177>B\025B>@\214\226>\377s\376>\373\365\377?\343\211~>\205\320b>\213\236\377>3\0136>u\237:>\325\373~>\344\r\037>>\035(>\247\364!>\2613%>\207]!>\320S\376A\354 _>\337PT>\342\226[>\304\307\177>\360\"x>\312\023\200>Wfp>8$W>\235\014\202>\230\210m>1\342L>b\234\013?\362XM>QPL>\006Va>\3168>>\262\367t>x\252k>\266\225\231>z@B>\244\340?>>8]>\214v\206>\316\210Z>\275\343U>\366\0321>b\2128>\310\2611>\340n/>\312\272\'>\207\274\207>tl\034>\214[\357=\020\345@>\1778\376=\264~#>\326U*>\374g\003>\377\013\000>\361\375T>\246\330\007>\365\203~>\311\367\033>\261\240\177>8`\">i\364 >\321\365\363=\0241~>\005\365\376=S\303\035?\203\003\020>\264\322\377>$\241\177>\264d\t>H\000C>\360/~>\352\301\377=\037\300\n>\0000\033>r|\377=\025\004\002>\276\021\262>\343\245M>3\302\351>LE\005>\n\"~>\341q\341>\265\022~>\322^\036>\206\216\031>\306\n\310>\322_T>\367\037w>\374\227A>\010\272G>T&\022>y\217>>\275H\033>\002=\376>\232x0>\322C~>\032\350\212>\234\322\036>2%\376>\266\345#>.1\021>\302,\351>\025x&>\354\363.>\362\210\025>\035\032\036>\267X\014>zc\177@\336L_>\274,k>{\266\203>\366\266~?\225F\211>\302~\243>\253.\214>5\241l>g\021\214>\347\376\177>H\026T>\305\220\377>\000\\Y>\334\332>>\224\2459>\334ja>\260\313p>\024\026\\>9\334\177A\334\330\222>\347\376e>\014\230W>\253P\252>i\300C>\340\261Y>721>#k)>\035.#>R(0>\224\336!>"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/weights_quant/FakeQuantWithMinMaxVarsPerChannel"
op: "FakeQuantWithMinMaxVarsPerChannel"
input: "BoxPredictor_4/ClassPredictor/weights/read"
input: "BoxPredictor_4/ClassPredictor/weights_quant/min"
input: "BoxPredictor_4/ClassPredictor/weights_quant/max"
attr {
key: "narrow_range"
value {
b: true
}
}
attr {
key: "num_bits"
value {
i: 8
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/Conv2D"
op: "Conv2D"
input: "input"
input: "BoxPredictor_4/ClassPredictor/weights_quant/FakeQuantWithMinMaxVarsPerChannel"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "data_format"
value {
s: "NHWC"
}
}
attr {
key: "dilations"
value {
list {
i: 1
i: 1
i: 1
i: 1
}
}
}
attr {
key: "explicit_paddings"
value {
list {
}
}
}
attr {
key: "padding"
value {
s: "SAME"
}
}
attr {
key: "strides"
value {
list {
i: 1
i: 1
i: 1
i: 1
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/biases"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
dim {
size: 186
}
}
tensor_content: "\324\202\223\276\337\210\375\275\351\212\374\275p@\346\275HD\364\275W\236\362\275i\222\001\276\'\370\365\275:\250\345\275\244\214\373\275}\373\025\276^\351\000\2767_\017\276\362\t\322\2751%\376\275\364\020\324\275,\352\323\275\233\350\365\275\3777\014\276\371\022\277\2745{\366\275\270\207\366\275b\215\010\276\332\252\"\276\273\313\332\275\354\237\361\275\365W9\276o\364B\276\236HD\276$\250B\276CRC\276K\265\246\275f5\016\276[I\017\276\206\346\r\276\306\307\032\276\267\323\375\275\222\377\002\276\037\231\030\276\346W\001\2762F\004\276\021/\034\276\273\215\357\275\014m5\276\307[\021\276K\r\022\276Xv\365\275\312L\372\275A4\026\276\210[\024\276\254\242\003\276\207f\000\276\\C\023\276\322\233\000\276\266\0018\276\233\225\370\275\243\030\004\276]\201C\276\374j:\276\361\257@\276\017z<\276P?A\276a:\375\276\023\220\342\275W\026\377\275qD\005\276\'\271\371\275\342\207\n\276\273\221\003\276\372\205\363\275Ok\334\275\306\233\023\276y\271\"\276\313\345\n\276UH\"\276\233j\366\275\0026\377\275O\263\341\275\005\340\365\275,$\n\276\222\030\010\276\243\020\346\275\301\322\007\276n\252\374\275\325\251\007\276\325\033,\276\352\217\345\275\234\334\t\276\024\241@\276\256\365H\276zbA\276\262\361A\276\275C>\276\353Z\005>\2050&\276\035\222&\276\2457%\276\377/\'\276^\263\037\276\202\341%\276}\312\034\276&\2520\276Y\313,\276\232C*\276\233\375\032\276\212\250%\276\020\362\034\276\212\213-\276\211\211\030\276P\256\"\276\260\307\027\276?\332$\276\213\326\025\2761\243\023\276L\335\034\276\375\034\035\276L\2112\276\016\3571\276\224]\036\276\r\3165\276\232\340&\276?\2315\276^\342,\276\360{2\276\314\031\274=s\363\r\276C\227\035\276\332`\037\276\236\332\031\276Kj0\276$\034\035\276\227\262\033\276\231\260\033\2764\213\035\276\021\363$\276y\372&\276m`/\276<\272\027\276\267l\025\276\034x\031\276\202\313\034\276\026\363\027\276\307(\014\276<\332\005\276\231\316!\276\022\355\027\276-\251\037\2764\203+\276c \032\276\006#\036\276\22064\276\27450\2768O3\276\013\2321\276\31143\276a\367\n\2763\347\362\275?\037\003\276\241\375\001\276\340\003\332\275e\342\357\275\022\226\376\275\214\206\366\275\220\303\311\275\360\342\374\275\246\361\016\276\234\227\351\275\227\306\023\276\234\252\325\275\200\002\001\276\\\243\317\275\302\233\311\275\177\024\002\276\325\027\002\276\'\351\236=\316q\366\275\243>\010\276\203\204\373\275\365F/\276\225\323\346\275\250,\375\275E\0048\276\306\340?\276[/<\276\212\025B\276\251\264?\276"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/biases/read"
op: "Identity"
input: "BoxPredictor_4/ClassPredictor/biases"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@BoxPredictor_4/ClassPredictor/biases"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/BiasAdd"
op: "BiasAdd"
input: "BoxPredictor_4/ClassPredictor/Conv2D"
input: "BoxPredictor_4/ClassPredictor/biases/read"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "data_format"
value {
s: "NHWC"
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/act_quant/min"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
}
float_val: -14.066669
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/act_quant/min/read"
op: "Identity"
input: "BoxPredictor_4/ClassPredictor/act_quant/min"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@BoxPredictor_4/ClassPredictor/act_quant/min"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/act_quant/max"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
}
float_val: 9.810242
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/act_quant/max/read"
op: "Identity"
input: "BoxPredictor_4/ClassPredictor/act_quant/max"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@BoxPredictor_4/ClassPredictor/act_quant/max"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/act_quant/FakeQuantWithMinMaxVars"
op: "FakeQuantWithMinMaxVars"
input: "BoxPredictor_4/ClassPredictor/BiasAdd"
input: "BoxPredictor_4/ClassPredictor/act_quant/min/read"
input: "BoxPredictor_4/ClassPredictor/act_quant/max/read"
attr {
key: "narrow_range"
value {
b: false
}
}
attr {
key: "num_bits"
value {
i: 8
}
}
}
node {
name: "BoxPredictor_4/Reshape_1/shape"
op: "Const"
attr {
key: "dtype"
value {
type: DT_INT32
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_INT32
tensor_shape {
dim {
size: 3
}
}
tensor_content: "\001\000\000\000\377\377\377\377\037\000\000\000"
}
}
}
}
node {
name: "output"
op: "Reshape"
input: "BoxPredictor_4/ClassPredictor/act_quant/FakeQuantWithMinMaxVars"
input: "BoxPredictor_4/Reshape_1/shape"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "Tshape"
value {
type: DT_INT32
}
}
}
# MLIR-LABEL: func @main
# MLIR-SAME: (%[[ARG_0:[a-z0-9]+]]: tensor<1x1x1x256x!quant.uniform<i8:f32, 0.21632751372549019:27>>) -> tensor<1x6x31x!quant.uniform<i8:f32, 0.09363494573854933:22>>
# MLIR-SAME: control_outputs = ""
# MLIR-SAME: inputs = "input"
# MLIR-SAME: outputs = "output"
# MLIR: %[[shape:.*]] = arith.constant dense<[1, -1, 31]> : tensor<3xi32>
# MLIR: %[[bias:.*]] = "tfl.pseudo_qconst"() <{qtype = tensor<186x!quant.uniform<i32:f32:0
# MLIR: %[[weight:.*]] = "tfl.pseudo_qconst"() <{qtype = tensor<186x1x1x256x!quant.uniform<i8<-127:127>:f32:0, {0.12581039038230116,
# MLIR: %[[conv:.*]] = "tfl.conv_2d"(%[[ARG_0]], %[[weight]], %[[bias]]) <{dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32}
# MLIR: %[[reshape:.*]] = "tfl.reshape"(%[[conv]], %[[shape]]) : (tensor<1x1x1x186x!quant.uniform<i8:f32, 0.09363494573854933:22>>, tensor<3xi32>)
# MLIR: return %[[reshape]] : tensor<1x6x31x!quant.uniform<i8:f32, 0.09363494573854933:22>>
# MLIR: }
@@ -0,0 +1,418 @@
# RUN: tf_tfl_translate -tf-input-arrays=input -tf-input-shapes=1,1,1,256 -tf-input-data-types=DT_FLOAT -tf-inference-type=DT_QINT8 -tf-input-min-values='-33.614346' -tf-input-max-values='21.54917' -tf-output-arrays=output %s -o - --output-mlir 2>&1 | FileCheck --check-prefix=MLIR %s
node {
name: "input"
op: "Placeholder"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "shape"
value {
shape {
dim {
size: 1
}
dim {
size: 1
}
dim {
size: 1
}
dim {
size: 256
}
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/weights"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
dim {
size: 1
}
dim {
size: 1
}
dim {
size: 256
}
dim {
size: 186
}
}
float_val: 1.0
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/weights/read"
op: "Identity"
input: "BoxPredictor_4/ClassPredictor/weights"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@BoxPredictor_4/ClassPredictor/weights"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/weights_quant/min"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
dim {
size: 186
}
}
tensor_content: "\217\245\177\301\005@d\276C\030x\276S\320\177\276.\227q\277\260]\223\276j\016\250\276\305\017\202\276\200+\201\276\275\377\177\276\310&\202\276\314\210k\276\3178W\277\335\356_\276\332GG\276`\200>\276o_c\276\312\224k\2767\033S\276M=\376\300y-\271\276\225\021g\276\272lZ\276\353r\251\276\025\354G\276\357\220\\\2765j0\2765Q(\276\013>0\276Y\r\'\276\224\013\"\276G=\377\300\022\211E\276\344\035O\276\242\220l\276w\307\020\2773`\376\276\331\377\202\276\374\016Y\276\224\273^\2767`~\276V\016>\276\226\333g\276*\241K\276\224g\177\276\320\315(\276t\376\177\276B\025B\276@\214\226\276\377s\376\276\373\365\377\277\343\211~\276\205\320b\276\213\236\377\2763\0136\276u\237:\276\325\373~\276\344\r\037\276>\035(\276\247\364!\276\2613%\276\207]!\276\320S\376\301\354 _\276\337PT\276\342\226[\276\304\307\177\276\360\"x\276\312\023\200\276Wfp\2768$W\276\235\014\202\276\230\210m\2761\342L\276b\234\013\277\362XM\276QPL\276\006Va\276\3168>\276\262\367t\276x\252k\276\266\225\231\276z@B\276\244\340?\276>8]\276\214v\206\276\316\210Z\276\275\343U\276\366\0321\276b\2128\276\310\2611\276\340n/\276\312\272\'\276\207\274\207\276tl\034\276\214[\357\275\020\345@\276\1778\376\275\264~#\276\326U*\276\374g\003\276\377\013\000\276\361\375T\276\246\330\007\276\365\203~\276\311\367\033\276\261\240\177\2768`\"\276i\364 \276\321\365\363\275\0241~\276\005\365\376\275S\303\035\277\203\003\020\276\264\322\377\276$\241\177\276\264d\t\276H\000C\276\360/~\276\352\301\377\275\037\300\n\276\0000\033\276r|\377\275\025\004\002\276\276\021\262\276\343\245M\2763\302\351\276LE\005\276\n\"~\276\341q\341\276\265\022~\276\322^\036\276\206\216\031\276\306\n\310\276\322_T\276\367\037w\276\374\227A\276\010\272G\276T&\022\276y\217>\276\275H\033\276\002=\376\276\232x0\276\322C~\276\032\350\212\276\234\322\036\2762%\376\276\266\345#\276.1\021\276\302,\351\276\025x&\276\354\363.\276\362\210\025\276\035\032\036\276\267X\014\276zc\177\300\336L_\276\274,k\276{\266\203\276\366\266~\277\225F\211\276\302~\243\276\253.\214\2765\241l\276g\021\214\276\347\376\177\276H\026T\276\305\220\377\276\000\\Y\276\334\332>\276\224\2459\276\334ja\276\260\313p\276\024\026\\\2769\334\177\301\334\330\222\276\347\376e\276\014\230W\276\253P\252\276i\300C\276\340\261Y\276721\276#k)\276\035.#\276R(0\276\224\336!\276"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/weights_quant/max"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
dim {
size: 186
}
}
tensor_content: "\217\245\177A\005@d>C\030x>S\320\177>.\227q?\260]\223>j\016\250>\305\017\202>\200+\201>\275\377\177>\310&\202>\314\210k>\3178W?\335\356_>\332GG>`\200>>o_c>\312\224k>7\033S>M=\376@y-\271>\225\021g>\272lZ>\353r\251>\025\354G>\357\220\\>5j0>5Q(>\013>0>Y\r\'>\224\013\">G=\377@\022\211E>\344\035O>\242\220l>w\307\020?3`\376>\331\377\202>\374\016Y>\224\273^>7`~>V\016>>\226\333g>*\241K>\224g\177>\320\315(>t\376\177>B\025B>@\214\226>\377s\376>\373\365\377?\343\211~>\205\320b>\213\236\377>3\0136>u\237:>\325\373~>\344\r\037>>\035(>\247\364!>\2613%>\207]!>\320S\376A\354 _>\337PT>\342\226[>\304\307\177>\360\"x>\312\023\200>Wfp>8$W>\235\014\202>\230\210m>1\342L>b\234\013?\362XM>QPL>\006Va>\3168>>\262\367t>x\252k>\266\225\231>z@B>\244\340?>>8]>\214v\206>\316\210Z>\275\343U>\366\0321>b\2128>\310\2611>\340n/>\312\272\'>\207\274\207>tl\034>\214[\357=\020\345@>\1778\376=\264~#>\326U*>\374g\003>\377\013\000>\361\375T>\246\330\007>\365\203~>\311\367\033>\261\240\177>8`\">i\364 >\321\365\363=\0241~>\005\365\376=S\303\035?\203\003\020>\264\322\377>$\241\177>\264d\t>H\000C>\360/~>\352\301\377=\037\300\n>\0000\033>r|\377=\025\004\002>\276\021\262>\343\245M>3\302\351>LE\005>\n\"~>\341q\341>\265\022~>\322^\036>\206\216\031>\306\n\310>\322_T>\367\037w>\374\227A>\010\272G>T&\022>y\217>>\275H\033>\002=\376>\232x0>\322C~>\032\350\212>\234\322\036>2%\376>\266\345#>.1\021>\302,\351>\025x&>\354\363.>\362\210\025>\035\032\036>\267X\014>zc\177@\336L_>\274,k>{\266\203>\366\266~?\225F\211>\302~\243>\253.\214>5\241l>g\021\214>\347\376\177>H\026T>\305\220\377>\000\\Y>\334\332>>\224\2459>\334ja>\260\313p>\024\026\\>9\334\177A\334\330\222>\347\376e>\014\230W>\253P\252>i\300C>\340\261Y>721>#k)>\035.#>R(0>\224\336!>"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/weights_quant/FakeQuantWithMinMaxVarsPerChannel"
op: "FakeQuantWithMinMaxVarsPerChannel"
input: "BoxPredictor_4/ClassPredictor/weights/read"
input: "BoxPredictor_4/ClassPredictor/weights_quant/min"
input: "BoxPredictor_4/ClassPredictor/weights_quant/max"
attr {
key: "narrow_range"
value {
b: true
}
}
attr {
key: "num_bits"
value {
i: 4
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/Conv2D"
op: "Conv2D"
input: "input"
input: "BoxPredictor_4/ClassPredictor/weights_quant/FakeQuantWithMinMaxVarsPerChannel"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "data_format"
value {
s: "NHWC"
}
}
attr {
key: "dilations"
value {
list {
i: 1
i: 1
i: 1
i: 1
}
}
}
attr {
key: "explicit_paddings"
value {
list {
}
}
}
attr {
key: "padding"
value {
s: "SAME"
}
}
attr {
key: "strides"
value {
list {
i: 1
i: 1
i: 1
i: 1
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/biases"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
dim {
size: 186
}
}
tensor_content: "\324\202\223\276\337\210\375\275\351\212\374\275p@\346\275HD\364\275W\236\362\275i\222\001\276\'\370\365\275:\250\345\275\244\214\373\275}\373\025\276^\351\000\2767_\017\276\362\t\322\2751%\376\275\364\020\324\275,\352\323\275\233\350\365\275\3777\014\276\371\022\277\2745{\366\275\270\207\366\275b\215\010\276\332\252\"\276\273\313\332\275\354\237\361\275\365W9\276o\364B\276\236HD\276$\250B\276CRC\276K\265\246\275f5\016\276[I\017\276\206\346\r\276\306\307\032\276\267\323\375\275\222\377\002\276\037\231\030\276\346W\001\2762F\004\276\021/\034\276\273\215\357\275\014m5\276\307[\021\276K\r\022\276Xv\365\275\312L\372\275A4\026\276\210[\024\276\254\242\003\276\207f\000\276\\C\023\276\322\233\000\276\266\0018\276\233\225\370\275\243\030\004\276]\201C\276\374j:\276\361\257@\276\017z<\276P?A\276a:\375\276\023\220\342\275W\026\377\275qD\005\276\'\271\371\275\342\207\n\276\273\221\003\276\372\205\363\275Ok\334\275\306\233\023\276y\271\"\276\313\345\n\276UH\"\276\233j\366\275\0026\377\275O\263\341\275\005\340\365\275,$\n\276\222\030\010\276\243\020\346\275\301\322\007\276n\252\374\275\325\251\007\276\325\033,\276\352\217\345\275\234\334\t\276\024\241@\276\256\365H\276zbA\276\262\361A\276\275C>\276\353Z\005>\2050&\276\035\222&\276\2457%\276\377/\'\276^\263\037\276\202\341%\276}\312\034\276&\2520\276Y\313,\276\232C*\276\233\375\032\276\212\250%\276\020\362\034\276\212\213-\276\211\211\030\276P\256\"\276\260\307\027\276?\332$\276\213\326\025\2761\243\023\276L\335\034\276\375\034\035\276L\2112\276\016\3571\276\224]\036\276\r\3165\276\232\340&\276?\2315\276^\342,\276\360{2\276\314\031\274=s\363\r\276C\227\035\276\332`\037\276\236\332\031\276Kj0\276$\034\035\276\227\262\033\276\231\260\033\2764\213\035\276\021\363$\276y\372&\276m`/\276<\272\027\276\267l\025\276\034x\031\276\202\313\034\276\026\363\027\276\307(\014\276<\332\005\276\231\316!\276\022\355\027\276-\251\037\2764\203+\276c \032\276\006#\036\276\22064\276\27450\2768O3\276\013\2321\276\31143\276a\367\n\2763\347\362\275?\037\003\276\241\375\001\276\340\003\332\275e\342\357\275\022\226\376\275\214\206\366\275\220\303\311\275\360\342\374\275\246\361\016\276\234\227\351\275\227\306\023\276\234\252\325\275\200\002\001\276\\\243\317\275\302\233\311\275\177\024\002\276\325\027\002\276\'\351\236=\316q\366\275\243>\010\276\203\204\373\275\365F/\276\225\323\346\275\250,\375\275E\0048\276\306\340?\276[/<\276\212\025B\276\251\264?\276"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/biases/read"
op: "Identity"
input: "BoxPredictor_4/ClassPredictor/biases"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@BoxPredictor_4/ClassPredictor/biases"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/BiasAdd"
op: "BiasAdd"
input: "BoxPredictor_4/ClassPredictor/Conv2D"
input: "BoxPredictor_4/ClassPredictor/biases/read"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "data_format"
value {
s: "NHWC"
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/act_quant/min"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
}
float_val: -14.066669
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/act_quant/min/read"
op: "Identity"
input: "BoxPredictor_4/ClassPredictor/act_quant/min"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@BoxPredictor_4/ClassPredictor/act_quant/min"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/act_quant/max"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
}
float_val: 9.810242
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/act_quant/max/read"
op: "Identity"
input: "BoxPredictor_4/ClassPredictor/act_quant/max"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@BoxPredictor_4/ClassPredictor/act_quant/max"
}
}
}
}
node {
name: "BoxPredictor_4/ClassPredictor/act_quant/FakeQuantWithMinMaxVars"
op: "FakeQuantWithMinMaxVars"
input: "BoxPredictor_4/ClassPredictor/BiasAdd"
input: "BoxPredictor_4/ClassPredictor/act_quant/min/read"
input: "BoxPredictor_4/ClassPredictor/act_quant/max/read"
attr {
key: "narrow_range"
value {
b: false
}
}
attr {
key: "num_bits"
value {
i: 8
}
}
}
node {
name: "BoxPredictor_4/Reshape_1/shape"
op: "Const"
attr {
key: "dtype"
value {
type: DT_INT32
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_INT32
tensor_shape {
dim {
size: 3
}
}
tensor_content: "\001\000\000\000\377\377\377\377\037\000\000\000"
}
}
}
}
node {
name: "output"
op: "Reshape"
input: "BoxPredictor_4/ClassPredictor/act_quant/FakeQuantWithMinMaxVars"
input: "BoxPredictor_4/Reshape_1/shape"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "Tshape"
value {
type: DT_INT32
}
}
}
# MLIR-LABEL: func @main
# MLIR-SAME: (%[[ARG_0:[a-z0-9]+]]: tensor<1x1x1x256x!quant.uniform<i8:f32, 0.21632751372549019:27>>) -> tensor<1x6x31x!quant.uniform<i8:f32, 0.09363494573854933:22>>
# MLIR-SAME: control_outputs = ""
# MLIR-SAME: inputs = "input"
# MLIR-SAME: outputs = "output"
# MLIR: %[[shape:.*]] = arith.constant dense<[1, -1, 31]> : tensor<3xi32>
# MLIR: %[[bias:.*]] = "tfl.pseudo_qconst"() <{qtype = tensor<186x!quant.uniform<i32:f32:0
# MLIR: %[[weight:.*]] = "tfl.pseudo_qconst"() <{qtype = tensor<186x1x1x256x!quant.uniform<i4<-7:7>:f32:0, {2.2825599397931779,
# MLIR: %[[conv:.*]] = "tfl.conv_2d"(%[[ARG_0]], %[[weight]], %[[bias]]) <{dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32}
# MLIR: %[[reshape:.*]] = "tfl.reshape"(%[[conv]], %[[shape]]) : (tensor<1x1x1x186x!quant.uniform<i8:f32, 0.09363494573854933:22>>, tensor<3xi32>)
# MLIR: return %[[reshape]] : tensor<1x6x31x!quant.uniform<i8:f32, 0.09363494573854933:22>>
# MLIR: }
@@ -0,0 +1,56 @@
# RUN: tf_tfl_translate -tf-input-arrays=input -tf-input-shapes=4 -tf-input-data-types=DT_INT32 -tf-output-arrays=output %s -o - --output-mlir | FileCheck %s
node {
name: "default"
op: "Const"
attr {
key: "dtype"
value {
type: DT_INT32
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_INT32
tensor_shape {
}
int_val: 0
}
}
}
}
node {
name: "input"
op: "Identity"
input: "default"
attr {
key: "T"
value {
type: DT_INT32
}
}
}
node {
name: "output"
op: "Identity"
input: "input"
attr {
key: "T"
value {
type: DT_INT32
}
}
}
versions {
producer: 27
}
# CHECK-LABEL: func @main
# CHECK-SAME: (%[[ARG_0:[a-z0-9]+]]: tensor<4xi32>) -> tensor<4xi32>
# CHECK-SAME: control_outputs = ""
# CHECK-SAME: inputs = "input"
# CHECK-SAME: outputs = "output"
# CHECK-NEXT: return %[[ARG_0]] : tensor<4xi32>
# CHECK-NEXT: }
@@ -0,0 +1,148 @@
# RUN: tf_tfl_translate -tf-input-arrays=unranked -tf-input-shapes=1,8,8,2 -tf-input-data-types=DT_INT32 -tf-output-arrays=unranked,static,static_10 %s -o - --output-mlir | FileCheck %s
node {
name: "tf.Const"
op: "Const"
attr {
key: "dtype"
value {
type: DT_INT32
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_INT32
tensor_shape {
dim {
size: 10
}
}
int_val: 0
}
}
}
experimental_debug_info {
}
}
node {
name: "tf.Const1"
op: "Const"
attr {
key: "dtype"
value {
type: DT_INT32
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_INT32
tensor_shape {
}
int_val: 0
}
}
}
experimental_debug_info {
}
}
node {
name: "unranked"
op: "PlaceholderWithDefault"
input: "tf.Const1"
attr {
key: "dtype"
value {
type: DT_INT32
}
}
attr {
key: "shape"
value {
shape {
unknown_rank: true
}
}
}
attr {
key: "type"
value {
type: DT_INT32
}
}
experimental_debug_info {
}
}
node {
name: "static"
op: "PlaceholderWithDefault"
input: "tf.Const1"
attr {
key: "dtype"
value {
type: DT_INT32
}
}
attr {
key: "shape"
value {
shape {
}
}
}
attr {
key: "type"
value {
type: DT_INT32
}
}
experimental_debug_info {
}
}
node {
name: "static_10"
op: "PlaceholderWithDefault"
input: "tf.Const"
attr {
key: "dtype"
value {
type: DT_INT32
}
}
attr {
key: "shape"
value {
shape {
dim {
size: 10
}
}
}
}
attr {
key: "type"
value {
type: DT_INT32
}
}
experimental_debug_info {
}
}
library {
}
versions {
producer: 198
}
# CHECK-LABEL: func @main
# CHECK-SAME: ([[VAL_0:%.*]]: tensor<1x8x8x2xi32>) -> (tensor<1x8x8x2xi32>, tensor<i32>, tensor<10xi32>)
# CHECK-SAME: control_outputs = ""
# CHECK-SAME: inputs = "unranked"
# CHECK-SAME: outputs = "unranked,static,static_10"
# CHECK-DAG: [[VAL_2:%.*]] = arith.constant dense<0> : tensor<10xi32>
# CHECK-DAG: [[VAL_1:%.*]] = arith.constant dense<0> : tensor<i32>
# CHECK: return [[VAL_0]], [[VAL_1]], [[VAL_2]] : tensor<1x8x8x2xi32>, tensor<i32>, tensor<10xi32>
# CHECK: }
@@ -0,0 +1,421 @@
# RUN: tf_tfl_translate -tf-input-arrays=a,b -tf-input-data-types=DT_FLOAT,DT_FLOAT -tf-input-shapes=: -tf-output-arrays=StatefulIf,StatelessIf %s -o - --output-mlir | FileCheck %s
node {
name: "tf.Less"
op: "Less"
input: "a"
input: "b"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
experimental_debug_info {
}
}
node {
name: "my_equal"
op: "Equal"
input: "a"
input: "b"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
experimental_debug_info {
}
}
node {
name: "cst0"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
dim {
size: 4
}
}
float_val: 1.0
float_val: 2.0
float_val: 3.0
float_val: 4.0
}
}
}
}
node {
name: "cst1"
op: "Const"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
dim {
size: 4
}
}
float_val: 5.0
float_val: 6.0
float_val: 7.0
float_val: 8.0
}
}
}
}
node {
name: "StatefulIf"
op: "If"
input: "tf.Less"
input: "a"
input: "b"
input: "cst0"
input: "cst1"
attr {
key: "Tcond"
value {
type: DT_BOOL
}
}
attr {
key: "Tin"
value {
list {
type: DT_FLOAT
type: DT_FLOAT
type: DT_FLOAT
type: DT_FLOAT
}
}
}
attr {
key: "Tout"
value {
list {
type: DT_FLOAT
}
}
}
attr {
key: "else_branch"
value {
func {
name: "cond_false"
}
}
}
attr {
key: "then_branch"
value {
func {
name: "cond_true"
}
}
}
experimental_debug_info {
}
}
node {
name: "StatelessIf"
op: "StatelessIf"
input: "my_equal"
input: "a"
input: "b"
attr {
key: "Tcond"
value {
type: DT_BOOL
}
}
attr {
key: "Tin"
value {
list {
type: DT_FLOAT
type: DT_FLOAT
}
}
}
attr {
key: "Tout"
value {
list {
type: DT_FLOAT
}
}
}
attr {
key: "else_branch"
value {
func {
name: "cond_false_1"
}
}
}
attr {
key: "then_branch"
value {
func {
name: "cond_true_1"
}
}
}
experimental_debug_info {
}
}
node {
name: "main"
op: "_Retval"
input: "StatefulIf"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "index"
value {
i: 0
}
}
}
node {
name: "main1"
op: "_Retval"
input: "StatelessIf"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "index"
value {
i: 1
}
}
}
node {
name: "a"
op: "Placeholder"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
experimental_debug_info {
}
}
node {
name: "b"
op: "Placeholder"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
experimental_debug_info {
}
}
library {
function {
signature {
name: "cond_true"
input_arg {
name: "cond_true_arg0"
type: DT_FLOAT
}
input_arg {
name: "cond_true_arg1"
type: DT_FLOAT
}
input_arg {
name: "cond_true_arg2"
type: DT_FLOAT
}
input_arg {
name: "cond_true_arg3"
type: DT_FLOAT
}
output_arg {
name: "cond_true_ret"
type: DT_FLOAT
}
}
node_def {
name: "tf.Add"
op: "Add"
input: "cond_true_arg2"
input: "cond_true_arg3"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
experimental_debug_info {
original_node_names: "tf.Add"
}
}
ret {
key: "cond_true_ret"
value: "tf.Add:z:0"
}
}
function {
signature {
name: "cond_false"
input_arg {
name: "cond_false_arg0"
type: DT_FLOAT
}
input_arg {
name: "cond_false_arg1"
type: DT_FLOAT
}
input_arg {
name: "cond_false_arg2"
type: DT_FLOAT
}
input_arg {
name: "cond_false_arg3"
type: DT_FLOAT
}
output_arg {
name: "cond_false_ret"
type: DT_FLOAT
}
}
node_def {
name: "tf.Mul"
op: "Mul"
input: "cond_false_arg0"
input: "cond_false_arg3"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
experimental_debug_info {
original_node_names: "tf.Mul"
}
}
ret {
key: "cond_false_ret"
value: "tf.Mul:z:0"
}
}
function {
signature {
name: "cond_true_1"
input_arg {
name: "cond_true_arg0"
type: DT_FLOAT
}
input_arg {
name: "cond_true_arg1"
type: DT_FLOAT
}
output_arg {
name: "cond_true_ret"
type: DT_FLOAT
}
}
node_def {
name: "tf.Sub"
op: "Sub"
input: "cond_true_arg0"
input: "cond_true_arg1"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
experimental_debug_info {
original_node_names: "tf.Sub"
}
}
ret {
key: "cond_true_ret"
value: "tf.Sub:z:0"
}
}
function {
signature {
name: "cond_false_1"
input_arg {
name: "cond_false_arg0"
type: DT_FLOAT
}
input_arg {
name: "cond_false_arg1"
type: DT_FLOAT
}
output_arg {
name: "cond_false_ret"
type: DT_FLOAT
}
}
node_def {
name: "tf.Div"
op: "Div"
input: "cond_false_arg0"
input: "cond_false_arg1"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
experimental_debug_info {
original_node_names: "tf.Div"
}
}
ret {
key: "cond_false_ret"
value: "tf.Div:z:0"
}
}
}
versions {
producer: 115
min_consumer: 12
}
# CHECK: func @main
# CHECK-DAG: constant dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00]>
# CHECK-DAG: constant dense<[5.000000e+00, 6.000000e+00, 7.000000e+00, 8.000000e+00]>
# CHECK: "tf.If"{{.+}}else_branch = @cond_false_10{{.+}}is_stateless = true{{.+}}then_branch = @cond_true_10
# CHECK: "tf.If"{{.+}}else_branch = @cond_false0{{.+}}is_stateless = false{{.+}}then_branch = @cond_true0
# CHECK: func private @cond_false_10
# CHECK-NEXT: tfl.div
# CHECK: func private @cond_true_10
# CHECK-NEXT: tfl.sub
# CHECK: func private @cond_false0
# CHECK-NEXT: tfl.mul
# CHECK: func private @cond_true0
# CHECK-NEXT: tfl.add
@@ -0,0 +1,124 @@
# RUN: tf_tfl_translate -tf-input-arrays=input0,input1 \
# RUN: -tf-input-shapes=4:4 \
# RUN: -tf-input-data-types=DT_FLOAT,DT_FLOAT \
# RUN: -tf-output-arrays=Add \
# RUN: -tf-inference-type=DT_QUINT8 \
# RUN: -tf-input-min-values='-2,-3' \
# RUN: -tf-input-max-values='2,3' \
# RUN: --quant-stats=%s.stats \
# RUN: %s -o - --output-mlir 2>&1 \
# RUN: | FileCheck --check-prefix=MLIR %s
# RUN: tf_tfl_translate -tf-input-arrays=input0,input1 \
# RUN: -tf-input-shapes=4:4 \
# RUN: -tf-input-data-types=DT_FLOAT,DT_FLOAT \
# RUN: -tf-output-arrays=Add \
# RUN: -tf-inference-type=DT_QUINT8 \
# RUN: -tf-input-min-values='-2,-3' \
# RUN: -tf-input-max-values='2,3' \
# RUN: --quant-stats=%s.stats \
# RUN: %s -o - \
# RUN: | flatbuffer_to_string - \
# RUN: | FileCheck %s
node {
name: "Add"
op: "Add"
input: "input0"
input: "input1"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
}
node {
name: "input0"
op: "Placeholder"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
}
node {
name: "input1"
op: "Placeholder"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
}
versions {
producer: 27
}
# MLIR-LABEL: func @main(%arg0: tensor<4x!quant.uniform<u8:f32, 0.015686274509803921:128>>, %arg1: tensor<4x!quant.uniform<u8:f32, 0.023529411764705882:128>>) -> tensor<4x!quant.uniform<u8:f32, 0.0078431372549019607:128>>
# MLIR-SAME: attributes {tf.entry_function = {control_outputs = "", inputs = "input0,input1", outputs = "Add"}} {
# MLIR-NEXT: %[[add:.*]] = tfl.add(%arg0, %arg1) <{fused_activation_function = "NONE"}> : (tensor<4x!quant.uniform<u8:f32, 0.015686274509803921:128>>, tensor<4x!quant.uniform<u8:f32, 0.023529411764705882:128>>) -> tensor<4x!quant.uniform<u8:f32, 0.0078431372549019607:128>>
# MLIR-NEXT: return %[[add]] : tensor<4x!quant.uniform<u8:f32, 0.0078431372549019607:128>>
# MLIR-NEXT: }
# CHECK-LABEL: {
# CHECK-NEXT: version: 3,
# CHECK-NEXT: operator_codes: [ {
# CHECK-NEXT: version: 1
# CHECK-NEXT: } ],
# CHECK-NEXT: subgraphs: [ {
# CHECK-NEXT: tensors: [ {
# CHECK-NEXT: shape: [ 4 ],
# CHECK-NEXT: type: UINT8,
# CHECK-NEXT: buffer: 1,
# CHECK-NEXT: name: "input0",
# CHECK-NEXT: quantization: {
# CHECK-NEXT: scale: [ 0.015686 ],
# CHECK-NEXT: zero_point: [ 128 ]
# CHECK-NEXT: },
# CHECK-NEXT: has_rank: true
# CHECK-NEXT: }, {
# CHECK-NEXT: shape: [ 4 ],
# CHECK-NEXT: type: UINT8,
# CHECK-NEXT: buffer: 2,
# CHECK-NEXT: name: "input1",
# CHECK-NEXT: quantization: {
# CHECK-NEXT: scale: [ 0.023529 ],
# CHECK-NEXT: zero_point: [ 128 ]
# CHECK-NEXT: },
# CHECK-NEXT: has_rank: true
# CHECK-NEXT: }, {
# CHECK-NEXT: shape: [ 4 ],
# CHECK-NEXT: type: UINT8,
# CHECK-NEXT: buffer: 3,
# CHECK-NEXT: name: "Add",
# CHECK-NEXT: quantization: {
# CHECK-NEXT: scale: [ 0.007843 ],
# CHECK-NEXT: zero_point: [ 128 ]
# CHECK-NEXT: },
# CHECK-NEXT: has_rank: true
# CHECK-NEXT: } ],
# CHECK-NEXT: inputs: [ 0, 1 ],
# CHECK-NEXT: outputs: [ 2 ],
# CHECK-NEXT: operators: [ {
# CHECK-NEXT: inputs: [ 0, 1 ],
# CHECK-NEXT: outputs: [ 2 ],
# CHECK-NEXT: builtin_options_type: AddOptions,
# CHECK-NEXT: builtin_options: {
# CHECK-EMPTY:
# CHECK-NEXT: }
# CHECK-NEXT: } ],
# CHECK-NEXT: name: "main"
# CHECK-NEXT: } ],
# CHECK-NEXT: description: "MLIR Converted.",
# CHECK-NEXT: buffers: [ {
# CHECK-EMPTY:
# CHECK-NEXT: }, {
# CHECK-EMPTY:
# CHECK-NEXT: }, {
# CHECK-EMPTY:
# CHECK-NEXT: }, {
# CHECK: data: [ 49, 46, 53, 46, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
# CHECK-NEXT: } ]
@@ -0,0 +1,9 @@
entries {
name: "Add"
params {
min_max {
min: -1
max: 1
}
}
}
@@ -0,0 +1,90 @@
# RUN: tf_tfl_translate -tf-input-arrays=Placeholder,Placeholder_1 -tf-input-shapes=2,5,3:3,7 -tf-input-data-types=DT_FLOAT,DT_FLOAT -tf-output-arrays=MatMul -unfold_batchmatmul=true -output-mlir %s -o - 2>&1 | FileCheck %s
node {
name: "Placeholder"
op: "Placeholder"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "shape"
value {
shape {
dim {
size: 2
}
dim {
size: 5
}
dim {
size: 3
}
}
}
}
}
node {
name: "Placeholder_1"
op: "Placeholder"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "shape"
value {
shape {
dim {
size: 3
}
dim {
size: 7
}
}
}
}
}
node {
name: "MatMul"
op: "BatchMatMulV2"
input: "Placeholder"
input: "Placeholder_1"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "adj_x"
value {
b: false
}
}
attr {
key: "adj_y"
value {
b: false
}
}
}
versions {
producer: 175
}
# CHECK: func @main(%[[VAL_0:.*]]: tensor<2x5x3xf32>, %[[VAL_1:.*]]: tensor<3x7xf32>) -> tensor<2x5x7xf32> attributes {tf.entry_function = {control_outputs = "", inputs = "Placeholder,Placeholder_1", outputs = "MatMul"}} {
# CHECK-DAG: %[[VAL_2:.*]] = arith.constant dense<[1, 0]> : tensor<2xi32>
# CHECK-DAG: %[[VAL_3:.*]] = "tfl.no_value"() <{value}> : () -> none
# CHECK-DAG: %[[VAL_6:.*]] = arith.constant dense<0> : tensor<i32>
# CHECK: %[[VAL_7:.*]]:2 = "tfl.split"(%[[VAL_6]], %[[VAL_0]]) <{num_splits = 2 : i32}> : (tensor<i32>, tensor<2x5x3xf32>) -> (tensor<1x5x3xf32>, tensor<1x5x3xf32>)
# CHECK: %[[VAL_9:.*]] = "tfl.transpose"(%[[VAL_1]], %[[VAL_2]]) : (tensor<3x7xf32>, tensor<2xi32>) -> tensor<7x3xf32>
# CHECK: %[[VAL_10:.*]] = "tfl.fully_connected"(%[[VAL_7]]#0, %[[VAL_9]], %[[VAL_3]]) <{fused_activation_function = "NONE", keep_num_dims = false, weights_format = "DEFAULT"}> : (tensor<1x5x3xf32>, tensor<7x3xf32>, none) -> tensor<5x7xf32>
# CHECK: %[[VAL_11:.*]] = "tfl.fully_connected"(%[[VAL_7]]#1, %[[VAL_9]], %[[VAL_3]]) <{fused_activation_function = "NONE", keep_num_dims = false, weights_format = "DEFAULT"}> : (tensor<1x5x3xf32>, tensor<7x3xf32>, none) -> tensor<5x7xf32>
# CHECK: %[[VAL_12:.*]] = "tfl.pack"(%[[VAL_10]], %[[VAL_11]]) <{axis = 0 : i32, values_count = 2 : i32}> : (tensor<5x7xf32>, tensor<5x7xf32>) -> tensor<2x5x7xf32>
# CHECK: return %[[VAL_12]] : tensor<2x5x7xf32>
# CHECK: }
@@ -0,0 +1,83 @@
# RUN: tf_tfl_translate -unfold_batchmatmul=false -tf-input-arrays=Placeholder,Placeholder_1 -tf-input-shapes=2,5,3:3,7 -tf-input-data-types=DT_FLOAT,DT_FLOAT -tf-output-arrays=MatMul -output-mlir %s -o - 2>&1 | FileCheck %s
node {
name: "Placeholder"
op: "Placeholder"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "shape"
value {
shape {
dim {
size: 2
}
dim {
size: 5
}
dim {
size: 3
}
}
}
}
}
node {
name: "Placeholder_1"
op: "Placeholder"
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "shape"
value {
shape {
dim {
size: 3
}
dim {
size: 7
}
}
}
}
}
node {
name: "MatMul"
op: "BatchMatMulV2"
input: "Placeholder"
input: "Placeholder_1"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "adj_x"
value {
b: false
}
}
attr {
key: "adj_y"
value {
b: false
}
}
}
versions {
producer: 175
}
# CHECK: func @main(%[[VAL_0:.*]]: tensor<2x5x3xf32>, %[[VAL_1:.*]]: tensor<3x7xf32>) -> tensor<2x5x7xf32> attributes {tf.entry_function = {control_outputs = "", inputs = "Placeholder,Placeholder_1", outputs = "MatMul"}} {
# CHECK: %[[VAL_2:.*]] = "tfl.batch_matmul"(%[[VAL_0]], %[[VAL_1]]) <{adj_x = false, adj_y = false}> : (tensor<2x5x3xf32>, tensor<3x7xf32>) -> tensor<2x5x7xf32>
# CHECK: return %[[VAL_2]] : tensor<2x5x7xf32>
# CHECK: }
@@ -0,0 +1,65 @@
load("//tensorflow:tensorflow.bzl", "tf_native_cc_binary")
load("//tensorflow:tensorflow.default.bzl", "filegroup")
load("//tensorflow/compiler/mlir:glob_lit_test.bzl", "glob_lit_tests")
# copybara:uncomment package(default_applicable_licenses = ["//tensorflow:LICENSE"])
licenses(["notice"])
glob_lit_tests(
name = "all_tests",
data = [
":extra_files",
":test_utilities",
],
driver = "@llvm-project//mlir:run_lit.sh",
test_file_exts = [
"mlir",
"cc",
"json",
],
)
# Bundle together all of the test utilities that are used by tests.
filegroup(
name = "test_utilities",
testonly = True,
data = [
":importer_test_min_max",
":test_schema.fbs",
"//tensorflow/compiler/mlir/lite:flatbuffer_to_string",
"//tensorflow/compiler/mlir/lite:flatbuffer_translate",
"//tensorflow/compiler/mlir/lite:json_to_flatbuffer",
"//tensorflow/compiler/mlir/lite:litert-opt",
"//tensorflow/compiler/mlir/lite:tf_tfl_translate",
"@llvm-project//llvm:FileCheck",
],
)
# Bundle together all the files that are used by the non-mlir file-based tests.
filegroup(
name = "extra_files",
srcs = glob(
[
"**/importer_test_min_max.cc.mlir",
"**/reshape.mlir",
],
),
)
# A binary to inject min/max to a tflite model.
# A file check command is used to verify the imported result from this
# binary format.
tf_native_cc_binary(
name = "importer_test_min_max",
srcs = [
"importer_test_min_max.cc",
],
deps = [
"//tensorflow/compiler/mlir/lite/core:absl_error_model_builder",
"//tensorflow/compiler/mlir/lite/schema:schema_fbs",
"//tensorflow/compiler/mlir/lite/schema:schema_utils",
"@com_google_absl//absl/strings",
"@llvm-project//llvm:Support",
],
)
@@ -0,0 +1,24 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// Ensure basic_lstm roundtrip exactly
func.func @main(%arg0: tensor<1x384xf32>, %arg1: tensor<1x96xf32>, %arg2: tensor<384x480xf32>, %arg3: tensor<384xf32>, %arg4: tensor<1x96xf32>) -> tensor<1x96xf32> {
// CHECK-LABEL: @main
// CHECK: "tfl.basic_lstm"({{.*}}) <{cell_clip = 1.000000e+00 : f32, fused_activation_function = "RELU", kernel_type = #tfl<lstm_kernel_type_attr BASIC>, proj_clip = 2.000000e+00 : f32}> {asymmetric_quantize_inputs = false} : (tensor<1x384xf32>, tensor<1x96xf32>, tensor<384x480xf32>, tensor<384xf32>, tensor<1x96xf32>) -> (tensor<1x96xf32>, tensor<1x96xf32>, tensor<1x480xf32>, tensor<1x384xf32>)
%0:4 = "tfl.basic_lstm"(%arg0, %arg1, %arg2, %arg3, %arg4) {fused_activation_function = "RELU", cell_clip = 1.0 : f32, proj_clip = 2.0 : f32} : (tensor<1x384xf32>, tensor<1x96xf32>, tensor<384x480xf32>, tensor<384xf32>, tensor<1x96xf32>) -> (tensor<1x96xf32>, tensor<1x96xf32>, tensor<1x480xf32>, tensor<1x384xf32>)
func.return %0#0 : tensor<1x96xf32>
}
@@ -0,0 +1,49 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: tf_tfl_translate --enable-hlo-to-tf-conversion --input-mlir %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s --check-prefix=CHECK-ROUNDTRIP
module {
// CHECK-LABEL: func.func public @main
func.func public @main(%arg0: tensor<3x2x4x7x9xi32>, %arg1: tensor<4x3x5x2xi32>) -> tensor<4x3x5x8xi32> {
// CHECK-ROUNDTRIP: %0 = "tfl.pseudo_const"() <{value = dense<{{\[\[\[\[}}0]], {{\[\[}}1]], {{\[\[}}2]]]]> : tensor<1x3x1x1xi32>}> : () -> tensor<1x3x1x1xi32>
// CHECK-ROUNDTRIP: %1 = "tfl.pseudo_const"() <{value = dense<[4, 3, 5, 1]> : tensor<4xi64>}> : () -> tensor<4xi64>
// CHECK-ROUNDTRIP: %2 = "tfl.broadcast_to"(%0, %1) : (tensor<1x3x1x1xi32>, tensor<4xi64>) -> tensor<4x3x5x1xi32>
// CHECK-ROUNDTRIP: %3 = "tfl.pseudo_const"() <{value = dense<{{\[\[\[\[}}0]]], {{\[\[\[}}1]]], {{\[\[\[}}2]]], {{\[\[\[}}3]]]]> : tensor<4x1x1x1xi32>}> : () -> tensor<4x1x1x1xi32>
// CHECK-ROUNDTRIP: %4 = "tfl.broadcast_to"(%3, %1) : (tensor<4x1x1x1xi32>, tensor<4xi64>) -> tensor<4x3x5x1xi32>
// CHECK-ROUNDTRIP: %[[concat:.*]] = "tfl.concatenation"(%2, %4, %arg1) <{axis = 3 : i32, fused_activation_function = "NONE"}> :
// CHECK-ROUNDTRIP-SAME: (tensor<4x3x5x1xi32>, tensor<4x3x5x1xi32>, tensor<4x3x5x2xi32>) -> tensor<4x3x5x4xi32>
// CHECK-ROUNDTRIP: %[[gather:.*]] = "stablehlo.gather"(%arg0, %[[concat]]) <{
// CHECK-ROUNDTRIP-SAME: dimension_numbers = #stablehlo.gather<
// CHECK-ROUNDTRIP-SAME: offset_dims = [3], collapsed_slice_dims = [0, 1, 2, 3],
// CHECK-ROUNDTRIP-SAME: start_index_map = [0, 2, 1, 3], index_vector_dim = 3>,
// CHECK-ROUNDTRIP-SAME: slice_sizes = array<i64: 1, 1, 1, 1, 8>}> :
// CHECK-ROUNDTRIP-SAME: (tensor<3x2x4x7x9xi32>, tensor<4x3x5x4xi32>) -> tensor<4x3x5x8xi32>
// CHECK-ROUNDTRIP: return %[[gather]]
%0 = "stablehlo.gather"(%arg0, %arg1) {
dimension_numbers = #stablehlo.gather<
offset_dims = [3],
collapsed_slice_dims = [1, 3],
operand_batching_dims = [0, 2],
start_indices_batching_dims = [1, 0],
start_index_map = [1, 3],
index_vector_dim = 3
>,
slice_sizes = array<i64: 1, 1, 1, 1, 8>,
indices_are_sorted = false
} : (tensor<3x2x4x7x9xi32>, tensor<4x3x5x2xi32>) -> tensor<4x3x5x8xi32>
return %0 : tensor<4x3x5x8xi32>
}
}
@@ -0,0 +1,51 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: tf_tfl_translate --enable-hlo-to-tf-conversion --input-mlir %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s --check-prefix=CHECK-ROUNDTRIP
module {
// CHECK-LABEL: func.func public @main
func.func public @main(%arg0: tensor<3x2x4x7x9xi32>, %arg1: tensor<4x3x5x2xi32>, %arg2: tensor<4x3x5x8xi32>) -> tensor<3x2x4x7x9xi32> {
// CHECK-ROUNDTRIP: %0 = "tfl.pseudo_const"() <{value = dense<{{\[\[\[\[}}0]], {{\[\[}}1]], {{\[\[}}2]]]]> : tensor<1x3x1x1xi32>}> : () -> tensor<1x3x1x1xi32>
// CHECK-ROUNDTRIP: %1 = "tfl.pseudo_const"() <{value = dense<[4, 3, 5, 1]> : tensor<4xi64>}> : () -> tensor<4xi64>
// CHECK-ROUNDTRIP: %2 = "tfl.broadcast_to"(%0, %1) : (tensor<1x3x1x1xi32>, tensor<4xi64>) -> tensor<4x3x5x1xi32>
// CHECK-ROUNDTRIP: %3 = "tfl.pseudo_const"() <{value = dense<{{\[\[\[\[}}0]]], {{\[\[\[}}1]]], {{\[\[\[}}2]]], {{\[\[\[}}3]]]]> : tensor<4x1x1x1xi32>}> : () -> tensor<4x1x1x1xi32>
// CHECK-ROUNDTRIP: %4 = "tfl.broadcast_to"(%3, %1) : (tensor<4x1x1x1xi32>, tensor<4xi64>) -> tensor<4x3x5x1xi32>
// CHECK-ROUNDTRIP: %[[concat:.*]] = "tfl.concatenation"(%2, %4, %arg1) <{axis = 3 : i32, fused_activation_function = "NONE"}> :
// CHECK-ROUNDTRIP-SAME: (tensor<4x3x5x1xi32>, tensor<4x3x5x1xi32>, tensor<4x3x5x2xi32>) -> tensor<4x3x5x4xi32>
// CHECK-ROUNDTRIP: %[[scatter:.*]] = "stablehlo.scatter"(%arg0, %[[concat]], %arg2) <{
// CHECK-ROUNDTRIP-SAME: scatter_dimension_numbers = #stablehlo.scatter
// CHECK-ROUNDTRIP-SAME: update_window_dims = [3], inserted_window_dims = [0, 1, 2, 3],
// CHECK-ROUNDTRIP-SAME: scatter_dims_to_operand_dims = [0, 2, 1, 3], index_vector_dim = 3>}>
// CHECK-ROUNDTRIP: (tensor<3x2x4x7x9xi32>, tensor<4x3x5x4xi32>, tensor<4x3x5x8xi32>) -> tensor<3x2x4x7x9xi32>
// CHECK-ROUNDTRIP: return %[[scatter]]
%0 = "stablehlo.scatter"(%arg0, %arg1, %arg2) <{
indices_are_sorted = false,
scatter_dimension_numbers = #stablehlo.scatter<
update_window_dims = [3],
inserted_window_dims = [1, 3],
input_batching_dims = [0, 2],
scatter_indices_batching_dims = [1, 0],
scatter_dims_to_operand_dims = [1, 3],
index_vector_dim = 3
>,
unique_indices = false
}> ({
^bb0(%arg3: tensor<i32>, %arg4: tensor<i32>):
stablehlo.return %arg4 : tensor<i32>
}) : (tensor<3x2x4x7x9xi32>, tensor<4x3x5x2xi32>, tensor<4x3x5x8xi32>) -> tensor<3x2x4x7x9xi32>
return %0 : tensor<3x2x4x7x9xi32>
}
}
@@ -0,0 +1,23 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// Ensure bucketize roundtrip exactly
func.func @main(%arg0: tensor<3x2xf32>) -> tensor<3x2xi32> {
// CHECK-LABEL: @main
// CHECK: "tfl.bucketize"(%arg0) <{boundaries = [0.000000e+00 : f32, 1.000000e+01 : f32, 1.000000e+02 : f32]}> : (tensor<3x2xf32>) -> tensor<3x2xi32>
%0 = "tfl.bucketize"(%arg0) {boundaries = [0.0 : f32, 10.0 : f32, 100.0 : f32]} : (tensor<3x2xf32>) -> tensor<3x2xi32>
func.return %0 : tensor<3x2xi32>
}
@@ -0,0 +1,26 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// Ensure cast with bfloat16 roundtrip exactly
func.func @main(tensor<4x5xbf16>) -> tensor<4x5xbf16> {
^bb0(%arg0: tensor<4x5xbf16>):
// CHECK-LABEL: @main
// CHECK: (tensor<4x5xbf16>) -> tensor<4x5xf32>
// CHECK-NEXT: (tensor<4x5xf32>) -> tensor<4x5xbf16>
%0 = "tfl.cast" (%arg0) : (tensor<4x5xbf16>) -> tensor<4x5xf32> loc("cast1")
%1 = "tfl.cast" (%0) : (tensor<4x5xf32>) -> tensor<4x5xbf16> loc("cast2")
func.return %1 : tensor<4x5xbf16>
}
@@ -0,0 +1,39 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: tf_tfl_translate --enable-hlo-to-tf-conversion --input-mlir %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s --check-prefix=CHECK-ROUNDTRIP
module {
func.func public @main( %arg0: tensor<i64>) -> tensor<i64> {
%0 = func.call @test_add_roundtrip(%arg0) : (tensor<i64>) -> tensor<i64>
return %0 : tensor<i64>
}
// CHECK-LABEL: func.func private @test_add_roundtrip
func.func private @test_add_roundtrip(%arg0: tensor<i64>) -> tensor<i64> {
// CHECK-ROUNDTRIP{LITERAL}: %0 = stablehlo.composite "stablehlo.add_n" %arg0 {composite_attributes = {test_bool = false, test_f32_tensor = dense<[[0.000000e+00, 1.000000e+00], [2.000000e+00, 3.000000e+00]]> : tensor<2x2xf32>, test_i32_tensor = dense<5> : tensor<1xi32>, test_i64_tensor = dense<[6, 7]> : tensor<2xi64>, test_int = 2 : i64, test_string = "test"}, decomposition = @add_n.impl} : (tensor<i64>) -> tensor<i64>
%0 = stablehlo.composite "stablehlo.add_n" %arg0 { composite_attributes = { test_int = 2 : i64, test_bool = 0 : i1, test_string = "test", test_i32_tensor = dense<5> : tensor<1xi32>, test_i64_tensor = dense<[6, 7]> : tensor<2xi64>, test_f32_tensor = dense<[[0.0, 1.0],[2.0, 3.0]]> : tensor<2x2xf32>}, decomposition = @add_n.impl } : (tensor<i64>) -> tensor<i64>
return %0 : tensor<i64>
}
func.func private @add_n.impl(%arg0: tensor<i64>) -> tensor<i64> {
%0 = stablehlo.constant dense<2> : tensor<i64>
%1 = stablehlo.add %arg0, %0 : tensor<i64>
return %1 : tensor<i64>
}
}
@@ -0,0 +1,162 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// Ensure constants roundtrip exactly
func.func @bool() -> tensor<4xi1> {
// CHECK-LABEL: @bool
// CHECK: value = dense<[false, true, true, false]> : tensor<4xi1>
%0 = "tfl.pseudo_const"() { value = dense<[false, true, true, false]> : tensor<4xi1> } : () -> tensor<4xi1>
func.return %0 : tensor<4xi1>
}
func.func @complex64() -> tensor<4xcomplex<f32>> {
// CHECK-LABEL: @complex64
// CHECK: value = #tf_type<tensor_proto : "0x746674656E736F722464747970653A2044545F434F4D504C455836342074656E736F725F7368617065207B2064696D207B2073697A653A2034207D207D2074656E736F725F636F6E74656E743A20225C3030305C3030305C3230303F5C3030305C3030305C3230303F5C3030305C3030305C303030405C3030305C3030305C303030405C3030305C30303040405C3030305C30303040405C3030305C3030305C323030405C3030305C3030305C3230304022"> : tensor<4xcomplex<f32>>
%0 = "tfl.pseudo_const"() { value = #tf_type<tensor_proto : "0x746674656E736F722464747970653A2044545F434F4D504C455836342074656E736F725F7368617065207B2064696D207B2073697A653A2034207D207D2074656E736F725F636F6E74656E743A20225C3030305C3030305C3230303F5C3030305C3030305C3230303F5C3030305C3030305C303030405C3030305C3030305C303030405C3030305C30303040405C3030305C30303040405C3030305C3030305C323030405C3030305C3030305C3230304022"> : tensor<4xcomplex<f32>> } : () -> tensor<4xcomplex<f32>>
func.return %0 : tensor<4xcomplex<f32>>
}
func.func @complex128() -> tensor<4xcomplex<f64>> {
// CHECK-LABEL: @complex128
// CHECK: value = #tf_type<tensor_proto : "0x746674656E736F722464747970653A2044545F434F4D504C45583132382074656E736F725F7368617065207B2064696D207B2073697A653A2034207D207D2074656E736F725F636F6E74656E743A20225C3030305C3030305C3030305C3030305C3030305C3030305C3336303F5C3030305C3030305C3030305C3030305C3030305C3030305C303030405C3030305C3030305C3030305C3030305C3030305C3030305C303030405C3030305C3030305C3030305C3030305C3030305C3030305C303030405C3030305C3030305C3030305C3030305C3030305C3030305C303130405C3030305C3030305C3030305C3030305C3030305C3030305C303030405C3030305C3030305C3030305C3030305C3030305C3030305C303230405C3030305C3030305C3030305C3030305C3030305C3030305C3030304022"> : tensor<4xcomplex<f64>>
%0 = "tfl.pseudo_const"() { value = #tf_type<tensor_proto : "0x746674656E736F722464747970653A2044545F434F4D504C45583132382074656E736F725F7368617065207B2064696D207B2073697A653A2034207D207D2074656E736F725F636F6E74656E743A20225C3030305C3030305C3030305C3030305C3030305C3030305C3336303F5C3030305C3030305C3030305C3030305C3030305C3030305C303030405C3030305C3030305C3030305C3030305C3030305C3030305C303030405C3030305C3030305C3030305C3030305C3030305C3030305C303030405C3030305C3030305C3030305C3030305C3030305C3030305C303130405C3030305C3030305C3030305C3030305C3030305C3030305C303030405C3030305C3030305C3030305C3030305C3030305C3030305C303230405C3030305C3030305C3030305C3030305C3030305C3030305C3030304022"> : tensor<4xcomplex<f64>> } : () -> tensor<4xcomplex<f64>>
func.return %0 : tensor<4xcomplex<f64>>
}
func.func @f16() -> tensor<4xf16> {
// CHECK-LABEL: @f16
// CHECK: value = dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00]> : tensor<4xf16>
%0 = "tfl.pseudo_const"() { value = dense<[1.0, 2.0, 3.0, 4.0]> : tensor<4xf16> } : () -> tensor<4xf16>
func.return %0 : tensor<4xf16>
}
func.func @f32() -> tensor<4xf32> {
// CHECK-LABEL: @f32
// CHECK: value = dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00]> : tensor<4xf32>
%0 = "tfl.pseudo_const"() { value = dense<[1.0, 2.0, 3.0, 4.0]> : tensor<4xf32> } : () -> tensor<4xf32>
func.return %0 : tensor<4xf32>
}
func.func @f64() -> tensor<4xf64> {
// CHECK-LABEL: @f64
// CHECK: value = dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00]> : tensor<4xf64>
%0 = "tfl.pseudo_const"() { value = dense<[1.0, 2.0, 3.0, 4.0]> : tensor<4xf64> } : () -> tensor<4xf64>
func.return %0 : tensor<4xf64>
}
func.func @i8() -> tensor<4xi8> {
// CHECK-LABEL: @i8
// CHECK: value = dense<[1, 2, 3, 4]> : tensor<4xi8>
%0 = "tfl.pseudo_const" () { value = dense<[1, 2, 3, 4]> : tensor<4xi8> } : () -> tensor<4xi8>
func.return %0 : tensor<4xi8>
}
func.func @i16() -> tensor<4xi16> {
// CHECK-LABEL: @i16
// CHECK: value = dense<[1, 2, 3, 258]> : tensor<4xi16>
%0 = "tfl.pseudo_const" () { value = dense<[1, 2, 3, 258]> : tensor<4xi16> } : () -> tensor<4xi16>
func.return %0 : tensor<4xi16>
}
func.func @i32() -> tensor<4xi32> {
// CHECK-LABEL: @i32
// CHECK: value = dense<[1, 2, 3, 16909060]> : tensor<4xi32>
// Check bytes come back in the right order
%0 = "tfl.pseudo_const" () { value = dense<[1, 2, 3, 16909060]> : tensor<4xi32> } : () -> tensor<4xi32>
func.return %0 : tensor<4xi32>
}
func.func @i64() -> tensor<4xi64> {
// CHECK-LABEL: @i64
// CHECK: value = dense<[1, 2, 3, 72623859790382856]> : tensor<4xi64>
%0 = "tfl.pseudo_const" () { value = dense<[1, 2, 3, 72623859790382856]> : tensor<4xi64> } : () -> tensor<4xi64>
func.return %0 : tensor<4xi64>
}
func.func @string() -> tensor<2x2x!tf_type.string> {
// CHECK-LABEL: @string
// CHECK: value = dense<{{\[\["1", "12"\], \["123", "1234"\]\]}}> : tensor<2x2x!tf_type.string>
%0 = "tfl.pseudo_const"() { value = dense<[["1", "12"], ["123", "1234"]]> : tensor<2x2x!tf_type.string> } : () -> tensor<2x2x!tf_type.string>
func.return %0 : tensor<2x2x!tf_type.string>
}
func.func @string_norank() -> tensor<!tf_type.string> {
// CHECK-LABEL: @string_norank
// CHECK: value = dense<"test"> : tensor<!tf_type.string>
%0 = "tfl.pseudo_const"() { value = dense<"test"> : tensor<!tf_type.string> } : () -> tensor<!tf_type.string>
func.return %0 : tensor<!tf_type.string>
}
func.func @uint8() -> tensor<4xui8> {
// CHECK-LABEL: @uint8
// CHECK: value = dense<[222, 173, 190, 239]> : tensor<4xui8>
%0 = "tfl.pseudo_const"() {value = dense<[222, 173, 190, 239]> : tensor<4xui8>} : () -> tensor<4xui8>
func.return %0 : tensor<4xui8>
}
func.func @int4() -> tensor<5xi4> {
// CHECK-LABEL: @int4
// CHECK: value = dense<[6, 3, -2, -7, -8]> : tensor<5xi4>
%0 = "tfl.pseudo_const"() {value = dense<[6, 3, -2, -7, -8]> : tensor<5xi4>} : () -> tensor<5xi4>
func.return %0 : tensor<5xi4>
}
func.func @qi32_per_axis() -> tensor<3x3x!quant.uniform<i32:f32:1, {1.0, 0.5:1, 0.25:1}>> {
// CHECK-LABEL: @qi32_per_axis
// CHECK: <{qtype = tensor<3x3x!quant.uniform<i32:f32:1, {1.000000e+00,5.000000e-01:1,2.500000e-01:1}>>, value = dense<1> : tensor<3x3xi32>}> : () -> tensor<3x3x!quant.uniform<i32:f32:1, {1.000000e+00,5.000000e-01:1,2.500000e-01:1}>>
%0 = "tfl.pseudo_qconst"() { qtype = tensor<3x3x!quant.uniform<i32:f32:1, {1.0, 0.5:1, 0.25:1}>>, value = dense<1> : tensor<3x3xi32>} : () -> tensor<3x3x!quant.uniform<i32:f32:1, {1.0, 0.5:1, 0.25:1}>>
func.return %0 : tensor<3x3x!quant.uniform<i32:f32:1, {1.0, 0.5:1, 0.25:1}>>
}
func.func @qi32_per_axis_zero() -> tensor<3x3x!quant.uniform<i32:f32:0, {1.0, 0.5:1, 0.25:1}>> {
// CHECK-LABEL: @qi32_per_axis_zero
// CHECK: <{qtype = tensor<3x3x!quant.uniform<i32:f32:0, {1.000000e+00,5.000000e-01:1,2.500000e-01:1}>>, value = dense<1> : tensor<3x3xi32>}> : () -> tensor<3x3x!quant.uniform<i32:f32:0, {1.000000e+00,5.000000e-01:1,2.500000e-01:1}>>
%0 = "tfl.pseudo_qconst"() { qtype = tensor<3x3x!quant.uniform<i32:f32:0, {1.0, 0.5:1, 0.25:1}>>, value = dense<1> : tensor<3x3xi32>} : () -> tensor<3x3x!quant.uniform<i32:f32:0, {1.0, 0.5:1, 0.25:1}>>
func.return %0 : tensor<3x3x!quant.uniform<i32:f32:0, {1.0, 0.5:1, 0.25:1}>>
}
func.func @qu8() -> tensor<3x!quant.uniform<u8<1:255>:f32, 1.0>> {
// CHECK-LABEL: @qu8
// CHECK: <{qtype = tensor<3x!quant.uniform<u8<1:255>:f32, 1.000000e+00>>, value = dense<1> : tensor<3xi8>}> : () -> tensor<3x!quant.uniform<u8<1:255>:f32, 1.000000e+00>>
%0 = "tfl.pseudo_qconst"() { qtype = tensor<3x!quant.uniform<u8<1:255>:f32, 1.0>>, value = dense<1> : tensor<3xi8>} : () -> tensor<3x!quant.uniform<u8<1:255>:f32, 1.0>>
func.return %0 : tensor<3x!quant.uniform<u8<1:255>:f32, 1.0>>
}
func.func @sparse_f32() -> tensor<3x2xf32> {
// CHECK-LABEL: @sparse_f32
// CHECK: <{compressed_data = dense<[1.000000e+00, 2.000000e+00, 5.000000e-01, 2.500000e-01, -1.000000e+00, -2.000000e+00, -5.000000e-01, -2.500000e-01]> : tensor<8xf32>, s_param = #tfl.sparsity_parameter<traversal_order = [0, 1, 2, 3], block_map = [3, 1], dim_metadata = <format = DENSE, dense_size = 16, segments = [], indices = []>, <format = DENSE, dense_size = 1, segments = [], indices = []>, <format = DENSE, dense_size = 1, segments = [], indices = []>, <format = SPARSE_CSR, dense_size = 0, segments = [0, 5, 11], indices = [1, 4, 9]>>, value = dense<0.000000e+00> : tensor<3x2xf32>}>
%0 = "tfl.pseudo_sparse_const"() {compressed_data = dense<[1.0, 2.0, 0.5, 0.25, -1.0, -2.0, -0.5, -0.25]> : tensor<8xf32>, s_param = #tfl.sparsity_parameter<traversal_order = [0, 1, 2, 3], block_map = [3, 1], dim_metadata = #tfl.dimension_metadata<format = DENSE, dense_size = 16, segments = [], indices = []>, #tfl.dimension_metadata<format = DENSE, dense_size = 1, segments = [], indices = []>, #tfl.dimension_metadata<format = DENSE, dense_size = 1, segments = [], indices = []>, #tfl.dimension_metadata<format = SPARSE_CSR, dense_size = 0, segments = [0, 5, 11], indices = [1, 4, 9]>>, value = dense<0.000000e+00> : tensor<3x2xf32>} : () -> tensor<3x2xf32>
func.return %0: tensor<3x2xf32>
}
func.func @sparse_f16() -> tensor<3x2xf16> {
// CHECK-LABEL: @sparse_f16
// CHECK: <{compressed_data = dense<[1.000000e+00, 2.000000e+00, 5.000000e-01, 2.500000e-01, -1.000000e+00, -2.000000e+00, -5.000000e-01, -2.500000e-01]> : tensor<8xf16>, s_param = #tfl.sparsity_parameter<traversal_order = [0, 1, 2, 3], block_map = [3, 1], dim_metadata = <format = DENSE, dense_size = 16, segments = [], indices = []>, <format = DENSE, dense_size = 1, segments = [], indices = []>, <format = DENSE, dense_size = 1, segments = [], indices = []>, <format = SPARSE_CSR, dense_size = 0, segments = [0, 5, 11], indices = [1, 4, 9]>>, value = dense<0.000000e+00> : tensor<3x2xf16>}>
%0 = "tfl.pseudo_sparse_const"() {compressed_data = dense<[1.0, 2.0, 0.5, 0.25, -1.0, -2.0, -0.5, -0.25]> : tensor<8xf16>, s_param = #tfl.sparsity_parameter<traversal_order = [0, 1, 2, 3], block_map = [3, 1], dim_metadata = #tfl.dimension_metadata<format = DENSE, dense_size = 16, segments = [], indices = []>, #tfl.dimension_metadata<format = DENSE, dense_size = 1, segments = [], indices = []>, #tfl.dimension_metadata<format = DENSE, dense_size = 1, segments = [], indices = []>, #tfl.dimension_metadata<format = SPARSE_CSR, dense_size = 0, segments = [0, 5, 11], indices = [1, 4, 9]>>, value = dense<0.000000e+00> : tensor<3x2xf16>} : () -> tensor<3x2xf16>
func.return %0: tensor<3x2xf16>
}
func.func @sparse_qu8() -> tensor<3x2x!quant.uniform<u8<1:255>:f32, 1.0>> {
// CHECK-LABEL: @sparse_qu8
// CHECK: <{compressed_data = dense<[1, 2, 3, 4, -1, -2, -3, -4]> : tensor<8xi8>, qtype = tensor<3x2x!quant.uniform<u8<1:255>:f32, 1.000000e+00>>, s_param = #tfl.sparsity_parameter<traversal_order = [0, 1, 2, 3], block_map = [3, 1], dim_metadata = <format = DENSE, dense_size = 16, segments = [], indices = []>, <format = DENSE, dense_size = 1, segments = [], indices = []>, <format = DENSE, dense_size = 1, segments = [], indices = []>, <format = SPARSE_CSR, dense_size = 0, segments = [0, 5, 11], indices = [1, 4, 9]>>, value = dense<0> : tensor<3x2xi8>}>
%0 = "tfl.pseudo_sparse_qconst"() {compressed_data = dense<[1, 2, 3, 4, -1, -2, -3, -4]> : tensor<8xi8>, qtype = tensor<3x2x!quant.uniform<u8<1:255>:f32, 1.0>>, s_param = #tfl.sparsity_parameter<traversal_order = [0, 1, 2, 3], block_map = [3, 1], dim_metadata = #tfl.dimension_metadata<format = DENSE, dense_size = 16, segments = [], indices = []>, #tfl.dimension_metadata<format = DENSE, dense_size = 1, segments = [], indices = []>, #tfl.dimension_metadata<format = DENSE, dense_size = 1, segments = [], indices = []>, #tfl.dimension_metadata<format = SPARSE_CSR, dense_size = 0, segments = [0, 5, 11], indices = [1, 4, 9]>>, value = dense<42> : tensor<3x2xi8>} : () -> tensor<3x2x!quant.uniform<u8<1:255>:f32, 1.0>>
func.return %0: tensor<3x2x!quant.uniform<u8<1:255>:f32, 1.0>>
}
// Identity function to make the exporter happy
func.func @main(%arg0: tensor<4xi8>) -> tensor<4xi8> {
func.return %arg0 : tensor<4xi8>
}
@@ -0,0 +1,162 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer --use-buffer-offset %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// Ensure constants roundtrip exactly
func.func @bool() -> tensor<4xi1> {
// CHECK-LABEL: @bool
// CHECK: value = dense<[false, true, true, false]> : tensor<4xi1>
%0 = "tfl.pseudo_const"() { value = dense<[false, true, true, false]> : tensor<4xi1> } : () -> tensor<4xi1>
func.return %0 : tensor<4xi1>
}
func.func @complex64() -> tensor<4xcomplex<f32>> {
// CHECK-LABEL: @complex64
// CHECK: value = #tf_type<tensor_proto : "0x746674656E736F722464747970653A2044545F434F4D504C455836342074656E736F725F7368617065207B2064696D207B2073697A653A2034207D207D2074656E736F725F636F6E74656E743A20225C3030305C3030305C3230303F5C3030305C3030305C3230303F5C3030305C3030305C303030405C3030305C3030305C303030405C3030305C30303040405C3030305C30303040405C3030305C3030305C323030405C3030305C3030305C3230304022"> : tensor<4xcomplex<f32>>
%0 = "tfl.pseudo_const"() { value = #tf_type<tensor_proto : "0x746674656E736F722464747970653A2044545F434F4D504C455836342074656E736F725F7368617065207B2064696D207B2073697A653A2034207D207D2074656E736F725F636F6E74656E743A20225C3030305C3030305C3230303F5C3030305C3030305C3230303F5C3030305C3030305C303030405C3030305C3030305C303030405C3030305C30303040405C3030305C30303040405C3030305C3030305C323030405C3030305C3030305C3230304022"> : tensor<4xcomplex<f32>> } : () -> tensor<4xcomplex<f32>>
func.return %0 : tensor<4xcomplex<f32>>
}
func.func @complex128() -> tensor<4xcomplex<f64>> {
// CHECK-LABEL: @complex128
// CHECK: value = #tf_type<tensor_proto : "0x746674656E736F722464747970653A2044545F434F4D504C45583132382074656E736F725F7368617065207B2064696D207B2073697A653A2034207D207D2074656E736F725F636F6E74656E743A20225C3030305C3030305C3030305C3030305C3030305C3030305C3336303F5C3030305C3030305C3030305C3030305C3030305C3030305C303030405C3030305C3030305C3030305C3030305C3030305C3030305C303030405C3030305C3030305C3030305C3030305C3030305C3030305C303030405C3030305C3030305C3030305C3030305C3030305C3030305C303130405C3030305C3030305C3030305C3030305C3030305C3030305C303030405C3030305C3030305C3030305C3030305C3030305C3030305C303230405C3030305C3030305C3030305C3030305C3030305C3030305C3030304022"> : tensor<4xcomplex<f64>>
%0 = "tfl.pseudo_const"() { value = #tf_type<tensor_proto : "0x746674656E736F722464747970653A2044545F434F4D504C45583132382074656E736F725F7368617065207B2064696D207B2073697A653A2034207D207D2074656E736F725F636F6E74656E743A20225C3030305C3030305C3030305C3030305C3030305C3030305C3336303F5C3030305C3030305C3030305C3030305C3030305C3030305C303030405C3030305C3030305C3030305C3030305C3030305C3030305C303030405C3030305C3030305C3030305C3030305C3030305C3030305C303030405C3030305C3030305C3030305C3030305C3030305C3030305C303130405C3030305C3030305C3030305C3030305C3030305C3030305C303030405C3030305C3030305C3030305C3030305C3030305C3030305C303230405C3030305C3030305C3030305C3030305C3030305C3030305C3030304022"> : tensor<4xcomplex<f64>> } : () -> tensor<4xcomplex<f64>>
func.return %0 : tensor<4xcomplex<f64>>
}
func.func @f16() -> tensor<4xf16> {
// CHECK-LABEL: @f16
// CHECK: value = dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00]> : tensor<4xf16>
%0 = "tfl.pseudo_const"() { value = dense<[1.0, 2.0, 3.0, 4.0]> : tensor<4xf16> } : () -> tensor<4xf16>
func.return %0 : tensor<4xf16>
}
func.func @f32() -> tensor<4xf32> {
// CHECK-LABEL: @f32
// CHECK: value = dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00]> : tensor<4xf32>
%0 = "tfl.pseudo_const"() { value = dense<[1.0, 2.0, 3.0, 4.0]> : tensor<4xf32> } : () -> tensor<4xf32>
func.return %0 : tensor<4xf32>
}
func.func @f64() -> tensor<4xf64> {
// CHECK-LABEL: @f64
// CHECK: value = dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00]> : tensor<4xf64>
%0 = "tfl.pseudo_const"() { value = dense<[1.0, 2.0, 3.0, 4.0]> : tensor<4xf64> } : () -> tensor<4xf64>
func.return %0 : tensor<4xf64>
}
func.func @i8() -> tensor<4xi8> {
// CHECK-LABEL: @i8
// CHECK: value = dense<[1, 2, 3, 4]> : tensor<4xi8>
%0 = "tfl.pseudo_const" () { value = dense<[1, 2, 3, 4]> : tensor<4xi8> } : () -> tensor<4xi8>
func.return %0 : tensor<4xi8>
}
func.func @i16() -> tensor<4xi16> {
// CHECK-LABEL: @i16
// CHECK: value = dense<[1, 2, 3, 258]> : tensor<4xi16>
%0 = "tfl.pseudo_const" () { value = dense<[1, 2, 3, 258]> : tensor<4xi16> } : () -> tensor<4xi16>
func.return %0 : tensor<4xi16>
}
func.func @i32() -> tensor<4xi32> {
// CHECK-LABEL: @i32
// CHECK: value = dense<[1, 2, 3, 16909060]> : tensor<4xi32>
// Check bytes come back in the right order
%0 = "tfl.pseudo_const" () { value = dense<[1, 2, 3, 16909060]> : tensor<4xi32> } : () -> tensor<4xi32>
func.return %0 : tensor<4xi32>
}
func.func @i64() -> tensor<4xi64> {
// CHECK-LABEL: @i64
// CHECK: value = dense<[1, 2, 3, 72623859790382856]> : tensor<4xi64>
%0 = "tfl.pseudo_const" () { value = dense<[1, 2, 3, 72623859790382856]> : tensor<4xi64> } : () -> tensor<4xi64>
func.return %0 : tensor<4xi64>
}
func.func @string() -> tensor<2x2x!tf_type.string> {
// CHECK-LABEL: @string
// CHECK: value = dense<{{\[\["1", "12"\], \["123", "1234"\]\]}}> : tensor<2x2x!tf_type.string>
%0 = "tfl.pseudo_const"() { value = dense<[["1", "12"], ["123", "1234"]]> : tensor<2x2x!tf_type.string> } : () -> tensor<2x2x!tf_type.string>
func.return %0 : tensor<2x2x!tf_type.string>
}
func.func @string_norank() -> tensor<!tf_type.string> {
// CHECK-LABEL: @string_norank
// CHECK: value = dense<"test"> : tensor<!tf_type.string>
%0 = "tfl.pseudo_const"() { value = dense<"test"> : tensor<!tf_type.string> } : () -> tensor<!tf_type.string>
func.return %0 : tensor<!tf_type.string>
}
func.func @uint8() -> tensor<4xui8> {
// CHECK-LABEL: @uint8
// CHECK: value = dense<[222, 173, 190, 239]> : tensor<4xui8>
%0 = "tfl.pseudo_const"() {value = dense<[222, 173, 190, 239]> : tensor<4xui8>} : () -> tensor<4xui8>
func.return %0 : tensor<4xui8>
}
func.func @int4() -> tensor<5xi4> {
// CHECK-LABEL: @int4
// CHECK: value = dense<[6, 3, -2, -7, -8]> : tensor<5xi4>
%0 = "tfl.pseudo_const"() {value = dense<[6, 3, -2, -7, -8]> : tensor<5xi4>} : () -> tensor<5xi4>
func.return %0 : tensor<5xi4>
}
func.func @qi32_per_axis() -> tensor<3x3x!quant.uniform<i32:f32:1, {1.0, 0.5:1, 0.25:1}>> {
// CHECK-LABEL: @qi32_per_axis
// CHECK: <{qtype = tensor<3x3x!quant.uniform<i32:f32:1, {1.000000e+00,5.000000e-01:1,2.500000e-01:1}>>, value = dense<1> : tensor<3x3xi32>}> : () -> tensor<3x3x!quant.uniform<i32:f32:1, {1.000000e+00,5.000000e-01:1,2.500000e-01:1}>>
%0 = "tfl.pseudo_qconst"() { qtype = tensor<3x3x!quant.uniform<i32:f32:1, {1.0, 0.5:1, 0.25:1}>>, value = dense<1> : tensor<3x3xi32>} : () -> tensor<3x3x!quant.uniform<i32:f32:1, {1.0, 0.5:1, 0.25:1}>>
func.return %0 : tensor<3x3x!quant.uniform<i32:f32:1, {1.0, 0.5:1, 0.25:1}>>
}
func.func @qi32_per_axis_zero() -> tensor<3x3x!quant.uniform<i32:f32:0, {1.0, 0.5:1, 0.25:1}>> {
// CHECK-LABEL: @qi32_per_axis_zero
// CHECK: <{qtype = tensor<3x3x!quant.uniform<i32:f32:0, {1.000000e+00,5.000000e-01:1,2.500000e-01:1}>>, value = dense<1> : tensor<3x3xi32>}> : () -> tensor<3x3x!quant.uniform<i32:f32:0, {1.000000e+00,5.000000e-01:1,2.500000e-01:1}>>
%0 = "tfl.pseudo_qconst"() { qtype = tensor<3x3x!quant.uniform<i32:f32:0, {1.0, 0.5:1, 0.25:1}>>, value = dense<1> : tensor<3x3xi32>} : () -> tensor<3x3x!quant.uniform<i32:f32:0, {1.0, 0.5:1, 0.25:1}>>
func.return %0 : tensor<3x3x!quant.uniform<i32:f32:0, {1.0, 0.5:1, 0.25:1}>>
}
func.func @qu8() -> tensor<3x!quant.uniform<u8<1:255>:f32, 1.0>> {
// CHECK-LABEL: @qu8
// CHECK: <{qtype = tensor<3x!quant.uniform<u8<1:255>:f32, 1.000000e+00>>, value = dense<1> : tensor<3xi8>}> : () -> tensor<3x!quant.uniform<u8<1:255>:f32, 1.000000e+00>>
%0 = "tfl.pseudo_qconst"() { qtype = tensor<3x!quant.uniform<u8<1:255>:f32, 1.0>>, value = dense<1> : tensor<3xi8>} : () -> tensor<3x!quant.uniform<u8<1:255>:f32, 1.0>>
func.return %0 : tensor<3x!quant.uniform<u8<1:255>:f32, 1.0>>
}
func.func @sparse_f32() -> tensor<3x2xf32> {
// CHECK-LABEL: @sparse_f32
// CHECK: <{compressed_data = dense<[1.000000e+00, 2.000000e+00, 5.000000e-01, 2.500000e-01, -1.000000e+00, -2.000000e+00, -5.000000e-01, -2.500000e-01]> : tensor<8xf32>, s_param = #tfl.sparsity_parameter<traversal_order = [0, 1, 2, 3], block_map = [3, 1], dim_metadata = <format = DENSE, dense_size = 16, segments = [], indices = []>, <format = DENSE, dense_size = 1, segments = [], indices = []>, <format = DENSE, dense_size = 1, segments = [], indices = []>, <format = SPARSE_CSR, dense_size = 0, segments = [0, 5, 11], indices = [1, 4, 9]>>, value = dense<0.000000e+00> : tensor<3x2xf32>}>
%0 = "tfl.pseudo_sparse_const"() {compressed_data = dense<[1.0, 2.0, 0.5, 0.25, -1.0, -2.0, -0.5, -0.25]> : tensor<8xf32>, s_param = #tfl.sparsity_parameter<traversal_order = [0, 1, 2, 3], block_map = [3, 1], dim_metadata = #tfl.dimension_metadata<format = DENSE, dense_size = 16, segments = [], indices = []>, #tfl.dimension_metadata<format = DENSE, dense_size = 1, segments = [], indices = []>, #tfl.dimension_metadata<format = DENSE, dense_size = 1, segments = [], indices = []>, #tfl.dimension_metadata<format = SPARSE_CSR, dense_size = 0, segments = [0, 5, 11], indices = [1, 4, 9]>>, value = dense<0.000000e+00> : tensor<3x2xf32>} : () -> tensor<3x2xf32>
func.return %0: tensor<3x2xf32>
}
func.func @sparse_f16() -> tensor<3x2xf16> {
// CHECK-LABEL: @sparse_f16
// CHECK: <{compressed_data = dense<[1.000000e+00, 2.000000e+00, 5.000000e-01, 2.500000e-01, -1.000000e+00, -2.000000e+00, -5.000000e-01, -2.500000e-01]> : tensor<8xf16>, s_param = #tfl.sparsity_parameter<traversal_order = [0, 1, 2, 3], block_map = [3, 1], dim_metadata = <format = DENSE, dense_size = 16, segments = [], indices = []>, <format = DENSE, dense_size = 1, segments = [], indices = []>, <format = DENSE, dense_size = 1, segments = [], indices = []>, <format = SPARSE_CSR, dense_size = 0, segments = [0, 5, 11], indices = [1, 4, 9]>>, value = dense<0.000000e+00> : tensor<3x2xf16>}>
%0 = "tfl.pseudo_sparse_const"() {compressed_data = dense<[1.0, 2.0, 0.5, 0.25, -1.0, -2.0, -0.5, -0.25]> : tensor<8xf16>, s_param = #tfl.sparsity_parameter<traversal_order = [0, 1, 2, 3], block_map = [3, 1], dim_metadata = #tfl.dimension_metadata<format = DENSE, dense_size = 16, segments = [], indices = []>, #tfl.dimension_metadata<format = DENSE, dense_size = 1, segments = [], indices = []>, #tfl.dimension_metadata<format = DENSE, dense_size = 1, segments = [], indices = []>, #tfl.dimension_metadata<format = SPARSE_CSR, dense_size = 0, segments = [0, 5, 11], indices = [1, 4, 9]>>, value = dense<0.000000e+00> : tensor<3x2xf16>} : () -> tensor<3x2xf16>
func.return %0: tensor<3x2xf16>
}
func.func @sparse_qu8() -> tensor<3x2x!quant.uniform<u8<1:255>:f32, 1.0>> {
// CHECK-LABEL: @sparse_qu8
// CHECK: <{compressed_data = dense<[1, 2, 3, 4, -1, -2, -3, -4]> : tensor<8xi8>, qtype = tensor<3x2x!quant.uniform<u8<1:255>:f32, 1.000000e+00>>, s_param = #tfl.sparsity_parameter<traversal_order = [0, 1, 2, 3], block_map = [3, 1], dim_metadata = <format = DENSE, dense_size = 16, segments = [], indices = []>, <format = DENSE, dense_size = 1, segments = [], indices = []>, <format = DENSE, dense_size = 1, segments = [], indices = []>, <format = SPARSE_CSR, dense_size = 0, segments = [0, 5, 11], indices = [1, 4, 9]>>, value = dense<0> : tensor<3x2xi8>}>
%0 = "tfl.pseudo_sparse_qconst"() {compressed_data = dense<[1, 2, 3, 4, -1, -2, -3, -4]> : tensor<8xi8>, qtype = tensor<3x2x!quant.uniform<u8<1:255>:f32, 1.0>>, s_param = #tfl.sparsity_parameter<traversal_order = [0, 1, 2, 3], block_map = [3, 1], dim_metadata = #tfl.dimension_metadata<format = DENSE, dense_size = 16, segments = [], indices = []>, #tfl.dimension_metadata<format = DENSE, dense_size = 1, segments = [], indices = []>, #tfl.dimension_metadata<format = DENSE, dense_size = 1, segments = [], indices = []>, #tfl.dimension_metadata<format = SPARSE_CSR, dense_size = 0, segments = [0, 5, 11], indices = [1, 4, 9]>>, value = dense<42> : tensor<3x2xi8>} : () -> tensor<3x2x!quant.uniform<u8<1:255>:f32, 1.0>>
func.return %0: tensor<3x2x!quant.uniform<u8<1:255>:f32, 1.0>>
}
// Identity function to make the exporter happy
func.func @main(%arg0: tensor<4xi8>) -> tensor<4xi8> {
func.return %arg0 : tensor<4xi8>
}
@@ -0,0 +1,75 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// We need a "main" function, or the flatbuffer exporter won't export anything.
// CHECK-LABEL: @main
func.func @main(%arg0: tensor<1xf32>) -> tensor<1xf32> {
func.return %arg0: tensor<1xf32>
}
// CHECK-NEXT: return
// CHECK-LABEL: @unneeded_control_node_gets_deleted
func.func @unneeded_control_node_gets_deleted(%arg0: tensor<1xf32>)->tensor<1xf32> {
%tmp0, %ctl0 = tfl.control_node controls "tfl.neg"(%arg0): (tensor<1xf32>) -> tensor<1xf32>
func.return %tmp0: tensor<1xf32>
}
// CHECK-NEXT: %[[tmp:.*]] = "tfl.neg"(%arg0)
// CHECK-NEXT: return %[[tmp]]
// CHECK-LABEL: @long_chain
func.func @long_chain(%arg0: tensor<1xf32>)->tensor<1xf32> {
%tmp0, %ctl0 = tfl.control_node controls "tfl.neg"(%arg0): (tensor<1xf32>) -> tensor<1xf32>
%tmp1, %ctl1 = tfl.control_node(%ctl0) controls "tfl.neg"(%tmp0): (tensor<1xf32>) -> tensor<1xf32>
%tmp2, %ctl2 = tfl.control_node(%ctl1) controls "tfl.neg"(%tmp1): (tensor<1xf32>) -> tensor<1xf32>
%tmp3, %ctl3 = tfl.control_node(%ctl2) controls "tfl.neg"(%tmp2): (tensor<1xf32>) -> tensor<1xf32>
func.return %tmp3: tensor<1xf32>
}
// CHECK-NEXT: %[[t0:.*]], %[[c0:.*]] = tfl.control_node controls "tfl.neg"(%arg0)
// CHECK-NEXT: %[[t1:.*]], %[[c1:.*]] = tfl.control_node(%[[c0]]) controls "tfl.neg"(%[[t0]])
// CHECK-NEXT: %[[t2:.*]], %[[c2:.*]] = tfl.control_node(%[[c1]]) controls "tfl.neg"(%[[t1]])
// CHECK-NEXT: %[[t3:.*]], %[[c3:.*]] = tfl.control_node(%[[c2]]) controls "tfl.neg"(%[[t2]])
// CHECK-NEXT: return %[[t3]]
// CHECK-LABEL: @overlapping_chains
func.func @overlapping_chains(%arg0: tensor<1xf32>)->tensor<1xf32> {
%tmp0, %ctl0 = tfl.control_node controls "tfl.neg"(%arg0): (tensor<1xf32>) -> tensor<1xf32>
%tmp1, %ctl1 = tfl.control_node controls "tfl.neg"(%tmp0): (tensor<1xf32>) -> tensor<1xf32>
%tmp2, %ctl2 = tfl.control_node(%ctl0) controls "tfl.neg"(%tmp1): (tensor<1xf32>) -> tensor<1xf32>
%tmp3, %ctl3 = tfl.control_node(%ctl1) controls "tfl.neg"(%tmp2): (tensor<1xf32>) -> tensor<1xf32>
func.return %tmp3: tensor<1xf32>
}
// CHECK-NEXT: %[[t0:.*]], %[[c0:.*]] = tfl.control_node controls "tfl.neg"(%arg0)
// CHECK-NEXT: %[[t1:.*]], %[[c1:.*]] = tfl.control_node controls "tfl.neg"(%[[t0]])
// CHECK-NEXT: %[[t2:.*]], %[[c2:.*]] = tfl.control_node(%[[c0]]) controls "tfl.neg"(%[[t1]])
// CHECK-NEXT: %[[t3:.*]], %[[c3:.*]] = tfl.control_node(%[[c1]]) controls "tfl.neg"(%[[t2]])
// CHECK-NEXT: return %[[t3]]
// CHECK-LABEL: @multiple_node_args
func.func @multiple_node_args(%arg0: tensor<1xf32>)->tensor<1xf32> {
%tmp0, %ctl0 = tfl.control_node controls "tfl.neg"(%arg0): (tensor<1xf32>) -> tensor<1xf32>
%tmp1, %ctl1 = tfl.control_node controls "tfl.neg"(%tmp0): (tensor<1xf32>) -> tensor<1xf32>
%tmp2, %ctl2 = tfl.control_node controls "tfl.neg"(%tmp1): (tensor<1xf32>) -> tensor<1xf32>
%tmp3, %ctl3 = tfl.control_node controls "tfl.neg"(%tmp2): (tensor<1xf32>) -> tensor<1xf32>
%tmp4, %ctl4 = tfl.control_node(%ctl2, %ctl0, %ctl3, %ctl2, %ctl1) controls "tfl.neg"(%tmp3): (tensor<1xf32>) -> tensor<1xf32>
func.return %tmp4: tensor<1xf32>
}
// CHECK-NEXT: %[[t0:.*]], %[[c0:.*]] = tfl.control_node controls "tfl.neg"(%arg0)
// CHECK-NEXT: %[[t1:.*]], %[[c1:.*]] = tfl.control_node controls "tfl.neg"(%[[t0]])
// CHECK-NEXT: %[[t2:.*]], %[[c2:.*]] = tfl.control_node controls "tfl.neg"(%[[t1]])
// CHECK-NEXT: %[[t3:.*]], %[[c3:.*]] = tfl.control_node controls "tfl.neg"(%[[t2]])
// CHECK-NEXT: %[[t4:.*]], %[[c4:.*]] = tfl.control_node(%[[c0]], %[[c1]], %[[c2]], %[[c3]]) controls "tfl.neg"(%[[t3]])
// CHECK-NEXT: return %[[t4]]
@@ -0,0 +1,30 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
func.func @main(%arg0: tensor<32x4x4x128xf32>, %arg1: tensor<1x32x42x128xf32>, %arg2: tensor<4xi32>) -> tensor<1x64x84x32xf32> {
%0 = "tfl.custom"(%arg0, %arg1, %arg2) {custom_code = "Convolution2DTransposeBias", custom_option = #tfl<const_bytes : "0x010000000200000002000000">} : (tensor<32x4x4x128xf32>, tensor<1x32x42x128xf32>, tensor<4xi32>) -> tensor<1x64x84x32xf32>
func.return %0 : tensor<1x64x84x32xf32>
}
// CHECK-LABEL: main
// CHECK: "tfl.custom"(%arg0, %arg1, %arg2) <{custom_code = "Convolution2DTransposeBias", custom_option = #tfl<const_bytes : "0x010000000200000002000000">}> : (tensor<32x4x4x128xf32>, tensor<1x32x42x128xf32>, tensor<4xi32>) -> tensor<1x64x84x32xf32>
func.func @main_non_hex_bytes(%arg0: tensor<32x4x4x128xf32>, %arg1: tensor<1x32x42x128xf32>, %arg2: tensor<4xi32>) -> tensor<1x64x84x32xf32> {
%0 = "tfl.custom"(%arg0, %arg1, %arg2) {custom_code = "Convolution2DTransposeBias", custom_option = #tfl<const_bytes : "this is a string">} : (tensor<32x4x4x128xf32>, tensor<1x32x42x128xf32>, tensor<4xi32>) -> tensor<1x64x84x32xf32>
func.return %0 : tensor<1x64x84x32xf32>
}
// CHECK-LABEL: main_non_hex_bytes
// Hex representation below determined by the following command: echo -n "this is a string" | od -An -t x1 | tr -d ' ' | tr '[:lower:]' '[:upper:']
// CHECK: "tfl.custom"(%arg0, %arg1, %arg2) <{custom_code = "Convolution2DTransposeBias", custom_option = #tfl<const_bytes : "0x74686973206973206120737472696E67">}> : (tensor<32x4x4x128xf32>, tensor<1x32x42x128xf32>, tensor<4xi32>) -> tensor<1x64x84x32xf32>
@@ -0,0 +1,22 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer --use-buffer-offset %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
func.func @main(%arg0: tensor<32x4x4x128xf32>, %arg1: tensor<1x32x42x128xf32>, %arg2: tensor<4xi32>) -> tensor<1x64x84x32xf32> {
%0 = "tfl.custom"(%arg0, %arg1, %arg2) {custom_code = "Convolution2DTransposeBias", custom_option = #tfl<const_bytes : "0x010000000200000002000000">} : (tensor<32x4x4x128xf32>, tensor<1x32x42x128xf32>, tensor<4xi32>) -> tensor<1x64x84x32xf32>
func.return %0 : tensor<1x64x84x32xf32>
}
// CHECK-LABEL: main
// CHECK: "tfl.custom"(%arg0, %arg1, %arg2) <{custom_code = "Convolution2DTransposeBias", custom_option = #tfl<const_bytes : "0x010000000200000002000000">}> : (tensor<32x4x4x128xf32>, tensor<1x32x42x128xf32>, tensor<4xi32>) -> tensor<1x64x84x32xf32>
@@ -0,0 +1,66 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer --serialize-debug-metadata=true %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir --mlir-print-debuginfo -o - | FileCheck %s
// This test verifies that debug locations are round-trippable.
#loc = loc("<stdin>":0:0)
#loc5 = loc("main"(#loc))
#loc8 = loc("cond_true"(#loc))
#loc10 = loc("cond_false"(#loc))
module @jit_relu attributes {jax.uses_shape_polymorphism = false, mhlo.num_partitions = 1 : i32, mhlo.num_replicas = 1 : i32, tfl._legalize_tfl_variables = true} {
func.func @main(%arg0: tensor<1xf32>, %arg1: tensor<1xf32>) -> tensor<1xf32> {
%0 = tfl.less(%arg0, %arg1) : (tensor<1xf32>, tensor<1xf32>) -> tensor<1xi1> loc(#loc6)
// CHECK-DAG: {{.*}} = tfl.less(%arg0, %arg1) : (tensor<1xf32>, tensor<1xf32>) -> tensor<1xi1> loc(#loc6)
%1 = "tf.If"(%0, %arg0, %arg1) <{else_branch = @cond_false, is_stateless = false, then_branch = @cond_true}> : (tensor<1xi1>, tensor<1xf32>, tensor<1xf32>) -> tensor<1xf32> loc(#loc7)
// CHECK-DAG: {{.*}} = "tf.If"(%0, %arg0, %arg1) {{.*}} -> tensor<1xf32> loc(#loc7)
func.return %1 : tensor<1xf32> loc(#loc)
} loc(#loc5)
func.func @cond_true(%arg0: tensor<*xf32>, %arg1: tensor<*xf32>) -> tensor<*xf32> {
%0 = tfl.add %arg0, %arg1 {fused_activation_function = "NONE"} : tensor<*xf32> loc(#loc16)
// CHECK-DAG: {{.*}} = tfl.add %arg0, %arg1 {fused_activation_function = "NONE"} : tensor<*xf32> loc(#loc16)
func.return %0 : tensor<*xf32> loc(#loc)
} loc(#loc8)
func.func @cond_false(%arg0: tensor<*xf32>, %arg1: tensor<*xf32>) -> tensor<*xf32> {
%0 = tfl.mul %arg0, %arg1 {fused_activation_function = "NONE"} : tensor<*xf32> loc(#loc15)
// CHECK-DAG: {{.*}} = tfl.mul %arg0, %arg1 {fused_activation_function = "NONE"} : tensor<*xf32> loc(#loc15)
func.return %0 : tensor<*xf32> loc(#loc)
} loc(#loc10)
} loc(#loc)
#loc1 = loc("tfl.less")
// CHECK-DAG: #loc1 = loc("tfl.less")
#loc2 = loc("tf.If")
// CHECK-DAG: #loc2 = loc("tf.If")
#loc3 = loc("<ipython-input-7-340b9abeb7a8>":1:4)
// CHECK-DAG: #loc3 = loc("<ipython-input-7-340b9abeb7a8>":1:4)
#loc4 = loc("third_party/py/IPython/v3_2_3/core/interactiveshell.py":3066:16)
// CHECK-DAG: #loc4 = loc("third_party/py/IPython/v3_2_3/core/interactiveshell.py":3066:16)
#loc6 = loc(fused<"tflite.importer_wrapper">[#loc1])
// CHECK-DAG: #loc6 = loc(fused<"tflite.importer_wrapper">[#loc1])
#loc7 = loc(fused<"tflite.importer_wrapper">[#loc2])
// CHECK-DAG: #loc7 = loc(fused<"tflite.importer_wrapper">[#loc2])
#loc9 = loc(callsite(#loc3 at #loc4))
// CHECK-DAG: #loc9 = loc(callsite(#loc3 at #loc4))
#loc11 = loc(fused<"">[#loc3, #loc4])
// CHECK-DAG: #loc11 = loc(fused<"">[#loc3, #loc4])
#loc12 = loc("jit(relu)/jit(main)/max"(#loc9))
// CHECK-DAG: #loc12 = loc("jit(relu)/jit(main)/max"(#loc9))
#loc13 = loc("tfl.mul"(#loc11))
// CHECK-DAG: #loc13 = loc("tfl.mul"(#loc11))
#loc14 = loc("jit(relu)/jit(main)/max"(#loc12))
// CHECK-DAG: #loc14 = loc("jit(relu)/jit(main)/max"(#loc12))
#loc15 = loc(fused<"tflite.importer_wrapper">[#loc13])
// CHECK-DAG: #loc15 = loc(fused<"tflite.importer_wrapper">[#loc13])
#loc16 = loc(fused<"tflite.importer_wrapper">[#loc14])
// CHECK-DAG: #loc16 = loc(fused<"tflite.importer_wrapper">[#loc14])
@@ -0,0 +1,69 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// Ensure constants roundtrip exactly
func.func @f32() -> tensor<4xf32> {
// CHECK-LABEL: @f32
// CHECK: value = dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00]> : tensor<4xf32>
%0 = "tfl.pseudo_const"() { value = dense_resource<dense_elements_f32> : tensor<4xf32> } : () -> tensor<4xf32>
func.return %0 : tensor<4xf32>
}
func.func @i8() -> tensor<4xi8> {
// CHECK-LABEL: @i8
// CHECK: value = dense<[1, 2, 3, 4]> : tensor<4xi8>
%0 = "tfl.pseudo_const" () { value = dense_resource<dense_elements_i8> : tensor<4xi8> } : () -> tensor<4xi8>
func.return %0 : tensor<4xi8>
}
func.func @i16() -> tensor<4xi16> {
// CHECK-LABEL: @i16
// CHECK: value = dense<[1, 2, 3, 258]> : tensor<4xi16>
%0 = "tfl.pseudo_const" () { value = dense_resource<dense_elements_i16> : tensor<4xi16> } : () -> tensor<4xi16>
func.return %0 : tensor<4xi16>
}
func.func @i32() -> tensor<4xi32> {
// CHECK-LABEL: @i32
// CHECK: value = dense<[1, 2, 3, 16909060]> : tensor<4xi32>
// Check bytes come back in the right order
%0 = "tfl.pseudo_const" () { value = dense_resource<dense_elements_i32> : tensor<4xi32> } : () -> tensor<4xi32>
func.return %0 : tensor<4xi32>
}
func.func @uint8() -> tensor<4xui8> {
// CHECK-LABEL: @uint8
// CHECK: value = dense<[222, 173, 190, 239]> : tensor<4xui8>
%0 = "tfl.pseudo_const"() {value = dense_resource<dense_elements_i8_1> : tensor<4xui8>} : () -> tensor<4xui8>
func.return %0 : tensor<4xui8>
}
// Identity function to make the exporter happy
func.func @main(%arg0: tensor<4xi8>) -> tensor<4xi8> {
func.return %arg0 : tensor<4xi8>
}
{-#
dialect_resources: {
builtin: {
dense_elements_f32: "0x400000000000803F000000400000404000008040",
dense_elements_i16: "0x400000000100020003000201",
dense_elements_i32: "0x4000000001000000020000000300000004030201",
dense_elements_i8: "0x4000000001020304",
dense_elements_i8_1: "0x40000000DEADBEEF"
}
}
#-}
@@ -0,0 +1,69 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer --use-buffer-offset %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// Ensure constants roundtrip exactly
func.func @f32() -> tensor<4xf32> {
// CHECK-LABEL: @f32
// CHECK: value = dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00]> : tensor<4xf32>
%0 = "tfl.pseudo_const"() { value = dense_resource<dense_elements_f32> : tensor<4xf32> } : () -> tensor<4xf32>
func.return %0 : tensor<4xf32>
}
func.func @i8() -> tensor<4xi8> {
// CHECK-LABEL: @i8
// CHECK: value = dense<[1, 2, 3, 4]> : tensor<4xi8>
%0 = "tfl.pseudo_const" () { value = dense_resource<dense_elements_i8> : tensor<4xi8> } : () -> tensor<4xi8>
func.return %0 : tensor<4xi8>
}
func.func @i16() -> tensor<4xi16> {
// CHECK-LABEL: @i16
// CHECK: value = dense<[1, 2, 3, 258]> : tensor<4xi16>
%0 = "tfl.pseudo_const" () { value = dense_resource<dense_elements_i16> : tensor<4xi16> } : () -> tensor<4xi16>
func.return %0 : tensor<4xi16>
}
func.func @i32() -> tensor<4xi32> {
// CHECK-LABEL: @i32
// CHECK: value = dense<[1, 2, 3, 16909060]> : tensor<4xi32>
// Check bytes come back in the right order
%0 = "tfl.pseudo_const" () { value = dense_resource<dense_elements_i32> : tensor<4xi32> } : () -> tensor<4xi32>
func.return %0 : tensor<4xi32>
}
func.func @uint8() -> tensor<4xui8> {
// CHECK-LABEL: @uint8
// CHECK: value = dense<[222, 173, 190, 239]> : tensor<4xui8>
%0 = "tfl.pseudo_const"() {value = dense_resource<dense_elements_i8_1> : tensor<4xui8>} : () -> tensor<4xui8>
func.return %0 : tensor<4xui8>
}
// Identity function to make the exporter happy
func.func @main(%arg0: tensor<4xi8>) -> tensor<4xi8> {
func.return %arg0 : tensor<4xi8>
}
{-#
dialect_resources: {
builtin: {
dense_elements_f32: "0x400000000000803F000000400000404000008040",
dense_elements_i16: "0x400000000100020003000201",
dense_elements_i32: "0x4000000001000000020000000300000004030201",
dense_elements_i8: "0x4000000001020304",
dense_elements_i8_1: "0x40000000DEADBEEF"
}
}
#-}
@@ -0,0 +1,23 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// CHECK: func @main(%arg0: tensor<?x19x19x3xf32>) -> tensor<?x9x9x4xf32>
func.func @main(%arg0: tensor<?x19x19x3xf32>) -> tensor<?x9x9x4xf32> {
%cst = arith.constant dense<1.0> : tensor<4xf32>
%cst_3 = arith.constant dense<2.0> : tensor<4x3x3x3xf32>
%0 = "tfl.conv_2d"(%arg0, %cst_3, %cst) {dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "RELU6", padding = "VALID", stride_h = 2 : i32, stride_w = 2 : i32} : (tensor<?x19x19x3xf32>, tensor<4x3x3x3xf32>, tensor<4xf32>) -> tensor<?x9x9x4xf32>
func.return %0 : tensor<?x9x9x4xf32>
}
@@ -0,0 +1,81 @@
// RUN: json_to_flatbuffer %p/test_schema.fbs %s | flatbuffer_translate --tflite-flatbuffer-to-mlir -o - | FileCheck %s
// If input and output tensors don't have names, there shouldn't be an
// `tf.entry_function` attribute created.
// CHECK-NOT: tf.entry_function
{
"version": 3,
"operator_codes": [
{
"builtin_code": "CONV_2D"
}
],
"subgraphs": [
{
"tensors": [
{
"shape": [
256,
32,
32,
3
],
"quantization": {
}
},
{
"shape": [
16,
3,
3,
3
],
"quantization": {
}
},
{
"shape": [
0
],
},
{
"shape": [
256,
32,
32,
16
],
"quantization": {
}
}
],
"inputs": [
0,
1
],
"outputs": [
3
],
"operators": [
{
"inputs": [
0,
1,
-1
],
"outputs": [
3
],
"builtin_options_type": "Conv2DOptions",
"builtin_options": {
"stride_w": 1,
"stride_h": 1
}
}
],
"name": "main"
}
],
"description": "MLIR Converted."
}
@@ -0,0 +1,28 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
module {
func.func public @main(%arg0: tensor<2x2xf32>) -> tensor<2x2xf32> {
%0 = "tfl.external_const"() <{external_buffer = #tfl.external_buffer<group_name = "test.bin", offset = 0, length = 13, packing = "unpacked">}> : () -> tensor<2x2xf32>
%1 = tfl.add %arg0, %0 {fused_activation_function = "NONE"} : tensor<2x2xf32>
return %1 : tensor<2x2xf32>
}
}
// CHECK-LABEL: @main
// CHECK: %0 = "tfl.external_const"() <{external_buffer = #tfl.external_buffer<group_name = "test.bin", offset = 0, length = 13, packing = "unpacked">}>
// CHECK-NEXT: %1 = tfl.add %arg0, %0 {fused_activation_function = "NONE"} : tensor<2x2xf32>
// CHECK-NEXT: return %1
@@ -0,0 +1,28 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir --use-external-constant - -o - | FileCheck %s
// Ensure that `tfl.external_const` is imported when the flag `-use-external-constant` is enabled.
func.func @main(tensor<40x37xf32>, tensor<40x37xf32>) -> tensor<40x40xf32> {
^bb0(%arg0: tensor<40x37xf32>, %arg1: tensor<40x37xf32>):
%cst = arith.constant dense<1.0> : tensor<40xf32>
%0:2 = "tfl.fully_connected"(%arg0, %arg1, %cst) {fused_activation_function = "NONE", keep_num_dims = false, weights_format = "DEFAULT"} : (tensor<40x37xf32>, tensor<40x37xf32>, tensor<40xf32>) -> (tensor<40x40xf32>, tensor<40x40xf32>)
func.return %0 : tensor<40x40xf32>
// CHECK-LABEL: func @main(%arg0: tensor<40x37xf32>, %arg1: tensor<40x37xf32>) -> tensor<40x40xf32>
// CHECK: %[[CONST:[0-9]+]] = "tfl.external_const"() <{buffer_index = 3 : i32}> : () -> tensor<40xf32>
// CHECK-NEXT: %[[FULL:[0-9]+]]:2 = "tfl.fully_connected"(%arg0, %arg1, %[[CONST]]) <{asymmetric_quantize_inputs = false, fused_activation_function = "NONE", keep_num_dims = false, weights_format = "DEFAULT"}>
// CHECK-NEXT: return %[[FULL]]#0
}
@@ -0,0 +1,79 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// Confirm function references in if ops are preserved
func.func @main(%arg0: tensor<1xf32>, %arg1: tensor<1xf32>) -> tensor<1xf32> {
// CHECK: %{{.*}} = "tf.If"(%{{.*}}, %{{.*}}, %{{.*}}) <{else_branch = @cond_false, is_stateless = false, then_branch = @cond_true}> : (tensor<1xi1>, tensor<1xf32>, tensor<1xf32>) -> tensor<1xf32>
%0 = "tfl.less"(%arg0, %arg1) : (tensor<1xf32>, tensor<1xf32>) -> tensor<1xi1>
%1 = "tf.If"(%0, %arg0, %arg1) {else_branch = @cond_false, then_branch = @cond_true, is_stateless = false} : (tensor<1xi1>, tensor<1xf32>, tensor<1xf32>) -> tensor<1xf32>
func.return %1 : tensor<1xf32>
}
func.func @cond_true(%arg0: tensor<*xf32>, %arg1: tensor<*xf32>) -> tensor<*xf32> {
%0 = tfl.add %arg0, %arg1 {fused_activation_function = "NONE"} : tensor<*xf32>
func.return %0 : tensor<*xf32>
}
func.func @cond_false(%arg0: tensor<*xf32>, %arg1: tensor<*xf32>) -> tensor<*xf32> {
%0 = tfl.mul %arg0, %arg1 {fused_activation_function = "NONE"} : tensor<*xf32>
func.return %0 : tensor<*xf32>
}
// -----
func.func @tfl_if(%arg0: tensor<i1>) -> tensor<i32> {
// CHECK: %{{.*}} = "tf.If"(%{{.*}}, %{{.*}}) <{else_branch = @tfl.if_else, is_stateless = false, then_branch = @tfl.if_then}> : (tensor<i1>, tensor<i32>) -> tensor<i32>
%cst = arith.constant dense<0> : tensor<i32>
%0 = tfl.add %cst, %cst {fused_activation_function = "NONE"} : tensor<i32>
%1 = "tfl.if"(%arg0) ({
%2 = func.call @tfl.if_then(%0) : (tensor<i32>) -> tensor<i32>
"tfl.yield"(%2) : (tensor<i32>) -> ()
}, {
%2 = func.call @tfl.if_else(%0) : (tensor<i32>) -> tensor<i32>
"tfl.yield"(%2) : (tensor<i32>) -> ()
}) : (tensor<i1>) -> tensor<i32>
return %1 : tensor<i32>
}
func.func private @tfl.if_then(%arg0: tensor<i32>) -> tensor<i32> {
return %arg0 : tensor<i32>
}
func.func private @tfl.if_else(%arg0: tensor<i32>) -> tensor<i32> {
%0 = tfl.mul %arg0, %arg0 {fused_activation_function = "NONE"} : tensor<i32>
return %0 : tensor<i32>
}
// -----
func.func @tfl_if_multi_args(%arg0: tensor<i1>) -> tensor<i32> {
// CHECK: %{{.*}} = "tf.If"(%{{.*}}, %{{.*}}, %{{.*}}) <{else_branch = @tfl.if_else_1, is_stateless = false, then_branch = @tfl.if_then_1}> : (tensor<i1>, tensor<i32>, tensor<i32>) -> tensor<i32>
%cst = arith.constant dense<0> : tensor<i32>
%0 = tfl.add %cst, %cst {fused_activation_function = "NONE"} : tensor<i32>
%1 = tfl.mul %cst, %cst {fused_activation_function = "NONE"} : tensor<i32>
%2 = "tfl.if"(%arg0) ({
%2 = func.call @tfl.if_then_1(%0, %1) : (tensor<i32>, tensor<i32>) -> tensor<i32>
"tfl.yield"(%2) : (tensor<i32>) -> ()
}, {
%2 = func.call @tfl.if_else_1(%0, %1) : (tensor<i32>, tensor<i32>) -> tensor<i32>
"tfl.yield"(%2) : (tensor<i32>) -> ()
}) : (tensor<i1>) -> tensor<i32>
return %1 : tensor<i32>
}
func.func private @tfl.if_then_1(%arg0: tensor<i32>, %arg1: tensor<i32>) -> tensor<i32> {
return %arg0 : tensor<i32>
}
func.func private @tfl.if_else_1(%arg0: tensor<i32>, %arg1: tensor<i32>) -> tensor<i32> {
%0 = tfl.mul %arg0, %arg1 {fused_activation_function = "NONE"} : tensor<i32>
return %0 : tensor<i32>
}
@@ -0,0 +1,85 @@
// RUN: json_to_flatbuffer %p/test_schema.fbs %s | flatbuffer_translate --tflite-flatbuffer-to-mlir -o - | FileCheck %s
// CHECK: %[[CST:.*]] = "tfl.no_value"() <{value}> : () -> none
// CHECK: %[[RES0:.*]] = "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<256x32x32x3xf32>, tensor<16x3x3x3xf32>, none) -> tensor<256x32x32x16xf32>
// CHECK: return %[[RES0]] : tensor<256x32x32x16xf32>
{
"version": 3,
"operator_codes": [
{
"builtin_code": "CONV_2D"
}
],
"subgraphs": [
{
"tensors": [
{
"shape": [
256,
32,
32,
3
],
"name": "arg0",
"quantization": {
}
},
{
"shape": [
16,
3,
3,
3
],
"name": "arg1",
"quantization": {
}
},
{
"shape": [
0
],
"name": "cst"
},
{
"shape": [
256,
32,
32,
16
],
"name": "output",
"quantization": {
}
}
],
"inputs": [
0,
1
],
"outputs": [
3
],
"operators": [
{
"inputs": [
0,
1,
-1
],
"outputs": [
3
],
"builtin_options_type": "Conv2DOptions",
"builtin_options": {
"stride_w": 1,
"stride_h": 1
}
}
],
"name": "main"
}
],
"description": "MLIR Converted."
}
@@ -0,0 +1,172 @@
/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include <iostream>
#include <memory>
#include <optional>
#include <string>
#include <system_error>
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/raw_ostream.h"
#include "tensorflow/compiler/mlir/lite/core/absl_error_model_builder.h"
#include "tensorflow/compiler/mlir/lite/schema/schema_generated.h"
#include "tensorflow/compiler/mlir/lite/schema/schema_utils.h"
using llvm::cl::opt;
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s.mlir -o - \
// RUN: | %p/importer_test_min_max - \
// RUN: | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - \
// RUN: | FileCheck %s
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s.mlir -o - \
// RUN: | %p/importer_test_min_max - \
// RUN: | flatbuffer_to_string - \
// RUN: | FileCheck --check-prefix=FB %s
// Tests for verifying the tflite model with min/max can be imported
// correctly.
// NOLINTNEXTLINE
static opt<std::string> inputFileName(llvm::cl::Positional,
llvm::cl::desc("<input file>"),
llvm::cl::init("-"));
namespace mlir {
namespace {
std::optional<std::unique_ptr<tflite::ModelT>> InjectStatsToFullyConnected(
llvm::StringRef buffer) {
auto model_ptr = TFL::FlatBufferModelAbslError::VerifyAndBuildFromBuffer(
buffer.data(), buffer.size());
if (nullptr == model_ptr) {
return std::nullopt;
}
std::unique_ptr<tflite::ModelT> model(model_ptr->GetModel()->UnPack());
// FB-LABEL: name: "arg0",
// FB-NEXT: quantization: {
// FB-NEXT: min: [ -1.0 ],
// FB-NEXT: max: [ 1.0 ]
// FB-NEXT: }
// FB-LABEL: name: "arg1",
// FB-NEXT: quantization: {
// FB-EMPTY:
// FB-NEXT: }
// FB-LABEL: name: "tfl.fully_connected",
// FB-NEXT: quantization: {
// FB-NEXT: min: [ -0.0, -1.0, -2.0, -3.0, -4.0, -5.0, -6.0, -7.0,
// FB-SAME: -8.0, -9.0, -10.0, -11.0, -12.0, -13.0, -14.0, -15.0, -16.0,
// FB-SAME: -17.0, -18.0, -19.0, -20.0, -21.0, -22.0, -23.0, -24.0, -25.0,
// FB-SAME: -26.0, -27.0, -28.0, -29.0, -30.0, -31.0, -32.0, -33.0, -34.0,
// FB-SAME: -35.0, -36.0, -37.0, -38.0, -39.0 ],
// FB-NEXT: max: [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0,
// FB-SAME: 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0,
// FB-SAME: 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0,
// FB-SAME: 32.0, 33.0, 34.0, 35.0, 36.0, 37.0, 38.0, 39.0 ],
// FB-NEXT: quantized_dimension: 1
// FB-NEXT: }
// FB-LABEL: name: "tfl.fully_connected:1",
// FB-NEXT: quantization: {
// FB-EMPTY:
// FB-NEXT: }
// FB-LABEL: operators: [ {
// FB-NEXT: inputs: [ 0, 1, 2 ],
// FB-NEXT: outputs: [ 3, 4 ],
// FB-NEXT: builtin_options_type: FullyConnectedOptions,
// FB-NEXT: builtin_options: {
// FB-EMPTY:
// FB-NEXT: }
// FB-NEXT: } ],
// CHECK-LABEL: func @main(%arg0: tensor<40x37xf32>, %arg1: tensor<40x37xf32>)
// CHECK-SAME: -> tensor<40x40xf32>
// CHECK: %[[stat:.*]] = "quantfork.stats"(%arg0) <{layerStats = dense
// CHECK-SAME: <[-1.000000e+00, 1.000000e+00]> : tensor<2xf32>}>
// CHECK-SAME: : (tensor<40x37xf32>) -> tensor<40x37xf32>
// CHECK-NEXT: %[[cst:.*]] = "tfl.pseudo_const"() <{value = dense<
// CHECK-SAME: 1.000000e+00> : tensor<40xf32>}> : () -> tensor<40xf32>
// CHECK-NEXT: %[[fc:.*]]:2 = "tfl.fully_connected"(%[[stat]], %arg1,
// CHECK-NEXT: %[[stat1:.*]] = "quantfork.stats"(%[[fc]]#0)
// CHECK-SAME: <{axis = 1 : i64,
// CHECK-SAME: axisStats = dense<{{\[}}[-0.000000e+00, 0.000000e+00],
// CHECK-SAME: [-1.000000e+00, 1.000000e+00],
// CHECK-SAME: [-2.000000e+00, 2.000000e+00]
// CHECK-NEXT: return %[[stat1]] : tensor<40x40xf32>
// CHECK-NEXT: }
// Find the tensors and inject the min and max to the input and output
for (auto& sub_graph : model->subgraphs) {
for (auto& op : sub_graph->operators) {
if (tflite::GetBuiltinCode(
model->operator_codes[op->opcode_index].get()) ==
tflite::BuiltinOperator_FULLY_CONNECTED) {
// inject min/max to the input and output tensors
auto& input_tensor = sub_graph->tensors[op->inputs[0]];
input_tensor->quantization->scale.clear();
input_tensor->quantization->zero_point.clear();
input_tensor->quantization->min.push_back(-1.0);
input_tensor->quantization->max.push_back(1.0);
auto& output_tensor = sub_graph->tensors[op->outputs[0]];
auto shape = output_tensor->shape;
output_tensor->quantization->scale.clear();
output_tensor->quantization->zero_point.clear();
for (int i = 0; i < shape.back(); ++i) {
output_tensor->quantization->min.push_back(-1.0 * i);
output_tensor->quantization->max.push_back(1.0 * i);
}
output_tensor->quantization->quantized_dimension = shape.size() - 1;
}
}
}
return model;
}
} // namespace
} // namespace mlir
int main(int argc, char** argv) {
llvm::InitLLVM y(argc, argv);
llvm::cl::ParseCommandLineOptions(argc, argv);
auto file_or_err = llvm::MemoryBuffer::getFileOrSTDIN(inputFileName.c_str());
if (std::error_code error = file_or_err.getError()) {
llvm::errs() << argv[0] << ": could not open input file '" << inputFileName
<< "': " << error.message() << "\n";
return 1;
}
auto buffer = file_or_err->get();
auto maybe_module =
mlir::InjectStatsToFullyConnected(buffer->getBuffer().str());
if (!maybe_module.has_value()) {
return 1;
}
flatbuffers::FlatBufferBuilder builder;
flatbuffers::Offset<tflite::Model> output_model_location =
tflite::Model::Pack(builder, maybe_module.value().get());
tflite::FinishModelBuffer(builder, output_model_location);
std::string output_model_content(
reinterpret_cast<const char*>(builder.GetBufferPointer()),
builder.GetSize());
std::cout << output_model_content << "\n";
return 0;
}
@@ -0,0 +1,28 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// This only test the exporter and importer are working without min/max quantization parameters.
func.func @main(tensor<40x37xf32>, tensor<40x37xf32>) -> tensor<40x40xf32> {
^bb0(%arg0: tensor<40x37xf32>, %arg1: tensor<40x37xf32>):
%cst = arith.constant dense<1.0> : tensor<40xf32>
%0:2 = "tfl.fully_connected"(%arg0, %arg1, %cst) {fused_activation_function = "NONE", keep_num_dims = false, weights_format = "DEFAULT"} : (tensor<40x37xf32>, tensor<40x37xf32>, tensor<40xf32>) -> (tensor<40x40xf32>, tensor<40x40xf32>)
func.return %0 : tensor<40x40xf32>
// CHECK-LABEL: func @main(%arg0: tensor<40x37xf32>, %arg1: tensor<40x37xf32>) -> tensor<40x40xf32>
// CHECK: %[[CONST:[0-9]+]] = "tfl.pseudo_const"() <{value = dense<1.000000e+00> : tensor<40xf32>}>
// CHECK-NEXT: %[[FULL:[0-9]+]]:2 = "tfl.fully_connected"(%arg0, %arg1, %[[CONST]]) <{asymmetric_quantize_inputs = false, fused_activation_function = "NONE", keep_num_dims = false, weights_format = "DEFAULT"}>
// CHECK-NEXT: return %[[FULL]]#0
}
@@ -0,0 +1,28 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate -input-arrays=squared_difference --experimental-prune-unreachable-nodes-unconditionally --tflite-flatbuffer-to-mlir - -o -
// TODO(b/329300758): re-enable filecheck | FileCheck %s
// Tests -input-arrays flag.
func.func @main(%arg0: tensor<4xf32>) -> tensor<4xf32> {
%0 = "tfl.pseudo_const" () {value = dense<1.0> : tensor<4xf32>} : () -> tensor<4xf32> loc("Const")
%1 = "tfl.squared_difference"(%arg0, %0) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32> loc("squared_difference")
%2 = "tfl.mul"(%0, %1) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32> loc("mul")
func.return %2 : tensor<4xf32>
// CHECK-LABEL: main
// CHECK-NOT: tfl.squared_difference
// CHECK: tfl.mul %[[CONST:.*]], %arg0
}
@@ -0,0 +1,26 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// Tests input and output names from FlatBuffer are added to `tf.entry_function` attribute.
// CHECK-LABEL: @main
func.func @main(%arg0: tensor<4xi8>, %arg1: tensor<4xi32>) -> (tensor<4xi32>, tensor<4xi8>)
// CHECK: attributes {tf.entry_function = {inputs = "input0,input1", outputs = "output0,output1"}}
attributes {tf.entry_function = {inputs = "input0,input1", outputs = "output0,output1"}} {
%0 = "tfl.neg"(%arg0) : (tensor<4xi8>) -> tensor<4xi8> loc("neg")
%1 = "tfl.neg"(%arg1) : (tensor<4xi32>) -> tensor<4xi32> loc("neg")
func.return %1, %0 : tensor<4xi32>, tensor<4xi8>
}
@@ -0,0 +1,44 @@
// RUN: json_to_flatbuffer %p/test_schema.fbs %s | flatbuffer_translate --tflite-flatbuffer-to-mlir -o - | FileCheck %s
// CHECK: %0 = "tfl.pseudo_const"() <{value = dense<2> : tensor<2xi32>}> : () -> tensor<2xi32>
// CHECK: %1 = "tfl.reshape"(%arg0, %0) : (tensor<1x4xf32>, tensor<2xi32>) -> tensor<2x2xf32>
{
"version": 3,
"operator_codes": [
{
"builtin_code": "RESHAPE"
}
],
"subgraphs": [
{
"tensors": [
{
"shape": [1, 4],
"name": "input",
"quantization": {
}
},
{
"shape": [2, 2],
"name": "output",
"quantization": {
}
}
],
"inputs": [0],
"outputs": [1],
"operators": [
{
"inputs": [ 0 ],
"outputs": [ 1 ],
"builtin_options_type": "ReshapeOptions",
"builtin_options": {
"new_shape": [ 2, 2 ]
}
}
]
}
],
"buffers": []
}
@@ -0,0 +1,346 @@
// RUN: json_to_flatbuffer %p/test_schema.fbs %s | flatbuffer_translate --tflite-flatbuffer-to-mlir -o - | FileCheck %s
// RUN: json_to_flatbuffer %p/test_schema.fbs %s | flatbuffer_translate --tflite-flatbuffer-to-mlir -o - | flatbuffer_translate -mlir-to-tflite-flatbuffer - -o - | flatbuffer_to_string - | FileCheck --check-prefix=RoundTrip %s
// CHECK-DAG: %[[input_18:.*]] = "quantfork.stats"({{.*}}) <{layerStats = dense<[-8.000000e-01, 1.600000e+00]> : tensor<2xf32>}> : (tensor<1x4xf32>) -> tensor<1x4xf32>
// CHECK-DAG: %[[input_19:.*]] = "quantfork.stats"({{.*}}) <{layerStats = dense<[-2.000000e+00, 4.000000e+00]> : tensor<2xf32>}> : (tensor<1x2xf32>) -> tensor<1x2xf32>
// CHECK: "tfl.unidirectional_sequence_lstm"({{.*}}, %[[input_18]], %[[input_19]], %{{[0-9]+}}, %{{[0-9]+}}, %{{[0-9]+}}, %{{[0-9]+}})
// CHECK-SAME: effective_hidden_scale_intermediate = tensor<*x!quant.calibrated<f32<-5.000000e-01:5.000000e-01>>>
// CHECK-SAME: input_to_cell_intermediate = tensor<*x!quant.calibrated<f32<-4.000000e+00:4.000000e+00>>>
// CHECK-SAME: input_to_forget_intermediate = tensor<*x!quant.calibrated<f32<-1.600000e+01:1.600000e+01>>>
// CHECK-SAME: input_to_input_intermediate = tensor<*x!quant.calibrated<f32<-3.200000e+01:3.200000e+01>>>
// CHECK-SAME: input_to_output_intermediate = tensor<*x!quant.calibrated<f32<-1.000000e+00:1.000000e+00>>>
// Checks if calibrated type is exported back to quantized type.
// RoundTrip: name: "effective_hidden_scale_intermediate",
// RoundTrip-NEXT: quantization: {
// RoundTrip-NEXT: min: [ -0.5 ],
// RoundTrip-NEXT: max: [ 0.5 ]
{
"version": 3,
"operator_codes": [
{
"builtin_code": "UNIDIRECTIONAL_SEQUENCE_LSTM"
}
],
"subgraphs": [
{
"tensors": [
{
"shape": [1, 5, 2],
"name": "input0"
},
{
"shape": [2, 5],
"buffer": 1,
"name": "input2input_weights1"
},
{
"shape": [2, 5],
"buffer": 2,
"name": "input2forget_weights2"
},
{
"shape": [2, 5],
"buffer": 3,
"name": "input2cell_weights3"
},
{
"shape": [2, 5],
"buffer": 4,
"name": "input2output_weights4"
},
{
"shape": [2, 4],
"buffer": 5,
"name": "rec2input_weights5"
},
{
"shape": [2, 4],
"buffer": 6,
"name": "rec2forget_weights6"
},
{
"shape": [2, 4],
"buffer": 7,
"name": "rec2cell_weights7"
},
{
"shape": [2, 4],
"buffer": 8,
"name": "rec2output_weights8"
},
{
"shape": [2],
"buffer": 9,
"name": "cell2input_weights9"
},
{
"shape": [2],
"buffer": 10,
"name": "cell2forget_weights10"
},
{
"shape": [2],
"buffer": 11,
"name": "cell2output_weights11"
},
{
"shape": [2],
"buffer": 12,
"name": "input_gate_bias12"
},
{
"shape": [2],
"buffer": 13,
"name": "forget_gate_bias13"
},
{
"shape": [2],
"buffer": 14,
"name": "cell_gate_bias14"
},
{
"shape": [2],
"buffer": 15,
"name": "output_gate_bias15"
},
{
"shape": [4, 2],
"buffer": 16,
"name": "proj_weights16"
},
{
"shape": [4],
"buffer": 17,
"name": "proj_bias17"
},
{
"shape": [1, 4],
"name": "input_activation_state18",
"is_variable": true,
"quantization": {
"min": [-0.8],
"max": [1.6]
}
},
{
"shape": [1, 2],
"name": "input_cell_state19",
"is_variable": true,
"quantization": {
"min": [-2.0],
"max": [4.0]
}
},
{
"shape": [2],
"buffer": 18,
"name": "input_norm20"
},
{
"shape": [2],
"buffer": 19,
"name": "forget_norm21"
},
{
"shape": [2],
"buffer": 20,
"name": "cell_norm22"
},
{
"shape": [2],
"buffer": 21,
"name": "output_norm23"
},
{
"shape": [],
"name": "output24"
},
{
"shape": [],
"name": "intermediate_0",
"is_variable": true,
"quantization": {
"min": [-32],
"max": [32]
}
},
{
"shape": [],
"name": "intermediate_1",
"is_variable": true,
"quantization": {
"min": [-16],
"max": [16]
}
},
{
"shape": [],
"name": "intermediate_2",
"is_variable": true,
"quantization": {
"min": [-4],
"max": [4]
}
},
{
"shape": [],
"name": "intermediate_3",
"is_variable": true,
"quantization": {
"min": [-1.0],
"max": [1.0]
}
},
{
"shape": [],
"name": "intermediate_4",
"is_variable": true,
"quantization": {
"min": [-0.5],
"max": [0.5]
}
}
],
"inputs": [0],
"outputs": [24],
"operators": [
{
"inputs": [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23
],
"outputs": [24],
"intermediates": [
25, 26, 27, 28, 29
],
"builtin_options_type": "UnidirectionalSequenceLSTMOptions",
"builtin_options": {
"fused_activation_function": "TANH",
"cell_clip": 50.0
},
"mutating_variable_inputs": [
false,
false, false, false, false,
false, false, false, false,
false, false, false,
false, false, false, false,
true, true,
false, false, false, false
]
}
]
}
],
"buffers": [
{
"data": []
},
{
"data": [
36, 167, 168, 63, 0, 140, 72, 191, 120, 20, 147, 62, 20, 152, 196, 190, 121, 98, 82, 187, 95, 128, 213, 61, 189, 3, 138, 63, 54, 103, 13, 62, 46, 224, 66, 63, 157, 204, 180, 191
]
},
{
"data": [
223, 20, 21, 64, 246, 166, 31, 191, 6, 51, 157, 188, 114, 90, 167, 62, 118, 240, 59, 63, 49, 162, 255, 62, 17, 91, 160, 63, 32, 47, 26, 63, 40, 136, 178, 191, 243, 154, 236, 61
]
},
{
"data": [
137, 231, 86, 63, 41, 154, 16, 63, 239, 37, 77, 191, 55, 189, 24, 189, 86, 63, 18, 63, 42, 55, 13, 191, 110, 139, 138, 191, 219, 148, 181, 63, 71, 232, 108, 191, 66, 226, 145, 191
]
},
{
"data": [
245, 179, 225, 190, 51, 202, 176, 189, 132, 47, 53, 191, 155, 25, 50, 191, 197, 130, 240, 191, 98, 125, 45, 62, 243, 70, 83, 62, 85, 155, 139, 63, 113, 239, 11, 192, 35, 251, 139, 62
]
},
{
"data": [
248, 188, 211, 191, 142, 11, 73, 62, 36, 8, 84, 63, 186, 208, 11, 191, 76, 208, 190, 191, 223, 200, 210, 63, 183, 170, 103, 63, 116, 129, 145, 63
]
},
{
"data": [
235, 202, 222, 190, 159, 201, 112, 191, 217, 248, 166, 63, 165, 199, 131, 191, 130, 59, 47, 63, 179, 11, 186, 62, 55, 168, 18, 192, 152, 213, 26, 64
]
},
{
"data": [
245, 123, 138, 62, 213, 106, 231, 59, 211, 218, 250, 62, 25, 157, 134, 63, 147, 22, 164, 63, 25, 221, 139, 62, 1, 230, 247, 62, 210, 185, 142, 63
]
},
{
"data": [
197, 123, 23, 192, 45, 96, 178, 190, 174, 87, 165, 62, 213, 225, 200, 191, 119, 248, 15, 191, 128, 125, 171, 189, 90, 125, 222, 63, 4, 76, 95, 62
]
},
{
"data": [
210, 73, 183, 63, 248, 177, 13, 191
]
},
{
"data": [
78, 251, 212, 191, 169, 29, 147, 63
]
},
{
"data": [
178, 227, 203, 191, 247, 155, 103, 63
]
},
{
"data": [
206, 111, 165, 190, 153, 77, 227, 63
]
},
{
"data": [
255, 114, 132, 191, 253, 202, 140, 191
]
},
{
"data": [
90, 247, 1, 192, 125, 120, 209, 191
]
},
{
"data": [
65, 75, 243, 191, 58, 122, 146, 190
]
},
{
"data": [
40, 135, 20, 63, 109, 50, 220, 191, 56, 241, 189, 63, 65, 12, 92, 63, 61, 14, 162, 62, 157, 138, 81, 63, 125, 61, 191, 61, 102, 231, 20, 63
]
},
{
"data": [
145, 79, 49, 189, 175, 235, 220, 190, 182, 111, 157, 190, 144, 236, 97, 191
]
},
{
"data": [
76, 188, 109, 63, 228, 150, 201, 190
]
},
{
"data": [
6, 146, 66, 191, 122, 127, 100, 191
]
},
{
"data": [
216, 59, 169, 190, 161, 178, 215, 191
]
},
{
"data": [
208, 144, 101, 191, 127, 233, 195, 190
]
}
]
}
@@ -0,0 +1,109 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// Ensure lstm roundtrip exactly
func.func @main(%arg0: tensor<1x4xf32>, %arg1: tensor<4x4xf32>, %arg2: tensor<4x4xf32>, %arg3: tensor<4x4xf32>, %arg4: tensor<4x4xf32>, %arg5: tensor<4x4xf32>, %arg6: tensor<4x4xf32>, %arg7: tensor<4x4xf32>, %arg8: tensor<4x4xf32>, %arg9: tensor<4xf32>, %arg10: tensor<4xf32>, %arg11: tensor<4xf32>, %arg12: tensor<1x4xf32>, %arg13: tensor<4xf32>, %arg14: tensor<4xf32>, %arg15: tensor<4xf32>, %arg16: tensor<4x4xf32>, %arg17: tensor<4xf32>, %arg18: tensor<4xf32>, %arg19: tensor<4xf32>, %arg20: tensor<4xf32>, %arg21: tensor<4xf32>) -> tensor<1x4xf32> {
%cst0 = "tfl.pseudo_const" () {value = dense<0.0> : tensor<1x4xf32>} : () -> tensor<1x4xf32> loc("Const")
%cst1 = "tfl.pseudo_const" () {value = dense<0.0> : tensor<1x4xf32>} : () -> tensor<1x4xf32> loc("Const")
%24 = "tfl.lstm"(%arg0, %arg1, %arg2, %arg3, %arg4, %arg5, %arg6, %arg7, %arg8, %arg9, %arg10, %arg11, %arg12, %arg13, %arg14, %arg15, %arg16, %arg17, %cst0, %cst1, %arg18, %arg19, %arg20, %arg21) ({}) {cell_clip = 0.000000e+00 : f32, fused_activation_function = "NONE", kernel_type = #tfl<lstm_kernel_type_attr FULL>, proj_clip = 0.000000e+00 : f32} : (tensor<1x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<1x4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4x4xf32>, tensor<4xf32>, tensor<1x4xf32>, tensor<1x4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>) -> tensor<1x4xf32>
func.return %24 : tensor<1x4xf32>
// CHECK-LABEL: main
// separate lines since there is no region for this op. third_party/tensorflow/compiler/mlir/lite/ir/tfl_ops.td: 3252
// CHECK-DAG: %[[RES0:.*]] = "tfl.pseudo_const"() <{value = dense<{{.*}}> : tensor<1x4xf32>}> {tfl.is_variable} : () -> tensor<1x4xf32>
// CHECK-DAG: %[[RES1:.*]] = "tfl.pseudo_const"() <{value = dense<{{.*}}> : tensor<1x4xf32>}> {tfl.is_variable} : () -> tensor<1x4xf32>
// CHECK: %[[RES2:.*]] = "tfl.lstm"(%arg0, %arg1, %arg2, %arg3, %arg4, %arg5, %arg6, %arg7, %arg8, %arg9, %arg10, %arg11, %arg12, %arg13, %arg14, %arg15, %arg16, %arg17, %[[RES0]], %[[RES1]], %arg18, %arg19, %arg20, %arg21)
// CHECK-SAME: <{asymmetric_quantize_inputs = false, cell_clip = 0.000000e+00 : f32, fused_activation_function = "NONE", kernel_type = #tfl<lstm_kernel_type_attr FULL>, proj_clip = 0.000000e+00 : f32}> ({
// CHECK: }) : (tensor<1x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<1x4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4x4xf32>, tensor<4xf32>, tensor<1x4xf32>, tensor<1x4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>) -> tensor<1x4xf32>
// CHECK: return %[[RES2]]
}
// -----
func.func @testFullyQuantizedLSTM(%arg0: tensor<1x528x!quant.uniform<i8:f32, 0.037248000502586365:-19>>, %arg1: tensor<2048x528x!quant.uniform<i8<-127:127>:f32, 0.059801999479532242>>, %arg2: tensor<2048x528x!quant.uniform<i8<-127:127>:f32, 0.031925998628139496>>, %arg3: tensor<2048x528x!quant.uniform<i8<-127:127>:f32, 0.056272000074386597>>, %arg4: tensor<2048x528x!quant.uniform<i8<-127:127>:f32, 0.063763998448848724>>, %arg5: tensor<2048x640x!quant.uniform<i8<-127:127>:f32, 0.013358999975025654>>, %arg6: tensor<2048x640x!quant.uniform<i8<-127:127>:f32, 0.022830000147223473>>, %arg7: tensor<2048x640x!quant.uniform<i8<-127:127>:f32, 0.032276000827550888>>, %arg8: tensor<2048x640x!quant.uniform<i8<-127:127>:f32, 0.035427000373601913>>, %arg9: tensor<2048x!quant.uniform<i32:f32, 4.2675782196965883E-7>>, %arg10: tensor<2048x!quant.uniform<i32:f32, 1.0742187583900886E-7>>, %arg11: tensor<2048x!quant.uniform<i32:f32, 1.6406249869760359E-7>>, %arg12: tensor<2048x!quant.uniform<i32:f32, 1.523437447303877E-7>>, %arg13: tensor<640x2048x!quant.uniform<i8<-127:127>:f32, 0.021174000576138496>>, %arg14: tensor<640x!quant.uniform<i32:f32, 1.601389680352559E-4>>, %arg15: tensor<2048x!quant.uniform<i16:f32, 4.3700000969693065E-4>>, %arg16: tensor<2048x!quant.uniform<i16:f32, 1.1000000085914508E-4>>, %arg17: tensor<2048x!quant.uniform<i16:f32, 1.6799999866634607E-4>>, %arg18: tensor<2048x!quant.uniform<i16:f32, 1.55999994603917E-4>>, %arg19: tensor<1x640x!quant.uniform<i8:f32, 0.09671100229024887:10>>, %arg20: tensor<1x2048x!quant.uniform<i16:f32, 4.8799999058246613E-4>>) -> tensor<1x640x!quant.uniform<i8:f32, 0.09671100229024887:10>> {
%cst = "tfl.no_value"() {value = unit} : () -> none
%0 = "tfl.lstm"(%arg0, %arg1, %arg2, %arg3, %arg4, %arg5, %arg6, %arg7, %arg8, %cst, %cst, %cst, %arg9, %arg10, %arg11, %arg12, %arg13, %arg14, %arg19, %arg20, %arg15, %arg16, %arg17, %arg18) ({}) {cell_clip = 1.000000e+01 : f32, fused_activation_function = "TANH", input_to_input_intermediate = tensor<0x!quant.uniform<i16:f32, 0.0049890000373125076>>, input_to_forget_intermediate = tensor<0x!quant.uniform<i16:f32, 0.0078849997371435165>>, input_to_cell_intermediate = tensor<0x!quant.uniform<i16:f32, 0.0087630003690719604>>, input_to_output_intermediate = tensor<0x!quant.uniform<i16:f32, 0.0057529998011887074>>, effective_hidden_scale_intermediate = tensor<0x!quant.uniform<i8:f32, 0.0075630000792443752:2>>, kernel_type = #tfl<lstm_kernel_type_attr FULL>, proj_clip = 0.01 : f32} : (tensor<1x528x!quant.uniform<i8:f32, 0.037248000502586365:-19>>, tensor<2048x528x!quant.uniform<i8<-127:127>:f32, 0.059801999479532242>>, tensor<2048x528x!quant.uniform<i8<-127:127>:f32, 0.031925998628139496>>, tensor<2048x528x!quant.uniform<i8<-127:127>:f32, 0.056272000074386597>>, tensor<2048x528x!quant.uniform<i8<-127:127>:f32, 0.063763998448848724>>, tensor<2048x640x!quant.uniform<i8<-127:127>:f32, 0.013358999975025654>>, tensor<2048x640x!quant.uniform<i8<-127:127>:f32, 0.022830000147223473>>, tensor<2048x640x!quant.uniform<i8<-127:127>:f32, 0.032276000827550888>>, tensor<2048x640x!quant.uniform<i8<-127:127>:f32, 0.035427000373601913>>, none, none, none, tensor<2048x!quant.uniform<i32:f32, 4.2675782196965883E-7>>, tensor<2048x!quant.uniform<i32:f32, 1.0742187583900886E-7>>, tensor<2048x!quant.uniform<i32:f32, 1.6406249869760359E-7>>, tensor<2048x!quant.uniform<i32:f32, 1.523437447303877E-7>>, tensor<640x2048x!quant.uniform<i8<-127:127>:f32, 0.021174000576138496>>, tensor<640x!quant.uniform<i32:f32, 1.601389680352559E-4>>, tensor<1x640x!quant.uniform<i8:f32, 0.09671100229024887:10>>, tensor<1x2048x!quant.uniform<i16:f32, 4.8799999058246613E-4>>, tensor<2048x!quant.uniform<i16:f32, 4.3700000969693065E-4>>, tensor<2048x!quant.uniform<i16:f32, 1.1000000085914508E-4>>, tensor<2048x!quant.uniform<i16:f32, 1.6799999866634607E-4>>, tensor<2048x!quant.uniform<i16:f32, 1.55999994603917E-4>>) -> tensor<1x640x!quant.uniform<i8:f32, 0.09671100229024887:10>>
func.return %0 : tensor<1x640x!quant.uniform<i8:f32, 0.09671100229024887:10>>
// CHECK-LABEL: testFullyQuantizedLSTM
// CHECK: %[[CST:.*]] = "tfl.no_value"() <{value}> : () -> none
// CHECK: %[[RES0:.*]] = "tfl.lstm"(%arg0, %arg1, %arg2, %arg3, %arg4, %arg5, %arg6, %arg7, %arg8, %[[CST]], %[[CST]], %[[CST]], %arg9, %arg10, %arg11, %arg12, %arg13, %arg14, %arg19, %arg20, %arg15, %arg16, %arg17, %arg18)
// CHECK-SAME: <{asymmetric_quantize_inputs = false, cell_clip = 1.000000e+01 : f32, effective_hidden_scale_intermediate = tensor<0x!quant.uniform<i8:f32, 0.0075630000792443752:2>>, fused_activation_function = "TANH", input_to_cell_intermediate = tensor<0x!quant.uniform<i16:f32, 0.0087630003690719604>>, input_to_forget_intermediate = tensor<0x!quant.uniform<i16:f32, 0.0078849997371435165>>, input_to_input_intermediate = tensor<0x!quant.uniform<i16:f32, 0.0049890000373125076>>, input_to_output_intermediate = tensor<0x!quant.uniform<i16:f32, 0.0057529998011887074>>, kernel_type = #tfl<lstm_kernel_type_attr FULL>, proj_clip = 0.00999999977 : f32}> ({
// CHECK: }) : (tensor<1x528x!quant.uniform<i8:f32, 0.037248000502586365:-19>>, tensor<2048x528x!quant.uniform<i8:f32, 0.059801999479532242>>, tensor<2048x528x!quant.uniform<i8:f32, 0.031925998628139496>>, tensor<2048x528x!quant.uniform<i8:f32, 0.056272000074386597>>, tensor<2048x528x!quant.uniform<i8:f32, 0.063763998448848724>>, tensor<2048x640x!quant.uniform<i8:f32, 0.013358999975025654>>, tensor<2048x640x!quant.uniform<i8:f32, 0.022830000147223473>>, tensor<2048x640x!quant.uniform<i8:f32, 0.032276000827550888>>, tensor<2048x640x!quant.uniform<i8:f32, 0.035427000373601913>>, none, none, none, tensor<2048x!quant.uniform<i32:f32, 4.2675782196965883E-7>>, tensor<2048x!quant.uniform<i32:f32, 1.0742187583900886E-7>>, tensor<2048x!quant.uniform<i32:f32, 1.6406249869760359E-7>>, tensor<2048x!quant.uniform<i32:f32, 1.523437447303877E-7>>, tensor<640x2048x!quant.uniform<i8:f32, 0.021174000576138496>>, tensor<640x!quant.uniform<i32:f32, 1.6013896674849093E-4>>, tensor<1x640x!quant.uniform<i8:f32, 0.09671100229024887:10>>, tensor<1x2048x!quant.uniform<i16:f32, 4.8799999058246613E-4>>, tensor<2048x!quant.uniform<i16:f32, 4.3700000969693065E-4>>, tensor<2048x!quant.uniform<i16:f32, 1.1000000085914508E-4>>, tensor<2048x!quant.uniform<i16:f32, 1.6799999866634607E-4>>, tensor<2048x!quant.uniform<i16:f32, 1.55999994603917E-4>>) -> tensor<1x640x!quant.uniform<i8:f32, 0.09671100229024887:10>>
}
// -----
// CHECK-LABEL: testUnidirectionalSequenceLstmWithIntermediates
func.func @testUnidirectionalSequenceLstmWithIntermediates(%arg0: tensor<? x ? x ? x f32>, %arg1: tensor<? x ? x f32>, %arg2: tensor<? x ? x f32>, %arg3: tensor<? x ? x f32>, %arg4: tensor<? x ? x f32>, %arg5: tensor<? x ? x f32>, %arg6: tensor<? x ? x f32>, %arg7: tensor<? x ? x f32>, %arg8: tensor<? x ? x f32>, %arg9: tensor<? x f32>, %arg10: tensor<? x f32>, %arg11: tensor<? x f32>, %arg12: tensor<? x f32>, %arg13: tensor<? x f32>, %arg14: tensor<? x f32>, %arg15: tensor<? x f32>, %arg16: tensor<? x ? x f32>, %arg17: tensor<? x f32>, %arg18: tensor<? x ? x f32>, %arg19: tensor<? x ? xf32>, %arg20: tensor<? x f32>, %arg21: tensor<? x f32>, %arg22: tensor<? x f32>, %arg23: tensor<? x f32>) -> tensor<? x ? x ? x f32> {
// CHECK: "tfl.unidirectional_sequence_lstm"(%arg0, %arg1, %arg2, %arg3, %arg4, %arg5, %arg6, %arg7, %arg8, %arg9, %arg10, %arg11, %arg12, %arg13, %arg14, %arg15, %arg16, %arg17, %arg18, %arg19, %arg20, %arg21, %arg22, %arg23) <{asymmetric_quantize_inputs = false, cell_clip = 1.000000e+01 : f32, diagonal_recurrent_tensors = false, effective_hidden_scale_intermediate = tensor<0x!quant.uniform<i8:f32, 0.0077881771139800549>>, fused_activation_function = "TANH", input_to_cell_intermediate = tensor<0xf32>, input_to_forget_intermediate = tensor<0xf32>, input_to_input_intermediate = tensor<0xf32>, input_to_output_intermediate = tensor<0xf32>, proj_clip = 0.000000e+00 : f32, time_major = false}> : (tensor<?x?x?xf32>, tensor<?x?xf32>, tensor<?x?xf32>, tensor<?x?xf32>, tensor<?x?xf32>, tensor<?x?xf32>, tensor<?x?xf32>, tensor<?x?xf32>, tensor<?x?xf32>, tensor<?xf32>, tensor<?xf32>, tensor<?xf32>, tensor<?xf32>, tensor<?xf32>, tensor<?xf32>, tensor<?xf32>, tensor<?x?xf32>, tensor<?xf32>, tensor<?x?xf32>, tensor<?x?xf32>, tensor<?xf32>, tensor<?xf32>, tensor<?xf32>, tensor<?xf32>) -> tensor<?x?x?xf32>
%0 = "tfl.unidirectional_sequence_lstm"(%arg0, %arg1, %arg2, %arg3, %arg4, %arg5, %arg6, %arg7, %arg8, %arg9, %arg10, %arg11, %arg12, %arg13, %arg14, %arg15, %arg16, %arg17, %arg18, %arg19, %arg20, %arg21, %arg22, %arg23) {cell_clip = 1.000000e+01 : f32, effective_hidden_scale_intermediate = tensor<0x!quant.uniform<i8:f32, 0.0077881771139800549>>, fused_activation_function = "TANH", input_to_cell_intermediate = tensor<0xf32>, input_to_forget_intermediate = tensor<0xf32>, input_to_input_intermediate = tensor<0xf32>, input_to_output_intermediate = tensor<0xf32>, proj_clip = 0.000000e+00 : f32, time_major = false} : (tensor<?x?x?xf32>, tensor<?x?xf32>, tensor<?x?xf32>, tensor<?x?xf32>, tensor<?x?xf32>, tensor<?x?xf32>, tensor<?x?xf32>, tensor<?x?xf32>, tensor<?x?xf32>, tensor<?xf32>, tensor<?xf32>, tensor<?xf32>, tensor<?xf32>, tensor<?xf32>, tensor<?xf32>, tensor<?xf32>, tensor<?x?xf32>, tensor<?xf32>, tensor<?x?xf32>, tensor<?x?xf32>, tensor<?xf32>, tensor<?xf32>, tensor<?xf32>, tensor<?xf32>) -> tensor<?x?x?xf32>
func.return %0 : tensor<?x?x?xf32>
}
// -----
// CHECK-LABEL: testLSTMAsymAttributeTrue
func.func @testLSTMAsymAttributeTrue(%arg0: tensor<1x4xf32>, %arg1: tensor<4x4xf32>, %arg2: tensor<4x4xf32>, %arg3: tensor<4x4xf32>, %arg4: tensor<4x4xf32>, %arg5: tensor<4x4xf32>, %arg6: tensor<4x4xf32>, %arg7: tensor<4x4xf32>, %arg8: tensor<4x4xf32>, %arg9: tensor<4xf32>, %arg10: tensor<4xf32>, %arg11: tensor<4xf32>, %arg12: tensor<1x4xf32>, %arg13: tensor<4xf32>, %arg14: tensor<4xf32>, %arg15: tensor<4xf32>, %arg16: tensor<4x4xf32>, %arg17: tensor<4xf32>, %arg18: tensor<4xf32>, %arg19: tensor<4xf32>, %arg20: tensor<4xf32>, %arg21: tensor<4xf32>) -> tensor<1x4xf32> {
%cst0 = "tfl.pseudo_const" () {value = dense<0.0> : tensor<1x4xf32>} : () -> tensor<1x4xf32> loc("Const")
%cst1 = "tfl.pseudo_const" () {value = dense<0.0> : tensor<1x4xf32>} : () -> tensor<1x4xf32> loc("Const")
%24 = "tfl.lstm"(%arg0, %arg1, %arg2, %arg3, %arg4, %arg5, %arg6, %arg7, %arg8, %arg9, %arg10, %arg11, %arg12, %arg13, %arg14, %arg15, %arg16, %arg17, %cst0, %cst1, %arg18, %arg19, %arg20, %arg21) ({}) {asymmetric_quantize_inputs = true, cell_clip = 0.000000e+00 : f32, fused_activation_function = "NONE", kernel_type = #tfl<lstm_kernel_type_attr FULL>, proj_clip = 0.000000e+00 : f32} : (tensor<1x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<1x4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4x4xf32>, tensor<4xf32>, tensor<1x4xf32>, tensor<1x4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>) -> tensor<1x4xf32>
func.return %24 : tensor<1x4xf32>
// CHECK-DAG: %[[RES0:.*]] = "tfl.pseudo_const"() <{value = dense<{{.*}}> : tensor<1x4xf32>}> {tfl.is_variable} : () -> tensor<1x4xf32>
// CHECK-DAG: %[[RES1:.*]] = "tfl.pseudo_const"() <{value = dense<{{.*}}> : tensor<1x4xf32>}> {tfl.is_variable} : () -> tensor<1x4xf32>
// CHECK: %[[RES2:.*]] = "tfl.lstm"(%arg0, %arg1, %arg2, %arg3, %arg4, %arg5, %arg6, %arg7, %arg8, %arg9, %arg10, %arg11, %arg12, %arg13, %arg14, %arg15, %arg16, %arg17, %[[RES0]], %[[RES1]], %arg18, %arg19, %arg20, %arg21)
// CHECK-SAME: <{asymmetric_quantize_inputs = true, cell_clip = 0.000000e+00 : f32, fused_activation_function = "NONE", kernel_type = #tfl<lstm_kernel_type_attr FULL>, proj_clip = 0.000000e+00 : f32}> ({
// CHECK: }) : (tensor<1x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<1x4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4x4xf32>, tensor<4xf32>, tensor<1x4xf32>, tensor<1x4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>) -> tensor<1x4xf32>
// CHECK: return %[[RES2]]
}
// -----
// CHECK-LABEL: testLSTMAsymAttributeFalse
func.func @testLSTMAsymAttributeFalse(%arg0: tensor<1x4xf32>, %arg1: tensor<4x4xf32>, %arg2: tensor<4x4xf32>, %arg3: tensor<4x4xf32>, %arg4: tensor<4x4xf32>, %arg5: tensor<4x4xf32>, %arg6: tensor<4x4xf32>, %arg7: tensor<4x4xf32>, %arg8: tensor<4x4xf32>, %arg9: tensor<4xf32>, %arg10: tensor<4xf32>, %arg11: tensor<4xf32>, %arg12: tensor<1x4xf32>, %arg13: tensor<4xf32>, %arg14: tensor<4xf32>, %arg15: tensor<4xf32>, %arg16: tensor<4x4xf32>, %arg17: tensor<4xf32>, %arg18: tensor<4xf32>, %arg19: tensor<4xf32>, %arg20: tensor<4xf32>, %arg21: tensor<4xf32>) -> tensor<1x4xf32> {
%cst0 = "tfl.pseudo_const" () {value = dense<0.0> : tensor<1x4xf32>} : () -> tensor<1x4xf32> loc("Const")
%cst1 = "tfl.pseudo_const" () {value = dense<0.0> : tensor<1x4xf32>} : () -> tensor<1x4xf32> loc("Const")
%24 = "tfl.lstm"(%arg0, %arg1, %arg2, %arg3, %arg4, %arg5, %arg6, %arg7, %arg8, %arg9, %arg10, %arg11, %arg12, %arg13, %arg14, %arg15, %arg16, %arg17, %cst0, %cst1, %arg18, %arg19, %arg20, %arg21) ({}) {asymmetric_quantize_inputs = false, cell_clip = 0.000000e+00 : f32, fused_activation_function = "NONE", kernel_type = #tfl<lstm_kernel_type_attr FULL>, proj_clip = 0.000000e+00 : f32} : (tensor<1x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<1x4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4x4xf32>, tensor<4xf32>, tensor<1x4xf32>, tensor<1x4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>) -> tensor<1x4xf32>
func.return %24 : tensor<1x4xf32>
// CHECK-DAG: %[[RES0:.*]] = "tfl.pseudo_const"() <{value = dense<{{.*}}> : tensor<1x4xf32>}> {tfl.is_variable} : () -> tensor<1x4xf32>
// CHECK-DAG: %[[RES1:.*]] = "tfl.pseudo_const"() <{value = dense<{{.*}}> : tensor<1x4xf32>}> {tfl.is_variable} : () -> tensor<1x4xf32>
// CHECK: %[[RES2:.*]] = "tfl.lstm"(%arg0, %arg1, %arg2, %arg3, %arg4, %arg5, %arg6, %arg7, %arg8, %arg9, %arg10, %arg11, %arg12, %arg13, %arg14, %arg15, %arg16, %arg17, %[[RES0]], %[[RES1]], %arg18, %arg19, %arg20, %arg21)
// CHECK-SAME: <{asymmetric_quantize_inputs = false, cell_clip = 0.000000e+00 : f32, fused_activation_function = "NONE", kernel_type = #tfl<lstm_kernel_type_attr FULL>, proj_clip = 0.000000e+00 : f32}> ({
// CHECK: }) : (tensor<1x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<1x4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4x4xf32>, tensor<4xf32>, tensor<1x4xf32>, tensor<1x4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>) -> tensor<1x4xf32>
// CHECK: return %[[RES2]]
}
// -----
// CHECK-LABEL: testLSTMAsymAttributeDefault
func.func @testLSTMAsymAttributeDefault(%arg0: tensor<1x4xf32>, %arg1: tensor<4x4xf32>, %arg2: tensor<4x4xf32>, %arg3: tensor<4x4xf32>, %arg4: tensor<4x4xf32>, %arg5: tensor<4x4xf32>, %arg6: tensor<4x4xf32>, %arg7: tensor<4x4xf32>, %arg8: tensor<4x4xf32>, %arg9: tensor<4xf32>, %arg10: tensor<4xf32>, %arg11: tensor<4xf32>, %arg12: tensor<1x4xf32>, %arg13: tensor<4xf32>, %arg14: tensor<4xf32>, %arg15: tensor<4xf32>, %arg16: tensor<4x4xf32>, %arg17: tensor<4xf32>, %arg18: tensor<4xf32>, %arg19: tensor<4xf32>, %arg20: tensor<4xf32>, %arg21: tensor<4xf32>) -> tensor<1x4xf32> {
%cst0 = "tfl.pseudo_const" () {value = dense<0.0> : tensor<1x4xf32>} : () -> tensor<1x4xf32> loc("Const")
%cst1 = "tfl.pseudo_const" () {value = dense<0.0> : tensor<1x4xf32>} : () -> tensor<1x4xf32> loc("Const")
%24 = "tfl.lstm"(%arg0, %arg1, %arg2, %arg3, %arg4, %arg5, %arg6, %arg7, %arg8, %arg9, %arg10, %arg11, %arg12, %arg13, %arg14, %arg15, %arg16, %arg17, %cst0, %cst1, %arg18, %arg19, %arg20, %arg21) ({}) {cell_clip = 0.000000e+00 : f32, fused_activation_function = "NONE", kernel_type = #tfl<lstm_kernel_type_attr FULL>, proj_clip = 0.000000e+00 : f32} : (tensor<1x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<1x4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4x4xf32>, tensor<4xf32>, tensor<1x4xf32>, tensor<1x4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>) -> tensor<1x4xf32>
func.return %24 : tensor<1x4xf32>
// CHECK-DAG: %[[RES0:.*]] = "tfl.pseudo_const"() <{value = dense<{{.*}}> : tensor<1x4xf32>}> {tfl.is_variable} : () -> tensor<1x4xf32>
// CHECK-DAG: %[[RES1:.*]] = "tfl.pseudo_const"() <{value = dense<{{.*}}> : tensor<1x4xf32>}> {tfl.is_variable} : () -> tensor<1x4xf32>
// CHECK: %[[RES2:.*]] = "tfl.lstm"(%arg0, %arg1, %arg2, %arg3, %arg4, %arg5, %arg6, %arg7, %arg8, %arg9, %arg10, %arg11, %arg12, %arg13, %arg14, %arg15, %arg16, %arg17, %[[RES0]], %[[RES1]], %arg18, %arg19, %arg20, %arg21)
// CHECK-SAME: <{asymmetric_quantize_inputs = false, cell_clip = 0.000000e+00 : f32, fused_activation_function = "NONE", kernel_type = #tfl<lstm_kernel_type_attr FULL>, proj_clip = 0.000000e+00 : f32}> ({
// CHECK: }) : (tensor<1x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<1x4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4x4xf32>, tensor<4xf32>, tensor<1x4xf32>, tensor<1x4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>, tensor<4xf32>) -> tensor<1x4xf32>
// CHECK: return %[[RES2]]
}
@@ -0,0 +1,23 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// Confirm a wide array of attribute survives the round-trip
func.func @main(tensor<1x6x6x16xf32>) -> tensor<1x1x1x16xf32> {
^bb0(%arg0: tensor<1x6x6x16xf32>):
// CHECK: "tfl.average_pool_2d"(%{{.*}}) <{filter_height = 3 : i32, filter_width = 6 : i32, fused_activation_function = "NONE", padding = "VALID", stride_h = 3 : i32, stride_w = 1 : i32}> : (tensor<1x6x6x16xf32>) -> tensor<1x1x1x16xf32>
%0 = "tfl.average_pool_2d"(%arg0) {filter_height = 3 : i32, filter_width = 6 : i32, fused_activation_function = "NONE", padding = "VALID", stride_h = 3 : i32, stride_w = 1 : i32} : (tensor<1x6x6x16xf32>) -> tensor<1x1x1x16xf32> loc("avgpool")
func.return %0 : tensor<1x1x1x16xf32>
}
@@ -0,0 +1,32 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// Confirm float constants and operators survive a roundtrip
func.func @main(tensor<4xf32>) -> tensor<4xf32> {
^bb0(%arg0: tensor<4xf32>):
// CHECK: [[CONST:%.*]] = "tfl.pseudo_const"() <{value = dense<1.000000e+00> : tensor<4xf32>}> : () -> tensor<4xf32>
// CHECK-NEXT: [[SQDIFF:%.*]] = tfl.squared_difference %arg0, [[CONST]] : tensor<4xf32>
// CHECK-NEXT: %{{.*}} = tfl.mul %arg0, [[SQDIFF]] {fused_activation_function = "NONE"} : tensor<4xf32>
%0 = "tfl.pseudo_const" () {value = dense<1.0> : tensor<4xf32>} : () -> tensor<4xf32> loc("Const")
// Confirm that attributes that cannot be stored in the flatbuffer options
// for a given operator are dropped silently.
%1 = "tfl.squared_difference"(%arg0, %0) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32> loc("squared_difference")
%2 = "tfl.mul"(%arg0, %1) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32> loc("mul")
%3 = "tfl.div"(%2, %1) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32> loc("div")
%4 = "tfl.exp"(%3) : (tensor<4xf32>) -> tensor<4xf32> loc("exp")
%5 = "tfl.neg"(%4) : (tensor<4xf32>) -> tensor<4xf32> loc("neg")
func.return %5 : tensor<4xf32>
}
@@ -0,0 +1,42 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
func.func @main(%arg0: tensor<4x10x15xf32>, %arg1: tensor<4x15x17xf32>) -> tensor<4x10x17xf32> {
%0 = "tfl.batch_matmul"(%arg0, %arg1) {adj_x = false, adj_y = false} : (tensor<4x10x15xf32>, tensor<4x15x17xf32>) -> tensor<4x10x17xf32>
func.return %0: tensor<4x10x17xf32>
// CHECK-LABEL: main
// CHECK: %[[RESULT0:.*]] = "tfl.batch_matmul"(%arg0, %arg1) <{adj_x = false, adj_y = false, asymmetric_quantize_inputs = false}> : (tensor<4x10x15xf32>, tensor<4x15x17xf32>) -> tensor<4x10x17xf32>
// CHECK: return %[[RESULT0]]
}
// CHECK-LABEL: testMatmulAsymAttributeTrue
func.func @testMatmulAsymAttributeTrue(%arg0: tensor<4x10x15xf32>, %arg1: tensor<4x15x17xf32>) -> tensor<4x10x17xf32> {
%0 = "tfl.batch_matmul"(%arg0, %arg1) {adj_x = false, adj_y = false, asymmetric_quantize_inputs = true} : (tensor<4x10x15xf32>, tensor<4x15x17xf32>) -> tensor<4x10x17xf32>
func.return %0: tensor<4x10x17xf32>
// CHECK: %[[RESULT0:.*]] = "tfl.batch_matmul"(%arg0, %arg1) <{adj_x = false, adj_y = false, asymmetric_quantize_inputs = true}> : (tensor<4x10x15xf32>, tensor<4x15x17xf32>) -> tensor<4x10x17xf32>
// CHECK: return %[[RESULT0]]
}
// CHECK-LABEL: testMatmulAsymAttributeFalse
func.func @testMatmulAsymAttributeFalse(%arg0: tensor<4x10x15xf32>, %arg1: tensor<4x15x17xf32>) -> tensor<4x10x17xf32> {
%0 = "tfl.batch_matmul"(%arg0, %arg1) {adj_x = false, adj_y = false, asymmetric_quantize_inputs = false} : (tensor<4x10x15xf32>, tensor<4x15x17xf32>) -> tensor<4x10x17xf32>
func.return %0: tensor<4x10x17xf32>
// CHECK: %[[RESULT0:.*]] = "tfl.batch_matmul"(%arg0, %arg1) <{adj_x = false, adj_y = false, asymmetric_quantize_inputs = false}> : (tensor<4x10x15xf32>, tensor<4x15x17xf32>) -> tensor<4x10x17xf32>
// CHECK: return %[[RESULT0]]
}
@@ -0,0 +1,30 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer --emit-stablehlo-ops=true %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir --disable-vhlo-to-stablehlo=true - -o - | FileCheck %s
// test stablehlo roundtrip
module {
func.func @main(%arg0: tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32> {
%0 = "vhlo.logistic_v1"(%arg0) : (tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32>
%1 = "tfl.exp"(%0) : (tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32> loc("exp")
func.return %1 : tensor<1x1x1x96xf32>
}
}
// CHECK: func.func @main(%arg0: tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32> attributes {tf.entry_function = {inputs = "arg0", outputs = "exp"}} {
// CHECK-NEXT: %0 = "vhlo.logistic_v1"(%arg0) : (tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32>
// CHECK-NEXT: %1 = "tfl.exp"(%0) : (tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32>
// CHECK-NEXT: return %1 : tensor<1x1x1x96xf32>
// CHECK-NEXT: }
@@ -0,0 +1,90 @@
// RUN: json_to_flatbuffer %p/test_schema.fbs %s | flatbuffer_translate --tflite-flatbuffer-to-mlir --mlir-print-debuginfo -o - | FileCheck %s
// CHECK: #[[LOC0:.*]] = loc("<stdin>":0:0)
// CHECK: "tfl.split"
// CHECK-SAME: loc(#[[SPLIT_LOC:.*]])
// CHECK: #[[LOC1:.*]] = loc("output0"(#[[LOC0]]))
// CHECK: #[[LOC2:.*]] = loc("output1"(#[[LOC0]]))
// CHECK: #[[SPLIT_LOC]] = loc(fused[#[[LOC1]], #[[LOC2]]])
{
"version": 3,
"operator_codes": [
{
"builtin_code": "SPLIT"
}
],
"subgraphs": [
{
"tensors": [
{
"shape": [
1
],
"name": "split_dim",
"quantization": {
}
},
{
"shape": [
256,
32,
32,
3
],
"name": "input",
"quantization": {
}
},
{
"shape": [
128,
32,
32,
3
],
"name": "output0",
"quantization": {
}
},
{
"shape": [
128,
32,
32,
3
],
"name": "output1",
"quantization": {
}
}
],
"inputs": [
0,
1
],
"outputs": [
2,
3
],
"operators": [
{
"inputs": [
0,
1
],
"outputs": [
2,
3
],
"builtin_options_type": "SplitOptions",
"builtin_options": {
"num_splits": 2
}
}
],
"name": "main"
}
],
"description": "MLIR Converted."
}
@@ -0,0 +1,25 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// Test to make sure optional parameters survive a roundtrip
func.func @main(%arg0: tensor<40x37xf32>, %arg1: tensor<40x37xf32>) -> tensor<40x40xf32> {
// CHECK: [[NONE:%.*]] = "tfl.no_value"() <{value}> : () -> none
// CHECK: "tfl.fully_connected"(%arg0, %arg1, [[NONE]])
// CHECK-SAME: (tensor<40x37xf32>, tensor<40x37xf32>, none) -> (tensor<40x40xf32>, tensor<40x40xf32>)
%cst = "tfl.no_value"() {value = unit} : () -> none
%0:2 = "tfl.fully_connected"(%arg0, %arg1, %cst) {fused_activation_function = "NONE", keep_num_dims = false, weights_format = "DEFAULT"} : (tensor<40x37xf32>, tensor<40x37xf32>, none) -> (tensor<40x40xf32>, tensor<40x40xf32>)
func.return %0 : tensor<40x40xf32>
}
@@ -0,0 +1,80 @@
// RUN: json_to_flatbuffer %p/test_schema.fbs %s | flatbuffer_translate --tflite-flatbuffer-to-mlir -o - | FileCheck %s
// This test is to test that if the flatbuffer omits the last optional input `bias` of tfl.conv_2d op, the flatbuffer_importer will automatically adds `none` value to tfl.conv_2d.
// CHECK: %[[CST:.*]] = "tfl.no_value"() <{value}> : () -> none
// CHECK: %[[RES0:.*]] = "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<256x32x32x3xf32>, tensor<16x3x3x3xf32>, none) -> tensor<256x32x32x16xf32>
// CHECK: return %[[RES0]] : tensor<256x32x32x16xf32>
{
"version": 3,
"operator_codes": [
{
"builtin_code": "CONV_2D"
}
],
"subgraphs": [
{
"tensors": [
{
"shape": [
256,
32,
32,
3
],
"name": "arg0",
"quantization": {
}
},
{
"shape": [
16,
3,
3,
3
],
"name": "arg1",
"quantization": {
}
},
{
"shape": [
256,
32,
32,
16
],
"name": "output",
"quantization": {
}
}
],
"inputs": [
0,
1
],
"outputs": [
2
],
"operators": [
{
"inputs": [
0,
1
],
"outputs": [
2
],
"builtin_options_type": "Conv2DOptions",
"builtin_options": {
"stride_w": 1,
"stride_h": 1
}
}
],
"name": "main"
}
],
"description": "MLIR Converted."
}
@@ -0,0 +1,33 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate -output-arrays=mul,exp,div --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// Confirm output-arrays works.
func.func @main(tensor<4xf32>) -> tensor<4xf32> {
^bb0(%arg0: tensor<4xf32>):
%0 = "tfl.pseudo_const" () {value = dense<2.0> : tensor<4xf32>} : () -> tensor<4xf32> loc("Const")
%1 = "tfl.squared_difference"(%arg0, %0) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32> loc("squared_difference")
// CHECK: %[[MUL:.*]] = tfl.mul
%2 = "tfl.mul"(%0, %1) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32> loc("mul")
// CHECK: %[[DIV:.*]] = tfl.div
%3 = "tfl.div"(%2, %1) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32> loc("div")
// CHECK: %[[EXP:.*]] = "tfl.exp"
%4 = "tfl.exp"(%3) : (tensor<4xf32>) -> tensor<4xf32> loc("exp")
// tfl.neg should not be pruned
// CHECK: %[[NEG:.*]] = "tfl.neg"
%5 = "tfl.neg"(%4) : (tensor<4xf32>) -> tensor<4xf32> loc("neg")
// CHECK: return %[[MUL]], %[[EXP]], %[[DIV]]
func.return %5 : tensor<4xf32>
}
@@ -0,0 +1,33 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate -output-arrays=mul,exp,div --experimental-prune-unreachable-nodes-unconditionally --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// Confirm graph pruning.
func.func @main(tensor<4xf32>) -> tensor<4xf32> {
^bb0(%arg0: tensor<4xf32>):
%0 = "tfl.pseudo_const" () {value = dense<2.0> : tensor<4xf32>} : () -> tensor<4xf32> loc("Const")
%1 = "tfl.squared_difference"(%arg0, %0) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32> loc("squared_difference")
// CHECK: %[[MUL:.*]] = tfl.mul
%2 = "tfl.mul"(%0, %1) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32> loc("mul")
// CHECK: %[[DIV:.*]] = tfl.div
%3 = "tfl.div"(%2, %1) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32> loc("div")
// CHECK: %[[EXP:.*]] = "tfl.exp"
%4 = "tfl.exp"(%3) : (tensor<4xf32>) -> tensor<4xf32> loc("exp")
// tfl.neg should be pruned
// CHECK-NOT: "tfl.neg"
%5 = "tfl.neg"(%4) : (tensor<4xf32>) -> tensor<4xf32> loc("neg")
// CHECK: return %[[MUL]], %[[EXP]], %[[DIV]]
func.return %5 : tensor<4xf32>
}
@@ -0,0 +1,30 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate -output-arrays=mul,div,exp --experimental-prune-unreachable-nodes-unconditionally --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// CHECK: (%[[ARG:.*]]: tensor<4xf32>) -> (tensor<4xf32>, tensor<4xf32>, tensor<4xf32>)
func.func @main(%arg0: tensor<4xf32>) -> tensor<4xf32> attributes {tf.entry_function = {inputs = "mul"}} {
%0 = "tfl.pseudo_const" () {value = dense<1.0> : tensor<4xf32>} : () -> tensor<4xf32> loc("Const")
%1 = "tfl.squared_difference"(%arg0, %0) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32> loc("squared_difference")
// CHECK: %[[DIV:.*]] = tfl.div
%2 = "tfl.div"(%1, %arg0) {fused_activation_function = "NONE"} : (tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32> loc("div")
// CHECK: %[[EXP:.*]] = "tfl.exp"
%3 = "tfl.exp"(%2) : (tensor<4xf32>) -> tensor<4xf32> loc("exp")
// tfl.neg should be pruned
// CHECK-NOT: "tfl.neg"
%4 = "tfl.neg"(%3) : (tensor<4xf32>) -> tensor<4xf32> loc("neg")
// CHECK: return %[[ARG]], %[[DIV]], %[[EXP]]
func.return %4 : tensor<4xf32>
}
@@ -0,0 +1,24 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// Ensure "quantfork.stats" roundtrip exactly
func.func @main(%arg0: tensor<1x512x672x8xf32>) -> tensor<1x512x672x8xf32> {
// CHECK-LABEL: @main
// CHECK: %[[RES0:.*]] = "quantfork.stats"(%arg0) <{layerStats = dense<[0.000000e+00, 2.550000e+02]> : tensor<2xf32>}> : (tensor<1x512x672x8xf32>) -> tensor<1x512x672x8xf32>
%0 = "quantfork.stats"(%arg0) {layerStats = dense<[0.000000e+00, 2.550000e+02]> : tensor<2xf32>} : (tensor<1x512x672x8xf32>) -> tensor<1x512x672x8xf32>
func.return %0 : tensor<1x512x672x8xf32>
}
@@ -0,0 +1,49 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// CHECK-LABEL: main
func.func @main(%arg0: tensor<1x224x224x3xf32>) -> tensor<1x401408xf32> {
// CHECK: %{{.*}} = "tfl.quantize"(%{{.*}}) <{qtype = tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>}> : (tensor<1x224x224x3xf32>) -> tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>
// The float values here doesn't match exactly because double -> float -> double is lossy
// CHECK-NEXT: %{{.*}} = "tfl.pseudo_qconst"() <{qtype = tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 0.021826678{{[0-9]*}}:151>>, value = dense<-76> : tensor<32x3x3x3xi8>}> : () -> tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 0.021826678{{[0-9]*}}:151>>
// CHECK-NEXT: %{{.*}} = "tfl.pseudo_qconst"() <{qtype = tensor<32x!quant.uniform<i32:f32, 1.7052092{{[0-9]*}}E-4>>, value = dense<0> : tensor<32xi32>}> : () -> tensor<32x!quant.uniform<i32:f32, 1.7052092{{[0-9]*}}E-4>>
// CHECK: %{{.*}} = "tfl.dequantize"(%{{.*}}) : (tensor<1x401408x!quant.uniform<u8:f32, 3.906250e-03>>) -> tensor<1x401408xf32>
%cst = arith.constant dense<[1, 401408]> : tensor<2xi32>
%0 = "tfl.quantize"(%arg0) {qtype = tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>} : (tensor<1x224x224x3xf32>) -> tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>
%1 = "tfl.pseudo_qconst"() {qtype = tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 0.021826678373682216:151>>, value = dense<-76> : tensor<32x3x3x3xi8>} : () -> tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 0.021826678373682216:151>>
%2 = "tfl.pseudo_qconst"() {qtype = tensor<32x!quant.uniform<i32:f32, 1.7052092479439231E-4>>, value = dense<0> : tensor<32xi32>} : () -> tensor<32x!quant.uniform<i32:f32, 1.7052092479439231E-4>>
%3 = "tfl.conv_2d"(%0, %1, %2) {dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 2 : i32, stride_w = 2 : i32} : (tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>, tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 0.021826678373682216:151>>, tensor<32x!quant.uniform<i32:f32, 1.7052092479439231E-4>>) -> tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>
%4 = "tfl.reshape"(%3, %cst) : (tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>, tensor<2xi32>) -> tensor<1x401408x!quant.uniform<u8:f32, 0.023528476789885875>>
%5 = "tfl.softmax"(%4) {beta = 1.000000e+00 : f32} : (tensor<1x401408x!quant.uniform<u8:f32, 0.023528476789885875>>) -> tensor<1x401408x!quant.uniform<u8:f32, 3.906250e-03>>
%6 = "tfl.dequantize"(%5) : (tensor<1x401408x!quant.uniform<u8:f32, 3.906250e-03>>) -> tensor<1x401408xf32>
func.return %6 : tensor<1x401408xf32>
}
// CHECK-LABEL: quantized_constant
func.func @quantized_constant(%arg0: tensor<1x2xf32>) -> tensor<2x2xf32> {
%1 = "tfl.quantize"(%arg0) {qtype = tensor<1x2x!quant.uniform<u8:f32, 1.0>>, volatile} : (tensor<1x2xf32>) -> tensor<1x2x!quant.uniform<u8:f32, 1.0>>
%cst = "tfl.pseudo_qconst"() {qtype = tensor<1x2x!quant.uniform<u8:f32, 1.0>>, value = dense<-76> : tensor<1x2xi8>} : () -> tensor<1x2x!quant.uniform<u8:f32, 1.0>>
%2 = "tfl.concatenation"(%1, %cst) {axis = 0 : i32, fused_activation_function = "NONE"} : (tensor<1x2x!quant.uniform<u8:f32, 1.0>>, tensor<1x2x!quant.uniform<u8:f32, 1.0>>) -> tensor<2x2x!quant.uniform<u8:f32, 1.0>>
%3 = "tfl.dequantize"(%2) : (tensor<2x2x!quant.uniform<u8:f32, 1.0>>) -> tensor<2x2xf32>
func.return %3 : tensor<2x2xf32>
// CHECK-NEXT: %[[Q:.*]] = "tfl.quantize"(%arg0) <{qtype = tensor<1x2x!quant.uniform<u8:f32, 1.000000e+00>>}> : (tensor<1x2xf32>) -> tensor<1x2x!quant.uniform<u8:f32, 1.000000e+00>>
// CHECK-NEXT: %[[CST:.*]] = "tfl.pseudo_qconst"() <{qtype = tensor<1x2x!quant.uniform<u8:f32, 1.000000e+00>>, value = dense<-76> : tensor<1x2xi8>}> : () -> tensor<1x2x!quant.uniform<u8:f32, 1.000000e+00>>
// CHECK-NEXT: %[[CONCAT:.*]] = "tfl.concatenation"(%[[Q]], %[[CST]]) <{axis = 0 : i32, fused_activation_function = "NONE"}> : (tensor<1x2x!quant.uniform<u8:f32, 1.000000e+00>>, tensor<1x2x!quant.uniform<u8:f32, 1.000000e+00>>) -> tensor<2x2x!quant.uniform<u8:f32, 1.000000e+00>>
// CHECK-NEXT: %[[DQ:.*]] = "tfl.dequantize"(%[[CONCAT]]) : (tensor<2x2x!quant.uniform<u8:f32, 1.000000e+00>>) -> tensor<2x2xf32>
// CHECK-NEXT: return %[[DQ]] : tensor<2x2xf32>
}
@@ -0,0 +1,25 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// Confirm we can extract type info from reshape
func.func @main() -> tensor<2x2xf32> {
// CHECK: %[[cst:.*]] = "tfl.pseudo_const"() <{value = dense<2> : tensor<2xi32>}> : () -> tensor<2xi32>
// CHECK: %{{.*}} = "tfl.reshape"(%{{.*}}, %[[cst]]) : (tensor<4xf32>, tensor<2xi32>) -> tensor<2x2xf32>
%cst = arith.constant dense<[2, 2]> : tensor<2xi32>
%0 = "tfl.pseudo_const" () {value = dense<1.0> : tensor<4xf32>} : () -> tensor<4xf32> loc("Const")
%1 = "tfl.reshape" (%0, %cst) : (tensor<4xf32>, tensor<2xi32>) -> tensor<2x2xf32> loc("reshape")
func.return %1 : tensor<2x2xf32>
}
@@ -0,0 +1,32 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// CHECK: {tf_saved_model.index_path = ["input2"]}
// CHECK-SAME: {tf_saved_model.index_path = ["input1"]}
// CHECK-SAME: {tf_saved_model.index_path = ["start_logits"]}
// CHECK-SAME: {tf_saved_model.index_path = ["end_logits"]}
// CHECK-SAME: tf.entry_function = {inputs = "serving_default_input2:0,serving_default_input1:0", outputs = "StatefulPartitionedCall:1,StatefulPartitionedCall:0"}
// CHECK-SAME: tf_saved_model.exported_names = ["serving_default"]
module attributes {tf.versions = {bad_consumers = [], min_consumer = 12 : i32, producer = 554 : i32}, tf_saved_model.semantics} {
func.func @main(%arg0: tensor<?x384xf32> {tf_saved_model.index_path = ["input2"]}, %arg1: tensor<?x384xf32> {tf_saved_model.index_path = ["input1"]}) -> (tensor<?x5xf32> {tf_saved_model.index_path = ["start_logits"]}, tensor<?x5xf32> {tf_saved_model.index_path = ["end_logits"]}) attributes {tf.entry_function = {control_outputs = "", inputs = "serving_default_input2:0,serving_default_input1:0", outputs = "StatefulPartitionedCall:1,StatefulPartitionedCall:0"}, tf_saved_model.exported_names = ["serving_default"]} {
%cst = arith.constant dense<0.000000e+00> : tensor<5xf32>
%cst_0 = arith.constant dense<1.0> : tensor<5x384xf32>
%cst_1 = arith.constant dense<1.0> : tensor<5x384xf32>
%0 = "tfl.fully_connected"(%arg0, %cst_0, %cst) {fused_activation_function = "NONE", keep_num_dims = false, weights_format = "DEFAULT"} : (tensor<?x384xf32>, tensor<5x384xf32>, tensor<5xf32>) -> tensor<?x5xf32>
%1 = "tfl.fully_connected"(%arg0, %cst_1, %cst) {fused_activation_function = "NONE", keep_num_dims = false, weights_format = "DEFAULT"} : (tensor<?x384xf32>, tensor<5x384xf32>, tensor<5xf32>) -> tensor<?x5xf32>
func.return %1, %0 : tensor<?x5xf32>, tensor<?x5xf32>
}
}
@@ -0,0 +1,42 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// CHECK: func @add(
// CHECK-SAME: {tf_saved_model.index_path = ["input1"]}
// CHECK-SAME: {tf_saved_model.index_path = ["input2"]}
// CHECK-SAME: {tf_saved_model.index_path = ["result"]}
// CHECK-SAME: tf.entry_function = {inputs = "input1:0,input2:0", outputs = "result:0"}
// CHECK-SAME: tf_saved_model.exported_names = ["add"]
// CHECK: func @sub(
// CHECK-SAME: {tf_saved_model.index_path = ["input2"]}
// CHECK-SAME: {tf_saved_model.index_path = ["input1"]}
// CHECK-SAME: {tf_saved_model.index_path = ["result"]}
// CHECK-SAME: tf.entry_function = {inputs = "input2:0,input1:0", outputs = "result:0"}
// CHECK-SAME: tf_saved_model.exported_names = ["sub"]
module attributes {tf.versions = {bad_consumers = [], min_consumer = 12 : i32, producer = 554 : i32}, tf_saved_model.semantics} {
func.func @add(%arg0: tensor<?xf32> {tf_saved_model.index_path = ["input1"]}, %arg1: tensor<?xf32> {tf_saved_model.index_path = ["input2"]}) -> (tensor<?xf32> {tf_saved_model.index_path = ["result"]}) attributes {tf.entry_function = {control_outputs = "", inputs = "input1:0,input2:0", outputs = "result:0"}, tf_saved_model.exported_names = ["add"]} {
%0 = tfl.add %arg0, %arg1 {fused_activation_function = "NONE"} : tensor<?xf32>
%1 = tfl.add %0, %0 {fused_activation_function = "NONE"} : tensor<?xf32>
func.return %1 : tensor<?xf32>
}
func.func @sub(%arg0: tensor<?xf32> {tf_saved_model.index_path = ["input2"]}, %arg1: tensor<?xf32> {tf_saved_model.index_path = ["input1"]}) -> (tensor<?xf32> {tf_saved_model.index_path = ["result"]}) attributes {tf.entry_function = {control_outputs = "", inputs = "input2:0,input1:0", outputs = "result:0"}, tf_saved_model.exported_names = ["sub"]} {
%0 = tfl.sub %arg0, %arg1 {fused_activation_function = "NONE"} : tensor<?xf32>
func.return %0 : tensor<?xf32>
}
}
@@ -0,0 +1,38 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o -
// TODO(b/329300758): add file check back after the cl is fixed | FileCheck %s
// Check a few basic properties of the import-export,
// including constants retaining their shape
// and the module including the TFLite version.
func.func @main(tensor<3x2xi32>) -> tensor<3x2xi32> {
^bb0(%arg0: tensor<3x2xi32>):
// CHECK: module attributes
// CHECK-SAME: tfl.description = "MLIR Converted."
// CHECK-SAME: tfl.schema_version = 3 : i32
// CHECK: %{{.*}} = "tfl.pseudo_const"() <{value = dense<{{\[\[1, 2\], \[3, 4\], \[5, 6\]\]}}> : tensor<3x2xi32>}>
// CHECK-NEXT: [[SUB:%.*]] = tfl.sub %{{.*}}, %{{.*}} {fused_activation_function = "RELU6"} : tensor<3x2xi32>
// CHECK-NEXT: [[SCALAR:%.*]] = "tfl.pseudo_const"() <{value = dense<10> : tensor<i32>}> : () -> tensor<i32>
// CHECK-NEXT: [[ADD:%.*]] = tfl.add([[SCALAR]], [[SUB]]) {fused_activation_function = "NONE"} : (tensor<i32>, tensor<3x2xi32>) -> tensor<3x2xi32>
// CHECK-NEXT: return [[ADD]] : tensor<3x2xi32>
%0 = "tfl.pseudo_const" () {value = dense<[[1, 2], [3, 4], [5, 6]]> : tensor<3x2xi32>} : () -> tensor<3x2xi32> loc("Const")
%1 = "tfl.sub" (%arg0, %0) {fused_activation_function = "RELU6"} : (tensor<3x2xi32>, tensor<3x2xi32>) -> tensor<3x2xi32> loc("sub")
%2 = "arith.constant" () {value = dense<10> : tensor<i32>} : () -> tensor<i32> loc("Const2")
%3 = "tfl.add" (%2, %1) {fused_activation_function = "NONE"} : (tensor<i32>, tensor<3x2xi32>) -> tensor<3x2xi32> loc("add")
func.return %3 : tensor<3x2xi32>
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,22 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
func.func @main(%arg0 : tensor<!tf_type.variant<tensor<2xi32>>>, %arg1: tensor<!tf_type.variant<tensor<*xi32>>>) -> tensor<!tf_type.variant<tensor<2xi32>>> {
func.return %arg0 : tensor<!tf_type.variant<tensor<2xi32>>>
}
// CHECK: func.func @main(%[[ARG0:.*]]: tensor<!tf_type.variant<tensor<2xi32>>>, %[[ARG1:.*]]: tensor<!tf_type.variant<tensor<*xi32>>>) -> tensor<!tf_type.variant<tensor<2xi32>>>
// CHECK-NEXT: return %[[ARG0]] : tensor<!tf_type.variant<tensor<2xi32>>>
@@ -0,0 +1,42 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: litert-opt --tfl-legalize-tf-while %s -o - | flatbuffer_translate -mlir-to-tflite-flatbuffer - -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// This test is to test for unranked function output from input, the output type should be compatible with input type.
// CHECK: func @main(%arg0: tensor<1xf32>) -> tensor<*xf32> attributes {tf.entry_function = {inputs = "arg0", outputs = "tfl.while"}} {
// CHECK: %0 = "tfl.while"(%arg0) ({
// CHECK: ^bb0(%arg1: tensor<*xf32>):
// CHECK: %[[RES0:.*]] = func.call @cond(%arg1) : (tensor<*xf32>) -> tensor<*xf32>
// CHECK: "tfl.yield"(%[[RES0]]) : (tensor<*xf32>) -> ()
// CHECK: }, {
// CHECK: ^bb0(%arg1: tensor<*xf32>):
// CHECK: %[[RES1:.*]] = func.call @body(%arg1) : (tensor<*xf32>) -> tensor<*xf32>
// CHECK: "tfl.yield"(%[[RES1]]) : (tensor<*xf32>) -> ()
// CHECK: }) : (tensor<1xf32>) -> tensor<*xf32>
// CHECK: return %0 : tensor<*xf32>
// CHECK: }
func.func @main(%arg0: tensor<1xf32>) -> tensor<*xf32> {
%0 = "tf.While"(%arg0) {cond = @cond, body = @body, is_stateless = false} : (tensor<1xf32>) -> tensor<*xf32>
func.return %0 : tensor<*xf32>
}
func.func @cond(%arg1: tensor<*xf32>) -> tensor<*xf32> {
func.return %arg1: tensor<*xf32>
}
func.func @body(%arg1: tensor<*xf32>) -> tensor<*xf32> {
func.return %arg1: tensor<*xf32>
}
@@ -0,0 +1,24 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: litert-opt --tfl-legalize-tf-while %s -o - | flatbuffer_translate -mlir-to-tflite-flatbuffer - -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// CHECK-LABEL: main
func.func @main(%arg0: tensor<*xf32>) -> tensor<*xf32> {
// CHECK: %{{.*}} = tfl.add %{{.*}}, %{{.*}} {fused_activation_function = "NONE"} : tensor<*xf32>
// CHECK: return %{{.*}} : tensor<*xf32>
%0 = tfl.add(%arg0, %arg0) {fused_activation_function = "NONE"} : (tensor<*xf32>, tensor<*xf32>) -> tensor<*xf32>
return %0 : tensor<*xf32>
}
@@ -0,0 +1,22 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// CHECK-LABEL: main
func.func @main() -> tensor<3x2xi32> {
// CHECK: "tfl.pseudo_const"() <{value = dense<0> : tensor<3x2xi32>}> {tfl.is_variable} : () -> tensor<3x2xi32>
%0 = "tfl.pseudo_const"() {value = dense<0> : tensor<3x2xi32>, tfl.is_variable} : () -> tensor<3x2xi32> loc("variable")
func.return %0 : tensor<3x2xi32>
}
@@ -0,0 +1,584 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer --emit-stablehlo-ops=true %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir --disable-vhlo-to-stablehlo=true - -o - | FileCheck %s
// test stablehlo roundtrip
// Identity function to make the exporter happy
func.func @main(%arg0: tensor<4xi8>) -> tensor<4xi8> {
func.return %arg0 : tensor<4xi8>
}
//CHECK:func.func @main(%arg0: tensor<4xi8>) -> tensor<4xi8> attributes {tf.entry_function = {inputs = "arg0", outputs = "arg0"}} {
//CHECK: return %arg0 : tensor<4xi8>
//CHECK:}
func.func @logistic(%arg0: tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32> {
%0 = "vhlo.logistic_v1"(%arg0) : (tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32>
func.return %0 : tensor<1x1x1x96xf32>
}
// CHECK:func.func private @logistic(%arg0: tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32> {
// CHECK: %0 = "vhlo.logistic_v1"(%arg0) : (tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32>
// CHECK: return %0 : tensor<1x1x1x96xf32>
// CHECK:}
func.func @add(%arg0: tensor<1xf32>, %arg1: tensor<1xf32>) -> tensor<1xf32> {
%0 = "vhlo.add_v1"(%arg0, %arg1) : (tensor<1xf32>, tensor<1xf32>) -> tensor<1xf32>
func.return %0 : tensor<1xf32>
}
// CHECK:func.func private @add(%arg0: tensor<1xf32>, %arg1: tensor<1xf32>) -> tensor<1xf32> {
// CHECK: %0 = "vhlo.add_v1"(%arg0, %arg1) : (tensor<1xf32>, tensor<1xf32>) -> tensor<1xf32>
// CHECK: return %0 : tensor<1xf32>
// CHECK:}
func.func @multiply(%arg0: tensor<1xf32>, %arg1: tensor<1xf32>) -> tensor<1xf32> {
%0 = "vhlo.multiply_v1"(%arg0, %arg1) : (tensor<1xf32>, tensor<1xf32>) -> tensor<1xf32>
func.return %0 : tensor<1xf32>
}
// CHECK:func.func private @multiply(%arg0: tensor<1xf32>, %arg1: tensor<1xf32>) -> tensor<1xf32> {
// CHECK: %0 = "vhlo.multiply_v1"(%arg0, %arg1) : (tensor<1xf32>, tensor<1xf32>) -> tensor<1xf32>
// CHECK: return %0 : tensor<1xf32>
// CHECK:}
func.func @divide(%arg0: tensor<1xf32>, %arg1: tensor<1xf32>) -> tensor<1xf32> {
%0 = "vhlo.divide_v1"(%arg0, %arg1) : (tensor<1xf32>, tensor<1xf32>) -> tensor<1xf32>
func.return %0 : tensor<1xf32>
}
// CHECK:func.func private @divide(%arg0: tensor<1xf32>, %arg1: tensor<1xf32>) -> tensor<1xf32> {
// CHECK: %0 = "vhlo.divide_v1"(%arg0, %arg1) : (tensor<1xf32>, tensor<1xf32>) -> tensor<1xf32>
// CHECK: return %0 : tensor<1xf32>
// CHECK:}
func.func @maximum(%arg0: tensor<1xf32>, %arg1: tensor<1xf32>) -> tensor<1xf32> {
%0 = "vhlo.maximum_v1"(%arg0, %arg1) : (tensor<1xf32>, tensor<1xf32>) -> tensor<1xf32>
func.return %0 : tensor<1xf32>
}
// CHECK:func.func private @maximum(%arg0: tensor<1xf32>, %arg1: tensor<1xf32>) -> tensor<1xf32> {
// CHECK: %0 = "vhlo.maximum_v1"(%arg0, %arg1) : (tensor<1xf32>, tensor<1xf32>) -> tensor<1xf32>
// CHECK: return %0 : tensor<1xf32>
// CHECK:}
func.func @reshape(%arg0 : tensor<1x128xi32>) -> tensor<4x32x1xi32>{
%0 = "vhlo.reshape_v1"(%arg0) : (tensor<1x128xi32>) -> tensor<4x32x1xi32>
func.return %0 : tensor<4x32x1xi32>
}
//CHECK:func.func private @reshape(%arg0: tensor<1x128xi32>) -> tensor<4x32x1xi32> {
//CHECK-NEXT: %0 = "vhlo.reshape_v1"(%arg0) : (tensor<1x128xi32>) -> tensor<4x32x1xi32>
//CHECK-NEXT: return %0 : tensor<4x32x1xi32>
//CHECK-NEXT:}
func.func @clamp(%arg0: tensor<f32>, %arg1: tensor<1x256x256x24xf32>, %arg2: tensor<f32>) -> tensor<1x256x256x24xf32>{
%0 = "vhlo.clamp_v1"(%arg0, %arg1, %arg2) : (tensor<f32>, tensor<1x256x256x24xf32>, tensor<f32>) -> tensor<1x256x256x24xf32>
return %0 : tensor<1x256x256x24xf32>
}
//CHECK:func.func private @clamp(%arg0: tensor<f32>, %arg1: tensor<1x256x256x24xf32>, %arg2: tensor<f32>) -> tensor<1x256x256x24xf32> {
//CHECK-NEXT: %0 = "vhlo.clamp_v1"(%arg0, %arg1, %arg2) : (tensor<f32>, tensor<1x256x256x24xf32>, tensor<f32>) -> tensor<1x256x256x24xf32>
//CHECK-NEXT: return %0 : tensor<1x256x256x24xf32>
//CHECK-NEXT:}
func.func @concat(%arg0: tensor<1x30x1xi32>, %arg1: tensor<1x30x1xi32>) -> tensor<1x30x2xi32> {
%0 = "vhlo.concatenate_v1"(%arg0, %arg1) <{dimension = #vhlo.integer_v1<2 : i64>}> : (tensor<1x30x1xi32>, tensor<1x30x1xi32>) -> tensor<1x30x2xi32>
func.return %0 : tensor<1x30x2xi32>
}
//CHECK:func.func private @concat(%arg0: tensor<1x30x1xi32>, %arg1: tensor<1x30x1xi32>) -> tensor<1x30x2xi32> {
//CHECK-NEXT: %0 = "vhlo.concatenate_v1"(%arg0, %arg1) <{dimension = #vhlo.integer_v1<2 : i64>}> : (tensor<1x30x1xi32>, tensor<1x30x1xi32>) -> tensor<1x30x2xi32>
//CHECK-NEXT: return %0 : tensor<1x30x2xi32>
//CHECK-NEXT:}
func.func @broadcast_in_dim(%arg0: tensor<1x32x256xf32>) -> tensor<4x32x256xf32>{
%0 = "vhlo.broadcast_in_dim_v1"(%arg0) <{broadcast_dimensions = #vhlo.tensor_v1<dense<[0, 1, 2]> : tensor<3xi64>>}> : (tensor<1x32x256xf32>) -> tensor<4x32x256xf32>
return %0 : tensor<4x32x256xf32>
}
//CHECK:func.func private @broadcast_in_dim(%arg0: tensor<1x32x256xf32>) -> tensor<4x32x256xf32> {
//CHECK-NEXT: %0 = "vhlo.broadcast_in_dim_v1"(%arg0) <{broadcast_dimensions = #vhlo.tensor_v1<dense<[0, 1, 2]> : tensor<3xi64>>}> : (tensor<1x32x256xf32>) -> tensor<4x32x256xf32>
//CHECK-NEXT: return %0 : tensor<4x32x256xf32>
//CHECK-NEXT:}
func.func @slice(%arg0: tensor<160x20x1xf32>) -> tensor<1x1x1xf32> {
%0 = "vhlo.slice_v1"(%arg0) <{limit_indices = #vhlo.tensor_v1<dense<[0, 0, 0]> : tensor<3xi64>>,
start_indices = #vhlo.tensor_v1<dense<[1, 1, 1]> : tensor<3xi64>>,
strides = #vhlo.tensor_v1<dense<[1, 1, 1]> : tensor<3xi64>>}> : (tensor<160x20x1xf32>) -> tensor<1x1x1xf32>
return %0 : tensor<1x1x1xf32>
}
//CHECK:func.func private @slice(%arg0: tensor<160x20x1xf32>) -> tensor<1x1x1xf32> {
//CHECK-NEXT: %0 = "vhlo.slice_v1"(%arg0) <{limit_indices = #vhlo.tensor_v1<dense<0> : tensor<3xi64>>, start_indices = #vhlo.tensor_v1<dense<1> : tensor<3xi64>>, strides = #vhlo.tensor_v1<dense<1> : tensor<3xi64>>}> : (tensor<160x20x1xf32>) -> tensor<1x1x1xf32>
//CHECK-NEXT: return %0 : tensor<1x1x1xf32>
//CHECK-NEXT:}
func.func @convolution(%arg0: tensor<1x1x1600x32xf32>, %arg1: tensor<1x13x1x32xf32>) -> tensor<1x1x1600x32xf32> {
%0 = "vhlo.convolution_v1"(%arg0, %arg1) <{batch_group_count = #vhlo.integer_v1<1 : i64>,
feature_group_count = #vhlo.integer_v1<32 : i64>,
input_batch_dimension = #vhlo.integer_v1<0 : i64>,
input_feature_dimension = #vhlo.integer_v1<3 : i64>,
input_spatial_dimensions = #vhlo.tensor_v1<dense<[1, 2]> : tensor<2xi64>>,
kernel_input_feature_dimension = #vhlo.integer_v1<2 : i64>,
kernel_output_feature_dimension = #vhlo.integer_v1<3 : i64>,
kernel_spatial_dimensions = #vhlo.tensor_v1<dense<[0, 1]> : tensor<2xi64>>,
lhs_dilation = #vhlo.tensor_v1<dense<1> : tensor<2xi64>>,
output_batch_dimension = #vhlo.integer_v1<0 : i64>,
output_feature_dimension = #vhlo.integer_v1<3 : i64>,
output_spatial_dimensions = #vhlo.tensor_v1<dense<[1, 2]> : tensor<2xi64>>,
padding = #vhlo.tensor_v1<dense<0> : tensor<2x2xi64>>,
precision_config = #vhlo.array_v1<[#vhlo<precision_v1 DEFAULT>, #vhlo<precision_v1 DEFAULT>]>,
rhs_dilation = #vhlo.tensor_v1<dense<1> : tensor<2xi64>>,
window_reversal = #vhlo.tensor_v1<dense<false> : tensor<2xi1>>,
window_strides = #vhlo.tensor_v1<dense<1> : tensor<2xi64>>}>
: (tensor<1x1x1600x32xf32>, tensor<1x13x1x32xf32>) -> tensor<1x1x1600x32xf32>
return %0 : tensor<1x1x1600x32xf32>
}
//CHECK:func.func private @convolution(%arg0: tensor<1x1x1600x32xf32>, %arg1: tensor<1x13x1x32xf32>) -> tensor<1x1x1600x32xf32> {
//CHECK: %0 = "vhlo.convolution_v1"(%arg0, %arg1) <{
//CHECK-SAME: batch_group_count = #vhlo.integer_v1<1 : i64>,
//CHECK-SAME: feature_group_count = #vhlo.integer_v1<32 : i64>,
//CHECK-SAME: input_batch_dimension = #vhlo.integer_v1<0 : i64>,
//CHECK-SAME: input_feature_dimension = #vhlo.integer_v1<3 : i64>,
//CHECK-SAME: input_spatial_dimensions = #vhlo.tensor_v1<dense<[1, 2]> : tensor<2xi64>>,
//CHECK-SAME: kernel_input_feature_dimension = #vhlo.integer_v1<2 : i64>,
//CHECK-SAME: kernel_output_feature_dimension = #vhlo.integer_v1<3 : i64>,
//CHECK-SAME: kernel_spatial_dimensions = #vhlo.tensor_v1<dense<[0, 1]> : tensor<2xi64>>,
//CHECK-SAME: lhs_dilation = #vhlo.tensor_v1<dense<1> : tensor<2xi64>>,
//CHECK-SAME: output_batch_dimension = #vhlo.integer_v1<0 : i64>,
//CHECK-SAME: output_feature_dimension = #vhlo.integer_v1<3 : i64>,
//CHECK-SAME: output_spatial_dimensions = #vhlo.tensor_v1<dense<[1, 2]> : tensor<2xi64>>,
//CHECK-SAME: padding = #vhlo.tensor_v1<dense<0> : tensor<2x2xi64>>,
//CHECK-SAME: precision_config = #vhlo.array_v1<[#vhlo<precision_v1 DEFAULT>, #vhlo<precision_v1 DEFAULT>]>,
//CHECK-SAME: rhs_dilation = #vhlo.tensor_v1<dense<1> : tensor<2xi64>>,
//CHECK-SAME: window_reversal = #vhlo.tensor_v1<dense<false> : tensor<2xi1>>,
//CHECK-SAME: window_strides = #vhlo.tensor_v1<dense<1> : tensor<2xi64>>}> : (tensor<1x1x1600x32xf32>, tensor<1x13x1x32xf32>) -> tensor<1x1x1600x32xf32>
//CHECK-NEXT: return %0 : tensor<1x1x1600x32xf32>
//CHECK-NEXT:}
func.func @reduce(%arg0: tensor<1x16x16x320xf32>, %arg3 : tensor<f32>) -> tensor<1x320xf32> {
%0 = "vhlo.reduce_v1" (%arg0, %arg3) <{
dimensions = #vhlo.tensor_v1<dense<[1, 2]> : tensor<2xi64>>
}> ({
^bb0(%arg1: tensor<1xf32>, %arg2: tensor<1xf32>):
%421 = "vhlo.add_v1"(%arg1, %arg2) : (tensor<1xf32>, tensor<1xf32>) -> tensor<1xf32>
"vhlo.return_v1" (%421) : (tensor<1xf32>) -> ()
}) : (tensor<1x16x16x320xf32>, tensor<f32>) -> tensor<1x320xf32>
return %0 : tensor<1x320xf32>
}
//CHECK:func.func private @reduce(%arg0: tensor<1x16x16x320xf32>, %arg1: tensor<f32>) -> tensor<1x320xf32> {
//CHECK-NEXT: %0 = "vhlo.reduce_v1"(%arg0, %arg1) <{dimensions = #vhlo.tensor_v1<dense<[1, 2]> : tensor<2xi64>>}> ({
//CHECK-NEXT: ^bb0(%arg2: tensor<1xf32>, %arg3: tensor<1xf32>):
//CHECK-NEXT: %1 = "vhlo.add_v1"(%arg2, %arg3) : (tensor<1xf32>, tensor<1xf32>) -> tensor<1xf32>
//CHECK-NEXT: "vhlo.return_v1"(%1) : (tensor<1xf32>) -> ()
//CHECK-NEXT: }) : (tensor<1x16x16x320xf32>, tensor<f32>) -> tensor<1x320xf32>
//CHECK-NEXT: return %0 : tensor<1x320xf32>
//CHECK-NEXT:}
func.func @abs(%arg0: tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32> {
%0 = "vhlo.abs_v1" (%arg0) : (tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32>
func.return %0 : tensor<1x1x1x96xf32>
}
//CHECK:func.func private @abs(%arg0: tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32> {
//CHECK-NEXT: %0 = "vhlo.abs_v1"(%arg0) : (tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32>
//CHECK-NEXT: return %0 : tensor<1x1x1x96xf32>
//CHECK-NEXT:}
func.func @and(%arg0: tensor<1x30x1xi32>, %arg1: tensor<1x30x1xi32>) -> tensor<1x30x1xi32> {
%0 = "vhlo.and_v1" (%arg0, %arg1) : (tensor<1x30x1xi32>, tensor<1x30x1xi32>) -> tensor<1x30x1xi32>
func.return %0 : tensor<1x30x1xi32>
}
//CHECK:func.func private @and(%arg0: tensor<1x30x1xi32>, %arg1: tensor<1x30x1xi32>) -> tensor<1x30x1xi32> {
//CHECK-NEXT: %0 = "vhlo.and_v1"(%arg0, %arg1) : (tensor<1x30x1xi32>, tensor<1x30x1xi32>) -> tensor<1x30x1xi32>
//CHECK-NEXT: return %0 : tensor<1x30x1xi32>
//CHECK-NEXT:}
func.func @cos(%arg0: tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32> {
%0 = "vhlo.cosine_v1" (%arg0) : (tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32>
func.return %0 : tensor<1x1x1x96xf32>
}
//CHECK:func.func private @cos(%arg0: tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32> {
//CHECK-NEXT: %0 = "vhlo.cosine_v1"(%arg0) : (tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32>
//CHECK-NEXT: return %0 : tensor<1x1x1x96xf32>
//CHECK-NEXT:}
func.func @exp(%arg0: tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32> {
%0 = "vhlo.exponential_v1" (%arg0) : (tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32>
func.return %0 : tensor<1x1x1x96xf32>
}
//CHECK:func.func private @exp(%arg0: tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32> {
//CHECK-NEXT: %0 = "vhlo.exponential_v1"(%arg0) : (tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32>
//CHECK-NEXT: return %0 : tensor<1x1x1x96xf32>
//CHECK-NEXT:}
func.func @floor(%arg0: tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32> {
%0 = "vhlo.floor_v1" (%arg0) : (tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32>
func.return %0 : tensor<1x1x1x96xf32>
}
//CHECK:func.func private @floor(%arg0: tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32> {
//CHECK-NEXT: %0 = "vhlo.floor_v1"(%arg0) : (tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32>
//CHECK-NEXT: return %0 : tensor<1x1x1x96xf32>
//CHECK-NEXT:}
func.func @log(%arg0: tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32> {
%0 = "vhlo.log_v1" (%arg0) : (tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32>
func.return %0 : tensor<1x1x1x96xf32>
}
//CHECK:func.func private @log(%arg0: tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32> {
//CHECK-NEXT: %0 = "vhlo.log_v1"(%arg0) : (tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32>
//CHECK-NEXT: return %0 : tensor<1x1x1x96xf32>
//CHECK-NEXT:}
func.func @min(%arg0: tensor<1x30x1xi32>, %arg1: tensor<1x30x1xi32>) -> tensor<1x30x1xi32> {
%0 = "vhlo.minimum_v1" (%arg0, %arg1) : (tensor<1x30x1xi32>, tensor<1x30x1xi32>) -> tensor<1x30x1xi32>
func.return %0 : tensor<1x30x1xi32>
}
//CHECK:func.func private @min(%arg0: tensor<1x30x1xi32>, %arg1: tensor<1x30x1xi32>) -> tensor<1x30x1xi32> {
//CHECK-NEXT: %0 = "vhlo.minimum_v1"(%arg0, %arg1) : (tensor<1x30x1xi32>, tensor<1x30x1xi32>) -> tensor<1x30x1xi32>
//CHECK-NEXT: return %0 : tensor<1x30x1xi32>
//CHECK-NEXT:}
func.func @neg(%arg0: tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32> {
%0 = "vhlo.negate_v1" (%arg0) : (tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32>
func.return %0 : tensor<1x1x1x96xf32>
}
//CHECK:func.func private @neg(%arg0: tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32> {
//CHECK-NEXT: %0 = "vhlo.negate_v1"(%arg0) : (tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32>
//CHECK-NEXT: return %0 : tensor<1x1x1x96xf32>
//CHECK-NEXT:}
func.func @or(%arg0: tensor<1x30x1xi32>, %arg1: tensor<1x30x1xi32>) -> tensor<1x30x1xi32> {
%0 = "vhlo.or_v1" (%arg0, %arg1) : (tensor<1x30x1xi32>, tensor<1x30x1xi32>) -> tensor<1x30x1xi32>
func.return %0 : tensor<1x30x1xi32>
}
//CHECK:func.func private @or(%arg0: tensor<1x30x1xi32>, %arg1: tensor<1x30x1xi32>) -> tensor<1x30x1xi32> {
//CHECK-NEXT: %0 = "vhlo.or_v1"(%arg0, %arg1) : (tensor<1x30x1xi32>, tensor<1x30x1xi32>) -> tensor<1x30x1xi32>
//CHECK-NEXT: return %0 : tensor<1x30x1xi32>
//CHECK-NEXT:}
func.func @power(%arg0: tensor<1x30x1xi32>, %arg1: tensor<1x30x1xi32>) -> tensor<1x30x1xi32> {
%0 = "vhlo.power_v1" (%arg0, %arg1) : (tensor<1x30x1xi32>, tensor<1x30x1xi32>) -> tensor<1x30x1xi32>
func.return %0 : tensor<1x30x1xi32>
}
//CHECK:func.func private @power(%arg0: tensor<1x30x1xi32>, %arg1: tensor<1x30x1xi32>) -> tensor<1x30x1xi32> {
//CHECK-NEXT: %0 = "vhlo.power_v1"(%arg0, %arg1) : (tensor<1x30x1xi32>, tensor<1x30x1xi32>) -> tensor<1x30x1xi32>
//CHECK-NEXT: return %0 : tensor<1x30x1xi32>
//CHECK-NEXT:}
func.func @remainder(%arg0: tensor<1x30x1xi32>, %arg1: tensor<1x30x1xi32>) -> tensor<1x30x1xi32> {
%0 = "vhlo.remainder_v1" (%arg0, %arg1) : (tensor<1x30x1xi32>, tensor<1x30x1xi32>) -> tensor<1x30x1xi32>
func.return %0 : tensor<1x30x1xi32>
}
//CHECK:func.func private @remainder(%arg0: tensor<1x30x1xi32>, %arg1: tensor<1x30x1xi32>) -> tensor<1x30x1xi32> {
//CHECK-NEXT: %0 = "vhlo.remainder_v1"(%arg0, %arg1) : (tensor<1x30x1xi32>, tensor<1x30x1xi32>) -> tensor<1x30x1xi32>
//CHECK-NEXT: return %0 : tensor<1x30x1xi32>
//CHECK-NEXT:}
func.func @rsqrt(%arg0: tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32> {
%0 = "vhlo.rsqrt_v1" (%arg0) : (tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32>
func.return %0 : tensor<1x1x1x96xf32>
}
//CHECK:func.func private @rsqrt(%arg0: tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32> {
//CHECK-NEXT: %0 = "vhlo.rsqrt_v1"(%arg0) : (tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32>
//CHECK-NEXT: return %0 : tensor<1x1x1x96xf32>
//CHECK-NEXT:}
func.func @select(%arg0: tensor<1x30x1xi1>, %arg1: tensor<1x30x1xi32>, %arg2: tensor<1x30x1xi32>) -> tensor<1x30x1xi32> {
%0 = "vhlo.select_v1" (%arg0, %arg1, %arg2) : (tensor<1x30x1xi1>, tensor<1x30x1xi32>, tensor<1x30x1xi32>) -> tensor<1x30x1xi32>
func.return %0 : tensor<1x30x1xi32>
}
//CHECK:func.func private @select(%arg0: tensor<1x30x1xi1>, %arg1: tensor<1x30x1xi32>, %arg2: tensor<1x30x1xi32>) -> tensor<1x30x1xi32> {
//CHECK-NEXT: %0 = "vhlo.select_v1"(%arg0, %arg1, %arg2) : (tensor<1x30x1xi1>, tensor<1x30x1xi32>, tensor<1x30x1xi32>) -> tensor<1x30x1xi32>
//CHECK-NEXT: return %0 : tensor<1x30x1xi32>
//CHECK-NEXT:}
func.func @sub(%arg0: tensor<1x30x1xi32>, %arg1: tensor<1x30x1xi32>) -> tensor<1x30x1xi32> {
%0 = "vhlo.subtract_v1" (%arg0, %arg1) : (tensor<1x30x1xi32>, tensor<1x30x1xi32>) -> tensor<1x30x1xi32>
func.return %0 : tensor<1x30x1xi32>
}
//CHECK:func.func private @sub(%arg0: tensor<1x30x1xi32>, %arg1: tensor<1x30x1xi32>) -> tensor<1x30x1xi32> {
//CHECK-NEXT: %0 = "vhlo.subtract_v1"(%arg0, %arg1) : (tensor<1x30x1xi32>, tensor<1x30x1xi32>) -> tensor<1x30x1xi32>
//CHECK-NEXT: return %0 : tensor<1x30x1xi32>
//CHECK-NEXT:}
func.func @tanh(%arg0: tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32> {
%0 = "vhlo.tanh_v1" (%arg0) : (tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32>
func.return %0 : tensor<1x1x1x96xf32>
}
//CHECK:func.func private @tanh(%arg0: tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32> {
//CHECK-NEXT: %0 = "vhlo.tanh_v1"(%arg0) : (tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32>
//CHECK-NEXT: return %0 : tensor<1x1x1x96xf32>
//CHECK-NEXT:}
func.func @iota() -> tensor<3x4xf32> {
%0 = "vhlo.iota_v1" () <{iota_dimension = #vhlo.integer_v1<0 : i64>}> : () -> tensor<3x4xf32>
return %0 : tensor<3x4xf32>
}
//CHECK:func.func private @iota() -> tensor<3x4xf32> {
//CHECK-NEXT: %0 = "vhlo.iota_v1"() <{iota_dimension = #vhlo.integer_v1<0 : i64>}> : () -> tensor<3x4xf32>
//CHECK-NEXT: return %0 : tensor<3x4xf32>
//CHECK-NEXT:}
func.func @compare(%arg0: tensor<i64>, %arg1: tensor<i64>) -> tensor<i1> {
%0 = "vhlo.compare_v1" (%arg0, %arg1) <{compare_type = #vhlo<comparison_type_v1 SIGNED>, comparison_direction = #vhlo<comparison_direction_v1 EQ>}> : (tensor<i64>, tensor<i64>) -> tensor<i1>
func.return %0 : tensor<i1>
}
//CHECK:func.func private @compare(%arg0: tensor<i64>, %arg1: tensor<i64>) -> tensor<i1> {
//CHECK-NEXT: %0 = "vhlo.compare_v1"(%arg0, %arg1) <{compare_type = #vhlo<comparison_type_v1 SIGNED>, comparison_direction = #vhlo<comparison_direction_v1 EQ>}> : (tensor<i64>, tensor<i64>) -> tensor<i1>
//CHECK-NEXT: return %0 : tensor<i1>
//CHECK-NEXT:}
func.func @dynamic_update_slice(%arg0: tensor<4x4xi64>, %arg1: tensor<2x3xi64>, %arg2: tensor<i64>, %arg3: tensor<i64>) -> tensor<4x4xi64> {
%0 = "vhlo.dynamic_update_slice_v1"(%arg0, %arg1, %arg2, %arg3) : (tensor<4x4xi64>, tensor<2x3xi64>, tensor<i64>, tensor<i64>) -> tensor<4x4xi64>
return %0 : tensor<4x4xi64>
}
//CHECK:func.func private @dynamic_update_slice(%arg0: tensor<4x4xi64>, %arg1: tensor<2x3xi64>, %arg2: tensor<i64>, %arg3: tensor<i64>) -> tensor<4x4xi64> {
//CHECK-NEXT: %0 = "vhlo.dynamic_update_slice_v1"(%arg0, %arg1, %arg2, %arg3) : (tensor<4x4xi64>, tensor<2x3xi64>, tensor<i64>, tensor<i64>) -> tensor<4x4xi64>
//CHECK-NEXT: return %0 : tensor<4x4xi64>
//CHECK-NEXT:}
func.func @dyanmic_slice(%arg0: tensor<3x3xi64>, %arg1: tensor<i64>, %arg2: tensor<i64>) -> tensor<3x3xi64> {
%0 = "vhlo.dynamic_slice_v1"(%arg0, %arg1, %arg2) <{
slice_sizes = #vhlo.tensor_v1<dense<[3, 3]> : tensor<2xi64>>
}> : (tensor<3x3xi64>, tensor<i64>, tensor<i64>) -> tensor<3x3xi64>
return %0 : tensor<3x3xi64>
}
//CHECK:func.func private @dyanmic_slice(%arg0: tensor<3x3xi64>, %arg1: tensor<i64>, %arg2: tensor<i64>) -> tensor<3x3xi64> {
//CHECK-NEXT: %0 = "vhlo.dynamic_slice_v1"(%arg0, %arg1, %arg2) <{
//CHECK-SAME: slice_sizes = #vhlo.tensor_v1<dense<3> : tensor<2xi64>>
//CHECK-SAME: }> : (tensor<3x3xi64>, tensor<i64>, tensor<i64>) -> tensor<3x3xi64>
//CHECK-NEXT: return %0 : tensor<3x3xi64>
//CHECK-NEXT:}
func.func @pad(%arg0: tensor<1x160x1xf32>, %arg1: tensor<f32>) -> tensor<1x161x1xf32> {
%0 = "vhlo.pad_v1" (%arg0, %arg1) <{edge_padding_low = #vhlo.tensor_v1<dense<[0, 1, 0]> : tensor<3xi64>>,
edge_padding_high = #vhlo.tensor_v1<dense<0> : tensor<3xi64>>,
interior_padding = #vhlo.tensor_v1<dense<0> : tensor<3xi64>>}> : (tensor<1x160x1xf32>, tensor<f32>) -> tensor<1x161x1xf32>
return %0 : tensor<1x161x1xf32>
}
//CHECK:func.func private @pad(%arg0: tensor<1x160x1xf32>, %arg1: tensor<f32>) -> tensor<1x161x1xf32> {
//CHECK-NEXT: %0 = "vhlo.pad_v1"(%arg0, %arg1) <{edge_padding_high = #vhlo.tensor_v1<dense<0> : tensor<3xi64>>,
//CHECK-SAME: edge_padding_low = #vhlo.tensor_v1<dense<[0, 1, 0]> : tensor<3xi64>>,
//CHECK-SAME: interior_padding = #vhlo.tensor_v1<dense<0> : tensor<3xi64>>}> : (tensor<1x160x1xf32>, tensor<f32>) -> tensor<1x161x1xf32>
//CHECK-NEXT: return %0 : tensor<1x161x1xf32>
//CHECK-NEXT:}
func.func @convert(%arg0: tensor<2xf64>) -> tensor<2xf32> {
%0 = "vhlo.convert_v1" (%arg0) : (tensor<2xf64>) -> tensor<2xf32>
return %0 : tensor<2xf32>
}
//CHECK:func.func private @convert(%arg0: tensor<2xf64>) -> tensor<2xf32> {
//CHECK-NEXT: %0 = "vhlo.convert_v1"(%arg0) : (tensor<2xf64>) -> tensor<2xf32>
//CHECK-NEXT: return %0 : tensor<2xf32>
//CHECK-NEXT:}
func.func @reduce_window(%arg0: tensor<1x160x1xf32>, %arg1: tensor<f32>) -> tensor<1x160x1xf32> {
%0 = "vhlo.reduce_window_v1"(%arg0, %arg1) <{base_dilations = #vhlo.tensor_v1<dense<1> : tensor<3xi64>>,
padding = #vhlo.tensor_v1<dense<[[0, 0], [159, 0], [0, 0]]> : tensor<3x2xi64>>,
window_dilations = #vhlo.tensor_v1<dense<1> : tensor<3xi64>>,
window_dimensions = #vhlo.tensor_v1<dense<[1, 160, 1]> : tensor<3xi64>>,
window_strides = #vhlo.tensor_v1<dense<1> : tensor<3xi64>>}> ({
^bb0(%arg23: tensor<f32>, %arg24: tensor<f32>):
%1112 = "vhlo.add_v1" (%arg23, %arg24) : (tensor<f32>, tensor<f32>) -> tensor<f32>
"vhlo.return_v1" (%1112) : (tensor<f32>) -> ()
}) : (tensor<1x160x1xf32>, tensor<f32>) -> tensor<1x160x1xf32>
return %0 : tensor<1x160x1xf32>
}
//CHECK:func.func private @reduce_window(%arg0: tensor<1x160x1xf32>, %arg1: tensor<f32>) -> tensor<1x160x1xf32> {
//CHECK-NEXT: %0 = "vhlo.reduce_window_v1"(%arg0, %arg1) <{base_dilations = #vhlo.tensor_v1<dense<1> : tensor<3xi64>>,
//CHECK-SAME{LITERAL}: padding = #vhlo.tensor_v1<dense<[[0, 0], [159, 0], [0, 0]]> : tensor<3x2xi64>>,
//CHECK-SAME: window_dilations = #vhlo.tensor_v1<dense<1> : tensor<3xi64>>,
//CHECK-SAME: window_dimensions = #vhlo.tensor_v1<dense<[1, 160, 1]> : tensor<3xi64>>,
//CHECK-SAME: window_strides = #vhlo.tensor_v1<dense<1> : tensor<3xi64>>}> ({
//CHECK-NEXT: ^bb0(%arg2: tensor<f32>, %arg3: tensor<f32>):
//CHECK-NEXT: %1 = "vhlo.add_v1"(%arg2, %arg3) : (tensor<f32>, tensor<f32>) -> tensor<f32>
//CHECK-NEXT: "vhlo.return_v1"(%1) : (tensor<f32>) -> ()
//CHECK-NEXT: }) : (tensor<1x160x1xf32>, tensor<f32>) -> tensor<1x160x1xf32>
//CHECK-NEXT: return %0 : tensor<1x160x1xf32>
//CHECK-NEXT:}
func.func @dot_general(%arg0: tensor<1x1x167xf32>, %arg1: tensor<167x64xf32>) -> tensor<1x1x64xf32> {
%0 = "vhlo.dot_general_v1"(%arg0, %arg1) <{
lhs_batching_dimensions = #vhlo.tensor_v1<dense<0> : tensor<1xi64>>,
lhs_contracting_dimensions = #vhlo.tensor_v1<dense<2> : tensor<1xi64>>,
rhs_batching_dimensions = #vhlo.tensor_v1<dense<0> : tensor<1xi64>>,
rhs_contracting_dimensions = #vhlo.tensor_v1<dense<0> : tensor<1xi64>>,
precision_config = #vhlo.array_v1<[#vhlo<precision_v1 DEFAULT>, #vhlo<precision_v1 DEFAULT>]>}> : (tensor<1x1x167xf32>, tensor<167x64xf32>) -> tensor<1x1x64xf32>
return %0 : tensor<1x1x64xf32>
}
//CHECK:func.func private @dot_general(%arg0: tensor<1x1x167xf32>, %arg1: tensor<167x64xf32>) -> tensor<1x1x64xf32> {
//CHECK-NEXT: %0 = "vhlo.dot_general_v1"(%arg0, %arg1) <{
//CHECK-SAME: lhs_batching_dimensions = #vhlo.tensor_v1<dense<0> : tensor<1xi64>>,
//CHECK-SAME: lhs_contracting_dimensions = #vhlo.tensor_v1<dense<2> : tensor<1xi64>>,
//CHECK-SAME: precision_config = #vhlo.array_v1<[#vhlo<precision_v1 DEFAULT>, #vhlo<precision_v1 DEFAULT>]>,
//CHECK-SAME: rhs_batching_dimensions = #vhlo.tensor_v1<dense<0> : tensor<1xi64>>,
//CHECK-SAME: rhs_contracting_dimensions = #vhlo.tensor_v1<dense<0> : tensor<1xi64>>}> : (tensor<1x1x167xf32>, tensor<167x64xf32>) -> tensor<1x1x64xf32>
//CHECK-NEXT: return %0 : tensor<1x1x64xf32>
//CHECK-NEXT:}
func.func @sort(%arg0: tensor<448xf32>, %arg1: tensor<448xi32>) -> tensor<448xf32> {
%0, %1 = "vhlo.sort_v1"(%arg0, %arg1) <{dimension = #vhlo.integer_v1<0 : i64>, is_stable = #vhlo.bool_v1<true>}> ({
^bb0(%arg23: tensor<f32>, %arg24: tensor<f32>, %arg25: tensor<i32>, %arg26: tensor<i32>):
%1112 = "vhlo.compare_v1"(%arg23, %arg24) <{compare_type = #vhlo<comparison_type_v1 TOTALORDER>, comparison_direction = #vhlo<comparison_direction_v1 GT>}> : (tensor<f32>, tensor<f32>) -> tensor<i1>
"vhlo.return_v1"(%1112) : (tensor<i1>) -> ()
}) : (tensor<448xf32>, tensor<448xi32>) -> (tensor<448xf32>, tensor<448xi32>)
return %0 : tensor<448xf32>
}
//CHECK:func.func private @sort(%arg0: tensor<448xf32>, %arg1: tensor<448xi32>) -> tensor<448xf32> {
//CHECK-NEXT: %0:2 = "vhlo.sort_v1"(%arg0, %arg1) <{dimension = #vhlo.integer_v1<0 : i64>, is_stable = #vhlo.bool_v1<true>}> ({
//CHECK-NEXT: ^bb0(%arg2: tensor<f32>, %arg3: tensor<f32>, %arg4: tensor<i32>, %arg5: tensor<i32>):
//CHECK-NEXT: %1 = "vhlo.compare_v1"(%arg2, %arg3) <{compare_type = #vhlo<comparison_type_v1 TOTALORDER>, comparison_direction = #vhlo<comparison_direction_v1 GT>}> : (tensor<f32>, tensor<f32>) -> tensor<i1>
//CHECK-NEXT: "vhlo.return_v1"(%1) : (tensor<i1>) -> ()
//CHECK-NEXT: }) : (tensor<448xf32>, tensor<448xi32>) -> (tensor<448xf32>, tensor<448xi32>)
//CHECK-NEXT: return %0#0 : tensor<448xf32>
//CHECK-NEXT:}
func.func @while(%init_i: tensor<i64>, %init_sum: tensor<i64>) -> tensor<i64>{
%0, %1 = "vhlo.while_v1"(%init_i, %init_sum) ({
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%cond = "vhlo.compare_v1"(%arg0, %arg1) {
comparison_direction = #vhlo<comparison_direction_v1 LT>,
compare_type = #vhlo<comparison_type_v1 NOTYPE>
} : (tensor<i64>, tensor<i64>) -> tensor<i1>
"vhlo.return_v1"(%cond) : (tensor<i1>) -> ()
}, {
^bb0(%arg0: tensor<i64>, %arg1: tensor<i64>):
%new_sum = "vhlo.add_v1"(%arg1, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
%new_i = "vhlo.add_v1" (%arg0, %arg1) : (tensor<i64>, tensor<i64>) -> tensor<i64>
"vhlo.return_v1"(%new_i, %new_sum) : (tensor<i64>, tensor<i64>) ->()
}) : (tensor<i64>, tensor<i64>) -> (tensor<i64>, tensor<i64>)
return %0 : tensor<i64>
}
//CHECK:func.func private @while(%arg0: tensor<i64>, %arg1: tensor<i64>) -> tensor<i64> {
//CHECK-NEXT: %0:2 = "vhlo.while_v1"(%arg0, %arg1) ({
//CHECK-NEXT: ^bb0(%arg2: tensor<i64>, %arg3: tensor<i64>):
//CHECK-NEXT: %1 = "vhlo.compare_v1"(%arg2, %arg3) <{compare_type = #vhlo<comparison_type_v1 NOTYPE>, comparison_direction = #vhlo<comparison_direction_v1 LT>}> : (tensor<i64>, tensor<i64>) -> tensor<i1>
//CHECK-NEXT: "vhlo.return_v1"(%1) : (tensor<i1>) -> ()
//CHECK-NEXT: }, {
//CHECK-NEXT: ^bb0(%arg2: tensor<i64>, %arg3: tensor<i64>):
//CHECK-NEXT: %1 = "vhlo.add_v1"(%arg3, %arg3) : (tensor<i64>, tensor<i64>) -> tensor<i64>
//CHECK-NEXT: %2 = "vhlo.add_v1"(%arg2, %arg3) : (tensor<i64>, tensor<i64>) -> tensor<i64>
//CHECK-NEXT: "vhlo.return_v1"(%2, %1) : (tensor<i64>, tensor<i64>) -> ()
//CHECK-NEXT: }) : (tensor<i64>, tensor<i64>) -> (tensor<i64>, tensor<i64>)
//CHECK-NEXT: return %0#0 : tensor<i64>
//CHECK-NEXT:}
func.func @gather(%operand: tensor<3x4x2xi32>, %start_indices: tensor<2x3x2xi64>) -> tensor<2x3x2x2xi32>{
%result = "vhlo.gather_v1"(%operand, %start_indices) <{
offset_dims = #vhlo.tensor_v1<dense<[2, 3]> : tensor<2xi64>>,
collapsed_slice_dims = #vhlo.tensor_v1<dense<0> : tensor<1xi64>>,
start_index_map = #vhlo.tensor_v1<dense<[1, 0]> : tensor<2xi64>>,
index_vector_dim = #vhlo.integer_v1<2 : i64>,
slice_sizes = #vhlo.tensor_v1<dense<[1, 2, 2]> : tensor<3xi64>>,
indices_are_sorted = #vhlo.bool_v1<false>
}> : (tensor<3x4x2xi32>, tensor<2x3x2xi64>) -> tensor<2x3x2x2xi32>
return %result : tensor<2x3x2x2xi32>
}
// CHECK: func.func private @gather(%arg0: tensor<3x4x2xi32>, %arg1: tensor<2x3x2xi64>) -> tensor<2x3x2x2xi32> {
// CHECK-NEXT: %0 = "vhlo.gather_v1"(%arg0, %arg1) <{collapsed_slice_dims = #vhlo.tensor_v1<dense<0> : tensor<1xi64>>, index_vector_dim = #vhlo.integer_v1<2 : i64>, indices_are_sorted = #vhlo.bool_v1<false>, offset_dims = #vhlo.tensor_v1<dense<[2, 3]> : tensor<2xi64>>, slice_sizes = #vhlo.tensor_v1<dense<[1, 2, 2]> : tensor<3xi64>>, start_index_map = #vhlo.tensor_v1<dense<[1, 0]> : tensor<2xi64>>}> : (tensor<3x4x2xi32>, tensor<2x3x2xi64>) -> tensor<2x3x2x2xi32>
// CHECK-NEXT: return %0 : tensor<2x3x2x2xi32>
// CHECK-NEXT:}
func.func @transpose(%arg0: tensor<2x3x2xi32>) -> tensor<2x3x2xi32> {
%0 = "vhlo.transpose_v1"(%arg0) <{permutation = #vhlo.tensor_v1<dense<[2, 1, 0]> : tensor<3xi64>>}> : (tensor<2x3x2xi32>) -> tensor<2x3x2xi32>
return %0 : tensor<2x3x2xi32>
}
// CHECK:func.func private @transpose(%arg0: tensor<2x3x2xi32>) -> tensor<2x3x2xi32> {
// CHECK-NEXT: %0 = "vhlo.transpose_v1"(%arg0) <{permutation = #vhlo.tensor_v1<dense<[2, 1, 0]> : tensor<3xi64>>}> : (tensor<2x3x2xi32>) -> tensor<2x3x2xi32>
// CHECK-NEXT: return %0 : tensor<2x3x2xi32>
// CHECK-NEXT:}
func.func @rng_bit_generator(%arg0: tensor<2xui64>) -> (tensor<2xui64>, tensor<10x12xui32>) {
%output_state, %output = "vhlo.rng_bit_generator_v1"(%arg0) <{rng_algorithm = #vhlo<rng_algorithm_v1 DEFAULT>}> : (tensor<2xui64>) -> (tensor<2xui64>, tensor<10x12xui32>)
func.return %output_state, %output : tensor<2xui64>, tensor<10x12xui32>
}
// CHECK:func.func private @rng_bit_generator(%arg0: tensor<2xui64>) -> (tensor<2xui64>, tensor<10x12xui32>) {
// CHECK-NEXT: %output_state, %output = "vhlo.rng_bit_generator_v1"(%arg0) <{rng_algorithm = #vhlo<rng_algorithm_v1 DEFAULT>}> : (tensor<2xui64>) -> (tensor<2xui64>, tensor<10x12xui32>)
// CHECK-NEXT: return %output_state, %output : tensor<2xui64>, tensor<10x12xui32>
// CHECK-NEXT:}
func.func @scatter(%input_tensor: tensor<200x100x300xf32>,
%scatter_indices: tensor<10x2xi32>, %updates: tensor<10x300xf32>) ->
tensor<200x100x300xf32> {
%0 = "vhlo.scatter_v1" (%input_tensor, %scatter_indices, %updates) <{
update_window_dims = #vhlo.tensor_v1<dense<1> : tensor<1xi64>>,
inserted_window_dims = #vhlo.tensor_v1<dense<[0, 1]> : tensor<2xi64>>,
scatter_dims_to_operand_dims = #vhlo.tensor_v1<dense<[0, 1]> : tensor<2xi64>>,
index_vector_dim = #vhlo.integer_v1<1 : i64>,
indices_are_sorted = #vhlo.bool_v1<true>,
unique_indices = #vhlo.bool_v1<true>}> ({
^bb0(%lhs: tensor<f32>, %rhs: tensor<f32>):
"vhlo.return_v1"(%lhs) : (tensor<f32>) -> ()
}): (tensor<200x100x300xf32>, tensor<10x2xi32>, tensor<10x300xf32>) ->
tensor<200x100x300xf32>
func.return %0 : tensor<200x100x300xf32>
}
// CHECK-LABEL: func.func private @scatter(%arg0: tensor<200x100x300xf32>, %arg1: tensor<10x2xi32>, %arg2: tensor<10x300xf32>) -> tensor<200x100x300xf32> {
// CHECK-NEXT: %0 = "vhlo.scatter_v1"(%arg0, %arg1, %arg2) <{index_vector_dim = #vhlo.integer_v1<1 : i64>, indices_are_sorted = #vhlo.bool_v1<true>, inserted_window_dims = #vhlo.tensor_v1<dense<[0, 1]> : tensor<2xi64>>, scatter_dims_to_operand_dims = #vhlo.tensor_v1<dense<[0, 1]> : tensor<2xi64>>, unique_indices = #vhlo.bool_v1<true>, update_window_dims = #vhlo.tensor_v1<dense<1> : tensor<1xi64>>}> ({
// CHECK-NEXT: ^bb0(%arg3: tensor<f32>, %arg4: tensor<f32>):
// CHECK-NEXT: "vhlo.return_v1"(%arg3) : (tensor<f32>) -> ()
// CHECK-NEXT: }) : (tensor<200x100x300xf32>, tensor<10x2xi32>, tensor<10x300xf32>) -> tensor<200x100x300xf32>
// CHECK-NEXT: return %0 : tensor<200x100x300xf32>
// CHECK-NEXT: }
// CHECK-LABEL: @shift_left
func.func @shift_left(%arg0: tensor<2x2xi32>, %arg1: tensor<2x2xi32>) -> tensor<2x2xi32> {
%0 = "vhlo.shift_left_v1"(%arg0, %arg1) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
func.return %0 : tensor<2x2xi32>
}
// CHECK: "vhlo.shift_left_v1"(%arg0, %arg1) : (tensor<2x2xi32>, tensor<2x2xi32>) -> tensor<2x2xi32>
// CHECK-LABEL: @cbrt
func.func @cbrt(%arg0: tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32> {
%0 = "vhlo.cbrt_v1" (%arg0) : (tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32>
func.return %0 : tensor<1x1x1x96xf32>
}
//CHECK: %0 = "vhlo.cbrt_v1"(%arg0) : (tensor<1x1x1x96xf32>) -> tensor<1x1x1x96xf32>
//CHECK: return %0 : tensor<1x1x1x96xf32>
@@ -0,0 +1,28 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer --emit-stablehlo-ops=true %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir --disable-vhlo-to-stablehlo=true - -o - | FileCheck %s
// test stablehlo roundtrip
module attributes {tfl.metadata = {"keep_stablehlo_constant" = "true"}} {
func.func @main () -> tensor<1x1x1x96xf32> {
%0 = "vhlo.constant_v1"() <{value = #vhlo.tensor_v1<dense<0.000000e+00> : tensor<f32>>}> : () -> tensor<1x1x1x96xf32>
func.return %0 : tensor<1x1x1x96xf32>
}
}
//CHECK: func.func @main() -> tensor<1x1x1x96xf32> attributes {tf.entry_function = {outputs = "vhlo.constant_v1"}} {
//CHECK-NEXT: %0 = "vhlo.constant_v1"() <{value = #vhlo.tensor_v1<dense<0.000000e+00> : tensor<1x1x1x96xf32>>}> : () -> tensor<1x1x1x96xf32>
//CHECK-NEXT: return %0 : tensor<1x1x1x96xf32>
//CHECK-NEXT: }
@@ -0,0 +1,77 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer --emit-stablehlo-ops=true %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir --disable-vhlo-to-stablehlo=true - -o - | FileCheck %s
// test stablehlo roundtrip
//test TF ops wrapped in stablehlo custom_call
// Identity function to make the exporter happy
func.func @main(%arg0: tensor<4xi8>) -> tensor<4xi8> {
func.return %arg0 : tensor<4xi8>
}
//CHECK:func.func @main(%arg0: tensor<4xi8>) -> tensor<4xi8> attributes {tf.entry_function = {inputs = "arg0", outputs = "arg0"}} {
//CHECK: return %arg0 : tensor<4xi8>
//CHECK:}
func.func @custom_tf_op(%arg0: tensor<1x320x1x1xf32>, %arg1: tensor<2xi32>) -> tensor<1x1600x1x1xf32> {
%0 = "vhlo.custom_call_v1" (%arg0, %arg1) <{api_version = #vhlo<api_version_v1 API_VERSION_ORIGINAL>,
backend_config = #vhlo.string_v1<"">,
call_target_name = #vhlo.string_v1<"tf.ResizeBilinear">,
called_computations = #vhlo.array_v1<[]>,
has_side_effect = #vhlo.bool_v1<false>,
operand_layouts = #vhlo.array_v1<[]>,
output_operand_aliases = #vhlo.array_v1<[]>,
result_layouts = #vhlo.array_v1<[]>}> {align_corners = #vhlo.bool_v1<true>, device = #vhlo.string_v1<"">, half_pixel_centers = #vhlo.bool_v1<false>} : (tensor<1x320x1x1xf32>, tensor<2xi32>) -> tensor<1x1600x1x1xf32>
return %0 : tensor<1x1600x1x1xf32>
}
//CHECK:func.func private @custom_tf_op(%arg0: tensor<1x320x1x1xf32>, %arg1: tensor<2xi32>) -> tensor<1x1600x1x1xf32> {
//CHECK: %0 = "vhlo.custom_call_v1"(%arg0, %arg1) <{
//CHECK-SAME: api_version = #vhlo<api_version_v1 API_VERSION_ORIGINAL>,
//CHECK-SAME: backend_config = #vhlo.string_v1<"">,
//CHECK-SAME: call_target_name = #vhlo.string_v1<"tf.ResizeBilinear">,
//CHECK-SAME: called_computations = #vhlo.array_v1<[]>,
//CHECK-SAME: has_side_effect = #vhlo.bool_v1<false>,
//CHECK-SAME: operand_layouts = #vhlo.array_v1<[]>,
//CHECK-SAME: output_operand_aliases = #vhlo.array_v1<[]>,
//CHECK-SAME: result_layouts = #vhlo.array_v1<[]>}> {align_corners = #vhlo.bool_v1<true>, device = #vhlo.string_v1<"">, half_pixel_centers = #vhlo.bool_v1<false>} : (tensor<1x320x1x1xf32>, tensor<2xi32>) -> tensor<1x1600x1x1xf32>
//CHECK-NEXT: return %0 : tensor<1x1600x1x1xf32>
//CHECK-NEXT:}
func.func @custom_op_with_backend(%arg0: tensor<1x320x1x1xf32>, %arg1: tensor<2xi32>) -> tensor<1x1600x1x1xf32> {
%0 = "vhlo.custom_call_v1" (%arg0, %arg1) <{api_version = #vhlo<api_version_v1 API_VERSION_ORIGINAL>,
backend_config = #vhlo.string_v1<"">,
call_target_name = #vhlo.string_v1<"custom_backend">,
called_computations = #vhlo.array_v1<[]>,
has_side_effect = #vhlo.bool_v1<true>,
operand_layouts = #vhlo.array_v1<[]>,
output_operand_aliases = #vhlo.array_v1<[]>,
result_layouts = #vhlo.array_v1<[]>}> : (tensor<1x320x1x1xf32>, tensor<2xi32>) -> tensor<1x1600x1x1xf32>
return %0 : tensor<1x1600x1x1xf32>
}
//CHECK:func.func private @custom_op_with_backend(%arg0: tensor<1x320x1x1xf32>, %arg1: tensor<2xi32>) -> tensor<1x1600x1x1xf32> {
//CHECK: "vhlo.custom_call_v1"(%arg0, %arg1) <{
//CHECK-SAME: api_version = #vhlo<api_version_v1 API_VERSION_ORIGINAL>,
//CHECK-SAME: backend_config = #vhlo.string_v1<"">,
//CHECK-SAME: call_target_name = #vhlo.string_v1<"custom_backend">,
//CHECK-SAME: called_computations = #vhlo.array_v1<[]>,
//CHECK-SAME: has_side_effect = #vhlo.bool_v1<true>,
//CHECK-SAME: operand_layouts = #vhlo.array_v1<[]>,
//CHECK-SAME: output_operand_aliases = #vhlo.array_v1<[]>,
//CHECK-SAME: result_layouts = #vhlo.array_v1<[]>}> : (tensor<1x320x1x1xf32>, tensor<2xi32>) -> tensor<1x1600x1x1xf32>
//CHECK-NEXT: return %0 : tensor<1x1600x1x1xf32>
//CHECK-NEXT:}
@@ -0,0 +1,51 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: flatbuffer_translate -mlir-to-tflite-flatbuffer %s -o - | flatbuffer_translate --tflite-flatbuffer-to-mlir - -o - | FileCheck %s
// Check to see if nested regions in while loops are preserved
// CHECK: %{{.*}}:2 = "tfl.while"(%{{.*}}, %{{.*}}) ({
// CHECK: ^bb0(%{{.*}}: tensor<*xi32>, %{{.*}}: tensor<*xf32>):
// CHECK: "tfl.yield"(%{{.*}}) : (tensor<i1>) -> ()
// CHECK: }, {
// CHECK: ^bb0(%{{.*}}: tensor<*xi32>, %{{.*}}: tensor<*xf32>):
// CHECK: "tfl.yield"(%{{.*}}, %{{.*}}) : (tensor<*xi32>, tensor<*xf32>) -> ()
// CHECK: }) : (tensor<i32>, tensor<1xf32>) -> (tensor<i32>, tensor<1xf32>)
func.func @main(%arg0: tensor<i32>, %arg1: tensor<1xf32>) -> tensor<1xf32> {
// While %arg0 is greater than zero, element wise add %arg1 with itself.
%0:2 = "tfl.while"(%arg0, %arg1) ({
^bb0(%arg2: tensor<*xi32>, %arg3: tensor<*xf32>):
%1 = func.call @cond(%arg2, %arg3) : (tensor<*xi32>, tensor<*xf32>) -> tensor<i1>
"tfl.yield"(%1) : (tensor<i1>) -> ()
}, {
^bb0(%arg2: tensor<*xi32>, %arg3: tensor<*xf32>):
%1:2 = func.call @body(%arg2, %arg3) : (tensor<*xi32>, tensor<*xf32>) -> (tensor<*xi32>, tensor<*xf32>)
"tfl.yield"(%1#0, %1#1) : (tensor<*xi32>, tensor<*xf32>) -> ()
}) {is_stateless = false} : (tensor<i32>, tensor<1xf32>) -> (tensor<i32>, tensor<1xf32>)
func.return %0#1 : tensor<1xf32>
}
func.func @cond(%arg0: tensor<*xi32>, %arg1: tensor<*xf32>) -> tensor<i1> {
%cst = arith.constant dense<0> : tensor<i32> loc("Const")
%0 = "tfl.greater"(%arg0, %cst) : (tensor<*xi32>, tensor<i32>) -> tensor<i1>
func.return %0 : tensor<i1>
}
func.func @body(%arg0: tensor<*xi32>, %arg1: tensor<*xf32>) -> (tensor<*xi32>, tensor<*xf32>) {
%cst = arith.constant dense<1> : tensor<i32> loc("Const")
%0 = "tfl.sub"(%arg0, %cst) {fused_activation_function = "NONE"} : (tensor<*xi32>, tensor<i32>) -> tensor<*xi32>
%1 = tfl.add %arg1, %arg1 {fused_activation_function = "NONE"} : tensor<*xf32>
func.return %0, %1 : tensor<*xi32>, tensor<*xf32>
}
@@ -0,0 +1,593 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: litert-opt %s -tfl-fuse-qdq | FileCheck %s
// CHECK-LABEL: QuantizeConvDRQ
func.func private @XlaCallModule_quant.fake_quant.impl_0(%arg0: tensor<1x4x4x3xf32>) -> tensor<1x4x4x3xf32>
func.func @QuantizeConvDRQ(%arg0: tensor<1x4x4x3xf32>) -> (tensor<1x4x4x1xf32>) {
// CHECK: %cst = arith.constant dense<0.000000e+00> : tensor<1xf32>
%cst = arith.constant dense<0.000000e+00> : tensor<1xf32>
%cst_0 = arith.constant dense<[[[[1.76285899, -0.257785767, 0.20429258], [1.16310906, 0.23124367, 0.529797196]], [[0.348971426, -0.319283515, -0.772461354], [0.316666812, 1.88180697, -1.78054631]]]]> : tensor<1x2x2x3xf32>
%0 = stablehlo.composite "quant.fake_quant" %arg0 {composite_attributes = {dtype = "i8", narrow_range = false, quantization_dimension = 0 : i32, scale = dense<> : tensor<0xf64>, zero_point = dense<> : tensor<0xi64>}, decomposition = @XlaCallModule_quant.fake_quant.impl_0} : (tensor<1x4x4x3xf32>) -> tensor<1x4x4x3xf32>
// CHECK{LITERAL}: %0 = "tfl.pseudo_qconst"() <{qtype = tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>, value = dense<[[[[119, -17, 14], [78, 16, 36]], [[24, -22, -52], [21, 127, -120]]]]> : tensor<1x2x2x3xi8>}> : () -> tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>
%1 = "tfl.quantize"(%cst_0) <{qtype = tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>}> : (tensor<1x2x2x3xf32>) -> tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>
%2 = "tfl.dequantize"(%1) : (tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>) -> tensor<1x2x2x3xf32>
// CHECK: %1 = "tfl.conv_2d"(%arg0, %0, %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<1x4x4x3xf32>, tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>, tensor<1xf32>) -> tensor<1x4x4x1xf32>
%3 = "tfl.conv_2d"(%0, %2, %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<1x4x4x3xf32>, tensor<1x2x2x3xf32>, tensor<1xf32>) -> tensor<1x4x4x1xf32>
// CHECK: return %1 : tensor<1x4x4x1xf32>
return %3 : tensor<1x4x4x1xf32>
}
// -----
// CHECK-LABEL: QuantizeConvDrqWithPad
func.func private @XlaCallModule_quant.fake_quant.impl_1(%arg0: tensor<1x4x4x3xf32>) -> tensor<1x4x4x3xf32>
func.func @QuantizeConvDrqWithPad(%arg0: tensor<1x4x4x3xf32>) -> (tensor<1x6x6x1xf32>) {
// CHECK: %cst_0 = arith.constant dense<0.000000e+00> : tensor<1xf32>
%cst = arith.constant dense<0.000000e+00> : tensor<1xf32>
%cst_0 = arith.constant dense<[[[[1.76285899, -0.257785767, 0.20429258], [1.16310906, 0.23124367, 0.529797196]], [[0.348971426, -0.319283515, -0.772461354], [0.316666812, 1.88180697, -1.78054631]]]]> : tensor<1x2x2x3xf32>
%0 = stablehlo.composite "quant.fake_quant" %arg0 {composite_attributes = {dtype = "i8", narrow_range = false, quantization_dimension = 0 : i32, scale = dense<> : tensor<0xf64>, zero_point = dense<> : tensor<0xi64>}, decomposition = @XlaCallModule_quant.fake_quant.impl_1} : (tensor<1x4x4x3xf32>) -> tensor<1x4x4x3xf32>
// CHECK-LITERAL: %cst = arith.constant dense<[[0, 0], [1, 1], [1, 1], [0, 0]]> : tensor<4x2xi32>
%paddings = arith.constant dense<[[0, 0], [1, 1], [1, 1], [0, 0]]> : tensor<4x2xi32>
// CHECK: %0 = "tfl.pad"(%arg0, %cst) : (tensor<1x4x4x3xf32>, tensor<4x2xi32>) -> tensor<1x6x6x3xf32>
%1 = "tfl.pad"(%0, %paddings) : (tensor<1x4x4x3xf32>, tensor<4x2xi32>) -> tensor<1x6x6x3xf32>
// CHECK{LITERAL}: %1 = "tfl.pseudo_qconst"() <{qtype = tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>, value = dense<[[[[119, -17, 14], [78, 16, 36]], [[24, -22, -52], [21, 127, -120]]]]> : tensor<1x2x2x3xi8>}> : () -> tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>
%2 = "tfl.quantize"(%cst_0) <{qtype = tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>}> : (tensor<1x2x2x3xf32>) -> tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>
%3 = "tfl.dequantize"(%2) : (tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>) -> tensor<1x2x2x3xf32>
// CHECK: %2 = "tfl.conv_2d"(%0, %1, %cst_0) <{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<1x6x6x3xf32>, tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>, tensor<1xf32>) -> tensor<1x6x6x1xf32>
%4 = "tfl.conv_2d"(%1, %3, %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<1x6x6x3xf32>, tensor<1x2x2x3xf32>, tensor<1xf32>) -> tensor<1x6x6x1xf32>
// CHECK: return %2 : tensor<1x6x6x1xf32>
return %4 : tensor<1x6x6x1xf32>
}
// -----
// CHECK-LABEL: QuantizeConvWithBiasDRQ
func.func @QuantizeConvWithBiasDRQ(%arg0: tensor<1x4x4x3xf32>) -> (tensor<1x4x4x1xf32>) {
// CHECK: %cst = arith.constant dense<1.14751196> : tensor<1xf32>
%cst = arith.constant dense<1.14751196> : tensor<1xf32>
%cst_0 = arith.constant dense<[[[[1.76285899, -0.257785767, 0.20429258], [1.16310906, 0.23124367, 0.529797196]], [[0.348971426, -0.319283515, -0.772461354], [0.316666812, 1.88180697, -1.78054631]]]]> : tensor<1x2x2x3xf32>
%0 = stablehlo.composite "quant.fake_quant" %arg0 {composite_attributes = {dtype = "i8", narrow_range = false, quantization_dimension = 0 : i32, scale = dense<> : tensor<0xf64>, zero_point = dense<> : tensor<0xi64>}, decomposition = @XlaCallModule_quant.fake_quant.impl_0} : (tensor<1x4x4x3xf32>) -> tensor<1x4x4x3xf32>
// CHECK{LITERAL}: %0 = "tfl.pseudo_qconst"() <{qtype = tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>, value = dense<[[[[119, -17, 14], [78, 16, 36]], [[24, -22, -52], [21, 127, -120]]]]> : tensor<1x2x2x3xi8>}> : () -> tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>
%1 = "tfl.quantize"(%cst_0) <{qtype = tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>}> : (tensor<1x2x2x3xf32>) -> tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>
%2 = "tfl.dequantize"(%1) : (tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>) -> tensor<1x2x2x3xf32>
// CHECK: %1 = "tfl.conv_2d"(%arg0, %0, %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<1x4x4x3xf32>, tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>, tensor<1xf32>) -> tensor<1x4x4x1xf32>
%3 = "tfl.conv_2d"(%0, %2, %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<1x4x4x3xf32>, tensor<1x2x2x3xf32>, tensor<1xf32>) -> tensor<1x4x4x1xf32>
// CHECK: return %1 : tensor<1x4x4x1xf32>
return %3 : tensor<1x4x4x1xf32>
}
// -----
// CHECK-LABEL: QuantizeConvWithBiasAndReluDRQ
func.func @QuantizeConvWithBiasAndReluDRQ(%arg0: tensor<1x4x4x3xf32>) -> (tensor<1x4x4x1xf32>) {
// CHECK: %cst = arith.constant dense<1.14751196> : tensor<1xf32>
%cst = arith.constant dense<1.14751196> : tensor<1xf32>
%cst_0 = arith.constant dense<[[[[1.76285899, -0.257785767, 0.20429258], [1.16310906, 0.23124367, 0.529797196]], [[0.348971426, -0.319283515, -0.772461354], [0.316666812, 1.88180697, -1.78054631]]]]> : tensor<1x2x2x3xf32>
%0 = stablehlo.composite "quant.fake_quant" %arg0 {composite_attributes = {dtype = "i8", narrow_range = false, quantization_dimension = 0 : i32, scale = dense<> : tensor<0xf64>, zero_point = dense<> : tensor<0xi64>}, decomposition = @XlaCallModule_quant.fake_quant.impl_0} : (tensor<1x4x4x3xf32>) -> tensor<1x4x4x3xf32>
// CHECK{LITERAL}: %0 = "tfl.pseudo_qconst"() <{qtype = tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>, value = dense<[[[[119, -17, 14], [78, 16, 36]], [[24, -22, -52], [21, 127, -120]]]]> : tensor<1x2x2x3xi8>}> : () -> tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>
%1 = "tfl.quantize"(%cst_0) <{qtype = tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>}> : (tensor<1x2x2x3xf32>) -> tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>
%2 = "tfl.dequantize"(%1) : (tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>) -> tensor<1x2x2x3xf32>
// CHECK: %1 = "tfl.conv_2d"(%arg0, %0, %cst) <{dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "RELU", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32}> : (tensor<1x4x4x3xf32>, tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>, tensor<1xf32>) -> tensor<1x4x4x1xf32>
%3 = "tfl.conv_2d"(%0, %2, %cst) <{dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "RELU", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32}> : (tensor<1x4x4x3xf32>, tensor<1x2x2x3xf32>, tensor<1xf32>) -> tensor<1x4x4x1xf32>
// CHECK: return %1 : tensor<1x4x4x1xf32>
return %3 : tensor<1x4x4x1xf32>
}
// -----
// CHECK-LABEL: QuantizeConvWithBiasAndReluWeightOnly
func.func @QuantizeConvWithBiasAndReluWeightOnly(%arg0: tensor<1x4x4x3xf32>) -> (tensor<1x4x4x1xf32>) {
// CHECK: %cst = arith.constant dense<1.14751196> : tensor<1xf32>
%cst = arith.constant dense<1.14751196> : tensor<1xf32>
%cst_0 = arith.constant dense<[[[[1.76285899, -0.257785767, 0.20429258], [1.16310906, 0.23124367, 0.529797196]], [[0.348971426, -0.319283515, -0.772461354], [0.316666812, 1.88180697, -1.78054631]]]]> : tensor<1x2x2x3xf32>
// CHECK{LITERAL}: %0 = "tfl.pseudo_qconst"() <{qtype = tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>, value = dense<[[[[119, -17, 14], [78, 16, 36]], [[24, -22, -52], [21, 127, -120]]]]> : tensor<1x2x2x3xi8>}> : () -> tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>
%0 = "tfl.quantize"(%cst_0) <{qtype = tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>}> : (tensor<1x2x2x3xf32>) -> tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>
// CHECK: %1 = "tfl.dequantize"(%0) : (tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>) -> tensor<1x2x2x3xf32>
%1 = "tfl.dequantize"(%0) : (tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>) -> tensor<1x2x2x3xf32>
// CHECK: %2 = "tfl.conv_2d"(%arg0, %1, %cst) <{dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "RELU", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32}> : (tensor<1x4x4x3xf32>, tensor<1x2x2x3xf32>, tensor<1xf32>) -> tensor<1x4x4x1xf32>
%2 = "tfl.conv_2d"(%arg0, %1, %cst) <{dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "RELU", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32}> : (tensor<1x4x4x3xf32>, tensor<1x2x2x3xf32>, tensor<1xf32>) -> tensor<1x4x4x1xf32>
// CHECK: return %2 : tensor<1x4x4x1xf32>
return %2 : tensor<1x4x4x1xf32>
}
// -----
// CHECK-LABEL: QuantizeConvWithBiasAndReluSRQ
func.func @QuantizeConvWithBiasAndReluSRQ(%arg0: tensor<1x4x4x3xf32>) -> (tensor<1x4x4x1xf32>) {
%cst = arith.constant dense<1.14751196> : tensor<1xf32>
// CHECK: %0 = "tfl.pseudo_qconst"() <{qtype = tensor<1x!quant.uniform<i32:f32, 5.576458833533339E-5>>, value = dense<20578> : tensor<1xi32>}> : () -> tensor<1x!quant.uniform<i32:f32, 5.576458833533339E-5>>
%0 = "tfl.quantize"(%cst) <{qtype = tensor<1x!quant.uniform<i32:f32, 5.576458833533339E-5>>}> : (tensor<1xf32>) -> tensor<1x!quant.uniform<i32:f32, 5.576458833533339E-5>>
%1 = "tfl.dequantize"(%0) : (tensor<1x!quant.uniform<i32:f32, 5.576458833533339E-5>>) -> tensor<1xf32>
%cst_0 = arith.constant dense<[[[[1.76285899, -0.257785767, 0.20429258], [1.16310906, 0.23124367, 0.529797196]], [[0.348971426, -0.319283515, -0.772461354], [0.316666812, 1.88180697, -1.78054631]]]]> : tensor<1x2x2x3xf32>
// CHECK: %1 = "tfl.quantize"(%arg0) <{qtype = tensor<1x4x4x3x!quant.uniform<i8:f32, 0.0037634586915373802:-128>>}> : (tensor<1x4x4x3xf32>) -> tensor<1x4x4x3x!quant.uniform<i8:f32, 0.0037634586915373802:-128>>
%2 = "tfl.quantize"(%arg0) <{qtype = tensor<1x4x4x3x!quant.uniform<i8:f32, 0.0037634586915373802:-128>>}> : (tensor<1x4x4x3xf32>) -> tensor<1x4x4x3x!quant.uniform<i8:f32, 0.0037634586915373802:-128>>
%3 = "tfl.dequantize"(%2) : (tensor<1x4x4x3x!quant.uniform<i8:f32, 0.0037634586915373802:-128>>) -> tensor<1x4x4x3xf32>
// CHECK{LITERAL}: %2 = "tfl.pseudo_qconst"() <{qtype = tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>, value = dense<[[[[119, -17, 14], [78, 16, 36]], [[24, -22, -52], [21, 127, -120]]]]> : tensor<1x2x2x3xi8>}> : () -> tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>
%4 = "tfl.quantize"(%cst_0) <{qtype = tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>}> : (tensor<1x2x2x3xf32>) -> tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>
%5 = "tfl.dequantize"(%4) : (tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>) -> tensor<1x2x2x3xf32>
// CHECK: %3 = "tfl.conv_2d"(%1, %2, %0) <{dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "RELU", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32}> : (tensor<1x4x4x3x!quant.uniform<i8:f32, 0.0037634586915373802:-128>>, tensor<1x2x2x3x!quant.uniform<i8:f32, 0.014817377552390099>>, tensor<1x!quant.uniform<i32:f32, 5.576458833533339E-5>>) -> tensor<1x4x4x1x!quant.uniform<i8:f32, 0.013401651754975319:-128>>
%6 = "tfl.conv_2d"(%3, %5, %1) <{dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "RELU", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32}> : (tensor<1x4x4x3xf32>, tensor<1x2x2x3xf32>, tensor<1xf32>) -> tensor<1x4x4x1xf32>
%7 = "tfl.quantize"(%6) <{qtype = tensor<1x4x4x1x!quant.uniform<i8:f32, 0.013401651754975319:-128>>}> : (tensor<1x4x4x1xf32>) -> tensor<1x4x4x1x!quant.uniform<i8:f32, 0.013401651754975319:-128>>
// CHECK: %4 = "tfl.dequantize"(%3) : (tensor<1x4x4x1x!quant.uniform<i8:f32, 0.013401651754975319:-128>>) -> tensor<1x4x4x1xf32>
%8 = "tfl.dequantize"(%7) : (tensor<1x4x4x1x!quant.uniform<i8:f32, 0.013401651754975319:-128>>) -> tensor<1x4x4x1xf32>
// CHECK: return %4 : tensor<1x4x4x1xf32>
return %8 : tensor<1x4x4x1xf32>
}
// -----
// CHECK-LABEL: QuantizeEmbeddingLookupDrq
func.func @QuantizeEmbeddingLookupDrq(%arg0: tensor<2xi32>) -> (tensor<2x4xf32>){
%cst = arith.constant dense<[[1.0545162, -0.969288647, -0.594602108, -0.0318857245], [2.41093326, -1.87844908, -0.784769594, -0.313708425], [0.333708912, 1.76770353, -1.02776456, 1.41117179], [-0.508497119, -0.526377499, 0.503150403, 1.05497932], [-0.0874073281, 0.795816719, 2.65656161, -0.58229059]]> : tensor<5x4xf32>
// CHECK{LITERAL}: %0 = "tfl.pseudo_qconst"() <{qtype = tensor<5x4x!quant.uniform<i8:f32:0, {0.0082384077832102776,0.018835416063666344,0.013810183852910995,0.0082420259714126587,0.020754387602210045}>>, value = dense<[[127, -118, -72, -4], [127, -100, -42, -17], [24, 127, -74, 102], [-62, -64, 61, 127], [-4, 38, 127, -28]]> : tensor<5x4xi8>}> : () -> tensor<5x4x!quant.uniform<i8:f32:0, {0.0082384077832102776,0.018835416063666344,0.013810183852910995,0.0082420259714126587,0.020754387602210045}>>
%0 = "tfl.quantize"(%cst) <{qtype = tensor<5x4x!quant.uniform<i8:f32:0, {0.0082384077832102776,0.018835416063666344,0.013810183852910995,0.0082420259714126587,0.020754387602210045}>>}> : (tensor<5x4xf32>) -> tensor<5x4x!quant.uniform<i8:f32:0, {0.0082384077832102776,0.018835416063666344,0.013810183852910995,0.0082420259714126587,0.020754387602210045}>>
%1 = "tfl.dequantize"(%0) : (tensor<5x4x!quant.uniform<i8:f32:0, {0.0082384077832102776,0.018835416063666344,0.013810183852910995,0.0082420259714126587,0.020754387602210045}>>) -> tensor<5x4xf32>
// CHECK: %1 = "tfl.embedding_lookup"(%arg0, %0) : (tensor<2xi32>, tensor<5x4x!quant.uniform<i8:f32:0, {0.0082384077832102776,0.018835416063666344,0.013810183852910995,0.0082420259714126587,0.020754387602210045}>>) -> tensor<2x4xf32>
%2 = "tfl.embedding_lookup"(%arg0, %1) : (tensor<2xi32>, tensor<5x4xf32>) -> tensor<2x4xf32>
// CHECK: return %1 : tensor<2x4xf32>
return %2 : tensor<2x4xf32>
}
// -----
// CHECK-LABEL: DQQToRequantize
func.func @DQQToRequantize(%arg0: tensor<1x128x128x320x!quant.uniform<i8:f32, 0.17072822153568268:6>>) -> (tensor<1x128x128x320x!quant.uniform<i8:f32, 0.1043805405497551:-6>>) {
%0 = "tfl.dequantize"(%arg0) : (tensor<1x128x128x320x!quant.uniform<i8:f32, 0.17072822153568268:6>>) -> tensor<1x128x128x320xf32>
// CHECK: %0 = "tfl.quantize"(%arg0) <{qtype = tensor<1x128x128x320x!quant.uniform<i8:f32, 0.1043805405497551:-6>>}> : (tensor<1x128x128x320x!quant.uniform<i8:f32, 0.17072822153568268:6>>) -> tensor<1x128x128x320x!quant.uniform<i8:f32, 0.1043805405497551:-6>>
%1 = "tfl.quantize"(%0) <{qtype = tensor<1x128x128x320x!quant.uniform<i8:f32, 0.1043805405497551:-6>>}> : (tensor<1x128x128x320xf32>) -> tensor<1x128x128x320x!quant.uniform<i8:f32, 0.1043805405497551:-6>>
// CHECK: return %0 : tensor<1x128x128x320x!quant.uniform<i8:f32, 0.1043805405497551:-6>>
return %1 : tensor<1x128x128x320x!quant.uniform<i8:f32, 0.1043805405497551:-6>>
}
// -----
func.func @VolatileQuantizeConst() -> (tensor<1xf32>) {
%cst = arith.constant dense<1.14751196> : tensor<1xf32>
// CHECK: %0 = "tfl.pseudo_qconst"() <{qtype = tensor<1x!quant.uniform<i32:f32, 5.576458833533339E-5>>, value = dense<20578> : tensor<1xi32>}> {volatile} : () -> tensor<1x!quant.uniform<i32:f32, 5.576458833533339E-5>>
%0 = "tfl.quantize"(%cst) <{qtype = tensor<1x!quant.uniform<i32:f32, 5.576458833533339E-5>>}> {volatile} : (tensor<1xf32>) -> tensor<1x!quant.uniform<i32:f32, 5.576458833533339E-5>>
// CHECK: %1 = "tfl.dequantize"(%0) : (tensor<1x!quant.uniform<i32:f32, 5.576458833533339E-5>>) -> tensor<1xf32>
%1 = "tfl.dequantize"(%0) : (tensor<1x!quant.uniform<i32:f32, 5.576458833533339E-5>>) -> tensor<1xf32>
// CHECK: return %1 : tensor<1xf32>
return %1 : tensor<1xf32>
}
// -----
// CHECK-LABEL: QuantizeFloatConst
func.func @QuantizeFloatConst() -> tensor<2x2x!quant.uniform<u8:f32, 7.8431372549019615E-4:128>> {
%0 = arith.constant dense<-0.1> : tensor<2x2xf32>
// CHECK: %[[cst:.*]] = "tfl.pseudo_qconst"() <{qtype = tensor<2x2x!quant.uniform<u8:f32, 7.8431372549019615E-4:128>>, value = dense<0> : tensor<2x2xi8>}>
%1 = "tfl.quantize"(%0) {qtype = tensor<2x2x!quant.uniform<u8:f32, 7.8431372549019615E-4:128>>} : (tensor<2x2xf32>) -> tensor<2x2x!quant.uniform<u8:f32, 7.8431372549019615E-4:128>>
// CHECK: return %[[cst]]
func.return %1 : tensor<2x2x!quant.uniform<u8:f32, 7.8431372549019615E-4:128>>
}
// -----
// CHECK-LABEL: QuantizeFloatConst4Bits
func.func @QuantizeFloatConst4Bits() -> tensor<2x4x!quant.uniform<i4:f32, 2.500000e-01:-1>> {
%0 = arith.constant dense<[[-0.75, -0.5, -0.25, 0.0], [0.25, 0.5, 0.75, 1.0]]> : tensor<2x4xf32>
// CHECK: %[[cst:.*]] = "tfl.pseudo_qconst"() <{qtype = tensor<2x4x!quant.uniform<i4:f32, 2.500000e-01:-1>>, value = dense<{{\[\[}}-4, -3, -2, -1{{\]}}, [0, 1, 2, 3{{\]\]}}> : tensor<2x4xi4>}>
%1 = "tfl.quantize"(%0) {qtype = tensor<2x4x!quant.uniform<i4:f32, 2.500000e-01:-1>>} : (tensor<2x4xf32>) -> tensor<2x4x!quant.uniform<i4:f32, 2.500000e-01:-1>>
// CHECK: return %[[cst]]
func.return %1 : tensor<2x4x!quant.uniform<i4:f32, 2.500000e-01:-1>>
}
// -----
// CHECK-LABEL: QuantizeDenseFloatConst
func.func @QuantizeDenseFloatConst() -> tensor<2x2x!quant.uniform<u8:f32, 7.8431372549019615E-4:128>> {
%0 = arith.constant dense<[[-0.1, 1.0], [1.0, 3.0]]> : tensor<2x2xf32>
// CHECK: %[[cst:.*]] = "tfl.pseudo_qconst"() <{qtype = tensor<2x2x!quant.uniform<u8:f32, 7.8431372549019615E-4:128>>, value = dense<{{\[\[}}0, -1], {{\[}}-1, -1]]> : tensor<2x2xi8>}>
%1 = "tfl.quantize"(%0) {qtype = tensor<2x2x!quant.uniform<u8:f32, 7.8431372549019615E-4:128>>} : (tensor<2x2xf32>) -> tensor<2x2x!quant.uniform<u8:f32, 7.8431372549019615E-4:128>>
// CHECK: return %[[cst]]
func.return %1 : tensor<2x2x!quant.uniform<u8:f32, 7.8431372549019615E-4:128>>
}
// -----
// CHECK-LABEL: QuantizeSplatFloatConst
func.func @QuantizeSplatFloatConst() -> tensor<2x2x!quant.uniform<u8:f32, 7.8431372549019615E-4:128>> {
%0 = arith.constant dense<3.0> : tensor<2x2xf32>
// CHECK: %[[cst:.*]] = "tfl.pseudo_qconst"() <{qtype = tensor<2x2x!quant.uniform<u8:f32, 7.8431372549019615E-4:128>>, value = dense<-1> : tensor<2x2xi8>}>
%1 = "tfl.quantize"(%0) {qtype = tensor<2x2x!quant.uniform<u8:f32, 7.8431372549019615E-4:128>>} : (tensor<2x2xf32>) -> tensor<2x2x!quant.uniform<u8:f32, 7.8431372549019615E-4:128>>
// CHECK: return %[[cst]]
func.return %1 : tensor<2x2x!quant.uniform<u8:f32, 7.8431372549019615E-4:128>>
}
// -----
// CHECK-LABEL: DequantizeAndQuantize
func.func @DequantizeAndQuantize() -> tensor<2x2x!quant.uniform<u8:f32, 7.8431372549019615E-4:128>> {
// CHECK: %[[cst:.*]] = "tfl.pseudo_qconst"() <{qtype = tensor<2x2x!quant.uniform<u8:f32, 7.8431372549019615E-4:128>>, value = dense<-1> : tensor<2x2xi8>}>
%cst = "tfl.pseudo_qconst"() {qtype = tensor<2x2x!quant.uniform<u8:f32, 7.8431372549019615E-4:128>>, value = dense<-1> : tensor<2x2xi8>} : () -> tensor<2x2x!quant.uniform<u8:f32, 7.8431372549019615E-4:128>>
%0 = "tfl.dequantize"(%cst) : (tensor<2x2x!quant.uniform<u8:f32, 7.8431372549019615E-4:128>>) -> tensor<2x2xf32>
%1 = "tfl.quantize"(%0) {qtype = tensor<2x2x!quant.uniform<u8:f32, 7.8431372549019615E-4:128>>} : (tensor<2x2xf32>) -> tensor<2x2x!quant.uniform<u8:f32, 7.8431372549019615E-4:128>>
// CHECK: return %[[cst]] : tensor<2x2x!quant.uniform<u8:f32, 7.8431372549019615E-4:128>>
func.return %1 : tensor<2x2x!quant.uniform<u8:f32, 7.8431372549019615E-4:128>>
}
// -----
// CHECK-LABEL: QuantizeConv2D
func.func @QuantizeConv2D(tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>> {
^bb0(%arg0: tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>):
%cst = arith.constant dense<-1.23697901> : tensor<32xf32>
// CHECK: %[[cst0:.*]] = "tfl.pseudo_qconst"() <{qtype = tensor<32x!quant.uniform<i32:f32, 7.812500e-04>>, value = dense<-1583> : tensor<32xi32>}>
%0 = "tfl.quantize"(%cst) <{qtype = tensor<32x!quant.uniform<i32:f32, 7.812500e-04>>}> : (tensor<32xf32>) -> tensor<32x!quant.uniform<i32:f32, 7.812500e-04>>
%1 = "tfl.dequantize"(%0) : (tensor<32x!quant.uniform<i32:f32, 7.812500e-04>>) -> tensor<32xf32>
%2 = "tfl.dequantize"(%arg0) : (tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x224x224x3xf32>
%w = arith.constant dense<-1.0> : tensor<32x3x3x3xf32>
// CHECK: %[[cst1:.*]] = "tfl.pseudo_qconst"() <{qtype = tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 1.000000e-01>>, value = dense<1> : tensor<32x3x3x3xi8>}>
%3 = "tfl.quantize"(%w) {qtype = tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 0.1>>} : (tensor<32x3x3x3xf32>) -> tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 0.1>>
%4 = "tfl.dequantize"(%3) : (tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 0.1>>) -> tensor<32x3x3x3xf32>
// CHECK: %[[conv:.*]] = "tfl.conv_2d"(%arg0, %[[cst1]], %[[cst0]])
%5 = "tfl.conv_2d"(%2, %4, %1) {dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 2 : i32, stride_w = 2 : i32} : (tensor<1x224x224x3xf32>, tensor<32x3x3x3xf32>, tensor<32xf32>) -> tensor<1x112x112x32xf32>
%6 = "tfl.quantize"(%5) {qtype = tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>} : (tensor<1x112x112x32xf32>) -> tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>
// CHECK: return %[[conv]] : tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>
func.return %6 : tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>
}
// -----
// CHECK-LABEL: QuantizeConv2D4Bit
func.func @QuantizeConv2D4Bit(tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>> {
^bb0(%arg0: tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>):
%cst = arith.constant dense<-1.23697901> : tensor<32xf32>
// CHECK: %[[cst0:.*]] = "tfl.pseudo_qconst"() <{qtype = tensor<32x!quant.uniform<i32:f32, 7.812500e-04>>, value = dense<-1583> : tensor<32xi32>}>
%0 = "tfl.quantize"(%cst) <{qtype = tensor<32x!quant.uniform<i32:f32, 7.812500e-04>>}> : (tensor<32xf32>) -> tensor<32x!quant.uniform<i32:f32, 7.812500e-04>>
%1 = "tfl.dequantize"(%0) : (tensor<32x!quant.uniform<i32:f32, 7.812500e-04>>) -> tensor<32xf32>
%2 = "tfl.dequantize"(%arg0) : (tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x224x224x3xf32>
%w = arith.constant dense<-1.0> : tensor<32x3x3x3xf32>
// CHECK: %[[cst1:.*]] = "tfl.pseudo_qconst"() <{qtype = tensor<32x3x3x3x!quant.uniform<u4<1:15>:f32, 1.000000e-01>>, value = dense<1> : tensor<32x3x3x3xi4>}>
%3 = "tfl.quantize"(%w) {qtype = tensor<32x3x3x3x!quant.uniform<u4<1:15>:f32, 0.1>>} : (tensor<32x3x3x3xf32>) -> tensor<32x3x3x3x!quant.uniform<u4<1:15>:f32, 0.1>>
%4 = "tfl.dequantize"(%3) : (tensor<32x3x3x3x!quant.uniform<u4<1:15>:f32, 0.1>>) -> tensor<32x3x3x3xf32>
// CHECK: %[[conv:.*]] = "tfl.conv_2d"(%arg0, %[[cst1]], %[[cst0]])
%5 = "tfl.conv_2d"(%2, %4, %1) {dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "SAME", stride_h = 2 : i32, stride_w = 2 : i32} : (tensor<1x224x224x3xf32>, tensor<32x3x3x3xf32>, tensor<32xf32>) -> tensor<1x112x112x32xf32>
%6 = "tfl.quantize"(%5) {qtype = tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>} : (tensor<1x112x112x32xf32>) -> tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>
// CHECK: return %[[conv]] : tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>
func.return %6 : tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>
}
// -----
// CHECK-LABEL: QuantizeDepthwiseConv2D
func.func @QuantizeDepthwiseConv2D(tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>> {
^bb0(%arg0: tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>):
%cst = arith.constant dense<-1.23697901> : tensor<32xf32>
// CHECK: %[[cst0:.*]] = "tfl.pseudo_qconst"() <{qtype = tensor<32x!quant.uniform<i32:f32, 1.7052092479439231E-4>>, value = dense<-7254> : tensor<32xi32>}>
%0 = "tfl.quantize"(%cst) <{qtype = tensor<32x!quant.uniform<i32:f32, 1.7052092479439231E-4>>}> : (tensor<32xf32>) -> tensor<32x!quant.uniform<i32:f32, 1.7052092479439231E-4>>
%1 = "tfl.dequantize"(%0) : (tensor<32x!quant.uniform<i32:f32, 1.7052092479439231E-4>>) -> tensor<32xf32>
%2 = "tfl.dequantize"(%arg0) : (tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x224x224x3xf32>
// CHECK: %[[cst1:.*]] = "tfl.pseudo_qconst"() <{qtype = tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 0.021826678373682216:151>>, value = dense<-76> : tensor<32x3x3x3xi8>}>
%3 = "tfl.pseudo_qconst"() {qtype = tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 0.021826678373682216:151>>, value = dense<-76> : tensor<32x3x3x3xi8>} : () -> tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 0.021826678373682216:151>>
%4 = "tfl.dequantize"(%3) : (tensor<32x3x3x3x!quant.uniform<u8<1:255>:f32, 0.021826678373682216:151>>) -> tensor<32x3x3x3xf32>
// CHECK: %[[conv:.*]] = "tfl.depthwise_conv_2d"(%arg0, %[[cst1]], %[[cst0]]) <{depth_multiplier = 4 : i32, dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "VALID", stride_h = 4 : i32, stride_w = 5 : i32}>
%5 = "tfl.depthwise_conv_2d"(%2, %4, %1) {depth_multiplier = 4 : i32, dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, fused_activation_function = "NONE", padding = "VALID", stride_h = 4 : i32, stride_w = 5 : i32} : (tensor<1x224x224x3xf32>, tensor<32x3x3x3xf32>, tensor<32xf32>) -> tensor<1x112x112x32xf32>
%6 = "tfl.quantize"(%5) {qtype = tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>} : (tensor<1x112x112x32xf32>) -> tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>
// CHECK: return %[[conv]]
func.return %6 : tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>
}
// -----
// CHECK-LABEL: QuantizeFullyConnected
func.func @QuantizeFullyConnected(tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>> {
^bb0(%arg0: tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>):
%cst = arith.constant dense<-1.23697901> : tensor<32xf32>
// CHECK: %[[cst_0:.*]] = "tfl.pseudo_qconst"() <{qtype = tensor<32x!quant.uniform<i32:f32, 1.7052092479439231E-4>>, value = dense<-7254> : tensor<32xi32>}>
%0 = "tfl.quantize"(%cst) <{qtype = tensor<32x!quant.uniform<i32:f32, 1.7052092479439231E-4>>}> : (tensor<32xf32>) -> tensor<32x!quant.uniform<i32:f32, 1.7052092479439231E-4>>
%1 = "tfl.dequantize"(%0) : (tensor<32x!quant.uniform<i32:f32, 1.7052092479439231E-4>>) -> tensor<32xf32>
%2 = "tfl.dequantize"(%arg0) : (tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x224x224x3xf32>
// CHECK: %[[cst_1:.*]] = "tfl.pseudo_qconst"() <{qtype = tensor<32x12x!quant.uniform<u8<1:255>:f32, 0.021826678373682216:151>>, value = dense<-76> : tensor<32x12xi8>}>
%3 = "tfl.pseudo_qconst"() {qtype = tensor<32x12x!quant.uniform<u8<1:255>:f32, 0.021826678373682216:151>>, value = dense<-76> : tensor<32x12xi8>} : () -> tensor<32x12x!quant.uniform<u8<1:255>:f32, 0.021826678373682216:151>>
%4 = "tfl.dequantize"(%3) : (tensor<32x12x!quant.uniform<u8<1:255>:f32, 0.021826678373682216:151>>) -> tensor<32x12xf32>
// CHECK: %[[fc:.*]] = "tfl.fully_connected"(%arg0, %[[cst_1]], %[[cst_0]]) <{fused_activation_function = "NONE", keep_num_dims = false, weights_format = "DEFAULT"}>
%5 = "tfl.fully_connected"(%2, %4, %1) {fused_activation_function = "NONE", keep_num_dims = false, weights_format = "DEFAULT"} : (tensor<1x224x224x3xf32>, tensor<32x12xf32>, tensor<32xf32>) -> tensor<1x112x112x32xf32>
%6 = "tfl.quantize"(%5) {qtype = tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>} : (tensor<1x112x112x32xf32>) -> tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>
// CHECK: return %[[fc]]
func.return %6 : tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>
}
// -----
// CHECK-LABEL: QuantizeFullyConnected4Bit
func.func @QuantizeFullyConnected4Bit(tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>> {
^bb0(%arg0: tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>):
%cst = arith.constant dense<-1.23697901> : tensor<32xf32>
// CHECK: %[[cst_0:.*]] = "tfl.pseudo_qconst"() <{qtype = tensor<32x!quant.uniform<i32:f32, 0.0030937367812500002>>, value = dense<-400> : tensor<32xi32>}>
%0 = "tfl.quantize"(%cst) <{qtype = tensor<32x!quant.uniform<i32:f32, 0.0030937367812500002>>}> : (tensor<32xf32>) -> tensor<32x!quant.uniform<i32:f32, 0.0030937367812500002>>
%1 = "tfl.dequantize"(%0) : (tensor<32x!quant.uniform<i32:f32, 0.0030937367812500002>>) -> tensor<32xf32>
%2 = "tfl.dequantize"(%arg0) : (tensor<1x224x224x3x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x224x224x3xf32>
// CHECK: %[[cst_1:.*]] = "tfl.pseudo_qconst"() <{qtype = tensor<32x12x!quant.uniform<u4<1:15>:f32, 0.39599830800000002:8>>, value = dense<-7> : tensor<32x12xi4>}>
%3 = "tfl.pseudo_qconst"() {qtype = tensor<32x12x!quant.uniform<u4<1:15>:f32, 0.395998308:8>>, value = dense<-7> : tensor<32x12xi4>} : () -> tensor<32x12x!quant.uniform<u4<1:15>:f32, 0.395998308:8>>
%4 = "tfl.dequantize"(%3) : (tensor<32x12x!quant.uniform<u4<1:15>:f32, 0.395998308:8>>) -> tensor<32x12xf32>
// CHECK: %[[fc:.*]] = "tfl.fully_connected"(%arg0, %[[cst_1]], %[[cst_0]]) <{fused_activation_function = "NONE", keep_num_dims = false, weights_format = "DEFAULT"}>
%5 = "tfl.fully_connected"(%2, %4, %1) {fused_activation_function = "NONE", keep_num_dims = false, weights_format = "DEFAULT"} : (tensor<1x224x224x3xf32>, tensor<32x12xf32>, tensor<32xf32>) -> tensor<1x112x112x32xf32>
%6 = "tfl.quantize"(%5) {qtype = tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>} : (tensor<1x112x112x32xf32>) -> tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>
// CHECK: return %[[fc]]
func.return %6 : tensor<1x112x112x32x!quant.uniform<u8:f32, 0.023528476789885875>>
}
// -----
// CHECK-LABEL: QuantizeNoBiasFullyConnected
func.func @QuantizeNoBiasFullyConnected(%arg0: tensor<3x!quant.uniform<u8:f32, 1.0>>, %arg1: tensor<3x3x!quant.uniform<u8<1:255>:f32, 1.0>>, %arg2: none) -> tensor<3x!quant.uniform<u8:f32, 1.0>> {
%0 = "tfl.dequantize"(%arg0) : (tensor<3x!quant.uniform<u8:f32, 1.0>>) -> tensor<3xf32>
%1 = "tfl.dequantize"(%arg1) : (tensor<3x3x!quant.uniform<u8<1:255>:f32, 1.0>>) -> tensor<3x3xf32>
// CHECK: %[[fc:.*]] = "tfl.fully_connected"(%arg0, %arg1, %arg2)
%2 = "tfl.fully_connected"(%0, %1, %arg2) {fused_activation_function = "NONE", keep_num_dims = false, weights_format = "DEFAULT"} : (tensor<3xf32>, tensor<3x3xf32>, none) -> tensor<3xf32>
%3 = "tfl.quantize"(%2) {qtype = tensor<3x!quant.uniform<u8:f32, 1.0>>} : (tensor<3xf32>) -> tensor<3x!quant.uniform<u8:f32, 1.0>>
// CHECK: return %[[fc]]
func.return %3 : tensor<3x!quant.uniform<u8:f32, 1.0>>
}
// -----
// CHECK-LABEL: QuantizeAveragePool2D
func.func @QuantizeAveragePool2D(tensor<1x6x6x16x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x1x1x16x!quant.uniform<u8:f32, 7.812500e-03:128>> {
^bb0(%arg0: tensor<1x6x6x16x!quant.uniform<u8:f32, 7.812500e-03:128>>):
%0 = "tfl.dequantize"(%arg0) : (tensor<1x6x6x16x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x6x6x16xf32>
// CHECK: %[[avgp:.*]] = "tfl.average_pool_2d"(%arg0)
%1 = "tfl.average_pool_2d"(%0) {name = "avgpool", filter_height = 3 : i32, filter_width = 6 : i32, fused_activation_function = "NONE", padding = "VALID", stride_h = 3 : i32, stride_w = 1 : i32} : (tensor<1x6x6x16xf32>) -> tensor<1x1x1x16xf32>
%2 = "tfl.quantize"(%1) {qtype = tensor<1x1x1x16x!quant.uniform<u8:f32, 7.812500e-03:128>>} : (tensor<1x1x1x16xf32>) -> tensor<1x1x1x16x!quant.uniform<u8:f32, 7.812500e-03:128>>
// CHECK: return %[[avgp]] : tensor<1x1x1x16x!quant.uniform<u8:f32, 7.812500e-03:128>>
func.return %2 : tensor<1x1x1x16x!quant.uniform<u8:f32, 7.812500e-03:128>>
}
// -----
// This behavior is intentioally different than the legacy quantized pass.
// [quantized value] -> [DQ] -> [Float] pattern is no longer quantized.
// CHECK-LABEL: NoQuantizeAveragePool2D
func.func @NoQuantizeAveragePool2D(tensor<1x6x6x16x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x1x1x16xf32> {
^bb0(%arg0: tensor<1x6x6x16x!quant.uniform<u8:f32, 7.812500e-03:128>>):
// CHECK: %[[DQ:.*]] = "tfl.dequantize"(%arg0)
%0 = "tfl.dequantize"(%arg0) : (tensor<1x6x6x16x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x6x6x16xf32>
// CHECK: %[[AVGP:.*]] = "tfl.average_pool_2d"(%[[DQ]])
%1 = "tfl.average_pool_2d"(%0) {name = "avgpool", filter_height = 3 : i32, filter_width = 6 : i32, fused_activation_function = "NONE", padding = "VALID", stride_h = 3 : i32, stride_w = 1 : i32} : (tensor<1x6x6x16xf32>) -> tensor<1x1x1x16xf32>
// CHECK: return %[[AVGP]] : tensor<1x1x1x16xf32>
func.return %1 : tensor<1x1x1x16xf32>
}
// -----
// CHECK-LABEL: QuantizeReshape2D
func.func @QuantizeReshape2D(tensor<1x6x6x16x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x36x16x!quant.uniform<u8:f32, 7.812500e-03:128>> {
^bb0(%arg0: tensor<1x6x6x16x!quant.uniform<u8:f32, 7.812500e-03:128>>):
%cst = arith.constant dense<[1, 36, 16]> : tensor<3xi32>
%0 = "tfl.dequantize"(%arg0) : (tensor<1x6x6x16x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x6x6x16xf32>
// CHECK: %[[rs:.*]] = "tfl.reshape"(%arg0, %{{.*}})
%1 = "tfl.reshape"(%0, %cst) : (tensor<1x6x6x16xf32>, tensor<3xi32>) -> tensor<1x36x16xf32>
%2 = "tfl.quantize"(%1) {qtype = tensor<1x36x16x!quant.uniform<u8:f32, 7.812500e-03:128>>} : (tensor<1x36x16xf32>) -> tensor<1x36x16x!quant.uniform<u8:f32, 7.812500e-03:128>>
// CHECK: return %[[rs]] : tensor<1x36x16x!quant.uniform<u8:f32, 7.812500e-03:128>>
func.return %2 : tensor<1x36x16x!quant.uniform<u8:f32, 7.812500e-03:128>>
}
// -----
// CHECK-LABEL: QuantizeSoftmax
func.func @QuantizeSoftmax(tensor<1x6x6x16x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x6x6x16x!quant.uniform<u8:f32, 3.906250e-03>> {
^bb0(%arg0: tensor<1x6x6x16x!quant.uniform<u8:f32, 7.812500e-03:128>>):
%0 = "tfl.dequantize"(%arg0) : (tensor<1x6x6x16x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x6x6x16xf32>
// CHECK: %[[sm:.*]] = "tfl.softmax"(%arg0)
%1 = "tfl.softmax"(%0) {beta = 1.000000e+00 : f32} : (tensor<1x6x6x16xf32>) -> tensor<1x6x6x16xf32>
%2 = "tfl.quantize"(%1) {qtype = tensor<1x6x6x16x!quant.uniform<u8:f32, 3.906250e-03>>} : (tensor<1x6x6x16xf32>) -> tensor<1x6x6x16x!quant.uniform<u8:f32, 3.906250e-03>>
// CHECK: return %[[sm]] : tensor<1x6x6x16x!quant.uniform<u8:f32, 3.906250e-03>>
func.return %2 : tensor<1x6x6x16x!quant.uniform<u8:f32, 3.906250e-03>>
}
// -----
// CHECK-LABEL: QuantizeLogistic
func.func @QuantizeLogistic(tensor<1x6x6x16x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x6x6x16x!quant.uniform<u8:f32, 3.906250e-03>> {
^bb0(%arg0: tensor<1x6x6x16x!quant.uniform<u8:f32, 7.812500e-03:128>>):
%0 = "tfl.dequantize"(%arg0) : (tensor<1x6x6x16x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x6x6x16xf32>
// CHECK: %[[lg:.*]] = "tfl.logistic"(%arg0) : (tensor<1x6x6x16x!quant.uniform<u8:f32, 7.812500e-03:128>>)
%1 = "tfl.logistic"(%0) : (tensor<1x6x6x16xf32>) -> tensor<1x6x6x16xf32>
%2 = "tfl.quantize"(%1) {qtype = tensor<1x6x6x16x!quant.uniform<u8:f32, 3.906250e-03>>} : (tensor<1x6x6x16xf32>) -> tensor<1x6x6x16x!quant.uniform<u8:f32, 3.906250e-03>>
// CHECK: return %[[lg]] : tensor<1x6x6x16x!quant.uniform<u8:f32, 3.906250e-03>>
func.return %2 : tensor<1x6x6x16x!quant.uniform<u8:f32, 3.906250e-03>>
}
// -----
// CHECK-LABEL: QuantizeAdd
func.func @QuantizeAdd(tensor<1x56x56x24x!quant.uniform<u8:f32, 0.27583434161017922:119>>, tensor<1x56x56x24x!quant.uniform<u8:f32, 0.40149296779258581:136>>) -> tensor<1x56x56x24x!quant.uniform<u8:f32, 0.4321689530914905:133>> {
^bb0(%arg0: tensor<1x56x56x24x!quant.uniform<u8:f32, 0.27583434161017922:119>>, %arg1: tensor<1x56x56x24x!quant.uniform<u8:f32, 0.40149296779258581:136>>):
%0 = "tfl.dequantize"(%arg0) : (tensor<1x56x56x24x!quant.uniform<u8:f32, 0.27583434161017922:119>>) -> tensor<1x56x56x24xf32>
%1 = "tfl.dequantize"(%arg1) : (tensor<1x56x56x24x!quant.uniform<u8:f32, 0.40149296779258581:136>>) -> tensor<1x56x56x24xf32>
// CHECK: %[[add:.*]] = tfl.add(%arg0, %arg1) <{fused_activation_function = "NONE"}> : (tensor<1x56x56x24x!quant.uniform<u8:f32, 0.27583434161017922:119>>, tensor<1x56x56x24x!quant.uniform<u8:f32, 0.40149296779258581:136>>)
%2 = tfl.add %0, %1 {fused_activation_function = "NONE"} : tensor<1x56x56x24xf32> loc("Block")
%3 = "tfl.quantize"(%2) {qtype = tensor<1x56x56x24x!quant.uniform<u8:f32, 0.4321689530914905:133>>} : (tensor<1x56x56x24xf32>) -> tensor<1x56x56x24x!quant.uniform<u8:f32, 0.4321689530914905:133>>
// CHECK: return %[[add]] : tensor<1x56x56x24x!quant.uniform<u8:f32, 0.4321689530914905:133>>
func.return %3 : tensor<1x56x56x24x!quant.uniform<u8:f32, 0.4321689530914905:133>>
}
// -----
// CHECK-LABEL: QuantizeConcat
func.func @QuantizeConcat(tensor<1x2x!quant.uniform<u8:f32, 1.000000e-01:128>>, tensor<1x2x!quant.uniform<u8:f32, 1.000000e-01:128>>) -> tensor<2x2x!quant.uniform<u8:f32, 1.000000e-01:128>> {
^bb0(%arg0: tensor<1x2x!quant.uniform<u8:f32, 1.000000e-01:128>>, %arg1: tensor<1x2x!quant.uniform<u8:f32, 1.000000e-01:128>>):
%0 = "tfl.dequantize"(%arg0) : (tensor<1x2x!quant.uniform<u8:f32, 1.000000e-01:128>>) -> tensor<1x2xf32>
%1 = "tfl.dequantize"(%arg1) : (tensor<1x2x!quant.uniform<u8:f32, 1.000000e-01:128>>) -> tensor<1x2xf32>
// CHECK: %[[cc:.*]] = "tfl.concatenation"(%arg0, %arg1) <{axis = 0 : i32, fused_activation_function = "NONE"}>
%2 = "tfl.concatenation"(%0, %1) {axis = 0 : i32, fused_activation_function = "NONE"} : (tensor<1x2xf32>, tensor<1x2xf32>) -> tensor<2x2xf32>
%3 = "tfl.quantize"(%2) {qtype = tensor<2x2x!quant.uniform<u8:f32, 1.000000e-01:128>>} : (tensor<2x2xf32>) -> tensor<2x2x!quant.uniform<u8:f32, 1.000000e-01:128>>
// CHECK: return %[[cc]] : tensor<2x2x!quant.uniform<u8:f32, 1.000000e-01:128>>
func.return %3 : tensor<2x2x!quant.uniform<u8:f32, 1.000000e-01:128>>
}
// -----
// CHECK-LABEL: QuantizeMaxPool2D
func.func @QuantizeMaxPool2D(tensor<1x6x6x16x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x1x1x16x!quant.uniform<u8:f32, 7.812500e-03:128>> {
^bb0(%arg0: tensor<1x6x6x16x!quant.uniform<u8:f32, 7.812500e-03:128>>):
%0 = "tfl.dequantize"(%arg0) : (tensor<1x6x6x16x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x6x6x16xf32>
// CHECK: %[[mp:.*]] = "tfl.max_pool_2d"(%arg0) <{filter_height = 1 : i32, filter_width = 1 : i32, fused_activation_function = "RELU6", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32}> : (tensor<1x6x6x16x!quant.uniform<u8:f32, 7.812500e-03:128>>) -> tensor<1x1x1x16x!quant.uniform<u8:f32, 7.812500e-03:128>>
%1 = "tfl.max_pool_2d"(%0) {filter_height = 1 : i32, filter_width = 1 : i32, fused_activation_function = "RELU6", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32} : (tensor<1x6x6x16xf32>) -> tensor<1x1x1x16xf32>
%2 = "tfl.quantize"(%1) {qtype = tensor<1x1x1x16x!quant.uniform<u8:f32, 7.812500e-03:128>>} : (tensor<1x1x1x16xf32>) -> tensor<1x1x1x16x!quant.uniform<u8:f32, 7.812500e-03:128>>
// CHECK: return %[[mp]] : tensor<1x1x1x16x!quant.uniform<u8:f32, 7.812500e-03:128>>
func.return %2 : tensor<1x1x1x16x!quant.uniform<u8:f32, 7.812500e-03:128>>
}
// -----
// CHECK-LABEL: QuantizeSplit
func.func @QuantizeSplit(%arg: tensor<4x!quant.uniform<u8:f32, 1.0>>, %cst: tensor<i32>) -> (tensor<2x!quant.uniform<u8:f32, 1.0>>,tensor<2x!quant.uniform<u8:f32, 1.0>>) {
%0 = "tfl.dequantize"(%arg) : (tensor<4x!quant.uniform<u8:f32, 1.0>>) -> tensor<4xf32>
// CHECK: %[[sp:.*]]:2 = "tfl.split"(%arg1, %arg0) <{num_splits = 2 : i32}> : (tensor<i32>, tensor<4x!quant.uniform<u8:f32, 1.000000e+00>>)
%1:2 = "tfl.split"(%cst, %0) {num_splits = 2 : i32} : (tensor<i32>, tensor<4xf32>) -> (tensor<2xf32>, tensor<2xf32>)
%2 = "tfl.quantize"(%1#0) {qtype = tensor<2x!quant.uniform<u8:f32, 1.0>>} : (tensor<2xf32>) -> tensor<2x!quant.uniform<u8:f32, 1.0>>
%3 = "tfl.quantize"(%1#1) {qtype = tensor<2x!quant.uniform<u8:f32, 1.0>>} : (tensor<2xf32>) -> tensor<2x!quant.uniform<u8:f32, 1.0>>
// CHECK: return %[[sp]]#0, %[[sp]]#1
func.return %2, %3 : tensor<2x!quant.uniform<u8:f32, 1.0>>, tensor<2x!quant.uniform<u8:f32, 1.0>>
}
// -----
// CHECK-LABEL: QuantizeCustomTfOp
func.func @QuantizeCustomTfOp(%arg0: tensor<128x128x!quant.uniform<u8:f32, 0.1:127>>,
%arg1: tensor<1x!quant.uniform<u8:f32, 0.2:127>>, %arg2: tensor<1x!quant.uniform<u8:f32, 0.4:127>>,
%arg3: tensor<1xi32>) -> (tensor<128x128x!quant.uniform<u8:f32, 0.2:125>>) {
%0 = "tfl.dequantize"(%arg0) : (tensor<128x128x!quant.uniform<u8:f32, 0.1:127>>) -> tensor<128x128xf32>
%1 = "tfl.dequantize"(%arg1) : (tensor<1x!quant.uniform<u8:f32, 0.2:127>>) -> tensor<1xf32>
%2 = "tfl.dequantize"(%arg2) : (tensor<1x!quant.uniform<u8:f32, 0.4:127>>) -> tensor<1xf32>
// CHECK: %4 = "tfl.custom_tf"(%arg0, %arg1, %arg2, %arg3) ({
// CHECK-NEXT: ^bb0(%arg4: tensor<128x128xf32>, %arg5: tensor<1xf32>, %arg6: tensor<1xf32>, %arg7: tensor<1xi32>):
// CHECK-NEXT: "tf.LayerNorm"(%arg4, %arg5, %arg6, %arg7) {_tfl_quant_trait = "fully_quantizable", device = ""} : (tensor<128x128xf32>, tensor<1xf32>, tensor<1xf32>, tensor<1xi32>) -> tensor<128x128xf32>
// CHECK-NEXT: "tfl.yield"
// CHECK-NEXT: }) {_tfl_quant_trait = "fully_quantizable", device = ""} :
// CHECK-SAME: (tensor<128x128x!quant.uniform<u8:f32, 1.000000e-01:127>>, tensor<1x!quant.uniform<u8:f32, 2.000000e-01:127>>, tensor<1x!quant.uniform<u8:f32, 4.000000e-01:127>>, tensor<1xi32>)
// CHECK-SAME: -> tensor<128x128x!quant.uniform<u8:f32, 2.000000e-01:125>>
%3 = "tfl.custom_tf"(%0, %1, %2, %arg3) ({
^bb0(%a1: tensor<128x128xf32>, %a2: tensor<1xf32>, %a3: tensor<1xf32>, %a4: tensor<1xi32>):
%4 = "tf.LayerNorm"(%a1, %a2, %a3, %a4) {_tfl_quant_trait = "fully_quantizable", device = ""} : (tensor<128x128xf32>, tensor<1xf32>, tensor<1xf32>, tensor<1xi32>) -> tensor<128x128xf32>
"tfl.yield"(%4) : (tensor<128x128xf32>) -> ()
}) {_tfl_quant_trait = "fully_quantizable", device = ""} : (tensor<128x128xf32>, tensor<1xf32>, tensor<1xf32>, tensor<1xi32>) -> tensor<128x128xf32>
%4 = "tfl.quantize"(%3) {qtype = tensor<128x128x!quant.uniform<u8:f32, 0.2:125>>} : (tensor<128x128xf32>) -> tensor<128x128x!quant.uniform<u8:f32, 0.2:125>>
func.return %4 : tensor<128x128x!quant.uniform<u8:f32, 0.2:125>>
}
// -----
// Checks that legacy path correctly handles asymmetric quantized values.
// CHECK-LABEL: CheckLegacyQuantizeAdd
func.func @CheckLegacyQuantizeAdd() -> tensor<1x2x!quant.uniform<i8:f32, 0.0078431372549019607:-128>> {
%cst = arith.constant dense<[[1.000000e+00, 2.000000e+00]]> : tensor<1x2xf32>
// CHECK: "tfl.pseudo_qconst"() <{qtype = tensor<1x2x!quant.uniform<i8:f32, 0.0078431372549019607:-128>>, value = dense<{{\[\[}}-1, 127]]> : tensor<1x2xi8>}>
%0 = "tfl.quantize"(%cst) {qtype = tensor<1x2x!quant.uniform<i8:f32, 0.0078431372549019607:-128>>, volatile} : (tensor<1x2xf32>) -> tensor<1x2x!quant.uniform<i8:f32, 0.0078431372549019607:-128>>
func.return %0 : tensor<1x2x!quant.uniform<i8:f32, 0.0078431372549019607:-128>>
}
// -----
func.func private @testIfThen(tensor<*xf32>) -> tensor<*xf32>
func.func private @testIfElse(tensor<*xf32>) -> tensor<*xf32>
// CHECK-LABEL: NotQuantizeIf
func.func @NotQuantizeIf(%arg0: tensor<i1>,
%arg1: tensor<4x!quant.uniform<u8:f32, 1.0>>) -> (tensor<4x!quant.uniform<u8:f32, 1.0>>) {
// CHECK: %[[dq:.*]] = "tfl.dequantize"(%arg1)
%0 = "tfl.dequantize"(%arg1) : (tensor<4x!quant.uniform<u8:f32, 1.0>>) -> tensor<4xf32>
// CHECK-NEXT: %[[if:.*]] = "tf.If"(%arg0, %[[dq]]
%1 = "tf.If"(%arg0, %0) {then_branch = @testIfThen, else_branch = @testIfElse, is_stateless = false} : (tensor<i1>, tensor<4xf32>) -> tensor<4xf32>
// CHECK-NEXT: %[[q:.*]] = "tfl.quantize"(%[[if]])
%2 = "tfl.quantize"(%1) {qtype = tensor<4x!quant.uniform<u8:f32, 1.0>>} : (tensor<4xf32>) -> tensor<4x!quant.uniform<u8:f32, 1.0>>
// CHECK-NEXT: return %[[q]]
func.return %2 : tensor<4x!quant.uniform<u8:f32, 1.0>>
}
// -----
// CHECK-LABEL: NotQuantizeReadVariable
func.func @NotQuantizeReadVariable() -> tensor<1x2x3x!quant.uniform<u8<1:255>:f32, 0.047244094488188976:128>> {
// CHECK: %[[handle:.*]] = "tfl.var_handle"() <{container = "", shared_name = "states"}> : () -> tensor<!tf_type.resource<tensor<1x2x3xf32>>>
%0 = "tfl.var_handle"() {container = "", shared_name = "states"} : () -> tensor<!tf_type.resource<tensor<1x2x3xf32>>>
// CHECK-NEXT: %[[read:.*]] = "tfl.read_variable"(%[[handle]]) : (tensor<!tf_type.resource<tensor<1x2x3xf32>>>) -> tensor<1x2x3xf32>
%1 = "tfl.read_variable"(%0) : (tensor<!tf_type.resource<tensor<1x2x3xf32>>>) -> tensor<1x2x3xf32>
// CHECK-NEXT: %[[quantize:.*]] = "tfl.quantize"(%[[read]]) <{qtype = tensor<1x2x3x!quant.uniform<u8<1:255>:f32, 0.047244094488188976:128>>}> : (tensor<1x2x3xf32>) -> tensor<1x2x3x!quant.uniform<u8<1:255>:f32, 0.047244094488188976:128>>
%2 = "tfl.quantize"(%1) {qtype = tensor<1x2x3x!quant.uniform<u8<1:255>:f32, 0.047244094488188976:128>>} : (tensor<1x2x3xf32>) -> tensor<1x2x3x!quant.uniform<u8<1:255>:f32, 0.047244094488188976:128>>
// CHECK-NEXT: return %[[quantize]]
func.return %2 : tensor<1x2x3x!quant.uniform<u8<1:255>:f32, 0.047244094488188976:128>>
}
// -----
// CHECK-LABEL: QuantizeTposeConv
func.func @QuantizeTposeConv(%arg0: tensor<2x2x3x2048xf32>) -> tensor<2x3x2x2048x!quant.uniform<u8:f32, 0.1:128>> {
%output_shape = arith.constant dense<[2, 3, 2, 2048]> : tensor<4xi32>
// CHECK: %[[QARG0:.*]] = "tfl.quantize"(%arg0)
%q_arg0 = "tfl.quantize"(%arg0) {qtype = tensor<2x2x3x2048x!quant.uniform<u8:f32, 0.1:128>>} : (tensor<2x2x3x2048xf32>) -> tensor<2x2x3x2048x!quant.uniform<u8:f32, 0.1:128>>
%dq_arg0 = "tfl.dequantize"(%q_arg0) : (tensor<2x2x3x2048x!quant.uniform<u8:f32, 0.1:128>>) -> tensor<2x2x3x2048xf32>
// CHECK: %[[W:.*]] = "tfl.pseudo_qconst"()
%q_weighs = "tfl.pseudo_qconst"() {qtype = tensor<4x2x2x2048x!quant.uniform<u8<1:255>:f32, 0.15:151>>, value = dense<-76> : tensor<4x2x2x2048xi8>} : () -> tensor<4x2x2x2048x!quant.uniform<u8<1:255>:f32, 0.15:151>>
%dq_weights = "tfl.dequantize"(%q_weighs) : (tensor<4x2x2x2048x!quant.uniform<u8<1:255>:f32, 0.15:151>>) -> tensor<4x2x2x2048xf32>
%bias = "tfl.no_value"() {value} : () -> none
// CHECK: %[[CONV:.*]] = "tfl.transpose_conv"(%cst, %[[W]], %[[QARG0]], %0) <{fused_activation_function = "NONE", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32}> : (tensor<4xi32>, tensor<4x2x2x2048x!quant.uniform<u8<1:255>:f32, 1.500000e-01:151>>, tensor<2x2x3x2048x!quant.uniform<u8:f32, 1.000000e-01:128>>, none) -> tensor<2x3x2x2048x!quant.uniform<u8:f32, 1.000000e-01:128>>
%out = "tfl.transpose_conv"(%output_shape, %dq_weights, %dq_arg0, %bias) {fused_activation_function = "NONE", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32} : (tensor<4xi32>, tensor<4x2x2x2048xf32>, tensor<2x2x3x2048xf32>, none) -> tensor<2x3x2x2048xf32>
%q_out = "tfl.quantize"(%out) {qtype = tensor<2x3x2x2048x!quant.uniform<u8:f32, 0.1:128>>} : (tensor<2x3x2x2048xf32>) -> tensor<2x3x2x2048x!quant.uniform<u8:f32, 0.1:128>>
// CHECK: return %[[CONV]]
func.return %q_out : tensor<2x3x2x2048x!quant.uniform<u8:f32, 0.1:128>>
}
// -----
// CHECK-LABEL: foldQuantWeightsIntoEmbeddingLookup
func.func @foldQuantWeightsIntoEmbeddingLookup(%arg0: tensor<3xi32>) -> tensor<3x512xf32> {
%q_weighs = "tfl.pseudo_qconst"() {qtype = tensor<3074x512x!quant.uniform<u8<1:255>:f32, 0.15:151>>, value = dense<-76> : tensor<3074x512xi8>} : () -> tensor<3074x512x!quant.uniform<u8<1:255>:f32, 0.15:151>>
// CHECK-NOT: "tfl.dequantize"
%dq_weights = "tfl.dequantize"(%q_weighs) : (tensor<3074x512x!quant.uniform<u8<1:255>:f32, 0.15:151>>) -> tensor<3074x512xf32>
// CHECK: "tfl.embedding_lookup"(%arg0, %0) : (tensor<3xi32>, tensor<3074x512x!quant.uniform<u8<1:255>:f32
%out = "tfl.embedding_lookup"(%arg0, %dq_weights) : (tensor<3xi32>, tensor<3074x512xf32>) -> tensor<3x512xf32>
func.return %out : tensor<3x512xf32>
}
// -----
// CHECK-LABEL: RequantizationSquash
func.func @RequantizationSquash(%arg0: tensor<64x1x128xf32>) -> tensor<64x128xf32> {
%cst_132 = arith.constant dense<[64, 128]> : tensor<2xi32>
%683 = "tfl.quantize"(%arg0) <{qtype = tensor<64x1x128x!quant.uniform<i8:f32, 0.8>>}> {volatile} : (tensor<64x1x128xf32>) -> tensor<64x1x128x!quant.uniform<i8:f32, 0.8>>
// CHECK-NOT: "tfl.dequantize"(%{{.*}}) : (tensor<64x1x128x!quant.uniform<i8:f32, 0.8>>) -> tensor<64x1x128xf32>
%688 = "tfl.dequantize"(%683) : (tensor<64x1x128x!quant.uniform<i8:f32, 0.8>>) -> tensor<64x1x128xf32>
%698 = "tfl.quantize"(%688) <{qtype = tensor<64x1x128x!quant.uniform<i8:f32, 0.8>>}> : (tensor<64x1x128xf32>) -> tensor<64x1x128x!quant.uniform<i8:f32, 0.8>>
%699 = "tfl.dequantize"(%698) : (tensor<64x1x128x!quant.uniform<i8:f32, 0.8>>) -> tensor<64x1x128xf32>
// CHECK: "tfl.reshape"
// CHECK-SAME: (tensor<64x1x128x!quant.uniform<i8:f32, 8.000000e-01>>, tensor<2xi32>) -> tensor<64x128x!quant.uniform<i8:f32, 8.000000e-01>>
%700 = "tfl.reshape"(%699, %cst_132) : (tensor<64x1x128xf32>, tensor<2xi32>) -> tensor<64x128xf32>
%701 = "tfl.quantize"(%700) <{qtype = tensor<64x128x!quant.uniform<i8:f32, 0.8>>}> : (tensor<64x128xf32>) -> tensor<64x128x!quant.uniform<i8:f32, 0.8>>
%702 = "tfl.dequantize"(%701) : (tensor<64x128x!quant.uniform<i8:f32, 0.8>>) -> tensor<64x128xf32>
func.return %702 : tensor<64x128xf32>
}
// -----
// CHECK-LABEL: RequantizationDifferentScalesNoSquash
func.func @RequantizationDifferentScalesNoSquash(%arg0: tensor<64x1x128xf32>) -> tensor<64x128xf32> {
%cst_132 = arith.constant dense<[64, 128]> : tensor<2xi32>
%683 = "tfl.quantize"(%arg0) <{qtype = tensor<64x1x128x!quant.uniform<i8:f32, 0.2>>}> {volatile} : (tensor<64x1x128xf32>) -> tensor<64x1x128x!quant.uniform<i8:f32, 0.2>>
%688 = "tfl.dequantize"(%683) : (tensor<64x1x128x!quant.uniform<i8:f32, 0.2>>) -> tensor<64x1x128xf32>
// CHECK: %[[REQUANT:.*]] = "tfl.quantize"(%{{.*}}) <{qtype = tensor<64x1x128x!quant.uniform<i8:f32, 8.000000e-01>>}> : (tensor<64x1x128xf32>) -> tensor<64x1x128x!quant.uniform<i8:f32, 8.000000e-01>>
%698 = "tfl.quantize"(%688) <{qtype = tensor<64x1x128x!quant.uniform<i8:f32, 0.8>>}> : (tensor<64x1x128xf32>) -> tensor<64x1x128x!quant.uniform<i8:f32, 0.8>>
%699 = "tfl.dequantize"(%698) : (tensor<64x1x128x!quant.uniform<i8:f32, 0.8>>) -> tensor<64x1x128xf32>
// CHECK: "tfl.reshape"(%[[REQUANT]], %{{.*}}) : (tensor<64x1x128x!quant.uniform<i8:f32, 8.000000e-01>>, tensor<2xi32>) -> tensor<64x128x!quant.uniform<i8:f32, 8.000000e-01>>
%700 = "tfl.reshape"(%699, %cst_132) : (tensor<64x1x128xf32>, tensor<2xi32>) -> tensor<64x128xf32>
%701 = "tfl.quantize"(%700) <{qtype = tensor<64x128x!quant.uniform<i8:f32, 0.8>>}> : (tensor<64x128xf32>) -> tensor<64x128x!quant.uniform<i8:f32, 0.8>>
%702 = "tfl.dequantize"(%701) : (tensor<64x128x!quant.uniform<i8:f32, 0.8>>) -> tensor<64x128xf32>
func.return %702 : tensor<64x128xf32>
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,147 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: litert-opt -split-input-file -verify-diagnostics -tfl-get-arithmetic-count %s | FileCheck %s
func.func @testConv2D(tensor<256x32x32x3xf32>, tensor<16x3x3x3xf32>, tensor<16xf32>) -> tensor<256x32x32x16xf32> {
^bb0(%arg0: tensor<256x32x32x3xf32>, %arg1: tensor<16x3x3x3xf32>, %arg2: tensor<16xf32>):
// CHECK: _arithmetic_count = 230686720 : i64
%0 = "tfl.conv_2d"(%arg0, %arg1, %arg2) {dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32, fused_activation_function = "RELU6"} : (tensor<256x32x32x3xf32>, tensor<16x3x3x3xf32>, tensor<16xf32>) -> tensor<256x32x32x16xf32>
func.return %0 : tensor<256x32x32x16xf32>
}
func.func @testConv2DDynamicShape(tensor<?x32x32x3xf32>, tensor<16x3x3x3xf32>, tensor<16xf32>) -> tensor<?x32x32x16xf32> {
^bb0(%arg0: tensor<?x32x32x3xf32>, %arg1: tensor<16x3x3x3xf32>, %arg2: tensor<16xf32>):
// CHECK: _arithmetic_count = -1 : i64
%0 = "tfl.conv_2d"(%arg0, %arg1, %arg2) {dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32, fused_activation_function = "RELU6"} : (tensor<?x32x32x3xf32>, tensor<16x3x3x3xf32>, tensor<16xf32>) -> tensor<?x32x32x16xf32>
func.return %0 : tensor<?x32x32x16xf32>
}
func.func @testDepthwiseConv2D(tensor<1x112x112x3xf32>, tensor<1x3x3x32xf32>, tensor<32xf32>) -> tensor<1x112x112x32xf32> {
^bb0(%arg0: tensor<1x112x112x3xf32>, %arg1: tensor<1x3x3x32xf32>, %arg2: tensor<32xf32>):
// CHECK: _arithmetic_count = 7626752 : i64
%0 = "tfl.depthwise_conv_2d"(%arg0, %arg1, %arg2) {depth_multiplier = 1 : i32, dilation_h_factor = 1 : i32, dilation_w_factor = 1 : i32, padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32, fused_activation_function = "RELU6"} : (tensor<1x112x112x3xf32>, tensor<1x3x3x32xf32>, tensor<32xf32>) -> tensor<1x112x112x32xf32>
func.return %0 : tensor<1x112x112x32xf32>
}
func.func @fully_connected(%arg0: tensor<1x37xf32>, %arg1: tensor<40x37xf32>, %arg2: tensor<40xf32>) -> tensor<1x40xf32> {
// CHECK: _arithmetic_count = 3000 : i64
%0 = "tfl.fully_connected"(%arg0, %arg1, %arg2) {fused_activation_function = "NONE", keep_num_dims = false, weights_format = "DEFAULT"} : (tensor<1x37xf32>, tensor<40x37xf32>, tensor<40xf32>) -> tensor<1x40xf32>
func.return %0 : tensor<1x40xf32>
}
func.func @testAdd(%arg0: tensor<10x10x10xf32>, %arg1: tensor<10x10x10xf32>) -> tensor<10x10x10xf32> {
// CHECK: _arithmetic_count = 1000 : i64
%0 = "tfl.add"(%arg0, %arg1) {fused_activation_function = "NONE"} : (tensor<10x10x10xf32>, tensor<10x10x10xf32>) -> tensor<10x10x10xf32>
func.return %0 : tensor<10x10x10xf32>
}
func.func @testAddBroadcast(%arg0: tensor<10x10x10xf32>, %arg1: tensor<10xf32>) -> tensor<10x10x10xf32> {
// CHECK: _arithmetic_count = 1000 : i64
%0 = "tfl.add"(%arg0, %arg1) {fused_activation_function = "NONE"} : (tensor<10x10x10xf32>, tensor<10xf32>) -> tensor<10x10x10xf32>
func.return %0 : tensor<10x10x10xf32>
}
func.func @testSub(%arg0: tensor<10x10x10xf32>, %arg1: tensor<10x10x10xf32>) -> tensor<10x10x10xf32> {
// CHECK: _arithmetic_count = 1000 : i64
%0 = "tfl.sub"(%arg0, %arg1) {fused_activation_function = "NONE"} : (tensor<10x10x10xf32>, tensor<10x10x10xf32>) -> tensor<10x10x10xf32>
func.return %0 : tensor<10x10x10xf32>
}
func.func @testSubBroadcast(%arg0: tensor<10x10x10xf32>, %arg1: tensor<10xf32>) -> tensor<10x10x10xf32> {
// CHECK: _arithmetic_count = 1000 : i64
%0 = "tfl.sub"(%arg0, %arg1) {fused_activation_function = "NONE"} : (tensor<10x10x10xf32>, tensor<10xf32>) -> tensor<10x10x10xf32>
func.return %0 : tensor<10x10x10xf32>
}
func.func @testMul(%arg0: tensor<10x10x10xf32>, %arg1: tensor<10x10x10xf32>) -> tensor<10x10x10xf32> {
// CHECK: _arithmetic_count = 1000 : i64
%0 = "tfl.mul"(%arg0, %arg1) {fused_activation_function = "NONE"} : (tensor<10x10x10xf32>, tensor<10x10x10xf32>) -> tensor<10x10x10xf32>
func.return %0 : tensor<10x10x10xf32>
}
func.func @testMulBroadcast(%arg0: tensor<10x10x10xf32>, %arg1: tensor<10xf32>) -> tensor<10x10x10xf32> {
// CHECK: _arithmetic_count = 1000 : i64
%0 = "tfl.mul"(%arg0, %arg1) {fused_activation_function = "NONE"} : (tensor<10x10x10xf32>, tensor<10xf32>) -> tensor<10x10x10xf32>
func.return %0 : tensor<10x10x10xf32>
}
func.func @testDiv(%arg0: tensor<10x10x10xf32>, %arg1: tensor<10x10x10xf32>) -> tensor<10x10x10xf32> {
// CHECK: _arithmetic_count = 1000 : i64
%0 = "tfl.div"(%arg0, %arg1) {fused_activation_function = "NONE"} : (tensor<10x10x10xf32>, tensor<10x10x10xf32>) -> tensor<10x10x10xf32>
func.return %0 : tensor<10x10x10xf32>
}
func.func @testDivBroadcast(%arg0: tensor<10x10x10xf32>, %arg1: tensor<10xf32>) -> tensor<10x10x10xf32> {
// CHECK: _arithmetic_count = 1000 : i64
%0 = "tfl.div"(%arg0, %arg1) {fused_activation_function = "NONE"} : (tensor<10x10x10xf32>, tensor<10xf32>) -> tensor<10x10x10xf32>
func.return %0 : tensor<10x10x10xf32>
}
func.func @testLogistic(%arg0: tensor<10x10xf32>) -> tensor<10x10xf32> {
// CHECK: _arithmetic_count = 6400 : i64
%0 = "tfl.logistic"(%arg0) : (tensor<10x10xf32>) -> tensor<10x10xf32>
func.return %0 : tensor<10x10xf32>
}
func.func @testLogSoftmax(%arg0: tensor<10x10xf32>) -> tensor<10x10xf32> {
// CHECK: _arithmetic_count = 6400 : i64
%0 = "tfl.log_softmax"(%arg0) : (tensor<10x10xf32>) -> tensor<10x10xf32>
func.return %0 : tensor<10x10xf32>
}
func.func @testSoftmax(%arg0: tensor<10x10xf32>) -> tensor<10x10xf32> {
// CHECK: _arithmetic_count = 6400 : i64
%0 = "tfl.softmax"(%arg0) {beta = 1.000000e+00 : f32} : (tensor<10x10xf32>) -> tensor<10x10xf32>
func.return %0 : tensor<10x10xf32>
}
func.func @testTanh(%arg0: tensor<10x10xf32>) -> tensor<10x10xf32> {
// CHECK: _arithmetic_count = 6400 : i64
%0 = "tfl.tanh"(%arg0) : (tensor<10x10xf32>) -> tensor<10x10xf32>
func.return %0 : tensor<10x10xf32>
}
func.func @testAddN(%arg0: tensor<10x10xf32>, %arg1: tensor<10x10xf32>, %arg2: tensor<10x10xf32>) -> tensor<10x10xf32> {
// CHECK: _arithmetic_count = 200 : i64
%0 = "tfl.add_n"(%arg0, %arg1, %arg2) {fused_activation_function = "NONE"} : (tensor<10x10xf32>, tensor<10x10xf32>, tensor<10x10xf32>) -> tensor<10x10xf32>
func.return %0 : tensor<10x10xf32>
}
func.func @testMaxPool2D(tensor<1x10x10x3xf32>) -> tensor<1x10x10x3xf32> {
^bb0(%arg0: tensor<1x10x10x3xf32>):
// CHECK: _arithmetic_count = 2700 : i64
%0 = "tfl.max_pool_2d"(%arg0) {filter_height = 3 : i32, filter_width = 3 : i32, fused_activation_function = "RELU6", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32} : (tensor<1x10x10x3xf32>) -> tensor<1x10x10x3xf32>
func.return %0 : tensor<1x10x10x3xf32>
}
func.func @testAveragePool2D(tensor<1x10x10x3xf32>) -> tensor<1x10x10x3xf32> {
^bb0(%arg0: tensor<1x10x10x3xf32>):
// CHECK: _arithmetic_count = 2700 : i64
%0 = "tfl.average_pool_2d"(%arg0) {filter_height = 3 : i32, filter_width = 3 : i32, fused_activation_function = "RELU6", padding = "SAME", stride_h = 1 : i32, stride_w = 1 : i32} : (tensor<1x10x10x3xf32>) -> tensor<1x10x10x3xf32>
func.return %0 : tensor<1x10x10x3xf32>
}
func.func @testTransposeConv(%arg0: tensor<4xi32>, %arg1: tensor<32x4x4x128xf32>, %arg2: tensor<1x32x42x128xf32>) -> tensor<1x64x84x32xf32> {
%cst = "tfl.no_value"() {value = unit} : () -> none
// CHECK: _arithmetic_count = 176160768 : i64
%0 = "tfl.transpose_conv"(%arg0, %arg1, %arg2, %cst) {padding = "SAME", stride_h = 2 : i32, stride_w = 2 : i32, fused_activation_function = "NONE"} : (tensor<4xi32>, tensor<32x4x4x128xf32>, tensor<1x32x42x128xf32>, none) -> tensor<1x64x84x32xf32>
func.return %0 : tensor<1x64x84x32xf32>
}
func.func @testL2Norm(%arg0: tensor<10x10xf32>) -> tensor<10x10xf32> {
// CHECK: _arithmetic_count = 300 : i64
%0 = "tfl.l2_normalization"(%arg0) {fused_activation_function = "NONE"} : (tensor<10x10xf32>) -> tensor<10x10xf32>
func.return %0 : tensor<10x10xf32>
}
@@ -0,0 +1,140 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: litert-opt %s -tfl-gpu-compatibility | FileCheck %s
module {
func.func @test_strided_slice_promotion(%arg0: tensor<1x12xi1>) -> tensor<1x3xi1> {
// CHECK-LABEL: func.func @test_strided_slice_promotion
// CHECK-DAG: %[[C0:.*]] = "tfl.pseudo_const"() <{value = dense<0> : tensor<2xi32>}>
// CHECK-DAG: %[[C1:.*]] = "tfl.pseudo_const"() <{value = dense<[1, 3]> : tensor<2xi32>}>
// CHECK-DAG: %[[C2:.*]] = "tfl.pseudo_const"() <{value = dense<1> : tensor<2xi32>}>
// CHECK: %[[CAST_IN:.*]] = "tfl.cast"(%arg0) : (tensor<1x12xi1>) -> tensor<1x12xf32>
// CHECK: %[[SS:.*]] = "tfl.strided_slice"(%[[CAST_IN]], %[[C0]], %[[C1]], %[[C2]])
// CHECK-SAME: {{.*}} (tensor<1x12xf32>, tensor<2xi32>, tensor<2xi32>, tensor<2xi32>) -> tensor<1x3xf32>
// CHECK: %[[CAST_OUT:.*]] = "tfl.cast"(%[[SS]]) : (tensor<1x3xf32>) -> tensor<1x3xi1>
// CHECK: return %[[CAST_OUT]]
%cst = "tfl.pseudo_const"() <{value = dense<[0, 0]> : tensor<2xi32>}> : () -> tensor<2xi32>
%cst_0 = "tfl.pseudo_const"() <{value = dense<[1, 3]> : tensor<2xi32>}> : () -> tensor<2xi32>
%cst_1 = "tfl.pseudo_const"() <{value = dense<[1, 1]> : tensor<2xi32>}> : () -> tensor<2xi32>
%0 = "tfl.strided_slice"(%arg0, %cst, %cst_0, %cst_1) <{begin_mask = 0 : i32, ellipsis_mask = 0 : i32, end_mask = 0 : i32, new_axis_mask = 0 : i32, offset = false, shrink_axis_mask = 0 : i32}> : (tensor<1x12xi1>, tensor<2xi32>, tensor<2xi32>, tensor<2xi32>) -> tensor<1x3xi1>
func.return %0 : tensor<1x3xi1>
}
func.func @test_pad_promotion_expansion(%arg0: tensor<1x36xi1>) -> tensor<1x48xi1> {
// CHECK-LABEL: func.func @test_pad_promotion_expansion
// CHECK-DAG: %[[C0:.*]] = "tfl.pseudo_const"() <{value = dense<[1, 48]> : tensor<2xi32>}>
// CHECK-DAG: %[[C1:.*]] = "tfl.pseudo_const"() <{value = {{.*}} : tensor<3x2xi32>}>
// CHECK-DAG: %[[C2:.*]] = "tfl.pseudo_const"() <{value = dense<[1, 1, 36]> : tensor<3xi32>}>
// CHECK: %[[RE_IN:.*]] = "tfl.reshape"(%arg0, %[[C2]]) : (tensor<1x36xi1>, tensor<3xi32>) -> tensor<1x1x36xi1>
// CHECK: %[[CAST_IN:.*]] = "tfl.cast"(%[[RE_IN]]) : (tensor<1x1x36xi1>) -> tensor<1x1x36xf32>
// CHECK: %[[PAD:.*]] = "tfl.pad"(%[[CAST_IN]], %[[C1]]) : (tensor<1x1x36xf32>, tensor<3x2xi32>) -> tensor<1x1x48xf32>
// CHECK: %[[CAST_OUT:.*]] = "tfl.cast"(%[[PAD]]) : (tensor<1x1x48xf32>) -> tensor<1x1x48xi1>
// CHECK: %[[RE_OUT:.*]] = "tfl.reshape"(%[[CAST_OUT]], %[[C0]]) : (tensor<1x1x48xi1>, tensor<2xi32>) -> tensor<1x48xi1>
// CHECK: return %[[RE_OUT]]
%cst = "tfl.pseudo_const"() <{value = dense<[[0, 0], [0, 12]]> : tensor<2x2xi32>}> : () -> tensor<2x2xi32>
%0 = "tfl.pad"(%arg0, %cst) : (tensor<1x36xi1>, tensor<2x2xi32>) -> tensor<1x48xi1>
func.return %0 : tensor<1x48xi1>
}
func.func @test_batch_matmul_swap(%arg0: tensor<8x48x24xf32>) -> tensor<8x13x24xf32> {
// CHECK-LABEL: func.func @test_batch_matmul_swap
// CHECK-DAG: %[[CST:.*]] = "tfl.pseudo_const"() <{value = dense<1.000000e+00> : tensor<8x13x48xf32>}> : () -> tensor<8x13x48xf32>
// CHECK-DAG: %[[PERM:.*]] = "tfl.pseudo_const"() <{value = dense<[0, 2, 1]> : tensor<3xi32>}> : () -> tensor<3xi32>
// CHECK: %[[BMM:.*]] = "tfl.batch_matmul"(%arg0, %[[CST]]) <{adj_x = true, adj_y = true, asymmetric_quantize_inputs = false}> : (tensor<8x48x24xf32>, tensor<8x13x48xf32>) -> tensor<8x24x13xf32>
// CHECK: %[[RES:.*]] = "tfl.transpose"(%[[BMM]], %[[PERM]]) : (tensor<8x24x13xf32>, tensor<3xi32>) -> tensor<8x13x24xf32>
// CHECK: return %[[RES]] : tensor<8x13x24xf32>
%cst = "tfl.pseudo_const"() <{value = dense<1.0> : tensor<8x13x48xf32>}> : () -> tensor<8x13x48xf32>
%0 = "tfl.batch_matmul"(%cst, %arg0) <{adj_x = false, adj_y = false, asymmetric_quantize_inputs = false}> : (tensor<8x13x48xf32>, tensor<8x48x24xf32>) -> tensor<8x13x24xf32>
func.return %0 : tensor<8x13x24xf32>
}
func.func @test_broadcast_to(%arg0: tensor<1x2x1x24xi1>, %arg1: tensor<1x1x12x24xi1>) -> tensor<1x2x12x24xi1> {
// CHECK-LABEL: func.func @test_broadcast_to
// CHECK-DAG: %[[MULT2:.*]] = "tfl.pseudo_const"() <{value = dense<[1, 2, 1, 1]> : tensor<4xi64>}> : () -> tensor<4xi64>
// CHECK-DAG: %[[MULT1:.*]] = "tfl.pseudo_const"() <{value = dense<[1, 1, 12, 1]> : tensor<4xi64>}> : () -> tensor<4xi64>
// CHECK: %[[CAST1:.*]] = "tfl.cast"(%arg0) : (tensor<1x2x1x24xi1>) -> tensor<1x2x1x24xi32>
// CHECK: %[[TILE1:.*]] = "tfl.tile"(%[[CAST1]], %[[MULT1]]) : (tensor<1x2x1x24xi32>, tensor<4xi64>) -> tensor<1x2x12x24xi32>
// CHECK: %[[CAST2:.*]] = "tfl.cast"(%[[TILE1]]) : (tensor<1x2x12x24xi32>) -> tensor<1x2x12x24xi1>
// CHECK: %[[CAST3:.*]] = "tfl.cast"(%arg1) : (tensor<1x1x12x24xi1>) -> tensor<1x1x12x24xi32>
// CHECK: %[[TILE2:.*]] = "tfl.tile"(%[[CAST3]], %[[MULT2]]) : (tensor<1x1x12x24xi32>, tensor<4xi64>) -> tensor<1x2x12x24xi32>
// CHECK: %[[CAST4:.*]] = "tfl.cast"(%[[TILE2]]) : (tensor<1x2x12x24xi32>) -> tensor<1x2x12x24xi1>
// CHECK: %[[RES:.*]] = tfl.logical_and %[[CAST2]], %[[CAST4]] : tensor<1x2x12x24xi1>
// CHECK: return %[[RES]] : tensor<1x2x12x24xi1>
%0 = "tfl.pseudo_const"() <{value = dense<[1, 2, 12, 24]> : tensor<4xi64>}> : () -> tensor<4xi64>
%1 = "tfl.broadcast_to"(%arg0, %0) : (tensor<1x2x1x24xi1>, tensor<4xi64>) -> tensor<1x2x12x24xi1>
%2 = "tfl.broadcast_to"(%arg1, %0) : (tensor<1x1x12x24xi1>, tensor<4xi64>) -> tensor<1x2x12x24xi1>
%3 = tfl.logical_and %1, %2 : tensor<1x2x12x24xi1>
func.return %3 : tensor<1x2x12x24xi1>
}
func.func @test_broadcast_sum_to_mul(%arg0: tensor<25x1x1x1xf32>) -> tensor<25x1x1x1xf32> {
// CHECK-LABEL: func.func @test_broadcast_sum_to_mul
// CHECK: %[[SCALE:.*]] = "tfl.pseudo_const"() <{value = dense<8.192000e+03> : tensor<f32>}> : () -> tensor<f32>
// CHECK: %[[RES:.*]] = tfl.mul(%arg0, %[[SCALE]]) <{fused_activation_function = "NONE"}> : (tensor<25x1x1x1xf32>, tensor<f32>) -> tensor<25x1x1x1xf32>
// CHECK: return %[[RES]] : tensor<25x1x1x1xf32>
%0 = "tfl.pseudo_const"() <{value = dense<[25, 64, 1, 128]> : tensor<4xi64>}> : () -> tensor<4xi64>
%1 = "tfl.broadcast_to"(%arg0, %0) : (tensor<25x1x1x1xf32>, tensor<4xi64>) -> tensor<25x64x1x128xf32>
%2 = "tfl.pseudo_const"() <{value = dense<[1, 3]> : tensor<2xi32>}> : () -> tensor<2xi32>
%3 = "tfl.sum"(%1, %2) <{keep_dims = true}> : (tensor<25x64x1x128xf32>, tensor<2xi32>) -> tensor<25x1x1x1xf32>
func.return %3 : tensor<25x1x1x1xf32>
}
func.func @test_fuse_dequantize_fc(%arg0: tensor<1x16x384xf32>, %arg1: tensor<1536x384x!quant.uniform<i4:f32:0, {1.0}>>) -> tensor<1x16x1536xf32> {
// CHECK-LABEL: func.func @test_fuse_dequantize_fc
// CHECK: %[[CST:.*]] = "tfl.no_value"()
// CHECK: %[[FC:.*]] = "tfl.fully_connected"(%arg0, %arg1, %[[CST]])
// CHECK-SAME: asymmetric_quantize_inputs = false, fused_activation_function = "NONE", keep_num_dims = true, weights_format = "DEFAULT"
// CHECK-NEXT: return %[[FC]]
%cst = "tfl.no_value"() {value} : () -> none
%0 = "tfl.dequantize"(%arg1) : (tensor<1536x384x!quant.uniform<i4:f32:0, {1.0}>>) -> tensor<1536x384xf32>
%1 = "tfl.fully_connected"(%arg0, %0, %cst) <{asymmetric_quantize_inputs = false, fused_activation_function = "NONE", keep_num_dims = true, weights_format = "DEFAULT"}> : (tensor<1x16x384xf32>, tensor<1536x384xf32>, none) -> tensor<1x16x1536xf32>
return %1 : tensor<1x16x1536xf32>
}
func.func @test_swap_add(%arg0: tensor<f32>, %arg1: tensor<25x1x1x1xf32>) -> tensor<25x1x1x1xf32> {
// CHECK-LABEL: func.func @test_swap_add
// CHECK: %[[CST:.*]] = "tfl.pseudo_const"() <{value = dense<1> : tensor<1xi32>}> : () -> tensor<1xi32>
// CHECK: %[[RESHAPE:.*]] = "tfl.reshape"(%arg0, %[[CST]]) : (tensor<f32>, tensor<1xi32>) -> tensor<1xf32>
// CHECK: tfl.add(%arg1, %[[RESHAPE]]) <{fused_activation_function = "NONE"}> : (tensor<25x1x1x1xf32>, tensor<1xf32>) -> tensor<25x1x1x1xf32>
%0 = "tfl.add"(%arg0, %arg1) <{fused_activation_function = "NONE"}> : (tensor<f32>, tensor<25x1x1x1xf32>) -> tensor<25x1x1x1xf32>
func.return %0 : tensor<25x1x1x1xf32>
}
func.func @test_tile_non_splat(%arg0: tensor<1x1x12x24xi1>) -> (tensor<1x2x12x24xi1>, tensor<1x2x2xi32>) {
// CHECK-LABEL: func.func @test_tile_non_splat
// CHECK: %[[CST0:.*]] = arith.constant dense<true> : tensor<1x2x12x24xi1>
// CHECK: %[[CST1:.*]] = "tfl.pseudo_const"() <{value = dense<{{.*}}> : tensor<1x2x2xi32>}>
// CHECK: return %[[CST0]], %[[CST1]]
%cst = "tfl.pseudo_const"() <{value = dense<true> : tensor<1x1x12x24xi1>}> : () -> tensor<1x1x12x24xi1>
%multiples = "tfl.pseudo_const"() <{value = dense<[1, 2, 1, 1]> : tensor<4xi64>}> : () -> tensor<4xi64>
%0 = "tfl.tile"(%cst, %multiples) : (tensor<1x1x12x24xi1>, tensor<4xi64>) -> tensor<1x2x12x24xi1>
%cst_non_splat = "tfl.pseudo_const"() <{value = dense<[[[1, 2], [3, 4]]]> : tensor<1x2x2xi32>}> : () -> tensor<1x2x2xi32>
%multiples_2 = "tfl.pseudo_const"() <{value = dense<[1, 2, 1]> : tensor<3xi64>}> : () -> tensor<3xi64>
%1 = "tfl.tile"(%cst_non_splat, %multiples_2) : (tensor<1x2x2xi32>, tensor<3xi64>) -> tensor<1x2x2xi32>
return %0, %1 : tensor<1x2x12x24xi1>, tensor<1x2x2xi32>
}
func.func @tile_bool(%arg0: tensor<1x2x1x24xi1>, %arg1: tensor<4xi64>) -> tensor<1x2x12x24xi1> {
// CHECK-LABEL: tile_bool
// CHECK: %[[CAST_IN:.*]] = "tfl.cast"(%arg0) : (tensor<1x2x1x24xi1>) -> tensor<1x2x1x24xi32>
// CHECK: %[[TILE:.*]] = "tfl.tile"(%[[CAST_IN]], %arg1) : (tensor<1x2x1x24xi32>, tensor<4xi64>) -> tensor<1x2x12x24xi32>
// CHECK: %[[CAST_OUT:.*]] = "tfl.cast"(%[[TILE]]) : (tensor<1x2x12x24xi32>) -> tensor<1x2x12x24xi1>
// CHECK: return %[[CAST_OUT]]
%0 = "tfl.tile"(%arg0, %arg1) : (tensor<1x2x1x24xi1>, tensor<4xi64>) -> tensor<1x2x12x24xi1>
func.return %0 : tensor<1x2x12x24xi1>
}
}
@@ -0,0 +1,47 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: litert-opt %s --tf-guarantee-all-funcs-one-use --tf-shape-inference | FileCheck %s
module attributes {tf.versions = {producer = 888 : i32}} {
// CHECK-LABEL: func @while_main
// CHECK: %0 = "tf.While"(%arg0)
// CHECK-SAME: body = @while_body
// CHECK-SAME: cond = @while_cond
// CHECK: "tf.While"(%arg1)
// CHECK-SAME: body = @while_body_0
// CHECK-SAME: cond = @while_cond_1
// CHECK: func @while_body(%arg0: tensor<256x256xi32>)
// CHECK: func @while_cond(%arg0: tensor<256x256xi32>)
// CHECK: func private @while_body_0(%arg0: tensor<128xi32>)
// CHECK: func private @while_cond_1(%arg0: tensor<128xi32>)
func.func @while_main(%arg0: tensor<256x256xi32>, %arg1: tensor<128xi32>) -> (tensor<256x256xi32>, tensor<128xi32>) {
%0 = "tf.While"(%arg0) {body = @while_body, cond = @while_cond, device = "", is_stateless = true} : (tensor<256x256xi32>) -> (tensor<256x256xi32>)
%1 = "tf.While"(%arg1) {body = @while_body, cond = @while_cond, device = "", is_stateless = true} : (tensor<128xi32>) -> (tensor<128xi32>)
func.return %0, %1: tensor<256x256xi32>, tensor<128xi32>
}
func.func @while_body(%arg0: tensor<*xi32>) -> (tensor<*xi32>) {
%0 = "tf.Rank"(%arg0) : (tensor<*xi32>) -> tensor<i32>
%1 = "tf.Add"(%0, %arg0): (tensor<i32>, tensor<*xi32>) -> tensor<*xi32>
func.return %1: tensor<*xi32>
}
func.func @while_cond(%arg0: tensor<*xi32>) -> tensor<*xi1> {
%cst = arith.constant dense<10> : tensor<i32>
%0 = "tf.Less"(%arg0, %cst) {T = i32, device = ""} : (tensor<*xi32>, tensor<i32>) -> tensor<*xi1>
func.return %0 : tensor<*xi1>
}
}
@@ -0,0 +1,32 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: litert-opt %s -inline='default-pipeline=''' | FileCheck %s
// Inline a function that contains only tfl ops.
func.func @func_with_tfl_ops(%arg0 : tensor<2xi32>) -> tensor<2xi32> {
%0 = "tfl.sub"(%arg0, %arg0) {fused_activation_function = "RELU6"} : (tensor<2xi32>, tensor<2xi32>) -> tensor<2xi32>
%1 = "tfl.add"(%0, %arg0) {fused_activation_function = "RELU6"} : (tensor<2xi32>, tensor<2xi32>) -> tensor<2xi32>
func.return %1: tensor<2xi32>
}
// CHECK-LABEL: func @inline_with_arg
// CHECK-SAME: [[VAL_0:%.*]]: tensor<2xi32>
func.func @inline_with_arg(%arg0 : tensor<2xi32>) -> tensor<2xi32> {
// CHECK-NEXT: [[VAL_1:%.*]] = tfl.sub [[VAL_0]], [[VAL_0]] {fused_activation_function = "RELU6"} : tensor<2xi32>
// CHECK-NEXT: [[VAL_2:%.*]] = tfl.add [[VAL_1]], [[VAL_0]] {fused_activation_function = "RELU6"} : tensor<2xi32>
// CHECK-NEXT: return [[VAL_2]] : tensor<2xi32>
%0 = func.call @func_with_tfl_ops(%arg0) : (tensor<2xi32>) -> tensor<2xi32>
func.return %0 : tensor<2xi32>
}
@@ -0,0 +1,54 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: litert-opt -split-input-file -tfl-insert-call-once-op %s | FileCheck %s
// Tests that new call_once op is added when there is a session initializer.
module attributes {tf_saved_model.semantics} {
"tf_saved_model.session_initializer"() {initializers = [@init_all_tables]} : () -> ()
func.func @init_all_tables()
attributes {tf_saved_model.exported_names = ["__tf_saved_model_session_initializer"]} {
%cst = arith.constant dense<[1, 2, 3, 4]> : tensor<4xi64>
%cst_0 = arith.constant dense<["a", "b", "c", "d"]> : tensor<4x!tf_type.string>
%0 = "tf.HashTableV2"() {container = "", device = "", key_dtype = i64, shared_name = "hash_table_dba2ccaa-f1b1-46d6-b276-98008f69da71", use_node_name_sharing = false, value_dtype = !tf_type.string} : () -> tensor<!tf_type.resource>
"tf.LookupTableImportV2"(%0, %cst, %cst_0) {device = ""} : (tensor<!tf_type.resource>, tensor<4xi64>, tensor<4x!tf_type.string>) -> ()
func.return
// CHECK-LABEL: @init_all_tables
}
func.func @serving_default(%arg0: tensor<i64> {tf_saved_model.index_path = ["x"]}) -> (tensor<*x!tf_type.string> {tf_saved_model.index_path = ["r"]})
attributes {tf.entry_function = {control_outputs = "", inputs = "input:0", outputs = "hash_table_Lookup/LookupTableFindV2:0"}, tf_saved_model.exported_names = ["serving_default"]} {
%cst = arith.constant dense<"f"> : tensor<!tf_type.string>
%0 = "tf.HashTableV2"() {container = "", device = "", key_dtype = i64, shared_name = "hash_table_dba2ccaa-f1b1-46d6-b276-98008f69da71", use_node_name_sharing = false, value_dtype = !tf_type.string} : () -> tensor<!tf_type.resource>
%1 = "tf.LookupTableFindV2"(%0, %arg0, %cst) {device = ""} : (tensor<!tf_type.resource>, tensor<i64>, tensor<!tf_type.string>) -> tensor<*x!tf_type.string>
func.return %1 : tensor<*x!tf_type.string>
// CHECK-LABEL: @serving_default
// CHECK: "tfl.call_once"() <{session_init_function = "init_all_tables"}> : () -> ()
}
}
// -----
// Tests that no call_once op is added.
module attributes {tf_saved_model.semantics} {
func.func @no_call_once(%arg0: tensor<i64> {tf_saved_model.index_path = ["x"]}) -> (tensor<i64> {tf_saved_model.index_path = ["r"]})
attributes {tf.entry_function = {control_outputs = "", inputs = "input:0", outputs = "output:0"}, tf_saved_model.exported_names = ["serving_default"]} {
func.return %arg0 : tensor<i64>
// CHECK-LABEL: no_call_once
// CHECK-NOT: "tfl.call_once"
}
}
@@ -0,0 +1,170 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: litert-opt -tfl-legalize-tensorlist -canonicalize -split-input-file %s | FileCheck %s
// CHECK-LABEL: listReserveScalarShapeI32
func.func @listReserveScalarShapeI32(%arg0: tensor<i32>, %arg1: tensor<i32>) -> tensor<!tf_type.variant<tensor<*xi32>>> {
%0 = "tf.TensorListReserve"(%arg0, %arg1) : (tensor<i32>, tensor<i32>) -> tensor<!tf_type.variant<tensor<*xi32>>>
// CHECK: %0 = "tfl.custom"(%arg0, %arg1) <{custom_code = "TensorListReserve", custom_option = #tfl<const_bytes : "0x02">}> : (tensor<i32>, tensor<i32>) -> tensor<!tf_type.variant<tensor<*xi32>>>
func.return %0 : tensor<!tf_type.variant<tensor<*xi32>>>
}
// -----
// CHECK-LABEL: listReserve1DShapeI32
func.func @listReserve1DShapeI32(%arg0: tensor<2xi32>, %arg1: tensor<i32>) -> tensor<!tf_type.variant<tensor<*xi32>>> {
%0 = "tf.TensorListReserve"(%arg0, %arg1) : (tensor<2xi32>, tensor<i32>) -> tensor<!tf_type.variant<tensor<*xi32>>>
// CHECK: %0 = "tfl.custom"(%arg0, %arg1) <{custom_code = "TensorListReserve", custom_option = #tfl<const_bytes : "0x02">}> : (tensor<2xi32>, tensor<i32>) -> tensor<!tf_type.variant<tensor<*xi32>>>
func.return %0 : tensor<!tf_type.variant<tensor<*xi32>>>
}
// -----
// CHECK-LABEL: listReserveScalarShapeFloat
func.func @listReserveScalarShapeFloat(%arg0: tensor<i32>, %arg1: tensor<i32>) -> tensor<!tf_type.variant<tensor<*xf32>>> {
%0 = "tf.TensorListReserve"(%arg0, %arg1) : (tensor<i32>, tensor<i32>) -> tensor<!tf_type.variant<tensor<*xf32>>>
// CHECK: %0 = "tfl.custom"(%arg0, %arg1) <{custom_code = "TensorListReserve", custom_option = #tfl<const_bytes : "0x00">}> : (tensor<i32>, tensor<i32>) -> tensor<!tf_type.variant<tensor<*xf32>>>
func.return %0 : tensor<!tf_type.variant<tensor<*xf32>>>
}
// -----
// CHECK-LABEL: listReserveScalarShapeLong
func.func @listReserveScalarShapeLong(%arg0: tensor<i32>, %arg1: tensor<i32>) -> tensor<!tf_type.variant<tensor<*xi64>>> {
%0 = "tf.TensorListReserve"(%arg0, %arg1) : (tensor<i32>, tensor<i32>) -> tensor<!tf_type.variant<tensor<*xi64>>>
// CHECK: %0 = "tfl.custom"(%arg0, %arg1) <{custom_code = "TensorListReserve", custom_option = #tfl<const_bytes : "0x04">}> : (tensor<i32>, tensor<i32>) -> tensor<!tf_type.variant<tensor<*xi64>>>
func.return %0 : tensor<!tf_type.variant<tensor<*xi64>>>
}
// -----
// CHECK-LABEL: listReserveScalarShapeBool
func.func @listReserveScalarShapeBool(%arg0: tensor<i32>, %arg1: tensor<i32>) -> tensor<!tf_type.variant<tensor<*xi1>>> {
%0 = "tf.TensorListReserve"(%arg0, %arg1) : (tensor<i32>, tensor<i32>) -> tensor<!tf_type.variant<tensor<*xi1>>>
// CHECK: %0 = "tfl.custom"(%arg0, %arg1) <{custom_code = "TensorListReserve", custom_option = #tfl<const_bytes : "0x06">}> : (tensor<i32>, tensor<i32>) -> tensor<!tf_type.variant<tensor<*xi1>>>
func.return %0 : tensor<!tf_type.variant<tensor<*xi1>>>
}
// -----
// CHECK-LABEL: listStack
func.func @listStack(%arg0: tensor<!tf_type.variant<tensor<*xi32>>>, %arg1: tensor<i32>) -> tensor<*xi32> {
%0 = "tf.TensorListStack"(%arg0, %arg1) : (tensor<!tf_type.variant<tensor<*xi32>>>, tensor<i32>) -> tensor<*xi32>
// CHECK: %0 = "tfl.custom"(%arg0, %arg1) <{custom_code = "TensorListStack", custom_option = #tfl<const_bytes : "0x">}> : (tensor<!tf_type.variant<tensor<*xi32>>>, tensor<i32>) -> tensor<*xi32>
func.return %0 : tensor<*xi32>
}
// -----
// CHECK-LABEL: listSetItem
func.func @listSetItem(%arg0: tensor<!tf_type.variant<tensor<*xi32>>>, %arg1: tensor<i32>, %arg2: tensor<*xi32>) -> tensor<!tf_type.variant<tensor<*xi32>>> {
%0 = "tf.TensorListSetItem"(%arg0, %arg1, %arg2) : (tensor<!tf_type.variant<tensor<*xi32>>>, tensor<i32>, tensor<*xi32>) -> tensor<!tf_type.variant<tensor<*xi32>>>
// CHECK: %0 = "tfl.custom"(%arg0, %arg1, %arg2) <{custom_code = "TensorListSetItem", custom_option = #tfl<const_bytes : "0x">}> : (tensor<!tf_type.variant<tensor<*xi32>>>, tensor<i32>, tensor<*xi32>) -> tensor<!tf_type.variant<tensor<*xi32>>>
func.return %0 : tensor<!tf_type.variant<tensor<*xi32>>>
}
// -----
// CHECK-LABEL: listGetItem
func.func @listGetItem(%arg0: tensor<!tf_type.variant<tensor<*xi32>>>, %arg1: tensor<i32>, %arg2: tensor<2xi32>) -> tensor<2xi32> {
%0 = "tf.TensorListGetItem"(%arg0, %arg1, %arg2) : (tensor<!tf_type.variant<tensor<*xi32>>>, tensor<i32>, tensor<2xi32>) -> tensor<2xi32>
// CHECK: %0 = "tfl.custom"(%arg0, %arg1, %arg2) <{custom_code = "TensorListGetItem", custom_option = #tfl<const_bytes : "0x">}> : (tensor<!tf_type.variant<tensor<*xi32>>>, tensor<i32>, tensor<2xi32>) -> tensor<2xi32>
func.return %0 : tensor<2xi32>
}
// -----
// CHECK-LABEL: listFromTensor
func.func @listFromTensor(%tensor: tensor<3xi32>, %shape : tensor<?xi32>) -> tensor<!tf_type.variant<tensor<i32>>> {
%0 = "tf.TensorListFromTensor"(%tensor, %shape) : (tensor<3xi32>, tensor<?xi32>) -> tensor<!tf_type.variant<tensor<i32>>>
func.return %0 : tensor<!tf_type.variant<tensor<i32>>>
// CHECK: %0 = "tfl.custom"(%arg0, %arg1) <{custom_code = "TensorListFromTensor", custom_option = #tfl<const_bytes : "0x">}> : (tensor<3xi32>, tensor<?xi32>) -> tensor<!tf_type.variant<tensor<i32>>>
}
// -----
// CHECK-LABEL: typeNotSupportedNotLegalized
func.func @typeNotSupportedNotLegalized(%arg0: tensor<!tf_type.variant<tensor<*xf64>>>, %arg1: tensor<i32>, %arg2: tensor<*xf64>) -> tensor<!tf_type.variant<tensor<*xf64>>> {
%0 = "tf.TensorListSetItem"(%arg0, %arg1, %arg2) : (tensor<!tf_type.variant<tensor<*xf64>>>, tensor<i32>, tensor<*xf64>) -> tensor<!tf_type.variant<tensor<*xf64>>>
// CHECK-NOT: "tfl.custom"
// CHECK-MSG: Tried legalizing to tfl custom tensorlist ops, but not all can be supported.
func.return %0 : tensor<!tf_type.variant<tensor<*xf64>>>
}
// -----
// CHECK-LABEL: listLength
func.func @listLength(%arg0: tensor<!tf_type.variant<tensor<*xi32>>>) -> tensor<i32> {
%0 = "tf.TensorListLength"(%arg0) : (tensor<!tf_type.variant<tensor<*xi32>>>) -> tensor<i32>
// CHECK: %0 = "tfl.custom"(%arg0) <{custom_code = "TensorListLength", custom_option = #tfl<const_bytes : "0x">}> : (tensor<!tf_type.variant<tensor<*xi32>>>) -> tensor<i32>
func.return %0 : tensor<i32>
}
// -----
// CHECK-LABEL: listEmptyToListReserve
func.func @listEmptyToListReserve(%arg0: tensor<?xi32>, %arg1: tensor<i32>) -> tensor<!tf_type.variant<tensor<*xi64>>> {
%0 = "tf.EmptyTensorList"(%arg0, %arg1) : (tensor<?xi32>, tensor<i32>) -> tensor<!tf_type.variant<tensor<*xi64>>>
// CHECK: %cst = arith.constant dense<0> : tensor<i32>
// CHECK: %0 = "tfl.custom"(%arg0, %cst) <{custom_code = "TensorListReserve", custom_option = #tfl<const_bytes : "0x04">}> : (tensor<?xi32>, tensor<i32>) -> tensor<!tf_type.variant<tensor<*xi64>>>
func.return %0 : tensor<!tf_type.variant<tensor<*xi64>>>
}
// -----
// CHECK-LABEL: listElementShape
func.func @listElementShape(%arg0: tensor<!tf_type.variant<tensor<*xi32>>>) -> tensor<*xi32> {
%0 = "tf.TensorListElementShape"(%arg0) : (tensor<!tf_type.variant<tensor<*xi32>>>) -> tensor<*xi32>
// CHECK: %0 = "tfl.custom"(%arg0) <{custom_code = "TensorListElementShape", custom_option = #tfl<const_bytes : "0x">}> : (tensor<!tf_type.variant<tensor<*xi32>>>) -> tensor<*xi32>
func.return %0 : tensor<*xi32>
}
// -----
// CHECK-LABEL: listPopBack
func.func @listPopBack(%arg0: tensor<!tf_type.variant<tensor<2xi32>>>, %arg1: tensor<1xi32>) -> (tensor<!tf_type.variant<tensor<2xi32>>>, tensor<2xi32>) {
%0, %1 = "tf.TensorListPopBack"(%arg0, %arg1) : (tensor<!tf_type.variant<tensor<2xi32>>>, tensor<1xi32>) -> (tensor<!tf_type.variant<tensor<2xi32>>>, tensor<2xi32>)
// CHECK: %0:2 = "tfl.custom"(%arg0, %arg1) <{custom_code = "TensorListPopBack", custom_option = #tfl<const_bytes : "0x">}> : (tensor<!tf_type.variant<tensor<2xi32>>>, tensor<1xi32>) -> (tensor<!tf_type.variant<tensor<2xi32>>>, tensor<2xi32>)
func.return %0, %1 : tensor<!tf_type.variant<tensor<2xi32>>>, tensor<2xi32>
}
// -----
// CHECK-LABEL: listPushBack
func.func @listPushBack(%arg0: tensor<!tf_type.variant<tensor<?x1xf32>>>, %arg1: tensor<16x1xf32>) -> tensor<!tf_type.variant<tensor<?x1xf32>>> {
%0 = "tf.TensorListPushBack"(%arg0, %arg1) : (tensor<!tf_type.variant<tensor<?x1xf32>>>, tensor<16x1xf32>) -> tensor<!tf_type.variant<tensor<?x1xf32>>>
// CHECK: %0 = "tfl.custom"(%arg0, %arg1) <{custom_code = "TensorListPushBack", custom_option = #tfl<const_bytes : "0x">}> : (tensor<!tf_type.variant<tensor<?x1xf32>>>, tensor<16x1xf32>) -> tensor<!tf_type.variant<tensor<?x1xf32>>>
func.return %0: tensor<!tf_type.variant<tensor<?x1xf32>>>
}
// -----
// CHECK-LABEL: variantAddN
func.func @variantAddN(%arg0: tensor<!tf_type.variant<tensor<*xi32>>>, %arg1: tensor<!tf_type.variant<tensor<*xi32>>>) -> tensor<!tf_type.variant<tensor<*xi32>>> {
%1 = "tf.AddN"(%arg0, %arg1) : (tensor<!tf_type.variant<tensor<*xi32>>>, tensor<!tf_type.variant<tensor<*xi32>>>) -> tensor<!tf_type.variant<tensor<*xi32>>>
// CHECK: %0 = "tfl.custom"(%arg0, %arg1) <{custom_code = "VariantAddN", custom_option = #tfl<const_bytes : "0x">}> : (tensor<!tf_type.variant<tensor<*xi32>>>, tensor<!tf_type.variant<tensor<*xi32>>>) -> tensor<!tf_type.variant<tensor<*xi32>>>
func.return %1 : tensor<!tf_type.variant<tensor<*xi32>>>
}
// -----
// CHECK-LABEL: variantZeroesLikeNoLegalize
func.func @variantZeroesLikeNoLegalize(%arg0: tensor<i32>, %arg1: tensor<i32>) -> tensor<!tf_type.variant<tensor<*xi64>>> {
%0 = "tf.TensorListReserve"(%arg0, %arg1) : (tensor<i32>, tensor<i32>) -> tensor<!tf_type.variant<tensor<*xi64>>>
%1 = "tf.ZerosLike"(%0) : (tensor<!tf_type.variant<tensor<*xi64>>>) -> tensor<!tf_type.variant<tensor<*xi64>>>
// CHECK-NOT: "tfl.custom"
// CHECK-MSG: Tried legalizing to tfl custom tensorlist ops, but not all can be supported.
func.return %1 : tensor<!tf_type.variant<tensor<*xi64>>>
}
@@ -0,0 +1,25 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: litert-opt %s -tfl-legalize-tf='preserve-assert-op=true' | FileCheck %s --dump-input=fail
func.func @preserve_assert(%arg0: tensor<1xi32>, %arg1: tensor<1xi32>) -> tensor<1xi1> {
%0 = "tf.LessEqual"(%arg0, %arg1) : (tensor<1xi32>, tensor<1xi32>) -> tensor<1xi1>
"tf.Assert"(%0, %arg1) {summarize = 3} : (tensor<1xi1>, tensor<1xi32>) -> ()
func.return %0 : tensor<1xi1>
// CHECK-LABEL: preserve_assert
// CHECK: tfl.less_equal
// CHECK: Assert
// CHECK: return
}
@@ -0,0 +1,148 @@
// Copyright 2026 The TensorFlow Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ==============================================================================
// RUN: litert-opt %s -split-input-file -tfl-legalize-hashtables-tf --cse | FileCheck %s
// Test for case with string -> int64 hashtable.
func.func @hashtable_string_to_int64(%arg0: tensor<i64>) -> tensor<*xi64> {
%cst = arith.constant dense<"f"> : tensor<!tf_type.string>
%0 = "tf.HashTableV2"() {container = "", device = "", key_dtype = !tf_type.string, shared_name = "hash_table_e308c10b-91c8-416c-81f9-af5bf6aba847", use_node_name_sharing = false, value_dtype = i64} : () -> tensor<!tf_type.resource>
%1 = "tf.LookupTableFindV2"(%0, %cst, %arg0) {device = ""} : (tensor<!tf_type.resource>, tensor<!tf_type.string>, tensor<i64>) -> tensor<*xi64>
// CHECK-LABEL: hashtable_string_to_int64
// CHECK: [[CST:%.*]] = arith.constant dense<"f"> : tensor<!tf_type.string>
// CHECK-NEXT: [[HASH_TABLE:%.*]] = "tfl.hashtable"() <{key_dtype = !tf_type.string, table_id = {{[-]?[0-9]+}} : i32, value_dtype = i64}> : () -> tensor<1x!tf_type.resource>
// CHECK-NEXT: [[FIND:%.*]] = "tfl.hashtable_find"([[HASH_TABLE]], [[CST]], %arg0) : (tensor<1x!tf_type.resource>, tensor<!tf_type.string>, tensor<i64>) -> tensor<*xi64>
// CHECK-NEXT: return [[FIND]] : tensor<*xi64>
func.return %1 : tensor<*xi64>
}
// -----
// Test for case with int64 -> string hashtable.
func.func @hashtable_int64_to_string(%arg0: tensor<i64>) -> tensor<*x!tf_type.string> {
%cst = arith.constant dense<"f"> : tensor<!tf_type.string>
%0 = "tf.HashTableV2"() {container = "", device = "", key_dtype = i64, shared_name = "hash_table_e308c10b-91c8-416c-81f9-af5bf6aba847", use_node_name_sharing = false, value_dtype = !tf_type.string} : () -> tensor<!tf_type.resource>
%1 = "tf.LookupTableFindV2"(%0, %arg0, %cst) {device = ""} : (tensor<!tf_type.resource>, tensor<i64>, tensor<!tf_type.string>) -> tensor<*x!tf_type.string>
// CHECK-LABEL: hashtable_int64_to_string
// CHECK: [[CST:%.*]] = arith.constant dense<"f"> : tensor<!tf_type.string>
// CHECK-NEXT: [[HASH_TABLE:%.*]] = "tfl.hashtable"() <{key_dtype = i64, table_id = {{[-]?[0-9]+}} : i32, value_dtype = !tf_type.string}> : () -> tensor<1x!tf_type.resource>
// CHECK-NEXT: [[FIND:%.*]] = "tfl.hashtable_find"([[HASH_TABLE]], %arg0, [[CST]]) : (tensor<1x!tf_type.resource>, tensor<i64>, tensor<!tf_type.string>) -> tensor<*x!tf_type.string>
// CHECK-NEXT: return [[FIND]] : tensor<*x!tf_type.string>
func.return %1 : tensor<*x!tf_type.string>
}
// -----
// Test for case with unsupported string -> string mapping.
func.func @no_legalization_on_hashtable_string_to_string(%arg0: tensor<!tf_type.string>) {
%0 = "tf.HashTableV2"() {container = "", device = "", key_dtype = !tf_type.string, shared_name = "hash_table_e308c10b-91c8-416c-81f9-af5bf6aba847", use_node_name_sharing = false, value_dtype = !tf_type.string} : () -> tensor<!tf_type.resource>
"tf.LookupTableRemoveV2"(%0, %arg0) {device = ""} : (tensor<!tf_type.resource>, tensor<!tf_type.string>) -> ()
// CHECK-LABEL: no_legalization_on_hashtable_string_to_string
// CHECK-NEXT: "tf.HashTableV2"
// CHECK-NEXT: "tf.LookupTableRemoveV2"
func.return
}
// -----
// Test for case with import op.
func.func @hashtable_import(%arg0: tensor<5x!tf_type.string>) {
%cst = arith.constant dense<["emerson", "lake", "palmer"]> : tensor<3x!tf_type.string>
%cst_0 = arith.constant dense<[0, 1, 2]> : tensor<3xi64>
%0 = "tf.HashTableV2"() {container = "", device = "", key_dtype = !tf_type.string, shared_name = "hash_table_1dd4fef4-646d-491f-a3a8-bf5334f45813", use_node_name_sharing = false, value_dtype = i64} : () -> tensor<!tf_type.resource>
"tf.LookupTableImportV2"(%0, %cst, %cst_0) {device = ""} : (tensor<!tf_type.resource>, tensor<3x!tf_type.string>, tensor<3xi64>) -> ()
func.return
// CHECK-LABEL: hashtable_import
// CHECK: [[CST:%.*]] = arith.constant dense<["emerson", "lake", "palmer"]> : tensor<3x!tf_type.string>
// CHECK-NEXT: [[CST_0:%.*]] = arith.constant dense<[0, 1, 2]> : tensor<3xi64>
// CHECK-NEXT: [[HASH_TABLE:%.*]] = "tfl.hashtable"() <{key_dtype = !tf_type.string, table_id = {{[-]?[0-9]+}} : i32, value_dtype = i64}> : () -> tensor<1x!tf_type.resource>
// CHECK-NEXT: "tfl.hashtable_import"([[HASH_TABLE]], [[CST]], [[CST_0]]) : (tensor<1x!tf_type.resource>, tensor<3x!tf_type.string>, tensor<3xi64>) -> ()
}
// -----
// Test for case with size op.
func.func @hashtable_size(%arg0: tensor<5x!tf_type.string>) -> tensor<i64> {
%0 = "tf.HashTableV2"() {container = "", device = "", key_dtype = !tf_type.string, shared_name = "hash_table_1dd4fef4-646d-491f-a3a8-bf5334f45813", use_node_name_sharing = false, value_dtype = i64} : () -> tensor<!tf_type.resource>
%1 = "tf.LookupTableSizeV2"(%0) {device = ""} : (tensor<!tf_type.resource>) -> tensor<i64>
// CHECK-LABEL: hashtable_size
// CHECK-NEXT: [[HASH_TABLE:%.*]] = "tfl.hashtable"() <{key_dtype = !tf_type.string, table_id = {{[-]?[0-9]+}} : i32, value_dtype = i64}> : () -> tensor<1x!tf_type.resource>
// CHECK-NEXT: [[SIZE:%.*]] = "tfl.hashtable_size"([[HASH_TABLE]]) : (tensor<1x!tf_type.resource>) -> tensor<i64>
// CHECK-NEXT: return [[SIZE]] : tensor<i64>
func.return %1 : tensor<i64>
}
// -----
// Test for case with import and find ops.
func.func @hashtable_import_then_find(%arg0: tensor<5x!tf_type.string>) -> tensor<*xi64> {
%cst = arith.constant dense<["emerson", "lake", "palmer"]> : tensor<3x!tf_type.string>
%cst_0 = arith.constant dense<-1> : tensor<i64>
%cst_1 = arith.constant dense<[0, 1, 2]> : tensor<3xi64>
%0 = "tf.HashTableV2"() {container = "", device = "", key_dtype = !tf_type.string, shared_name = "hash_table_1dd4fef4-646d-491f-a3a8-bf5334f45813", use_node_name_sharing = false, value_dtype = i64} : () -> tensor<!tf_type.resource>
"tf.LookupTableImportV2"(%0, %cst, %cst_1) {device = ""} : (tensor<!tf_type.resource>, tensor<3x!tf_type.string>, tensor<3xi64>) -> ()
%1 = "tf.LookupTableFindV2"(%0, %arg0, %cst_0) {device = ""} : (tensor<!tf_type.resource>, tensor<5x!tf_type.string>, tensor<i64>) -> tensor<*xi64>
// CHECK-LABEL: hashtable_import_then_find
// CHECK: [[CST:%.*]] = arith.constant dense<["emerson", "lake", "palmer"]> : tensor<3x!tf_type.string>
// CHECK-NEXT: [[CST_0:%.*]] = arith.constant dense<-1> : tensor<i64>
// CHECK-NEXT: [[CST_1:%.*]] = arith.constant dense<[0, 1, 2]> : tensor<3xi64>
// CHECK-NEXT: [[HASH_TABLE:%.*]] = "tfl.hashtable"() <{key_dtype = !tf_type.string, table_id = {{[-]?[0-9]+}} : i32, value_dtype = i64}> : () -> tensor<1x!tf_type.resource>
// CHECK-NEXT: "tfl.hashtable_import"([[HASH_TABLE]], [[CST]], [[CST_1]]) : (tensor<1x!tf_type.resource>, tensor<3x!tf_type.string>, tensor<3xi64>) -> ()
// CHECK-NEXT: [[FIND:%.*]] = "tfl.hashtable_find"([[HASH_TABLE]], %arg0, [[CST_0]]) : (tensor<1x!tf_type.resource>, tensor<5x!tf_type.string>, tensor<i64>) -> tensor<*xi64>
// CHECK-NEXT: return [[FIND]] : tensor<*xi64>
func.return %1 : tensor<*xi64>
}
// -----
// Test for case with import and size ops.
func.func @hashtable_import_then_size(%arg0: tensor<5x!tf_type.string>) -> tensor<i64> {
%cst = arith.constant dense<["emerson", "lake", "palmer"]> : tensor<3x!tf_type.string>
%cst_0 = arith.constant dense<[0, 1, 2]> : tensor<3xi64>
%0 = "tf.HashTableV2"() {container = "", device = "", key_dtype = !tf_type.string, shared_name = "hash_table_1dd4fef4-646d-491f-a3a8-bf5334f45813", use_node_name_sharing = false, value_dtype = i64} : () -> tensor<!tf_type.resource>
"tf.LookupTableImportV2"(%0, %cst, %cst_0) {device = ""} : (tensor<!tf_type.resource>, tensor<3x!tf_type.string>, tensor<3xi64>) -> ()
%1 = "tf.LookupTableSizeV2"(%0) {device = ""} : (tensor<!tf_type.resource>) -> tensor<i64>
// CHECK-LABEL: hashtable_import_then_size
// CHECK: [[CST:%.*]] = arith.constant dense<["emerson", "lake", "palmer"]> : tensor<3x!tf_type.string>
// CHECK-NEXT: [[CST_0:%.*]] = arith.constant dense<[0, 1, 2]> : tensor<3xi64>
// CHECK-NEXT: [[HASH_TABLE:%.*]] = "tfl.hashtable"() <{key_dtype = !tf_type.string, table_id = {{[-]?[0-9]+}} : i32, value_dtype = i64}> : () -> tensor<1x!tf_type.resource>
// CHECK-NEXT: "tfl.hashtable_import"([[HASH_TABLE]], [[CST]], [[CST_0]]) : (tensor<1x!tf_type.resource>, tensor<3x!tf_type.string>, tensor<3xi64>) -> ()
// CHECK-NEXT: [[SIZE:%.*]] = "tfl.hashtable_size"([[HASH_TABLE]]) : (tensor<1x!tf_type.resource>) -> tensor<i64>
// CHECK-NEXT: return [[SIZE]] : tensor<i64>
func.return %1 : tensor<i64>
}
// -----
// Test for case with unsupported LookupTableRemoveV2 op.
func.func @no_legalization_on_hashtable_remove(%arg0: tensor<i64>) {
%0 = "tf.HashTableV2"() {container = "", device = "", key_dtype = i64, shared_name = "hash_table_e308c10b-91c8-416c-81f9-af5bf6aba847", use_node_name_sharing = false, value_dtype = !tf_type.string} : () -> tensor<!tf_type.resource>
"tf.LookupTableRemoveV2"(%0, %arg0) {device = ""} : (tensor<!tf_type.resource>, tensor<i64>) -> ()
// CHECK-LABEL: no_legalization_on_hashtable_remove
// CHECK-NEXT: "tf.HashTableV2"
// CHECK-NEXT: "tf.LookupTableRemoveV2"
func.return
}
// -----
// Test for case with unsupported MutableHashTableV2 op.
func.func @no_legalization_on_mutable_hashtable(%arg0: tensor<i64>) {
%0 = "tf.MutableHashTableV2Op"() {container = "", key_dtype = i64, use_node_name_sharing = false, value_dtype = !tf_type.string} : () -> tensor<!tf_type.resource>
"tf.LookupTableRemoveV2"(%0, %arg0) {device = ""} : (tensor<!tf_type.resource>, tensor<i64>) -> ()
// CHECK-LABEL: no_legalization_on_mutable_hashtable
// CHECK-NEXT: "tf.MutableHashTableV2Op"
// CHECK-NEXT: "tf.LookupTableRemoveV2"
func.return
}

Some files were not shown because too many files have changed in this diff Show More