xref: /llvm-project/mlir/test/Conversion/ArithToSPIRV/arith-to-spirv.mlir (revision b537df973731c4b84fdf6f9f44371c2b50205703)
1// RUN: mlir-opt -split-input-file -convert-arith-to-spirv -verify-diagnostics %s | FileCheck %s
2
3//===----------------------------------------------------------------------===//
4// arithmetic ops
5//===----------------------------------------------------------------------===//
6
7module attributes {
8  spirv.target_env = #spirv.target_env<
9    #spirv.vce<v1.0, [Int8, Int16, Int64, Float16, Float64, Shader], []>, #spirv.resource_limits<>>
10} {
11
12// Check integer operation conversions.
13// CHECK-LABEL: @int32_scalar
14func.func @int32_scalar(%lhs: i32, %rhs: i32) {
15  // CHECK: spirv.IAdd %{{.*}}, %{{.*}}: i32
16  %0 = arith.addi %lhs, %rhs: i32
17  // CHECK: spirv.ISub %{{.*}}, %{{.*}}: i32
18  %1 = arith.subi %lhs, %rhs: i32
19  // CHECK: spirv.IMul %{{.*}}, %{{.*}}: i32
20  %2 = arith.muli %lhs, %rhs: i32
21  // CHECK: spirv.SDiv %{{.*}}, %{{.*}}: i32
22  %3 = arith.divsi %lhs, %rhs: i32
23  // CHECK: spirv.UDiv %{{.*}}, %{{.*}}: i32
24  %4 = arith.divui %lhs, %rhs: i32
25  // CHECK: spirv.UMod %{{.*}}, %{{.*}}: i32
26  %5 = arith.remui %lhs, %rhs: i32
27  return
28}
29
30// CHECK-LABEL: @int32_scalar_srem
31// CHECK-SAME: (%[[LHS:.+]]: i32, %[[RHS:.+]]: i32)
32func.func @int32_scalar_srem(%lhs: i32, %rhs: i32) {
33  // CHECK: %[[LABS:.+]] = spirv.GL.SAbs %[[LHS]] : i32
34  // CHECK: %[[RABS:.+]] = spirv.GL.SAbs %[[RHS]] : i32
35  // CHECK:  %[[ABS:.+]] = spirv.UMod %[[LABS]], %[[RABS]] : i32
36  // CHECK:  %[[POS:.+]] = spirv.IEqual %[[LHS]], %[[LABS]] : i32
37  // CHECK:  %[[NEG:.+]] = spirv.SNegate %[[ABS]] : i32
38  // CHECK:      %{{.+}} = spirv.Select %[[POS]], %[[ABS]], %[[NEG]] : i1, i32
39  %0 = arith.remsi %lhs, %rhs: i32
40  return
41}
42
43// CHECK-LABEL: @index_scalar
44func.func @index_scalar(%lhs: index, %rhs: index) {
45  // CHECK: spirv.IAdd %{{.*}}, %{{.*}}: i32
46  %0 = arith.addi %lhs, %rhs: index
47  // CHECK: spirv.ISub %{{.*}}, %{{.*}}: i32
48  %1 = arith.subi %lhs, %rhs: index
49  // CHECK: spirv.IMul %{{.*}}, %{{.*}}: i32
50  %2 = arith.muli %lhs, %rhs: index
51  // CHECK: spirv.SDiv %{{.*}}, %{{.*}}: i32
52  %3 = arith.divsi %lhs, %rhs: index
53  // CHECK: spirv.UDiv %{{.*}}, %{{.*}}: i32
54  %4 = arith.divui %lhs, %rhs: index
55  // CHECK: spirv.UMod %{{.*}}, %{{.*}}: i32
56  %5 = arith.remui %lhs, %rhs: index
57  return
58}
59
60// CHECK-LABEL: @index_scalar_srem
61// CHECK-SAME: (%[[A:.+]]: index, %[[B:.+]]: index)
62func.func @index_scalar_srem(%lhs: index, %rhs: index) {
63  // CHECK-DAG: %[[LHS:.+]] = builtin.unrealized_conversion_cast %[[A]] : index to i32
64  // CHECK-DAG: %[[RHS:.+]] = builtin.unrealized_conversion_cast %[[B]] : index to i32
65  // CHECK: %[[LABS:.+]] = spirv.GL.SAbs %[[LHS]] : i32
66  // CHECK: %[[RABS:.+]] = spirv.GL.SAbs %[[RHS]] : i32
67  // CHECK:  %[[ABS:.+]] = spirv.UMod %[[LABS]], %[[RABS]] : i32
68  // CHECK:  %[[POS:.+]] = spirv.IEqual %[[LHS]], %[[LABS]] : i32
69  // CHECK:  %[[NEG:.+]] = spirv.SNegate %[[ABS]] : i32
70  // CHECK:      %{{.+}} = spirv.Select %[[POS]], %[[ABS]], %[[NEG]] : i1, i32
71  %0 = arith.remsi %lhs, %rhs: index
72  return
73}
74
75// Check integer add-with-carry conversions.
76// CHECK-LABEL: @int32_scalar_addui_extended
77// CHECK-SAME: (%[[LHS:.+]]: i32, %[[RHS:.+]]: i32)
78func.func @int32_scalar_addui_extended(%lhs: i32, %rhs: i32) -> (i32, i1) {
79  // CHECK-NEXT: %[[IAC:.+]] = spirv.IAddCarry %[[LHS]], %[[RHS]] : !spirv.struct<(i32, i32)>
80  // CHECK-DAG:  %[[SUM:.+]] = spirv.CompositeExtract %[[IAC]][0 : i32] : !spirv.struct<(i32, i32)>
81  // CHECK-DAG:  %[[C0:.+]]  = spirv.CompositeExtract %[[IAC]][1 : i32] : !spirv.struct<(i32, i32)>
82  // CHECK-DAG:  %[[ONE:.+]] = spirv.Constant 1 : i32
83  // CHECK-NEXT: %[[C1:.+]]  = spirv.IEqual %[[C0]], %[[ONE]] : i32
84  // CHECK-NEXT: return %[[SUM]], %[[C1]] : i32, i1
85  %sum, %overflow = arith.addui_extended %lhs, %rhs: i32, i1
86  return %sum, %overflow : i32, i1
87}
88
89// CHECK-LABEL: @int32_vector_addui_extended
90// CHECK-SAME: (%[[LHS:.+]]: vector<4xi32>, %[[RHS:.+]]: vector<4xi32>)
91func.func @int32_vector_addui_extended(%lhs: vector<4xi32>, %rhs: vector<4xi32>) -> (vector<4xi32>, vector<4xi1>) {
92  // CHECK-NEXT: %[[IAC:.+]] = spirv.IAddCarry %[[LHS]], %[[RHS]] : !spirv.struct<(vector<4xi32>, vector<4xi32>)>
93  // CHECK-DAG:  %[[SUM:.+]] = spirv.CompositeExtract %[[IAC]][0 : i32] : !spirv.struct<(vector<4xi32>, vector<4xi32>)>
94  // CHECK-DAG:  %[[C0:.+]]  = spirv.CompositeExtract %[[IAC]][1 : i32] : !spirv.struct<(vector<4xi32>, vector<4xi32>)>
95  // CHECK-DAG:  %[[ONE:.+]] = spirv.Constant dense<1> : vector<4xi32>
96  // CHECK-NEXT: %[[C1:.+]]  = spirv.IEqual %[[C0]], %[[ONE]] : vector<4xi32>
97  // CHECK-NEXT: return %[[SUM]], %[[C1]] : vector<4xi32>, vector<4xi1>
98  %sum, %overflow = arith.addui_extended %lhs, %rhs: vector<4xi32>, vector<4xi1>
99  return %sum, %overflow : vector<4xi32>, vector<4xi1>
100}
101
102// Check extended signed integer multiplication conversions.
103// CHECK-LABEL: @int32_scalar_mulsi_extended
104// CHECK-SAME: (%[[LHS:.+]]: i32, %[[RHS:.+]]: i32)
105func.func @int32_scalar_mulsi_extended(%lhs: i32, %rhs: i32) -> (i32, i32) {
106  // CHECK-NEXT: %[[MUL:.+]]   = spirv.SMulExtended %[[LHS]], %[[RHS]] : !spirv.struct<(i32, i32)>
107  // CHECK-DAG:  %[[LOW:.+]]   = spirv.CompositeExtract %[[MUL]][0 : i32] : !spirv.struct<(i32, i32)>
108  // CHECK-DAG:  %[[HIGH:.+]]  = spirv.CompositeExtract %[[MUL]][1 : i32] : !spirv.struct<(i32, i32)>
109  // CHECK-NEXT: return %[[LOW]], %[[HIGH]] : i32, i32
110  %low, %high = arith.mulsi_extended %lhs, %rhs: i32
111  return %low, %high : i32, i32
112}
113
114// CHECK-LABEL: @int32_vector_mulsi_extended
115// CHECK-SAME: (%[[LHS:.+]]: vector<4xi32>, %[[RHS:.+]]: vector<4xi32>)
116func.func @int32_vector_mulsi_extended(%lhs: vector<4xi32>, %rhs: vector<4xi32>) -> (vector<4xi32>, vector<4xi32>) {
117  // CHECK-NEXT: %[[MUL:.+]]   = spirv.SMulExtended %[[LHS]], %[[RHS]] : !spirv.struct<(vector<4xi32>, vector<4xi32>)>
118  // CHECK-DAG:  %[[LOW:.+]]   = spirv.CompositeExtract %[[MUL]][0 : i32] : !spirv.struct<(vector<4xi32>, vector<4xi32>)>
119  // CHECK-DAG:  %[[HIGH:.+]]  = spirv.CompositeExtract %[[MUL]][1 : i32] : !spirv.struct<(vector<4xi32>, vector<4xi32>)>
120  // CHECK-NEXT: return %[[LOW]], %[[HIGH]] : vector<4xi32>, vector<4xi32>
121  %low, %high = arith.mulsi_extended %lhs, %rhs: vector<4xi32>
122  return %low, %high : vector<4xi32>, vector<4xi32>
123}
124
125// Check extended unsigned integer multiplication conversions.
126// CHECK-LABEL: @int32_scalar_mului_extended
127// CHECK-SAME: (%[[LHS:.+]]: i32, %[[RHS:.+]]: i32)
128func.func @int32_scalar_mului_extended(%lhs: i32, %rhs: i32) -> (i32, i32) {
129  // CHECK-NEXT: %[[MUL:.+]]   = spirv.UMulExtended %[[LHS]], %[[RHS]] : !spirv.struct<(i32, i32)>
130  // CHECK-DAG:  %[[LOW:.+]]   = spirv.CompositeExtract %[[MUL]][0 : i32] : !spirv.struct<(i32, i32)>
131  // CHECK-DAG:  %[[HIGH:.+]]  = spirv.CompositeExtract %[[MUL]][1 : i32] : !spirv.struct<(i32, i32)>
132  // CHECK-NEXT: return %[[LOW]], %[[HIGH]] : i32, i32
133  %low, %high = arith.mului_extended %lhs, %rhs: i32
134  return %low, %high : i32, i32
135}
136
137// CHECK-LABEL: @int32_vector_mului_extended
138// CHECK-SAME: (%[[LHS:.+]]: vector<4xi32>, %[[RHS:.+]]: vector<4xi32>)
139func.func @int32_vector_mului_extended(%lhs: vector<4xi32>, %rhs: vector<4xi32>) -> (vector<4xi32>, vector<4xi32>) {
140  // CHECK-NEXT: %[[MUL:.+]]   = spirv.UMulExtended %[[LHS]], %[[RHS]] : !spirv.struct<(vector<4xi32>, vector<4xi32>)>
141  // CHECK-DAG:  %[[LOW:.+]]   = spirv.CompositeExtract %[[MUL]][0 : i32] : !spirv.struct<(vector<4xi32>, vector<4xi32>)>
142  // CHECK-DAG:  %[[HIGH:.+]]  = spirv.CompositeExtract %[[MUL]][1 : i32] : !spirv.struct<(vector<4xi32>, vector<4xi32>)>
143  // CHECK-NEXT: return %[[LOW]], %[[HIGH]] : vector<4xi32>, vector<4xi32>
144  %low, %high = arith.mului_extended %lhs, %rhs: vector<4xi32>
145  return %low, %high : vector<4xi32>, vector<4xi32>
146}
147
148// Check float unary operation conversions.
149// CHECK-LABEL: @float32_unary_scalar
150func.func @float32_unary_scalar(%arg0: f32) {
151  // CHECK: spirv.FNegate %{{.*}}: f32
152  %0 = arith.negf %arg0 : f32
153  return
154}
155
156// Check float binary operation conversions.
157// CHECK-LABEL: @float32_binary_scalar
158func.func @float32_binary_scalar(%lhs: f32, %rhs: f32) {
159  // CHECK: spirv.FAdd %{{.*}}, %{{.*}}: f32
160  %0 = arith.addf %lhs, %rhs: f32
161  // CHECK: spirv.FSub %{{.*}}, %{{.*}}: f32
162  %1 = arith.subf %lhs, %rhs: f32
163  // CHECK: spirv.FMul %{{.*}}, %{{.*}}: f32
164  %2 = arith.mulf %lhs, %rhs: f32
165  // CHECK: spirv.FDiv %{{.*}}, %{{.*}}: f32
166  %3 = arith.divf %lhs, %rhs: f32
167  // CHECK: spirv.FRem %{{.*}}, %{{.*}}: f32
168  %4 = arith.remf %lhs, %rhs: f32
169  return
170}
171
172// Check int vector types.
173// CHECK-LABEL: @int_vector234
174func.func @int_vector234(%arg0: vector<2xi8>, %arg1: vector<4xi64>) {
175  // CHECK: spirv.SDiv %{{.*}}, %{{.*}}: vector<2xi8>
176  %0 = arith.divsi %arg0, %arg0: vector<2xi8>
177  // CHECK: spirv.UDiv %{{.*}}, %{{.*}}: vector<4xi64>
178  %1 = arith.divui %arg1, %arg1: vector<4xi64>
179  return
180}
181
182// CHECK-LABEL: @index_vector
183func.func @index_vector(%arg0: vector<4xindex>) {
184  // CHECK: spirv.UMod %{{.*}}, %{{.*}}: vector<4xi32>
185  %0 = arith.remui %arg0, %arg0: vector<4xindex>
186  return
187}
188
189// CHECK-LABEL: @vector_srem
190// CHECK-SAME: (%[[LHS:.+]]: vector<3xi16>, %[[RHS:.+]]: vector<3xi16>)
191func.func @vector_srem(%arg0: vector<3xi16>, %arg1: vector<3xi16>) {
192  // CHECK: %[[LABS:.+]] = spirv.GL.SAbs %[[LHS]] : vector<3xi16>
193  // CHECK: %[[RABS:.+]] = spirv.GL.SAbs %[[RHS]] : vector<3xi16>
194  // CHECK:  %[[ABS:.+]] = spirv.UMod %[[LABS]], %[[RABS]] : vector<3xi16>
195  // CHECK:  %[[POS:.+]] = spirv.IEqual %[[LHS]], %[[LABS]] : vector<3xi16>
196  // CHECK:  %[[NEG:.+]] = spirv.SNegate %[[ABS]] : vector<3xi16>
197  // CHECK:      %{{.+}} = spirv.Select %[[POS]], %[[ABS]], %[[NEG]] : vector<3xi1>, vector<3xi16>
198  %0 = arith.remsi %arg0, %arg1: vector<3xi16>
199  return
200}
201
202// Check float vector types.
203// CHECK-LABEL: @float_vector234
204func.func @float_vector234(%arg0: vector<2xf16>, %arg1: vector<3xf64>) {
205  // CHECK: spirv.FAdd %{{.*}}, %{{.*}}: vector<2xf16>
206  %0 = arith.addf %arg0, %arg0: vector<2xf16>
207  // CHECK: spirv.FMul %{{.*}}, %{{.*}}: vector<3xf64>
208  %1 = arith.mulf %arg1, %arg1: vector<3xf64>
209  return
210}
211
212// CHECK-LABEL: @one_elem_vector
213func.func @one_elem_vector(%arg0: vector<1xi32>) {
214  // CHECK: spirv.IAdd %{{.+}}, %{{.+}}: i32
215  %0 = arith.addi %arg0, %arg0: vector<1xi32>
216  return
217}
218
219} // end module
220
221// -----
222
223//===----------------------------------------------------------------------===//
224// Bit ops
225//===----------------------------------------------------------------------===//
226
227module attributes {
228  spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [], []>, #spirv.resource_limits<>>
229} {
230
231// CHECK-LABEL: @bitwise_scalar
232func.func @bitwise_scalar(%arg0 : i32, %arg1 : i32) {
233  // CHECK: spirv.BitwiseAnd
234  %0 = arith.andi %arg0, %arg1 : i32
235  // CHECK: spirv.BitwiseOr
236  %1 = arith.ori %arg0, %arg1 : i32
237  // CHECK: spirv.BitwiseXor
238  %2 = arith.xori %arg0, %arg1 : i32
239  return
240}
241
242// CHECK-LABEL: @bitwise_vector
243func.func @bitwise_vector(%arg0 : vector<4xi32>, %arg1 : vector<4xi32>) {
244  // CHECK: spirv.BitwiseAnd
245  %0 = arith.andi %arg0, %arg1 : vector<4xi32>
246  // CHECK: spirv.BitwiseOr
247  %1 = arith.ori %arg0, %arg1 : vector<4xi32>
248  // CHECK: spirv.BitwiseXor
249  %2 = arith.xori %arg0, %arg1 : vector<4xi32>
250  return
251}
252
253// CHECK-LABEL: @logical_scalar
254func.func @logical_scalar(%arg0 : i1, %arg1 : i1) {
255  // CHECK: spirv.LogicalAnd
256  %0 = arith.andi %arg0, %arg1 : i1
257  // CHECK: spirv.LogicalOr
258  %1 = arith.ori %arg0, %arg1 : i1
259  // CHECK: spirv.LogicalNotEqual
260  %2 = arith.xori %arg0, %arg1 : i1
261  return
262}
263
264// CHECK-LABEL: @logical_vector
265func.func @logical_vector(%arg0 : vector<4xi1>, %arg1 : vector<4xi1>) {
266  // CHECK: spirv.LogicalAnd
267  %0 = arith.andi %arg0, %arg1 : vector<4xi1>
268  // CHECK: spirv.LogicalOr
269  %1 = arith.ori %arg0, %arg1 : vector<4xi1>
270  // CHECK: spirv.LogicalNotEqual
271  %2 = arith.xori %arg0, %arg1 : vector<4xi1>
272  return
273}
274
275// CHECK-LABEL: @shift_scalar
276func.func @shift_scalar(%arg0 : i32, %arg1 : i32) {
277  // CHECK: spirv.ShiftLeftLogical
278  %0 = arith.shli %arg0, %arg1 : i32
279  // CHECK: spirv.ShiftRightArithmetic
280  %1 = arith.shrsi %arg0, %arg1 : i32
281  // CHECK: spirv.ShiftRightLogical
282  %2 = arith.shrui %arg0, %arg1 : i32
283  return
284}
285
286// CHECK-LABEL: @shift_vector
287func.func @shift_vector(%arg0 : vector<4xi32>, %arg1 : vector<4xi32>) {
288  // CHECK: spirv.ShiftLeftLogical
289  %0 = arith.shli %arg0, %arg1 : vector<4xi32>
290  // CHECK: spirv.ShiftRightArithmetic
291  %1 = arith.shrsi %arg0, %arg1 : vector<4xi32>
292  // CHECK: spirv.ShiftRightLogical
293  %2 = arith.shrui %arg0, %arg1 : vector<4xi32>
294  return
295}
296
297} // end module
298
299// -----
300
301//===----------------------------------------------------------------------===//
302// arith.cmpf
303//===----------------------------------------------------------------------===//
304
305module attributes {
306  spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [], []>, #spirv.resource_limits<>>
307} {
308
309// CHECK-LABEL: @cmpf
310func.func @cmpf(%arg0 : f32, %arg1 : f32) {
311  // CHECK: spirv.FOrdEqual
312  %1 = arith.cmpf oeq, %arg0, %arg1 : f32
313  // CHECK: spirv.FOrdGreaterThan
314  %2 = arith.cmpf ogt, %arg0, %arg1 : f32
315  // CHECK: spirv.FOrdGreaterThanEqual
316  %3 = arith.cmpf oge, %arg0, %arg1 : f32
317  // CHECK: spirv.FOrdLessThan
318  %4 = arith.cmpf olt, %arg0, %arg1 : f32
319  // CHECK: spirv.FOrdLessThanEqual
320  %5 = arith.cmpf ole, %arg0, %arg1 : f32
321  // CHECK: spirv.FOrdNotEqual
322  %6 = arith.cmpf one, %arg0, %arg1 : f32
323  // CHECK: spirv.FUnordEqual
324  %7 = arith.cmpf ueq, %arg0, %arg1 : f32
325  // CHECK: spirv.FUnordGreaterThan
326  %8 = arith.cmpf ugt, %arg0, %arg1 : f32
327  // CHECK: spirv.FUnordGreaterThanEqual
328  %9 = arith.cmpf uge, %arg0, %arg1 : f32
329  // CHECK: spirv.FUnordLessThan
330  %10 = arith.cmpf ult, %arg0, %arg1 : f32
331  // CHECK: FUnordLessThanEqual
332  %11 = arith.cmpf ule, %arg0, %arg1 : f32
333  // CHECK: spirv.FUnordNotEqual
334  %12 = arith.cmpf une, %arg0, %arg1 : f32
335  return
336}
337
338// CHECK-LABEL: @vec1cmpf
339func.func @vec1cmpf(%arg0 : vector<1xf32>, %arg1 : vector<1xf32>) {
340  // CHECK: spirv.FOrdGreaterThan
341  %0 = arith.cmpf ogt, %arg0, %arg1 : vector<1xf32>
342  // CHECK: spirv.FUnordLessThan
343  %1 = arith.cmpf ult, %arg0, %arg1 : vector<1xf32>
344  return
345}
346
347} // end module
348
349// -----
350
351// With Kernel capability, we can convert NaN check to spirv.Ordered/spirv.Unordered.
352module attributes {
353  spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [Kernel], []>, #spirv.resource_limits<>>
354} {
355
356// CHECK-LABEL: @cmpf
357func.func @cmpf(%arg0 : f32, %arg1 : f32) {
358  // CHECK: spirv.Ordered
359  %0 = arith.cmpf ord, %arg0, %arg1 : f32
360  // CHECK: spirv.Unordered
361  %1 = arith.cmpf uno, %arg0, %arg1 : f32
362  return
363}
364
365} // end module
366
367// -----
368
369// Without Kernel capability, we need to convert NaN check to spirv.IsNan.
370module attributes {
371  spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [], []>, #spirv.resource_limits<>>
372} {
373
374// CHECK-LABEL: @cmpf
375// CHECK-SAME: %[[LHS:.+]]: f32, %[[RHS:.+]]: f32
376func.func @cmpf(%arg0 : f32, %arg1 : f32) {
377  // CHECK:      %[[LHS_NAN:.+]] = spirv.IsNan %[[LHS]] : f32
378  // CHECK-NEXT: %[[RHS_NAN:.+]] = spirv.IsNan %[[RHS]] : f32
379  // CHECK-NEXT: %[[OR:.+]] = spirv.LogicalOr %[[LHS_NAN]], %[[RHS_NAN]] : i1
380  // CHECK-NEXT: %{{.+}} = spirv.LogicalNot %[[OR]] : i1
381  %0 = arith.cmpf ord, %arg0, %arg1 : f32
382
383  // CHECK-NEXT: %[[LHS_NAN:.+]] = spirv.IsNan %[[LHS]] : f32
384  // CHECK-NEXT: %[[RHS_NAN:.+]] = spirv.IsNan %[[RHS]] : f32
385  // CHECK-NEXT: %{{.+}} = spirv.LogicalOr %[[LHS_NAN]], %[[RHS_NAN]] : i1
386  %1 = arith.cmpf uno, %arg0, %arg1 : f32
387  return
388}
389
390} // end module
391
392// -----
393
394//===----------------------------------------------------------------------===//
395// arith.cmpi
396//===----------------------------------------------------------------------===//
397
398module attributes {
399  spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [], []>, #spirv.resource_limits<>>
400} {
401
402// CHECK-LABEL: @cmpi
403func.func @cmpi(%arg0 : i32, %arg1 : i32) {
404  // CHECK: spirv.IEqual
405  %0 = arith.cmpi eq, %arg0, %arg1 : i32
406  // CHECK: spirv.INotEqual
407  %1 = arith.cmpi ne, %arg0, %arg1 : i32
408  // CHECK: spirv.SLessThan
409  %2 = arith.cmpi slt, %arg0, %arg1 : i32
410  // CHECK: spirv.SLessThanEqual
411  %3 = arith.cmpi sle, %arg0, %arg1 : i32
412  // CHECK: spirv.SGreaterThan
413  %4 = arith.cmpi sgt, %arg0, %arg1 : i32
414  // CHECK: spirv.SGreaterThanEqual
415  %5 = arith.cmpi sge, %arg0, %arg1 : i32
416  // CHECK: spirv.ULessThan
417  %6 = arith.cmpi ult, %arg0, %arg1 : i32
418  // CHECK: spirv.ULessThanEqual
419  %7 = arith.cmpi ule, %arg0, %arg1 : i32
420  // CHECK: spirv.UGreaterThan
421  %8 = arith.cmpi ugt, %arg0, %arg1 : i32
422  // CHECK: spirv.UGreaterThanEqual
423  %9 = arith.cmpi uge, %arg0, %arg1 : i32
424  return
425}
426
427// CHECK-LABEL: @indexcmpi
428func.func @indexcmpi(%arg0 : index, %arg1 : index) {
429  // CHECK: spirv.IEqual
430  %0 = arith.cmpi eq, %arg0, %arg1 : index
431  // CHECK: spirv.INotEqual
432  %1 = arith.cmpi ne, %arg0, %arg1 : index
433  // CHECK: spirv.SLessThan
434  %2 = arith.cmpi slt, %arg0, %arg1 : index
435  // CHECK: spirv.SLessThanEqual
436  %3 = arith.cmpi sle, %arg0, %arg1 : index
437  // CHECK: spirv.SGreaterThan
438  %4 = arith.cmpi sgt, %arg0, %arg1 : index
439  // CHECK: spirv.SGreaterThanEqual
440  %5 = arith.cmpi sge, %arg0, %arg1 : index
441  // CHECK: spirv.ULessThan
442  %6 = arith.cmpi ult, %arg0, %arg1 : index
443  // CHECK: spirv.ULessThanEqual
444  %7 = arith.cmpi ule, %arg0, %arg1 : index
445  // CHECK: spirv.UGreaterThan
446  %8 = arith.cmpi ugt, %arg0, %arg1 : index
447  // CHECK: spirv.UGreaterThanEqual
448  %9 = arith.cmpi uge, %arg0, %arg1 : index
449  return
450}
451
452// CHECK-LABEL: @vec1cmpi
453func.func @vec1cmpi(%arg0 : vector<1xi32>, %arg1 : vector<1xi32>) {
454  // CHECK: spirv.ULessThan
455  %0 = arith.cmpi ult, %arg0, %arg1 : vector<1xi32>
456  // CHECK: spirv.SGreaterThan
457  %1 = arith.cmpi sgt, %arg0, %arg1 : vector<1xi32>
458  return
459}
460
461// CHECK-LABEL: @boolcmpi_equality
462func.func @boolcmpi_equality(%arg0 : i1, %arg1 : i1) {
463  // CHECK: spirv.LogicalEqual
464  %0 = arith.cmpi eq, %arg0, %arg1 : i1
465  // CHECK: spirv.LogicalNotEqual
466  %1 = arith.cmpi ne, %arg0, %arg1 : i1
467  return
468}
469
470// CHECK-LABEL: @boolcmpi_unsigned
471func.func @boolcmpi_unsigned(%arg0 : i1, %arg1 : i1) {
472  // CHECK-COUNT-2: spirv.Select
473  // CHECK: spirv.UGreaterThanEqual
474  %0 = arith.cmpi uge, %arg0, %arg1 : i1
475  // CHECK-COUNT-2: spirv.Select
476  // CHECK: spirv.ULessThan
477  %1 = arith.cmpi ult, %arg0, %arg1 : i1
478  return
479}
480
481// CHECK-LABEL: @vec1boolcmpi_equality
482func.func @vec1boolcmpi_equality(%arg0 : vector<1xi1>, %arg1 : vector<1xi1>) {
483  // CHECK: spirv.LogicalEqual
484  %0 = arith.cmpi eq, %arg0, %arg1 : vector<1xi1>
485  // CHECK: spirv.LogicalNotEqual
486  %1 = arith.cmpi ne, %arg0, %arg1 : vector<1xi1>
487  return
488}
489
490// CHECK-LABEL: @vec1boolcmpi_unsigned
491func.func @vec1boolcmpi_unsigned(%arg0 : vector<1xi1>, %arg1 : vector<1xi1>) {
492  // CHECK-COUNT-2: spirv.Select
493  // CHECK: spirv.UGreaterThanEqual
494  %0 = arith.cmpi uge, %arg0, %arg1 : vector<1xi1>
495  // CHECK-COUNT-2: spirv.Select
496  // CHECK: spirv.ULessThan
497  %1 = arith.cmpi ult, %arg0, %arg1 : vector<1xi1>
498  return
499}
500
501// CHECK-LABEL: @vecboolcmpi_equality
502func.func @vecboolcmpi_equality(%arg0 : vector<4xi1>, %arg1 : vector<4xi1>) {
503  // CHECK: spirv.LogicalEqual
504  %0 = arith.cmpi eq, %arg0, %arg1 : vector<4xi1>
505  // CHECK: spirv.LogicalNotEqual
506  %1 = arith.cmpi ne, %arg0, %arg1 : vector<4xi1>
507  return
508}
509
510// CHECK-LABEL: @vecboolcmpi_unsigned
511func.func @vecboolcmpi_unsigned(%arg0 : vector<3xi1>, %arg1 : vector<3xi1>) {
512  // CHECK-COUNT-2: spirv.Select
513  // CHECK: spirv.UGreaterThanEqual
514  %0 = arith.cmpi uge, %arg0, %arg1 : vector<3xi1>
515  // CHECK-COUNT-2: spirv.Select
516  // CHECK: spirv.ULessThan
517  %1 = arith.cmpi ult, %arg0, %arg1 : vector<3xi1>
518  return
519}
520
521
522} // end module
523
524// -----
525
526//===----------------------------------------------------------------------===//
527// arith.constant
528//===----------------------------------------------------------------------===//
529
530module attributes {
531  spirv.target_env = #spirv.target_env<
532    #spirv.vce<v1.0, [Int8, Int16, Int64, Float16, Float64], []>, #spirv.resource_limits<>>
533} {
534
535// CHECK-LABEL: @constant
536func.func @constant() {
537  // CHECK: spirv.Constant true
538  %0 = arith.constant true
539  // CHECK: spirv.Constant 42 : i32
540  %1 = arith.constant 42 : i32
541  // CHECK: spirv.Constant 5.000000e-01 : f32
542  %2 = arith.constant 0.5 : f32
543  // CHECK: spirv.Constant dense<[2, 3]> : vector<2xi32>
544  %3 = arith.constant dense<[2, 3]> : vector<2xi32>
545  // CHECK: spirv.Constant 1 : i32
546  %4 = arith.constant 1 : index
547  // CHECK: spirv.Constant dense<1> : tensor<6xi32> : !spirv.array<6 x i32>
548  %5 = arith.constant dense<1> : tensor<2x3xi32>
549  // CHECK: spirv.Constant dense<1.000000e+00> : tensor<6xf32> : !spirv.array<6 x f32>
550  %6 = arith.constant dense<1.0> : tensor<2x3xf32>
551  // CHECK: spirv.Constant dense<{{\[}}1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf32> : !spirv.array<6 x f32>
552  %7 = arith.constant dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]> : tensor<2x3xf32>
553  // CHECK: spirv.Constant dense<{{\[}}1, 2, 3, 4, 5, 6]> : tensor<6xi32> : !spirv.array<6 x i32>
554  %8 = arith.constant dense<[[1, 2, 3], [4, 5, 6]]> : tensor<2x3xi32>
555  // CHECK: spirv.Constant dense<{{\[}}1, 2, 3, 4, 5, 6]> : tensor<6xi32> : !spirv.array<6 x i32>
556  %9 = arith.constant dense<[[1, 2], [3, 4], [5, 6]]> : tensor<3x2xi32>
557  // CHECK: spirv.Constant dense<{{\[}}1, 2, 3, 4, 5, 6]> : tensor<6xi32> : !spirv.array<6 x i32>
558  %10 = arith.constant dense<[1, 2, 3, 4, 5, 6]> : tensor<6xi32>
559  return
560}
561
562// CHECK-LABEL: @constant_16bit
563func.func @constant_16bit() {
564  // CHECK: spirv.Constant 4 : i16
565  %0 = arith.constant 4 : i16
566  // CHECK: spirv.Constant 5.000000e+00 : f16
567  %1 = arith.constant 5.0 : f16
568  // CHECK: spirv.Constant dense<[2, 3]> : vector<2xi16>
569  %2 = arith.constant dense<[2, 3]> : vector<2xi16>
570  // CHECK: spirv.Constant dense<4.000000e+00> : tensor<5xf16> : !spirv.array<5 x f16>
571  %3 = arith.constant dense<4.0> : tensor<5xf16>
572  return
573}
574
575// CHECK-LABEL: @constant_64bit
576func.func @constant_64bit() {
577  // CHECK: spirv.Constant 4 : i64
578  %0 = arith.constant 4 : i64
579  // CHECK: spirv.Constant 5.000000e+00 : f64
580  %1 = arith.constant 5.0 : f64
581  // CHECK: spirv.Constant dense<[2, 3]> : vector<2xi64>
582  %2 = arith.constant dense<[2, 3]> : vector<2xi64>
583  // CHECK: spirv.Constant dense<4.000000e+00> : tensor<5xf64> : !spirv.array<5 x f64>
584  %3 = arith.constant dense<4.0> : tensor<5xf64>
585  return
586}
587
588// CHECK-LABEL: @constant_size1
589func.func @constant_size1() {
590  // CHECK: spirv.Constant true
591  %0 = arith.constant dense<true> : tensor<1xi1>
592  // CHECK: spirv.Constant 4 : i64
593  %1 = arith.constant dense<4> : vector<1xi64>
594  // CHECK: spirv.Constant 5.000000e+00 : f64
595  %2 = arith.constant dense<5.0> : tensor<1xf64>
596  return
597}
598
599} // end module
600
601// -----
602
603// Check that constants are widened to 32-bit when no special capability.
604module attributes {
605  spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [], []>, #spirv.resource_limits<>>
606} {
607
608// CHECK-LABEL: @constant_16bit
609func.func @constant_16bit() {
610  // CHECK: spirv.Constant 4 : i32
611  %0 = arith.constant 4 : i16
612  // CHECK: spirv.Constant 5.000000e+00 : f32
613  %1 = arith.constant 5.0 : f16
614  // CHECK: spirv.Constant dense<[2, 3]> : vector<2xi32>
615  %2 = arith.constant dense<[2, 3]> : vector<2xi16>
616  // CHECK: spirv.Constant dense<4.000000e+00> : tensor<5xf32> : !spirv.array<5 x f32>
617  %3 = arith.constant dense<4.0> : tensor<5xf16>
618  // CHECK: spirv.Constant dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00]> : tensor<4xf32> : !spirv.array<4 x f32>
619  %4 = arith.constant dense<[[1.0, 2.0], [3.0, 4.0]]> : tensor<2x2xf16>
620  return
621}
622
623// CHECK-LABEL: @constant_size1
624func.func @constant_size1() {
625  // CHECK: spirv.Constant 4 : i32
626  %0 = arith.constant dense<4> : vector<1xi16>
627  // CHECK: spirv.Constant 5.000000e+00 : f32
628  %1 = arith.constant dense<5.0> : tensor<1xf16>
629  return
630}
631
632// CHECK-LABEL: @corner_cases
633func.func @corner_cases() {
634 // CHECK: %{{.*}} = spirv.Constant -1 : i32
635  %5 = arith.constant -1 : i16
636  // CHECK: %{{.*}} = spirv.Constant -2 : i32
637  %6 = arith.constant -2 : i16
638  // CHECK: %{{.*}} = spirv.Constant -1 : i32
639  %7 = arith.constant -1 : index
640  // CHECK: %{{.*}} = spirv.Constant -2 : i32
641  %8 = arith.constant -2 : index
642
643  // CHECK: spirv.Constant false
644  %9 = arith.constant false
645  // CHECK: spirv.Constant true
646  %10 = arith.constant true
647
648  return
649}
650
651} // end module
652
653// -----
654
655//===----------------------------------------------------------------------===//
656// Cast ops
657//===----------------------------------------------------------------------===//
658
659module attributes {
660  spirv.target_env = #spirv.target_env<
661    #spirv.vce<v1.0, [Int8, Int16, Int64, Float16, Float64], []>, #spirv.resource_limits<>>
662} {
663
664// CHECK-LABEL: index_cast1
665func.func @index_cast1(%arg0: i16) {
666  // CHECK: spirv.SConvert %{{.+}} : i16 to i32
667  %0 = arith.index_cast %arg0 : i16 to index
668  return
669}
670
671// CHECK-LABEL: index_cast2
672func.func @index_cast2(%arg0: index) {
673  // CHECK: spirv.SConvert %{{.+}} : i32 to i16
674  %0 = arith.index_cast %arg0 : index to i16
675  return
676}
677
678// CHECK-LABEL: index_cast3
679func.func @index_cast3(%arg0: i32) {
680  // CHECK-NOT: spirv.SConvert
681  %0 = arith.index_cast %arg0 : i32 to index
682  return
683}
684
685// CHECK-LABEL: index_cast4
686func.func @index_cast4(%arg0: index) {
687  // CHECK-NOT: spirv.UConvert
688  %0 = arith.index_cast %arg0 : index to i32
689  return
690}
691
692// CHECK-LABEL: index_castui1
693func.func @index_castui1(%arg0: i16) {
694  // CHECK: spirv.UConvert %{{.+}} : i16 to i32
695  %0 = arith.index_castui %arg0 : i16 to index
696  return
697}
698
699// CHECK-LABEL: index_castui2
700func.func @index_castui2(%arg0: index) {
701  // CHECK: spirv.UConvert %{{.+}} : i32 to i16
702  %0 = arith.index_castui %arg0 : index to i16
703  return
704}
705
706// CHECK-LABEL: index_castui3
707func.func @index_castui3(%arg0: i32) {
708  // CHECK-NOT: spirv.UConvert
709  %0 = arith.index_castui %arg0 : i32 to index
710  return
711}
712
713// CHECK-LABEL: index_castui4
714func.func @index_castui4(%arg0: index) {
715  // CHECK-NOT: spirv.UConvert
716  %0 = arith.index_cast %arg0 : index to i32
717  return
718}
719
720// CHECK-LABEL: @bit_cast
721func.func @bit_cast(%arg0: vector<2xf32>, %arg1: i64) {
722  // CHECK: spirv.Bitcast %{{.+}} : vector<2xf32> to vector<2xi32>
723  %0 = arith.bitcast %arg0 : vector<2xf32> to vector<2xi32>
724  // CHECK: spirv.Bitcast %{{.+}} : i64 to f64
725  %1 = arith.bitcast %arg1 : i64 to f64
726  return
727}
728
729// CHECK-LABEL: @fpext1
730func.func @fpext1(%arg0: f16) -> f64 {
731  // CHECK: spirv.FConvert %{{.*}} : f16 to f64
732  %0 = arith.extf %arg0 : f16 to f64
733  return %0 : f64
734}
735
736// CHECK-LABEL: @fpext2
737func.func @fpext2(%arg0 : f32) -> f64 {
738  // CHECK: spirv.FConvert %{{.*}} : f32 to f64
739  %0 = arith.extf %arg0 : f32 to f64
740  return %0 : f64
741}
742
743// CHECK-LABEL: @fptrunc1
744func.func @fptrunc1(%arg0 : f64) -> f16 {
745  // CHECK: spirv.FConvert %{{.*}} : f64 to f16
746  %0 = arith.truncf %arg0 : f64 to f16
747  return %0 : f16
748}
749
750// CHECK-LABEL: @fptrunc2
751func.func @fptrunc2(%arg0: f32) -> f16 {
752  // CHECK: spirv.FConvert %{{.*}} : f32 to f16
753  %0 = arith.truncf %arg0 : f32 to f16
754  return %0 : f16
755}
756
757
758// CHECK-LABEL: @experimental_constrained_fptrunc
759func.func @experimental_constrained_fptrunc(%arg0 : f64) {
760  // CHECK: spirv.FConvert %arg0 {fp_rounding_mode = #spirv.fp_rounding_mode<RTE>} : f64 to f32
761  %0 = arith.truncf %arg0 to_nearest_even : f64 to f32
762  // CHECK: spirv.FConvert %arg0 {fp_rounding_mode = #spirv.fp_rounding_mode<RTN>} : f64 to f32
763  %1 = arith.truncf %arg0 downward : f64 to f32
764  // CHECK: spirv.FConvert %arg0 {fp_rounding_mode = #spirv.fp_rounding_mode<RTP>} : f64 to f32
765  %2 = arith.truncf %arg0 upward : f64 to f32
766  // CHECK: spirv.FConvert %arg0 {fp_rounding_mode = #spirv.fp_rounding_mode<RTZ>} : f64 to f32
767  %3 = arith.truncf %arg0 toward_zero : f64 to f32
768  return
769}
770
771
772// CHECK-LABEL: @sitofp1
773func.func @sitofp1(%arg0 : i32) -> f32 {
774  // CHECK: spirv.ConvertSToF %{{.*}} : i32 to f32
775  %0 = arith.sitofp %arg0 : i32 to f32
776  return %0 : f32
777}
778
779// CHECK-LABEL: @sitofp2
780func.func @sitofp2(%arg0 : i64) -> f64 {
781  // CHECK: spirv.ConvertSToF %{{.*}} : i64 to f64
782  %0 = arith.sitofp %arg0 : i64 to f64
783  return %0 : f64
784}
785
786// CHECK-LABEL: @uitofp_i16_f32
787func.func @uitofp_i16_f32(%arg0: i16) -> f32 {
788  // CHECK: spirv.ConvertUToF %{{.*}} : i16 to f32
789  %0 = arith.uitofp %arg0 : i16 to f32
790  return %0 : f32
791}
792
793// CHECK-LABEL: @uitofp_i32_f32
794func.func @uitofp_i32_f32(%arg0 : i32) -> f32 {
795  // CHECK: spirv.ConvertUToF %{{.*}} : i32 to f32
796  %0 = arith.uitofp %arg0 : i32 to f32
797  return %0 : f32
798}
799
800// CHECK-LABEL: @uitofp_i1_f32
801func.func @uitofp_i1_f32(%arg0 : i1) -> f32 {
802  // CHECK: %[[ZERO:.+]] = spirv.Constant 0.000000e+00 : f32
803  // CHECK: %[[ONE:.+]] = spirv.Constant 1.000000e+00 : f32
804  // CHECK: spirv.Select %{{.*}}, %[[ONE]], %[[ZERO]] : i1, f32
805  %0 = arith.uitofp %arg0 : i1 to f32
806  return %0 : f32
807}
808
809// CHECK-LABEL: @uitofp_i1_f64
810func.func @uitofp_i1_f64(%arg0 : i1) -> f64 {
811  // CHECK: %[[ZERO:.+]] = spirv.Constant 0.000000e+00 : f64
812  // CHECK: %[[ONE:.+]] = spirv.Constant 1.000000e+00 : f64
813  // CHECK: spirv.Select %{{.*}}, %[[ONE]], %[[ZERO]] : i1, f64
814  %0 = arith.uitofp %arg0 : i1 to f64
815  return %0 : f64
816}
817
818// CHECK-LABEL: @uitofp_vec_i1_f32
819func.func @uitofp_vec_i1_f32(%arg0 : vector<4xi1>) -> vector<4xf32> {
820  // CHECK: %[[ZERO:.+]] = spirv.Constant dense<0.000000e+00> : vector<4xf32>
821  // CHECK: %[[ONE:.+]] = spirv.Constant dense<1.000000e+00> : vector<4xf32>
822  // CHECK: spirv.Select %{{.*}}, %[[ONE]], %[[ZERO]] : vector<4xi1>, vector<4xf32>
823  %0 = arith.uitofp %arg0 : vector<4xi1> to vector<4xf32>
824  return %0 : vector<4xf32>
825}
826
827// CHECK-LABEL: @uitofp_vec_i1_f64
828spirv.func @uitofp_vec_i1_f64(%arg0: vector<4xi1>) -> vector<4xf64> "None" {
829  // CHECK: %[[ZERO:.+]] = spirv.Constant dense<0.000000e+00> : vector<4xf64>
830  // CHECK: %[[ONE:.+]] = spirv.Constant dense<1.000000e+00> : vector<4xf64>
831  // CHECK: spirv.Select %{{.*}}, %[[ONE]], %[[ZERO]] : vector<4xi1>, vector<4xf64>
832  %0 = spirv.Constant dense<0.000000e+00> : vector<4xf64>
833  %1 = spirv.Constant dense<1.000000e+00> : vector<4xf64>
834  %2 = spirv.Select %arg0, %1, %0 : vector<4xi1>, vector<4xf64>
835  spirv.ReturnValue %2 : vector<4xf64>
836}
837
838// CHECK-LABEL: @sexti1
839func.func @sexti1(%arg0: i16) -> i64 {
840  // CHECK: spirv.SConvert %{{.*}} : i16 to i64
841  %0 = arith.extsi %arg0 : i16 to i64
842  return %0 : i64
843}
844
845// CHECK-LABEL: @sexti2
846func.func @sexti2(%arg0 : i32) -> i64 {
847  // CHECK: spirv.SConvert %{{.*}} : i32 to i64
848  %0 = arith.extsi %arg0 : i32 to i64
849  return %0 : i64
850}
851
852// CHECK-LABEL: @sext_bool_scalar
853// CHECK-SAME:  ([[ARG:%.+]]: i1) -> i32
854func.func @sext_bool_scalar(%arg0 : i1) -> i32 {
855  // CHECK-DAG:  [[ONES:%.+]] = spirv.Constant -1 : i32
856  // CHECK-DAG:  [[ZERO:%.+]] = spirv.Constant 0 : i32
857  // CHECK:      [[SEL:%.+]]  = spirv.Select [[ARG]], [[ONES]], [[ZERO]] : i1, i32
858  // CHECK-NEXT: return [[SEL]] : i32
859  %0 = arith.extsi %arg0 : i1 to i32
860  return %0 : i32
861}
862
863// CHECK-LABEL: @sext_bool_vector
864// CHECK-SAME:  ([[ARG:%.+]]: vector<3xi1>) -> vector<3xi32>
865func.func @sext_bool_vector(%arg0 : vector<3xi1>) -> vector<3xi32> {
866  // CHECK-DAG:  [[ONES:%.+]] = spirv.Constant dense<-1> : vector<3xi32>
867  // CHECK-DAG:  [[ZERO:%.+]] = spirv.Constant dense<0> : vector<3xi32>
868  // CHECK:      [[SEL:%.+]]  = spirv.Select [[ARG]], [[ONES]], [[ZERO]] : vector<3xi1>, vector<3xi32>
869  // CHECK-NEXT: return [[SEL]] : vector<3xi32>
870  %0 = arith.extsi %arg0 : vector<3xi1> to vector<3xi32>
871  return %0 : vector<3xi32>
872}
873
874// CHECK-LABEL: @zexti1
875func.func @zexti1(%arg0: i16) -> i64 {
876  // CHECK: spirv.UConvert %{{.*}} : i16 to i64
877  %0 = arith.extui %arg0 : i16 to i64
878  return %0 : i64
879}
880
881// CHECK-LABEL: @zexti2
882func.func @zexti2(%arg0 : i32) -> i64 {
883  // CHECK: spirv.UConvert %{{.*}} : i32 to i64
884  %0 = arith.extui %arg0 : i32 to i64
885  return %0 : i64
886}
887
888// CHECK-LABEL: @zexti3
889func.func @zexti3(%arg0 : i1) -> i32 {
890  // CHECK: %[[ZERO:.+]] = spirv.Constant 0 : i32
891  // CHECK: %[[ONE:.+]] = spirv.Constant 1 : i32
892  // CHECK: spirv.Select %{{.*}}, %[[ONE]], %[[ZERO]] : i1, i32
893  %0 = arith.extui %arg0 : i1 to i32
894  return %0 : i32
895}
896
897// CHECK-LABEL: @zexti4
898func.func @zexti4(%arg0 : vector<4xi1>) -> vector<4xi32> {
899  // CHECK: %[[ZERO:.+]] = spirv.Constant dense<0> : vector<4xi32>
900  // CHECK: %[[ONE:.+]] = spirv.Constant dense<1> : vector<4xi32>
901  // CHECK: spirv.Select %{{.*}}, %[[ONE]], %[[ZERO]] : vector<4xi1>, vector<4xi32>
902  %0 = arith.extui %arg0 : vector<4xi1> to vector<4xi32>
903  return %0 : vector<4xi32>
904}
905
906// CHECK-LABEL: @zexti5
907func.func @zexti5(%arg0 : vector<4xi1>) -> vector<4xi64> {
908  // CHECK: %[[ZERO:.+]] = spirv.Constant dense<0> : vector<4xi64>
909  // CHECK: %[[ONE:.+]] = spirv.Constant dense<1> : vector<4xi64>
910  // CHECK: spirv.Select %{{.*}}, %[[ONE]], %[[ZERO]] : vector<4xi1>, vector<4xi64>
911  %0 = arith.extui %arg0 : vector<4xi1> to vector<4xi64>
912  return %0 : vector<4xi64>
913}
914
915// CHECK-LABEL: @trunci1
916func.func @trunci1(%arg0 : i64) -> i16 {
917  // CHECK: spirv.SConvert %{{.*}} : i64 to i16
918  %0 = arith.trunci %arg0 : i64 to i16
919  return %0 : i16
920}
921
922// CHECK-LABEL: @trunci2
923func.func @trunci2(%arg0: i32) -> i16 {
924  // CHECK: spirv.SConvert %{{.*}} : i32 to i16
925  %0 = arith.trunci %arg0 : i32 to i16
926  return %0 : i16
927}
928
929// CHECK-LABEL: @trunc_to_i1
930func.func @trunc_to_i1(%arg0: i32) -> i1 {
931  // CHECK: %[[MASK:.*]] = spirv.Constant 1 : i32
932  // CHECK: %[[MASKED_SRC:.*]] = spirv.BitwiseAnd %{{.*}}, %[[MASK]] : i32
933  // CHECK: %[[IS_ONE:.*]] = spirv.IEqual %[[MASKED_SRC]], %[[MASK]] : i32
934  // CHECK-DAG: %[[TRUE:.*]] = spirv.Constant true
935  // CHECK-DAG: %[[FALSE:.*]] = spirv.Constant false
936  // CHECK: spirv.Select %[[IS_ONE]], %[[TRUE]], %[[FALSE]] : i1, i1
937  %0 = arith.trunci %arg0 : i32 to i1
938  return %0 : i1
939}
940
941// CHECK-LABEL: @trunc_to_veci1
942func.func @trunc_to_veci1(%arg0: vector<4xi32>) -> vector<4xi1> {
943  // CHECK: %[[MASK:.*]] = spirv.Constant dense<1> : vector<4xi32>
944  // CHECK: %[[MASKED_SRC:.*]] = spirv.BitwiseAnd %{{.*}}, %[[MASK]] : vector<4xi32>
945  // CHECK: %[[IS_ONE:.*]] = spirv.IEqual %[[MASKED_SRC]], %[[MASK]] : vector<4xi32>
946  // CHECK-DAG: %[[TRUE:.*]] = spirv.Constant dense<true> : vector<4xi1>
947  // CHECK-DAG: %[[FALSE:.*]] = spirv.Constant dense<false> : vector<4xi1>
948  // CHECK: spirv.Select %[[IS_ONE]], %[[TRUE]], %[[FALSE]] : vector<4xi1>, vector<4xi1>
949  %0 = arith.trunci %arg0 : vector<4xi32> to vector<4xi1>
950  return %0 : vector<4xi1>
951}
952
953// CHECK-LABEL: @fptoui1
954func.func @fptoui1(%arg0 : f32) -> i32 {
955  // CHECK: spirv.ConvertFToU %{{.*}} : f32 to i32
956  %0 = arith.fptoui %arg0 : f32 to i32
957  return %0 : i32
958}
959
960// CHECK-LABEL: @fptoui2
961func.func @fptoui2(%arg0 : f16) -> i16 {
962  // CHECK: spirv.ConvertFToU %{{.*}} : f16 to i16
963  %0 = arith.fptoui %arg0 : f16 to i16
964  return %0 : i16
965}
966
967// CHECK-LABEL: @fptosi1
968func.func @fptosi1(%arg0 : f32) -> i32 {
969  // CHECK: spirv.ConvertFToS %{{.*}} : f32 to i32
970  %0 = arith.fptosi %arg0 : f32 to i32
971  return %0 : i32
972}
973
974// CHECK-LABEL: @fptosi2
975func.func @fptosi2(%arg0 : f16) -> i16 {
976  // CHECK: spirv.ConvertFToS %{{.*}} : f16 to i16
977  %0 = arith.fptosi %arg0 : f16 to i16
978  return %0 : i16
979}
980
981} // end module
982
983// -----
984
985// Checks that cast types will be adjusted when missing special capabilities for
986// certain non-32-bit scalar types.
987module attributes {
988  spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [Float64], []>, #spirv.resource_limits<>>
989} {
990
991// CHECK-LABEL: @fpext1
992// CHECK-SAME: %[[A:.*]]: f16
993func.func @fpext1(%arg0: f16) -> f64 {
994  // CHECK: %[[ARG:.+]] = builtin.unrealized_conversion_cast %[[A]] : f16 to f32
995  // CHECK-NEXT: spirv.FConvert %[[ARG]] : f32 to f64
996  %0 = arith.extf %arg0 : f16 to f64
997  return %0: f64
998}
999
1000// CHECK-LABEL: @fpext2
1001// CHECK-SAME: %[[ARG:.*]]: f32
1002func.func @fpext2(%arg0 : f32) -> f64 {
1003  // CHECK-NEXT: spirv.FConvert %[[ARG]] : f32 to f64
1004  %0 = arith.extf %arg0 : f32 to f64
1005  return %0: f64
1006}
1007
1008// CHECK-LABEL: @trunci4_scalar
1009//  CHECK-SAME: %[[ARG:.*]]: i32
1010func.func @trunci4_scalar(%arg0 : i32) -> i4 {
1011  // CHECK: %[[MASK:.+]] = spirv.Constant 15 : i32
1012  // CHECK: %[[AND:.+]] = spirv.BitwiseAnd %[[ARG]], %[[MASK]] : i32
1013  %0 = arith.trunci %arg0 : i32 to i4
1014  // CHECK: %[[RET:.+]] = builtin.unrealized_conversion_cast %[[AND]] : i32 to i4
1015  // CHECK: return %[[RET]] : i4
1016  return %0 : i4
1017}
1018
1019// CHECK-LABEL: @trunci4_vector
1020//  CHECK-SAME: %[[ARG:.*]]: vector<2xi32>
1021func.func @trunci4_vector(%arg0 : vector<2xi32>) -> vector<2xi4> {
1022  // CHECK: %[[MASK:.+]] = spirv.Constant dense<15> : vector<2xi32>
1023  // CHECK: %[[AND:.+]] = spirv.BitwiseAnd %[[ARG]], %[[MASK]] : vector<2xi32>
1024  %0 = arith.trunci %arg0 : vector<2xi32> to vector<2xi4>
1025  // CHECK: %[[RET:.+]] = builtin.unrealized_conversion_cast %[[AND]] : vector<2xi32> to vector<2xi4>
1026  // CHECK: return %[[RET]] : vector<2xi4>
1027  return %0 : vector<2xi4>
1028}
1029
1030// CHECK-LABEL: @zexti4_scalar
1031func.func @zexti4_scalar(%arg0: i4) -> i32 {
1032  // CHECK: %[[INPUT:.+]] = builtin.unrealized_conversion_cast %{{.+}} : i4 to i32
1033  // CHECK: %[[MASK:.+]] = spirv.Constant 15 : i32
1034  // CHECK: %[[AND:.+]] = spirv.BitwiseAnd %[[INPUT]], %[[MASK]] : i32
1035  %0 = arith.extui %arg0 : i4 to i32
1036  // CHECK: return %[[AND]] : i32
1037  return %0 : i32
1038}
1039
1040// CHECK-LABEL: @zexti4_vector
1041func.func @zexti4_vector(%arg0: vector<3xi4>) -> vector<3xi32> {
1042  // CHECK: %[[INPUT:.+]] = builtin.unrealized_conversion_cast %{{.+}} : vector<3xi4> to vector<3xi32>
1043  // CHECK: %[[MASK:.+]] = spirv.Constant dense<15> : vector<3xi32>
1044  // CHECK: %[[AND:.+]] = spirv.BitwiseAnd %[[INPUT]], %[[MASK]] : vector<3xi32>
1045  %0 = arith.extui %arg0 : vector<3xi4> to vector<3xi32>
1046  // CHECK: return %[[AND]] : vector<3xi32>
1047  return %0 : vector<3xi32>
1048}
1049
1050// CHECK-LABEL: @sexti4_scalar
1051func.func @sexti4_scalar(%arg0: i4) -> i32 {
1052  // CHECK: %[[INPUT:.+]] = builtin.unrealized_conversion_cast %arg0 : i4 to i32
1053  // CHECK: %[[SIZE:.+]] = spirv.Constant 28 : i32
1054  // CHECK: %[[SL:.+]] = spirv.ShiftLeftLogical %[[INPUT]], %[[SIZE]] : i32, i32
1055  // CHECK: %[[SR:.+]] = spirv.ShiftRightArithmetic %[[SL]], %[[SIZE]] : i32, i32
1056  %0 = arith.extsi %arg0 : i4 to i32
1057  // CHECK: return %[[SR]] : i32
1058  return %0 : i32
1059}
1060
1061// CHECK-LABEL: @sexti4_vector
1062func.func @sexti4_vector(%arg0: vector<4xi4>) -> vector<4xi32> {
1063  // CHECK: %[[INPUT:.+]] = builtin.unrealized_conversion_cast %arg0 : vector<4xi4> to vector<4xi32>
1064  // CHECK: %[[SIZE:.+]] = spirv.Constant dense<28> : vector<4xi32>
1065  // CHECK: %[[SL:.+]] = spirv.ShiftLeftLogical %[[INPUT]], %[[SIZE]] : vector<4xi32>, vector<4xi32>
1066  // CHECK: %[[SR:.+]] = spirv.ShiftRightArithmetic %[[SL]], %[[SIZE]] : vector<4xi32>, vector<4xi32>
1067  %0 = arith.extsi %arg0 : vector<4xi4> to vector<4xi32>
1068  // CHECK: return %[[SR]] : vector<4xi32>
1069  return %0 : vector<4xi32>
1070}
1071
1072} // end module
1073
1074// -----
1075
1076// Checks that cast types will be adjusted when missing special capabilities for
1077// certain non-32-bit scalar types.
1078module attributes {
1079  spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [Float16], []>, #spirv.resource_limits<>>
1080} {
1081
1082// CHECK-LABEL: @fptrunc1
1083// CHECK-SAME: %[[ARG:.*]]: f32
1084func.func @fptrunc1(%arg0: f32) -> f16 {
1085  // CHECK-NEXT: spirv.FConvert %[[ARG]] : f32 to f16
1086  %0 = arith.truncf %arg0 : f32 to f16
1087  return %0: f16
1088}
1089
1090} // end module
1091
1092// -----
1093
1094// Check various lowerings for OpenCL.
1095module attributes {
1096  spirv.target_env = #spirv.target_env<
1097    #spirv.vce<v1.0, [Int16, Kernel], []>, #spirv.resource_limits<>>
1098} {
1099
1100// Check integer operation conversions.
1101// CHECK-LABEL: @int32_scalar
1102func.func @int32_scalar(%lhs: i32, %rhs: i32) {
1103  // CHECK: spirv.IAdd %{{.*}}, %{{.*}}: i32
1104  %0 = arith.addi %lhs, %rhs: i32
1105  // CHECK: spirv.ISub %{{.*}}, %{{.*}}: i32
1106  %1 = arith.subi %lhs, %rhs: i32
1107  // CHECK: spirv.IMul %{{.*}}, %{{.*}}: i32
1108  %2 = arith.muli %lhs, %rhs: i32
1109  // CHECK: spirv.SDiv %{{.*}}, %{{.*}}: i32
1110  %3 = arith.divsi %lhs, %rhs: i32
1111  // CHECK: spirv.UDiv %{{.*}}, %{{.*}}: i32
1112  %4 = arith.divui %lhs, %rhs: i32
1113  // CHECK: spirv.UMod %{{.*}}, %{{.*}}: i32
1114  %5 = arith.remui %lhs, %rhs: i32
1115  // CHECK: spirv.CL.s_max %{{.*}}, %{{.*}}: i32
1116  %6 = arith.maxsi %lhs, %rhs : i32
1117  // CHECK: spirv.CL.u_max %{{.*}}, %{{.*}}: i32
1118  %7 = arith.maxui %lhs, %rhs : i32
1119  // CHECK: spirv.CL.s_min %{{.*}}, %{{.*}}: i32
1120  %8 = arith.minsi %lhs, %rhs : i32
1121  // CHECK: spirv.CL.u_min %{{.*}}, %{{.*}}: i32
1122  %9 = arith.minui %lhs, %rhs : i32
1123  return
1124}
1125
1126// Check float binary operation conversions.
1127// CHECK-LABEL: @float32_binary_scalar
1128func.func @float32_binary_scalar(%lhs: f32, %rhs: f32) {
1129  // CHECK: spirv.FAdd %{{.*}}, %{{.*}}: f32
1130  %0 = arith.addf %lhs, %rhs: f32
1131  // CHECK: spirv.FSub %{{.*}}, %{{.*}}: f32
1132  %1 = arith.subf %lhs, %rhs: f32
1133  // CHECK: spirv.FMul %{{.*}}, %{{.*}}: f32
1134  %2 = arith.mulf %lhs, %rhs: f32
1135  // CHECK: spirv.FDiv %{{.*}}, %{{.*}}: f32
1136  %3 = arith.divf %lhs, %rhs: f32
1137  // CHECK: spirv.FRem %{{.*}}, %{{.*}}: f32
1138  %4 = arith.remf %lhs, %rhs: f32
1139  return
1140}
1141
1142// CHECK-LABEL: @float32_minimumf_scalar
1143// CHECK-SAME: %[[LHS:.+]]: f32, %[[RHS:.+]]: f32
1144func.func @float32_minimumf_scalar(%arg0 : f32, %arg1 : f32) -> f32 {
1145  // CHECK: %[[MIN:.+]] = spirv.CL.fmin %arg0, %arg1 : f32
1146  // CHECK: %[[LHS_NAN:.+]] = spirv.IsNan %[[LHS]] : f32
1147  // CHECK: %[[RHS_NAN:.+]] = spirv.IsNan %[[RHS]] : f32
1148  // CHECK: %[[SELECT1:.+]] = spirv.Select %[[LHS_NAN]], %[[LHS]], %[[MIN]]
1149  // CHECK: %[[SELECT2:.+]] = spirv.Select %[[RHS_NAN]], %[[RHS]], %[[SELECT1]]
1150  %0 = arith.minimumf %arg0, %arg1 : f32
1151  // CHECK: return %[[SELECT2]]
1152  return %0: f32
1153}
1154
1155// CHECK-LABEL: @float32_minnumf_scalar
1156// CHECK-SAME: %[[LHS:.+]]: f32, %[[RHS:.+]]: f32
1157func.func @float32_minnumf_scalar(%arg0 : f32, %arg1 : f32) -> f32 {
1158  // CHECK: %[[MIN:.+]] = spirv.CL.fmin %arg0, %arg1 : f32
1159  %0 = arith.minnumf %arg0, %arg1 : f32
1160  // CHECK: return %[[MIN]]
1161  return %0: f32
1162}
1163
1164// CHECK-LABEL: @float32_maximumf_scalar
1165// CHECK-SAME: %[[LHS:.+]]: vector<2xf32>, %[[RHS:.+]]: vector<2xf32>
1166func.func @float32_maximumf_scalar(%arg0 : vector<2xf32>, %arg1 : vector<2xf32>) -> vector<2xf32> {
1167  // CHECK: %[[MAX:.+]] = spirv.CL.fmax %arg0, %arg1 : vector<2xf32>
1168  // CHECK: %[[LHS_NAN:.+]] = spirv.IsNan %[[LHS]] : vector<2xf32>
1169  // CHECK: %[[RHS_NAN:.+]] = spirv.IsNan %[[RHS]] : vector<2xf32>
1170  // CHECK: %[[SELECT1:.+]] = spirv.Select %[[LHS_NAN]], %[[LHS]], %[[MAX]]
1171  // CHECK: %[[SELECT2:.+]] = spirv.Select %[[RHS_NAN]], %[[RHS]], %[[SELECT1]]
1172  %0 = arith.maximumf %arg0, %arg1 : vector<2xf32>
1173  // CHECK: return %[[SELECT2]]
1174  return %0: vector<2xf32>
1175}
1176
1177// CHECK-LABEL: @float32_maxnumf_scalar
1178// CHECK-SAME: %[[LHS:.+]]: vector<2xf32>, %[[RHS:.+]]: vector<2xf32>
1179func.func @float32_maxnumf_scalar(%arg0 : vector<2xf32>, %arg1 : vector<2xf32>) -> vector<2xf32> {
1180  // CHECK: %[[MAX:.+]] = spirv.CL.fmax %arg0, %arg1 : vector<2xf32>
1181  %0 = arith.maxnumf %arg0, %arg1 : vector<2xf32>
1182  // CHECK: return %[[MAX]]
1183  return %0: vector<2xf32>
1184}
1185
1186
1187// CHECK-LABEL: @scalar_srem
1188// CHECK-SAME: (%[[LHS:.+]]: i32, %[[RHS:.+]]: i32)
1189func.func @scalar_srem(%lhs: i32, %rhs: i32) {
1190  // CHECK: %[[LABS:.+]] = spirv.CL.s_abs %[[LHS]] : i32
1191  // CHECK: %[[RABS:.+]] = spirv.CL.s_abs %[[RHS]] : i32
1192  // CHECK:  %[[ABS:.+]] = spirv.UMod %[[LABS]], %[[RABS]] : i32
1193  // CHECK:  %[[POS:.+]] = spirv.IEqual %[[LHS]], %[[LABS]] : i32
1194  // CHECK:  %[[NEG:.+]] = spirv.SNegate %[[ABS]] : i32
1195  // CHECK:      %{{.+}} = spirv.Select %[[POS]], %[[ABS]], %[[NEG]] : i1, i32
1196  %0 = arith.remsi %lhs, %rhs: i32
1197  return
1198}
1199
1200// CHECK-LABEL: @vector_srem
1201// CHECK-SAME: (%[[LHS:.+]]: vector<3xi16>, %[[RHS:.+]]: vector<3xi16>)
1202func.func @vector_srem(%arg0: vector<3xi16>, %arg1: vector<3xi16>) {
1203  // CHECK: %[[LABS:.+]] = spirv.CL.s_abs %[[LHS]] : vector<3xi16>
1204  // CHECK: %[[RABS:.+]] = spirv.CL.s_abs %[[RHS]] : vector<3xi16>
1205  // CHECK:  %[[ABS:.+]] = spirv.UMod %[[LABS]], %[[RABS]] : vector<3xi16>
1206  // CHECK:  %[[POS:.+]] = spirv.IEqual %[[LHS]], %[[LABS]] : vector<3xi16>
1207  // CHECK:  %[[NEG:.+]] = spirv.SNegate %[[ABS]] : vector<3xi16>
1208  // CHECK:      %{{.+}} = spirv.Select %[[POS]], %[[ABS]], %[[NEG]] : vector<3xi1>, vector<3xi16>
1209  %0 = arith.remsi %arg0, %arg1: vector<3xi16>
1210  return
1211}
1212
1213} // end module
1214
1215// -----
1216
1217module attributes {
1218  spirv.target_env = #spirv.target_env<
1219    #spirv.vce<v1.0, [Shader, Int8, Int16, Int64, Float16, Float64],
1220             [SPV_KHR_storage_buffer_storage_class]>, #spirv.resource_limits<>>
1221} {
1222
1223// CHECK-LABEL: @select
1224func.func @select(%arg0 : i32, %arg1 : i32) {
1225  %0 = arith.cmpi sle, %arg0, %arg1 : i32
1226  // CHECK: spirv.Select
1227  %1 = arith.select %0, %arg0, %arg1 : i32
1228  return
1229}
1230
1231} // end module
1232
1233// -----
1234
1235//===----------------------------------------------------------------------===//
1236// arith.select
1237//===----------------------------------------------------------------------===//
1238
1239module attributes {
1240  spirv.target_env = #spirv.target_env<
1241    #spirv.vce<v1.0, [Int8, Int16, Int64, Float16, Float64, Shader], []>, #spirv.resource_limits<>>
1242} {
1243
1244// Check integer operation conversions.
1245// CHECK-LABEL: @int32_scalar
1246func.func @int32_scalar(%lhs: i32, %rhs: i32) {
1247  // CHECK: spirv.IAdd %{{.*}}, %{{.*}}: i32
1248  %0 = arith.addi %lhs, %rhs: i32
1249  // CHECK: spirv.ISub %{{.*}}, %{{.*}}: i32
1250  %1 = arith.subi %lhs, %rhs: i32
1251  // CHECK: spirv.IMul %{{.*}}, %{{.*}}: i32
1252  %2 = arith.muli %lhs, %rhs: i32
1253  // CHECK: spirv.SDiv %{{.*}}, %{{.*}}: i32
1254  %3 = arith.divsi %lhs, %rhs: i32
1255  // CHECK: spirv.UDiv %{{.*}}, %{{.*}}: i32
1256  %4 = arith.divui %lhs, %rhs: i32
1257  // CHECK: spirv.UMod %{{.*}}, %{{.*}}: i32
1258  %5 = arith.remui %lhs, %rhs: i32
1259  // CHECK: spirv.GL.SMax %{{.*}}, %{{.*}}: i32
1260  %6 = arith.maxsi %lhs, %rhs : i32
1261  // CHECK: spirv.GL.UMax %{{.*}}, %{{.*}}: i32
1262  %7 = arith.maxui %lhs, %rhs : i32
1263  // CHECK: spirv.GL.SMin %{{.*}}, %{{.*}}: i32
1264  %8 = arith.minsi %lhs, %rhs : i32
1265  // CHECK: spirv.GL.UMin %{{.*}}, %{{.*}}: i32
1266  %9 = arith.minui %lhs, %rhs : i32
1267  return
1268}
1269
1270// CHECK-LABEL: @scalar_srem
1271// CHECK-SAME: (%[[LHS:.+]]: i32, %[[RHS:.+]]: i32)
1272func.func @scalar_srem(%lhs: i32, %rhs: i32) {
1273  // CHECK: %[[LABS:.+]] = spirv.GL.SAbs %[[LHS]] : i32
1274  // CHECK: %[[RABS:.+]] = spirv.GL.SAbs %[[RHS]] : i32
1275  // CHECK:  %[[ABS:.+]] = spirv.UMod %[[LABS]], %[[RABS]] : i32
1276  // CHECK:  %[[POS:.+]] = spirv.IEqual %[[LHS]], %[[LABS]] : i32
1277  // CHECK:  %[[NEG:.+]] = spirv.SNegate %[[ABS]] : i32
1278  // CHECK:      %{{.+}} = spirv.Select %[[POS]], %[[ABS]], %[[NEG]] : i1, i32
1279  %0 = arith.remsi %lhs, %rhs: i32
1280  return
1281}
1282
1283// Check float unary operation conversions.
1284// CHECK-LABEL: @float32_unary_scalar
1285func.func @float32_unary_scalar(%arg0: f32) {
1286  // CHECK: spirv.FNegate %{{.*}}: f32
1287  %5 = arith.negf %arg0 : f32
1288  return
1289}
1290
1291// Check float binary operation conversions.
1292// CHECK-LABEL: @float32_binary_scalar
1293func.func @float32_binary_scalar(%lhs: f32, %rhs: f32) {
1294  // CHECK: spirv.FAdd %{{.*}}, %{{.*}}: f32
1295  %0 = arith.addf %lhs, %rhs: f32
1296  // CHECK: spirv.FSub %{{.*}}, %{{.*}}: f32
1297  %1 = arith.subf %lhs, %rhs: f32
1298  // CHECK: spirv.FMul %{{.*}}, %{{.*}}: f32
1299  %2 = arith.mulf %lhs, %rhs: f32
1300  // CHECK: spirv.FDiv %{{.*}}, %{{.*}}: f32
1301  %3 = arith.divf %lhs, %rhs: f32
1302  // CHECK: spirv.FRem %{{.*}}, %{{.*}}: f32
1303  %4 = arith.remf %lhs, %rhs: f32
1304  return
1305}
1306
1307// CHECK-LABEL: @float32_minimumf_scalar
1308// CHECK-SAME: %[[LHS:.+]]: f32, %[[RHS:.+]]: f32
1309func.func @float32_minimumf_scalar(%arg0 : f32, %arg1 : f32) -> f32 {
1310  // CHECK: %[[MIN:.+]] = spirv.GL.FMin %arg0, %arg1 : f32
1311  // CHECK: %[[LHS_NAN:.+]] = spirv.IsNan %[[LHS]] : f32
1312  // CHECK: %[[RHS_NAN:.+]] = spirv.IsNan %[[RHS]] : f32
1313  // CHECK: %[[SELECT1:.+]] = spirv.Select %[[LHS_NAN]], %[[LHS]], %[[MIN]]
1314  // CHECK: %[[SELECT2:.+]] = spirv.Select %[[RHS_NAN]], %[[RHS]], %[[SELECT1]]
1315  %0 = arith.minimumf %arg0, %arg1 : f32
1316  // CHECK: return %[[SELECT2]]
1317  return %0: f32
1318}
1319
1320// CHECK-LABEL: @float32_minnumf_scalar
1321// CHECK-SAME: %[[LHS:.+]]: f32, %[[RHS:.+]]: f32
1322func.func @float32_minnumf_scalar(%arg0 : f32, %arg1 : f32) -> f32 {
1323  // CHECK: %[[MIN:.+]] = spirv.GL.FMin %arg0, %arg1 : f32
1324  // CHECK: %[[LHS_NAN:.+]] = spirv.IsNan %[[LHS]] : f32
1325  // CHECK: %[[RHS_NAN:.+]] = spirv.IsNan %[[RHS]] : f32
1326  // CHECK: %[[SELECT1:.+]] = spirv.Select %[[LHS_NAN]], %[[RHS]], %[[MIN]]
1327  // CHECK: %[[SELECT2:.+]] = spirv.Select %[[RHS_NAN]], %[[LHS]], %[[SELECT1]]
1328  %0 = arith.minnumf %arg0, %arg1 : f32
1329  // CHECK: return %[[SELECT2]]
1330  return %0: f32
1331}
1332
1333// CHECK-LABEL: @float32_maximumf_scalar
1334// CHECK-SAME: %[[LHS:.+]]: vector<2xf32>, %[[RHS:.+]]: vector<2xf32>
1335func.func @float32_maximumf_scalar(%arg0 : vector<2xf32>, %arg1 : vector<2xf32>) -> vector<2xf32> {
1336  // CHECK: %[[MAX:.+]] = spirv.GL.FMax %arg0, %arg1 : vector<2xf32>
1337  // CHECK: %[[LHS_NAN:.+]] = spirv.IsNan %[[LHS]] : vector<2xf32>
1338  // CHECK: %[[RHS_NAN:.+]] = spirv.IsNan %[[RHS]] : vector<2xf32>
1339  // CHECK: %[[SELECT1:.+]] = spirv.Select %[[LHS_NAN]], %[[LHS]], %[[MAX]]
1340  // CHECK: %[[SELECT2:.+]] = spirv.Select %[[RHS_NAN]], %[[RHS]], %[[SELECT1]]
1341  %0 = arith.maximumf %arg0, %arg1 : vector<2xf32>
1342  // CHECK: return %[[SELECT2]]
1343  return %0: vector<2xf32>
1344}
1345
1346// CHECK-LABEL: @float32_maxnumf_scalar
1347// CHECK-SAME: %[[LHS:.+]]: vector<2xf32>, %[[RHS:.+]]: vector<2xf32>
1348func.func @float32_maxnumf_scalar(%arg0 : vector<2xf32>, %arg1 : vector<2xf32>) -> vector<2xf32> {
1349  // CHECK: %[[MAX:.+]] = spirv.GL.FMax %arg0, %arg1 : vector<2xf32>
1350  // CHECK: %[[LHS_NAN:.+]] = spirv.IsNan %[[LHS]] : vector<2xf32>
1351  // CHECK: %[[RHS_NAN:.+]] = spirv.IsNan %[[RHS]] : vector<2xf32>
1352  // CHECK: %[[SELECT1:.+]] = spirv.Select %[[LHS_NAN]], %[[RHS]], %[[MAX]]
1353  // CHECK: %[[SELECT2:.+]] = spirv.Select %[[RHS_NAN]], %[[LHS]], %[[SELECT1]]
1354  %0 = arith.maxnumf %arg0, %arg1 : vector<2xf32>
1355  // CHECK: return %[[SELECT2]]
1356  return %0: vector<2xf32>
1357}
1358
1359// Check int vector types.
1360// CHECK-LABEL: @int_vector234
1361func.func @int_vector234(%arg0: vector<2xi8>, %arg1: vector<4xi64>) {
1362  // CHECK: spirv.SDiv %{{.*}}, %{{.*}}: vector<2xi8>
1363  %0 = arith.divsi %arg0, %arg0: vector<2xi8>
1364  // CHECK: spirv.UDiv %{{.*}}, %{{.*}}: vector<4xi64>
1365  %1 = arith.divui %arg1, %arg1: vector<4xi64>
1366  return
1367}
1368
1369// CHECK-LABEL: @vector_srem
1370// CHECK-SAME: (%[[LHS:.+]]: vector<3xi16>, %[[RHS:.+]]: vector<3xi16>)
1371func.func @vector_srem(%arg0: vector<3xi16>, %arg1: vector<3xi16>) {
1372  // CHECK: %[[LABS:.+]] = spirv.GL.SAbs %[[LHS]] : vector<3xi16>
1373  // CHECK: %[[RABS:.+]] = spirv.GL.SAbs %[[RHS]] : vector<3xi16>
1374  // CHECK:  %[[ABS:.+]] = spirv.UMod %[[LABS]], %[[RABS]] : vector<3xi16>
1375  // CHECK:  %[[POS:.+]] = spirv.IEqual %[[LHS]], %[[LABS]] : vector<3xi16>
1376  // CHECK:  %[[NEG:.+]] = spirv.SNegate %[[ABS]] : vector<3xi16>
1377  // CHECK:      %{{.+}} = spirv.Select %[[POS]], %[[ABS]], %[[NEG]] : vector<3xi1>, vector<3xi16>
1378  %0 = arith.remsi %arg0, %arg1: vector<3xi16>
1379  return
1380}
1381
1382// Check float vector types.
1383// CHECK-LABEL: @float_vector234
1384func.func @float_vector234(%arg0: vector<2xf16>, %arg1: vector<3xf64>) {
1385  // CHECK: spirv.FAdd %{{.*}}, %{{.*}}: vector<2xf16>
1386  %0 = arith.addf %arg0, %arg0: vector<2xf16>
1387  // CHECK: spirv.FMul %{{.*}}, %{{.*}}: vector<3xf64>
1388  %1 = arith.mulf %arg1, %arg1: vector<3xf64>
1389  return
1390}
1391
1392// CHECK-LABEL: @one_elem_vector
1393func.func @one_elem_vector(%arg0: vector<1xi32>) {
1394  // CHECK: spirv.IAdd %{{.+}}, %{{.+}}: i32
1395  %0 = arith.addi %arg0, %arg0: vector<1xi32>
1396  return
1397}
1398
1399} // end module
1400
1401// -----
1402
1403// Check that types are converted to 32-bit when no special capabilities.
1404module attributes {
1405  spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [], []>, #spirv.resource_limits<>>
1406} {
1407
1408// CHECK-LABEL: @int_vector23
1409func.func @int_vector23(%arg0: vector<2xi8>, %arg1: vector<3xi16>) {
1410  // CHECK: spirv.SDiv %{{.*}}, %{{.*}}: vector<2xi32>
1411  %0 = arith.divsi %arg0, %arg0: vector<2xi8>
1412  // CHECK: spirv.SDiv %{{.*}}, %{{.*}}: vector<3xi32>
1413  %1 = arith.divsi %arg1, %arg1: vector<3xi16>
1414  return
1415}
1416
1417// CHECK-LABEL: @float_scalar
1418func.func @float_scalar(%arg0: f16) {
1419  // CHECK: spirv.FAdd %{{.*}}, %{{.*}}: f32
1420  %0 = arith.addf %arg0, %arg0: f16
1421  return
1422}
1423
1424} // end module
1425
1426// -----
1427
1428module attributes {
1429  spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [Int8, Int16, Int64, Float16, Float64, Kernel], [SPV_KHR_no_integer_wrap_decoration]>, #spirv.resource_limits<>>
1430} {
1431
1432// CHECK-LABEL: @ops_flags
1433func.func @ops_flags(%arg0: i64, %arg1: i64) {
1434  // CHECK: %{{.*}} = spirv.IAdd %{{.*}}, %{{.*}} {no_signed_wrap} : i64
1435  %0 = arith.addi %arg0, %arg1 overflow<nsw> : i64
1436  // CHECK: %{{.*}} = spirv.ISub %{{.*}}, %{{.*}} {no_unsigned_wrap} : i64
1437  %1 = arith.subi %arg0, %arg1 overflow<nuw> : i64
1438  // CHECK: %{{.*}} = spirv.IMul %{{.*}}, %{{.*}} {no_signed_wrap, no_unsigned_wrap} : i64
1439  %2 = arith.muli %arg0, %arg1 overflow<nsw, nuw> : i64
1440  // CHECK: %{{.*}} = spirv.ShiftLeftLogical %{{.*}}, %{{.*}} {no_signed_wrap, no_unsigned_wrap} : i64
1441  %3 = arith.shli %arg0, %arg1 overflow<nsw, nuw> : i64
1442  return
1443}
1444
1445} // end module
1446
1447
1448// -----
1449
1450module attributes {
1451  spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [Int8, Int16, Int64, Float16, Float64], []>, #spirv.resource_limits<>>
1452} {
1453
1454// No decorations should be generated is corresponding Extensions/Capabilities are missing
1455// CHECK-LABEL: @ops_flags
1456func.func @ops_flags(%arg0: i64, %arg1: i64) {
1457  // CHECK: %{{.*}} = spirv.IAdd %{{.*}}, %{{.*}} : i64
1458  %0 = arith.addi %arg0, %arg1 overflow<nsw> : i64
1459  // CHECK: %{{.*}} = spirv.ISub %{{.*}}, %{{.*}} : i64
1460  %1 = arith.subi %arg0, %arg1 overflow<nuw> : i64
1461  // CHECK: %{{.*}} = spirv.IMul %{{.*}}, %{{.*}} : i64
1462  %2 = arith.muli %arg0, %arg1 overflow<nsw, nuw> : i64
1463  // CHECK: %{{.*}} = spirv.IMul %{{.*}}, %{{.*}} : i64
1464  %3 = arith.muli %arg0, %arg1 overflow<nsw, nuw> : i64
1465  return
1466}
1467
1468} // end module
1469