1// RUN: mlir-opt --split-input-file -canonicalize="test-convergence" %s | FileCheck %s 2 3// CHECK-LABEL: @argmax_nofold 4func.func @argmax_nofold(%arg0: tensor<?x1xf32>) -> tensor<?x1xi32> { 5 // CHECK: tosa.argmax 6 %0 = tosa.argmax %arg0 {axis = 0 : i32}: (tensor<?x1xf32>) -> tensor<?x1xi32> 7 return %0 : tensor<?x1xi32> 8} 9 10// ----- 11 12// CHECK-LABEL: @add_bcast_zero_int 13func.func @add_bcast_zero_int(%arg0: tensor<4x2x3xi32>) -> tensor<4x2x3xi32> { 14 // CHECK-NOT: tosa.add 15 // CHECK: return %arg0 16 %zeros = "tosa.const"() {value = dense<0> : tensor<1x1x1xi32>} : () -> tensor<1x1x1xi32> 17 %1 = tosa.add %arg0, %zeros : (tensor<4x2x3xi32>, tensor<1x1x1xi32>) -> tensor<4x2x3xi32> 18 return %1 : tensor<4x2x3xi32> 19} 20 21// ----- 22 23// CHECK-LABEL: @add_zero_int 24func.func @add_zero_int(%arg0: tensor<2x3xi32>) -> tensor<2x3xi32> { 25 // CHECK: return %arg0 26 // CHECK-NOT: tosa.add 27 %zeros = "tosa.const"() {value = dense<0> : tensor<2x3xi32>} : () -> tensor<2x3xi32> 28 %1 = tosa.add %arg0, %zeros : (tensor<2x3xi32>, tensor<2x3xi32>) -> tensor<2x3xi32> 29 return %1 : tensor<2x3xi32> 30} 31 32// ----- 33 34// CHECK-LABEL: @cast_fold 35func.func @cast_fold(%arg0: tensor<?x1xf32>) -> tensor<?x1xf32> { 36 // CHECK: return %arg0 37 %0 = tosa.cast %arg0 : (tensor<?x1xf32>) -> tensor<?x1xf32> 38 return %0 : tensor<?x1xf32> 39} 40 41// ----- 42 43// CHECK-LABEL: @cast_nofold 44func.func @cast_nofold(%arg0: tensor<?x1xf32>) -> tensor<?x1xi32> { 45 // CHECK: tosa.cast 46 %0 = tosa.cast %arg0 : (tensor<?x1xf32>) -> tensor<?x1xi32> 47 return %0 : tensor<?x1xi32> 48} 49 50// ----- 51 52// CHECK-LABEL: @clamp_i32_not_noop 53func.func @clamp_i32_not_noop(%arg0: tensor<4xi32>) -> tensor<4xi32> { 54 // CHECK: tosa.clamp 55 %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> 56 return %0 : tensor<4xi32> 57} 58 59// ----- 60 61// CHECK-LABEL: @clamp_f16_not_noop 62func.func @clamp_f16_not_noop(%arg0: tensor<4xf16>) -> tensor<4xf16> { 63 // CHECK: tosa.clamp 64 %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> 65 return %0 : tensor<4xf16> 66} 67 68// ----- 69 70// CHECK-LABEL: @clamp_f32_not_noop 71func.func @clamp_f32_not_noop(%arg0: tensor<4xf32>) -> tensor<4xf32> { 72 // CHECK: tosa.clamp 73 %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> 74 return %0 : tensor<4xf32> 75} 76 77// ----- 78 79// CHECK-LABEL: @clamp_f16_is_noop 80func.func @clamp_f16_is_noop(%arg0: tensor<4xf16>) -> tensor<4xf16> { 81 // CHECK: return %arg0 82 // CHECK-NOT: "tosa.clamp" 83 // 0xFF800000 and 0x7F800000 are respectively negative and positive F32 infinity. 84 %0 = tosa.clamp %arg0 {min_int = -128 : i64, max_int = 127 : i64, min_fp = 0xFF800000 : f32, max_fp = 0x7F800000 : f32} : (tensor<4xf16>) -> tensor<4xf16> 85 return %0 : tensor<4xf16> 86} 87 88// ----- 89 90// CHECK-LABEL: @clamp_f32_is_noop 91func.func @clamp_f32_is_noop(%arg0: tensor<4xf32>) -> tensor<4xf32> { 92 // CHECK: return %arg0 93 // CHECK-NOT: "tosa.clamp" 94 // 0xFF800000 and 0x7F800000 are respectively negative and positive F32 infinity. 95 %0 = tosa.clamp %arg0 {min_int = -128 : i64, max_int = 127 : i64, min_fp = 0xFF800000 : f32, max_fp = 0x7F800000 : f32} : (tensor<4xf32>) -> tensor<4xf32> 96 return %0 : tensor<4xf32> 97} 98 99// ----- 100 101// CHECK-LABEL: @clamp_int8_is_noop 102func.func @clamp_int8_is_noop(%arg0: tensor<4xi8>) -> tensor<4xi8> { 103 // CHECK: return %arg0 104 // CHECK-NOT: tosa.clamp 105 %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> 106 return %0 : tensor<4xi8> 107} 108 109// ----- 110 111// CHECK-LABEL: @clamp_int16_is_noop 112func.func @clamp_int16_is_noop(%arg0: tensor<4xi16>) -> tensor<4xi16> { 113 // CHECK: return %arg0 114 // CHECK-NOT: tosa.clamp 115 %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> 116 return %0 : tensor<4xi16> 117} 118 119// ----- 120 121// CHECK-LABEL: @clamp_uint8_is_noop 122func.func @clamp_uint8_is_noop(%arg0: tensor<4xui8>) -> tensor<4xui8> { 123 // CHECK: return %arg0 124 // CHECK-NOT: tosa.clamp 125 %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> 126 return %0 : tensor<4xui8> 127} 128 129// ----- 130 131// CHECK-LABEL: @clamp_twice_is_single_clamp 132func.func @clamp_twice_is_single_clamp(%arg0: tensor<4xi8>) -> tensor<4xi8> { 133 // CHECK: tosa.clamp %arg0 {max_fp = 3.000000e+00 : f32, max_int = 2 : i64, min_fp = -3.000000e+00 : f32, min_int = -2 : i64} 134 %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> 135 %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> 136 return %1 : tensor<4xi8> 137} 138 139// ----- 140 141// CHECK: @disjoint_clamp_twice_is_not_single_clamp(%[[INPUT:.*]]: tensor<4xi8>) 142func.func @disjoint_clamp_twice_is_not_single_clamp(%arg0: tensor<4xi8>) -> tensor<4xi8> { 143 // CHECK: %[[CLAMP_1:.*]] = tosa.clamp %[[INPUT]] {max_fp = -5.000000e+00 : f32, max_int = -5 : i64, min_fp = -1.000000e+00 : f32, min_int = -10 : i64} : (tensor<4xi8>) -> tensor<4xi8> 144 // CHECK-NEXT: tosa.clamp %[[CLAMP_1]] {max_fp = 5.000000e+00 : f32, max_int = 5 : i64, min_fp = 1.000000e+00 : f32, min_int = 1 : i64} : (tensor<4xi8>) -> tensor<4xi8> 145 %0 = tosa.clamp %arg0 {max_fp = -5.0 : f32, max_int = -5 : i64, min_fp = -1.0 : f32, min_int = -10 : i64} : (tensor<4xi8>) -> tensor<4xi8> 146 %1 = tosa.clamp %0 {max_fp = 5.0 : f32, max_int = 5 : i64, min_fp = 1.0 : f32, min_int = 1 : i64} : (tensor<4xi8>) -> tensor<4xi8> 147 return %1 : tensor<4xi8> 148} 149 150// ----- 151 152// CHECK-LABEL: @clamp_twice_with_nan_propagate_is_single_clamp 153func.func @clamp_twice_with_nan_propagate_is_single_clamp(%arg0: tensor<4xi8>) -> tensor<4xi8> { 154 // CHECK: tosa.clamp %arg0 {max_fp = 3.000000e+00 : f32, max_int = 2 : i64, min_fp = -3.000000e+00 : f32, min_int = -2 : i64} 155 %0 = tosa.clamp %arg0 {max_fp = 3.0 : f32, max_int = 4 : i64, min_fp = -5.0 : f32, min_int = -2 : i64, nan_mode = "PROPAGATE"} : (tensor<4xi8>) -> tensor<4xi8> 156 %1 = tosa.clamp %0 {max_fp = 5.0 : f32, max_int = 2 : i64, min_fp = -3.0 : f32, min_int = -4 : i64, nan_mode = "PROPAGATE"} : (tensor<4xi8>) -> tensor<4xi8> 157 return %1 : tensor<4xi8> 158} 159 160// ----- 161 162// CHECK-LABEL: @clamp_twice_with_nan_ignore_is_single_clamp 163func.func @clamp_twice_with_nan_ignore_is_single_clamp(%arg0: tensor<4xi8>) -> tensor<4xi8> { 164 // CHECK: tosa.clamp %arg0 {max_fp = 3.000000e+00 : f32, max_int = 2 : i64, min_fp = -3.000000e+00 : f32, min_int = -2 : i64, nan_mode = "IGNORE"} 165 %0 = tosa.clamp %arg0 {max_fp = 3.0 : f32, max_int = 4 : i64, min_fp = -5.0 : f32, min_int = -2 : i64, nan_mode = "IGNORE"} : (tensor<4xi8>) -> tensor<4xi8> 166 %1 = tosa.clamp %0 {max_fp = 5.0 : f32, max_int = 2 : i64, min_fp = -3.0 : f32, min_int = -4 : i64, nan_mode = "IGNORE"} : (tensor<4xi8>) -> tensor<4xi8> 167 return %1 : tensor<4xi8> 168} 169 170// ----- 171 172// CHECK-LABEL: @clamp_twice_with_nan_ignore_propagate_is_single_clamp 173func.func @clamp_twice_with_nan_ignore_propagate_is_single_clamp(%arg0: tensor<4xi8>) -> tensor<4xi8> { 174 // CHECK: tosa.clamp %arg0 {max_fp = 3.000000e+00 : f32, max_int = 2 : i64, min_fp = -3.000000e+00 : f32, min_int = -2 : i64, nan_mode = "IGNORE"} 175 %0 = tosa.clamp %arg0 {max_fp = 3.0 : f32, max_int = 4 : i64, min_fp = -5.0 : f32, min_int = -2 : i64, nan_mode = "IGNORE"} : (tensor<4xi8>) -> tensor<4xi8> 176 %1 = tosa.clamp %0 {max_fp = 5.0 : f32, max_int = 2 : i64, min_fp = -3.0 : f32, min_int = -4 : i64, nan_mode = "PROPAGATE"} : (tensor<4xi8>) -> tensor<4xi8> 177 return %1 : tensor<4xi8> 178} 179 180// ----- 181 182// CHECK: @clamp_twice_with_nan_propagate_ignore_is_not_single_clamp(%[[INPUT:.*]]: tensor<4xi8>) 183func.func @clamp_twice_with_nan_propagate_ignore_is_not_single_clamp(%arg0: tensor<4xi8>) -> tensor<4xi8> { 184 // CHECK: %[[CLAMP_1:.*]] = tosa.clamp %[[INPUT]] {max_fp = 3.000000e+00 : f32, max_int = 4 : i64, min_fp = -5.000000e+00 : f32, min_int = -2 : i64} : (tensor<4xi8>) -> tensor<4xi8> 185 // CHECK-NEXT: tosa.clamp %[[CLAMP_1]] {max_fp = 5.000000e+00 : f32, max_int = 2 : i64, min_fp = -3.000000e+00 : f32, min_int = -4 : i64, nan_mode = "IGNORE"} : (tensor<4xi8>) -> tensor<4xi8> 186 %0 = tosa.clamp %arg0 {max_fp = 3.0 : f32, max_int = 4 : i64, min_fp = -5.0 : f32, min_int = -2 : i64, nan_mode = "PROPAGATE"} : (tensor<4xi8>) -> tensor<4xi8> 187 %1 = tosa.clamp %0 {max_fp = 5.0 : f32, max_int = 2 : i64, min_fp = -3.0 : f32, min_int = -4 : i64, nan_mode = "IGNORE"} : (tensor<4xi8>) -> tensor<4xi8> 188 return %1 : tensor<4xi8> 189} 190 191// ----- 192 193// CHECK-LABEL: @concat_fold 194func.func @concat_fold(%arg0: tensor<?x1xf32>) -> tensor<?x1xf32> { 195 // CHECK: return %arg0 196 %0 = tosa.concat %arg0 {axis = 0 : i32}: (tensor<?x1xf32>) -> tensor<?x1xf32> 197 return %0 : tensor<?x1xf32> 198} 199 200// ----- 201 202// CHECK-LABEL: @concat_fold_cast 203func.func @concat_fold_cast(%arg0: tensor<?x1xf32>) -> tensor<?x?xf32> { 204 // CHECK: %[[VAR0:.*]] = tensor.cast %arg0 205 // CHECK: return %[[VAR0]] 206 %0 = tosa.concat %arg0 {axis = 0 : i32}: (tensor<?x1xf32>) -> tensor<?x?xf32> 207 return %0 : tensor<?x?xf32> 208} 209 210// ----- 211 212// CHECK-LABEL: @conv2d_stride_2 213func.func @conv2d_stride_2(%arg0: tensor<4x10x10x2xf32>) -> tensor<4x10x10x3xf32> { 214 // CHECK: tosa.conv2d 215 %weight = "tosa.const"() {value = dense<[[[[1.0, 1.0]]], [[[1.0, 1.0]]], [[[1.0, 1.0]]]]> : tensor<3x1x1x2xf32>} : ()-> tensor<3x1x1x2xf32> 216 %bias = "tosa.const"() {value = dense<0.0> : tensor<3xf32>} : ()-> tensor<3xf32> 217 %0 = tosa.conv2d %arg0, %weight, %bias {acc_type = f32, pad = array<i64: 0, 0, 0, 0>, stride = array<i64: 2, 2>, dilation = array<i64: 1, 1>} : (tensor<4x10x10x2xf32>, tensor<3x1x1x2xf32>, tensor<3xf32>) -> tensor<4x10x10x3xf32> 218 return %0 : tensor<4x10x10x3xf32> 219} 220 221// ----- 222 223// CHECK-LABEL: @conv2d_weight_2x2 224func.func @conv2d_weight_2x2(%arg0: tensor<4x10x10x1xf32>) -> tensor<4x10x10x1xf32> { 225 // CHECK: tosa.conv2d 226 %weight = "tosa.const"() {value = dense<[[[[1.0], [1.0]], [[1.0], [1.0]]]]> : tensor<1x2x2x1xf32>} : ()-> tensor<1x2x2x1xf32> 227 %bias = "tosa.const"() {value = dense<0.0> : tensor<1xf32>} : ()-> tensor<1xf32> 228 %0 = tosa.conv2d %arg0, %weight, %bias {acc_type = f32, pad = array<i64: 0, 0, 0, 0>, stride = array<i64: 1, 1>, dilation = array<i64: 1, 1>} : (tensor<4x10x10x1xf32>, tensor<1x2x2x1xf32>, tensor<1xf32>) -> tensor<4x10x10x1xf32> 229 return %0 : tensor<4x10x10x1xf32> 230} 231 232// ----- 233 234// CHECK-LABEL: @depthwise_conv2d_stride_2 235func.func @depthwise_conv2d_stride_2(%arg0: tensor<4x10x10x2xf32>, %arg1: tensor<1x1x2x3xf32>, %arg2: tensor<6xf32>) -> tensor<4x10x10x6xf32> { 236 // CHECK: tosa.depthwise_conv2d 237 %0 = tosa.depthwise_conv2d %arg0, %arg1, %arg2 {acc_type = f32, pad = array<i64: 0, 0, 0, 0>, stride = array<i64: 2, 2>, dilation = array<i64: 1, 1>} : (tensor<4x10x10x2xf32>, tensor<1x1x2x3xf32>, tensor<6xf32>) -> tensor<4x10x10x6xf32> 238 return %0 : tensor<4x10x10x6xf32> 239} 240 241// ----- 242 243// CHECK-LABEL: @depthwise_conv2d_weight_2x2 244func.func @depthwise_conv2d_weight_2x2(%arg0: tensor<4x10x10x2xf32>, %arg1: tensor<2x2x2x3xf32>, %arg2: tensor<6xf32>) -> tensor<4x10x10x6xf32> { 245 // CHECK: tosa.depthwise_conv2d 246 %0 = tosa.depthwise_conv2d %arg0, %arg1, %arg2 {acc_type = f32, pad = array<i64: 0, 0, 0, 0>, stride = array<i64: 1, 1>, dilation = array<i64: 1, 1>} : (tensor<4x10x10x2xf32>, tensor<2x2x2x3xf32>, tensor<6xf32>) -> tensor<4x10x10x6xf32> 247 return %0 : tensor<4x10x10x6xf32> 248} 249 250// ----- 251 252// CHECK-LABEL: @max_pool2d_is_noop 253func.func @max_pool2d_is_noop(%arg0: tensor<10x1x1x3xf32>) -> tensor<10x1x1x3xf32> { 254 // CHECK-NOT: tosa.max_pool2d 255 // CHECK: return %arg0 256 %0 = tosa.max_pool2d %arg0 {kernel = array<i64: 1, 1>, pad = array<i64: 0, 0, 0, 0>, stride = array<i64: 1, 1>, dilation = array<i64: 1, 1>} : (tensor<10x1x1x3xf32>) -> tensor<10x1x1x3xf32> 257 return %0 : tensor<10x1x1x3xf32> 258} 259 260// ----- 261 262// CHECK-LABEL: @pad_noop 263func.func @pad_noop(%arg0: tensor<?x?xf32>) -> tensor<?x?xf32> { 264 // CHECK: return %arg0 265 %0 = tosa.const_shape { value = dense<0> : tensor<4xindex>} : () -> !tosa.shape<4> 266 %1 = tosa.pad %arg0, %0 : (tensor<?x?xf32>, !tosa.shape<4>) -> tensor<?x?xf32> 267 return %1 : tensor<?x?xf32> 268} 269 270// ----- 271 272// CHECK-LABEL: @pad_noop_padding_mismatch_nofold 273func.func @pad_noop_padding_mismatch_nofold(%arg0: tensor<?x?xf32>) -> tensor<?x?xf32> { 274 // CHECK: %[[PAD:.+]] = tosa.pad 275 // CHECK: return %[[PAD]] 276 %shape = tosa.const_shape { value = dense<[1, 0, 0, 1]> : tensor<4xindex>} : () -> !tosa.shape<4> 277 %1 = tosa.pad %arg0, %shape : (tensor<?x?xf32>, !tosa.shape<4>) -> tensor<?x?xf32> 278 return %1 : tensor<?x?xf32> 279} 280 281// ----- 282 283// CHECK-LABEL: @pad_noop_type_mismatch_nofold 284func.func @pad_noop_type_mismatch_nofold(%arg0: tensor<10xf32>) -> tensor<?xf32> { 285 // CHECK: %[[PAD:.+]] = tosa.pad 286 // CHECK: return %[[PAD]] 287 %shape = tosa.const_shape { value = dense<[1, 2]> : tensor<2xindex>} : () -> !tosa.shape<2> 288 %0 = tosa.pad %arg0, %shape : (tensor<10xf32>, !tosa.shape<2>) -> tensor<?xf32> 289 return %0 : tensor<?xf32> 290} 291 292// ----- 293 294// CHECK-LABEL: @pad_determine_val_i32 295func.func @pad_determine_val_i32(%arg0: tensor<?x?xi32>, %arg1 : tensor<2x2xi32>) -> tensor<?x?xi32> { 296 // CHECK-DAG: %[[ZERO:.+]] = "tosa.const"() <{value = dense<0> : tensor<i32>} 297 // CHECK-DAG: %[[PADDING:.+]] = tosa.const_shape {value = dense<[1, 0, 0, 1]> : tensor<4xindex>} : () -> !tosa.shape<4> 298 // CHECK: tosa.pad %arg0, %[[PADDING]], %[[ZERO]] 299 %0 = tosa.const_shape { value = dense<[1, 0, 0, 1]> : tensor<4xindex>} : () -> !tosa.shape<4> 300 %1 = tosa.pad %arg0, %0 : (tensor<?x?xi32>, !tosa.shape<4>) -> tensor<?x?xi32> 301 return %1 : tensor<?x?xi32> 302} 303 304// ----- 305 306// CHECK-LABEL: @pad_determine_val_f32 307func.func @pad_determine_val_f32(%arg0: tensor<?x?xf32>, %arg1 : tensor<2x2xi32>) -> tensor<?x?xf32> { 308 // CHECK-DAG: %[[ZERO:.+]] = "tosa.const"() <{value = dense<0.000000e+00> : tensor<f32>} 309 // CHECK-DAG: %[[PADDING:.+]] = tosa.const_shape {value = dense<[1, 0, 0, 1]> : tensor<4xindex>} : () -> !tosa.shape<4> 310 // CHECK: tosa.pad %arg0, %[[PADDING]], %[[ZERO]] 311 %0 = tosa.const_shape { value = dense<[1, 0, 0, 1]> : tensor<4xindex>} : () -> !tosa.shape<4> 312 %1 = tosa.pad %arg0, %0 : (tensor<?x?xf32>, !tosa.shape<4>) -> tensor<?x?xf32> 313 return %1 : tensor<?x?xf32> 314} 315 316// ----- 317 318// CHECK-LABEL: @pad_determine_val_quant 319func.func @pad_determine_val_quant(%arg0: tensor<?x?xi32>, %arg1 : tensor<2x2xi32>) -> tensor<?x?xi32> { 320 // CHECK-DAG: %[[ZERO:.+]] = "tosa.const"() <{value = dense<0> : tensor<i32>} 321 // CHECK-DAG: %[[PADDING:.+]] = tosa.const_shape {value = dense<[1, 0, 0, 1]> : tensor<4xindex>} : () -> !tosa.shape<4> 322 // CHECK: tosa.pad %arg0, %[[PADDING]], %[[ZERO]] 323 %0 = tosa.const_shape { value = dense<[1, 0, 0, 1]> : tensor<4xindex>} : () -> !tosa.shape<4> 324 %1 = tosa.pad %arg0, %0 {input_zp = 42 : i32} : (tensor<?x?xi32>, !tosa.shape<4>) -> tensor<?x?xi32> 325 return %1 : tensor<?x?xi32> 326} 327 328// ----- 329 330// CHECK-LABEL: @mul_one_float 331func.func @mul_one_float(%arg0: tensor<2x3xf32>) -> tensor<2x3xf32> { 332 // CHECK: return %arg0 333 // CHECK-NOT: tosa.mul 334 %ones = "tosa.const"() {value = dense<1.0> : tensor<2x3xf32>} : () -> tensor<2x3xf32> 335 %1 = tosa.mul %arg0, %ones : (tensor<2x3xf32>, tensor<2x3xf32>) -> tensor<2x3xf32> 336 return %1 : tensor<2x3xf32> 337} 338 339// ----- 340 341// CHECK-LABEL: @mul_bcast_one_float 342func.func @mul_bcast_one_float(%arg0: tensor<2x3xf32>) -> tensor<2x3xf32> { 343 // CHECK: return %arg0 344 // CHECK-NOT: tosa.mul 345 %ones = "tosa.const"() {value = dense<1.0> : tensor<1x1xf32>} : () -> tensor<1x1xf32> 346 %1 = tosa.mul %ones, %arg0 : (tensor<1x1xf32>, tensor<2x3xf32>) -> tensor<2x3xf32> 347 return %1 : tensor<2x3xf32> 348} 349 350// ----- 351 352// CHECK-LABEL: @mul_one_int 353func.func @mul_one_int(%arg0: tensor<2x3xi32>) -> tensor<2x3xi32> { 354 // CHECK: return %arg0 355 // CHECK-NOT: tosa.mul 356 %shift = "tosa.const"() <{value = dense<0> : tensor<1xi8>}> : () -> tensor<1xi8> 357 %ones = "tosa.const"() {value = dense<1> : tensor<2x3xi32>} : () -> tensor<2x3xi32> 358 %1 = tosa.mul %arg0, %ones, %shift : (tensor<2x3xi32>, tensor<2x3xi32>, tensor<1xi8>) -> tensor<2x3xi32> 359 return %1 : tensor<2x3xi32> 360} 361 362// ----- 363 364// CHECK-LABEL: @mul_one_int_and_shift 365func.func @mul_one_int_and_shift(%arg0: tensor<2x3xi32>) -> tensor<2x3xi32> { 366 // CHECK-DAG: %[[VAL_1:.*]] = "tosa.const"() <{value = dense<1> : tensor<2x3xi32>}> 367 // CHECK-DAG: %[[VAL_2:.*]] = "tosa.const"() <{value = dense<31> : tensor<1xi8>}> 368 // CHECK: %[[VAL_3:.*]] = tosa.mul %arg0, %[[VAL_1]], %[[VAL_2]] : (tensor<2x3xi32>, tensor<2x3xi32>, tensor<1xi8>) 369 %ones = "tosa.const"() {value = dense<1> : tensor<2x3xi32>} : () -> tensor<2x3xi32> 370 %shift = "tosa.const"() <{value = dense<31> : tensor<1xi8>}> : () -> tensor<1xi8> 371 %1 = tosa.mul %arg0, %ones, %shift : (tensor<2x3xi32>, tensor<2x3xi32>, tensor<1xi8>) -> tensor<2x3xi32> 372 return %1 : tensor<2x3xi32> 373} 374 375// ----- 376 377// CHECK-LABEL: @mul_zero_broadcast 378func.func @mul_zero_broadcast(%arg0: tensor<2x3xf32>) -> (tensor<2x3xf32>, tensor<2x3xf32>) { 379 // CHECK: %[[ZERO:.*]] = "tosa.const"() <{value = dense<0.000000e+00> : tensor<2x3xf32>} 380 // CHECK-NOT: tosa.mul 381 %zeros = "tosa.const"() {value = dense<0.0> : tensor<1x1xf32>} : () -> tensor<1x1xf32> 382 %1 = tosa.mul %arg0, %zeros : (tensor<2x3xf32>, tensor<1x1xf32>) -> tensor<2x3xf32> 383 384 // CHECK-NOT: tosa.mul 385 // CHECK: return %[[ZERO]], %[[ZERO]] 386 %2 = tosa.mul %zeros, %arg0 : (tensor<1x1xf32>, tensor<2x3xf32>) -> tensor<2x3xf32> 387 return %1, %2 : tensor<2x3xf32>, tensor<2x3xf32> 388} 389 390// ----- 391 392// CHECK-LABEL: @select_same_value 393func.func @select_same_value(%arg0: tensor<2x3xi1>, %arg1: tensor<2x3xi32>) -> tensor<2x3xi32> { 394 %0 = tosa.select %arg0, %arg1, %arg1 : (tensor<2x3xi1>, tensor<2x3xi32>, tensor<2x3xi32>) -> tensor<2x3xi32> 395 // CHECK: return %arg1 396 // CHECK-NOT: tosa.select 397 return %0 : tensor<2x3xi32> 398} 399 400// ----- 401 402// CHECK-LABEL: @select_true_value 403func.func @select_true_value(%arg0: tensor<2x3xi32>, %arg1: tensor<2x3xi32>) -> tensor<2x3xi32> { 404 %c1 = "tosa.const"() {value = dense<1> : tensor<2x3xi1>} : () -> tensor<2x3xi1> 405 %0 = tosa.select %c1, %arg0, %arg1 : (tensor<2x3xi1>, tensor<2x3xi32>, tensor<2x3xi32>) -> tensor<2x3xi32> 406 // CHECK: return %arg0 407 // CHECK-NOT: tosa.select 408 return %0 : tensor<2x3xi32> 409} 410 411// ----- 412 413// CHECK-LABEL: @select_false_value 414func.func @select_false_value(%arg0: tensor<2x3xi32>, %arg1: tensor<2x3xi32>) -> tensor<2x3xi32> { 415 %c0 = "tosa.const"() {value = dense<0> : tensor<2x3xi1>} : () -> tensor<2x3xi1> 416 %0 = tosa.select %c0, %arg0, %arg1 : (tensor<2x3xi1>, tensor<2x3xi32>, tensor<2x3xi32>) -> tensor<2x3xi32> 417 // CHECK: return %arg1 418 // CHECK-NOT: tosa.select 419 return %0 : tensor<2x3xi32> 420} 421 422// ----- 423 424// CHECK-LABEL: @select_not_pred 425func.func @select_not_pred(%arg0: tensor<2x3xi1>, %arg1: tensor<2x3xi32>, %arg2: tensor<2x3xi32>) -> tensor<2x3xi32> { 426 %0 = tosa.logical_not %arg0 : (tensor<2x3xi1>) -> tensor<2x3xi1> 427 %1 = tosa.select %0, %arg1, %arg2 : (tensor<2x3xi1>, tensor<2x3xi32>, tensor<2x3xi32>) -> tensor<2x3xi32> 428 // CHECK: tosa.select %arg0, %arg2, %arg1 429 return %1 : tensor<2x3xi32> 430} 431 432// ----- 433 434// CHECK-LABEL: @reduce_all_fold 435func.func @reduce_all_fold(%arg0: tensor<?x1xf32>) -> tensor<?x1xf32> { 436 // CHECK: return %arg0 437 %0 = tosa.reduce_all %arg0 {axis = 1 : i32}: (tensor<?x1xf32>) -> tensor<?x1xf32> 438 return %0 : tensor<?x1xf32> 439} 440 441// ----- 442 443// CHECK-LABEL: @reduce_all_nofold 444func.func @reduce_all_nofold(%arg0: tensor<?x1xf32>) -> tensor<?x1xf32> { 445 // CHECK: tosa.reduce_all 446 %0 = tosa.reduce_all %arg0 {axis = 0 : i32}: (tensor<?x1xf32>) -> tensor<?x1xf32> 447 return %0 : tensor<?x1xf32> 448} 449 450// ----- 451 452// CHECK-LABEL: @reduce_any_fold 453func.func @reduce_any_fold(%arg0: tensor<?x1xf32>) -> tensor<?x1xf32> { 454 // CHECK: return %arg0 455 %0 = tosa.reduce_any %arg0 {axis = 1 : i32}: (tensor<?x1xf32>) -> tensor<?x1xf32> 456 return %0 : tensor<?x1xf32> 457} 458 459// ----- 460 461// CHECK-LABEL: @reduce_any_nofold 462func.func @reduce_any_nofold(%arg0: tensor<?x1xf32>) -> tensor<?x1xf32> { 463 // CHECK: tosa.reduce_any 464 %0 = tosa.reduce_any %arg0 {axis = 0 : i32}: (tensor<?x1xf32>) -> tensor<?x1xf32> 465 return %0 : tensor<?x1xf32> 466} 467 468// ----- 469 470// CHECK-LABEL: @reduce_max_fold 471func.func @reduce_max_fold(%arg0: tensor<?x1xf32>) -> tensor<?x1xf32> { 472 // CHECK: return %arg0 473 %0 = tosa.reduce_max %arg0 {axis = 1 : i32}: (tensor<?x1xf32>) -> tensor<?x1xf32> 474 return %0 : tensor<?x1xf32> 475} 476 477// ----- 478 479// CHECK-LABEL: @reduce_max_nofold 480func.func @reduce_max_nofold(%arg0: tensor<?x1xf32>) -> tensor<?x1xf32> { 481 // CHECK: tosa.reduce_max 482 %0 = tosa.reduce_max %arg0 {axis = 0 : i32}: (tensor<?x1xf32>) -> tensor<?x1xf32> 483 return %0 : tensor<?x1xf32> 484} 485 486// ----- 487 488// CHECK-LABEL: @reduce_min_fold 489func.func @reduce_min_fold(%arg0: tensor<?x1xf32>) -> tensor<?x1xf32> { 490 // CHECK: return %arg0 491 %0 = tosa.reduce_min %arg0 {axis = 1 : i32}: (tensor<?x1xf32>) -> tensor<?x1xf32> 492 return %0 : tensor<?x1xf32> 493} 494 495// ----- 496 497// CHECK-LABEL: @reduce_min_nofold 498func.func @reduce_min_nofold(%arg0: tensor<?x1xf32>) -> tensor<?x1xf32> { 499 // CHECK: tosa.reduce_min 500 %0 = tosa.reduce_min %arg0 {axis = 0 : i32}: (tensor<?x1xf32>) -> tensor<?x1xf32> 501 return %0 : tensor<?x1xf32> 502} 503 504// ----- 505 506// CHECK-LABEL: @reduce_prod_fold 507func.func @reduce_prod_fold(%arg0: tensor<?x1xf32>) -> tensor<?x1xf32> { 508 // CHECK: return %arg0 509 %0 = tosa.reduce_prod %arg0 {axis = 1 : i32}: (tensor<?x1xf32>) -> tensor<?x1xf32> 510 return %0 : tensor<?x1xf32> 511} 512 513// ----- 514 515// CHECK-LABEL: @reduce_prod_nofold 516func.func @reduce_prod_nofold(%arg0: tensor<?x1xf32>) -> tensor<?x1xf32> { 517 // CHECK: tosa.reduce_prod 518 %0 = tosa.reduce_prod %arg0 {axis = 0 : i32}: (tensor<?x1xf32>) -> tensor<?x1xf32> 519 return %0 : tensor<?x1xf32> 520} 521 522// ----- 523 524// CHECK-LABEL: @reduce_sum_fold 525func.func @reduce_sum_fold(%arg0: tensor<?x1xf32>) -> tensor<?x1xf32> { 526 // CHECK: return %arg0 527 %0 = tosa.reduce_sum %arg0 {axis = 1 : i32}: (tensor<?x1xf32>) -> tensor<?x1xf32> 528 return %0 : tensor<?x1xf32> 529} 530 531// ----- 532 533// CHECK-LABEL: @reduce_sum_nofold 534func.func @reduce_sum_nofold(%arg0: tensor<?x1xf32>) -> tensor<?x1xf32> { 535 // CHECK: tosa.reduce_sum 536 %0 = tosa.reduce_sum %arg0 {axis = 0 : i32}: (tensor<?x1xf32>) -> tensor<?x1xf32> 537 return %0 : tensor<?x1xf32> 538} 539 540// ----- 541 542// CHECK-LABEL: @reshape_canonicalize 543func.func @reshape_canonicalize(%arg0: tensor<?x10xf32>) -> tensor<?x10xf32> { 544 // CHECK: return %arg0 545 %0 = tosa.reshape %arg0 {new_shape = array<i64: -1, 10>}: (tensor<?x10xf32>) -> tensor<?x10xf32> 546 return %0 : tensor<?x10xf32> 547} 548 549// ----- 550 551// CHECK-LABEL: @reshape_canonicalize_dyn_nofold 552func.func @reshape_canonicalize_dyn_nofold(%arg0: tensor<?x?x10xf32>) -> tensor<?x?x10xf32> { 553 // CHECK: %[[VAR0:.+]] = tosa.reshape %arg0 {new_shape = array<i64: -1, 2, 10>} : (tensor<?x?x10xf32>) -> tensor<?x?x10xf32> 554 // CHECK: return %[[VAR0]] : tensor<?x?x10xf32> 555 %0 = tosa.reshape %arg0 {new_shape = array<i64: -1, 2, 10>} : (tensor<?x?x10xf32>) -> tensor<?x?x10xf32> 556 return %0 : tensor<?x?x10xf32> 557} 558 559// ----- 560 561// CHECK-LABEL: @reshape_canonicalize_double 562func.func @reshape_canonicalize_double(%arg0: tensor<?x10xf32>) -> tensor<?x5xf32> { 563 // CHECK: %[[VAL_1:.*]] = tosa.reshape %arg0 {new_shape = array<i64: -1, 5>} 564 // CHECK: return %[[VAL_1]] 565 %0 = tosa.reshape %arg0 {new_shape = array<i64: 5, -1>}: (tensor<?x10xf32>) -> tensor<5x?xf32> 566 %1 = tosa.reshape %0 {new_shape = array<i64: -1, 5>}: (tensor<5x?xf32>) -> tensor<?x5xf32> 567 return %1 : tensor<?x5xf32> 568} 569 570// ----- 571 572// CHECK-LABEL: @reshape_canonicalize_const 573func.func @reshape_canonicalize_const() -> tensor<1x5xi32> { 574 // CHECK: %[[VAR0:.+]] = "tosa.const"() <{value = dense<{{\[\[}}0, 1, 2, 3, 4]]> : tensor<1x5xi32>} 575 // CHECK: return %[[VAR0]] 576 %0 = "tosa.const"() {value = dense<[0, 1, 2, 3, 4]> : tensor<5xi32>} : () -> tensor<5xi32> 577 %1 = tosa.reshape %0 {new_shape = array<i64: 1, 5>} : (tensor<5xi32>) -> tensor<1x5xi32> 578 return %1 : tensor<1x5xi32> 579} 580 581// ----- 582 583// CHECK-LABEL: @reshape_canonicalize_const_dynamic 584func.func @reshape_canonicalize_const_dynamic() -> tensor<1x?xi32> { 585 // CHECK: tosa.reshape 586 %0 = "tosa.const"() {value = dense<[0, 1, 2, 3, 4]> : tensor<5xi32>} : () -> tensor<5xi32> 587 %1 = tosa.reshape %0 {new_shape = array<i64: 1, 5>} : (tensor<5xi32>) -> tensor<1x?xi32> 588 return %1 : tensor<1x?xi32> 589} 590 591// ----- 592 593// CHECK-LABEL: @reshape_canonicalize_const_splat 594func.func @reshape_canonicalize_const_splat() -> (tensor<10xi32>, tensor<1x10xi32>) { 595 // CHECK-DAG: %[[VAR0:.+]] = "tosa.const"() <{value = dense<0> : tensor<10xi32>} 596 // CHECK-DAG: %[[VAR1:.+]] = "tosa.const"() <{value = dense<0> : tensor<1x10xi32>} 597 // CHECK: return %[[VAR0]], %[[VAR1]] 598 %0 = "tosa.const"() {value = dense<0> : tensor<10xi32>} : () -> tensor<10xi32> 599 %1 = tosa.reshape %0 {new_shape = array<i64: 1, 10>} : (tensor<10xi32>) -> tensor<1x10xi32> 600 return %0 , %1 : tensor<10xi32>, tensor<1x10xi32> 601} 602 603// ----- 604 605// CHECK-LABEL: @reshape_canonicalize_const_sparse 606func.func @reshape_canonicalize_const_sparse() -> (tensor<3xi32>, tensor<1x3xi32>) { 607 // CHECK: tosa.reshape 608 %0 = "tosa.const"() {value = dense<[1, 2, 3]> : tensor<3xi32>} : ()-> tensor<3xi32> 609 %1 = tosa.reshape %0 {new_shape = array<i64: 1, 3>} : (tensor<3xi32>) -> tensor<1x3xi32> 610 return %0 , %1 : tensor<3xi32>, tensor<1x3xi32> 611} 612 613// ----- 614 615// CHECK-LABEL: @reshape_canonicalize_quant_nofold 616func.func @reshape_canonicalize_quant_nofold() -> (tensor<1x3x!quant.uniform<i8:f32, 1.000000e+00>>) { 617 // disabled folding for quantized element types 618 // CHECK{LITERAL}: "tosa.const"() <{value = dense<[1, 2, 3]> : tensor<3xi8>}> : () -> tensor<3x!quant.uniform<i8:f32, 1.000000e+00>> 619 // CHECK{LITERAL}: tosa.reshape %0 {new_shape = array<i64: 1, 3>} : (tensor<3x!quant.uniform<i8:f32, 1.000000e+00>>) -> tensor<1x3x!quant.uniform<i8:f32, 1.000000e+00>> 620 %0 = "tosa.const"() {value = dense<[1, 2, 3]> : tensor<3xi8>} : ()-> tensor<3x!quant.uniform<i8:f32, 1.000000e+00>> 621 %1 = tosa.reshape %0 {new_shape = array<i64: 1, 3>} : (tensor<3x!quant.uniform<i8:f32, 1.000000e+00>>) -> tensor<1x3x!quant.uniform<i8:f32, 1.000000e+00>> 622 return %1 : tensor<1x3x!quant.uniform<i8:f32, 1.000000e+00>> 623} 624 625// ----- 626 627// CHECK-LABEL: @transpose_canonicalize_strip_quant 628func.func @transpose_canonicalize_strip_quant() -> (tensor<2x1x3x!quant.uniform<i8:f32, 1.000000e+00>>) { 629 // CHECK: "tosa.const"() <{value = dense<0> : tensor<1x2x3xi8>}> : () -> tensor<1x2x3x!quant.uniform<i8:f32, 1.000000e+00>> 630 // CHECK: tosa.reshape %0 {new_shape = array<i64: 2, 1, 3>} : (tensor<1x2x3x!quant.uniform<i8:f32, 1.000000e+00>>) -> tensor<2x1x3x!quant.uniform<i8:f32, 1.000000e+00>> 631 %perms = "tosa.const"() {value = dense<[1, 0, 2]> : tensor<3xi32>} : () -> tensor<3xi32> 632 %0 = "tosa.const"() {value = dense<0> : tensor<1x2x3xi8>} : ()-> tensor<1x2x3x!quant.uniform<i8:f32, 1.000000e+00>> 633 %1 = tosa.transpose %0, %perms : (tensor<1x2x3x!quant.uniform<i8:f32, 1.000000e+00>>, tensor<3xi32>) -> tensor<2x1x3x!quant.uniform<i8:f32, 1.000000e+00>> 634 return %1 : tensor<2x1x3x!quant.uniform<i8:f32, 1.000000e+00>> 635} 636 637// ----- 638 639// CHECK-LABEL: @slice_fold 640func.func @slice_fold(%arg0: tensor<3x4xf32>) -> tensor<3x4xf32> { 641 %0 = tosa.const_shape {value = dense<[0, 0]> : tensor<2xindex>} : () -> !tosa.shape<2> 642 %1 = tosa.const_shape {value = dense<[3, 4]> : tensor<2xindex>} : () -> !tosa.shape<2> 643 // CHECK: return %arg0 644 %3 = tosa.slice %arg0, %0, %1 : (tensor<3x4xf32>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<3x4xf32> 645 return %3 : tensor<3x4xf32> 646} 647 648// ----- 649 650// CHECK-LABEL: @slice_nofold 651func.func @slice_nofold(%arg0: tensor<?x4xf32>) -> tensor<?x4xf32> { 652 %0 = tosa.const_shape {value = dense<[0, 0]> : tensor<2xindex>} : () -> !tosa.shape<2> 653 %1 = tosa.const_shape {value = dense<[3, 4]> : tensor<2xindex>} : () -> !tosa.shape<2> 654 // CHECK: tosa.slice 655 %3 = tosa.slice %arg0, %0, %1 : (tensor<?x4xf32>, !tosa.shape<2>, !tosa.shape<2>) -> tensor<?x4xf32> 656 return %3 : tensor<?x4xf32> 657} 658 659// ----- 660 661// CHECK-LABEL: @tile_fold 662func.func @tile_fold(%arg0: tensor<3x4xf32>) -> tensor<3x4xf32> { 663 // CHECK: return %arg0 664 %cst = tosa.const_shape { value = dense<1> : tensor<2xindex> } : () -> !tosa.shape<2> 665 %0 = tosa.tile %arg0, %cst: (tensor<3x4xf32>, !tosa.shape<2>) -> tensor<3x4xf32> 666 return %0 : tensor<3x4xf32> 667} 668 669// ----- 670 671// CHECK-LABEL: @tile_nofold 672func.func @tile_nofold(%arg0: tensor<3x4xf32>) -> tensor<3x8xf32> { 673 // CHECK: tosa.tile 674 %cst = tosa.const_shape { value = dense<[1, 2]> : tensor<2xindex> } : () -> !tosa.shape<2> 675 %0 = tosa.tile %arg0, %cst: (tensor<3x4xf32>, !tosa.shape<2>) -> tensor<3x8xf32> 676 return %0 : tensor<3x8xf32> 677} 678 679// ----- 680 681// CHECK-LABEL: @transpose_no_op 682func.func @transpose_no_op(%arg0: tensor<3x4x5x6xf32>) -> tensor<3x4x5x6xf32> { 683 // CHECK: return %arg0 684 // CHECK-NOT: tosa.transpose 685 %perms = "tosa.const"() {value = dense<[0, 1, 2, 3]> : tensor<4xi32>} : () -> tensor<4xi32> 686 %1 = tosa.transpose %arg0, %perms : (tensor<3x4x5x6xf32>, tensor<4xi32>) -> tensor<3x4x5x6xf32> 687 return %1 : tensor<3x4x5x6xf32> 688} 689 690// ----- 691 692// CHECK-LABEL: @transpose_is_reshape 693func.func @transpose_is_reshape(%arg0: tensor<1x4x5x1xf32>) -> tensor<1x4x1x5xf32> { 694 // CHECK: tosa.reshape %arg0 {new_shape = array<i64: 1, 4, 1, 5>} : (tensor<1x4x5x1xf32>) -> tensor<1x4x1x5xf32> 695 %perms = "tosa.const"() <{value = dense<[3, 1, 0, 2]> : tensor<4xi32>}> : () -> tensor<4xi32> 696 %0 = tosa.transpose %arg0, %perms : (tensor<1x4x5x1xf32>, tensor<4xi32>) -> tensor<1x4x1x5xf32> 697 return %0 : tensor<1x4x1x5xf32> 698} 699 700// ----- 701 702// CHECK-LABEL: @single_bit_reshape 703// https://github.com/llvm/llvm-project/issues/55440 704func.func @single_bit_reshape() -> tensor<1xi1> { 705 // CHECK: "tosa.const"() <{value = dense<true> : tensor<1xi1>} 706 %0 = arith.constant dense<true> : tensor<1x1xi1> 707 %1 = tosa.reshape %0 {new_shape = array<i64: 1>} : (tensor<1x1xi1>) -> tensor<1xi1> 708 return %1 : tensor<1xi1> 709} 710 711// ----- 712 713// CHECK-LABEL: @fold_resize_nearest 714func.func @fold_resize_nearest(%arg0 : tensor<1x15x13x1xi8>) -> tensor<1x15x13x1xi8> { 715 // CHECK: return %arg0 716 %resize = tosa.resize %arg0 {mode = "NEAREST_NEIGHBOR" , scale = array<i64: 2, 2, 1, 1>, offset = array<i64: 0, 0>, border = array<i64: 0, 0>} : (tensor<1x15x13x1xi8>) -> tensor<1x15x13x1xi8> 717 return %resize : tensor<1x15x13x1xi8> 718} 719 720// ----- 721 722// CHECK-LABEL: @fold_resize_bilinear 723func.func @fold_resize_bilinear(%arg0 : tensor<1x15x13x1xi8>) -> tensor<1x15x13x1xi8> { 724 // CHECK: return %arg0 725 %resize = tosa.resize %arg0 {mode = "BILINEAR" , scale = array<i64: 2, 2, 1, 1>, offset = array<i64: 0, 0>, border = array<i64: 0, 0>} : (tensor<1x15x13x1xi8>) -> tensor<1x15x13x1xi8> 726 return %resize : tensor<1x15x13x1xi8> 727} 728 729// ----- 730 731// CHECK-LABEL: @canonicalize_concat_slice_final_axis 732// CHECK-SAME: %[[VAL_0:.*]]: tensor<1x12x12x1xf32>, %[[VAL_1:.*]]: tensor<1x12x12x1xf32> 733// CHECK: return %[[VAL_0]], %[[VAL_1]] : tensor<1x12x12x1xf32>, tensor<1x12x12x1xf32> 734func.func @canonicalize_concat_slice_final_axis(%arg0 : tensor<1x12x12x1xf32>, %arg1 : tensor<1x12x12x1xf32>) -> (tensor<1x12x12x1xf32>, tensor<1x12x12x1xf32>) { 735 %0 = tosa.concat %arg0, %arg1 {axis = 3 : i32} : (tensor<1x12x12x1xf32>, tensor<1x12x12x1xf32>) -> tensor<1x12x12x2xf32> 736 %1 = tosa.const_shape {value = dense<[0, 0, 0, 0]> : tensor<4xindex>} : () -> !tosa.shape<4> 737 %2 = tosa.const_shape {value = dense<[0, 0, 0, 1]> : tensor<4xindex>} : () -> !tosa.shape<4> 738 %3 = tosa.const_shape {value = dense<[1, 12, 12, 1]> : tensor<4xindex>} : () -> !tosa.shape<4> 739 %4 = tosa.slice %0, %1, %3 : (tensor<1x12x12x2xf32>, !tosa.shape<4>, !tosa.shape<4>) -> tensor<1x12x12x1xf32> 740 %5 = tosa.slice %0, %2, %3 : (tensor<1x12x12x2xf32>, !tosa.shape<4>, !tosa.shape<4>) -> tensor<1x12x12x1xf32> 741 return %4, %5 : tensor<1x12x12x1xf32>, tensor<1x12x12x1xf32> 742} 743 744// ----- 745 746// CHECK-LABEL: @canonicalize_concat_slice_middle_axis 747// CHECK-SAME: %[[VAL_0:.*]]: tensor<1x12x12xf32>, %[[VAL_1:.*]]: tensor<1x12x12xf32> 748// CHECK: return %[[VAL_0]], %[[VAL_1]] : tensor<1x12x12xf32>, tensor<1x12x12xf32> 749func.func @canonicalize_concat_slice_middle_axis(%arg0 : tensor<1x12x12xf32>, %arg1 : tensor<1x12x12xf32>) -> (tensor<1x12x12xf32>, tensor<1x12x12xf32>) { 750 %0 = tosa.concat %arg0, %arg1 {axis = 1 : i32} : (tensor<1x12x12xf32>, tensor<1x12x12xf32>) -> tensor<1x24x12xf32> 751 %1 = tosa.const_shape {value = dense<[0, 0, 0]> : tensor<3xindex>} : () -> !tosa.shape<3> 752 %2 = tosa.const_shape {value = dense<[0, 12, 0]> : tensor<3xindex>} : () -> !tosa.shape<3> 753 %3 = tosa.const_shape {value = dense<[1, 12, 12]> : tensor<3xindex>} : () -> !tosa.shape<3> 754 %4 = tosa.slice %0, %1, %3 : (tensor<1x24x12xf32>, !tosa.shape<3>, !tosa.shape<3>) -> tensor<1x12x12xf32> 755 %5 = tosa.slice %0, %2, %3 : (tensor<1x24x12xf32>, !tosa.shape<3>, !tosa.shape<3>) -> tensor<1x12x12xf32> 756 return %4, %5 : tensor<1x12x12xf32>, tensor<1x12x12xf32> 757} 758 759// ----- 760 761// CHECK-LABEL: @canonicalize_cross_concat_inputs 762// CHECK-SAME: %[[VAL_0:.*]]: tensor<1x12x12xf32>, %[[VAL_1:.*]]: tensor<1x12x12xf32> 763// CHECK-DAG: %[[VAL_2:.*]] = tosa.const_shape {value = dense<[1, 12, 20]> : tensor<3xindex>} 764// CHECK-DAG: %[[VAL_3:.*]] = tosa.const_shape {value = dense<[1, 12, 15]> : tensor<3xindex>} 765// CHECK-DAG: %[[VAL_4:.*]] = tosa.const_shape {value = dense<[0, 0, 4]> : tensor<3xindex>} 766// CHECK-DAG: %[[VAL_5:.*]] = tosa.const_shape {value = dense<0> : tensor<3xindex>} 767// CHECK: %[[VAL_6:.*]] = tosa.concat %[[VAL_0]], %[[VAL_1]] {axis = 2 : i32} : (tensor<1x12x12xf32>, tensor<1x12x12xf32>) -> tensor<1x12x24xf32> 768// CHECK: %[[VAL_7:.*]] = tosa.slice %[[VAL_6]], %[[VAL_5]], %[[VAL_3]] 769// CHECK: %[[VAL_8:.*]] = tosa.slice %[[VAL_6]], %[[VAL_4]], %[[VAL_2]] 770// CHECK: return %[[VAL_7]], %[[VAL_8]] : tensor<1x12x15xf32>, tensor<1x12x20xf32> 771func.func @canonicalize_cross_concat_inputs(%arg0 : tensor<1x12x12xf32>, %arg1 : tensor<1x12x12xf32>) -> (tensor<1x12x15xf32>, tensor<1x12x20xf32>) { 772 %0 = tosa.concat %arg0, %arg1 {axis = 2 : i32} : (tensor<1x12x12xf32>, tensor<1x12x12xf32>) -> tensor<1x12x24xf32> 773 %1 = tosa.const_shape {value = dense<[0, 0, 0]> : tensor<3xindex>} : () -> !tosa.shape<3> 774 %2 = tosa.const_shape {value = dense<[0, 0, 4]> : tensor<3xindex>} : () -> !tosa.shape<3> 775 %3 = tosa.const_shape {value = dense<[1, 12, 15]> : tensor<3xindex>} : () -> !tosa.shape<3> 776 %4 = tosa.const_shape {value = dense<[1, 12, 20]> : tensor<3xindex>} : () -> !tosa.shape<3> 777 %5 = tosa.slice %0, %1, %3 : (tensor<1x12x24xf32>, !tosa.shape<3>, !tosa.shape<3>) -> tensor<1x12x15xf32> 778 %6 = tosa.slice %0, %2, %4 : (tensor<1x12x24xf32>, !tosa.shape<3>, !tosa.shape<3>) -> tensor<1x12x20xf32> 779 return %5, %6 : tensor<1x12x15xf32>, tensor<1x12x20xf32> 780} 781 782// ----- 783 784// CHECK-LABEL: @canonicalize_concat_slice_on_non_concat_axis 785// CHECK-SAME: %[[VAL_0:.*]]: tensor<1x12x12xf32>, %[[VAL_1:.*]]: tensor<1x12x12xf32> 786// CHECK-DAG: %[[VAL_2:.*]] = tosa.const_shape {value = dense<[1, 3, 0]> : tensor<3xindex>} 787// CHECK-DAG: %[[VAL_3:.*]] = tosa.const_shape {value = dense<[1, 3, 12]> : tensor<3xindex>} 788// CHECK-DAG: %[[VAL_4:.*]] = tosa.const_shape {value = dense<0> : tensor<3xindex>} 789// CHECK-DAG: %[[VAL_5:.*]] = tosa.const_shape {value = dense<[1, 6, 12]> : tensor<3xindex>} 790// CHECK: %[[VAL_6:.*]] = tosa.slice %[[VAL_0]], %[[VAL_4]], %[[VAL_5]] 791// CHECK: %[[VAL_7:.*]] = tosa.slice %[[VAL_1]], %[[VAL_2]], %[[VAL_3]] 792// CHECK: return %[[VAL_6]], %[[VAL_7]] : tensor<1x6x12xf32>, tensor<1x3x12xf32> 793func.func @canonicalize_concat_slice_on_non_concat_axis(%arg0 : tensor<1x12x12xf32>, %arg1 : tensor<1x12x12xf32>) -> (tensor<1x6x12xf32>, tensor<1x3x12xf32>) { 794 %0 = tosa.concat %arg0, %arg1 {axis = 2 : i32} : (tensor<1x12x12xf32>, tensor<1x12x12xf32>) -> tensor<1x12x24xf32> 795 %1 = tosa.const_shape {value = dense<[0, 0, 0]> : tensor<3xindex>} : () -> !tosa.shape<3> 796 %2 = tosa.const_shape {value = dense<[1, 6, 12]> : tensor<3xindex>} : () -> !tosa.shape<3> 797 %3 = tosa.const_shape {value = dense<[1, 3, 12]> : tensor<3xindex>} : () -> !tosa.shape<3> 798 %4 = tosa.slice %0, %1, %2 : (tensor<1x12x24xf32>, !tosa.shape<3>, !tosa.shape<3>) -> tensor<1x6x12xf32> 799 %5 = tosa.slice %0, %3, %3 : (tensor<1x12x24xf32>, !tosa.shape<3>, !tosa.shape<3>) -> tensor<1x3x12xf32> 800 return %4, %5 : tensor<1x6x12xf32>, tensor<1x3x12xf32> 801} 802 803// ----- 804 805// CHECK-LABEL: @fold_log_exp 806func.func @fold_log_exp(%arg0: tensor<?x1xf32>) -> tensor<?x1xf32> { 807 // CHECK: return %arg{{.*}} : tensor<?x1xf32> 808 %0 = tosa.exp %arg0 : (tensor<?x1xf32>) -> tensor<?x1xf32> 809 %1 = tosa.log %0 : (tensor<?x1xf32>) -> tensor<?x1xf32> 810 return %1 : tensor<?x1xf32> 811} 812 813// ----- 814 815// CHECK-LABEL: @fold_exp_log 816func.func @fold_exp_log(%arg0: tensor<?x1xf32>) -> tensor<?x1xf32> { 817 // CHECK: return %arg{{.*}} : tensor<?x1xf32> 818 %0 = tosa.log %arg0 : (tensor<?x1xf32>) -> tensor<?x1xf32> 819 %1 = tosa.exp %0 : (tensor<?x1xf32>) -> tensor<?x1xf32> 820 return %1 : tensor<?x1xf32> 821} 822 823// ----- 824 825// CHECK-LABEL: @fold_negate_negate 826func.func @fold_negate_negate(%arg0: tensor<?x1xf32>) -> tensor<?x1xf32> { 827 // CHECK: return %arg{{.*}} : tensor<?x1xf32> 828 %0 = tosa.negate %arg0 : (tensor<?x1xf32>) -> tensor<?x1xf32> 829 %1 = tosa.negate %0 : (tensor<?x1xf32>) -> tensor<?x1xf32> 830 return %1 : tensor<?x1xf32> 831} 832 833// ----- 834 835// CHECK-LABEL: @fold_abs_abs 836func.func @fold_abs_abs(%arg0: tensor<?x1xf32>) -> tensor<?x1xf32> { 837 // CHECK: %[[ABS:.*]] = tosa.abs %arg{{.*}} : (tensor<?x1xf32>) -> tensor<?x1xf32> 838 // CHECK: return %[[ABS]] : tensor<?x1xf32> 839 %0 = tosa.abs %arg0 : (tensor<?x1xf32>) -> tensor<?x1xf32> 840 %1 = tosa.abs %0 : (tensor<?x1xf32>) -> tensor<?x1xf32> 841 return %1 : tensor<?x1xf32> 842} 843 844// ----- 845 846// CHECK-LABEL: @fold_reduce_rank_zero 847func.func @fold_reduce_rank_zero() { 848 // CHECK-NOT: tosa.reduce_min 849 // CHECK-NOT: tosa.reverse 850 %0 = tensor.empty() : tensor<i32> 851 %1 = tosa.reduce_min %0 {axis = 0 : i32} : (tensor<i32>) -> tensor<i32> 852 %2 = tosa.reverse %0 {axis = 0 : i32} : (tensor<i32>) -> tensor<i32> 853 return 854} 855 856// ----- 857 858// CHECK-LABEL: @fold_tile_rank_zero 859func.func nested @fold_tile_rank_zero() -> tensor<i32> { 860 // CHECK-NOT: tosa.tile 861 %0 = tensor.empty() : tensor<i32> 862 %cst = tosa.const_shape { value = dense<> : tensor<0xindex> } : () -> !tosa.shape<0> 863 %1 = tosa.tile %0, %cst : (tensor<i32>, !tosa.shape<0>) -> tensor<i32> 864 return %1 : tensor<i32> 865} 866 867// ----- 868 869// CHECK-LABEL: @reshape_quant_nofold 870// check that segfault is fixed 871func.func @reshape_quant_nofold() -> tensor<1x1x1x1xi32> { 872 %0 = "tosa.const"() {value = dense<127> : tensor<i8>} : () -> tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> 873 %1 = tosa.reshape %0 {new_shape = array<i64: 1, 1, 1, 1>} : (tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>>) -> tensor<1x1x1x1x!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> 874 %2 = tosa.rescale %1 {double_round = true, input_zp = -128 : i32, multiplier = array<i32: 1073741824>, output_zp = 0 : i32, per_channel = false, scale32 = true, shift = array<i8: 30>} : (tensor<1x1x1x1x!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>>) -> tensor<1x1x1x1xi32> 875 return %2 : tensor<1x1x1x1xi32> 876} 877 878// ----- 879 880// CHECK-LABEL: @add_quant_nofold 881// check that segfault is fixed 882func.func @add_quant_nofold() -> tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> { 883 %0 = "tosa.const"() {value = dense<127> : tensor<i8>} : () -> tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> 884 %1 = tosa.add %0, %0 : (tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>>, tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>>) -> tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> 885 return %1 : tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> 886} 887 888// ----- 889 890// CHECK-LABEL: @sub_quant_nofold 891// check that segfault is fixed 892func.func @sub_quant_nofold() -> tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> { 893 %0 = "tosa.const"() {value = dense<127> : tensor<i8>} : () -> tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> 894 %1 = tosa.sub %0, %0 : (tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>>, tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>>) -> tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> 895 return %1 : tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> 896} 897 898// ----- 899 900// CHECK-LABEL: @greater_quant_fold 901func.func @greater_quant_fold() -> tensor<i1> { 902 %0 = "tosa.const"() {value = dense<0> : tensor<i8>} : () -> tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> 903 // CHECK: "tosa.const"() <{value = dense<false> 904 %2 = "tosa.greater"(%0, %0) : (tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>>, tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>>) -> tensor<i1> 905 return %2 : tensor<i1> 906} 907 908// ----- 909 910// CHECK-LABEL: @greater_equal_quant_fold 911func.func @greater_equal_quant_fold() -> tensor<i1> { 912 %0 = "tosa.const"() {value = dense<0> : tensor<i8>} : () -> tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> 913 // CHECK: "tosa.const"() <{value = dense<true> 914 %2 = "tosa.greater_equal"(%0, %0) : (tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>>, tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>>) -> tensor<i1> 915 return %2 : tensor<i1> 916} 917 918// ----- 919 920// CHECK-LABEL: @equal_quant_fold 921func.func @equal_quant_fold() -> tensor<i1> { 922 %0 = "tosa.const"() {value = dense<0> : tensor<i8>} : () -> tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> 923 // CHECK: "tosa.const"() <{value = dense<true> 924 %2 = "tosa.equal"(%0, %0) : (tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>>, tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>>) -> tensor<i1> 925 return %2 : tensor<i1> 926} 927 928// ----- 929 930// CHECK-LABEL: @cast_quant_nofold 931func.func @cast_quant_nofold() -> tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:3>> { 932 // CHECK: tosa.cast 933 %0 = "tosa.const"() {value = dense<0> : tensor<i8>} : () -> tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> 934 %1 = "tosa.cast"(%0) : (tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>>) -> tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:3>> 935 return %1 : tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:3>> 936} 937 938// ----- 939 940// CHECK-LABEL: @reverse_quant_fold 941func.func @reverse_quant_fold() -> tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> { 942 // CHECK: %[[CST:.*]] = "tosa.const"() <{value = dense<0> : tensor<i8>}> : () -> tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> 943 // CHECK: return %[[CST]] 944 %0 = "tosa.const"() {value = dense<0> : tensor<i8>} : () -> tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> 945 %1 = "tosa.reverse"(%0) { axis = 0 : i32 } : (tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>>) -> tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> 946 return %1 : tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> 947} 948 949// ----- 950 951// CHECK-LABEL: @select_quant_fold 952func.func @select_quant_fold() -> tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> { 953 // CHECK: %[[CONST_0:.*]] = "tosa.const"() <{value = dense<0> : tensor<i8>}> : () -> tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> 954 // CHECK: return %[[CONST_0]] 955 %0 = "tosa.const"() {value = dense<true> : tensor<i1>} : () -> tensor<i1> 956 %1 = "tosa.const"() {value = dense<0> : tensor<i8>} : () -> tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> 957 %2 = "tosa.const"() {value = dense<127> : tensor<i8>} : () -> tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> 958 %3 = "tosa.select"(%0, %1, %2) : (tensor<i1>, tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>>, tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>>) -> tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> 959 return %3 : tensor<!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> 960} 961 962// ----- 963 964// CHECK-LABEL: @mul_quant_nofold 965func.func @mul_quant_nofold() -> tensor<1x!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> { 966 // CHECK: tosa.mul 967 %0 = "tosa.const"() {value = dense<0> : tensor<1xi8>} : () -> tensor<1x!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> 968 %1 = "tosa.const"() {value = dense<1> : tensor<1xi8>} : () -> tensor<1x!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> 969 %2 = tosa.mul %0, %1 : (tensor<1x!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>>, tensor<1x!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>>)-> tensor<1x!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> 970 return %2 : tensor<1x!quant.uniform<i8:f32, 3.0757404601899907E-5:-128>> 971} 972 973 974// ----- 975 976// CHECK-LABEL: @fold_reciprocal 977func.func nested @fold_reciprocal() -> tensor<3x600x1200xf32> { 978 // CHECK: %[[VAL_0:.*]] = "tosa.const"() <{value = dense<8.620690e-03> : tensor<3x600x1200xf32>}> : () -> tensor<3x600x1200xf32> 979 // CHECK: return %[[VAL_0]] : tensor<3x600x1200xf32> 980 // CHECK: } 981 %0 = "tosa.const"(){ value = dense<116.0>: tensor<f32> }: () -> tensor<f32> 982 %1 = "tosa.cast"(%0) : (tensor<f32>) -> tensor<3x600x1200xf32> 983 %2 = "tosa.reciprocal"(%1): (tensor<3x600x1200xf32>) -> tensor<3x600x1200xf32> 984 return %2 : tensor<3x600x1200xf32> 985} 986 987// ----- 988 989// CHECK-LABEL: @do_not_fold_reciprocal_int 990func.func nested @do_not_fold_reciprocal_int() -> tensor<3x600x1200xi32> { 991 // CHECK: tosa.reciprocal 992 %0 = "tosa.const"(){ value = dense<11>: tensor<i32> }: () -> tensor<i32> 993 %1 = "tosa.cast"(%0) : (tensor<i32>) -> tensor<3x600x1200xi32> 994 %2 = "tosa.reciprocal"(%1): (tensor<3x600x1200xi32>) -> tensor<3x600x1200xi32> 995 return %2 : tensor<3x600x1200xi32> 996} 997