// RUN: mlir-opt -canonicalize="test-convergence" %s | FileCheck %s // CHECK-LABEL: @argmax_nofold func.func @argmax_nofold(%arg0: tensor) -> tensor { // CHECK: tosa.argmax %0 = tosa.argmax %arg0 {axis = 0 : i32}: (tensor) -> tensor return %0 : tensor } // CHECK-LABEL: @add_bcast_zero_int func.func @add_bcast_zero_int(%arg0: tensor<4x2x3xi32>) -> tensor<4x2x3xi32> { // CHECK-NOT: tosa.add // CHECK: return %arg0 %zeros = "tosa.const"() {value = dense<0> : tensor<1x1x1xi32>} : () -> tensor<1x1x1xi32> %1 = tosa.add %arg0, %zeros : (tensor<4x2x3xi32>, tensor<1x1x1xi32>) -> tensor<4x2x3xi32> return %1 : tensor<4x2x3xi32> } // CHECK-LABEL: @add_zero_int func.func @add_zero_int(%arg0: tensor<2x3xi32>) -> tensor<2x3xi32> { // CHECK: return %arg0 // CHECK-NOT: tosa.add %zeros = "tosa.const"() {value = dense<0> : tensor<2x3xi32>} : () -> tensor<2x3xi32> %1 = tosa.add %arg0, %zeros : (tensor<2x3xi32>, tensor<2x3xi32>) -> tensor<2x3xi32> return %1 : tensor<2x3xi32> } // CHECK-LABEL: @cast_fold func.func @cast_fold(%arg0: tensor) -> tensor { // CHECK: return %arg0 %0 = tosa.cast %arg0 : (tensor) -> tensor return %0 : tensor } // CHECK-LABEL: @cast_nofold func.func @cast_nofold(%arg0: tensor) -> tensor { // CHECK: tosa.cast %0 = tosa.cast %arg0 : (tensor) -> tensor return %0 : tensor } // CHECK-LABEL: @clamp_i32_not_noop func.func @clamp_i32_not_noop(%arg0: tensor<4xi32>) -> tensor<4xi32> { // CHECK: tosa.clamp %0 = tosa.clamp %arg0 {min_int = 1 : i64, max_int = 4 : i64, min_fp = 1.0 : f32, max_fp = 4.0 : f32} : (tensor<4xi32>) -> tensor<4xi32> return %0 : tensor<4xi32> } // CHECK-LABEL: @clamp_f16_not_noop func.func @clamp_f16_not_noop(%arg0: tensor<4xf16>) -> tensor<4xf16> { // CHECK: tosa.clamp %0 = tosa.clamp %arg0 {min_int = -128 : i64, max_int = 127 : i64, min_fp = -3.40282347E+38 : f32, max_fp = 3.40282347E+38 : f32} : (tensor<4xf16>) -> tensor<4xf16> return %0 : tensor<4xf16> } // CHECK-LABEL: @clamp_f32_not_noop func.func @clamp_f32_not_noop(%arg0: tensor<4xf32>) -> tensor<4xf32> { // CHECK: tosa.clamp %0 = tosa.clamp %arg0 {min_int = -128 : i64, max_int = 127 : i64, min_fp = -3.40282347E+38 : f32, max_fp = 3.40282347E+38 : f32} : (tensor<4xf32>) -> tensor<4xf32> return %0 : tensor<4xf32> } // CHECK-LABEL: @clamp_f16_is_noop func.func @clamp_f16_is_noop(%arg0: tensor<4xf16>) -> tensor<4xf16> { // CHECK: return %arg0 // CHECK-NOT: "tosa.clamp" // 0xFF800000 and 0x7F800000 are respectively negative and positive F32 infinity. %0 = tosa.clamp %arg0 {min_int = -128 : i64, max_int = 127 : i64, min_fp = 0xFF800000 : f32, max_fp = 0x7F800000 : f32} : (tensor<4xf16>) -> tensor<4xf16> return %0 : tensor<4xf16> } // CHECK-LABEL: @clamp_f32_is_noop func.func @clamp_f32_is_noop(%arg0: tensor<4xf32>) -> tensor<4xf32> { // CHECK: return %arg0 // CHECK-NOT: "tosa.clamp" // 0xFF800000 and 0x7F800000 are respectively negative and positive F32 infinity. %0 = tosa.clamp %arg0 {min_int = -128 : i64, max_int = 127 : i64, min_fp = 0xFF800000 : f32, max_fp = 0x7F800000 : f32} : (tensor<4xf32>) -> tensor<4xf32> return %0 : tensor<4xf32> } // CHECK-LABEL: @clamp_int8_is_noop func.func @clamp_int8_is_noop(%arg0: tensor<4xi8>) -> tensor<4xi8> { // CHECK: return %arg0 // CHECK-NOT: tosa.clamp %0 = tosa.clamp %arg0 {min_int = -128 : i64, max_int = 127 : i64, min_fp = -3.40282347E+38 : f32, max_fp = 3.40282347E+38 : f32} : (tensor<4xi8>) -> tensor<4xi8> return %0 : tensor<4xi8> } // CHECK-LABEL: @clamp_int16_is_noop func.func @clamp_int16_is_noop(%arg0: tensor<4xi16>) -> tensor<4xi16> { // CHECK: return %arg0 // CHECK-NOT: tosa.clamp %0 = tosa.clamp %arg0 {min_int = -32768 : i64, max_int = 32767 : i64, min_fp = -3.40282347E+38 : f32, max_fp = 3.40282347E+38 : f32} : (tensor<4xi16>) -> tensor<4xi16> return %0 : tensor<4xi16> } // CHECK-LABEL: @clamp_uint8_is_noop func.func @clamp_uint8_is_noop(%arg0: tensor<4xui8>) -> tensor<4xui8> { // CHECK: return %arg0 // CHECK-NOT: tosa.clamp %0 = tosa.clamp %arg0 {min_int = 0 : i64, max_int = 255 : i64, min_fp = -3.40282347E+38 : f32, max_fp = 3.40282347E+38 : f32} : (tensor<4xui8>) -> tensor<4xui8> return %0 : tensor<4xui8> } // CHECK-LABEL: @clamp_twice_is_single_clamp func.func @clamp_twice_is_single_clamp(%arg0: tensor<4xi8>) -> tensor<4xi8> { // CHECK: tosa.clamp %arg0 {max_fp = 3.000000e+00 : f32, max_int = 2 : i64, min_fp = -3.000000e+00 : f32, min_int = -2 : i64} %0 = tosa.clamp %arg0 {max_fp = 3.0 : f32, max_int = 4 : i64, min_fp = -5.0 : f32, min_int = -2 : i64} : (tensor<4xi8>) -> tensor<4xi8> %1 = tosa.clamp %0 {max_fp = 5.0 : f32, max_int = 2 : i64, min_fp = -3.0 : f32, min_int = -4 : i64} : (tensor<4xi8>) -> tensor<4xi8> return %1 : tensor<4xi8> } // CHECK-LABEL: @concat_fold func.func @concat_fold(%arg0: tensor) -> tensor { // CHECK: return %arg0 %0 = tosa.concat %arg0 {axis = 0 : i32}: (tensor) -> tensor return %0 : tensor } // CHECK-LABEL: @concat_fold_cast func.func @concat_fold_cast(%arg0: tensor) -> tensor { // CHECK: %[[VAR0:.*]] = tensor.cast %arg0 // CHECK: return %[[VAR0]] %0 = tosa.concat %arg0 {axis = 0 : i32}: (tensor) -> tensor return %0 : tensor } // CHECK-LABEL: @conv2d_stride_2 func.func @conv2d_stride_2(%arg0: tensor<4x10x10x2xf32>) -> tensor<4x10x10x3xf32> { // CHECK: tosa.conv2d %weight = "tosa.const"() {value = dense<[[[[1.0, 1.0]]], [[[1.0, 1.0]]], [[[1.0, 1.0]]]]> : tensor<3x1x1x2xf32>} : ()-> tensor<3x1x1x2xf32> %bias = "tosa.const"() {value = dense<0.0> : tensor<3xf32>} : ()-> tensor<3xf32> %0 = tosa.conv2d %arg0, %weight, %bias {pad = array, stride = array, dilation = array} : (tensor<4x10x10x2xf32>, tensor<3x1x1x2xf32>, tensor<3xf32>) -> tensor<4x10x10x3xf32> return %0 : tensor<4x10x10x3xf32> } // CHECK-LABEL: @conv2d_weight_2x2 func.func @conv2d_weight_2x2(%arg0: tensor<4x10x10x1xf32>) -> tensor<4x10x10x1xf32> { // CHECK: tosa.conv2d %weight = "tosa.const"() {value = dense<[[[[1.0], [1.0]], [[1.0], [1.0]]]]> : tensor<1x2x2x1xf32>} : ()-> tensor<1x2x2x1xf32> %bias = "tosa.const"() {value = dense<0.0> : tensor<1xf32>} : ()-> tensor<1xf32> %0 = tosa.conv2d %arg0, %weight, %bias {pad = array, stride = array, dilation = array} : (tensor<4x10x10x1xf32>, tensor<1x2x2x1xf32>, tensor<1xf32>) -> tensor<4x10x10x1xf32> return %0 : tensor<4x10x10x1xf32> } // CHECK-LABEL: @depthwise_conv2d_stride_2 func.func @depthwise_conv2d_stride_2(%arg0: tensor<4x10x10x2xf32>, %arg1: tensor<1x1x2x3xf32>, %arg2: tensor<6xf32>) -> tensor<4x10x10x6xf32> { // CHECK: tosa.depthwise_conv2d %0 = tosa.depthwise_conv2d %arg0, %arg1, %arg2 {pad = array, stride = array, dilation = array} : (tensor<4x10x10x2xf32>, tensor<1x1x2x3xf32>, tensor<6xf32>) -> tensor<4x10x10x6xf32> return %0 : tensor<4x10x10x6xf32> } // CHECK-LABEL: @depthwise_conv2d_weight_2x2 func.func @depthwise_conv2d_weight_2x2(%arg0: tensor<4x10x10x2xf32>, %arg1: tensor<2x2x2x3xf32>, %arg2: tensor<6xf32>) -> tensor<4x10x10x6xf32> { // CHECK: tosa.depthwise_conv2d %0 = tosa.depthwise_conv2d %arg0, %arg1, %arg2 {pad = array, stride = array, dilation = array} : (tensor<4x10x10x2xf32>, tensor<2x2x2x3xf32>, tensor<6xf32>) -> tensor<4x10x10x6xf32> return %0 : tensor<4x10x10x6xf32> } // CHECK-LABEL: @max_pool2d_is_noop func.func @max_pool2d_is_noop(%arg0: tensor<10x1x1x3xf32>) -> tensor<10x1x1x3xf32> { // CHECK-NOT: tosa.max_pool2d // CHECK: return %arg0 %0 = tosa.max_pool2d %arg0 {kernel = array, pad = array, stride = array, dilation = array} : (tensor<10x1x1x3xf32>) -> tensor<10x1x1x3xf32> return %0 : tensor<10x1x1x3xf32> } // CHECK-LABEL: @pad_noop func.func @pad_noop(%arg0: tensor) -> tensor { // CHECK: return %arg0 %0 = "tosa.const"() { value = dense<0> : tensor<2x2xi32>} : () -> tensor<2x2xi32> %1 = tosa.pad %arg0, %0 : (tensor, tensor<2x2xi32>) -> tensor return %1 : tensor } // CHECK-LABEL: @pad_determine_val_i32 func.func @pad_determine_val_i32(%arg0: tensor, %arg1 : tensor<2x2xi32>) -> tensor { // CHECK: %[[ZERO:.+]] = "tosa.const"() <{value = dense<0> : tensor} // CHECK: tosa.pad %arg0, %arg1, %[[ZERO]] %0 = "tosa.const"() { value = dense<[[1, 0], [0, 1]]> : tensor<2x2xi32>} : () -> tensor<2x2xi32> %1 = tosa.pad %arg0, %arg1 : (tensor, tensor<2x2xi32>) -> tensor return %1 : tensor } // CHECK-LABEL: @pad_determine_val_f32 func.func @pad_determine_val_f32(%arg0: tensor, %arg1 : tensor<2x2xi32>) -> tensor { // CHECK: %[[ZERO:.+]] = "tosa.const"() <{value = dense<0.000000e+00> : tensor} // CHECK: tosa.pad %arg0, %arg1, %[[ZERO]] %0 = "tosa.const"() { value = dense<[[1, 0], [0, 1]]> : tensor<2x2xi32>} : () -> tensor<2x2xi32> %1 = tosa.pad %arg0, %arg1 : (tensor, tensor<2x2xi32>) -> tensor return %1 : tensor } // CHECK-LABEL: @pad_determine_val_quant func.func @pad_determine_val_quant(%arg0: tensor, %arg1 : tensor<2x2xi32>) -> tensor { // CHECK: %[[ZERO:.+]] = "tosa.const"() <{value = dense<42> : tensor} // CHECK: tosa.pad %arg0, %arg1, %[[ZERO]] %0 = "tosa.const"() { value = dense<[[1, 0], [0, 1]]> : tensor<2x2xi32>} : () -> tensor<2x2xi32> %1 = tosa.pad %arg0, %arg1 {quantization_info = #tosa.pad_quant} : (tensor, tensor<2x2xi32>) -> tensor return %1 : tensor } // CHECK-LABEL: @mul_one_float func.func @mul_one_float(%arg0: tensor<2x3xf32>) -> tensor<2x3xf32> { // CHECK: return %arg0 // CHECK-NOT: tosa.mul %ones = "tosa.const"() {value = dense<1.0> : tensor<2x3xf32>} : () -> tensor<2x3xf32> %1 = tosa.mul %arg0, %ones {shift = 0 : i8} : (tensor<2x3xf32>, tensor<2x3xf32>) -> tensor<2x3xf32> return %1 : tensor<2x3xf32> } // CHECK-LABEL: @mul_bcast_one_float func.func @mul_bcast_one_float(%arg0: tensor<2x3xf32>) -> tensor<2x3xf32> { // CHECK: return %arg0 // CHECK-NOT: tosa.mul %ones = "tosa.const"() {value = dense<1.0> : tensor<1x1xf32>} : () -> tensor<1x1xf32> %1 = tosa.mul %ones, %arg0 {shift = 0 : i8} : (tensor<1x1xf32>, tensor<2x3xf32>) -> tensor<2x3xf32> return %1 : tensor<2x3xf32> } // CHECK-LABEL: @mul_one_int func.func @mul_one_int(%arg0: tensor<2x3xi32>) -> tensor<2x3xi32> { // CHECK: return %arg0 // CHECK-NOT: tosa.mul %ones = "tosa.const"() {value = dense<1> : tensor<2x3xi32>} : () -> tensor<2x3xi32> %1 = tosa.mul %arg0, %ones {shift = 0 : i8} : (tensor<2x3xi32>, tensor<2x3xi32>) -> tensor<2x3xi32> return %1 : tensor<2x3xi32> } // CHECK-LABEL: @mul_zero_broadcast func.func @mul_zero_broadcast(%arg0: tensor<2x3xf32>) -> (tensor<2x3xf32>, tensor<2x3xf32>) { // CHECK: %[[ZERO:.*]] = "tosa.const"() <{value = dense<0.000000e+00> : tensor<2x3xf32>} // CHECK-NOT: tosa.mul %zeros = "tosa.const"() {value = dense<0.0> : tensor<1x1xf32>} : () -> tensor<1x1xf32> %1 = tosa.mul %arg0, %zeros {shift = 0 : i8} : (tensor<2x3xf32>, tensor<1x1xf32>) -> tensor<2x3xf32> // CHECK-NOT: tosa.mul // CHECK: return %[[ZERO]], %[[ZERO]] %2 = tosa.mul %zeros, %arg0 {shift = 0 : i8} : (tensor<1x1xf32>, tensor<2x3xf32>) -> tensor<2x3xf32> return %1, %2 : tensor<2x3xf32>, tensor<2x3xf32> } // CHECK-LABEL: @select_same_value func.func @select_same_value(%arg0: tensor<2x3xi1>, %arg1: tensor<2x3xi32>) -> tensor<2x3xi32> { %0 = tosa.select %arg0, %arg1, %arg1 : (tensor<2x3xi1>, tensor<2x3xi32>, tensor<2x3xi32>) -> tensor<2x3xi32> // CHECK: return %arg1 // CHECK-NOT: tosa.select return %0 : tensor<2x3xi32> } // CHECK-LABEL: @select_true_value func.func @select_true_value(%arg0: tensor<2x3xi32>, %arg1: tensor<2x3xi32>) -> tensor<2x3xi32> { %c1 = "tosa.const"() {value = dense<1> : tensor<2x3xi1>} : () -> tensor<2x3xi1> %0 = tosa.select %c1, %arg0, %arg1 : (tensor<2x3xi1>, tensor<2x3xi32>, tensor<2x3xi32>) -> tensor<2x3xi32> // CHECK: return %arg0 // CHECK-NOT: tosa.select return %0 : tensor<2x3xi32> } // CHECK-LABEL: @select_false_value func.func @select_false_value(%arg0: tensor<2x3xi32>, %arg1: tensor<2x3xi32>) -> tensor<2x3xi32> { %c0 = "tosa.const"() {value = dense<0> : tensor<2x3xi1>} : () -> tensor<2x3xi1> %0 = tosa.select %c0, %arg0, %arg1 : (tensor<2x3xi1>, tensor<2x3xi32>, tensor<2x3xi32>) -> tensor<2x3xi32> // CHECK: return %arg1 // CHECK-NOT: tosa.select return %0 : tensor<2x3xi32> } // CHECK-LABEL: @select_not_pred func.func @select_not_pred(%arg0: tensor<2x3xi1>, %arg1: tensor<2x3xi32>, %arg2: tensor<2x3xi32>) -> tensor<2x3xi32> { %0 = tosa.logical_not %arg0 : (tensor<2x3xi1>) -> tensor<2x3xi1> %1 = tosa.select %0, %arg1, %arg2 : (tensor<2x3xi1>, tensor<2x3xi32>, tensor<2x3xi32>) -> tensor<2x3xi32> // CHECK: tosa.select %arg0, %arg2, %arg1 return %1 : tensor<2x3xi32> } // CHECK-LABEL: @reduce_all_fold func.func @reduce_all_fold(%arg0: tensor) -> tensor { // CHECK: return %arg0 %0 = tosa.reduce_all %arg0 {axis = 1 : i32}: (tensor) -> tensor return %0 : tensor } // CHECK-LABEL: @reduce_all_nofold func.func @reduce_all_nofold(%arg0: tensor) -> tensor { // CHECK: tosa.reduce_all %0 = tosa.reduce_all %arg0 {axis = 0 : i32}: (tensor) -> tensor return %0 : tensor } // CHECK-LABEL: @reduce_any_fold func.func @reduce_any_fold(%arg0: tensor) -> tensor { // CHECK: return %arg0 %0 = tosa.reduce_any %arg0 {axis = 1 : i32}: (tensor) -> tensor return %0 : tensor } // CHECK-LABEL: @reduce_any_nofold func.func @reduce_any_nofold(%arg0: tensor) -> tensor { // CHECK: tosa.reduce_any %0 = tosa.reduce_any %arg0 {axis = 0 : i32}: (tensor) -> tensor return %0 : tensor } // CHECK-LABEL: @reduce_max_fold func.func @reduce_max_fold(%arg0: tensor) -> tensor { // CHECK: return %arg0 %0 = tosa.reduce_max %arg0 {axis = 1 : i32}: (tensor) -> tensor return %0 : tensor } // CHECK-LABEL: @reduce_max_nofold func.func @reduce_max_nofold(%arg0: tensor) -> tensor { // CHECK: tosa.reduce_max %0 = tosa.reduce_max %arg0 {axis = 0 : i32}: (tensor) -> tensor return %0 : tensor } // CHECK-LABEL: @reduce_min_fold func.func @reduce_min_fold(%arg0: tensor) -> tensor { // CHECK: return %arg0 %0 = tosa.reduce_min %arg0 {axis = 1 : i32}: (tensor) -> tensor return %0 : tensor } // CHECK-LABEL: @reduce_min_nofold func.func @reduce_min_nofold(%arg0: tensor) -> tensor { // CHECK: tosa.reduce_min %0 = tosa.reduce_min %arg0 {axis = 0 : i32}: (tensor) -> tensor return %0 : tensor } // CHECK-LABEL: @reduce_prod_fold func.func @reduce_prod_fold(%arg0: tensor) -> tensor { // CHECK: return %arg0 %0 = tosa.reduce_prod %arg0 {axis = 1 : i32}: (tensor) -> tensor return %0 : tensor } // CHECK-LABEL: @reduce_prod_nofold func.func @reduce_prod_nofold(%arg0: tensor) -> tensor { // CHECK: tosa.reduce_prod %0 = tosa.reduce_prod %arg0 {axis = 0 : i32}: (tensor) -> tensor return %0 : tensor } // CHECK-LABEL: @reduce_sum_fold func.func @reduce_sum_fold(%arg0: tensor) -> tensor { // CHECK: return %arg0 %0 = tosa.reduce_sum %arg0 {axis = 1 : i32}: (tensor) -> tensor return %0 : tensor } // CHECK-LABEL: @reduce_sum_nofold func.func @reduce_sum_nofold(%arg0: tensor) -> tensor { // CHECK: tosa.reduce_sum %0 = tosa.reduce_sum %arg0 {axis = 0 : i32}: (tensor) -> tensor return %0 : tensor } // CHECK-LABEL: @reshape_canonicalize func.func @reshape_canonicalize(%arg0: tensor) -> tensor { // CHECK: return %arg0 %0 = tosa.reshape %arg0 {new_shape = array}: (tensor) -> tensor return %0 : tensor } // CHECK-LABEL: @reshape_canonicalize_double func.func @reshape_canonicalize_double(%arg0: tensor) -> tensor { // CHECK: %[[VAL_1:.*]] = tosa.reshape %arg0 {new_shape = array} // CHECK: return %[[VAL_1]] %0 = tosa.reshape %arg0 {new_shape = array}: (tensor) -> tensor<5x?xf32> %1 = tosa.reshape %0 {new_shape = array}: (tensor<5x?xf32>) -> tensor return %1 : tensor } // CHECK-LABEL: @reshape_canonicalize_const func.func @reshape_canonicalize_const() -> tensor<1x5xi32> { // CHECK: %[[VAR0:.+]] = "tosa.const"() <{value = dense<{{\[\[}}0, 1, 2, 3, 4]]> : tensor<1x5xi32>} // CHECK: return %[[VAR0]] %0 = "tosa.const"() {value = dense<[0, 1, 2, 3, 4]> : tensor<5xi32>} : () -> tensor<5xi32> %1 = tosa.reshape %0 {new_shape = array} : (tensor<5xi32>) -> tensor<1x5xi32> return %1 : tensor<1x5xi32> } // CHECK-LABEL: @reshape_canonicalize_const_dynamic func.func @reshape_canonicalize_const_dynamic() -> tensor<1x?xi32> { // CHECK: tosa.reshape %0 = "tosa.const"() {value = dense<[0, 1, 2, 3, 4]> : tensor<5xi32>} : () -> tensor<5xi32> %1 = tosa.reshape %0 {new_shape = array} : (tensor<5xi32>) -> tensor<1x?xi32> return %1 : tensor<1x?xi32> } // CHECK-LABEL: @reshape_canonicalize_const_splat func.func @reshape_canonicalize_const_splat() -> (tensor<10xi32>, tensor<1x10xi32>) { // CHECK-DAG: %[[VAR0:.+]] = "tosa.const"() <{value = dense<0> : tensor<10xi32>} // CHECK-DAG: %[[VAR1:.+]] = "tosa.const"() <{value = dense<0> : tensor<1x10xi32>} // CHECK: return %[[VAR0]], %[[VAR1]] %0 = "tosa.const"() {value = dense<0> : tensor<10xi32>} : () -> tensor<10xi32> %1 = tosa.reshape %0 {new_shape = array} : (tensor<10xi32>) -> tensor<1x10xi32> return %0 , %1 : tensor<10xi32>, tensor<1x10xi32> } // CHECK-LABEL: @reshape_canonicalize_const_sparse func.func @reshape_canonicalize_const_sparse() -> (tensor<3xi32>, tensor<1x3xi32>) { // CHECK: tosa.reshape %0 = "tosa.const"() {value = dense<[1, 2, 3]> : tensor<3xi32>} : ()-> tensor<3xi32> %1 = tosa.reshape %0 {new_shape = array} : (tensor<3xi32>) -> tensor<1x3xi32> return %0 , %1 : tensor<3xi32>, tensor<1x3xi32> } // CHECK-LABEL: @reshape_canonicalize_quant func.func @reshape_canonicalize_quant() -> (tensor<1x3x!quant.uniform>) { // CHECK{LITERAL}: "tosa.const"() <{value = dense<[[1, 2, 3]]> : tensor<1x3xi8>}> : () -> tensor<1x3x!quant.uniform> %0 = "tosa.const"() {value = dense<[1, 2, 3]> : tensor<3xi8>} : ()-> tensor<3x!quant.uniform> %1 = tosa.reshape %0 {new_shape = array} : (tensor<3x!quant.uniform>) -> tensor<1x3x!quant.uniform> return %1 : tensor<1x3x!quant.uniform> } // CHECK-LABEL: @transpose_canonicalize_strip_quant func.func @transpose_canonicalize_strip_quant() -> (tensor<2x1x3xi8>) { // CHECK: "tosa.const"() <{value = dense<0> : tensor<2x1x3xi8>}> : () -> tensor<2x1x3xi8> %perms = "tosa.const"() {value = dense<[1, 0, 2]> : tensor<3xi32>} : () -> tensor<3xi32> %0 = "tosa.const"() {value = dense<0> : tensor<1x2x3xi8>} : ()-> tensor<1x2x3x!quant.uniform> %1 = tosa.transpose %0, %perms : (tensor<1x2x3x!quant.uniform>, tensor<3xi32>) -> tensor<2x1x3xi8> return %1 : tensor<2x1x3xi8> } // CHECK-LABEL: @slice_fold func.func @slice_fold(%arg0: tensor<3x4xf32>) -> tensor<3x4xf32> { // CHECK: return %arg0 %0 = tosa.slice %arg0 { size = array, start = array}: (tensor<3x4xf32>) -> tensor<3x4xf32> return %0 : tensor<3x4xf32> } // CHECK-LABEL: @slice_nofold func.func @slice_nofold(%arg0: tensor) -> tensor { // CHECK: tosa.slice %0 = tosa.slice %arg0 { size = array, start = array}: (tensor) -> tensor return %0 : tensor } // CHECK-LABEL: @tile_fold func.func @tile_fold(%arg0: tensor<3x4xf32>) -> tensor<3x4xf32> { // CHECK: return %arg0 %0 = tosa.tile %arg0 { multiples = array }: (tensor<3x4xf32>) -> tensor<3x4xf32> return %0 : tensor<3x4xf32> } // CHECK-LABEL: @tile_nofold func.func @tile_nofold(%arg0: tensor<3x4xf32>) -> tensor<3x8xf32> { // CHECK: tosa.tile %0 = tosa.tile %arg0 { multiples = array }: (tensor<3x4xf32>) -> tensor<3x8xf32> return %0 : tensor<3x8xf32> } // CHECK-LABEL: @transpose_no_op func.func @transpose_no_op(%arg0: tensor<3x4x5x6xf32>) -> tensor<3x4x5x6xf32> { // CHECK: return %arg0 // CHECK-NOT: tosa.transpose %perms = "tosa.const"() {value = dense<[0, 1, 2, 3]> : tensor<4xi32>} : () -> tensor<4xi32> %1 = tosa.transpose %arg0, %perms : (tensor<3x4x5x6xf32>, tensor<4xi32>) -> tensor<3x4x5x6xf32> return %1 : tensor<3x4x5x6xf32> } // CHECK-LABEL: @transpose_is_reshape func.func @transpose_is_reshape(%arg0: tensor<1x4x5x1xf32>) -> tensor<1x4x1x5xf32> { // CHECK: tosa.reshape %arg0 {new_shape = array} : (tensor<1x4x5x1xf32>) -> tensor<1x4x1x5xf32> %perms = "tosa.const"() <{value = dense<[3, 1, 0, 2]> : tensor<4xi32>}> : () -> tensor<4xi32> %0 = tosa.transpose %arg0, %perms : (tensor<1x4x5x1xf32>, tensor<4xi32>) -> tensor<1x4x1x5xf32> return %0 : tensor<1x4x1x5xf32> } // CHECK-LABEL: @single_bit_reshape // https://github.com/llvm/llvm-project/issues/55440 func.func @single_bit_reshape() -> tensor<1xi1> { // CHECK: "tosa.const"() <{value = dense : tensor<1xi1>} %0 = arith.constant dense : tensor<1x1xi1> %1 = tosa.reshape %0 {new_shape = array} : (tensor<1x1xi1>) -> tensor<1xi1> return %1 : tensor<1xi1> } // ----- // CHECK-LABEL: @fold_resize_nearest func.func @fold_resize_nearest(%arg0 : tensor<1x15x13x1xi8>) -> tensor<1x15x13x1xi8> { // CHECK: return %arg0 %resize = tosa.resize %arg0 {mode = "NEAREST_NEIGHBOR" , scale = array, offset = array, border = array} : (tensor<1x15x13x1xi8>) -> tensor<1x15x13x1xi8> return %resize : tensor<1x15x13x1xi8> } // ----- // CHECK-LABEL: @fold_resize_bilinear func.func @fold_resize_bilinear(%arg0 : tensor<1x15x13x1xi8>) -> tensor<1x15x13x1xi8> { // CHECK: return %arg0 %resize = tosa.resize %arg0 {mode = "BILINEAR" , scale = array, offset = array, border = array} : (tensor<1x15x13x1xi8>) -> tensor<1x15x13x1xi8> return %resize : tensor<1x15x13x1xi8> } // ----- // CHECK-LABEL: @canonicalize_concat_slice_final_axis // CHECK-SAME: %[[VAL_0:.*]]: tensor<1x12x12x1xf32>, %[[VAL_1:.*]]: tensor<1x12x12x1xf32> // CHECK: return %[[VAL_0]], %[[VAL_1]] : tensor<1x12x12x1xf32>, tensor<1x12x12x1xf32> func.func @canonicalize_concat_slice_final_axis(%arg0 : tensor<1x12x12x1xf32>, %arg1 : tensor<1x12x12x1xf32>) -> (tensor<1x12x12x1xf32>, tensor<1x12x12x1xf32>) { %0 = tosa.concat %arg0, %arg1 {axis = 3 : i32} : (tensor<1x12x12x1xf32>, tensor<1x12x12x1xf32>) -> tensor<1x12x12x2xf32> %1 = tosa.slice %0 {size = array, start = array} : (tensor<1x12x12x2xf32>) -> tensor<1x12x12x1xf32> %2 = tosa.slice %0 {size = array, start = array} : (tensor<1x12x12x2xf32>) -> tensor<1x12x12x1xf32> return %1, %2 : tensor<1x12x12x1xf32>, tensor<1x12x12x1xf32> } // ----- // CHECK-LABEL: @canonicalize_concat_slice_middle_axis // CHECK-SAME: %[[VAL_0:.*]]: tensor<1x12x12xf32>, %[[VAL_1:.*]]: tensor<1x12x12xf32> // CHECK: return %[[VAL_0]], %[[VAL_1]] : tensor<1x12x12xf32>, tensor<1x12x12xf32> func.func @canonicalize_concat_slice_middle_axis(%arg0 : tensor<1x12x12xf32>, %arg1 : tensor<1x12x12xf32>) -> (tensor<1x12x12xf32>, tensor<1x12x12xf32>) { %0 = tosa.concat %arg0, %arg1 {axis = 1 : i32} : (tensor<1x12x12xf32>, tensor<1x12x12xf32>) -> tensor<1x24x12xf32> %1 = tosa.slice %0 {size = array, start = array} : (tensor<1x24x12xf32>) -> tensor<1x12x12xf32> %2 = tosa.slice %0 {size = array, start = array} : (tensor<1x24x12xf32>) -> tensor<1x12x12xf32> return %1, %2 : tensor<1x12x12xf32>, tensor<1x12x12xf32> } // ----- // CHECK-LABEL: @canonicalize_cross_concat_inputs // CHECK-SAME: %[[VAL_0:.*]]: tensor<1x12x12xf32>, %[[VAL_1:.*]]: tensor<1x12x12xf32> // CHECK: %[[VAL_2:.*]] = tosa.concat %[[VAL_0]], %[[VAL_1]] {axis = 2 : i32} : (tensor<1x12x12xf32>, tensor<1x12x12xf32>) -> tensor<1x12x24xf32> // CHECK: %[[VAL_3:.*]] = tosa.slice %[[VAL_2]] {size = array, start = array} : (tensor<1x12x24xf32>) -> tensor<1x12x15xf32> // CHECK: %[[VAL_4:.*]] = tosa.slice %[[VAL_2]] {size = array, start = array} : (tensor<1x12x24xf32>) -> tensor<1x12x20xf32> // CHECK: return %[[VAL_3]], %[[VAL_4]] : tensor<1x12x15xf32>, tensor<1x12x20xf32> func.func @canonicalize_cross_concat_inputs(%arg0 : tensor<1x12x12xf32>, %arg1 : tensor<1x12x12xf32>) -> (tensor<1x12x15xf32>, tensor<1x12x20xf32>) { %0 = tosa.concat %arg0, %arg1 {axis = 2 : i32} : (tensor<1x12x12xf32>, tensor<1x12x12xf32>) -> tensor<1x12x24xf32> %1 = tosa.slice %0 {size = array, start = array} : (tensor<1x12x24xf32>) -> tensor<1x12x15xf32> %2 = tosa.slice %0 {size = array, start = array} : (tensor<1x12x24xf32>) -> tensor<1x12x20xf32> return %1, %2 : tensor<1x12x15xf32>, tensor<1x12x20xf32> } // ----- // CHECK-LABEL: @canonicalize_concat_slice_on_non_concat_axis // CHECK-SAME: %[[VAL_0:.*]]: tensor<1x12x12xf32>, %[[VAL_1:.*]]: tensor<1x12x12xf32> // CHECK: %[[VAL_2:.*]] = tosa.slice %[[VAL_0]] {size = array, start = array} : (tensor<1x12x12xf32>) -> tensor<1x6x12xf32> // CHECK: %[[VAL_3:.*]] = tosa.slice %[[VAL_1]] {size = array, start = array} : (tensor<1x12x12xf32>) -> tensor<1x3x12xf32> // CHECK: return %[[VAL_2]], %[[VAL_3]] : tensor<1x6x12xf32>, tensor<1x3x12xf32> func.func @canonicalize_concat_slice_on_non_concat_axis(%arg0 : tensor<1x12x12xf32>, %arg1 : tensor<1x12x12xf32>) -> (tensor<1x6x12xf32>, tensor<1x3x12xf32>) { %0 = tosa.concat %arg0, %arg1 {axis = 2 : i32} : (tensor<1x12x12xf32>, tensor<1x12x12xf32>) -> tensor<1x12x24xf32> %1 = tosa.slice %0 {size = array, start = array} : (tensor<1x12x24xf32>) -> tensor<1x6x12xf32> %2 = tosa.slice %0 {size = array, start = array} : (tensor<1x12x24xf32>) -> tensor<1x3x12xf32> return %1, %2 : tensor<1x6x12xf32>, tensor<1x3x12xf32> } // ----- // CHECK-LABEL func.func @fold_log_exp(%arg0: tensor) -> tensor { // CHECK: return %arg{{.*}} : tensor %0 = tosa.exp %arg0 : (tensor) -> tensor %1 = tosa.log %0 : (tensor) -> tensor return %1 : tensor } // ----- // CHECK-LABEL: @fold_exp_log func.func @fold_exp_log(%arg0: tensor) -> tensor { // CHECK: return %arg{{.*}} : tensor %0 = tosa.log %arg0 : (tensor) -> tensor %1 = tosa.exp %0 : (tensor) -> tensor return %1 : tensor } // ----- // CHECK-LABEL: @fold_negate_negate func.func @fold_negate_negate(%arg0: tensor) -> tensor { // CHECK: return %arg{{.*}} : tensor %0 = tosa.negate %arg0 : (tensor) -> tensor %1 = tosa.negate %0 : (tensor) -> tensor return %1 : tensor } // ----- // CHECK-LABEL: @fold_abs_abs func.func @fold_abs_abs(%arg0: tensor) -> tensor { // CHECK: %[[ABS:.*]] = tosa.abs %arg{{.*}} : (tensor) -> tensor // CHECK: return %[[ABS]] : tensor %0 = tosa.abs %arg0 : (tensor) -> tensor %1 = tosa.abs %0 : (tensor) -> tensor return %1 : tensor } // ----- // CHECK-LABEL: @fold_reduce_rank_zero func.func nested @fold_reduce_rank_zero() { // CHECK-NOT: tosa.reduce_min // CHECK-NOT: tosa.reverse %0 = tensor.empty() : tensor %1 = tosa.reduce_min %0 {axis = 0 : i32} : (tensor) -> tensor %2 = tosa.reverse %0 {axis = 0 : i32} : (tensor) -> tensor return } // ----- // CHECK-LABEL: @fold_tile_rank_zero func.func nested @fold_tile_rank_zero() -> tensor { // CHECK-NOT: tosa.tile %0 = tensor.empty() : tensor %1 = tosa.tile %0 {multiples = array} : (tensor) -> tensor return %1 : tensor } // ----- // CHECK-LABEL: @fold_reciprocal func.func nested @fold_reciprocal() -> tensor<3x600x1200xf32> { // CHECK: %[[VAL_0:.*]] = "tosa.const"() <{value = dense<8.620690e-03> : tensor<3x600x1200xf32>}> : () -> tensor<3x600x1200xf32> // CHECK: return %[[VAL_0]] : tensor<3x600x1200xf32> // CHECK: } %0 = "tosa.const"(){ value = dense<116.0>: tensor }: () -> tensor %1 = "tosa.cast"(%0) : (tensor) -> tensor<3x600x1200xf32> %2 = "tosa.reciprocal"(%1): (tensor<3x600x1200xf32>) -> tensor<3x600x1200xf32> return %2 : tensor<3x600x1200xf32> } // ----- // CHECK-LABEL: @do_not_fold_reciprocal_int func.func nested @do_not_fold_reciprocal_int() -> tensor<3x600x1200xi32> { // CHECK: tosa.reciprocal %0 = "tosa.const"(){ value = dense<11>: tensor }: () -> tensor %1 = "tosa.cast"(%0) : (tensor) -> tensor<3x600x1200xi32> %2 = "tosa.reciprocal"(%1): (tensor<3x600x1200xi32>) -> tensor<3x600x1200xi32> return %2 : tensor<3x600x1200xi32> }