Ensure SplitEdge to return the new block between the two given blocks
[llvm-project.git] / mlir / test / Dialect / SPIRV / canonicalize.mlir
blobcb955b4512ee5d6671f0be60766a5d7870e30037
1 // RUN: mlir-opt %s -split-input-file -pass-pipeline='func(canonicalize)' | FileCheck %s
3 //===----------------------------------------------------------------------===//
4 // spv.AccessChain
5 //===----------------------------------------------------------------------===//
7 func @combine_full_access_chain() -> f32 {
8   // CHECK: %[[INDEX:.*]] = spv.constant 0
9   // CHECK-NEXT: %[[VAR:.*]] = spv.Variable
10   // CHECK-NEXT: %[[PTR:.*]] = spv.AccessChain %[[VAR]][%[[INDEX]], %[[INDEX]], %[[INDEX]]]
11   // CHECK-NEXT: spv.Load "Function" %[[PTR]]
12   %c0 = spv.constant 0: i32
13   %0 = spv.Variable : !spv.ptr<!spv.struct<(!spv.array<4x!spv.array<4xf32>>, !spv.array<4xi32>)>, Function>
14   %1 = spv.AccessChain %0[%c0] : !spv.ptr<!spv.struct<(!spv.array<4x!spv.array<4xf32>>, !spv.array<4xi32>)>, Function>, i32
15   %2 = spv.AccessChain %1[%c0, %c0] : !spv.ptr<!spv.array<4x!spv.array<4xf32>>, Function>, i32, i32
16   %3 = spv.Load "Function" %2 : f32
17   spv.ReturnValue %3 : f32
20 // -----
22 func @combine_access_chain_multi_use() -> !spv.array<4xf32> {
23   // CHECK: %[[INDEX:.*]] = spv.constant 0
24   // CHECK-NEXT: %[[VAR:.*]] = spv.Variable
25   // CHECK-NEXT: %[[PTR_0:.*]] = spv.AccessChain %[[VAR]][%[[INDEX]], %[[INDEX]]]
26   // CHECK-NEXT: %[[PTR_1:.*]] = spv.AccessChain %[[VAR]][%[[INDEX]], %[[INDEX]], %[[INDEX]]]
27   // CHECK-NEXT: spv.Load "Function" %[[PTR_0]]
28   // CHECK-NEXT: spv.Load "Function" %[[PTR_1]]
29   %c0 = spv.constant 0: i32
30   %0 = spv.Variable : !spv.ptr<!spv.struct<(!spv.array<4x!spv.array<4xf32>>, !spv.array<4xi32>)>, Function>
31   %1 = spv.AccessChain %0[%c0] : !spv.ptr<!spv.struct<(!spv.array<4x!spv.array<4xf32>>, !spv.array<4xi32>)>, Function>, i32
32   %2 = spv.AccessChain %1[%c0] : !spv.ptr<!spv.array<4x!spv.array<4xf32>>, Function>, i32
33   %3 = spv.AccessChain %2[%c0] : !spv.ptr<!spv.array<4xf32>, Function>, i32
34   %4 = spv.Load "Function" %2 : !spv.array<4xf32>
35   %5 = spv.Load "Function" %3 : f32
36   spv.ReturnValue %4: !spv.array<4xf32>
39 // -----
41 func @dont_combine_access_chain_without_common_base() -> !spv.array<4xi32> {
42   // CHECK: %[[INDEX:.*]] = spv.constant 1
43   // CHECK-NEXT: %[[VAR_0:.*]] = spv.Variable
44   // CHECK-NEXT: %[[VAR_1:.*]] = spv.Variable
45   // CHECK-NEXT: %[[VAR_0_PTR:.*]] = spv.AccessChain %[[VAR_0]][%[[INDEX]]]
46   // CHECK-NEXT: %[[VAR_1_PTR:.*]] = spv.AccessChain %[[VAR_1]][%[[INDEX]]]
47   // CHECK-NEXT: spv.Load "Function" %[[VAR_0_PTR]]
48   // CHECK-NEXT: spv.Load "Function" %[[VAR_1_PTR]]
49   %c1 = spv.constant 1: i32
50   %0 = spv.Variable : !spv.ptr<!spv.struct<(!spv.array<4x!spv.array<4xf32>>, !spv.array<4xi32>)>, Function>
51   %1 = spv.Variable : !spv.ptr<!spv.struct<(!spv.array<4x!spv.array<4xf32>>, !spv.array<4xi32>)>, Function>
52   %2 = spv.AccessChain %0[%c1] : !spv.ptr<!spv.struct<(!spv.array<4x!spv.array<4xf32>>, !spv.array<4xi32>)>, Function>, i32
53   %3 = spv.AccessChain %1[%c1] : !spv.ptr<!spv.struct<(!spv.array<4x!spv.array<4xf32>>, !spv.array<4xi32>)>, Function>, i32
54   %4 = spv.Load "Function" %2 : !spv.array<4xi32>
55   %5 = spv.Load "Function" %3 : !spv.array<4xi32>
56   spv.ReturnValue %4 : !spv.array<4xi32>
59 // -----
61 //===----------------------------------------------------------------------===//
62 // spv.Bitcast
63 //===----------------------------------------------------------------------===//
65 func @convert_bitcast_full(%arg0 : vector<2xf32>) -> f64 {
66   // CHECK: %[[RESULT:.*]] = spv.Bitcast {{%.*}} : vector<2xf32> to f64
67   // CHECK-NEXT: spv.ReturnValue %[[RESULT]]
68   %0 = spv.Bitcast %arg0 : vector<2xf32> to vector<2xi32>
69   %1 = spv.Bitcast %0 : vector<2xi32> to i64
70   %2 = spv.Bitcast %1 : i64 to f64
71   spv.ReturnValue %2 : f64
74 // -----
76 func @convert_bitcast_multi_use(%arg0 : vector<2xf32>, %arg1 : !spv.ptr<i64, Uniform>) -> f64 {
77   // CHECK: %[[RESULT_0:.*]] = spv.Bitcast {{%.*}} : vector<2xf32> to i64
78   // CHECK-NEXT: %[[RESULT_1:.*]] = spv.Bitcast {{%.*}} : vector<2xf32> to f64
79   // CHECK-NEXT: spv.Store {{".*"}} {{%.*}}, %[[RESULT_0]]
80   // CHECK-NEXT: spv.ReturnValue %[[RESULT_1]]
81   %0 = spv.Bitcast %arg0 : vector<2xf32> to i64
82   %1 = spv.Bitcast %0 : i64 to f64
83   spv.Store "Uniform" %arg1, %0 : i64
84   spv.ReturnValue %1 : f64
87 // -----
89 //===----------------------------------------------------------------------===//
90 // spv.CompositeExtract
91 //===----------------------------------------------------------------------===//
93 // CHECK-LABEL: extract_vector
94 func @extract_vector() -> (i32, i32, i32) {
95   // CHECK: spv.constant 42 : i32
96   // CHECK: spv.constant -33 : i32
97   // CHECK: spv.constant 6 : i32
98   %0 = spv.constant dense<[42, -33, 6]> : vector<3xi32>
99   %1 = spv.CompositeExtract %0[0 : i32] : vector<3xi32>
100   %2 = spv.CompositeExtract %0[1 : i32] : vector<3xi32>
101   %3 = spv.CompositeExtract %0[2 : i32] : vector<3xi32>
102   return %1, %2, %3 : i32, i32, i32
105 // -----
107 // CHECK-LABEL: extract_array_final
108 func @extract_array_final() -> (i32, i32) {
109   // CHECK: spv.constant 4 : i32
110   // CHECK: spv.constant -5 : i32
111   %0 = spv.constant [dense<[4, -5]> : vector<2xi32>] : !spv.array<1 x vector<2xi32>>
112   %1 = spv.CompositeExtract %0[0 : i32, 0 : i32] : !spv.array<1 x vector<2 x i32>>
113   %2 = spv.CompositeExtract %0[0 : i32, 1 : i32] : !spv.array<1 x vector<2 x i32>>
114   return %1, %2 : i32, i32
117 // -----
119 // CHECK-LABEL: extract_array_interm
120 func @extract_array_interm() -> (vector<2xi32>) {
121   // CHECK: spv.constant dense<[4, -5]> : vector<2xi32>
122   %0 = spv.constant [dense<[4, -5]> : vector<2xi32>] : !spv.array<1 x vector<2xi32>>
123   %1 = spv.CompositeExtract %0[0 : i32] : !spv.array<1 x vector<2 x i32>>
124   return %1 : vector<2xi32>
127 // -----
129 // CHECK-LABEL: extract_from_not_constant
130 func @extract_from_not_constant() -> i32 {
131   %0 = spv.Variable : !spv.ptr<vector<3xi32>, Function>
132   %1 = spv.Load "Function" %0 : vector<3xi32>
133   // CHECK: spv.CompositeExtract
134   %2 = spv.CompositeExtract %1[0 : i32] : vector<3xi32>
135   spv.ReturnValue %2 : i32
138 // -----
140 //===----------------------------------------------------------------------===//
141 // spv.constant
142 //===----------------------------------------------------------------------===//
144 // TODO: test constants in different blocks
146 func @deduplicate_scalar_constant() -> (i32, i32) {
147   // CHECK: %[[CST:.*]] = spv.constant 42 : i32
148   %0 = spv.constant 42 : i32
149   %1 = spv.constant 42 : i32
150   // CHECK-NEXT: return %[[CST]], %[[CST]]
151   return %0, %1 : i32, i32
154 // -----
156 func @deduplicate_vector_constant() -> (vector<3xi32>, vector<3xi32>) {
157   // CHECK: %[[CST:.*]] = spv.constant dense<[1, 2, 3]> : vector<3xi32>
158   %0 = spv.constant dense<[1, 2, 3]> : vector<3xi32>
159   %1 = spv.constant dense<[1, 2, 3]> : vector<3xi32>
160   // CHECK-NEXT: return %[[CST]], %[[CST]]
161   return %0, %1 : vector<3xi32>, vector<3xi32>
164 // -----
166 func @deduplicate_composite_constant() -> (!spv.array<1 x vector<2xi32>>, !spv.array<1 x vector<2xi32>>) {
167   // CHECK: %[[CST:.*]] = spv.constant [dense<5> : vector<2xi32>] : !spv.array<1 x vector<2xi32>>
168   %0 = spv.constant [dense<5> : vector<2xi32>] : !spv.array<1 x vector<2xi32>>
169   %1 = spv.constant [dense<5> : vector<2xi32>] : !spv.array<1 x vector<2xi32>>
170   // CHECK-NEXT: return %[[CST]], %[[CST]]
171   return %0, %1 : !spv.array<1 x vector<2xi32>>, !spv.array<1 x vector<2xi32>>
174 // -----
176 //===----------------------------------------------------------------------===//
177 // spv.IAdd
178 //===----------------------------------------------------------------------===//
180 // CHECK-LABEL: @iadd_zero
181 // CHECK-SAME: (%[[ARG:.*]]: i32)
182 func @iadd_zero(%arg0: i32) -> (i32, i32) {
183   %zero = spv.constant 0 : i32
184   %0 = spv.IAdd %arg0, %zero : i32
185   %1 = spv.IAdd %zero, %arg0 : i32
186   // CHECK: return %[[ARG]], %[[ARG]]
187   return %0, %1: i32, i32
190 // CHECK-LABEL: @const_fold_scalar_iadd_normal
191 func @const_fold_scalar_iadd_normal() -> (i32, i32, i32) {
192   %c5 = spv.constant 5 : i32
193   %cn8 = spv.constant -8 : i32
195   // CHECK: spv.constant 10
196   // CHECK: spv.constant -16
197   // CHECK: spv.constant -3
198   %0 = spv.IAdd %c5, %c5 : i32
199   %1 = spv.IAdd %cn8, %cn8 : i32
200   %2 = spv.IAdd %c5, %cn8 : i32
201   return %0, %1, %2: i32, i32, i32
204 // CHECK-LABEL: @const_fold_scalar_iadd_flow
205 func @const_fold_scalar_iadd_flow() -> (i32, i32, i32, i32) {
206   %c1 = spv.constant 1 : i32
207   %c2 = spv.constant 2 : i32
208   %c3 = spv.constant 4294967295 : i32  // 2^32 - 1: 0xffff ffff
209   %c4 = spv.constant -2147483648 : i32 // -2^31   : 0x8000 0000
210   %c5 = spv.constant -1 : i32          //         : 0xffff ffff
211   %c6 = spv.constant -2 : i32          //         : 0xffff fffe
213   // 0x0000 0001 + 0xffff ffff = 0x1 0000 0000 -> 0x0000 0000
214   // CHECK: spv.constant 0
215   %0 = spv.IAdd %c1, %c3 : i32
216   // 0x0000 0002 + 0xffff ffff = 0x1 0000 0001 -> 0x0000 0001
217   // CHECK: spv.constant 1
218   %1 = spv.IAdd %c2, %c3 : i32
219   // 0x8000 0000 + 0xffff ffff = 0x1 7fff ffff -> 0x7fff ffff
220   // CHECK: spv.constant 2147483647
221   %2 = spv.IAdd %c4, %c5 : i32
222   // 0x8000 0000 + 0xffff fffe = 0x1 7fff fffe -> 0x7fff fffe
223   // CHECK: spv.constant 2147483646
224   %3 = spv.IAdd %c4, %c6 : i32
225   return %0, %1, %2, %3: i32, i32, i32, i32
228 // CHECK-LABEL: @const_fold_vector_iadd
229 func @const_fold_vector_iadd() -> vector<3xi32> {
230   %vc1 = spv.constant dense<[42, -55, 127]> : vector<3xi32>
231   %vc2 = spv.constant dense<[-3, -15, 28]> : vector<3xi32>
233   // CHECK: spv.constant dense<[39, -70, 155]>
234   %0 = spv.IAdd %vc1, %vc2 : vector<3xi32>
235   return %0: vector<3xi32>
238 // -----
240 //===----------------------------------------------------------------------===//
241 // spv.IMul
242 //===----------------------------------------------------------------------===//
244 // CHECK-LABEL: @imul_zero_one
245 // CHECK-SAME: (%[[ARG:.*]]: i32)
246 func @imul_zero_one(%arg0: i32) -> (i32, i32) {
247   // CHECK: %[[ZERO:.*]] = spv.constant 0
248   %zero = spv.constant 0 : i32
249   %one = spv.constant 1: i32
250   %0 = spv.IMul %arg0, %zero : i32
251   %1 = spv.IMul %one, %arg0 : i32
252   // CHECK: return %[[ZERO]], %[[ARG]]
253   return %0, %1: i32, i32
256 // CHECK-LABEL: @const_fold_scalar_imul_normal
257 func @const_fold_scalar_imul_normal() -> (i32, i32, i32) {
258   %c5 = spv.constant 5 : i32
259   %cn8 = spv.constant -8 : i32
260   %c7 = spv.constant 7 : i32
262   // CHECK: spv.constant 35
263   // CHECK: spv.constant -40
264   // CHECK: spv.constant -56
265   %0 = spv.IMul %c7, %c5 : i32
266   %1 = spv.IMul %c5, %cn8 : i32
267   %2 = spv.IMul %cn8, %c7 : i32
268   return %0, %1, %2: i32, i32, i32
271 // CHECK-LABEL: @const_fold_scalar_imul_flow
272 func @const_fold_scalar_imul_flow() -> (i32, i32, i32) {
273   %c1 = spv.constant 2 : i32
274   %c2 = spv.constant 4 : i32
275   %c3 = spv.constant 4294967295 : i32  // 2^32 - 1 : 0xffff ffff
276   %c4 = spv.constant 2147483647 : i32  // 2^31 - 1 : 0x7fff ffff
278   // (0xffff ffff << 1) = 0x1 ffff fffe -> 0xffff fffe
279   // CHECK: %[[CST2:.*]] = spv.constant -2
280   %0 = spv.IMul %c1, %c3 : i32
281   // (0x7fff ffff << 1) = 0x0 ffff fffe -> 0xffff fffe
282   %1 = spv.IMul %c1, %c4 : i32
283   // (0x7fff ffff << 2) = 0x1 ffff fffc -> 0xffff fffc
284   // CHECK: %[[CST4:.*]] = spv.constant -4
285   %2 = spv.IMul %c4, %c2 : i32
286   // CHECK: return %[[CST2]], %[[CST2]], %[[CST4]]
287   return %0, %1, %2: i32, i32, i32
291 // CHECK-LABEL: @const_fold_vector_imul
292 func @const_fold_vector_imul() -> vector<3xi32> {
293   %vc1 = spv.constant dense<[42, -55, 127]> : vector<3xi32>
294   %vc2 = spv.constant dense<[-3, -15, 28]> : vector<3xi32>
296   // CHECK: spv.constant dense<[-126, 825, 3556]>
297   %0 = spv.IMul %vc1, %vc2 : vector<3xi32>
298   return %0: vector<3xi32>
301 // -----
303 //===----------------------------------------------------------------------===//
304 // spv.ISub
305 //===----------------------------------------------------------------------===//
307 // CHECK-LABEL: @isub_x_x
308 func @isub_x_x(%arg0: i32) -> i32 {
309   // CHECK: spv.constant 0
310   %0 = spv.ISub %arg0, %arg0: i32
311   return %0: i32
314 // CHECK-LABEL: @const_fold_scalar_isub_normal
315 func @const_fold_scalar_isub_normal() -> (i32, i32, i32) {
316   %c5 = spv.constant 5 : i32
317   %cn8 = spv.constant -8 : i32
318   %c7 = spv.constant 7 : i32
320   // CHECK: spv.constant 2
321   // CHECK: spv.constant 13
322   // CHECK: spv.constant -15
323   %0 = spv.ISub %c7, %c5 : i32
324   %1 = spv.ISub %c5, %cn8 : i32
325   %2 = spv.ISub %cn8, %c7 : i32
326   return %0, %1, %2: i32, i32, i32
329 // CHECK-LABEL: @const_fold_scalar_isub_flow
330 func @const_fold_scalar_isub_flow() -> (i32, i32, i32, i32) {
331   %c1 = spv.constant 0 : i32
332   %c2 = spv.constant 1 : i32
333   %c3 = spv.constant 4294967295 : i32  // 2^32 - 1 : 0xffff ffff
334   %c4 = spv.constant 2147483647 : i32  // 2^31     : 0x7fff ffff
335   %c5 = spv.constant -1 : i32          //          : 0xffff ffff
336   %c6 = spv.constant -2 : i32          //          : 0xffff fffe
338   // 0x0000 0000 - 0xffff ffff -> 0x0000 0000 + 0x0000 0001 = 0x0000 0001
339   // CHECK: spv.constant 1
340   %0 = spv.ISub %c1, %c3 : i32
341   // 0x0000 0001 - 0xffff ffff -> 0x0000 0001 + 0x0000 0001 = 0x0000 0002
342   // CHECK: spv.constant 2
343   %1 = spv.ISub %c2, %c3 : i32
344   // 0xffff ffff - 0x7fff ffff -> 0xffff ffff + 0x8000 0001 = 0x1 8000 0000
345   // CHECK: spv.constant -2147483648
346   %2 = spv.ISub %c5, %c4 : i32
347   // 0xffff fffe - 0x7fff ffff -> 0xffff fffe + 0x8000 0001 = 0x1 7fff ffff
348   // CHECK: spv.constant 2147483647
349   %3 = spv.ISub %c6, %c4 : i32
350   return %0, %1, %2, %3: i32, i32, i32, i32
353 // CHECK-LABEL: @const_fold_vector_isub
354 func @const_fold_vector_isub() -> vector<3xi32> {
355   %vc1 = spv.constant dense<[42, -55, 127]> : vector<3xi32>
356   %vc2 = spv.constant dense<[-3, -15, 28]> : vector<3xi32>
358   // CHECK: spv.constant dense<[45, -40, 99]>
359   %0 = spv.ISub %vc1, %vc2 : vector<3xi32>
360   return %0: vector<3xi32>
363 // -----
365 //===----------------------------------------------------------------------===//
366 // spv.LogicalAnd
367 //===----------------------------------------------------------------------===//
369 // CHECK-LABEL: @convert_logical_and_true_false_scalar
370 // CHECK-SAME: %[[ARG:.+]]: i1
371 func @convert_logical_and_true_false_scalar(%arg: i1) -> (i1, i1) {
372   %true = spv.constant true
373   // CHECK: %[[FALSE:.+]] = spv.constant false
374   %false = spv.constant false
375   %0 = spv.LogicalAnd %true, %arg: i1
376   %1 = spv.LogicalAnd %arg, %false: i1
377   // CHECK: return %[[ARG]], %[[FALSE]]
378   return %0, %1: i1, i1
381 // CHECK-LABEL: @convert_logical_and_true_false_vector
382 // CHECK-SAME: %[[ARG:.+]]: vector<3xi1>
383 func @convert_logical_and_true_false_vector(%arg: vector<3xi1>) -> (vector<3xi1>, vector<3xi1>) {
384   %true = spv.constant dense<true> : vector<3xi1>
385   // CHECK: %[[FALSE:.+]] = spv.constant dense<false>
386   %false = spv.constant dense<false> : vector<3xi1>
387   %0 = spv.LogicalAnd %true, %arg: vector<3xi1>
388   %1 = spv.LogicalAnd %arg, %false: vector<3xi1>
389   // CHECK: return %[[ARG]], %[[FALSE]]
390   return %0, %1: vector<3xi1>, vector<3xi1>
393 // -----
395 //===----------------------------------------------------------------------===//
396 // spv.LogicalNot
397 //===----------------------------------------------------------------------===//
399 func @convert_logical_not_to_not_equal(%arg0: vector<3xi64>, %arg1: vector<3xi64>) -> vector<3xi1> {
400   // CHECK: %[[RESULT:.*]] = spv.INotEqual {{%.*}}, {{%.*}} : vector<3xi64>
401   // CHECK-NEXT: spv.ReturnValue %[[RESULT]] : vector<3xi1>
402   %2 = spv.IEqual %arg0, %arg1 : vector<3xi64>
403   %3 = spv.LogicalNot %2 : vector<3xi1>
404   spv.ReturnValue %3 : vector<3xi1>
407 // -----
409 func @convert_logical_not_to_equal(%arg0: vector<3xi64>, %arg1: vector<3xi64>) -> vector<3xi1> {
410   // CHECK: %[[RESULT:.*]] = spv.IEqual {{%.*}}, {{%.*}} : vector<3xi64>
411   // CHECK-NEXT: spv.ReturnValue %[[RESULT]] : vector<3xi1>
412   %2 = spv.INotEqual %arg0, %arg1 : vector<3xi64>
413   %3 = spv.LogicalNot %2 : vector<3xi1>
414   spv.ReturnValue %3 : vector<3xi1>
417 // -----
419 func @convert_logical_not_parent_multi_use(%arg0: vector<3xi64>, %arg1: vector<3xi64>, %arg2: !spv.ptr<vector<3xi1>, Uniform>) -> vector<3xi1> {
420   // CHECK: %[[RESULT_0:.*]] = spv.INotEqual {{%.*}}, {{%.*}} : vector<3xi64>
421   // CHECK-NEXT: %[[RESULT_1:.*]] = spv.IEqual {{%.*}}, {{%.*}} : vector<3xi64>
422   // CHECK-NEXT: spv.Store "Uniform" {{%.*}}, %[[RESULT_0]]
423   // CHECK-NEXT: spv.ReturnValue %[[RESULT_1]]
424   %0 = spv.INotEqual %arg0, %arg1 : vector<3xi64>
425   %1 = spv.LogicalNot %0 : vector<3xi1>
426   spv.Store "Uniform" %arg2, %0 : vector<3xi1>
427   spv.ReturnValue %1 : vector<3xi1>
430 // -----
432 func @convert_logical_not_to_logical_not_equal(%arg0: vector<3xi1>, %arg1: vector<3xi1>) -> vector<3xi1> {
433   // CHECK: %[[RESULT:.*]] = spv.LogicalNotEqual {{%.*}}, {{%.*}} : vector<3xi1>
434   // CHECK-NEXT: spv.ReturnValue %[[RESULT]] : vector<3xi1>
435   %2 = spv.LogicalEqual %arg0, %arg1 : vector<3xi1>
436   %3 = spv.LogicalNot %2 : vector<3xi1>
437   spv.ReturnValue %3 : vector<3xi1>
440 // -----
442 func @convert_logical_not_to_logical_equal(%arg0: vector<3xi1>, %arg1: vector<3xi1>) -> vector<3xi1> {
443   // CHECK: %[[RESULT:.*]] = spv.LogicalEqual {{%.*}}, {{%.*}} : vector<3xi1>
444   // CHECK-NEXT: spv.ReturnValue %[[RESULT]] : vector<3xi1>
445   %2 = spv.LogicalNotEqual %arg0, %arg1 : vector<3xi1>
446   %3 = spv.LogicalNot %2 : vector<3xi1>
447   spv.ReturnValue %3 : vector<3xi1>
450 // -----
452 //===----------------------------------------------------------------------===//
453 // spv.LogicalOr
454 //===----------------------------------------------------------------------===//
456 // CHECK-LABEL: @convert_logical_or_true_false_scalar
457 // CHECK-SAME: %[[ARG:.+]]: i1
458 func @convert_logical_or_true_false_scalar(%arg: i1) -> (i1, i1) {
459   // CHECK: %[[TRUE:.+]] = spv.constant true
460   %true = spv.constant true
461   %false = spv.constant false
462   %0 = spv.LogicalOr %true, %arg: i1
463   %1 = spv.LogicalOr %arg, %false: i1
464   // CHECK: return %[[TRUE]], %[[ARG]]
465   return %0, %1: i1, i1
468 // CHECK-LABEL: @convert_logical_or_true_false_vector
469 // CHECK-SAME: %[[ARG:.+]]: vector<3xi1>
470 func @convert_logical_or_true_false_vector(%arg: vector<3xi1>) -> (vector<3xi1>, vector<3xi1>) {
471   // CHECK: %[[TRUE:.+]] = spv.constant dense<true>
472   %true = spv.constant dense<true> : vector<3xi1>
473   %false = spv.constant dense<false> : vector<3xi1>
474   %0 = spv.LogicalOr %true, %arg: vector<3xi1>
475   %1 = spv.LogicalOr %arg, %false: vector<3xi1>
476   // CHECK: return %[[TRUE]], %[[ARG]]
477   return %0, %1: vector<3xi1>, vector<3xi1>
480 // -----
482 //===----------------------------------------------------------------------===//
483 // spv.selection
484 //===----------------------------------------------------------------------===//
486 func @canonicalize_selection_op_scalar_type(%cond: i1) -> () {
487   %0 = spv.constant 0: i32
488   // CHECK: %[[TRUE_VALUE:.*]] = spv.constant 1 : i32
489   %1 = spv.constant 1: i32
490   // CHECK: %[[FALSE_VALUE:.*]] = spv.constant 2 : i32
491   %2 = spv.constant 2: i32
492   // CHECK: %[[DST_VAR:.*]] = spv.Variable init({{%.*}}) : !spv.ptr<i32, Function>
493   %3 = spv.Variable init(%0) : !spv.ptr<i32, Function>
495   // CHECK: %[[SRC_VALUE:.*]] = spv.Select {{%.*}}, %[[TRUE_VALUE]], %[[FALSE_VALUE]] : i1, i32
496   // CHECK-NEXT: spv.Store "Function" %[[DST_VAR]], %[[SRC_VALUE]] ["Aligned", 4] : i32
497   // CHECK-NEXT: spv.Return
498   spv.selection {
499     spv.BranchConditional %cond, ^then, ^else
501   ^else:
502     spv.Store "Function" %3, %2 ["Aligned", 4]: i32
503     spv.Branch ^merge
505   ^then:
506     spv.Store "Function" %3, %1 ["Aligned", 4]: i32
507     spv.Branch ^merge
509   ^merge:
510     spv.mlir.merge
511   }
512   spv.Return
515 // -----
517 func @canonicalize_selection_op_vector_type(%cond: i1) -> () {
518   %0 = spv.constant dense<[0, 1, 2]> : vector<3xi32>
519   // CHECK: %[[TRUE_VALUE:.*]] = spv.constant dense<[1, 2, 3]> : vector<3xi32>
520   %1 = spv.constant dense<[1, 2, 3]> : vector<3xi32>
521   // CHECK: %[[FALSE_VALUE:.*]] = spv.constant dense<[2, 3, 4]> : vector<3xi32>
522   %2 = spv.constant dense<[2, 3, 4]> : vector<3xi32>
523   // CHECK: %[[DST_VAR:.*]] = spv.Variable init({{%.*}}) : !spv.ptr<vector<3xi32>, Function>
524   %3 = spv.Variable init(%0) : !spv.ptr<vector<3xi32>, Function>
526   // CHECK: %[[SRC_VALUE:.*]] = spv.Select {{%.*}}, %[[TRUE_VALUE]], %[[FALSE_VALUE]] : i1, vector<3xi32>
527   // CHECK-NEXT: spv.Store "Function" %[[DST_VAR]], %[[SRC_VALUE]] ["Aligned", 8] : vector<3xi32>
528   // CHECK-NEXT: spv.Return
529   spv.selection {
530     spv.BranchConditional %cond, ^then, ^else
532   ^then:
533     spv.Store "Function" %3, %1 ["Aligned", 8]:  vector<3xi32>
534     spv.Branch ^merge
536   ^else:
537     spv.Store "Function" %3, %2 ["Aligned", 8] : vector<3xi32>
538     spv.Branch ^merge
540   ^merge:
541     spv.mlir.merge
542   }
543   spv.Return
546 // -----
548 // Store to a different variables.
549 func @cannot_canonicalize_selection_op_0(%cond: i1) -> () {
550   %0 = spv.constant dense<[0, 1, 2]> : vector<3xi32>
551   // CHECK: %[[SRC_VALUE_0:.*]] = spv.constant dense<[1, 2, 3]> : vector<3xi32>
552   %1 = spv.constant dense<[1, 2, 3]> : vector<3xi32>
553   // CHECK: %[[SRC_VALUE_1:.*]] = spv.constant dense<[2, 3, 4]> : vector<3xi32>
554   %2 = spv.constant dense<[2, 3, 4]> : vector<3xi32>
555   // CHECK: %[[DST_VAR_0:.*]] = spv.Variable init({{%.*}}) : !spv.ptr<vector<3xi32>, Function>
556   %3 = spv.Variable init(%0) : !spv.ptr<vector<3xi32>, Function>
557   // CHECK: %[[DST_VAR_1:.*]] = spv.Variable init({{%.*}}) : !spv.ptr<vector<3xi32>, Function>
558   %4 = spv.Variable init(%0) : !spv.ptr<vector<3xi32>, Function>
560   // CHECK: spv.selection {
561   spv.selection {
562     // CHECK: spv.BranchConditional
563     // CHECK-SAME: ^bb1(%[[DST_VAR_0]], %[[SRC_VALUE_0]]
564     // CHECK-SAME: ^bb1(%[[DST_VAR_1]], %[[SRC_VALUE_1]]
565     spv.BranchConditional %cond, ^then, ^else
567   ^then:
568     // CHECK: ^bb1(%[[ARG0:.*]]: !spv.ptr<vector<3xi32>, Function>, %[[ARG1:.*]]: vector<3xi32>):
569     // CHECK: spv.Store "Function" %[[ARG0]], %[[ARG1]] ["Aligned", 8] : vector<3xi32>
570     spv.Store "Function" %3, %1 ["Aligned", 8]:  vector<3xi32>
571     spv.Branch ^merge
573   ^else:
574     spv.Store "Function" %4, %2 ["Aligned", 8] : vector<3xi32>
575     spv.Branch ^merge
577   ^merge:
578     spv.mlir.merge
579   }
580   spv.Return
583 // -----
585 // A conditional block consists of more than 2 operations.
586 func @cannot_canonicalize_selection_op_1(%cond: i1) -> () {
587   %0 = spv.constant dense<[0, 1, 2]> : vector<3xi32>
588   // CHECK: %[[SRC_VALUE_0:.*]] = spv.constant dense<[1, 2, 3]> : vector<3xi32>
589   %1 = spv.constant dense<[1, 2, 3]> : vector<3xi32>
590   // CHECK: %[[SRC_VALUE_1:.*]] = spv.constant dense<[2, 3, 4]> : vector<3xi32>
591   %2 = spv.constant dense<[2, 3, 4]> : vector<3xi32>
592   // CHECK: %[[DST_VAR_0:.*]] = spv.Variable init({{%.*}}) : !spv.ptr<vector<3xi32>, Function>
593   %3 = spv.Variable init(%0) : !spv.ptr<vector<3xi32>, Function>
594   // CHECK: %[[DST_VAR_1:.*]] = spv.Variable init({{%.*}}) : !spv.ptr<vector<3xi32>, Function>
595   %4 = spv.Variable init(%0) : !spv.ptr<vector<3xi32>, Function>
597   // CHECK: spv.selection {
598   spv.selection {
599     spv.BranchConditional %cond, ^then, ^else
601   ^then:
602     // CHECK: spv.Store "Function" %[[DST_VAR_0]], %[[SRC_VALUE_0]] ["Aligned", 8] : vector<3xi32>
603     spv.Store "Function" %3, %1 ["Aligned", 8] : vector<3xi32>
604     // CHECK: spv.Store "Function" %[[DST_VAR_1]], %[[SRC_VALUE_0]] ["Aligned", 8] : vector<3xi32>
605     spv.Store "Function" %4, %1 ["Aligned", 8]:  vector<3xi32>
606     spv.Branch ^merge
608   ^else:
609     // CHECK: spv.Store "Function" %[[DST_VAR_1]], %[[SRC_VALUE_1]] ["Aligned", 8] : vector<3xi32>
610     spv.Store "Function" %4, %2 ["Aligned", 8] : vector<3xi32>
611     spv.Branch ^merge
613   ^merge:
614     spv.mlir.merge
615   }
616   spv.Return
619 // -----
621 // A control-flow goes into `^then` block from `^else` block.
622 func @cannot_canonicalize_selection_op_2(%cond: i1) -> () {
623   %0 = spv.constant dense<[0, 1, 2]> : vector<3xi32>
624   // CHECK: %[[SRC_VALUE_0:.*]] = spv.constant dense<[1, 2, 3]> : vector<3xi32>
625   %1 = spv.constant dense<[1, 2, 3]> : vector<3xi32>
626   // CHECK: %[[SRC_VALUE_1:.*]] = spv.constant dense<[2, 3, 4]> : vector<3xi32>
627   %2 = spv.constant dense<[2, 3, 4]> : vector<3xi32>
628   // CHECK: %[[DST_VAR:.*]] = spv.Variable init({{%.*}}) : !spv.ptr<vector<3xi32>, Function>
629   %3 = spv.Variable init(%0) : !spv.ptr<vector<3xi32>, Function>
631   // CHECK: spv.selection {
632   spv.selection {
633     spv.BranchConditional %cond, ^then, ^else
635   ^then:
636     // CHECK: spv.Store "Function" %[[DST_VAR]], %[[SRC_VALUE_0]] ["Aligned", 8] : vector<3xi32>
637     spv.Store "Function" %3, %1 ["Aligned", 8]:  vector<3xi32>
638     spv.Branch ^merge
640   ^else:
641     // CHECK: spv.Store "Function" %[[DST_VAR]], %[[SRC_VALUE_1]] ["Aligned", 8] : vector<3xi32>
642     spv.Store "Function" %3, %2 ["Aligned", 8] : vector<3xi32>
643     spv.Branch ^then
645   ^merge:
646     spv.mlir.merge
647   }
648   spv.Return
651 // -----
653 // `spv.Return` as a block terminator.
654 func @cannot_canonicalize_selection_op_3(%cond: i1) -> () {
655   %0 = spv.constant dense<[0, 1, 2]> : vector<3xi32>
656   // CHECK: %[[SRC_VALUE_0:.*]] = spv.constant dense<[1, 2, 3]> : vector<3xi32>
657   %1 = spv.constant dense<[1, 2, 3]> : vector<3xi32>
658   // CHECK: %[[SRC_VALUE_1:.*]] = spv.constant dense<[2, 3, 4]> : vector<3xi32>
659   %2 = spv.constant dense<[2, 3, 4]> : vector<3xi32>
660   // CHECK: %[[DST_VAR:.*]] = spv.Variable init({{%.*}}) : !spv.ptr<vector<3xi32>, Function>
661   %3 = spv.Variable init(%0) : !spv.ptr<vector<3xi32>, Function>
663   // CHECK: spv.selection {
664   spv.selection {
665     spv.BranchConditional %cond, ^then, ^else
667   ^then:
668     // CHECK: spv.Store "Function" %[[DST_VAR]], %[[SRC_VALUE_0]] ["Aligned", 8] : vector<3xi32>
669     spv.Store "Function" %3, %1 ["Aligned", 8]:  vector<3xi32>
670     spv.Return
672   ^else:
673     // CHECK: spv.Store "Function" %[[DST_VAR]], %[[SRC_VALUE_1]] ["Aligned", 8] : vector<3xi32>
674     spv.Store "Function" %3, %2 ["Aligned", 8] : vector<3xi32>
675     spv.Branch ^merge
677   ^merge:
678     spv.mlir.merge
679   }
680   spv.Return
683 // -----
685 // Different memory access attributes.
686 func @cannot_canonicalize_selection_op_4(%cond: i1) -> () {
687   %0 = spv.constant dense<[0, 1, 2]> : vector<3xi32>
688   // CHECK: %[[SRC_VALUE_0:.*]] = spv.constant dense<[1, 2, 3]> : vector<3xi32>
689   %1 = spv.constant dense<[1, 2, 3]> : vector<3xi32>
690   // CHECK: %[[SRC_VALUE_1:.*]] = spv.constant dense<[2, 3, 4]> : vector<3xi32>
691   %2 = spv.constant dense<[2, 3, 4]> : vector<3xi32>
692   // CHECK: %[[DST_VAR:.*]] = spv.Variable init({{%.*}}) : !spv.ptr<vector<3xi32>, Function>
693   %3 = spv.Variable init(%0) : !spv.ptr<vector<3xi32>, Function>
695   // CHECK: spv.selection {
696   spv.selection {
697     spv.BranchConditional %cond, ^then, ^else
699   ^then:
700     // CHECK: spv.Store "Function" %[[DST_VAR]], %[[SRC_VALUE_0]] ["Aligned", 4] : vector<3xi32>
701     spv.Store "Function" %3, %1 ["Aligned", 4]:  vector<3xi32>
702     spv.Branch ^merge
704   ^else:
705     // CHECK: spv.Store "Function" %[[DST_VAR]], %[[SRC_VALUE_1]] ["Aligned", 8] : vector<3xi32>
706     spv.Store "Function" %3, %2 ["Aligned", 8] : vector<3xi32>
707     spv.Branch ^merge
709   ^merge:
710     spv.mlir.merge
711   }
712   spv.Return