1 // RUN: mlir-opt -split-input-file -convert-func-to-spirv %s -o - | FileCheck %s
2 // RUN: mlir-opt -split-input-file -convert-func-to-spirv="emulate-lt-32-bit-scalar-types=false" %s | \
3 // RUN: FileCheck %s --check-prefix=NOEMU
5 //===----------------------------------------------------------------------===//
7 //===----------------------------------------------------------------------===//
9 // Check that non-32-bit integer types are converted to 32-bit types if the
10 // corresponding capabilities are not available.
12 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [], []>, #spirv.resource_limits<>>
15 // CHECK-LABEL: spirv.func @integer8
19 // NOEMU-LABEL: func.func @integer8
23 func.func @integer8(%arg0: i8, %arg1: si8, %arg2: ui8) { return }
25 // CHECK-LABEL: spirv.func @integer16
29 // NOEMU-LABEL: func.func @integer16
33 func.func @integer16(%arg0: i16, %arg1: si16, %arg2: ui16) { return }
35 // We do not truncate 64-bit types to 32-bit ones.
36 // CHECK-LABEL: func.func @integer64
40 // NOEMU-LABEL: func.func @integer64
44 func.func @integer64(%arg0: i64, %arg1: si64, %arg2: ui64) { return }
46 // i128 is not supported by SPIR-V.
47 // CHECK-LABEL: func.func @integer128
49 // NOEMU-LABEL: func.func @integer128
51 func.func @integer128(%arg0: i128) { return }
57 // Check that non-32-bit integer types are kept untouched if the corresponding
58 // capabilities are available.
60 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [Int8, Int16, Int64], []>, #spirv.resource_limits<>>
63 // CHECK-LABEL: spirv.func @integer8
67 // NOEMU-LABEL: spirv.func @integer8
71 func.func @integer8(%arg0: i8, %arg1: si8, %arg2: ui8) { return }
73 // CHECK-LABEL: spirv.func @integer16
77 // NOEMU-LABEL: spirv.func @integer16
81 func.func @integer16(%arg0: i16, %arg1: si16, %arg2: ui16) { return }
83 // CHECK-LABEL: spirv.func @integer64
87 // NOEMU-LABEL: spirv.func @integer64
91 func.func @integer64(%arg0: i64, %arg1: si64, %arg2: ui64) { return }
97 // Check that power-of-two sub-byte bitwidths are converted to i32.
99 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [], []>, #spirv.resource_limits<>>
102 // CHECK: spirv.func @integer2(%{{.+}}: i32)
103 func.func @integer2(%arg0: i8) { return }
105 // CHECK: spirv.func @integer4(%{{.+}}: i32)
106 func.func @integer4(%arg0: i4) { return }
108 // CHECK: spirv.func @v3i4(%{{.+}}: vector<3xi32>)
109 func.func @v3i4(%arg0: vector<3xi4>) { return }
115 // Check that other bitwidths are not supported.
117 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [], []>, #spirv.resource_limits<>>
120 // CHECK-NOT: spirv.func @integer3
121 func.func @integer3(%arg0: i3) { return }
123 // CHECK-NOT: spirv.func @integer13
124 func.func @integer4(%arg0: i13) { return }
126 // CHECK-NOT: spirv.func @integer128
127 func.func @integer128(%arg0: i128) { return }
129 // CHECK-NOT: spirv.func @integer42
130 func.func @integer42(%arg0: i42) { return }
136 //===----------------------------------------------------------------------===//
138 //===----------------------------------------------------------------------===//
140 // The index type is always converted into i32 or i64, with i32 being the
143 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [], []>, #spirv.resource_limits<>>
146 // CHECK-LABEL: spirv.func @index_type
147 // CHECK-SAME: %{{.*}}: i32
148 func.func @index_type(%arg0: index) { return }
154 //===----------------------------------------------------------------------===//
156 //===----------------------------------------------------------------------===//
158 // Check that non-32-bit float types are converted to 32-bit types if the
159 // corresponding capabilities are not available.
161 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [], []>, #spirv.resource_limits<>>
164 // CHECK-LABEL: spirv.func @float16
166 // NOEMU-LABEL: func.func @float16
168 func.func @float16(%arg0: f16) { return }
170 // CHECK-LABEL: func.func @float64
172 // NOEMU-LABEL: func.func @float64
174 func.func @float64(%arg0: f64) { return }
176 // f80 is not supported by SPIR-V.
177 // CHECK-LABEL: func.func @float80
179 // NOEMU-LABEL: func.func @float80
181 func.func @float80(%arg0: f80) { return }
187 // Check that non-32-bit float types are kept untouched if the corresponding
188 // capabilities are available.
190 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [Float16, Float64], []>, #spirv.resource_limits<>>
193 // CHECK-LABEL: spirv.func @float16
195 // NOEMU-LABEL: spirv.func @float16
197 func.func @float16(%arg0: f16) { return }
199 // CHECK-LABEL: spirv.func @float64
201 // NOEMU-LABEL: spirv.func @float64
203 func.func @float64(%arg0: f64) { return }
209 // Check that bf16 is not supported.
211 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [], []>, #spirv.resource_limits<>>
214 // CHECK-NOT: spirv.func @bf16_type
215 func.func @bf16_type(%arg0: bf16) { return }
221 //===----------------------------------------------------------------------===//
223 //===----------------------------------------------------------------------===//
225 // Check that capabilities for scalar types affects complex types too: having
226 // special capabilities means keep vector types untouched.
228 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0,
229 [Float64, StorageUniform16, StorageBuffer16BitAccess],
230 [SPV_KHR_16bit_storage, SPV_KHR_8bit_storage]>, #spirv.resource_limits<>>
233 // CHECK-LABEL: func @complex_types
234 // CHECK-SAME: vector<2xf32>
235 // CHECK-SAME: vector<2xf64>
236 func.func @complex_types(
241 // CHECK-LABEL: func @memref_complex_types_with_cap
242 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<4 x vector<2xf16>, stride=4> [0])>, StorageBuffer>
243 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x vector<2xf16>, stride=4> [0])>, Uniform>
244 func.func @memref_complex_types_with_cap(
245 %arg0: memref<4xcomplex<f16>, #spirv.storage_class<StorageBuffer>>,
246 %arg1: memref<2x8xcomplex<f16>, #spirv.storage_class<Uniform>>
253 // Check that capabilities for scalar types affects complex types too: no special
254 // capabilities available means widening element types to 32-bit.
257 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [], []>, #spirv.resource_limits<>>
260 // Emulation is unimplemented right now.
261 // CHECK-LABEL: func @memref_complex_types_no_cap
262 // CHECK-SAME: memref<4xcomplex<f16>, #spirv.storage_class<StorageBuffer>>
263 // CHECK-SAME: memref<2x8xcomplex<f16>, #spirv.storage_class<Uniform>>
264 // NOEMU-LABEL: func @memref_complex_types_no_cap
265 // NOEMU-SAME: memref<4xcomplex<f16>, #spirv.storage_class<StorageBuffer>>
266 // NOEMU-SAME: memref<2x8xcomplex<f16>, #spirv.storage_class<Uniform>>
267 func.func @memref_complex_types_no_cap(
268 %arg0: memref<4xcomplex<f16>, #spirv.storage_class<StorageBuffer>>,
269 %arg1: memref<2x8xcomplex<f16>, #spirv.storage_class<Uniform>>
276 //===----------------------------------------------------------------------===//
278 //===----------------------------------------------------------------------===//
280 // Check that capabilities for scalar types affects vector types too: no special
281 // capabilities available means widening element types to 32-bit.
283 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [], []>, #spirv.resource_limits<>>
286 // CHECK-LABEL: spirv.func @int_vector
287 // CHECK-SAME: vector<2xi32>
288 // CHECK-SAME: vector<3xsi32>
289 func.func @int_vector(
291 %arg1: vector<3xsi16>
294 // CHECK-LABEL: spirv.func @float_vector
295 // CHECK-SAME: vector<2xf32>
296 func.func @float_vector(
300 // CHECK-LABEL: spirv.func @one_element_vector
301 // CHECK-SAME: %{{.+}}: i32
302 func.func @one_element_vector(%arg0: vector<1xi8>) { return }
304 // CHECK-LABEL: spirv.func @index_vector
305 // CHECK-SAME: %{{.*}}: vector<4xi32>
306 func.func @index_vector(%arg0: vector<4xindex>) { return }
312 // Check that capabilities for scalar types affects vector types too: having
313 // special capabilities means keep vector types untouched.
315 spirv.target_env = #spirv.target_env<
316 #spirv.vce<v1.0, [Int8, Int16, Int64, Float16, Float64], []>, #spirv.resource_limits<>>
319 // CHECK-LABEL: spirv.func @int_vector
320 // CHECK-SAME: vector<2xi8>
321 // CHECK-SAME: vector<3xsi16>
322 // CHECK-SAME: vector<4xui64>
323 func.func @int_vector(
325 %arg1: vector<3xsi16>,
326 %arg2: vector<4xui64>
329 // CHECK-LABEL: spirv.func @float_vector
330 // CHECK-SAME: vector<2xf16>
331 // CHECK-SAME: vector<3xf64>
332 func.func @float_vector(
333 %arg0: vector<2xf16>,
337 // CHECK-LABEL: spirv.func @one_element_vector
338 // CHECK-SAME: %{{.+}}: i32
339 func.func @one_element_vector(%arg0: vector<1xi32>) { return }
341 // CHECK-LABEL: spirv.func @zerod_vector
342 // CHECK-SAME: %{{.+}}: f32
343 func.func @zerod_vector(%arg0: vector<f32>) { return }
349 // Check that > 4-element vectors are not supported.
351 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [], []>, #spirv.resource_limits<>>
354 // CHECK-NOT: spirv.func @large_vector
355 func.func @large_vector(%arg0: vector<1024xi32>) { return }
361 //===----------------------------------------------------------------------===//
363 //===----------------------------------------------------------------------===//
365 // Check memory spaces.
367 spirv.target_env = #spirv.target_env<
368 #spirv.vce<v1.0, [], [SPV_KHR_storage_buffer_storage_class]>, #spirv.resource_limits<>>
371 // CHECK-LABEL: func @memref_mem_space
372 // CHECK-SAME: StorageBuffer
373 // CHECK-SAME: Uniform
374 // CHECK-SAME: Workgroup
375 // CHECK-SAME: PushConstant
376 // CHECK-SAME: Private
377 // CHECK-SAME: Function
378 func.func @memref_mem_space(
379 %arg0: memref<4xf32, #spirv.storage_class<StorageBuffer>>,
380 %arg1: memref<4xf32, #spirv.storage_class<Uniform>>,
381 %arg2: memref<4xf32, #spirv.storage_class<Workgroup>>,
382 %arg3: memref<4xf32, #spirv.storage_class<PushConstant>>,
383 %arg4: memref<4xf32, #spirv.storage_class<Private>>,
384 %arg5: memref<4xf32, #spirv.storage_class<Function>>
387 // CHECK-LABEL: func @memref_1bit_type
388 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<8 x i32, stride=4> [0])>, StorageBuffer>
389 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<8 x i32>)>, Function>
390 // NOEMU-LABEL: func @memref_1bit_type
391 // NOEMU-SAME: memref<4x8xi1, #spirv.storage_class<StorageBuffer>>
392 // NOEMU-SAME: memref<4x8xi1, #spirv.storage_class<Function>>
393 func.func @memref_1bit_type(
394 %arg0: memref<4x8xi1, #spirv.storage_class<StorageBuffer>>,
395 %arg1: memref<4x8xi1, #spirv.storage_class<Function>>
398 // CHECK-LABEL: func @memref_index_type
399 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<4 x i32, stride=4> [0])>, StorageBuffer>
400 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<4 x i32>)>, Function>
401 func.func @memref_index_type(
402 %arg0: memref<4xindex, #spirv.storage_class<StorageBuffer>>,
403 %arg1: memref<4xindex, #spirv.storage_class<Function>>
410 // Reject memory spaces.
412 spirv.target_env = #spirv.target_env<
413 #spirv.vce<v1.0, [], [SPV_KHR_storage_buffer_storage_class]>, #spirv.resource_limits<>>
416 // CHECK-LABEL: func @numeric_memref_mem_space1
417 // CHECK-SAME: memref<4xf32>
418 // NOEMU-LABEL: func @numeric_memref_mem_space1
419 // NOEMU-SAME: memref<4xf32>
420 func.func @numeric_memref_mem_space1(%arg0: memref<4xf32>) { return }
422 // CHECK-LABEL: func @numeric_memref_mem_space2
423 // CHECK-SAME: memref<4xf32, 3>
424 // NOEMU-LABEL: func @numeric_memref_mem_space2
425 // NOEMU-SAME: memref<4xf32, 3>
426 func.func @numeric_memref_mem_space2(%arg0: memref<4xf32, 3>) { return }
432 // Check that using non-32-bit scalar types in interface storage classes
433 // requires special capability and extension: convert them to 32-bit if not
436 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [], []>, #spirv.resource_limits<>>
439 // An i1 is store in 8-bit, so 5xi1 has 40 bits, which is stored in 2xi32.
440 // CHECK-LABEL: spirv.func @memref_1bit_type
441 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<2 x i32, stride=4> [0])>, StorageBuffer>
442 // NOEMU-LABEL: func @memref_1bit_type
443 // NOEMU-SAME: memref<5xi1, #spirv.storage_class<StorageBuffer>>
444 func.func @memref_1bit_type(%arg0: memref<5xi1, #spirv.storage_class<StorageBuffer>>) { return }
446 // 16 i2 values are tightly packed into one i32 value; so 33 i2 values takes 3 i32 value.
447 // CHECK-LABEL: spirv.func @memref_2bit_type
448 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<3 x i32, stride=4> [0])>, StorageBuffer>
449 func.func @memref_2bit_type(%arg0: memref<33xi2, #spirv.storage_class<StorageBuffer>>) { return }
451 // 8 i4 values are tightly packed into one i32 value; so 16 i4 values takes 2 i32 value.
452 // CHECK-LABEL: spirv.func @memref_4bit_type
453 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<2 x i32, stride=4> [0])>, StorageBuffer>
454 func.func @memref_4bit_type(%arg0: memref<16xi4, #spirv.storage_class<StorageBuffer>>) { return }
456 // CHECK-LABEL: spirv.func @memref_8bit_StorageBuffer
457 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<4 x i32, stride=4> [0])>, StorageBuffer>
458 // NOEMU-LABEL: func @memref_8bit_StorageBuffer
459 // NOEMU-SAME: memref<16xi8, #spirv.storage_class<StorageBuffer>>
460 func.func @memref_8bit_StorageBuffer(%arg0: memref<16xi8, #spirv.storage_class<StorageBuffer>>) { return }
462 // CHECK-LABEL: spirv.func @memref_8bit_Uniform
463 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<4 x si32, stride=4> [0])>, Uniform>
464 // NOEMU-LABEL: func @memref_8bit_Uniform
465 // NOEMU-SAME: memref<16xsi8, #spirv.storage_class<Uniform>>
466 func.func @memref_8bit_Uniform(%arg0: memref<16xsi8, #spirv.storage_class<Uniform>>) { return }
468 // CHECK-LABEL: spirv.func @memref_8bit_PushConstant
469 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<4 x ui32, stride=4> [0])>, PushConstant>
470 // NOEMU-LABEL: func @memref_8bit_PushConstant
471 // NOEMU-SAME: memref<16xui8, #spirv.storage_class<PushConstant>>
472 func.func @memref_8bit_PushConstant(%arg0: memref<16xui8, #spirv.storage_class<PushConstant>>) { return }
474 // CHECK-LABEL: spirv.func @memref_16bit_StorageBuffer
475 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<8 x i32, stride=4> [0])>, StorageBuffer>
476 // NOEMU-LABEL: func @memref_16bit_StorageBuffer
477 // NOEMU-SAME: memref<16xi16, #spirv.storage_class<StorageBuffer>>
478 func.func @memref_16bit_StorageBuffer(%arg0: memref<16xi16, #spirv.storage_class<StorageBuffer>>) { return }
480 // CHECK-LABEL: spirv.func @memref_16bit_Uniform
481 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<8 x si32, stride=4> [0])>, Uniform>
482 // NOEMU-LABEL: func @memref_16bit_Uniform
483 // NOEMU-SAME: memref<16xsi16, #spirv.storage_class<Uniform>>
484 func.func @memref_16bit_Uniform(%arg0: memref<16xsi16, #spirv.storage_class<Uniform>>) { return }
486 // CHECK-LABEL: spirv.func @memref_16bit_PushConstant
487 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<8 x ui32, stride=4> [0])>, PushConstant>
488 // NOEMU-LABEL: func @memref_16bit_PushConstant
489 // NOEMU-SAME: memref<16xui16, #spirv.storage_class<PushConstant>>
490 func.func @memref_16bit_PushConstant(%arg0: memref<16xui16, #spirv.storage_class<PushConstant>>) { return }
492 // CHECK-LABEL: spirv.func @memref_16bit_Input
493 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<8 x f32>)>, Input>
494 // NOEMU-LABEL: func @memref_16bit_Input
495 // NOEMU-SAME: memref<16xf16, #spirv.storage_class<Input>>
496 func.func @memref_16bit_Input(%arg3: memref<16xf16, #spirv.storage_class<Input>>) { return }
498 // CHECK-LABEL: spirv.func @memref_16bit_Output
499 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<8 x f32>)>, Output>
500 // NOEMU-LABEL: func @memref_16bit_Output
501 // NOEMU-SAME: memref<16xf16, #spirv.storage_class<Output>>
502 func.func @memref_16bit_Output(%arg4: memref<16xf16, #spirv.storage_class<Output>>) { return }
504 // We do not truncate i64 to i32.
506 // CHECK-LABEL: func.func @memref_64bit_StorageBuffer
507 // CHECK-SAME: memref<16xi64, #spirv.storage_class<StorageBuffer>>
508 // NOEMU-LABEL: func.func @memref_64bit_StorageBuffer
509 // NOEMU-SAME: memref<16xi64, #spirv.storage_class<StorageBuffer>>
510 func.func @memref_64bit_StorageBuffer(%arg0: memref<16xi64, #spirv.storage_class<StorageBuffer>>) { return }
512 // CHECK-LABEL: func.func @memref_64bit_Uniform
513 // CHECK-SAME: memref<16xsi64, #spirv.storage_class<Uniform>>
514 // NOEMU-LABEL: func.func @memref_64bit_Uniform
515 // NOEMU-SAME: memref<16xsi64, #spirv.storage_class<Uniform>>
516 func.func @memref_64bit_Uniform(%arg0: memref<16xsi64, #spirv.storage_class<Uniform>>) { return }
518 // CHECK-LABEL: func.func @memref_64bit_PushConstant
519 // CHECK-SAME: memref<16xui64, #spirv.storage_class<PushConstant>>
520 // NOEMU-LABEL: func.func @memref_64bit_PushConstant
521 // NOEMU-SAME: memref<16xui64, #spirv.storage_class<PushConstant>>
522 func.func @memref_64bit_PushConstant(%arg0: memref<16xui64, #spirv.storage_class<PushConstant>>) { return }
524 // CHECK-LABEL: func.func @memref_64bit_Input
525 // CHECK-SAME: memref<16xf64, #spirv.storage_class<Input>>
526 // NOEMU-LABEL: func.func @memref_64bit_Input
527 // NOEMU-SAME: memref<16xf64, #spirv.storage_class<Input>>
528 func.func @memref_64bit_Input(%arg3: memref<16xf64, #spirv.storage_class<Input>>) { return }
530 // CHECK-LABEL: func.func @memref_64bit_Output
531 // CHECK-SAME: memref<16xf64, #spirv.storage_class<Output>>
532 // NOEMU-LABEL: func.func @memref_64bit_Output
533 // NOEMU-SAME: memref<16xf64, #spirv.storage_class<Output>>
534 func.func @memref_64bit_Output(%arg4: memref<16xf64, #spirv.storage_class<Output>>) { return }
540 // Check that using non-32-bit scalar types in interface storage classes
541 // requires special capability and extension: keep as-is when the capability
542 // and extension is available.
544 spirv.target_env = #spirv.target_env<
545 #spirv.vce<v1.0, [StoragePushConstant8, StoragePushConstant16, Int64, Float64],
546 [SPV_KHR_8bit_storage, SPV_KHR_16bit_storage]>, #spirv.resource_limits<>>
549 // CHECK-LABEL: spirv.func @memref_8bit_PushConstant
550 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x i8, stride=1> [0])>, PushConstant>
551 // NOEMU-LABEL: spirv.func @memref_8bit_PushConstant
552 // NOEMU-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x i8, stride=1> [0])>, PushConstant>
553 func.func @memref_8bit_PushConstant(%arg0: memref<16xi8, #spirv.storage_class<PushConstant>>) { return }
555 // CHECK-LABEL: spirv.func @memref_16bit_PushConstant
556 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x i16, stride=2> [0])>, PushConstant>
557 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x f16, stride=2> [0])>, PushConstant>
558 // NOEMU-LABEL: spirv.func @memref_16bit_PushConstant
559 // NOEMU-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x i16, stride=2> [0])>, PushConstant>
560 // NOEMU-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x f16, stride=2> [0])>, PushConstant>
561 func.func @memref_16bit_PushConstant(
562 %arg0: memref<16xi16, #spirv.storage_class<PushConstant>>,
563 %arg1: memref<16xf16, #spirv.storage_class<PushConstant>>
566 // CHECK-LABEL: spirv.func @memref_64bit_PushConstant
567 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x i64, stride=8> [0])>, PushConstant>
568 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x f64, stride=8> [0])>, PushConstant>
569 // NOEMU-LABEL: spirv.func @memref_64bit_PushConstant
570 // NOEMU-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x i64, stride=8> [0])>, PushConstant>
571 // NOEMU-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x f64, stride=8> [0])>, PushConstant>
572 func.func @memref_64bit_PushConstant(
573 %arg0: memref<16xi64, #spirv.storage_class<PushConstant>>,
574 %arg1: memref<16xf64, #spirv.storage_class<PushConstant>>
581 // Check that using non-32-bit scalar types in interface storage classes
582 // requires special capability and extension: keep as-is when the capability
583 // and extension is available.
585 spirv.target_env = #spirv.target_env<
586 #spirv.vce<v1.0, [StorageBuffer8BitAccess, StorageBuffer16BitAccess, Int64, Float64],
587 [SPV_KHR_8bit_storage, SPV_KHR_16bit_storage]>, #spirv.resource_limits<>>
590 // CHECK-LABEL: spirv.func @memref_8bit_StorageBuffer
591 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x i8, stride=1> [0])>, StorageBuffer>
592 // NOEMU-LABEL: spirv.func @memref_8bit_StorageBuffer
593 // NOEMU-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x i8, stride=1> [0])>, StorageBuffer>
594 func.func @memref_8bit_StorageBuffer(%arg0: memref<16xi8, #spirv.storage_class<StorageBuffer>>) { return }
596 // CHECK-LABEL: spirv.func @memref_16bit_StorageBuffer
597 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x i16, stride=2> [0])>, StorageBuffer>
598 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x f16, stride=2> [0])>, StorageBuffer>
599 // NOEMU-LABEL: spirv.func @memref_16bit_StorageBuffer
600 // NOEMU-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x i16, stride=2> [0])>, StorageBuffer>
601 // NOEMU-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x f16, stride=2> [0])>, StorageBuffer>
602 func.func @memref_16bit_StorageBuffer(
603 %arg0: memref<16xi16, #spirv.storage_class<StorageBuffer>>,
604 %arg1: memref<16xf16, #spirv.storage_class<StorageBuffer>>
607 // CHECK-LABEL: spirv.func @memref_64bit_StorageBuffer
608 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x i64, stride=8> [0])>, StorageBuffer>
609 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x f64, stride=8> [0])>, StorageBuffer>
610 // NOEMU-LABEL: spirv.func @memref_64bit_StorageBuffer
611 // NOEMU-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x i64, stride=8> [0])>, StorageBuffer>
612 // NOEMU-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x f64, stride=8> [0])>, StorageBuffer>
613 func.func @memref_64bit_StorageBuffer(
614 %arg0: memref<16xi64, #spirv.storage_class<StorageBuffer>>,
615 %arg1: memref<16xf64, #spirv.storage_class<StorageBuffer>>
622 // Check that using non-32-bit scalar types in interface storage classes
623 // requires special capability and extension: keep as-is when the capability
624 // and extension is available.
626 spirv.target_env = #spirv.target_env<
627 #spirv.vce<v1.0, [UniformAndStorageBuffer8BitAccess, StorageUniform16, Int64, Float64],
628 [SPV_KHR_8bit_storage, SPV_KHR_16bit_storage]>, #spirv.resource_limits<>>
631 // CHECK-LABEL: spirv.func @memref_8bit_Uniform
632 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x i8, stride=1> [0])>, Uniform>
633 // NOEMU-LABEL: spirv.func @memref_8bit_Uniform
634 // NOEMU-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x i8, stride=1> [0])>, Uniform>
635 func.func @memref_8bit_Uniform(%arg0: memref<16xi8, #spirv.storage_class<Uniform>>) { return }
637 // CHECK-LABEL: spirv.func @memref_16bit_Uniform
638 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x i16, stride=2> [0])>, Uniform>
639 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x f16, stride=2> [0])>, Uniform>
640 // NOEMU-LABEL: spirv.func @memref_16bit_Uniform
641 // NOEMU-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x i16, stride=2> [0])>, Uniform>
642 // NOEMU-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x f16, stride=2> [0])>, Uniform>
643 func.func @memref_16bit_Uniform(
644 %arg0: memref<16xi16, #spirv.storage_class<Uniform>>,
645 %arg1: memref<16xf16, #spirv.storage_class<Uniform>>
648 // CHECK-LABEL: spirv.func @memref_64bit_Uniform
649 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x i64, stride=8> [0])>, Uniform>
650 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x f64, stride=8> [0])>, Uniform>
651 // NOEMU-LABEL: spirv.func @memref_64bit_Uniform
652 // NOEMU-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x i64, stride=8> [0])>, Uniform>
653 // NOEMU-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x f64, stride=8> [0])>, Uniform>
654 func.func @memref_64bit_Uniform(
655 %arg0: memref<16xi64, #spirv.storage_class<Uniform>>,
656 %arg1: memref<16xf64, #spirv.storage_class<Uniform>>
663 // Check that using non-32-bit scalar types in interface storage classes
664 // requires special capability and extension: keep as-is when the capability
665 // and extension is available.
667 spirv.target_env = #spirv.target_env<
668 #spirv.vce<v1.0, [StorageInputOutput16, Int64, Float64], [SPV_KHR_16bit_storage]>, #spirv.resource_limits<>>
671 // CHECK-LABEL: spirv.func @memref_16bit_Input
672 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x f16>)>, Input>
673 // NOEMU-LABEL: spirv.func @memref_16bit_Input
674 // NOEMU-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x f16>)>, Input>
675 func.func @memref_16bit_Input(%arg3: memref<16xf16, #spirv.storage_class<Input>>) { return }
677 // CHECK-LABEL: spirv.func @memref_16bit_Output
678 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x i16>)>, Output>
679 // NOEMU-LABEL: spirv.func @memref_16bit_Output
680 // NOEMU-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x i16>)>, Output>
681 func.func @memref_16bit_Output(%arg4: memref<16xi16, #spirv.storage_class<Output>>) { return }
683 // CHECK-LABEL: spirv.func @memref_64bit_Input
684 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x i64>)>, Input>
685 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x f64>)>, Input>
686 // NOEMU-LABEL: spirv.func @memref_64bit_Input
687 // NOEMU-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x i64>)>, Input>
688 // NOEMU-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x f64>)>, Input>
689 func.func @memref_64bit_Input(
690 %arg0: memref<16xi64, #spirv.storage_class<Input>>,
691 %arg1: memref<16xf64, #spirv.storage_class<Input>>
694 // CHECK-LABEL: spirv.func @memref_64bit_Output
695 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x i64>)>, Output>
696 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x f64>)>, Output>
697 // NOEMU-LABEL: spirv.func @memref_64bit_Output
698 // NOEMU-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x i64>)>, Output>
699 // NOEMU-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<16 x f64>)>, Output>
700 func.func @memref_64bit_Output(
701 %arg0: memref<16xi64, #spirv.storage_class<Output>>,
702 %arg1: memref<16xf64, #spirv.storage_class<Output>>
709 // Check that memref offset and strides affect the array size.
711 spirv.target_env = #spirv.target_env<
712 #spirv.vce<v1.0, [StorageBuffer16BitAccess], [SPV_KHR_16bit_storage]>, #spirv.resource_limits<>>
715 // CHECK-LABEL: spirv.func @memref_offset_strides
716 func.func @memref_offset_strides(
717 // CHECK-SAME: !spirv.array<64 x f32, stride=4> [0])>, StorageBuffer>
718 // CHECK-SAME: !spirv.array<72 x f32, stride=4> [0])>, StorageBuffer>
719 // CHECK-SAME: !spirv.array<256 x f32, stride=4> [0])>, StorageBuffer>
720 // CHECK-SAME: !spirv.array<64 x f32, stride=4> [0])>, StorageBuffer>
721 // CHECK-SAME: !spirv.array<88 x f32, stride=4> [0])>, StorageBuffer>
722 %arg0: memref<16x4xf32, strided<[4, 1], offset: 0>, #spirv.storage_class<StorageBuffer>>, // tightly packed; row major
723 %arg1: memref<16x4xf32, strided<[4, 1], offset: 8>, #spirv.storage_class<StorageBuffer>>, // offset 8
724 %arg2: memref<16x4xf32, strided<[16, 1], offset: 0>, #spirv.storage_class<StorageBuffer>>, // pad 12 after each row
725 %arg3: memref<16x4xf32, strided<[1, 16], offset: 0>, #spirv.storage_class<StorageBuffer>>, // tightly packed; col major
726 %arg4: memref<16x4xf32, strided<[1, 22], offset: 0>, #spirv.storage_class<StorageBuffer>>, // pad 4 after each col
728 // CHECK-SAME: !spirv.array<64 x f16, stride=2> [0])>, StorageBuffer>
729 // CHECK-SAME: !spirv.array<72 x f16, stride=2> [0])>, StorageBuffer>
730 // CHECK-SAME: !spirv.array<256 x f16, stride=2> [0])>, StorageBuffer>
731 // CHECK-SAME: !spirv.array<64 x f16, stride=2> [0])>, StorageBuffer>
732 // CHECK-SAME: !spirv.array<88 x f16, stride=2> [0])>, StorageBuffer>
733 %arg5: memref<16x4xf16, strided<[4, 1], offset: 0>, #spirv.storage_class<StorageBuffer>>,
734 %arg6: memref<16x4xf16, strided<[4, 1], offset: 8>, #spirv.storage_class<StorageBuffer>>,
735 %arg7: memref<16x4xf16, strided<[16, 1], offset: 0>, #spirv.storage_class<StorageBuffer>>,
736 %arg8: memref<16x4xf16, strided<[1, 16], offset: 0>, #spirv.storage_class<StorageBuffer>>,
737 %arg9: memref<16x4xf16, strided<[1, 22], offset: 0>, #spirv.storage_class<StorageBuffer>>
746 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [], []>, #spirv.resource_limits<>>
749 // Check that unranked shapes are not supported.
750 // CHECK-LABEL: func @unranked_memref
751 // CHECK-SAME: memref<*xi32>
752 func.func @unranked_memref(%arg0: memref<*xi32>) { return }
754 // CHECK-LABEL: func @memref_1bit_type
755 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.rtarray<i32, stride=4> [0])>, StorageBuffer>
756 // NOEMU-LABEL: func @memref_1bit_type
757 // NOEMU-SAME: memref<?xi1, #spirv.storage_class<StorageBuffer>>
758 func.func @memref_1bit_type(%arg0: memref<?xi1, #spirv.storage_class<StorageBuffer>>) { return }
760 // CHECK-LABEL: spirv.func @memref_2bit_type
761 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.rtarray<i32, stride=4> [0])>, StorageBuffer>
762 func.func @memref_2bit_type(%arg0: memref<?xi2, #spirv.storage_class<StorageBuffer>>) { return }
764 // CHECK-LABEL: spirv.func @memref_4bit_type
765 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.rtarray<i32, stride=4> [0])>, StorageBuffer>
766 func.func @memref_4bit_type(%arg0: memref<?xi4, #spirv.storage_class<StorageBuffer>>) { return }
768 // CHECK-LABEL: func @dynamic_dim_memref
769 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.rtarray<i32, stride=4> [0])>, StorageBuffer>
770 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.rtarray<f32, stride=4> [0])>, StorageBuffer>
771 func.func @dynamic_dim_memref(
772 %arg0: memref<8x?xi32, #spirv.storage_class<StorageBuffer>>,
773 %arg1: memref<?x?xf32, #spirv.storage_class<StorageBuffer>>) { return }
775 // Check that using non-32-bit scalar types in interface storage classes
776 // requires special capability and extension: convert them to 32-bit if not
779 // CHECK-LABEL: spirv.func @memref_8bit_StorageBuffer
780 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.rtarray<i32, stride=4> [0])>, StorageBuffer>
781 // NOEMU-LABEL: func @memref_8bit_StorageBuffer
782 // NOEMU-SAME: memref<?xi8, #spirv.storage_class<StorageBuffer>>
783 func.func @memref_8bit_StorageBuffer(%arg0: memref<?xi8, #spirv.storage_class<StorageBuffer>>) { return }
785 // CHECK-LABEL: spirv.func @memref_8bit_Uniform
786 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.rtarray<si32, stride=4> [0])>, Uniform>
787 // NOEMU-LABEL: func @memref_8bit_Uniform
788 // NOEMU-SAME: memref<?xsi8, #spirv.storage_class<Uniform>>
789 func.func @memref_8bit_Uniform(%arg0: memref<?xsi8, #spirv.storage_class<Uniform>>) { return }
791 // CHECK-LABEL: spirv.func @memref_8bit_PushConstant
792 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.rtarray<ui32, stride=4> [0])>, PushConstant>
793 // NOEMU-LABEL: func @memref_8bit_PushConstant
794 // NOEMU-SAME: memref<?xui8, #spirv.storage_class<PushConstant>>
795 func.func @memref_8bit_PushConstant(%arg0: memref<?xui8, #spirv.storage_class<PushConstant>>) { return }
797 // CHECK-LABEL: spirv.func @memref_16bit_StorageBuffer
798 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.rtarray<i32, stride=4> [0])>, StorageBuffer>
799 // NOEMU-LABEL: func @memref_16bit_StorageBuffer
800 // NOEMU-SAME: memref<?xi16, #spirv.storage_class<StorageBuffer>>
801 func.func @memref_16bit_StorageBuffer(%arg0: memref<?xi16, #spirv.storage_class<StorageBuffer>>) { return }
803 // CHECK-LABEL: spirv.func @memref_16bit_Uniform
804 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.rtarray<si32, stride=4> [0])>, Uniform>
805 // NOEMU-LABEL: func @memref_16bit_Uniform
806 // NOEMU-SAME: memref<?xsi16, #spirv.storage_class<Uniform>>
807 func.func @memref_16bit_Uniform(%arg0: memref<?xsi16, #spirv.storage_class<Uniform>>) { return }
809 // CHECK-LABEL: spirv.func @memref_16bit_PushConstant
810 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.rtarray<ui32, stride=4> [0])>, PushConstant>
811 // NOEMU-LABEL: func @memref_16bit_PushConstant
812 // NOEMU-SAME: memref<?xui16, #spirv.storage_class<PushConstant>>
813 func.func @memref_16bit_PushConstant(%arg0: memref<?xui16, #spirv.storage_class<PushConstant>>) { return }
815 // CHECK-LABEL: spirv.func @memref_16bit_Input
816 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.rtarray<f32>)>, Input>
817 // NOEMU-LABEL: func @memref_16bit_Input
818 // NOEMU-SAME: memref<?xf16, #spirv.storage_class<Input>>
819 func.func @memref_16bit_Input(%arg3: memref<?xf16, #spirv.storage_class<Input>>) { return }
821 // CHECK-LABEL: spirv.func @memref_16bit_Output
822 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.rtarray<f32>)>, Output>
823 // NOEMU-LABEL: func @memref_16bit_Output
824 // NOEMU-SAME: memref<?xf16, #spirv.storage_class<Output>>
825 func.func @memref_16bit_Output(%arg4: memref<?xf16, #spirv.storage_class<Output>>) { return }
833 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [], []>, #spirv.resource_limits<>>
836 // CHECK-LABEL: func @memref_vector
837 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<4 x vector<2xf32>, stride=8> [0])>, StorageBuffer>
838 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.array<4 x vector<4xf32>, stride=16> [0])>, Uniform>
839 func.func @memref_vector(
840 %arg0: memref<4xvector<2xf32>, #spirv.storage_class<StorageBuffer>>,
841 %arg1: memref<4xvector<4xf32>, #spirv.storage_class<Uniform>>)
844 // CHECK-LABEL: func @dynamic_dim_memref_vector
845 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<4xi32>, stride=16> [0])>, StorageBuffer>
846 // CHECK-SAME: !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<2xf32>, stride=8> [0])>, StorageBuffer>
847 func.func @dynamic_dim_memref_vector(
848 %arg0: memref<8x?xvector<4xi32>, #spirv.storage_class<StorageBuffer>>,
849 %arg1: memref<?x?xvector<2xf32>, #spirv.storage_class<StorageBuffer>>)
856 // Vector types, check that sizes not available in SPIR-V are not transformed.
858 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [], []>, #spirv.resource_limits<>>
861 // CHECK-LABEL: func @memref_vector_wrong_size
862 // CHECK-SAME: memref<4xvector<5xf32>, #spirv.storage_class<StorageBuffer>>
863 func.func @memref_vector_wrong_size(
864 %arg0: memref<4xvector<5xf32>, #spirv.storage_class<StorageBuffer>>)
871 //===----------------------------------------------------------------------===//
873 //===----------------------------------------------------------------------===//
875 // Check that tensor element types are kept untouched with proper capabilities.
877 spirv.target_env = #spirv.target_env<
878 #spirv.vce<v1.0, [Int8, Int16, Int64, Float16, Float64], []>, #spirv.resource_limits<>>
881 // CHECK-LABEL: spirv.func @int_tensor_types
882 // CHECK-SAME: !spirv.array<32 x i64>
883 // CHECK-SAME: !spirv.array<32 x i32>
884 // CHECK-SAME: !spirv.array<32 x i16>
885 // CHECK-SAME: !spirv.array<32 x i8>
886 func.func @int_tensor_types(
887 %arg0: tensor<8x4xi64>,
888 %arg1: tensor<8x4xi32>,
889 %arg2: tensor<8x4xi16>,
890 %arg3: tensor<8x4xi8>
893 // CHECK-LABEL: spirv.func @float_tensor_types
894 // CHECK-SAME: !spirv.array<32 x f64>
895 // CHECK-SAME: !spirv.array<32 x f32>
896 // CHECK-SAME: !spirv.array<32 x f16>
897 func.func @float_tensor_types(
898 %arg0: tensor<8x4xf64>,
899 %arg1: tensor<8x4xf32>,
900 %arg2: tensor<8x4xf16>
907 // Check that tensor element types are changed to 32-bit without capabilities.
909 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [], []>, #spirv.resource_limits<>>
912 // CHECK-LABEL: spirv.func @int_tensor_types
913 // CHECK-SAME: !spirv.array<32 x i32>
914 // CHECK-SAME: !spirv.array<32 x i32>
915 // CHECK-SAME: !spirv.array<32 x i32>
916 func.func @int_tensor_types(
917 %arg1: tensor<8x4xi32>,
918 %arg2: tensor<8x4xi16>,
919 %arg3: tensor<8x4xi8>
922 // CHECK-LABEL: spirv.func @float_tensor_types
923 // CHECK-SAME: !spirv.array<32 x f32>
924 // CHECK-SAME: !spirv.array<32 x f32>
925 func.func @float_tensor_types(
926 %arg1: tensor<8x4xf32>,
927 %arg2: tensor<8x4xf16>
931 // CHECK-LABEL: spirv.func @index_tensor_type
932 // CHECK-SAME: %{{.*}}: !spirv.array<20 x i32>
933 func.func @index_tensor_type(%arg0: tensor<4x5xindex>) { return }
939 // Check that dynamic shapes are not supported.
941 spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [], []>, #spirv.resource_limits<>>
944 // CHECK-LABEL: func @unranked_tensor
945 // CHECK-SAME: tensor<*xi32>
946 func.func @unranked_tensor(%arg0: tensor<*xi32>) { return }
948 // CHECK-LABEL: func @dynamic_dim_tensor
949 // CHECK-SAME: tensor<8x?xi32>
950 func.func @dynamic_dim_tensor(%arg0: tensor<8x?xi32>) { return }