xref: /llvm-project/mlir/test/Dialect/SPIRV/Transforms/canonicalize.mlir (revision bdf00e2216280edef1ec91ccc07987db92197b59)
1// RUN: mlir-opt %s -split-input-file -pass-pipeline='builtin.module(func.func(canonicalize{test-convergence region-simplify=aggressive}))' | FileCheck %s
2
3//===----------------------------------------------------------------------===//
4// spirv.AccessChain
5//===----------------------------------------------------------------------===//
6
7func.func @combine_full_access_chain() -> f32 {
8  // CHECK: %[[INDEX:.*]] = spirv.Constant 0
9  // CHECK-NEXT: %[[VAR:.*]] = spirv.Variable
10  // CHECK-NEXT: %[[PTR:.*]] = spirv.AccessChain %[[VAR]][%[[INDEX]], %[[INDEX]], %[[INDEX]]]
11  // CHECK-NEXT: spirv.Load "Function" %[[PTR]]
12  %c0 = spirv.Constant 0: i32
13  %0 = spirv.Variable : !spirv.ptr<!spirv.struct<(!spirv.array<4x!spirv.array<4xf32>>, !spirv.array<4xi32>)>, Function>
14  %1 = spirv.AccessChain %0[%c0] : !spirv.ptr<!spirv.struct<(!spirv.array<4x!spirv.array<4xf32>>, !spirv.array<4xi32>)>, Function>, i32 -> !spirv.ptr<!spirv.array<4x!spirv.array<4xf32>>, Function>
15  %2 = spirv.AccessChain %1[%c0, %c0] : !spirv.ptr<!spirv.array<4x!spirv.array<4xf32>>, Function>, i32, i32 -> !spirv.ptr<f32, Function>
16  %3 = spirv.Load "Function" %2 : f32
17  spirv.ReturnValue %3 : f32
18}
19
20// -----
21
22func.func @combine_access_chain_multi_use() -> !spirv.array<4xf32> {
23  // CHECK: %[[INDEX:.*]] = spirv.Constant 0
24  // CHECK-NEXT: %[[VAR:.*]] = spirv.Variable
25  // CHECK-NEXT: %[[PTR_0:.*]] = spirv.AccessChain %[[VAR]][%[[INDEX]], %[[INDEX]]]
26  // CHECK-NEXT: %[[PTR_1:.*]] = spirv.AccessChain %[[VAR]][%[[INDEX]], %[[INDEX]], %[[INDEX]]]
27  // CHECK-NEXT: spirv.Load "Function" %[[PTR_0]]
28  // CHECK-NEXT: spirv.Load "Function" %[[PTR_1]]
29  %c0 = spirv.Constant 0: i32
30  %0 = spirv.Variable : !spirv.ptr<!spirv.struct<(!spirv.array<4x!spirv.array<4xf32>>, !spirv.array<4xi32>)>, Function>
31  %1 = spirv.AccessChain %0[%c0] : !spirv.ptr<!spirv.struct<(!spirv.array<4x!spirv.array<4xf32>>, !spirv.array<4xi32>)>, Function>, i32 -> !spirv.ptr<!spirv.array<4x!spirv.array<4xf32>>, Function>
32  %2 = spirv.AccessChain %1[%c0] : !spirv.ptr<!spirv.array<4x!spirv.array<4xf32>>, Function>, i32 -> !spirv.ptr<!spirv.array<4xf32>, Function>
33  %3 = spirv.AccessChain %2[%c0] : !spirv.ptr<!spirv.array<4xf32>, Function>, i32 -> !spirv.ptr<f32, Function>
34  %4 = spirv.Load "Function" %2 : !spirv.array<4xf32>
35  %5 = spirv.Load "Function" %3 : f32
36  spirv.ReturnValue %4: !spirv.array<4xf32>
37}
38
39// -----
40
41func.func @dont_combine_access_chain_without_common_base() -> !spirv.array<4xi32> {
42  // CHECK: %[[INDEX:.*]] = spirv.Constant 1
43  // CHECK-NEXT: %[[VAR_0:.*]] = spirv.Variable
44  // CHECK-NEXT: %[[VAR_1:.*]] = spirv.Variable
45  // CHECK-NEXT: %[[VAR_0_PTR:.*]] = spirv.AccessChain %[[VAR_0]][%[[INDEX]]]
46  // CHECK-NEXT: %[[VAR_1_PTR:.*]] = spirv.AccessChain %[[VAR_1]][%[[INDEX]]]
47  // CHECK-NEXT: spirv.Load "Function" %[[VAR_0_PTR]]
48  // CHECK-NEXT: spirv.Load "Function" %[[VAR_1_PTR]]
49  %c1 = spirv.Constant 1: i32
50  %0 = spirv.Variable : !spirv.ptr<!spirv.struct<(!spirv.array<4x!spirv.array<4xf32>>, !spirv.array<4xi32>)>, Function>
51  %1 = spirv.Variable : !spirv.ptr<!spirv.struct<(!spirv.array<4x!spirv.array<4xf32>>, !spirv.array<4xi32>)>, Function>
52  %2 = spirv.AccessChain %0[%c1] : !spirv.ptr<!spirv.struct<(!spirv.array<4x!spirv.array<4xf32>>, !spirv.array<4xi32>)>, Function>, i32 -> !spirv.ptr<!spirv.array<4xi32>, Function>
53  %3 = spirv.AccessChain %1[%c1] : !spirv.ptr<!spirv.struct<(!spirv.array<4x!spirv.array<4xf32>>, !spirv.array<4xi32>)>, Function>, i32 -> !spirv.ptr<!spirv.array<4xi32>, Function>
54  %4 = spirv.Load "Function" %2 : !spirv.array<4xi32>
55  %5 = spirv.Load "Function" %3 : !spirv.array<4xi32>
56  spirv.ReturnValue %4 : !spirv.array<4xi32>
57}
58
59// -----
60
61//===----------------------------------------------------------------------===//
62// spirv.Bitcast
63//===----------------------------------------------------------------------===//
64
65func.func @convert_bitcast_full(%arg0 : vector<2xf32>) -> f64 {
66  // CHECK: %[[RESULT:.*]] = spirv.Bitcast {{%.*}} : vector<2xf32> to f64
67  // CHECK-NEXT: spirv.ReturnValue %[[RESULT]]
68  %0 = spirv.Bitcast %arg0 : vector<2xf32> to vector<2xi32>
69  %1 = spirv.Bitcast %0 : vector<2xi32> to i64
70  %2 = spirv.Bitcast %1 : i64 to f64
71  spirv.ReturnValue %2 : f64
72}
73
74// -----
75
76func.func @convert_bitcast_multi_use(%arg0 : vector<2xf32>, %arg1 : !spirv.ptr<i64, Uniform>) -> f64 {
77  // CHECK: %[[RESULT_0:.*]] = spirv.Bitcast {{%.*}} : vector<2xf32> to i64
78  // CHECK-NEXT: %[[RESULT_1:.*]] = spirv.Bitcast {{%.*}} : vector<2xf32> to f64
79  // CHECK-NEXT: spirv.Store {{".*"}} {{%.*}}, %[[RESULT_0]]
80  // CHECK-NEXT: spirv.ReturnValue %[[RESULT_1]]
81  %0 = spirv.Bitcast %arg0 : vector<2xf32> to i64
82  %1 = spirv.Bitcast %0 : i64 to f64
83  spirv.Store "Uniform" %arg1, %0 : i64
84  spirv.ReturnValue %1 : f64
85}
86
87// -----
88
89// CHECK-LABEL: @convert_bitcast_roundtip
90// CHECK-SAME:    %[[ARG:.+]]: i64
91func.func @convert_bitcast_roundtip(%arg0 : i64) -> i64 {
92  // CHECK: spirv.ReturnValue %[[ARG]]
93  %0 = spirv.Bitcast %arg0 : i64 to f64
94  %1 = spirv.Bitcast %0 : f64 to i64
95  spirv.ReturnValue %1 : i64
96}
97
98// -----
99
100// CHECK-LABEL: @convert_bitcast_chained_roundtip
101// CHECK-SAME:    %[[ARG:.+]]: i64
102func.func @convert_bitcast_chained_roundtip(%arg0 : i64) -> i64 {
103  // CHECK: spirv.ReturnValue %[[ARG]]
104  %0 = spirv.Bitcast %arg0 : i64 to f64
105  %1 = spirv.Bitcast %0 : f64 to vector<2xi32>
106  %2 = spirv.Bitcast %1 : vector<2xi32> to vector<2xf32>
107  %3 = spirv.Bitcast %2 : vector<2xf32> to i64
108  spirv.ReturnValue %3 : i64
109}
110
111// -----
112
113//===----------------------------------------------------------------------===//
114// spirv.CompositeExtract
115//===----------------------------------------------------------------------===//
116
117// CHECK-LABEL: extract_vector
118func.func @extract_vector() -> (i32, i32, i32) {
119  // CHECK-DAG: spirv.Constant 6 : i32
120  // CHECK-DAG: spirv.Constant -33 : i32
121  // CHECK-DAG: spirv.Constant 42 : i32
122  %0 = spirv.Constant dense<[42, -33, 6]> : vector<3xi32>
123  %1 = spirv.CompositeExtract %0[0 : i32] : vector<3xi32>
124  %2 = spirv.CompositeExtract %0[1 : i32] : vector<3xi32>
125  %3 = spirv.CompositeExtract %0[2 : i32] : vector<3xi32>
126  return %1, %2, %3 : i32, i32, i32
127}
128
129// -----
130
131// CHECK-LABEL: extract_array_final
132func.func @extract_array_final() -> (i32, i32) {
133  // CHECK-DAG: spirv.Constant -5 : i32
134  // CHECK-DAG: spirv.Constant 4 : i32
135  %0 = spirv.Constant [dense<[4, -5]> : vector<2xi32>] : !spirv.array<1 x vector<2xi32>>
136  %1 = spirv.CompositeExtract %0[0 : i32, 0 : i32] : !spirv.array<1 x vector<2 x i32>>
137  %2 = spirv.CompositeExtract %0[0 : i32, 1 : i32] : !spirv.array<1 x vector<2 x i32>>
138  return %1, %2 : i32, i32
139}
140
141// -----
142
143// CHECK-LABEL: extract_array_interm
144func.func @extract_array_interm() -> (vector<2xi32>) {
145  // CHECK: spirv.Constant dense<[4, -5]> : vector<2xi32>
146  %0 = spirv.Constant [dense<[4, -5]> : vector<2xi32>] : !spirv.array<1 x vector<2xi32>>
147  %1 = spirv.CompositeExtract %0[0 : i32] : !spirv.array<1 x vector<2 x i32>>
148  return %1 : vector<2xi32>
149}
150
151// -----
152
153// CHECK-LABEL: extract_from_not_constant
154func.func @extract_from_not_constant() -> i32 {
155  %0 = spirv.Variable : !spirv.ptr<vector<3xi32>, Function>
156  %1 = spirv.Load "Function" %0 : vector<3xi32>
157  // CHECK: spirv.CompositeExtract
158  %2 = spirv.CompositeExtract %1[0 : i32] : vector<3xi32>
159  spirv.ReturnValue %2 : i32
160}
161
162// -----
163
164// CHECK-LABEL: extract_insert
165//  CHECK-SAME: (%[[COMP:.+]]: !spirv.array<1 x vector<2xf32>>, %[[VAL:.+]]: f32)
166func.func @extract_insert(%composite: !spirv.array<1xvector<2xf32>>, %val: f32) -> (f32, f32) {
167  // CHECK: %[[INSERT:.+]] = spirv.CompositeInsert %[[VAL]], %[[COMP]]
168  %insert = spirv.CompositeInsert %val, %composite[0 : i32, 1 : i32] : f32 into !spirv.array<1xvector<2xf32>>
169  %1 = spirv.CompositeExtract %insert[0 : i32, 0 : i32] : !spirv.array<1xvector<2xf32>>
170  // CHECK: %[[S:.+]] = spirv.CompositeExtract %[[INSERT]][0 : i32, 0 : i32]
171  %2 = spirv.CompositeExtract %insert[0 : i32, 1 : i32] : !spirv.array<1xvector<2xf32>>
172  // CHECK: return %[[S]], %[[VAL]]
173  return %1, %2 : f32, f32
174}
175
176// -----
177
178// CHECK-LABEL: extract_construct
179//  CHECK-SAME: (%[[VAL1:.+]]: vector<2xf32>, %[[VAL2:.+]]: vector<2xf32>)
180func.func @extract_construct(%val1: vector<2xf32>, %val2: vector<2xf32>) -> (vector<2xf32>, vector<2xf32>) {
181  %construct = spirv.CompositeConstruct %val1, %val2 : (vector<2xf32>, vector<2xf32>) -> !spirv.array<2xvector<2xf32>>
182  %1 = spirv.CompositeExtract %construct[0 : i32] : !spirv.array<2xvector<2xf32>>
183  %2 = spirv.CompositeExtract %construct[1 : i32] : !spirv.array<2xvector<2xf32>>
184  // CHECK: return %[[VAL1]], %[[VAL2]]
185  return %1, %2 : vector<2xf32>, vector<2xf32>
186}
187
188// -----
189
190 // CHECK-LABEL: fold_composite_op
191 //  CHECK-SAME: (%[[COMP:.+]]: !spirv.struct<(f32, f32)>, %[[VAL1:.+]]: f32, %[[VAL2:.+]]: f32)
192  func.func @fold_composite_op(%composite: !spirv.struct<(f32, f32)>, %val1: f32, %val2: f32) -> f32 {
193    %insert = spirv.CompositeInsert %val1, %composite[0 : i32] : f32 into !spirv.struct<(f32, f32)>
194    %1 = spirv.CompositeInsert %val2, %insert[1 : i32] : f32 into !spirv.struct<(f32, f32)>
195    %2 = spirv.CompositeExtract %1[0 : i32] : !spirv.struct<(f32, f32)>
196    // CHECK-NEXT: return  %[[VAL1]]
197    return %2 : f32
198  }
199
200// -----
201
202 // CHECK-LABEL: fold_composite_op
203 //  CHECK-SAME: (%[[VAL1:.+]]: f32, %[[VAL2:.+]]: f32, %[[VAL3:.+]]: f32)
204  func.func @fold_composite_op(%val1: f32, %val2: f32, %val3: f32) -> f32 {
205    %composite = spirv.CompositeConstruct %val1, %val1, %val1 : (f32, f32, f32) -> !spirv.struct<(f32, f32, f32)>
206    %insert = spirv.CompositeInsert %val2, %composite[1 : i32] : f32 into !spirv.struct<(f32, f32, f32)>
207    %1 = spirv.CompositeInsert %val3, %insert[2 : i32] : f32 into !spirv.struct<(f32, f32, f32)>
208    %2 = spirv.CompositeExtract %1[0 : i32] : !spirv.struct<(f32, f32, f32)>
209    // CHECK-NEXT: return  %[[VAL1]]
210    return %2 : f32
211  }
212
213// -----
214
215// Not yet implemented case
216
217// CHECK-LABEL: extract_construct
218func.func @extract_construct(%val1: vector<3xf32>, %val2: f32) -> (f32, f32) {
219  // CHECK: spirv.CompositeConstruct
220  %construct = spirv.CompositeConstruct %val1, %val2 : (vector<3xf32>, f32) -> vector<4xf32>
221  // CHECK: spirv.CompositeExtract
222  %1 = spirv.CompositeExtract %construct[0 : i32] : vector<4xf32>
223  // CHECK: spirv.CompositeExtract
224  %2 = spirv.CompositeExtract %construct[1 : i32] : vector<4xf32>
225  return %1, %2 : f32, f32
226}
227
228// -----
229
230//===----------------------------------------------------------------------===//
231// spirv.Constant
232//===----------------------------------------------------------------------===//
233
234// TODO: test constants in different blocks
235
236func.func @deduplicate_scalar_constant() -> (i32, i32) {
237  // CHECK: %[[CST:.*]] = spirv.Constant 42 : i32
238  %0 = spirv.Constant 42 : i32
239  %1 = spirv.Constant 42 : i32
240  // CHECK-NEXT: return %[[CST]], %[[CST]]
241  return %0, %1 : i32, i32
242}
243
244// -----
245
246func.func @deduplicate_vector_constant() -> (vector<3xi32>, vector<3xi32>) {
247  // CHECK: %[[CST:.*]] = spirv.Constant dense<[1, 2, 3]> : vector<3xi32>
248  %0 = spirv.Constant dense<[1, 2, 3]> : vector<3xi32>
249  %1 = spirv.Constant dense<[1, 2, 3]> : vector<3xi32>
250  // CHECK-NEXT: return %[[CST]], %[[CST]]
251  return %0, %1 : vector<3xi32>, vector<3xi32>
252}
253
254// -----
255
256func.func @deduplicate_composite_constant() -> (!spirv.array<1 x vector<2xi32>>, !spirv.array<1 x vector<2xi32>>) {
257  // CHECK: %[[CST:.*]] = spirv.Constant [dense<5> : vector<2xi32>] : !spirv.array<1 x vector<2xi32>>
258  %0 = spirv.Constant [dense<5> : vector<2xi32>] : !spirv.array<1 x vector<2xi32>>
259  %1 = spirv.Constant [dense<5> : vector<2xi32>] : !spirv.array<1 x vector<2xi32>>
260  // CHECK-NEXT: return %[[CST]], %[[CST]]
261  return %0, %1 : !spirv.array<1 x vector<2xi32>>, !spirv.array<1 x vector<2xi32>>
262}
263
264// -----
265
266//===----------------------------------------------------------------------===//
267// spirv.IAdd
268//===----------------------------------------------------------------------===//
269
270// CHECK-LABEL: @iadd_zero
271// CHECK-SAME: (%[[ARG:.*]]: i32)
272func.func @iadd_zero(%arg0: i32) -> (i32, i32) {
273  %zero = spirv.Constant 0 : i32
274  %0 = spirv.IAdd %arg0, %zero : i32
275  %1 = spirv.IAdd %zero, %arg0 : i32
276  // CHECK: return %[[ARG]], %[[ARG]]
277  return %0, %1: i32, i32
278}
279
280// CHECK-LABEL: @const_fold_scalar_iadd_normal
281func.func @const_fold_scalar_iadd_normal() -> (i32, i32, i32) {
282  %c5 = spirv.Constant 5 : i32
283  %cn8 = spirv.Constant -8 : i32
284
285  // CHECK-DAG: spirv.Constant -3
286  // CHECK-DAG: spirv.Constant -16
287  // CHECK-DAG: spirv.Constant 10
288  %0 = spirv.IAdd %c5, %c5 : i32
289  %1 = spirv.IAdd %cn8, %cn8 : i32
290  %2 = spirv.IAdd %c5, %cn8 : i32
291  return %0, %1, %2: i32, i32, i32
292}
293
294// CHECK-LABEL: @const_fold_scalar_iadd_flow
295func.func @const_fold_scalar_iadd_flow() -> (i32, i32, i32, i32) {
296  %c1 = spirv.Constant 1 : i32
297  %c2 = spirv.Constant 2 : i32
298  %c3 = spirv.Constant 4294967295 : i32  // 2^32 - 1: 0xffff ffff
299  %c4 = spirv.Constant -2147483648 : i32 // -2^31   : 0x8000 0000
300  %c5 = spirv.Constant -1 : i32          //         : 0xffff ffff
301  %c6 = spirv.Constant -2 : i32          //         : 0xffff fffe
302
303  // 0x8000 0000 + 0xffff fffe = 0x1 7fff fffe -> 0x7fff fffe
304  // CHECK-DAG: spirv.Constant 2147483646
305  // 0x8000 0000 + 0xffff ffff = 0x1 7fff ffff -> 0x7fff ffff
306  // CHECK-DAG: spirv.Constant 2147483647
307  // 0x0000 0002 + 0xffff ffff = 0x1 0000 0001 -> 0x0000 0001
308  // CHECK-DAG: spirv.Constant 1
309  // 0x0000 0001 + 0xffff ffff = 0x1 0000 0000 -> 0x0000 0000
310  // CHECK-DAG: spirv.Constant 0
311  %0 = spirv.IAdd %c1, %c3 : i32
312   %1 = spirv.IAdd %c2, %c3 : i32
313  %2 = spirv.IAdd %c4, %c5 : i32
314  %3 = spirv.IAdd %c4, %c6 : i32
315  return %0, %1, %2, %3: i32, i32, i32, i32
316}
317
318// CHECK-LABEL: @const_fold_vector_iadd
319func.func @const_fold_vector_iadd() -> vector<3xi32> {
320  %vc1 = spirv.Constant dense<[42, -55, 127]> : vector<3xi32>
321  %vc2 = spirv.Constant dense<[-3, -15, 28]> : vector<3xi32>
322
323  // CHECK: spirv.Constant dense<[39, -70, 155]>
324  %0 = spirv.IAdd %vc1, %vc2 : vector<3xi32>
325  return %0: vector<3xi32>
326}
327
328// CHECK-LABEL: @iadd_poison
329//       CHECK:   %[[P:.*]] = ub.poison : i32
330//       CHECK:   return %[[P]]
331func.func @iadd_poison(%arg0: i32) -> i32 {
332  %0 = ub.poison : i32
333  %1 = spirv.IAdd %arg0, %0 : i32
334  return %1: i32
335}
336
337// -----
338
339//===----------------------------------------------------------------------===//
340// spirv.IAddCarry
341//===----------------------------------------------------------------------===//
342
343// CHECK-LABEL: @iaddcarry_x_0
344func.func @iaddcarry_x_0(%arg0 : i32) -> !spirv.struct<(i32, i32)> {
345  // CHECK: %[[RET:.*]] = spirv.CompositeConstruct
346  %c0 = spirv.Constant 0 : i32
347  %0 = spirv.IAddCarry %arg0, %c0 : !spirv.struct<(i32, i32)>
348
349  // CHECK: return %[[RET]]
350  return %0 : !spirv.struct<(i32, i32)>
351}
352
353// CHECK-LABEL: @const_fold_scalar_iaddcarry
354func.func @const_fold_scalar_iaddcarry() -> (!spirv.struct<(i32, i32)>, !spirv.struct<(i32, i32)>) {
355  %c5 = spirv.Constant 5 : i32
356  %cn5 = spirv.Constant -5 : i32
357  %cn8 = spirv.Constant -8 : i32
358
359  // CHECK-DAG: %[[C0:.*]] = spirv.Constant 0
360  // CHECK-DAG: %[[CN3:.*]] = spirv.Constant -3
361  // CHECK-DAG: %[[UNDEF1:.*]] = spirv.Undef
362  // CHECK-DAG: %[[INTER1:.*]] = spirv.CompositeInsert %[[CN3]], %[[UNDEF1]][0 : i32]
363  // CHECK-DAG: %[[CC_CN3_C0:.*]] = spirv.CompositeInsert %[[C0]], %[[INTER1]][1 : i32]
364  // CHECK-DAG: %[[C1:.*]] = spirv.Constant 1
365  // CHECK-DAG: %[[CN13:.*]] = spirv.Constant -13
366  // CHECK-DAG: %[[UNDEF2:.*]] = spirv.Undef
367  // CHECK-DAG: %[[INTER2:.*]] = spirv.CompositeInsert %[[CN13]], %[[UNDEF2]][0 : i32]
368  // CHECK-DAG: %[[CC_CN13_C1:.*]] = spirv.CompositeInsert %[[C1]], %[[INTER2]][1 : i32]
369  %0 = spirv.IAddCarry %c5, %cn8 : !spirv.struct<(i32, i32)>
370  %1 = spirv.IAddCarry %cn5, %cn8 : !spirv.struct<(i32, i32)>
371
372  // CHECK: return %[[CC_CN3_C0]], %[[CC_CN13_C1]]
373  return %0, %1 : !spirv.struct<(i32, i32)>, !spirv.struct<(i32, i32)>
374}
375
376// CHECK-LABEL: @const_fold_vector_iaddcarry
377func.func @const_fold_vector_iaddcarry() -> !spirv.struct<(vector<3xi32>, vector<3xi32>)> {
378  %v0 = spirv.Constant dense<[5, -3, -1]> : vector<3xi32>
379  %v1 = spirv.Constant dense<[-8, -8, 1]> : vector<3xi32>
380
381  // CHECK-DAG: %[[CV1:.*]] = spirv.Constant dense<[-3, -11, 0]>
382  // CHECK-DAG: %[[CV2:.*]] = spirv.Constant dense<[0, 1, 1]>
383  // CHECK-DAG: %[[UNDEF:.*]] = spirv.Undef
384  // CHECK-DAG: %[[INTER:.*]] = spirv.CompositeInsert %[[CV1]], %[[UNDEF]][0 : i32]
385  // CHECK-DAG: %[[CC_CV1_CV2:.*]] = spirv.CompositeInsert %[[CV2]], %[[INTER]][1 : i32]
386  %0 = spirv.IAddCarry %v0, %v1 : !spirv.struct<(vector<3xi32>, vector<3xi32>)>
387
388  // CHECK: return %[[CC_CV1_CV2]]
389  return %0 : !spirv.struct<(vector<3xi32>, vector<3xi32>)>
390}
391
392// -----
393
394//===----------------------------------------------------------------------===//
395// spirv.IMul
396//===----------------------------------------------------------------------===//
397
398// CHECK-LABEL: @imul_zero_one
399// CHECK-SAME: (%[[ARG:.*]]: i32)
400func.func @imul_zero_one(%arg0: i32) -> (i32, i32) {
401  // CHECK: %[[ZERO:.*]] = spirv.Constant 0
402  %zero = spirv.Constant 0 : i32
403  %one = spirv.Constant 1: i32
404  %0 = spirv.IMul %arg0, %zero : i32
405  %1 = spirv.IMul %one, %arg0 : i32
406  // CHECK: return %[[ZERO]], %[[ARG]]
407  return %0, %1: i32, i32
408}
409
410// CHECK-LABEL: @const_fold_scalar_imul_normal
411func.func @const_fold_scalar_imul_normal() -> (i32, i32, i32) {
412  %c5 = spirv.Constant 5 : i32
413  %cn8 = spirv.Constant -8 : i32
414  %c7 = spirv.Constant 7 : i32
415
416  // CHECK-DAG: spirv.Constant -56
417  // CHECK-DAG: spirv.Constant -40
418  // CHECK-DAG: spirv.Constant 35
419  %0 = spirv.IMul %c7, %c5 : i32
420  %1 = spirv.IMul %c5, %cn8 : i32
421  %2 = spirv.IMul %cn8, %c7 : i32
422  return %0, %1, %2: i32, i32, i32
423}
424
425// CHECK-LABEL: @const_fold_scalar_imul_flow
426func.func @const_fold_scalar_imul_flow() -> (i32, i32, i32) {
427  %c1 = spirv.Constant 2 : i32
428  %c2 = spirv.Constant 4 : i32
429  %c3 = spirv.Constant 4294967295 : i32  // 2^32 - 1 : 0xffff ffff
430  %c4 = spirv.Constant 2147483647 : i32  // 2^31 - 1 : 0x7fff ffff
431
432  // (0x7fff ffff << 2) = 0x1 ffff fffc -> 0xffff fffc
433  // CHECK-DAG: %[[CST4:.*]] = spirv.Constant -4
434
435  // (0xffff ffff << 1) = 0x1 ffff fffe -> 0xffff fffe
436  // CHECK-DAG: %[[CST2:.*]] = spirv.Constant -2
437  %0 = spirv.IMul %c1, %c3 : i32
438  // (0x7fff ffff << 1) = 0x0 ffff fffe -> 0xffff fffe
439  %1 = spirv.IMul %c1, %c4 : i32
440  %2 = spirv.IMul %c4, %c2 : i32
441  // CHECK: return %[[CST2]], %[[CST2]], %[[CST4]]
442  return %0, %1, %2: i32, i32, i32
443}
444
445
446// CHECK-LABEL: @const_fold_vector_imul
447func.func @const_fold_vector_imul() -> vector<3xi32> {
448  %vc1 = spirv.Constant dense<[42, -55, 127]> : vector<3xi32>
449  %vc2 = spirv.Constant dense<[-3, -15, 28]> : vector<3xi32>
450
451  // CHECK: spirv.Constant dense<[-126, 825, 3556]>
452  %0 = spirv.IMul %vc1, %vc2 : vector<3xi32>
453  return %0: vector<3xi32>
454}
455
456// -----
457
458//===----------------------------------------------------------------------===//
459// spirv.SMulExtended
460//===----------------------------------------------------------------------===//
461
462// CHECK-LABEL: @smulextended_x_0
463func.func @smulextended_x_0(%arg0 : i32) -> !spirv.struct<(i32, i32)> {
464  // CHECK: %[[C0:.*]] = spirv.Constant 0
465  // CHECK: %[[RET:.*]] = spirv.CompositeConstruct %[[C0]], %[[C0]]
466  %c0 = spirv.Constant 0 : i32
467  %0 = spirv.SMulExtended %arg0, %c0 : !spirv.struct<(i32, i32)>
468
469  // CHECK: return %[[RET]]
470  return %0 : !spirv.struct<(i32, i32)>
471}
472
473// CHECK-LABEL: @const_fold_scalar_smulextended
474func.func @const_fold_scalar_smulextended() -> (!spirv.struct<(i32, i32)>, !spirv.struct<(i32, i32)>) {
475  %c5 = spirv.Constant 5 : i32
476  %cn5 = spirv.Constant -5 : i32
477  %cn8 = spirv.Constant -8 : i32
478
479  // CHECK-DAG: %[[CN40:.*]] = spirv.Constant -40
480  // CHECK-DAG: %[[CN1:.*]] = spirv.Constant -1
481  // CHECK-DAG: %[[UNDEF1:.*]] = spirv.Undef
482  // CHECK-DAG: %[[INTER1:.*]] = spirv.CompositeInsert %[[CN40]], %[[UNDEF1]][0 : i32]
483  // CHECK-DAG: %[[CC_CN40_CN1:.*]] = spirv.CompositeInsert %[[CN1]], %[[INTER1]]
484  // CHECK-DAG: %[[C40:.*]] = spirv.Constant 40
485  // CHECK-DAG: %[[C0:.*]] = spirv.Constant 0
486  // CHECK-DAG: %[[UNDEF2:.*]] = spirv.Undef
487  // CHECK-DAG: %[[INTER2:.*]] = spirv.CompositeInsert %[[C40]], %[[UNDEF2]][0 : i32]
488  // CHECK-DAG: %[[CC_C40_C0:.*]] = spirv.CompositeInsert %[[C0]], %[[INTER2]][1 : i32]
489  %0 = spirv.SMulExtended %c5, %cn8 : !spirv.struct<(i32, i32)>
490  %1 = spirv.SMulExtended %cn5, %cn8 : !spirv.struct<(i32, i32)>
491
492  // CHECK: return %[[CC_CN40_CN1]], %[[CC_C40_C0]]
493  return %0, %1 : !spirv.struct<(i32, i32)>, !spirv.struct<(i32, i32)>
494}
495
496// CHECK-LABEL: @const_fold_vector_smulextended
497func.func @const_fold_vector_smulextended() -> !spirv.struct<(vector<3xi32>, vector<3xi32>)> {
498  %v0 = spirv.Constant dense<[2147483647, -5, -1]> : vector<3xi32>
499  %v1 = spirv.Constant dense<[5, -8, 1]> : vector<3xi32>
500
501  // CHECK-DAG: %[[CV1:.*]] = spirv.Constant dense<[2147483643, 40, -1]>
502  // CHECK-DAG: %[[CV2:.*]] = spirv.Constant dense<[2, 0, -1]>
503  // CHECK-DAG: %[[UNDEF:.*]] = spirv.Undef
504  // CHECK-DAG: %[[INTER:.*]] = spirv.CompositeInsert %[[CV1]], %[[UNDEF]][0 : i32]
505  // CHECK-DAG: %[[CC_CV1_CV2:.*]] = spirv.CompositeInsert %[[CV2]], %[[INTER]][1 : i32]
506  %0 = spirv.SMulExtended %v0, %v1 : !spirv.struct<(vector<3xi32>, vector<3xi32>)>
507
508  // CHECK: return %[[CC_CV1_CV2]]
509  return %0 : !spirv.struct<(vector<3xi32>, vector<3xi32>)>
510
511}
512
513// -----
514
515//===----------------------------------------------------------------------===//
516// spirv.UMulExtended
517//===----------------------------------------------------------------------===//
518
519// CHECK-LABEL: @umulextended_x_0
520func.func @umulextended_x_0(%arg0 : i32) -> !spirv.struct<(i32, i32)> {
521  // CHECK: %[[C0:.*]] = spirv.Constant 0
522  // CHECK: %[[RET:.*]] = spirv.CompositeConstruct %[[C0]], %[[C0]]
523  %c0 = spirv.Constant 0 : i32
524  %0 = spirv.UMulExtended %arg0, %c0 : !spirv.struct<(i32, i32)>
525
526  // CHECK: return %[[RET]]
527  return %0 : !spirv.struct<(i32, i32)>
528}
529
530// CHECK-LABEL: @umulextended_x_1
531// CHECK-SAME: (%[[ARG:.*]]: i32)
532func.func @umulextended_x_1(%arg0 : i32) -> !spirv.struct<(i32, i32)> {
533  // CHECK: %[[C0:.*]] = spirv.Constant 0
534  // CHECK: %[[RET:.*]] = spirv.CompositeConstruct %[[ARG]], %[[C0]]
535  %c0 = spirv.Constant 1 : i32
536  %0 = spirv.UMulExtended %arg0, %c0 : !spirv.struct<(i32, i32)>
537
538  // CHECK: return %[[RET]]
539  return %0 : !spirv.struct<(i32, i32)>
540}
541
542// CHECK-LABEL: @const_fold_scalar_umulextended
543func.func @const_fold_scalar_umulextended() -> (!spirv.struct<(i32, i32)>, !spirv.struct<(i32, i32)>) {
544  %c5 = spirv.Constant 5 : i32
545  %cn5 = spirv.Constant -5 : i32
546  %cn8 = spirv.Constant -8 : i32
547
548
549  // CHECK-DAG: %[[C40:.*]] = spirv.Constant 40
550  // CHECK-DAG: %[[CN13:.*]] = spirv.Constant -13
551  // CHECK-DAG: %[[CN40:.*]] = spirv.Constant -40
552  // CHECK-DAG: %[[C4:.*]] = spirv.Constant 4
553  // CHECK-DAG: %[[UNDEF1:.*]] = spirv.Undef
554  // CHECK-DAG: %[[INTER1:.*]] = spirv.CompositeInsert %[[CN40]], %[[UNDEF1]][0 : i32]
555  // CHECK-DAG: %[[CC_CN40_C4:.*]] = spirv.CompositeInsert %[[C4]], %[[INTER1]][1 : i32]
556  // CHECK-DAG: %[[UNDEF2:.*]] = spirv.Undef
557  // CHECK-DAG: %[[INTER2:.*]] = spirv.CompositeInsert %[[C40]], %[[UNDEF2]][0 : i32]
558  // CHECK-DAG: %[[CC_C40_CN13:.*]] = spirv.CompositeInsert %[[CN13]], %[[INTER2]][1 : i32]
559  %0 = spirv.UMulExtended %c5, %cn8 : !spirv.struct<(i32, i32)>
560  %1 = spirv.UMulExtended %cn5, %cn8 : !spirv.struct<(i32, i32)>
561
562  // CHECK: return %[[CC_CN40_C4]], %[[CC_C40_CN13]]
563  return %0, %1 : !spirv.struct<(i32, i32)>, !spirv.struct<(i32, i32)>
564}
565
566// CHECK-LABEL: @const_fold_vector_umulextended
567func.func @const_fold_vector_umulextended() -> !spirv.struct<(vector<3xi32>, vector<3xi32>)> {
568  %v0 = spirv.Constant dense<[2147483647, -5, -1]> : vector<3xi32>
569  %v1 = spirv.Constant dense<[5, -8, 1]> : vector<3xi32>
570
571  // CHECK-DAG: %[[CV1:.*]] = spirv.Constant dense<[2147483643, 40, -1]>
572  // CHECK-DAG: %[[CV2:.*]] = spirv.Constant dense<[2, -13, 0]>
573  // CHECK-DAG: %[[UNDEF:.*]] = spirv.Undef
574  // CHECK-DAG: %[[INTER:.*]] = spirv.CompositeInsert %[[CV1]], %[[UNDEF]]
575  // CHECK-DAG: %[[CC_CV1_CV2:.*]] = spirv.CompositeInsert %[[CV2]], %[[INTER]]
576  %0 = spirv.UMulExtended %v0, %v1 : !spirv.struct<(vector<3xi32>, vector<3xi32>)>
577
578  // CHECK: return %[[CC_CV1_CV2]]
579  return %0 : !spirv.struct<(vector<3xi32>, vector<3xi32>)>
580}
581
582// -----
583
584
585//===----------------------------------------------------------------------===//
586// spirv.ISub
587//===----------------------------------------------------------------------===//
588
589// CHECK-LABEL: @isub_x_x
590func.func @isub_x_x(%arg0: i32) -> i32 {
591  // CHECK: spirv.Constant 0
592  %0 = spirv.ISub %arg0, %arg0: i32
593  return %0: i32
594}
595
596// CHECK-LABEL: @const_fold_scalar_isub_normal
597func.func @const_fold_scalar_isub_normal() -> (i32, i32, i32) {
598  %c5 = spirv.Constant 5 : i32
599  %cn8 = spirv.Constant -8 : i32
600  %c7 = spirv.Constant 7 : i32
601
602  // CHECK-DAG: spirv.Constant -15
603  // CHECK-DAG: spirv.Constant 13
604  // CHECK-DAG: spirv.Constant 2
605  %0 = spirv.ISub %c7, %c5 : i32
606  %1 = spirv.ISub %c5, %cn8 : i32
607  %2 = spirv.ISub %cn8, %c7 : i32
608  return %0, %1, %2: i32, i32, i32
609}
610
611// CHECK-LABEL: @const_fold_scalar_isub_flow
612func.func @const_fold_scalar_isub_flow() -> (i32, i32, i32, i32) {
613  %c1 = spirv.Constant 0 : i32
614  %c2 = spirv.Constant 1 : i32
615  %c3 = spirv.Constant 4294967295 : i32  // 2^32 - 1 : 0xffff ffff
616  %c4 = spirv.Constant 2147483647 : i32  // 2^31     : 0x7fff ffff
617  %c5 = spirv.Constant -1 : i32          //          : 0xffff ffff
618  %c6 = spirv.Constant -2 : i32          //          : 0xffff fffe
619
620  // 0xffff ffff - 0x7fff ffff -> 0xffff ffff + 0x8000 0001 = 0x1 8000 0000
621  // CHECK-DAG: spirv.Constant -2147483648
622  // 0x0000 0001 - 0xffff ffff -> 0x0000 0001 + 0x0000 0001 = 0x0000 0002
623  // CHECK-DAG: spirv.Constant 2 :
624  // 0x0000 0000 - 0xffff ffff -> 0x0000 0000 + 0x0000 0001 = 0x0000 0001
625  // CHECK-DAG: spirv.Constant 1 :
626  // 0xffff fffe - 0x7fff ffff -> 0xffff fffe + 0x8000 0001 = 0x1 7fff ffff
627  // CHECK-DAG: spirv.Constant 2147483647
628  %0 = spirv.ISub %c1, %c3 : i32
629  %1 = spirv.ISub %c2, %c3 : i32
630  %2 = spirv.ISub %c5, %c4 : i32
631  %3 = spirv.ISub %c6, %c4 : i32
632  return %0, %1, %2, %3: i32, i32, i32, i32
633}
634
635// CHECK-LABEL: @const_fold_vector_isub
636func.func @const_fold_vector_isub() -> vector<3xi32> {
637  %vc1 = spirv.Constant dense<[42, -55, 127]> : vector<3xi32>
638  %vc2 = spirv.Constant dense<[-3, -15, 28]> : vector<3xi32>
639
640  // CHECK: spirv.Constant dense<[45, -40, 99]>
641  %0 = spirv.ISub %vc1, %vc2 : vector<3xi32>
642  return %0: vector<3xi32>
643}
644
645// -----
646
647//===----------------------------------------------------------------------===//
648// spirv.SDiv
649//===----------------------------------------------------------------------===//
650
651// CHECK-LABEL: @sdiv_x_1
652func.func @sdiv_x_1(%arg0 : i32) -> i32 {
653  // CHECK-NEXT: return %arg0 : i32
654  %c1 = spirv.Constant 1  : i32
655  %2 = spirv.SDiv %arg0, %c1: i32
656  return %2 : i32
657}
658
659// CHECK-LABEL: @sdiv_div_0_or_overflow
660func.func @sdiv_div_0_or_overflow() -> (i32, i32) {
661  // CHECK-DAG: %[[C0:.*]] = spirv.Constant 0
662  // CHECK-DAG: %[[CN1:.*]] = spirv.Constant -1
663  // CHECK-DAG: %[[CNMIN:.*]] = spirv.Constant -2147483648
664
665  %c0 = spirv.Constant 0 : i32
666  %cn1 = spirv.Constant -1 : i32
667  %min_i32 = spirv.Constant -2147483648 : i32
668
669  // CHECK: %0 = spirv.SDiv %[[CN1]], %[[C0]]
670  // CHECK: %1 = spirv.SDiv %[[CNMIN]], %[[CN1]]
671  %0 = spirv.SDiv %cn1, %c0 : i32
672  %1 = spirv.SDiv %min_i32, %cn1 : i32
673  return %0, %1 : i32, i32
674}
675
676// CHECK-LABEL: @const_fold_scalar_sdiv
677func.func @const_fold_scalar_sdiv() -> (i32, i32, i32, i32) {
678  %c56 = spirv.Constant 56 : i32
679  %c7 = spirv.Constant 7 : i32
680  %cn8 = spirv.Constant -8 : i32
681  %c3 = spirv.Constant 3 : i32
682  %cn3 = spirv.Constant -3 : i32
683
684  // CHECK-DAG: %[[CN18:.*]] = spirv.Constant -18
685  // CHECK-DAG: %[[CN2:.*]] = spirv.Constant -2
686  // CHECK-DAG: %[[CN7:.*]] = spirv.Constant -7
687  // CHECK-DAG: %[[C8:.*]] = spirv.Constant 8
688  %0 = spirv.SDiv %c56, %c7 : i32
689  %1 = spirv.SDiv %c56, %cn8 : i32
690  %2 = spirv.SDiv %cn8, %c3 : i32
691  %3 = spirv.SDiv %c56, %cn3 : i32
692
693  // CHECK: return %[[C8]], %[[CN7]], %[[CN2]], %[[CN18]]
694  return %0, %1, %2, %3: i32, i32, i32, i32
695}
696
697// CHECK-LABEL: @const_fold_vector_sdiv
698func.func @const_fold_vector_sdiv() -> vector<3xi32> {
699  // CHECK: %[[CVEC:.*]] = spirv.Constant dense<[0, -1, -3]>
700
701  %cv_num = spirv.Constant dense<[42, 24, -16]> : vector<3xi32>
702  %cv_denom = spirv.Constant dense<[76, -24, 5]> : vector<3xi32>
703  %0 = spirv.SDiv %cv_num, %cv_denom : vector<3xi32>
704
705  // CHECK: return %[[CVEC]]
706  return %0 : vector<3xi32>
707}
708
709// -----
710
711//===----------------------------------------------------------------------===//
712// spirv.SMod
713//===----------------------------------------------------------------------===//
714
715// CHECK-LABEL: @smod_x_1
716func.func @smod_x_1(%arg0: i32, %arg1: vector<3xi32>) -> (i32, vector<3xi32>) {
717  // CHECK-DAG: %[[C0:.*]] = spirv.Constant 0
718  // CHECK-DAG: %[[CVEC0:.*]] = spirv.Constant dense<0>
719  %c1 = spirv.Constant 1 : i32
720  %cv1 = spirv.Constant dense<1> : vector<3xi32>
721  %0 = spirv.SMod %arg0, %c1: i32
722  %1 = spirv.SMod %arg1, %cv1: vector<3xi32>
723
724  // CHECK: return %[[C0]], %[[CVEC0]]
725  return %0, %1 : i32, vector<3xi32>
726}
727
728// CHECK-LABEL: @smod_div_0_or_overflow
729func.func @smod_div_0_or_overflow() -> (i32, i32) {
730  // CHECK-DAG: %[[C0:.*]] = spirv.Constant 0
731  // CHECK-DAG: %[[CN1:.*]] = spirv.Constant -1
732  // CHECK-DAG: %[[CNMIN:.*]] = spirv.Constant -2147483648
733
734  %c0 = spirv.Constant 0 : i32
735  %cn1 = spirv.Constant -1 : i32
736  %min_i32 = spirv.Constant -2147483648 : i32
737
738  // CHECK: %0 = spirv.SMod %[[CN1]], %[[C0]]
739  // CHECK: %1 = spirv.SMod %[[CNMIN]], %[[CN1]]
740  %0 = spirv.SMod %cn1, %c0 : i32
741  %1 = spirv.SMod %min_i32, %cn1 : i32
742  return %0, %1 : i32, i32
743}
744
745// CHECK-LABEL: @const_fold_scalar_smod
746func.func @const_fold_scalar_smod() -> (i32, i32, i32, i32, i32, i32, i32, i32) {
747  %c56 = spirv.Constant 56 : i32
748  %cn56 = spirv.Constant -56 : i32
749  %c59 = spirv.Constant 59 : i32
750  %cn59 = spirv.Constant -59 : i32
751  %c7 = spirv.Constant 7 : i32
752  %cn8 = spirv.Constant -8 : i32
753  %c3 = spirv.Constant 3 : i32
754  %cn3 = spirv.Constant -3 : i32
755
756  // CHECK-DAG: %[[ZERO:.*]] = spirv.Constant 0 : i32
757  // CHECK-DAG: %[[TWO:.*]] = spirv.Constant 2 : i32
758  // CHECK-DAG: %[[FIFTYTHREE:.*]] = spirv.Constant 53 : i32
759  // CHECK-DAG: %[[NFIFTYTHREE:.*]] = spirv.Constant -53 : i32
760  // CHECK-DAG: %[[THREE:.*]] = spirv.Constant 3 : i32
761  // CHECK-DAG: %[[NTHREE:.*]] = spirv.Constant -3 : i32
762  %0 = spirv.SMod %c56, %c7 : i32
763  %1 = spirv.SMod %c56, %cn8 : i32
764  %2 = spirv.SMod %c56, %c3 : i32
765  %3 = spirv.SMod %cn3, %c56 : i32
766  %4 = spirv.SMod %cn3, %cn56 : i32
767  %5 = spirv.SMod %c59, %c56 : i32
768  %6 = spirv.SMod %c59, %cn56 : i32
769  %7 = spirv.SMod %cn59, %cn56 : i32
770
771  // CHECK: return %[[ZERO]], %[[ZERO]], %[[TWO]], %[[FIFTYTHREE]], %[[NTHREE]], %[[THREE]], %[[NFIFTYTHREE]], %[[NTHREE]]
772  return %0, %1, %2, %3, %4, %5, %6, %7 : i32, i32, i32, i32, i32, i32, i32, i32
773}
774
775// CHECK-LABEL: @const_fold_vector_smod
776func.func @const_fold_vector_smod() -> vector<3xi32> {
777  // CHECK: %[[CVEC:.*]] = spirv.Constant dense<[42, -4, 4]>
778
779  %cv = spirv.Constant dense<[42, 24, -16]> : vector<3xi32>
780  %cv_mod = spirv.Constant dense<[76, -7, 5]> : vector<3xi32>
781  %0 = spirv.SMod %cv, %cv_mod : vector<3xi32>
782
783  // CHECK: return %[[CVEC]]
784  return %0 : vector<3xi32>
785}
786
787// -----
788
789//===----------------------------------------------------------------------===//
790// spirv.SRem
791//===----------------------------------------------------------------------===//
792
793// CHECK-LABEL: @srem_x_1
794func.func @srem_x_1(%arg0: i32, %arg1: vector<3xi32>) -> (i32, vector<3xi32>) {
795  // CHECK-DAG: %[[C0:.*]] = spirv.Constant 0
796  // CHECK-DAG: %[[CVEC0:.*]] = spirv.Constant dense<0>
797  %c1 = spirv.Constant 1 : i32
798  %cv1 = spirv.Constant dense<1> : vector<3xi32>
799  %0 = spirv.SRem %arg0, %c1: i32
800  %1 = spirv.SRem %arg1, %cv1: vector<3xi32>
801
802  // CHECK: return %[[C0]], %[[CVEC0]]
803  return %0, %1 : i32, vector<3xi32>
804}
805
806// CHECK-LABEL: @srem_div_0_or_overflow
807func.func @srem_div_0_or_overflow() -> (i32, i32) {
808  // CHECK-DAG: %[[C0:.*]] = spirv.Constant 0
809  // CHECK-DAG: %[[CN1:.*]] = spirv.Constant -1
810  // CHECK-DAG: %[[CNMIN:.*]] = spirv.Constant -2147483648
811  %c0 = spirv.Constant 0 : i32
812  %cn1 = spirv.Constant -1 : i32
813  %min_i32 = spirv.Constant -2147483648 : i32
814
815  // CHECK: %0 = spirv.SRem %[[CN1]], %[[C0]]
816  // CHECK: %1 = spirv.SRem %[[CNMIN]], %[[CN1]]
817  %0 = spirv.SRem %cn1, %c0 : i32
818  %1 = spirv.SRem %min_i32, %cn1 : i32
819  return %0, %1 : i32, i32
820}
821
822// CHECK-LABEL: @const_fold_scalar_srem
823func.func @const_fold_scalar_srem() -> (i32, i32, i32, i32, i32) {
824  %c56 = spirv.Constant 56 : i32
825  %c7 = spirv.Constant 7 : i32
826  %cn8 = spirv.Constant -8 : i32
827  %c3 = spirv.Constant 3 : i32
828  %cn3 = spirv.Constant -3 : i32
829
830  // CHECK-DAG: %[[ONE:.*]] = spirv.Constant 1 : i32
831  // CHECK-DAG: %[[NTHREE:.*]] = spirv.Constant -3 : i32
832  // CHECK-DAG: %[[TWO:.*]] = spirv.Constant 2 : i32
833  // CHECK-DAG: %[[ZERO:.*]] = spirv.Constant 0 : i32
834  %0 = spirv.SRem %c56, %c7 : i32
835  %1 = spirv.SRem %c56, %cn8 : i32
836  %2 = spirv.SRem %c56, %c3 : i32
837  %3 = spirv.SRem %cn3, %c56 : i32
838  %4 = spirv.SRem %c7, %cn3 : i32
839  // CHECK: return %[[ZERO]], %[[ZERO]], %[[TWO]], %[[NTHREE]], %[[ONE]]
840  return %0, %1, %2, %3, %4 : i32, i32, i32, i32, i32
841}
842
843// -----
844
845//===----------------------------------------------------------------------===//
846// spirv.UDiv
847//===----------------------------------------------------------------------===//
848
849// CHECK-LABEL: @udiv_x_1
850func.func @udiv_x_1(%arg0 : i32) -> i32 {
851  // CHECK-NEXT: return %arg0 : i32
852  %c1 = spirv.Constant 1  : i32
853  %2 = spirv.UDiv %arg0, %c1: i32
854  return %2 : i32
855}
856
857// CHECK-LABEL: @udiv_div_0
858func.func @udiv_div_0() -> i32 {
859  // CHECK-DAG: %[[C0:.*]] = spirv.Constant 0
860  // CHECK-DAG: %[[CN1:.*]] = spirv.Constant -1
861  %c0 = spirv.Constant 0 : i32
862  %cn1 = spirv.Constant -1 : i32
863
864  // CHECK: %0 = spirv.UDiv %[[CN1]], %[[C0]]
865  %0 = spirv.UDiv %cn1, %c0 : i32
866  return %0 : i32
867}
868
869// CHECK-LABEL: @const_fold_scalar_udiv
870func.func @const_fold_scalar_udiv() -> (i32, i32, i32) {
871  %c56 = spirv.Constant 56 : i32
872  %c7 = spirv.Constant 7 : i32
873  %cn8 = spirv.Constant -8 : i32
874  %c3 = spirv.Constant 3 : i32
875
876  // CHECK-DAG: %[[C0:.*]] = spirv.Constant 0
877  // CHECK-DAG: %[[CBIG:.*]] = spirv.Constant 1431655762
878  // CHECK-DAG: %[[C8:.*]] = spirv.Constant 8
879  %0 = spirv.UDiv %c56, %c7 : i32
880  %1 = spirv.UDiv %cn8, %c3 : i32
881  %2 = spirv.UDiv %c56, %cn8 : i32
882
883  // CHECK: return %[[C8]], %[[CBIG]], %[[C0]]
884  return %0, %1, %2 : i32, i32, i32
885}
886
887// -----
888
889//===----------------------------------------------------------------------===//
890// spirv.UMod
891//===----------------------------------------------------------------------===//
892
893// CHECK-LABEL: @umod_x_1
894func.func @umod_x_1(%arg0: i32, %arg1: vector<3xi32>) -> (i32, vector<3xi32>) {
895  // CHECK-DAG: %[[C0:.*]] = spirv.Constant 0
896  // CHECK-DAG: %[[CVEC0:.*]] = spirv.Constant dense<0>
897  %c1 = spirv.Constant 1 : i32
898  %cv1 = spirv.Constant dense<1> : vector<3xi32>
899  %0 = spirv.UMod %arg0, %c1: i32
900  %1 = spirv.UMod %arg1, %cv1: vector<3xi32>
901
902  // CHECK: return %[[C0]], %[[CVEC0]]
903  return %0, %1 : i32, vector<3xi32>
904}
905
906// CHECK-LABEL: @umod_div_0
907func.func @umod_div_0() -> i32 {
908  // CHECK-DAG: %[[C0:.*]] = spirv.Constant 0
909  // CHECK-DAG: %[[CN1:.*]] = spirv.Constant -1
910  %c0 = spirv.Constant 0 : i32
911  %cn1 = spirv.Constant -1 : i32
912
913  // CHECK: %0 = spirv.UMod %[[CN1]], %[[C0]]
914  %0 = spirv.UMod %cn1, %c0 : i32
915  return %0 : i32
916}
917
918// CHECK-LABEL: @const_fold_scalar_umod
919func.func @const_fold_scalar_umod() -> (i32, i32, i32) {
920  %c56 = spirv.Constant 56 : i32
921  %c7 = spirv.Constant 7 : i32
922  %cn8 = spirv.Constant -8 : i32
923  %c3 = spirv.Constant 3 : i32
924
925  // CHECK-DAG: %[[C0:.*]] = spirv.Constant 0
926  // CHECK-DAG: %[[C2:.*]] = spirv.Constant 2
927  // CHECK-DAG: %[[C56:.*]] = spirv.Constant 56
928  %0 = spirv.UMod %c56, %c7 : i32
929  %1 = spirv.UMod %cn8, %c3 : i32
930  %2 = spirv.UMod %c56, %cn8 : i32
931
932  // CHECK: return %[[C0]], %[[C2]], %[[C56]]
933  return %0, %1, %2 : i32, i32, i32
934}
935
936// CHECK-LABEL: @const_fold_vector_umod
937func.func @const_fold_vector_umod() -> vector<3xi32> {
938  // CHECK: %[[CVEC:.*]] = spirv.Constant dense<[42, 24, 0]>
939
940  %cv = spirv.Constant dense<[42, 24, -16]> : vector<3xi32>
941  %cv_mod = spirv.Constant dense<[76, -7, 5]> : vector<3xi32>
942  %0 = spirv.UMod %cv, %cv_mod : vector<3xi32>
943
944  // CHECK: return %[[CVEC]]
945  return %0 : vector<3xi32>
946}
947
948// CHECK-LABEL: @umod_fold
949// CHECK-SAME: (%[[ARG:.*]]: i32)
950func.func @umod_fold(%arg0: i32) -> (i32, i32) {
951  // CHECK: %[[CONST4:.*]] = spirv.Constant 4
952  // CHECK: %[[CONST32:.*]] = spirv.Constant 32
953  %const1 = spirv.Constant 32 : i32
954  %0 = spirv.UMod %arg0, %const1 : i32
955  %const2 = spirv.Constant 4 : i32
956  %1 = spirv.UMod %0, %const2 : i32
957  // CHECK: %[[UMOD0:.*]] = spirv.UMod %[[ARG]], %[[CONST32]]
958  // CHECK: %[[UMOD1:.*]] = spirv.UMod %[[ARG]], %[[CONST4]]
959  // CHECK: return %[[UMOD0]], %[[UMOD1]]
960  return %0, %1: i32, i32
961}
962
963// CHECK-LABEL: @umod_fail_vector_fold
964// CHECK-SAME: (%[[ARG:.*]]: vector<4xi32>)
965func.func @umod_fail_vector_fold(%arg0: vector<4xi32>) -> (vector<4xi32>, vector<4xi32>) {
966  // CHECK: %[[CONST4:.*]] = spirv.Constant dense<4> : vector<4xi32>
967  // CHECK: %[[CONST32:.*]] = spirv.Constant dense<32> : vector<4xi32>
968  %const1 = spirv.Constant dense<32> : vector<4xi32>
969  %0 = spirv.UMod %arg0, %const1 : vector<4xi32>
970  // CHECK: %[[UMOD0:.*]] = spirv.UMod %[[ARG]], %[[CONST32]]
971  %const2 = spirv.Constant dense<4> : vector<4xi32>
972  %1 = spirv.UMod %0, %const2 : vector<4xi32>
973  // CHECK: %[[UMOD1:.*]] = spirv.UMod %[[UMOD0]], %[[CONST4]]
974  // CHECK: return %[[UMOD0]], %[[UMOD1]]
975  return %0, %1: vector<4xi32>, vector<4xi32>
976}
977
978// CHECK-LABEL: @umod_fold_same_divisor
979// CHECK-SAME: (%[[ARG:.*]]: i32)
980func.func @umod_fold_same_divisor(%arg0: i32) -> (i32, i32) {
981  // CHECK: %[[CONST1:.*]] = spirv.Constant 32
982  %const1 = spirv.Constant 32 : i32
983  %0 = spirv.UMod %arg0, %const1 : i32
984  %const2 = spirv.Constant 32 : i32
985  %1 = spirv.UMod %0, %const2 : i32
986  // CHECK: %[[UMOD0:.*]] = spirv.UMod %[[ARG]], %[[CONST1]]
987  // CHECK: %[[UMOD1:.*]] = spirv.UMod %[[ARG]], %[[CONST1]]
988  // CHECK: return %[[UMOD0]], %[[UMOD1]]
989  return %0, %1: i32, i32
990}
991
992// CHECK-LABEL: @umod_fail_fold
993// CHECK-SAME: (%[[ARG:.*]]: i32)
994func.func @umod_fail_fold(%arg0: i32) -> (i32, i32) {
995  // CHECK: %[[CONST5:.*]] = spirv.Constant 5
996  // CHECK: %[[CONST32:.*]] = spirv.Constant 32
997  %const1 = spirv.Constant 32 : i32
998  %0 = spirv.UMod %arg0, %const1 : i32
999  // CHECK: %[[UMOD0:.*]] = spirv.UMod %[[ARG]], %[[CONST32]]
1000  %const2 = spirv.Constant 5 : i32
1001  %1 = spirv.UMod %0, %const2 : i32
1002  // CHECK: %[[UMOD1:.*]] = spirv.UMod %[[UMOD0]], %[[CONST5]]
1003  // CHECK: return %[[UMOD0]], %[[UMOD1]]
1004  return %0, %1: i32, i32
1005}
1006
1007// -----
1008
1009//===----------------------------------------------------------------------===//
1010// spirv.SNegate
1011//===----------------------------------------------------------------------===//
1012
1013// CHECK-LABEL: @snegate_twice
1014// CHECK-SAME: (%[[ARG:.*]]: i32)
1015func.func @snegate_twice(%arg0 : i32) -> i32 {
1016  %0 = spirv.SNegate %arg0 : i32
1017  %1 = spirv.SNegate %0 : i32
1018
1019  // CHECK: return %[[ARG]] : i32
1020  return %1 : i32
1021}
1022
1023// CHECK-LABEL: @snegate_min
1024func.func @snegate_min() -> (i8, i8) {
1025  // CHECK: %[[MIN:.*]] = spirv.Constant -128 : i8
1026  %cmin = spirv.Constant -128 : i8
1027
1028  %0 = spirv.SNegate %cmin : i8
1029  %1 = spirv.SNegate %0 : i8
1030
1031  // CHECK: return %[[MIN]], %[[MIN]]
1032  return %0, %1 : i8, i8
1033}
1034
1035// CHECK-LABEL: @const_fold_scalar_snegate
1036func.func @const_fold_scalar_snegate() -> (i32, i32, i32) {
1037  %c0 = spirv.Constant 0 : i32
1038  %c3 = spirv.Constant 3 : i32
1039  %cn3 = spirv.Constant -3 : i32
1040
1041  // CHECK-DAG: %[[THREE:.*]] = spirv.Constant 3 : i32
1042  // CHECK-DAG: %[[NTHREE:.*]] = spirv.Constant -3 : i32
1043  // CHECK-DAG: %[[ZERO:.*]] = spirv.Constant 0 : i32
1044  %0 = spirv.SNegate %c0 : i32
1045  %1 = spirv.SNegate %c3 : i32
1046  %2 = spirv.SNegate %cn3 : i32
1047
1048  // CHECK: return %[[ZERO]], %[[NTHREE]], %[[THREE]]
1049  return %0, %1, %2  : i32, i32, i32
1050}
1051
1052// CHECK-LABEL: @const_fold_vector_snegate
1053func.func @const_fold_vector_snegate() -> vector<3xi32> {
1054  // CHECK: spirv.Constant dense<[0, 3, -3]>
1055  %cv = spirv.Constant dense<[0, -3, 3]> : vector<3xi32>
1056  %0 = spirv.SNegate %cv : vector<3xi32>
1057  return %0  : vector<3xi32>
1058}
1059
1060// -----
1061
1062//===----------------------------------------------------------------------===//
1063// spirv.Not
1064//===----------------------------------------------------------------------===//
1065
1066// CHECK-LABEL: @not_twice
1067// CHECK-SAME: (%[[ARG:.*]]: i32)
1068func.func @not_twice(%arg0 : i32) -> i32 {
1069  %0 = spirv.Not %arg0 : i32
1070  %1 = spirv.Not %0 : i32
1071
1072  // CHECK: return %[[ARG]] : i32
1073  return %1 : i32
1074}
1075
1076// CHECK-LABEL: @const_fold_scalar_not
1077func.func @const_fold_scalar_not() -> (i32, i32, i32) {
1078  %c0 = spirv.Constant 0 : i32
1079  %c3 = spirv.Constant 3 : i32
1080  %cn3 = spirv.Constant -3 : i32
1081
1082  // CHECK-DAG: %[[TWO:.*]] = spirv.Constant 2 : i32
1083  // CHECK-DAG: %[[NFOUR:.*]] = spirv.Constant -4 : i32
1084  // CHECK-DAG: %[[NONE:.*]] = spirv.Constant -1 : i32
1085  %0 = spirv.Not %c0 : i32
1086  %1 = spirv.Not %c3 : i32
1087  %2 = spirv.Not %cn3 : i32
1088
1089  // CHECK: return %[[NONE]], %[[NFOUR]], %[[TWO]]
1090  return %0, %1, %2  : i32, i32, i32
1091}
1092
1093// CHECK-LABEL: @const_fold_vector_not
1094func.func @const_fold_vector_not() -> vector<3xi32> {
1095  %cv = spirv.Constant dense<[-1, -4, 2]> : vector<3xi32>
1096
1097  // CHECK: spirv.Constant dense<[0, 3, -3]>
1098  %0 = spirv.Not %cv : vector<3xi32>
1099
1100  return %0 : vector<3xi32>
1101}
1102
1103// -----
1104
1105//===----------------------------------------------------------------------===//
1106// spirv.LogicalAnd
1107//===----------------------------------------------------------------------===//
1108
1109// CHECK-LABEL: @convert_logical_and_true_false_scalar
1110// CHECK-SAME: %[[ARG:.+]]: i1
1111func.func @convert_logical_and_true_false_scalar(%arg: i1) -> (i1, i1) {
1112  %true = spirv.Constant true
1113  // CHECK: %[[FALSE:.+]] = spirv.Constant false
1114  %false = spirv.Constant false
1115  %0 = spirv.LogicalAnd %true, %arg: i1
1116  %1 = spirv.LogicalAnd %arg, %false: i1
1117  // CHECK: return %[[ARG]], %[[FALSE]]
1118  return %0, %1: i1, i1
1119}
1120
1121// CHECK-LABEL: @convert_logical_and_true_false_vector
1122// CHECK-SAME: %[[ARG:.+]]: vector<3xi1>
1123func.func @convert_logical_and_true_false_vector(%arg: vector<3xi1>) -> (vector<3xi1>, vector<3xi1>) {
1124  %true = spirv.Constant dense<true> : vector<3xi1>
1125  // CHECK: %[[FALSE:.+]] = spirv.Constant dense<false>
1126  %false = spirv.Constant dense<false> : vector<3xi1>
1127  %0 = spirv.LogicalAnd %true, %arg: vector<3xi1>
1128  %1 = spirv.LogicalAnd %arg, %false: vector<3xi1>
1129  // CHECK: return %[[ARG]], %[[FALSE]]
1130  return %0, %1: vector<3xi1>, vector<3xi1>
1131}
1132
1133// -----
1134
1135//===----------------------------------------------------------------------===//
1136// spirv.LogicalNot
1137//===----------------------------------------------------------------------===//
1138
1139// CHECK-LABEL: @logical_not_twice
1140// CHECK-SAME: (%[[ARG:.*]]: i1)
1141func.func @logical_not_twice(%arg0 : i1) -> i1 {
1142  %0 = spirv.LogicalNot %arg0 : i1
1143  %1 = spirv.LogicalNot %0 : i1
1144
1145  // CHECK: return %[[ARG]] : i1
1146  return %1 : i1
1147}
1148
1149// CHECK-LABEL: @const_fold_scalar_logical_not
1150func.func @const_fold_scalar_logical_not() -> i1 {
1151  %true = spirv.Constant true
1152
1153  // CHECK: spirv.Constant false
1154  %0 = spirv.LogicalNot %true : i1
1155
1156  return %0 : i1
1157}
1158
1159// CHECK-LABEL: @const_fold_vector_logical_not
1160func.func @const_fold_vector_logical_not() -> vector<2xi1> {
1161  %cv = spirv.Constant dense<[true, false]> : vector<2xi1>
1162
1163  // CHECK: spirv.Constant dense<[false, true]>
1164  %0 = spirv.LogicalNot %cv : vector<2xi1>
1165
1166  return %0 : vector<2xi1>
1167}
1168
1169// -----
1170
1171func.func @convert_logical_not_to_not_equal(%arg0: vector<3xi64>, %arg1: vector<3xi64>) -> vector<3xi1> {
1172  // CHECK: %[[RESULT:.*]] = spirv.INotEqual {{%.*}}, {{%.*}} : vector<3xi64>
1173  // CHECK-NEXT: spirv.ReturnValue %[[RESULT]] : vector<3xi1>
1174  %2 = spirv.IEqual %arg0, %arg1 : vector<3xi64>
1175  %3 = spirv.LogicalNot %2 : vector<3xi1>
1176  spirv.ReturnValue %3 : vector<3xi1>
1177}
1178
1179// -----
1180
1181//===----------------------------------------------------------------------===//
1182// spirv.LogicalEqual
1183//===----------------------------------------------------------------------===//
1184
1185// CHECK-LABEL: @logical_equal_same
1186func.func @logical_equal_same(%arg0 : i1, %arg1 : vector<3xi1>) -> (i1, vector<3xi1>) {
1187  // CHECK-DAG: %[[CTRUE:.*]] = spirv.Constant true
1188  // CHECK-DAG: %[[CVTRUE:.*]] = spirv.Constant dense<true>
1189
1190  %0 = spirv.LogicalEqual %arg0, %arg0 : i1
1191  %1 = spirv.LogicalEqual %arg1, %arg1 : vector<3xi1>
1192  // CHECK: return %[[CTRUE]], %[[CVTRUE]]
1193  return %0, %1 : i1, vector<3xi1>
1194}
1195
1196// CHECK-LABEL: @const_fold_scalar_logical_equal
1197func.func @const_fold_scalar_logical_equal() -> (i1, i1) {
1198  %true = spirv.Constant true
1199  %false = spirv.Constant false
1200
1201  // CHECK-DAG: %[[CTRUE:.*]] = spirv.Constant true
1202  // CHECK-DAG: %[[CFALSE:.*]] = spirv.Constant false
1203  %0 = spirv.LogicalEqual %true, %false : i1
1204  %1 = spirv.LogicalEqual %false, %false : i1
1205
1206  // CHECK: return %[[CFALSE]], %[[CTRUE]]
1207  return %0, %1 : i1, i1
1208}
1209
1210// CHECK-LABEL: @const_fold_vector_logical_equal
1211func.func @const_fold_vector_logical_equal() -> vector<3xi1> {
1212  %cv0 = spirv.Constant dense<[true, false, true]> : vector<3xi1>
1213  %cv1 = spirv.Constant dense<[true, false, false]> : vector<3xi1>
1214
1215  // CHECK: %[[RET:.*]] = spirv.Constant dense<[true, true, false]>
1216  %0 = spirv.LogicalEqual %cv0, %cv1 : vector<3xi1>
1217
1218  // CHECK: return %[[RET]]
1219  return %0 : vector<3xi1>
1220}
1221
1222// -----
1223
1224//===----------------------------------------------------------------------===//
1225// spirv.LogicalNotEqual
1226//===----------------------------------------------------------------------===//
1227
1228// CHECK-LABEL: @convert_logical_not_equal_false
1229// CHECK-SAME: %[[ARG:.+]]: vector<4xi1>
1230func.func @convert_logical_not_equal_false(%arg: vector<4xi1>) -> vector<4xi1> {
1231  %cst = spirv.Constant dense<false> : vector<4xi1>
1232  // CHECK: spirv.ReturnValue %[[ARG]] : vector<4xi1>
1233  %0 = spirv.LogicalNotEqual %arg, %cst : vector<4xi1>
1234  spirv.ReturnValue %0 : vector<4xi1>
1235}
1236
1237// CHECK-LABEL: @logical_not_equal_same
1238func.func @logical_not_equal_same(%arg0 : i1, %arg1 : vector<3xi1>) -> (i1, vector<3xi1>) {
1239  // CHECK-DAG: %[[CFALSE:.*]] = spirv.Constant false
1240  // CHECK-DAG: %[[CVFALSE:.*]] = spirv.Constant dense<false>
1241  %0 = spirv.LogicalNotEqual %arg0, %arg0 : i1
1242  %1 = spirv.LogicalNotEqual %arg1, %arg1 : vector<3xi1>
1243
1244  // CHECK: return %[[CFALSE]], %[[CVFALSE]]
1245  return %0, %1 : i1, vector<3xi1>
1246}
1247
1248// CHECK-LABEL: @const_fold_scalar_logical_not_equal
1249func.func @const_fold_scalar_logical_not_equal() -> (i1, i1) {
1250  %true = spirv.Constant true
1251  %false = spirv.Constant false
1252
1253  // CHECK-DAG: %[[CTRUE:.*]] = spirv.Constant true
1254  // CHECK-DAG: %[[CFALSE:.*]] = spirv.Constant false
1255  %0 = spirv.LogicalNotEqual %true, %false : i1
1256  %1 = spirv.LogicalNotEqual %false, %false : i1
1257
1258  // CHECK: return %[[CTRUE]], %[[CFALSE]]
1259  return %0, %1 : i1, i1
1260}
1261
1262// CHECK-LABEL: @const_fold_vector_logical_not_equal
1263func.func @const_fold_vector_logical_not_equal() -> vector<3xi1> {
1264  %cv0 = spirv.Constant dense<[true, false, true]> : vector<3xi1>
1265  %cv1 = spirv.Constant dense<[true, false, false]> : vector<3xi1>
1266
1267  // CHECK: %[[RET:.*]] = spirv.Constant dense<[false, false, true]>
1268  %0 = spirv.LogicalNotEqual %cv0, %cv1 : vector<3xi1>
1269
1270  // CHECK: return %[[RET]]
1271  return %0 : vector<3xi1>
1272}
1273
1274// -----
1275
1276func.func @convert_logical_not_to_equal(%arg0: vector<3xi64>, %arg1: vector<3xi64>) -> vector<3xi1> {
1277  // CHECK: %[[RESULT:.*]] = spirv.IEqual {{%.*}}, {{%.*}} : vector<3xi64>
1278  // CHECK-NEXT: spirv.ReturnValue %[[RESULT]] : vector<3xi1>
1279  %2 = spirv.INotEqual %arg0, %arg1 : vector<3xi64>
1280  %3 = spirv.LogicalNot %2 : vector<3xi1>
1281  spirv.ReturnValue %3 : vector<3xi1>
1282}
1283
1284// -----
1285
1286func.func @convert_logical_not_parent_multi_use(%arg0: vector<3xi64>, %arg1: vector<3xi64>, %arg2: !spirv.ptr<vector<3xi1>, Uniform>) -> vector<3xi1> {
1287  // CHECK: %[[RESULT_0:.*]] = spirv.INotEqual {{%.*}}, {{%.*}} : vector<3xi64>
1288  // CHECK-NEXT: %[[RESULT_1:.*]] = spirv.IEqual {{%.*}}, {{%.*}} : vector<3xi64>
1289  // CHECK-NEXT: spirv.Store "Uniform" {{%.*}}, %[[RESULT_0]]
1290  // CHECK-NEXT: spirv.ReturnValue %[[RESULT_1]]
1291  %0 = spirv.INotEqual %arg0, %arg1 : vector<3xi64>
1292  %1 = spirv.LogicalNot %0 : vector<3xi1>
1293  spirv.Store "Uniform" %arg2, %0 : vector<3xi1>
1294  spirv.ReturnValue %1 : vector<3xi1>
1295}
1296
1297// -----
1298
1299func.func @convert_logical_not_to_logical_not_equal(%arg0: vector<3xi1>, %arg1: vector<3xi1>) -> vector<3xi1> {
1300  // CHECK: %[[RESULT:.*]] = spirv.LogicalNotEqual {{%.*}}, {{%.*}} : vector<3xi1>
1301  // CHECK-NEXT: spirv.ReturnValue %[[RESULT]] : vector<3xi1>
1302  %2 = spirv.LogicalEqual %arg0, %arg1 : vector<3xi1>
1303  %3 = spirv.LogicalNot %2 : vector<3xi1>
1304  spirv.ReturnValue %3 : vector<3xi1>
1305}
1306
1307// -----
1308
1309func.func @convert_logical_not_to_logical_equal(%arg0: vector<3xi1>, %arg1: vector<3xi1>) -> vector<3xi1> {
1310  // CHECK: %[[RESULT:.*]] = spirv.LogicalEqual {{%.*}}, {{%.*}} : vector<3xi1>
1311  // CHECK-NEXT: spirv.ReturnValue %[[RESULT]] : vector<3xi1>
1312  %2 = spirv.LogicalNotEqual %arg0, %arg1 : vector<3xi1>
1313  %3 = spirv.LogicalNot %2 : vector<3xi1>
1314  spirv.ReturnValue %3 : vector<3xi1>
1315}
1316
1317// -----
1318
1319//===----------------------------------------------------------------------===//
1320// spirv.LogicalOr
1321//===----------------------------------------------------------------------===//
1322
1323// CHECK-LABEL: @convert_logical_or_true_false_scalar
1324// CHECK-SAME: %[[ARG:.+]]: i1
1325func.func @convert_logical_or_true_false_scalar(%arg: i1) -> (i1, i1) {
1326  // CHECK: %[[TRUE:.+]] = spirv.Constant true
1327  %true = spirv.Constant true
1328  %false = spirv.Constant false
1329  %0 = spirv.LogicalOr %true, %arg: i1
1330  %1 = spirv.LogicalOr %arg, %false: i1
1331  // CHECK: return %[[TRUE]], %[[ARG]]
1332  return %0, %1: i1, i1
1333}
1334
1335// CHECK-LABEL: @convert_logical_or_true_false_vector
1336// CHECK-SAME: %[[ARG:.+]]: vector<3xi1>
1337func.func @convert_logical_or_true_false_vector(%arg: vector<3xi1>) -> (vector<3xi1>, vector<3xi1>) {
1338  // CHECK: %[[TRUE:.+]] = spirv.Constant dense<true>
1339  %true = spirv.Constant dense<true> : vector<3xi1>
1340  %false = spirv.Constant dense<false> : vector<3xi1>
1341  %0 = spirv.LogicalOr %true, %arg: vector<3xi1>
1342  %1 = spirv.LogicalOr %arg, %false: vector<3xi1>
1343  // CHECK: return %[[TRUE]], %[[ARG]]
1344  return %0, %1: vector<3xi1>, vector<3xi1>
1345}
1346
1347// -----
1348
1349//===----------------------------------------------------------------------===//
1350// spirv.Select
1351//===----------------------------------------------------------------------===//
1352
1353// CHECK-LABEL: @convert_select_scalar
1354// CHECK-SAME: %[[ARG1:.+]]: i32, %[[ARG2:.+]]: i32
1355func.func @convert_select_scalar(%arg1: i32, %arg2: i32) -> (i32, i32) {
1356  %true = spirv.Constant true
1357  %false = spirv.Constant false
1358  %0 = spirv.Select %true, %arg1, %arg2 : i1, i32
1359  %1 = spirv.Select %false, %arg1, %arg2 : i1, i32
1360
1361  // CHECK: return %[[ARG1]], %[[ARG2]]
1362  return %0, %1 : i32, i32
1363}
1364
1365// CHECK-LABEL: @convert_select_vector
1366// CHECK-SAME: %[[ARG1:.+]]: vector<3xi32>, %[[ARG2:.+]]: vector<3xi32>
1367func.func @convert_select_vector(%arg1: vector<3xi32>, %arg2: vector<3xi32>) -> (vector<3xi32>, vector<3xi32>) {
1368  %true = spirv.Constant dense<true> : vector<3xi1>
1369  %false = spirv.Constant dense<false> : vector<3xi1>
1370  %0 = spirv.Select %true, %arg1, %arg2 : vector<3xi1>, vector<3xi32>
1371  %1 = spirv.Select %false, %arg1, %arg2 : vector<3xi1>, vector<3xi32>
1372
1373  // CHECK: return %[[ARG1]], %[[ARG2]]
1374  return %0, %1: vector<3xi32>, vector<3xi32>
1375}
1376
1377// CHECK-LABEL: @convert_select_vector_extra
1378// CHECK-SAME: %[[CONDITIONS:.+]]: vector<2xi1>, %[[ARG1:.+]]: vector<2xi32>
1379func.func @convert_select_vector_extra(%conditions: vector<2xi1>, %arg1: vector<2xi32>) -> (vector<2xi32>, vector<2xi32>) {
1380  %true_false = spirv.Constant dense<[true, false]> : vector<2xi1>
1381  %cvec_1 = spirv.Constant dense<[42, -132]> : vector<2xi32>
1382  %cvec_2 = spirv.Constant dense<[0, 42]> : vector<2xi32>
1383
1384  // CHECK: %[[RES:.+]] = spirv.Constant dense<42>
1385  %0 = spirv.Select %true_false, %cvec_1, %cvec_2: vector<2xi1>, vector<2xi32>
1386
1387  %1 = spirv.Select %conditions, %arg1, %arg1 : vector<2xi1>, vector<2xi32>
1388
1389  // CHECK: return %[[RES]], %[[ARG1]]
1390  return %0, %1: vector<2xi32>, vector<2xi32>
1391}
1392
1393// -----
1394
1395//===----------------------------------------------------------------------===//
1396// spirv.IEqual
1397//===----------------------------------------------------------------------===//
1398
1399// CHECK-LABEL: @iequal_same
1400func.func @iequal_same(%arg0 : i32, %arg1 : vector<3xi32>) -> (i1, vector<3xi1>) {
1401  // CHECK-DAG: %[[CTRUE:.*]] = spirv.Constant true
1402  // CHECK-DAG: %[[CVTRUE:.*]] = spirv.Constant dense<true>
1403  %0 = spirv.IEqual %arg0, %arg0 : i32
1404  %1 = spirv.IEqual %arg1, %arg1 : vector<3xi32>
1405
1406  // CHECK: return %[[CTRUE]], %[[CVTRUE]]
1407  return %0, %1 : i1, vector<3xi1>
1408}
1409
1410// CHECK-LABEL: @const_fold_scalar_iequal
1411func.func @const_fold_scalar_iequal() -> (i1, i1) {
1412  %c5 = spirv.Constant 5 : i32
1413  %c6 = spirv.Constant 6 : i32
1414
1415  // CHECK-DAG: %[[CTRUE:.*]] = spirv.Constant true
1416  // CHECK-DAG: %[[CFALSE:.*]] = spirv.Constant false
1417  %0 = spirv.IEqual %c5, %c6 : i32
1418  %1 = spirv.IEqual %c5, %c5 : i32
1419
1420  // CHECK: return %[[CFALSE]], %[[CTRUE]]
1421  return %0, %1 : i1, i1
1422}
1423
1424// CHECK-LABEL: @const_fold_vector_iequal
1425func.func @const_fold_vector_iequal() -> vector<3xi1> {
1426  %cv0 = spirv.Constant dense<[-1, -4, 2]> : vector<3xi32>
1427  %cv1 = spirv.Constant dense<[-1, -3, 2]> : vector<3xi32>
1428
1429  // CHECK: %[[RET:.*]] = spirv.Constant dense<[true, false, true]>
1430  %0 = spirv.IEqual %cv0, %cv1 : vector<3xi32>
1431
1432  // CHECK: return %[[RET]]
1433  return %0 : vector<3xi1>
1434}
1435
1436// -----
1437
1438//===----------------------------------------------------------------------===//
1439// spirv.INotEqual
1440//===----------------------------------------------------------------------===//
1441
1442// CHECK-LABEL: @inotequal_same
1443func.func @inotequal_same(%arg0 : i32, %arg1 : vector<3xi32>) -> (i1, vector<3xi1>) {
1444  // CHECK-DAG: %[[CFALSE:.*]] = spirv.Constant false
1445  // CHECK-DAG: %[[CVFALSE:.*]] = spirv.Constant dense<false>
1446  %0 = spirv.INotEqual %arg0, %arg0 : i32
1447  %1 = spirv.INotEqual %arg1, %arg1 : vector<3xi32>
1448
1449  // CHECK: return %[[CFALSE]], %[[CVFALSE]]
1450  return %0, %1 : i1, vector<3xi1>
1451}
1452
1453// CHECK-LABEL: @const_fold_scalar_inotequal
1454func.func @const_fold_scalar_inotequal() -> (i1, i1) {
1455  %c5 = spirv.Constant 5 : i32
1456  %c6 = spirv.Constant 6 : i32
1457
1458  // CHECK-DAG: %[[CTRUE:.*]] = spirv.Constant true
1459  // CHECK-DAG: %[[CFALSE:.*]] = spirv.Constant false
1460  %0 = spirv.INotEqual %c5, %c6 : i32
1461  %1 = spirv.INotEqual %c5, %c5 : i32
1462
1463  // CHECK: return %[[CTRUE]], %[[CFALSE]]
1464  return %0, %1 : i1, i1
1465}
1466
1467// CHECK-LABEL: @const_fold_vector_inotequal
1468func.func @const_fold_vector_inotequal() -> vector<3xi1> {
1469  %cv0 = spirv.Constant dense<[-1, -4, 2]> : vector<3xi32>
1470  %cv1 = spirv.Constant dense<[-1, -3, 2]> : vector<3xi32>
1471
1472  // CHECK: %[[RET:.*]] = spirv.Constant dense<[false, true, false]>
1473  %0 = spirv.INotEqual %cv0, %cv1 : vector<3xi32>
1474
1475  // CHECK: return %[[RET]]
1476  return %0 : vector<3xi1>
1477}
1478
1479// -----
1480
1481//===----------------------------------------------------------------------===//
1482// spirv.SGreaterThan
1483//===----------------------------------------------------------------------===//
1484
1485// CHECK-LABEL: @sgt_same
1486func.func @sgt_same(%arg0 : i32, %arg1 : vector<3xi32>) -> (i1, vector<3xi1>) {
1487  // CHECK-DAG: %[[CFALSE:.*]] = spirv.Constant false
1488  // CHECK-DAG: %[[CVFALSE:.*]] = spirv.Constant dense<false>
1489  %0 = spirv.SGreaterThan %arg0, %arg0 : i32
1490  %1 = spirv.SGreaterThan %arg1, %arg1 : vector<3xi32>
1491
1492  // CHECK: return %[[CFALSE]], %[[CVFALSE]]
1493  return %0, %1 : i1, vector<3xi1>
1494}
1495
1496// CHECK-LABEL: @const_fold_scalar_sgt
1497func.func @const_fold_scalar_sgt() -> (i1, i1) {
1498  %c4 = spirv.Constant 4 : i32
1499  %c5 = spirv.Constant 5 : i32
1500  %c6 = spirv.Constant 6 : i32
1501
1502  // CHECK-DAG: %[[CTRUE:.*]] = spirv.Constant true
1503  // CHECK-DAG: %[[CFALSE:.*]] = spirv.Constant false
1504  %0 = spirv.SGreaterThan %c5, %c6 : i32
1505  %1 = spirv.SGreaterThan %c5, %c4 : i32
1506
1507  // CHECK: return %[[CFALSE]], %[[CTRUE]]
1508  return %0, %1 : i1, i1
1509}
1510
1511// CHECK-LABEL: @const_fold_vector_sgt
1512func.func @const_fold_vector_sgt() -> vector<3xi1> {
1513  %cv0 = spirv.Constant dense<[-1, -4, 3]> : vector<3xi32>
1514  %cv1 = spirv.Constant dense<[-1, -3, 2]> : vector<3xi32>
1515
1516  // CHECK: %[[RET:.*]] = spirv.Constant dense<[false, false, true]>
1517  %0 = spirv.SGreaterThan %cv0, %cv1 : vector<3xi32>
1518
1519  // CHECK: return %[[RET]]
1520  return %0 : vector<3xi1>
1521}
1522
1523// -----
1524
1525//===----------------------------------------------------------------------===//
1526// spirv.SGreaterThanEqual
1527//===----------------------------------------------------------------------===//
1528
1529// CHECK-LABEL: @sge_same
1530func.func @sge_same(%arg0 : i32, %arg1 : vector<3xi32>) -> (i1, vector<3xi1>) {
1531  // CHECK-DAG: %[[CTRUE:.*]] = spirv.Constant true
1532  // CHECK-DAG: %[[CVTRUE:.*]] = spirv.Constant dense<true>
1533  %0 = spirv.SGreaterThanEqual %arg0, %arg0 : i32
1534  %1 = spirv.SGreaterThanEqual %arg1, %arg1 : vector<3xi32>
1535
1536  // CHECK: return %[[CTRUE]], %[[CVTRUE]]
1537  return %0, %1 : i1, vector<3xi1>
1538}
1539
1540// CHECK-LABEL: @const_fold_scalar_sge
1541func.func @const_fold_scalar_sge() -> (i1, i1) {
1542  %c4 = spirv.Constant 4 : i32
1543  %c5 = spirv.Constant 5 : i32
1544  %c6 = spirv.Constant 6 : i32
1545
1546  // CHECK-DAG: %[[CTRUE:.*]] = spirv.Constant true
1547  // CHECK-DAG: %[[CFALSE:.*]] = spirv.Constant false
1548  %0 = spirv.SGreaterThanEqual %c5, %c6 : i32
1549  %1 = spirv.SGreaterThanEqual %c5, %c4 : i32
1550
1551  // CHECK: return %[[CFALSE]], %[[CTRUE]]
1552  return %0, %1 : i1, i1
1553}
1554
1555// CHECK-LABEL: @const_fold_vector_sge
1556func.func @const_fold_vector_sge() -> vector<3xi1> {
1557  %cv0 = spirv.Constant dense<[-1, -4, 3]> : vector<3xi32>
1558  %cv1 = spirv.Constant dense<[-1, -3, 2]> : vector<3xi32>
1559
1560  // CHECK: %[[RET:.*]] = spirv.Constant dense<[true, false, true]>
1561  %0 = spirv.SGreaterThanEqual %cv0, %cv1 : vector<3xi32>
1562
1563  // CHECK: return %[[RET]]
1564  return %0 : vector<3xi1>
1565}
1566
1567// -----
1568
1569//===----------------------------------------------------------------------===//
1570// spirv.UGreaterThan
1571//===----------------------------------------------------------------------===//
1572
1573// CHECK-LABEL: @ugt_same
1574func.func @ugt_same(%arg0 : i32, %arg1 : vector<3xi32>) -> (i1, vector<3xi1>) {
1575  // CHECK-DAG: %[[CFALSE:.*]] = spirv.Constant false
1576  // CHECK-DAG: %[[CVFALSE:.*]] = spirv.Constant dense<false>
1577  %0 = spirv.UGreaterThan %arg0, %arg0 : i32
1578  %1 = spirv.UGreaterThan %arg1, %arg1 : vector<3xi32>
1579
1580  // CHECK: return %[[CFALSE]], %[[CVFALSE]]
1581  return %0, %1 : i1, vector<3xi1>
1582}
1583
1584// CHECK-LABEL: @const_fold_scalar_ugt
1585func.func @const_fold_scalar_ugt() -> (i1, i1) {
1586  %c4 = spirv.Constant 4 : i32
1587  %c5 = spirv.Constant 5 : i32
1588  %cn6 = spirv.Constant -6 : i32
1589
1590  // CHECK-DAG: %[[CTRUE:.*]] = spirv.Constant true
1591  // CHECK-DAG: %[[CFALSE:.*]] = spirv.Constant false
1592  %0 = spirv.UGreaterThan %c5, %cn6 : i32
1593  %1 = spirv.UGreaterThan %c5, %c4 : i32
1594
1595  // CHECK: return %[[CFALSE]], %[[CTRUE]]
1596  return %0, %1 : i1, i1
1597}
1598
1599// CHECK-LABEL: @const_fold_vector_ugt
1600func.func @const_fold_vector_ugt() -> vector<3xi1> {
1601  %cv0 = spirv.Constant dense<[-1, -4, 3]> : vector<3xi32>
1602  %cv1 = spirv.Constant dense<[-1, -3, 2]> : vector<3xi32>
1603
1604  // CHECK: %[[RET:.*]] = spirv.Constant dense<[false, false, true]>
1605  %0 = spirv.UGreaterThan %cv0, %cv1 : vector<3xi32>
1606
1607  // CHECK: return %[[RET]]
1608  return %0 : vector<3xi1>
1609}
1610
1611// -----
1612
1613//===----------------------------------------------------------------------===//
1614// spirv.UGreaterThanEqual
1615//===----------------------------------------------------------------------===//
1616
1617// CHECK-LABEL: @uge_same
1618func.func @uge_same(%arg0 : i32, %arg1 : vector<3xi32>) -> (i1, vector<3xi1>) {
1619  // CHECK-DAG: %[[CTRUE:.*]] = spirv.Constant true
1620  // CHECK-DAG: %[[CVTRUE:.*]] = spirv.Constant dense<true>
1621  %0 = spirv.UGreaterThanEqual %arg0, %arg0 : i32
1622  %1 = spirv.UGreaterThanEqual %arg1, %arg1 : vector<3xi32>
1623
1624  // CHECK: return %[[CTRUE]], %[[CVTRUE]]
1625  return %0, %1 : i1, vector<3xi1>
1626}
1627
1628// CHECK-LABEL: @const_fold_scalar_uge
1629func.func @const_fold_scalar_uge() -> (i1, i1) {
1630  %c4 = spirv.Constant 4 : i32
1631  %c5 = spirv.Constant 5 : i32
1632  %cn6 = spirv.Constant -6 : i32
1633
1634  // CHECK-DAG: %[[CTRUE:.*]] = spirv.Constant true
1635  // CHECK-DAG: %[[CFALSE:.*]] = spirv.Constant false
1636  %0 = spirv.UGreaterThanEqual %c5, %cn6 : i32
1637  %1 = spirv.UGreaterThanEqual %c5, %c4 : i32
1638
1639  // CHECK: return %[[CFALSE]], %[[CTRUE]]
1640  return %0, %1 : i1, i1
1641}
1642
1643// CHECK-LABEL: @const_fold_vector_uge
1644func.func @const_fold_vector_uge() -> vector<3xi1> {
1645  %cv0 = spirv.Constant dense<[-1, -4, 3]> : vector<3xi32>
1646  %cv1 = spirv.Constant dense<[-1, -3, 2]> : vector<3xi32>
1647
1648  // CHECK: %[[RET:.*]] = spirv.Constant dense<[true, false, true]>
1649  %0 = spirv.UGreaterThanEqual %cv0, %cv1 : vector<3xi32>
1650
1651  // CHECK: return %[[RET]]
1652  return %0 : vector<3xi1>
1653}
1654
1655// -----
1656
1657//===----------------------------------------------------------------------===//
1658// spirv.SLessThan
1659//===----------------------------------------------------------------------===//
1660
1661// CHECK-LABEL: @slt_same
1662func.func @slt_same(%arg0 : i32, %arg1 : vector<3xi32>) -> (i1, vector<3xi1>) {
1663  // CHECK-DAG: %[[CFALSE:.*]] = spirv.Constant false
1664  // CHECK-DAG: %[[CVFALSE:.*]] = spirv.Constant dense<false>
1665  %0 = spirv.SLessThan %arg0, %arg0 : i32
1666  %1 = spirv.SLessThan %arg1, %arg1 : vector<3xi32>
1667
1668  // CHECK: return %[[CFALSE]], %[[CVFALSE]]
1669  return %0, %1 : i1, vector<3xi1>
1670}
1671
1672// CHECK-LABEL: @const_fold_scalar_slt
1673func.func @const_fold_scalar_slt() -> (i1, i1) {
1674  %c4 = spirv.Constant 4 : i32
1675  %c5 = spirv.Constant 5 : i32
1676  %c6 = spirv.Constant 6 : i32
1677
1678  // CHECK-DAG: %[[CTRUE:.*]] = spirv.Constant true
1679  // CHECK-DAG: %[[CFALSE:.*]] = spirv.Constant false
1680  %0 = spirv.SLessThan %c5, %c6 : i32
1681  %1 = spirv.SLessThan %c5, %c4 : i32
1682
1683  // CHECK: return %[[CTRUE]], %[[CFALSE]]
1684  return %0, %1 : i1, i1
1685}
1686
1687// CHECK-LABEL: @const_fold_vector_slt
1688func.func @const_fold_vector_slt() -> vector<3xi1> {
1689  %cv0 = spirv.Constant dense<[-1, -4, 3]> : vector<3xi32>
1690  %cv1 = spirv.Constant dense<[-1, -3, 2]> : vector<3xi32>
1691
1692  // CHECK: %[[RET:.*]] = spirv.Constant dense<[false, true, false]>
1693  %0 = spirv.SLessThan %cv0, %cv1 : vector<3xi32>
1694
1695  // CHECK: return %[[RET]]
1696  return %0 : vector<3xi1>
1697}
1698
1699// -----
1700
1701//===----------------------------------------------------------------------===//
1702// spirv.SLessThanEqual
1703//===----------------------------------------------------------------------===//
1704
1705// CHECK-LABEL: @sle_same
1706func.func @sle_same(%arg0 : i32, %arg1 : vector<3xi32>) -> (i1, vector<3xi1>) {
1707  // CHECK-DAG: %[[CTRUE:.*]] = spirv.Constant true
1708  // CHECK-DAG: %[[CVTRUE:.*]] = spirv.Constant dense<true>
1709  %0 = spirv.SLessThanEqual %arg0, %arg0 : i32
1710  %1 = spirv.SLessThanEqual %arg1, %arg1 : vector<3xi32>
1711
1712  // CHECK: return %[[CTRUE]], %[[CVTRUE]]
1713  return %0, %1 : i1, vector<3xi1>
1714}
1715
1716// CHECK-LABEL: @const_fold_scalar_sle
1717func.func @const_fold_scalar_sle() -> (i1, i1) {
1718  %c4 = spirv.Constant 4 : i32
1719  %c5 = spirv.Constant 5 : i32
1720  %c6 = spirv.Constant 6 : i32
1721
1722  // CHECK-DAG: %[[CTRUE:.*]] = spirv.Constant true
1723  // CHECK-DAG: %[[CFALSE:.*]] = spirv.Constant false
1724  %0 = spirv.SLessThanEqual %c5, %c6 : i32
1725  %1 = spirv.SLessThanEqual %c5, %c4 : i32
1726
1727  // CHECK: return %[[CTRUE]], %[[CFALSE]]
1728  return %0, %1 : i1, i1
1729}
1730
1731// CHECK-LABEL: @const_fold_vector_sle
1732func.func @const_fold_vector_sle() -> vector<3xi1> {
1733  %cv0 = spirv.Constant dense<[-1, -4, 3]> : vector<3xi32>
1734  %cv1 = spirv.Constant dense<[-1, -3, 2]> : vector<3xi32>
1735
1736  // CHECK: %[[RET:.*]] = spirv.Constant dense<[true, true, false]>
1737  %0 = spirv.SLessThanEqual %cv0, %cv1 : vector<3xi32>
1738
1739  // CHECK: return %[[RET]]
1740  return %0 : vector<3xi1>
1741}
1742
1743// -----
1744
1745//===----------------------------------------------------------------------===//
1746// spirv.ULessThan
1747//===----------------------------------------------------------------------===//
1748
1749// CHECK-LABEL: @ult_same
1750func.func @ult_same(%arg0 : i32, %arg1 : vector<3xi32>) -> (i1, vector<3xi1>) {
1751  // CHECK-DAG: %[[CFALSE:.*]] = spirv.Constant false
1752  // CHECK-DAG: %[[CVFALSE:.*]] = spirv.Constant dense<false>
1753  %0 = spirv.ULessThan %arg0, %arg0 : i32
1754  %1 = spirv.ULessThan %arg1, %arg1 : vector<3xi32>
1755
1756  // CHECK: return %[[CFALSE]], %[[CVFALSE]]
1757  return %0, %1 : i1, vector<3xi1>
1758}
1759
1760// CHECK-LABEL: @const_fold_scalar_ult
1761func.func @const_fold_scalar_ult() -> (i1, i1) {
1762  %c4 = spirv.Constant 4 : i32
1763  %c5 = spirv.Constant 5 : i32
1764  %cn6 = spirv.Constant -6 : i32
1765
1766  // CHECK-DAG: %[[CTRUE:.*]] = spirv.Constant true
1767  // CHECK-DAG: %[[CFALSE:.*]] = spirv.Constant false
1768  %0 = spirv.ULessThan %c5, %cn6 : i32
1769  %1 = spirv.ULessThan %c5, %c4 : i32
1770
1771  // CHECK: return %[[CTRUE]], %[[CFALSE]]
1772  return %0, %1 : i1, i1
1773}
1774
1775// CHECK-LABEL: @const_fold_vector_ult
1776func.func @const_fold_vector_ult() -> vector<3xi1> {
1777  %cv0 = spirv.Constant dense<[-1, -4, 3]> : vector<3xi32>
1778  %cv1 = spirv.Constant dense<[-1, -3, 2]> : vector<3xi32>
1779
1780  // CHECK: %[[RET:.*]] = spirv.Constant dense<[false, true, false]>
1781  %0 = spirv.ULessThan %cv0, %cv1 : vector<3xi32>
1782
1783  // CHECK: return %[[RET]]
1784  return %0 : vector<3xi1>
1785}
1786
1787// -----
1788
1789//===----------------------------------------------------------------------===//
1790// spirv.ULessThanEqual
1791//===----------------------------------------------------------------------===//
1792
1793// CHECK-LABEL: @ule_same
1794func.func @ule_same(%arg0 : i32, %arg1 : vector<3xi32>) -> (i1, vector<3xi1>) {
1795  // CHECK-DAG: %[[CTRUE:.*]] = spirv.Constant true
1796  // CHECK-DAG: %[[CVTRUE:.*]] = spirv.Constant dense<true>
1797  %0 = spirv.ULessThanEqual %arg0, %arg0 : i32
1798  %1 = spirv.ULessThanEqual %arg1, %arg1 : vector<3xi32>
1799
1800  // CHECK: return %[[CTRUE]], %[[CVTRUE]]
1801  return %0, %1 : i1, vector<3xi1>
1802}
1803
1804// CHECK-LABEL: @const_fold_scalar_ule
1805func.func @const_fold_scalar_ule() -> (i1, i1) {
1806  %c4 = spirv.Constant 4 : i32
1807  %c5 = spirv.Constant 5 : i32
1808  %cn6 = spirv.Constant -6 : i32
1809
1810  // CHECK-DAG: %[[CTRUE:.*]] = spirv.Constant true
1811  // CHECK-DAG: %[[CFALSE:.*]] = spirv.Constant false
1812  %0 = spirv.ULessThanEqual %c5, %cn6 : i32
1813  %1 = spirv.ULessThanEqual %c5, %c4 : i32
1814
1815  // CHECK: return %[[CTRUE]], %[[CFALSE]]
1816  return %0, %1 : i1, i1
1817}
1818
1819// CHECK-LABEL: @const_fold_vector_ule
1820func.func @const_fold_vector_ule() -> vector<3xi1> {
1821  %cv0 = spirv.Constant dense<[-1, -4, 3]> : vector<3xi32>
1822  %cv1 = spirv.Constant dense<[-1, -3, 2]> : vector<3xi32>
1823
1824  // CHECK: %[[RET:.*]] = spirv.Constant dense<[true, true, false]>
1825  %0 = spirv.ULessThanEqual %cv0, %cv1 : vector<3xi32>
1826
1827  // CHECK: return %[[RET]]
1828  return %0 : vector<3xi1>
1829}
1830
1831// -----
1832
1833//===----------------------------------------------------------------------===//
1834// spirv.LeftShiftLogical
1835//===----------------------------------------------------------------------===//
1836
1837// CHECK-LABEL: @lsl_x_0
1838// CHECK-SAME: (%[[ARG0:.*]]: i32, %[[ARG1:.*]]: vector<3xi32>)
1839func.func @lsl_x_0(%arg0 : i32, %arg1: vector<3xi32>) -> (i32, vector<3xi32>) {
1840  %c0 = spirv.Constant 0 : i32
1841  %cv0 = spirv.Constant dense<0> : vector<3xi32>
1842
1843  %0 = spirv.ShiftLeftLogical %arg0, %c0 : i32, i32
1844  %1 = spirv.ShiftLeftLogical %arg1, %cv0 : vector<3xi32>, vector<3xi32>
1845
1846  // CHECK: return %[[ARG0]], %[[ARG1]]
1847  return %0, %1 : i32, vector<3xi32>
1848}
1849
1850// CHECK-LABEL: @lsl_shift_overflow
1851// CHECK-SAME: (%[[ARG0:.*]]: i32, %[[ARG1:.*]]: vector<3xi32>)
1852func.func @lsl_shift_overflow(%arg0: i32, %arg1: vector<3xi32>) -> (i32, vector<3xi32>) {
1853  // CHECK-DAG: %[[C32:.*]] = spirv.Constant 32
1854  // CHECK-DAG: %[[CV:.*]] = spirv.Constant dense<[6, 18, 128]>
1855  %c32 = spirv.Constant 32 : i32
1856  %cv = spirv.Constant dense<[6, 18, 128]> : vector<3xi32>
1857
1858  // CHECK: %0 = spirv.ShiftLeftLogical %[[ARG0]], %[[C32]]
1859  // CHECK: %1 = spirv.ShiftLeftLogical %[[ARG1]], %[[CV]]
1860  %0 = spirv.ShiftLeftLogical %arg0, %c32 : i32, i32
1861  %1 = spirv.ShiftLeftLogical %arg1, %cv : vector<3xi32>, vector<3xi32>
1862
1863  return %0, %1 : i32, vector<3xi32>
1864}
1865
1866// CHECK-LABEL: @const_fold_scalar_lsl
1867func.func @const_fold_scalar_lsl() -> i32 {
1868  %c1 = spirv.Constant 65535 : i32  // 0x0000 ffff
1869  %c2 = spirv.Constant 17 : i32
1870
1871  // CHECK: %[[RET:.*]] = spirv.Constant -131072
1872  // 0x0000 ffff << 17 -> 0xfffe 0000
1873  %0 = spirv.ShiftLeftLogical %c1, %c2 : i32, i32
1874
1875  // CHECK: return %[[RET]]
1876  return %0 : i32
1877}
1878
1879// CHECK-LABEL: @const_fold_vector_lsl
1880func.func @const_fold_vector_lsl() -> vector<3xi32> {
1881  %c1 = spirv.Constant dense<[1, -1, 127]> : vector<3xi32>
1882  %c2 = spirv.Constant dense<[31, 16, 13]> : vector<3xi32>
1883
1884  // CHECK: %[[RET:.*]] = spirv.Constant dense<[-2147483648, -65536, 1040384]>
1885  %0 = spirv.ShiftLeftLogical %c1, %c2 : vector<3xi32>, vector<3xi32>
1886
1887  // CHECK: return %[[RET]]
1888  return %0 : vector<3xi32>
1889}
1890
1891// -----
1892
1893//===----------------------------------------------------------------------===//
1894// spirv.RightShiftArithmetic
1895//===----------------------------------------------------------------------===//
1896
1897// CHECK-LABEL: @asr_x_0
1898// CHECK-SAME: (%[[ARG0:.*]]: i32, %[[ARG1:.*]]: vector<3xi32>)
1899func.func @asr_x_0(%arg0 : i32, %arg1: vector<3xi32>) -> (i32, vector<3xi32>) {
1900  %c0 = spirv.Constant 0 : i32
1901  %cv0 = spirv.Constant dense<0> : vector<3xi32>
1902
1903  %0 = spirv.ShiftRightArithmetic %arg0, %c0 : i32, i32
1904  %1 = spirv.ShiftRightArithmetic %arg1, %cv0 : vector<3xi32>, vector<3xi32>
1905
1906  // CHECK: return %[[ARG0]], %[[ARG1]]
1907  return %0, %1 : i32, vector<3xi32>
1908}
1909
1910// CHECK-LABEL: @asr_shift_overflow
1911// CHECK-SAME: (%[[ARG0:.*]]: i32, %[[ARG1:.*]]: vector<3xi32>)
1912func.func @asr_shift_overflow(%arg0: i32, %arg1: vector<3xi32>) -> (i32, vector<3xi32>) {
1913  // CHECK-DAG: %[[C32:.*]] = spirv.Constant 32
1914  // CHECK-DAG: %[[CV:.*]] = spirv.Constant dense<[6, 18, 128]>
1915  %c32 = spirv.Constant 32 : i32
1916  %cv = spirv.Constant dense<[6, 18, 128]> : vector<3xi32>
1917
1918  // CHECK: %0 = spirv.ShiftRightArithmetic %[[ARG0]], %[[C32]]
1919  // CHECK: %1 = spirv.ShiftRightArithmetic %[[ARG1]], %[[CV]]
1920  %0 = spirv.ShiftRightArithmetic %arg0, %c32 : i32, i32
1921  %1 = spirv.ShiftRightArithmetic %arg1, %cv : vector<3xi32>, vector<3xi32>
1922
1923  return %0, %1 : i32, vector<3xi32>
1924}
1925
1926// CHECK-LABEL: @const_fold_scalar_asr
1927func.func @const_fold_scalar_asr() -> i32 {
1928  %c1 = spirv.Constant -131072 : i32  // 0xfffe 0000
1929  %c2 = spirv.Constant 17 : i32
1930  // 0x0000 ffff ashr 17 -> 0xffff ffff
1931  // CHECK: %[[RET:.*]] = spirv.Constant -1
1932  %0 = spirv.ShiftRightArithmetic %c1, %c2 : i32, i32
1933
1934  // CHECK: return %[[RET]]
1935  return %0 : i32
1936}
1937
1938// CHECK-LABEL: @const_fold_vector_asr
1939func.func @const_fold_vector_asr() -> vector<3xi32> {
1940  %c1 = spirv.Constant dense<[-2147483648, 239847, 127]> : vector<3xi32>
1941  %c2 = spirv.Constant dense<[31, 16, 13]> : vector<3xi32>
1942
1943  // CHECK: %[[RET:.*]] = spirv.Constant dense<[-1, 3, 0]>
1944  %0 = spirv.ShiftRightArithmetic %c1, %c2 : vector<3xi32>, vector<3xi32>
1945
1946  // CHECK: return %[[RET]]
1947  return %0 : vector<3xi32>
1948}
1949
1950// -----
1951
1952//===----------------------------------------------------------------------===//
1953// spirv.RightShiftLogical
1954//===----------------------------------------------------------------------===//
1955
1956// CHECK-LABEL: @lsr_x_0
1957// CHECK-SAME: (%[[ARG0:.*]]: i32, %[[ARG1:.*]]: vector<3xi32>)
1958func.func @lsr_x_0(%arg0 : i32, %arg1: vector<3xi32>) -> (i32, vector<3xi32>) {
1959  %c0 = spirv.Constant 0 : i32
1960  %cv0 = spirv.Constant dense<0> : vector<3xi32>
1961
1962  %0 = spirv.ShiftRightLogical %arg0, %c0 : i32, i32
1963  %1 = spirv.ShiftRightLogical %arg1, %cv0 : vector<3xi32>, vector<3xi32>
1964
1965  // CHECK: return %[[ARG0]], %[[ARG1]]
1966  return %0, %1 : i32, vector<3xi32>
1967}
1968
1969// CHECK-LABEL: @lsr_shift_overflow
1970// CHECK-SAME: (%[[ARG0:.*]]: i32, %[[ARG1:.*]]: vector<3xi32>)
1971func.func @lsr_shift_overflow(%arg0: i32, %arg1: vector<3xi32>) -> (i32, vector<3xi32>) {
1972  // CHECK-DAG: %[[C32:.*]] = spirv.Constant 32
1973  // CHECK-DAG: %[[CV:.*]] = spirv.Constant dense<[6, 18, 128]>
1974  %c32 = spirv.Constant 32 : i32
1975  %cv = spirv.Constant dense<[6, 18, 128]> : vector<3xi32>
1976
1977  // CHECK: %0 = spirv.ShiftRightLogical %[[ARG0]], %[[C32]]
1978  // CHECK: %1 = spirv.ShiftRightLogical %[[ARG1]], %[[CV]]
1979  %0 = spirv.ShiftRightLogical %arg0, %c32 : i32, i32
1980  %1 = spirv.ShiftRightLogical %arg1, %cv : vector<3xi32>, vector<3xi32>
1981  return %0, %1 : i32, vector<3xi32>
1982}
1983
1984// CHECK-LABEL: @const_fold_scalar_lsr
1985func.func @const_fold_scalar_lsr() -> i32 {
1986  %c1 = spirv.Constant -131072 : i32  // 0xfffe 0000
1987  %c2 = spirv.Constant 17 : i32
1988
1989  // 0x0000 ffff << 17 -> 0x0000 7fff
1990  // CHECK: %[[RET:.*]] = spirv.Constant 32767
1991  %0 = spirv.ShiftRightLogical %c1, %c2 : i32, i32
1992
1993  // CHECK: return %[[RET]]
1994  return %0 : i32
1995}
1996
1997// CHECK-LABEL: @const_fold_vector_lsr
1998func.func @const_fold_vector_lsr() -> vector<3xi32> {
1999  %c1 = spirv.Constant dense<[-2147483648, -1, -127]> : vector<3xi32>
2000  %c2 = spirv.Constant dense<[31, 16, 13]> : vector<3xi32>
2001
2002  // CHECK: %[[RET:.*]] = spirv.Constant dense<[1, 65535, 524287]>
2003  %0 = spirv.ShiftRightLogical %c1, %c2 : vector<3xi32>, vector<3xi32>
2004
2005  // CHECK: return %[[RET]]
2006  return %0 : vector<3xi32>
2007}
2008
2009// -----
2010
2011//===----------------------------------------------------------------------===//
2012// spirv.BitwiseAnd
2013//===----------------------------------------------------------------------===//
2014
2015// CHECK-LABEL: @bitwise_and_x_x
2016// CHECK-SAME: (%[[ARG0:.*]]: i32, %[[ARG1:.*]]: vector<3xi32>)
2017func.func @bitwise_and_x_x(%arg0: i32, %arg1: vector<3xi32>) -> (i32, vector<3xi32>) {
2018  %0 = spirv.BitwiseAnd %arg0, %arg0 : i32
2019  %1 = spirv.BitwiseAnd %arg1, %arg1 : vector<3xi32>
2020
2021  // CHECK: return %[[ARG0]], %[[ARG1]]
2022  return %0, %1 : i32, vector<3xi32>
2023}
2024
2025// CHECK-LABEL: @bitwise_and_x_0
2026func.func @bitwise_and_x_0(%arg0 : i32, %arg1 : vector<3xi32>) -> (i32, vector<3xi32>) {
2027  // CHECK-DAG: %[[C0:.*]] = spirv.Constant 0 : i32
2028  // CHECK-DAG: %[[CV0:.*]] = spirv.Constant dense<0> : vector<3xi32>
2029  %c0 = spirv.Constant 0 : i32
2030  %cv0 = spirv.Constant dense<0> : vector<3xi32>
2031
2032  %0 = spirv.BitwiseAnd %arg0, %c0 : i32
2033  %1 = spirv.BitwiseAnd %arg1, %cv0 : vector<3xi32>
2034
2035  // CHECK: return %[[C0]], %[[CV0]]
2036  return %0, %1 : i32, vector<3xi32>
2037}
2038
2039// CHECK-LABEL: @bitwise_and_x_n1
2040// CHECK-SAME: (%[[ARG0:.*]]: i32, %[[ARG1:.*]]: vector<3xi32>)
2041func.func @bitwise_and_x_n1(%arg0: i32, %arg1: vector<3xi32>) -> (i32, vector<3xi32>) {
2042  %cn1 = spirv.Constant -1 : i32
2043  %cvn1 = spirv.Constant dense<-1> : vector<3xi32>
2044  %0 = spirv.BitwiseAnd %arg0, %cn1 : i32
2045  %1 = spirv.BitwiseAnd %arg1, %cvn1 : vector<3xi32>
2046
2047  // CHECK: return %[[ARG0]], %[[ARG1]]
2048  return %0, %1 : i32, vector<3xi32>
2049}
2050
2051// CHECK-LABEL: @const_fold_scalar_band
2052func.func @const_fold_scalar_band() -> i32 {
2053  %c1 = spirv.Constant -268464129 : i32   // 0xefff 8fff
2054  %c2 = spirv.Constant 268464128: i32     // 0x1000 7000
2055
2056  // 0xefff 8fff | 0x1000 7000 = 0xffff ffff = -1
2057  // CHECK: %[[C0:.*]] = spirv.Constant 0
2058  %0 = spirv.BitwiseAnd %c1, %c2 : i32
2059
2060  // CHECK: return %[[C0]]
2061  return %0 : i32
2062}
2063
2064// CHECK-LABEL: @const_fold_vector_band
2065func.func @const_fold_vector_band() -> vector<3xi32> {
2066  %c1 = spirv.Constant dense<[42, -55, 127]> : vector<3xi32>
2067  %c2 = spirv.Constant dense<[-3, -15, 28]> : vector<3xi32>
2068
2069  // CHECK: %[[CV:.*]] = spirv.Constant dense<[40, -63, 28]>
2070  %0 = spirv.BitwiseAnd %c1, %c2 : vector<3xi32>
2071
2072  // CHECK: return %[[CV]]
2073  return %0 : vector<3xi32>
2074}
2075
2076// -----
2077
2078//===----------------------------------------------------------------------===//
2079// spirv.BitwiseOr
2080//===----------------------------------------------------------------------===//
2081
2082// CHECK-LABEL: @bitwise_or_x_x
2083// CHECK-SAME: (%[[ARG0:.*]]: i32, %[[ARG1:.*]]: vector<3xi32>)
2084func.func @bitwise_or_x_x(%arg0: i32, %arg1: vector<3xi32>) -> (i32, vector<3xi32>) {
2085  %0 = spirv.BitwiseOr %arg0, %arg0 : i32
2086  %1 = spirv.BitwiseOr %arg1, %arg1 : vector<3xi32>
2087
2088  // CHECK: return %[[ARG0]], %[[ARG1]]
2089  return %0, %1 : i32, vector<3xi32>
2090}
2091
2092// CHECK-LABEL: @bitwise_or_x_0
2093// CHECK-SAME: (%[[ARG0:.*]]: i32, %[[ARG1:.*]]: vector<3xi32>)
2094func.func @bitwise_or_x_0(%arg0: i32, %arg1: vector<3xi32>) -> (i32, vector<3xi32>) {
2095  %c1 = spirv.Constant 0 : i32
2096  %cv1 = spirv.Constant dense<0> : vector<3xi32>
2097  %0 = spirv.BitwiseOr %arg0, %c1 : i32
2098  %1 = spirv.BitwiseOr %arg1, %cv1 : vector<3xi32>
2099
2100  // CHECK: return %[[ARG0]], %[[ARG1]]
2101  return %0, %1 : i32, vector<3xi32>
2102}
2103
2104// CHECK-LABEL: @bitwise_or_x_n1
2105func.func @bitwise_or_x_n1(%arg0 : i32, %arg1 : vector<3xi32>) -> (i32, vector<3xi32>) {
2106  // CHECK-DAG: %[[CN1:.*]] = spirv.Constant -1 : i32
2107  // CHECK-DAG: %[[CVN1:.*]] = spirv.Constant dense<-1> : vector<3xi32>
2108  %cn1 = spirv.Constant -1 : i32
2109  %cvn1 = spirv.Constant dense<-1> : vector<3xi32>
2110  %0 = spirv.BitwiseOr %arg0, %cn1 : i32
2111  %1 = spirv.BitwiseOr %arg1, %cvn1 : vector<3xi32>
2112
2113  // CHECK: return %[[CN1]], %[[CVN1]]
2114  return %0, %1 : i32, vector<3xi32>
2115}
2116
2117// CHECK-LABEL: @const_fold_scalar_bor
2118func.func @const_fold_scalar_bor() -> i32 {
2119  %c1 = spirv.Constant -268464129 : i32   // 0xefff 8fff
2120  %c2 = spirv.Constant 268464128: i32     // 0x1000 7000
2121
2122  // 0xefff 8fff | 0x1000 7000 = 0xffff ffff = -1
2123  // CHECK: %[[CN1:.*]] = spirv.Constant -1
2124  %0 = spirv.BitwiseOr %c1, %c2 : i32
2125
2126  // CHECK: return %[[CN1]]
2127  return %0 : i32
2128}
2129
2130// CHECK-LABEL: @const_fold_vector_bor
2131func.func @const_fold_vector_bor() -> vector<3xi32> {
2132  %c1 = spirv.Constant dense<[42, -55, 127]> : vector<3xi32>
2133  %c2 = spirv.Constant dense<[-3, -15, 28]> : vector<3xi32>
2134
2135  // CHECK: %[[CV:.*]] = spirv.Constant dense<[-1, -7, 127]>
2136  %0 = spirv.BitwiseOr %c1, %c2 : vector<3xi32>
2137
2138  // CHECK: return %[[CV]]
2139  return %0 : vector<3xi32>
2140}
2141
2142// -----
2143
2144//===----------------------------------------------------------------------===//
2145// spirv.BitwiseXor
2146//===----------------------------------------------------------------------===//
2147
2148// CHECK-LABEL: @bitwise_xor_x_0
2149// CHECK-SAME: (%[[ARG0:.*]]: i32, %[[ARG1:.*]]: vector<3xi32>)
2150func.func @bitwise_xor_x_0(%arg0: i32, %arg1: vector<3xi32>) -> (i32, vector<3xi32>) {
2151  %c0 = spirv.Constant 0 : i32
2152  %cv0 = spirv.Constant dense<0> : vector<3xi32>
2153
2154  %0 = spirv.BitwiseXor %arg0, %c0 : i32
2155  %1 = spirv.BitwiseXor %arg1, %cv0 : vector<3xi32>
2156
2157  // CHECK: return %[[ARG0]], %[[ARG1]]
2158  return %0, %1 : i32, vector<3xi32>
2159}
2160
2161// CHECK-LABEL: @bitwise_xor_x_x
2162func.func @bitwise_xor_x_x(%arg0 : i32, %arg1 : vector<3xi32>) -> (i32, vector<3xi32>) {
2163  // CHECK-DAG: %[[C0:.*]] = spirv.Constant 0
2164  // CHECK-DAG: %[[CV0:.*]] = spirv.Constant dense<0>
2165  %0 = spirv.BitwiseXor %arg0, %arg0 : i32
2166  %1 = spirv.BitwiseXor %arg1, %arg1 : vector<3xi32>
2167
2168  // CHECK: return %[[C0]], %[[CV0]]
2169  return %0, %1 : i32, vector<3xi32>
2170}
2171
2172// CHECK-LABEL: @const_fold_scalar_bxor
2173func.func @const_fold_scalar_bxor() -> i32 {
2174  %c1 = spirv.Constant 4294967295 : i32  // 2^32 - 1: 0xffff ffff
2175  %c2 = spirv.Constant -2147483648 : i32 // -2^31   : 0x8000 0000
2176
2177  // 0x8000 0000 ^ 0xffff fffe = 0xefff ffff
2178  // CHECK: %[[CBIG:.*]] = spirv.Constant 2147483647
2179  %0 = spirv.BitwiseXor %c1, %c2 : i32
2180
2181  // CHECK: return %[[CBIG]]
2182  return %0 : i32
2183}
2184
2185// CHECK-LABEL: @const_fold_vector_bxor
2186func.func @const_fold_vector_bxor() -> vector<3xi32> {
2187  %c1 = spirv.Constant dense<[42, -55, 127]> : vector<3xi32>
2188  %c2 = spirv.Constant dense<[-3, -15, 28]> : vector<3xi32>
2189
2190  // CHECK: %[[CV:.*]] = spirv.Constant dense<[-41, 56, 99]>
2191  %0 = spirv.BitwiseXor %c1, %c2 : vector<3xi32>
2192
2193  // CHECK: return %[[CV]]
2194  return %0 : vector<3xi32>
2195}
2196
2197// -----
2198
2199//===----------------------------------------------------------------------===//
2200// spirv.mlir.selection
2201//===----------------------------------------------------------------------===//
2202
2203func.func @canonicalize_selection_op_scalar_type(%cond: i1) -> () {
2204  %0 = spirv.Constant 0: i32
2205  // CHECK-DAG: %[[TRUE_VALUE:.*]] = spirv.Constant 1 : i32
2206  %1 = spirv.Constant 1: i32
2207  // CHECK-DAG: %[[FALSE_VALUE:.*]] = spirv.Constant 2 : i32
2208  %2 = spirv.Constant 2: i32
2209  // CHECK: %[[DST_VAR:.*]] = spirv.Variable init({{%.*}}) : !spirv.ptr<i32, Function>
2210  %3 = spirv.Variable init(%0) : !spirv.ptr<i32, Function>
2211
2212  // CHECK: %[[SRC_VALUE:.*]] = spirv.Select {{%.*}}, %[[TRUE_VALUE]], %[[FALSE_VALUE]] : i1, i32
2213  // CHECK-NEXT: spirv.Store "Function" %[[DST_VAR]], %[[SRC_VALUE]] ["Aligned", 4] : i32
2214  // CHECK-NEXT: spirv.Return
2215  spirv.mlir.selection {
2216    spirv.BranchConditional %cond, ^then, ^else
2217
2218  ^else:
2219    spirv.Store "Function" %3, %2 ["Aligned", 4]: i32
2220    spirv.Branch ^merge
2221
2222  ^then:
2223    spirv.Store "Function" %3, %1 ["Aligned", 4]: i32
2224    spirv.Branch ^merge
2225
2226  ^merge:
2227    spirv.mlir.merge
2228  }
2229  spirv.Return
2230}
2231
2232// -----
2233
2234func.func @canonicalize_selection_op_vector_type(%cond: i1) -> () {
2235  %0 = spirv.Constant dense<[0, 1, 2]> : vector<3xi32>
2236  // CHECK-DAG: %[[TRUE_VALUE:.*]] = spirv.Constant dense<[1, 2, 3]> : vector<3xi32>
2237  %1 = spirv.Constant dense<[1, 2, 3]> : vector<3xi32>
2238  // CHECK-DAG: %[[FALSE_VALUE:.*]] = spirv.Constant dense<[2, 3, 4]> : vector<3xi32>
2239  %2 = spirv.Constant dense<[2, 3, 4]> : vector<3xi32>
2240  // CHECK: %[[DST_VAR:.*]] = spirv.Variable init({{%.*}}) : !spirv.ptr<vector<3xi32>, Function>
2241  %3 = spirv.Variable init(%0) : !spirv.ptr<vector<3xi32>, Function>
2242
2243  // CHECK: %[[SRC_VALUE:.*]] = spirv.Select {{%.*}}, %[[TRUE_VALUE]], %[[FALSE_VALUE]] : i1, vector<3xi32>
2244  // CHECK-NEXT: spirv.Store "Function" %[[DST_VAR]], %[[SRC_VALUE]] ["Aligned", 8] : vector<3xi32>
2245  // CHECK-NEXT: spirv.Return
2246  spirv.mlir.selection {
2247    spirv.BranchConditional %cond, ^then, ^else
2248
2249  ^then:
2250    spirv.Store "Function" %3, %1 ["Aligned", 8]:  vector<3xi32>
2251    spirv.Branch ^merge
2252
2253  ^else:
2254    spirv.Store "Function" %3, %2 ["Aligned", 8] : vector<3xi32>
2255    spirv.Branch ^merge
2256
2257  ^merge:
2258    spirv.mlir.merge
2259  }
2260  spirv.Return
2261}
2262
2263// -----
2264
2265// CHECK-LABEL: cannot_canonicalize_selection_op_0
2266
2267// Store to a different variables.
2268func.func @cannot_canonicalize_selection_op_0(%cond: i1) -> () {
2269  %0 = spirv.Constant dense<[0, 1, 2]> : vector<3xi32>
2270  // CHECK-DAG: %[[SRC_VALUE_1:.*]] = spirv.Constant dense<[2, 3, 4]> : vector<3xi32>
2271  // CHECK-DAG: %[[SRC_VALUE_0:.*]] = spirv.Constant dense<[1, 2, 3]> : vector<3xi32>
2272  %1 = spirv.Constant dense<[1, 2, 3]> : vector<3xi32>
2273  %2 = spirv.Constant dense<[2, 3, 4]> : vector<3xi32>
2274  // CHECK: %[[DST_VAR_0:.*]] = spirv.Variable init({{%.*}}) : !spirv.ptr<vector<3xi32>, Function>
2275  %3 = spirv.Variable init(%0) : !spirv.ptr<vector<3xi32>, Function>
2276  // CHECK: %[[DST_VAR_1:.*]] = spirv.Variable init({{%.*}}) : !spirv.ptr<vector<3xi32>, Function>
2277  %4 = spirv.Variable init(%0) : !spirv.ptr<vector<3xi32>, Function>
2278
2279  // CHECK: spirv.mlir.selection {
2280  spirv.mlir.selection {
2281    // CHECK: spirv.BranchConditional
2282    // CHECK-SAME: ^bb1(%[[DST_VAR_0]], %[[SRC_VALUE_0]]
2283    // CHECK-SAME: ^bb1(%[[DST_VAR_1]], %[[SRC_VALUE_1]]
2284    spirv.BranchConditional %cond, ^then, ^else
2285
2286  ^then:
2287    // CHECK: ^bb1(%[[ARG0:.*]]: !spirv.ptr<vector<3xi32>, Function>, %[[ARG1:.*]]: vector<3xi32>):
2288    // CHECK: spirv.Store "Function" %[[ARG0]], %[[ARG1]] ["Aligned", 8] : vector<3xi32>
2289    spirv.Store "Function" %3, %1 ["Aligned", 8]:  vector<3xi32>
2290    spirv.Branch ^merge
2291
2292  ^else:
2293    spirv.Store "Function" %4, %2 ["Aligned", 8] : vector<3xi32>
2294    spirv.Branch ^merge
2295
2296  ^merge:
2297    spirv.mlir.merge
2298  }
2299  spirv.Return
2300}
2301
2302// -----
2303
2304// CHECK-LABEL: cannot_canonicalize_selection_op_1
2305
2306// A conditional block consists of more than 2 operations.
2307func.func @cannot_canonicalize_selection_op_1(%cond: i1) -> () {
2308  %0 = spirv.Constant dense<[0, 1, 2]> : vector<3xi32>
2309  // CHECK-DAG: %[[SRC_VALUE_0:.*]] = spirv.Constant dense<[1, 2, 3]> : vector<3xi32>
2310  %1 = spirv.Constant dense<[1, 2, 3]> : vector<3xi32>
2311  // CHECK-DAG: %[[SRC_VALUE_1:.*]] = spirv.Constant dense<[2, 3, 4]> : vector<3xi32>
2312  %2 = spirv.Constant dense<[2, 3, 4]> : vector<3xi32>
2313  // CHECK: %[[DST_VAR_0:.*]] = spirv.Variable init({{%.*}}) : !spirv.ptr<vector<3xi32>, Function>
2314  %3 = spirv.Variable init(%0) : !spirv.ptr<vector<3xi32>, Function>
2315  // CHECK: %[[DST_VAR_1:.*]] = spirv.Variable init({{%.*}}) : !spirv.ptr<vector<3xi32>, Function>
2316  %4 = spirv.Variable init(%0) : !spirv.ptr<vector<3xi32>, Function>
2317
2318  // CHECK: spirv.mlir.selection {
2319  spirv.mlir.selection {
2320    spirv.BranchConditional %cond, ^then, ^else
2321
2322  ^then:
2323    // CHECK: spirv.Store "Function" %[[DST_VAR_0]], %[[SRC_VALUE_0]] ["Aligned", 8] : vector<3xi32>
2324    spirv.Store "Function" %3, %1 ["Aligned", 8] : vector<3xi32>
2325    // CHECK: spirv.Store "Function" %[[DST_VAR_1]], %[[SRC_VALUE_0]] ["Aligned", 8] : vector<3xi32>
2326    spirv.Store "Function" %4, %1 ["Aligned", 8]:  vector<3xi32>
2327    spirv.Branch ^merge
2328
2329  ^else:
2330    // CHECK: spirv.Store "Function" %[[DST_VAR_1]], %[[SRC_VALUE_1]] ["Aligned", 8] : vector<3xi32>
2331    spirv.Store "Function" %4, %2 ["Aligned", 8] : vector<3xi32>
2332    spirv.Branch ^merge
2333
2334  ^merge:
2335    spirv.mlir.merge
2336  }
2337  spirv.Return
2338}
2339
2340// -----
2341
2342// CHECK-LABEL: cannot_canonicalize_selection_op_2
2343
2344// A control-flow goes into `^then` block from `^else` block.
2345func.func @cannot_canonicalize_selection_op_2(%cond: i1) -> () {
2346  %0 = spirv.Constant dense<[0, 1, 2]> : vector<3xi32>
2347  // CHECK-DAG: %[[SRC_VALUE_0:.*]] = spirv.Constant dense<[1, 2, 3]> : vector<3xi32>
2348  %1 = spirv.Constant dense<[1, 2, 3]> : vector<3xi32>
2349  // CHECK-DAG: %[[SRC_VALUE_1:.*]] = spirv.Constant dense<[2, 3, 4]> : vector<3xi32>
2350  %2 = spirv.Constant dense<[2, 3, 4]> : vector<3xi32>
2351  // CHECK: %[[DST_VAR:.*]] = spirv.Variable init({{%.*}}) : !spirv.ptr<vector<3xi32>, Function>
2352  %3 = spirv.Variable init(%0) : !spirv.ptr<vector<3xi32>, Function>
2353
2354  // CHECK: spirv.mlir.selection {
2355  spirv.mlir.selection {
2356    spirv.BranchConditional %cond, ^then, ^else
2357
2358  ^then:
2359    // CHECK: spirv.Store "Function" %[[DST_VAR]], %[[SRC_VALUE_0]] ["Aligned", 8] : vector<3xi32>
2360    spirv.Store "Function" %3, %1 ["Aligned", 8]:  vector<3xi32>
2361    spirv.Branch ^merge
2362
2363  ^else:
2364    // CHECK: spirv.Store "Function" %[[DST_VAR]], %[[SRC_VALUE_1]] ["Aligned", 8] : vector<3xi32>
2365    spirv.Store "Function" %3, %2 ["Aligned", 8] : vector<3xi32>
2366    spirv.Branch ^then
2367
2368  ^merge:
2369    spirv.mlir.merge
2370  }
2371  spirv.Return
2372}
2373
2374// -----
2375
2376// CHECK-LABEL: cannot_canonicalize_selection_op_3
2377
2378// `spirv.Return` as a block terminator.
2379func.func @cannot_canonicalize_selection_op_3(%cond: i1) -> () {
2380  %0 = spirv.Constant dense<[0, 1, 2]> : vector<3xi32>
2381  %1 = spirv.Constant dense<[1, 2, 3]> : vector<3xi32>
2382  // CHECK-DAG: %[[SRC_VALUE_0:.*]] = spirv.Constant dense<[1, 2, 3]> : vector<3xi32>
2383  // CHECK-DAG: %[[SRC_VALUE_1:.*]] = spirv.Constant dense<[2, 3, 4]> : vector<3xi32>
2384  %2 = spirv.Constant dense<[2, 3, 4]> : vector<3xi32>
2385  // CHECK: %[[DST_VAR:.*]] = spirv.Variable init({{%.*}}) : !spirv.ptr<vector<3xi32>, Function>
2386  %3 = spirv.Variable init(%0) : !spirv.ptr<vector<3xi32>, Function>
2387
2388  // CHECK: spirv.mlir.selection {
2389  spirv.mlir.selection {
2390    spirv.BranchConditional %cond, ^then, ^else
2391
2392  ^then:
2393    // CHECK: spirv.Store "Function" %[[DST_VAR]], %[[SRC_VALUE_0]] ["Aligned", 8] : vector<3xi32>
2394    spirv.Store "Function" %3, %1 ["Aligned", 8]:  vector<3xi32>
2395    spirv.Return
2396
2397  ^else:
2398    // CHECK: spirv.Store "Function" %[[DST_VAR]], %[[SRC_VALUE_1]] ["Aligned", 8] : vector<3xi32>
2399    spirv.Store "Function" %3, %2 ["Aligned", 8] : vector<3xi32>
2400    spirv.Branch ^merge
2401
2402  ^merge:
2403    spirv.mlir.merge
2404  }
2405  spirv.Return
2406}
2407
2408// -----
2409
2410// CHECK-LABEL: cannot_canonicalize_selection_op_4
2411
2412// Different memory access attributes.
2413func.func @cannot_canonicalize_selection_op_4(%cond: i1) -> () {
2414  %0 = spirv.Constant dense<[0, 1, 2]> : vector<3xi32>
2415  // CHECK-DAG: %[[SRC_VALUE_0:.*]] = spirv.Constant dense<[1, 2, 3]> : vector<3xi32>
2416  %1 = spirv.Constant dense<[1, 2, 3]> : vector<3xi32>
2417  // CHECK-DAG: %[[SRC_VALUE_1:.*]] = spirv.Constant dense<[2, 3, 4]> : vector<3xi32>
2418  %2 = spirv.Constant dense<[2, 3, 4]> : vector<3xi32>
2419  // CHECK: %[[DST_VAR:.*]] = spirv.Variable init({{%.*}}) : !spirv.ptr<vector<3xi32>, Function>
2420  %3 = spirv.Variable init(%0) : !spirv.ptr<vector<3xi32>, Function>
2421
2422  // CHECK: spirv.mlir.selection {
2423  spirv.mlir.selection {
2424    spirv.BranchConditional %cond, ^then, ^else
2425
2426  ^then:
2427    // CHECK: spirv.Store "Function" %[[DST_VAR]], %[[SRC_VALUE_0]] ["Aligned", 4] : vector<3xi32>
2428    spirv.Store "Function" %3, %1 ["Aligned", 4]:  vector<3xi32>
2429    spirv.Branch ^merge
2430
2431  ^else:
2432    // CHECK: spirv.Store "Function" %[[DST_VAR]], %[[SRC_VALUE_1]] ["Aligned", 8] : vector<3xi32>
2433    spirv.Store "Function" %3, %2 ["Aligned", 8] : vector<3xi32>
2434    spirv.Branch ^merge
2435
2436  ^merge:
2437    spirv.mlir.merge
2438  }
2439  spirv.Return
2440}
2441