xref: /llvm-project/mlir/test/Dialect/SPIRV/IR/memory-ops.mlir (revision 2a30bfcef368667247ebbe30be84f73b92dbe800)
1// RUN: mlir-opt -split-input-file -verify-diagnostics %s | FileCheck %s
2
3//===----------------------------------------------------------------------===//
4// spirv.AccessChain
5//===----------------------------------------------------------------------===//
6
7func.func @access_chain_struct() -> () {
8  %0 = spirv.Constant 1: i32
9  %1 = spirv.Variable : !spirv.ptr<!spirv.struct<(f32, !spirv.array<4xf32>)>, Function>
10  // CHECK: spirv.AccessChain {{.*}}[{{.*}}, {{.*}}] : !spirv.ptr<!spirv.struct<(f32, !spirv.array<4 x f32>)>, Function>
11  %2 = spirv.AccessChain %1[%0, %0] : !spirv.ptr<!spirv.struct<(f32, !spirv.array<4xf32>)>, Function>, i32, i32 -> !spirv.ptr<f32, Function>
12  return
13}
14
15func.func @access_chain_1D_array(%arg0 : i32) -> () {
16  %0 = spirv.Variable : !spirv.ptr<!spirv.array<4xf32>, Function>
17  // CHECK: spirv.AccessChain {{.*}}[{{.*}}] : !spirv.ptr<!spirv.array<4 x f32>, Function>
18  %1 = spirv.AccessChain %0[%arg0] : !spirv.ptr<!spirv.array<4xf32>, Function>, i32 -> !spirv.ptr<f32, Function>
19  return
20}
21
22func.func @access_chain_2D_array_1(%arg0 : i32) -> () {
23  %0 = spirv.Variable : !spirv.ptr<!spirv.array<4x!spirv.array<4xf32>>, Function>
24  // CHECK: spirv.AccessChain {{.*}}[{{.*}}, {{.*}}] : !spirv.ptr<!spirv.array<4 x !spirv.array<4 x f32>>, Function>
25  %1 = spirv.AccessChain %0[%arg0, %arg0] : !spirv.ptr<!spirv.array<4x!spirv.array<4xf32>>, Function>, i32, i32 -> !spirv.ptr<f32, Function>
26  %2 = spirv.Load "Function" %1 ["Volatile"] : f32
27  return
28}
29
30func.func @access_chain_2D_array_2(%arg0 : i32) -> () {
31  %0 = spirv.Variable : !spirv.ptr<!spirv.array<4x!spirv.array<4xf32>>, Function>
32  // CHECK: spirv.AccessChain {{.*}}[{{.*}}] : !spirv.ptr<!spirv.array<4 x !spirv.array<4 x f32>>, Function>
33  %1 = spirv.AccessChain %0[%arg0] : !spirv.ptr<!spirv.array<4x!spirv.array<4xf32>>, Function>, i32 -> !spirv.ptr<!spirv.array<4xf32>, Function>
34  %2 = spirv.Load "Function" %1 ["Volatile"] : !spirv.array<4xf32>
35  return
36}
37
38func.func @access_chain_rtarray(%arg0 : i32) -> () {
39  %0 = spirv.Variable : !spirv.ptr<!spirv.rtarray<f32>, Function>
40  // CHECK: spirv.AccessChain {{.*}}[{{.*}}] : !spirv.ptr<!spirv.rtarray<f32>, Function>
41  %1 = spirv.AccessChain %0[%arg0] : !spirv.ptr<!spirv.rtarray<f32>, Function>, i32 -> !spirv.ptr<f32, Function>
42  %2 = spirv.Load "Function" %1 ["Volatile"] : f32
43  return
44}
45
46// -----
47
48func.func @access_chain_non_composite() -> () {
49  %0 = spirv.Constant 1: i32
50  %1 = spirv.Variable : !spirv.ptr<f32, Function>
51  // expected-error @+1 {{cannot extract from non-composite type 'f32' with index 0}}
52  %2 = spirv.AccessChain %1[%0] : !spirv.ptr<f32, Function>, i32 -> !spirv.ptr<f32, Function>
53  return
54}
55
56// -----
57
58func.func @access_chain_no_indices(%index0 : i32) -> () {
59  %0 = spirv.Variable : !spirv.ptr<!spirv.array<4x!spirv.array<4xf32>>, Function>
60  // expected-error @+1 {{custom op 'spirv.AccessChain' number of operands and types do not match: got 0 operands and 1 types}}
61  %1 = spirv.AccessChain %0[] : !spirv.ptr<!spirv.array<4x!spirv.array<4xf32>>, Function>, i32 -> !spirv.ptr<f32, Function>
62  return
63}
64
65// -----
66
67func.func @access_chain_missing_comma(%index0 : i32) -> () {
68  %0 = spirv.Variable : !spirv.ptr<!spirv.array<4x!spirv.array<4xf32>>, Function>
69  // expected-error @+1 {{expected ','}}
70  %1 = spirv.AccessChain %0[%index0] : !spirv.ptr<!spirv.array<4x!spirv.array<4xf32>>, Function> i32
71  return
72}
73
74// -----
75
76func.func @access_chain_invalid_indices_types_count(%index0 : i32) -> () {
77  %0 = spirv.Variable : !spirv.ptr<!spirv.array<4x!spirv.array<4xf32>>, Function>
78  // expected-error @+1 {{custom op 'spirv.AccessChain' number of operands and types do not match: got 1 operands and 2 types}}
79  %1 = spirv.AccessChain %0[%index0] : !spirv.ptr<!spirv.array<4x!spirv.array<4xf32>>, Function>, i32, i32 -> !spirv.ptr<!spirv.array<4xf32>, Function>
80  return
81}
82
83// -----
84
85func.func @access_chain_missing_indices_type(%index0 : i32) -> () {
86  %0 = spirv.Variable : !spirv.ptr<!spirv.array<4x!spirv.array<4xf32>>, Function>
87  // expected-error @+1 {{custom op 'spirv.AccessChain' number of operands and types do not match: got 2 operands and 1 types}}
88  %1 = spirv.AccessChain %0[%index0, %index0] : !spirv.ptr<!spirv.array<4x!spirv.array<4xf32>>, Function>, i32 -> !spirv.ptr<f32, Function>
89  return
90}
91
92// -----
93
94func.func @access_chain_invalid_type(%index0 : i32) -> () {
95  %0 = spirv.Variable : !spirv.ptr<!spirv.array<4x!spirv.array<4xf32>>, Function>
96  %1 = spirv.Load "Function" %0 ["Volatile"] : !spirv.array<4x!spirv.array<4xf32>>
97  // expected-error @+1 {{'spirv.AccessChain' op operand #0 must be any SPIR-V pointer type, but got '!spirv.array<4 x !spirv.array<4 x f32>>'}}
98  %2 = spirv.AccessChain %1[%index0] : !spirv.array<4x!spirv.array<4xf32>>, i32 -> f32
99  return
100}
101
102// -----
103
104func.func @access_chain_invalid_index_1(%index0 : i32) -> () {
105   %0 = spirv.Variable : !spirv.ptr<!spirv.array<4x!spirv.array<4xf32>>, Function>
106  // expected-error @+1 {{expected SSA operand}}
107  %1 = spirv.AccessChain %0[%index, 4] : !spirv.ptr<!spirv.array<4x!spirv.array<4xf32>>, Function>, i32, i32
108  return
109}
110
111// -----
112
113func.func @access_chain_invalid_index_2(%index0 : i32) -> () {
114  %0 = spirv.Variable : !spirv.ptr<!spirv.struct<(f32, !spirv.array<4xf32>)>, Function>
115  // expected-error @+1 {{index must be an integer spirv.Constant to access element of spirv.struct}}
116  %1 = spirv.AccessChain %0[%index0, %index0] : !spirv.ptr<!spirv.struct<(f32, !spirv.array<4xf32>)>, Function>, i32, i32 -> !spirv.ptr<f32, Function>
117  return
118}
119
120// -----
121
122func.func @access_chain_invalid_constant_type_1() -> () {
123  %0 = arith.constant 1: i32
124  %1 = spirv.Variable : !spirv.ptr<!spirv.struct<(f32, !spirv.array<4xf32>)>, Function>
125  // expected-error @+1 {{index must be an integer spirv.Constant to access element of spirv.struct, but provided arith.constant}}
126  %2 = spirv.AccessChain %1[%0, %0] : !spirv.ptr<!spirv.struct<(f32, !spirv.array<4xf32>)>, Function>, i32, i32 -> !spirv.ptr<f32, Function>
127  return
128}
129
130// -----
131
132func.func @access_chain_out_of_bounds() -> () {
133  %index0 = "spirv.Constant"() { value = 12: i32} : () -> i32
134  %0 = spirv.Variable : !spirv.ptr<!spirv.struct<(f32, !spirv.array<4xf32>)>, Function>
135  // expected-error @+1 {{'spirv.AccessChain' op index 12 out of bounds for '!spirv.struct<(f32, !spirv.array<4 x f32>)>'}}
136  %1 = spirv.AccessChain %0[%index0, %index0] : !spirv.ptr<!spirv.struct<(f32, !spirv.array<4xf32>)>, Function>, i32, i32 -> !spirv.ptr<f32, Function>
137  return
138}
139
140// -----
141
142func.func @access_chain_invalid_accessing_type(%index0 : i32) -> () {
143  %0 = spirv.Variable : !spirv.ptr<!spirv.array<4x!spirv.array<4xf32>>, Function>
144  // expected-error @+1 {{cannot extract from non-composite type 'f32' with index 0}}
145  %1 = spirv.AccessChain %0[%index0, %index0, %index0] : !spirv.ptr<!spirv.array<4x!spirv.array<4xf32>>, Function>, i32, i32, i32 -> !spirv.ptr<f32, Function>
146  return
147}
148// -----
149
150//===----------------------------------------------------------------------===//
151// spirv.LoadOp
152//===----------------------------------------------------------------------===//
153
154// CHECK-LABEL: @simple_load
155func.func @simple_load() -> () {
156  %0 = spirv.Variable : !spirv.ptr<f32, Function>
157  // CHECK: spirv.Load "Function" %{{.*}} : f32
158  %1 = spirv.Load "Function" %0 : f32
159  return
160}
161
162// CHECK-LABEL: @load_none_access
163func.func @load_none_access() -> () {
164  %0 = spirv.Variable : !spirv.ptr<f32, Function>
165  // CHECK: spirv.Load "Function" %{{.*}} ["None"] : f32
166  %1 = spirv.Load "Function" %0 ["None"] : f32
167  return
168}
169
170// CHECK-LABEL: @volatile_load
171func.func @volatile_load() -> () {
172  %0 = spirv.Variable : !spirv.ptr<f32, Function>
173  // CHECK: spirv.Load "Function" %{{.*}} ["Volatile"] : f32
174  %1 = spirv.Load "Function" %0 ["Volatile"] : f32
175  return
176}
177
178// CHECK-LABEL: @aligned_load
179func.func @aligned_load() -> () {
180  %0 = spirv.Variable : !spirv.ptr<f32, Function>
181  // CHECK: spirv.Load "Function" %{{.*}} ["Aligned", 4] : f32
182  %1 = spirv.Load "Function" %0 ["Aligned", 4] : f32
183  return
184}
185
186// CHECK-LABEL: @volatile_aligned_load
187func.func @volatile_aligned_load() -> () {
188  %0 = spirv.Variable : !spirv.ptr<f32, Function>
189  // CHECK: spirv.Load "Function" %{{.*}} ["Volatile|Aligned", 4] : f32
190  %1 = spirv.Load "Function" %0 ["Volatile|Aligned", 4] : f32
191  return
192}
193
194// -----
195
196// CHECK-LABEL: load_none_access
197func.func @load_none_access() -> () {
198  %0 = spirv.Variable : !spirv.ptr<f32, Function>
199  // CHECK: spirv.Load
200  // CHECK-SAME: ["None"]
201  %1 = "spirv.Load"(%0) {memory_access = #spirv.memory_access<None>} : (!spirv.ptr<f32, Function>) -> (f32)
202  return
203}
204
205// CHECK-LABEL: volatile_load
206func.func @volatile_load() -> () {
207  %0 = spirv.Variable : !spirv.ptr<f32, Function>
208  // CHECK: spirv.Load
209  // CHECK-SAME: ["Volatile"]
210  %1 = "spirv.Load"(%0) {memory_access = #spirv.memory_access<Volatile>} : (!spirv.ptr<f32, Function>) -> (f32)
211  return
212}
213
214// CHECK-LABEL: aligned_load
215func.func @aligned_load() -> () {
216  %0 = spirv.Variable : !spirv.ptr<f32, Function>
217  // CHECK: spirv.Load
218  // CHECK-SAME: ["Aligned", 4]
219  %1 = "spirv.Load"(%0) {memory_access = #spirv.memory_access<Aligned>, alignment = 4 : i32} : (!spirv.ptr<f32, Function>) -> (f32)
220  return
221}
222
223// CHECK-LABEL: volatile_aligned_load
224func.func @volatile_aligned_load() -> () {
225  %0 = spirv.Variable : !spirv.ptr<f32, Function>
226  // CHECK: spirv.Load
227  // CHECK-SAME: ["Volatile|Aligned", 4]
228  %1 = "spirv.Load"(%0) {memory_access = #spirv.memory_access<Volatile|Aligned>, alignment = 4 : i32} : (!spirv.ptr<f32, Function>) -> (f32)
229  return
230}
231
232// -----
233
234func.func @simple_load_missing_storageclass() -> () {
235  %0 = spirv.Variable : !spirv.ptr<f32, Function>
236  // expected-error @+1 {{expected attribute value}}
237  %1 = spirv.Load %0 : f32
238  return
239}
240
241// -----
242
243func.func @simple_load_missing_operand() -> () {
244  %0 = spirv.Variable : !spirv.ptr<f32, Function>
245  // expected-error @+1 {{expected SSA operand}}
246  %1 = spirv.Load "Function" : f32
247  return
248}
249
250// -----
251
252func.func @simple_load_missing_rettype() -> () {
253  %0 = spirv.Variable : !spirv.ptr<f32, Function>
254  // expected-error @+1 {{expected ':'}}
255  %1 = spirv.Load "Function" %0
256  return
257}
258
259// -----
260
261func.func @volatile_load_missing_lbrace() -> () {
262  %0 = spirv.Variable : !spirv.ptr<f32, Function>
263  // expected-error @+1 {{expected ':'}}
264  %1 = spirv.Load "Function" %0 "Volatile"] : f32
265  return
266}
267
268// -----
269
270func.func @volatile_load_missing_rbrace() -> () {
271  %0 = spirv.Variable : !spirv.ptr<f32, Function>
272  // expected-error @+1 {{expected ']'}}
273  %1 = spirv.Load "Function" %0 ["Volatile"} : f32
274  return
275}
276
277// -----
278
279func.func @aligned_load_missing_alignment() -> () {
280  %0 = spirv.Variable : !spirv.ptr<f32, Function>
281  // expected-error @+1 {{expected ','}}
282  %1 = spirv.Load "Function" %0 ["Aligned"] : f32
283  return
284}
285
286// -----
287
288func.func @aligned_load_missing_comma() -> () {
289  %0 = spirv.Variable : !spirv.ptr<f32, Function>
290  // expected-error @+1 {{expected ','}}
291  %1 = spirv.Load "Function" %0 ["Aligned" 4] : f32
292  return
293}
294
295// -----
296
297func.func @load_incorrect_attributes() -> () {
298  %0 = spirv.Variable : !spirv.ptr<f32, Function>
299  // expected-error @+1 {{expected ']'}}
300  %1 = spirv.Load "Function" %0 ["Volatile", 4] : f32
301  return
302}
303
304// -----
305
306func.func @load_unknown_memory_access() -> () {
307  %0 = spirv.Variable : !spirv.ptr<f32, Function>
308  // expected-error @+1 {{custom op 'spirv.Load' invalid memory_access attribute specification: "Something"}}
309  %1 = spirv.Load "Function" %0 ["Something"] : f32
310  return
311}
312
313// -----
314
315func.func @load_unknown_memory_access() -> () {
316  %0 = spirv.Variable : !spirv.ptr<f32, Function>
317  // expected-error @+1 {{custom op 'spirv.Load' invalid memory_access attribute specification: "Volatile|Something"}}
318  %1 = spirv.Load "Function" %0 ["Volatile|Something"] : f32
319  return
320}
321
322// -----
323
324func.func @load_unknown_memory_access() -> () {
325  %0 = spirv.Variable : !spirv.ptr<f32, Function>
326  // expected-error @+1 {{failed to satisfy constraint: valid SPIR-V MemoryAccess}}
327  %1 = "spirv.Load"(%0) {memory_access = 0x80000000 : i32} : (!spirv.ptr<f32, Function>) -> (f32)
328  return
329}
330
331// -----
332
333func.func @aligned_load_incorrect_attributes() -> () {
334  %0 = spirv.Variable : !spirv.ptr<f32, Function>
335  // expected-error @+1 {{expected ']'}}
336  %1 = spirv.Load "Function" %0 ["Aligned", 4, 23] : f32
337  return
338}
339
340// -----
341
342spirv.module Logical GLSL450 {
343  spirv.GlobalVariable @var0 : !spirv.ptr<f32, Input>
344  spirv.GlobalVariable @var1 : !spirv.ptr<!spirv.sampled_image<!spirv.image<f32, Dim2D, IsDepth, Arrayed, SingleSampled, NeedSampler, Unknown>>, UniformConstant>
345  // CHECK-LABEL: @simple_load
346  spirv.func @simple_load() -> () "None" {
347    // CHECK: spirv.Load "Input" {{%.*}} : f32
348    %0 = spirv.mlir.addressof @var0 : !spirv.ptr<f32, Input>
349    %1 = spirv.Load "Input" %0 : f32
350    %2 = spirv.mlir.addressof @var1 : !spirv.ptr<!spirv.sampled_image<!spirv.image<f32, Dim2D, IsDepth, Arrayed, SingleSampled, NeedSampler, Unknown>>, UniformConstant>
351    // CHECK: spirv.Load "UniformConstant" {{%.*}} : !spirv.sampled_image
352    %3 = spirv.Load "UniformConstant" %2 : !spirv.sampled_image<!spirv.image<f32, Dim2D, IsDepth, Arrayed, SingleSampled, NeedSampler, Unknown>>
353    spirv.Return
354  }
355}
356
357// -----
358
359//===----------------------------------------------------------------------===//
360// spirv.StoreOp
361//===----------------------------------------------------------------------===//
362
363func.func @simple_store(%arg0 : f32) -> () {
364  %0 = spirv.Variable : !spirv.ptr<f32, Function>
365  // CHECK: spirv.Store  "Function" %0, %arg0 : f32
366  spirv.Store  "Function" %0, %arg0 : f32
367  return
368}
369
370// CHECK-LABEL: @volatile_store
371func.func @volatile_store(%arg0 : f32) -> () {
372  %0 = spirv.Variable : !spirv.ptr<f32, Function>
373  // CHECK: spirv.Store  "Function" %0, %arg0 ["Volatile"] : f32
374  spirv.Store  "Function" %0, %arg0 ["Volatile"] : f32
375  return
376}
377
378// CHECK-LABEL: @aligned_store
379func.func @aligned_store(%arg0 : f32) -> () {
380  %0 = spirv.Variable : !spirv.ptr<f32, Function>
381  // CHECK: spirv.Store  "Function" %0, %arg0 ["Aligned", 4] : f32
382  spirv.Store  "Function" %0, %arg0 ["Aligned", 4] : f32
383  return
384}
385
386// -----
387
388func.func @simple_store_missing_ptr_type(%arg0 : f32) -> () {
389  %0 = spirv.Variable : !spirv.ptr<f32, Function>
390  // expected-error @+1 {{expected attribute value}}
391  spirv.Store  %0, %arg0 : f32
392  return
393}
394
395// -----
396
397func.func @simple_store_missing_operand(%arg0 : f32) -> () {
398  %0 = spirv.Variable : !spirv.ptr<f32, Function>
399  // expected-error @+1 {{expected operand}}
400  spirv.Store  "Function" , %arg0 : f32
401  return
402}
403
404// -----
405
406func.func @simple_store_missing_operand(%arg0 : f32) -> () {
407  %0 = spirv.Variable : !spirv.ptr<f32, Function>
408  // expected-error @+1 {{custom op 'spirv.Store' expected 2 operands}}
409  spirv.Store  "Function" %0 : f32
410  return
411}
412
413// -----
414
415func.func @volatile_store_missing_lbrace(%arg0 : f32) -> () {
416  %0 = spirv.Variable : !spirv.ptr<f32, Function>
417  // expected-error @+1 {{expected ':'}}
418  spirv.Store  "Function" %0, %arg0 "Volatile"] : f32
419  return
420}
421
422// -----
423
424func.func @volatile_store_missing_rbrace(%arg0 : f32) -> () {
425  %0 = spirv.Variable : !spirv.ptr<f32, Function>
426  // expected-error @+1 {{expected ']'}}
427  spirv.Store "Function" %0, %arg0 ["Volatile"} : f32
428  return
429}
430
431// -----
432
433func.func @aligned_store_missing_alignment(%arg0 : f32) -> () {
434  %0 = spirv.Variable : !spirv.ptr<f32, Function>
435  // expected-error @+1 {{expected ','}}
436  spirv.Store  "Function" %0, %arg0 ["Aligned"] : f32
437  return
438}
439
440// -----
441
442func.func @aligned_store_missing_comma(%arg0 : f32) -> () {
443  %0 = spirv.Variable : !spirv.ptr<f32, Function>
444  // expected-error @+1 {{expected ','}}
445  spirv.Store  "Function" %0, %arg0 ["Aligned" 4] : f32
446  return
447}
448
449// -----
450
451func.func @load_incorrect_attributes(%arg0 : f32) -> () {
452  %0 = spirv.Variable : !spirv.ptr<f32, Function>
453  // expected-error @+1 {{expected ']'}}
454  spirv.Store  "Function" %0, %arg0 ["Volatile", 4] : f32
455  return
456}
457
458// -----
459
460func.func @aligned_store_incorrect_attributes(%arg0 : f32) -> () {
461  %0 = spirv.Variable : !spirv.ptr<f32, Function>
462  // expected-error @+1 {{expected ']'}}
463  spirv.Store  "Function" %0, %arg0 ["Aligned", 4, 23] : f32
464  return
465}
466
467// -----
468
469spirv.module Logical GLSL450 {
470  spirv.GlobalVariable @var0 : !spirv.ptr<f32, Input>
471  spirv.func @simple_store(%arg0 : f32) -> () "None" {
472    %0 = spirv.mlir.addressof @var0 : !spirv.ptr<f32, Input>
473    // CHECK: spirv.Store  "Input" {{%.*}}, {{%.*}} : f32
474    spirv.Store  "Input" %0, %arg0 : f32
475    spirv.Return
476  }
477}
478
479// -----
480
481//===----------------------------------------------------------------------===//
482// spirv.Variable
483//===----------------------------------------------------------------------===//
484
485func.func @variable(%arg0: f32) -> () {
486  // CHECK: spirv.Variable : !spirv.ptr<f32, Function>
487  %0 = spirv.Variable : !spirv.ptr<f32, Function>
488  return
489}
490
491// -----
492
493func.func @variable_init_normal_constant() -> () {
494  // CHECK: %[[cst:.*]] = spirv.Constant
495  %0 = spirv.Constant 4.0 : f32
496  // CHECK: spirv.Variable init(%[[cst]]) : !spirv.ptr<f32, Function>
497  %1 = spirv.Variable init(%0) : !spirv.ptr<f32, Function>
498  return
499}
500
501// -----
502
503spirv.module Logical GLSL450 {
504  spirv.GlobalVariable @global : !spirv.ptr<f32, Workgroup>
505  spirv.func @variable_init_global_variable() -> () "None" {
506    %0 = spirv.mlir.addressof @global : !spirv.ptr<f32, Workgroup>
507    // CHECK: spirv.Variable init({{.*}}) : !spirv.ptr<!spirv.ptr<f32, Workgroup>, Function>
508    %1 = spirv.Variable init(%0) : !spirv.ptr<!spirv.ptr<f32, Workgroup>, Function>
509    spirv.Return
510  }
511}
512
513// -----
514
515spirv.module Logical GLSL450 {
516  spirv.SpecConstant @sc = 42 : i32
517  // CHECK-LABEL: @variable_init_spec_constant
518  spirv.func @variable_init_spec_constant() -> () "None" {
519    %0 = spirv.mlir.referenceof @sc : i32
520    // CHECK: spirv.Variable init(%0) : !spirv.ptr<i32, Function>
521    %1 = spirv.Variable init(%0) : !spirv.ptr<i32, Function>
522    spirv.Return
523  }
524}
525
526// -----
527
528func.func @variable_ptr_physical_buffer() -> () {
529  %0 = spirv.Variable {aliased_pointer} :
530    !spirv.ptr<!spirv.ptr<f32, PhysicalStorageBuffer>, Function>
531  %1 = spirv.Variable {restrict_pointer} :
532    !spirv.ptr<!spirv.ptr<f32, PhysicalStorageBuffer>, Function>
533  return
534}
535
536// -----
537
538func.func @variable_ptr_physical_buffer_no_decoration() -> () {
539  // expected-error @+1 {{must be decorated either 'AliasedPointer' or 'RestrictPointer'}}
540  %0 = spirv.Variable : !spirv.ptr<!spirv.ptr<f32, PhysicalStorageBuffer>, Function>
541  return
542}
543
544// -----
545
546func.func @variable_ptr_physical_buffer_two_alias_decorations() -> () {
547  // expected-error @+1 {{must have exactly one aliasing decoration}}
548  %0 = spirv.Variable {aliased_pointer, restrict_pointer} :
549    !spirv.ptr<!spirv.ptr<f32, PhysicalStorageBuffer>, Function>
550  return
551}
552
553// -----
554
555func.func @variable_ptr_array_physical_buffer() -> () {
556  %0 = spirv.Variable {aliased_pointer} :
557    !spirv.ptr<!spirv.array<4x!spirv.ptr<f32, PhysicalStorageBuffer>>, Function>
558  %1 = spirv.Variable {restrict_pointer} :
559    !spirv.ptr<!spirv.array<4x!spirv.ptr<f32, PhysicalStorageBuffer>>, Function>
560  return
561}
562
563// -----
564
565func.func @variable_ptr_array_physical_buffer_no_decoration() -> () {
566  // expected-error @+1 {{must be decorated either 'AliasedPointer' or 'RestrictPointer'}}
567  %0 = spirv.Variable :
568    !spirv.ptr<!spirv.array<4x!spirv.ptr<f32, PhysicalStorageBuffer>>, Function>
569  return
570}
571
572// -----
573
574func.func @variable_ptr_array_physical_buffer_two_alias_decorations() -> () {
575  // expected-error @+1 {{must have exactly one aliasing decoration}}
576  %0 = spirv.Variable {aliased_pointer, restrict_pointer} :
577    !spirv.ptr<!spirv.array<4x!spirv.ptr<f32, PhysicalStorageBuffer>>, Function>
578  return
579}
580
581// -----
582
583func.func @variable_bind() -> () {
584  // expected-error @+1 {{cannot have 'descriptor_set' attribute (only allowed in spirv.GlobalVariable)}}
585  %0 = spirv.Variable bind(1, 2) : !spirv.ptr<f32, Function>
586  return
587}
588
589// -----
590
591func.func @variable_init_bind() -> () {
592  %0 = spirv.Constant 4.0 : f32
593  // expected-error @+1 {{cannot have 'binding' attribute (only allowed in spirv.GlobalVariable)}}
594  %1 = spirv.Variable init(%0) {binding = 5 : i32} : !spirv.ptr<f32, Function>
595  return
596}
597
598// -----
599
600func.func @variable_builtin() -> () {
601  // expected-error @+1 {{cannot have 'built_in' attribute (only allowed in spirv.GlobalVariable)}}
602  %1 = spirv.Variable built_in("GlobalInvocationID") : !spirv.ptr<vector<3xi32>, Function>
603  return
604}
605
606// -----
607
608func.func @expect_ptr_result_type(%arg0: f32) -> () {
609  // expected-error @+1 {{expected spirv.ptr type}}
610  %0 = spirv.Variable : f32
611  return
612}
613
614// -----
615
616func.func @variable_init(%arg0: f32) -> () {
617  // expected-error @+1 {{op initializer must be the result of a constant or spirv.GlobalVariable op}}
618  %0 = spirv.Variable init(%arg0) : !spirv.ptr<f32, Function>
619  return
620}
621
622// -----
623
624func.func @cannot_be_generic_storage_class(%arg0: f32) -> () {
625  // expected-error @+1 {{op can only be used to model function-level variables. Use spirv.GlobalVariable for module-level variables}}
626  %0 = spirv.Variable : !spirv.ptr<f32, Generic>
627  return
628}
629
630// -----
631
632func.func @copy_memory_incompatible_ptrs() {
633  %0 = spirv.Variable : !spirv.ptr<f32, Function>
634  %1 = spirv.Variable : !spirv.ptr<i32, Function>
635  // expected-error @+1 {{both operands must be pointers to the same type}}
636  "spirv.CopyMemory"(%0, %1) {} : (!spirv.ptr<f32, Function>, !spirv.ptr<i32, Function>) -> ()
637  spirv.Return
638}
639
640// -----
641
642func.func @copy_memory_invalid_maa() {
643  %0 = spirv.Variable : !spirv.ptr<f32, Function>
644  %1 = spirv.Variable : !spirv.ptr<f32, Function>
645  // expected-error @+1 {{missing alignment value}}
646  "spirv.CopyMemory"(%0, %1) {memory_access=#spirv.memory_access<Aligned>} : (!spirv.ptr<f32, Function>, !spirv.ptr<f32, Function>) -> ()
647  spirv.Return
648}
649
650// -----
651
652func.func @copy_memory_invalid_source_maa() {
653  %0 = spirv.Variable : !spirv.ptr<f32, Function>
654  %1 = spirv.Variable : !spirv.ptr<f32, Function>
655  // expected-error @+1 {{invalid alignment specification with non-aligned memory access specification}}
656  "spirv.CopyMemory"(%0, %1) {source_memory_access=#spirv.memory_access<Volatile>, memory_access=#spirv.memory_access<Aligned>, source_alignment=8 : i32, alignment=4 : i32} : (!spirv.ptr<f32, Function>, !spirv.ptr<f32, Function>) -> ()
657  spirv.Return
658}
659
660// -----
661
662func.func @copy_memory_invalid_source_maa2() {
663  %0 = spirv.Variable : !spirv.ptr<f32, Function>
664  %1 = spirv.Variable : !spirv.ptr<f32, Function>
665  // expected-error @+1 {{missing alignment value}}
666  "spirv.CopyMemory"(%0, %1) {source_memory_access=#spirv.memory_access<Aligned>, memory_access=#spirv.memory_access<Aligned>, alignment=4 : i32} : (!spirv.ptr<f32, Function>, !spirv.ptr<f32, Function>) -> ()
667  spirv.Return
668}
669
670// -----
671
672func.func @copy_memory_print_maa() {
673  %0 = spirv.Variable : !spirv.ptr<f32, Function>
674  %1 = spirv.Variable : !spirv.ptr<f32, Function>
675
676  // CHECK: spirv.CopyMemory "Function" %{{.*}}, "Function" %{{.*}} ["Volatile"] : f32
677  "spirv.CopyMemory"(%0, %1) {memory_access=#spirv.memory_access<Volatile>} : (!spirv.ptr<f32, Function>, !spirv.ptr<f32, Function>) -> ()
678
679  // CHECK: spirv.CopyMemory "Function" %{{.*}}, "Function" %{{.*}} ["Aligned", 4] : f32
680  "spirv.CopyMemory"(%0, %1) {memory_access=#spirv.memory_access<Aligned>, alignment=4 : i32} : (!spirv.ptr<f32, Function>, !spirv.ptr<f32, Function>) -> ()
681
682  // CHECK: spirv.CopyMemory "Function" %{{.*}}, "Function" %{{.*}} ["Aligned", 4], ["Volatile"] : f32
683  "spirv.CopyMemory"(%0, %1) {source_memory_access=#spirv.memory_access<Volatile>, memory_access=#spirv.memory_access<Aligned>, alignment=4 : i32} : (!spirv.ptr<f32, Function>, !spirv.ptr<f32, Function>) -> ()
684
685  // CHECK: spirv.CopyMemory "Function" %{{.*}}, "Function" %{{.*}} ["Aligned", 4], ["Aligned", 8] : f32
686  "spirv.CopyMemory"(%0, %1) {source_memory_access=#spirv.memory_access<Aligned>, memory_access=#spirv.memory_access<Aligned>, source_alignment=8 : i32, alignment=4 : i32} : (!spirv.ptr<f32, Function>, !spirv.ptr<f32, Function>) -> ()
687
688  spirv.Return
689}
690
691// -----
692
693//===----------------------------------------------------------------------===//
694// spirv.PtrAccessChain
695//===----------------------------------------------------------------------===//
696
697// CHECK-LABEL:   func @ptr_access_chain1(
698// CHECK-SAME:    %[[ARG0:.*]]: !spirv.ptr<f32, CrossWorkgroup>,
699// CHECK-SAME:    %[[ARG1:.*]]: i64)
700// CHECK: spirv.PtrAccessChain %[[ARG0]][%[[ARG1]]] : !spirv.ptr<f32, CrossWorkgroup>, i64
701func.func @ptr_access_chain1(%arg0: !spirv.ptr<f32, CrossWorkgroup>, %arg1 : i64) -> () {
702  %0 = spirv.PtrAccessChain %arg0[%arg1] : !spirv.ptr<f32, CrossWorkgroup>, i64 -> !spirv.ptr<f32, CrossWorkgroup>
703  return
704}
705
706// -----
707
708//===----------------------------------------------------------------------===//
709// spirv.InBoundsPtrAccessChain
710//===----------------------------------------------------------------------===//
711
712// CHECK-LABEL:   func @inbounds_ptr_access_chain1(
713// CHECK-SAME:    %[[ARG0:.*]]: !spirv.ptr<f32, CrossWorkgroup>,
714// CHECK-SAME:    %[[ARG1:.*]]: i64)
715// CHECK: spirv.InBoundsPtrAccessChain %[[ARG0]][%[[ARG1]]] : !spirv.ptr<f32, CrossWorkgroup>, i64
716func.func @inbounds_ptr_access_chain1(%arg0: !spirv.ptr<f32, CrossWorkgroup>, %arg1 : i64) -> () {
717  %0 = spirv.InBoundsPtrAccessChain %arg0[%arg1] : !spirv.ptr<f32, CrossWorkgroup>, i64 -> !spirv.ptr<f32, CrossWorkgroup>
718  return
719}
720