xref: /llvm-project/mlir/test/Dialect/Tosa/canonicalize.mlir (revision 956c0707d9098499a2682297b71f46b0a562eed9)
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