1//===-- SPIRVAtomicOps.td - MLIR SPIR-V Atomic Ops ---------*- tablegen -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file contains atomic ops for the SPIR-V dialect. It corresponds to
10// "3.32.18. Atomic Instructions" of the SPIR-V specification.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef SPIRV_ATOMIC_OPS
15#define SPIRV_ATOMIC_OPS
16
17class SPV_AtomicUpdateOp<string mnemonic, list<OpTrait> traits = []> :
18  SPV_Op<mnemonic, traits> {
19  let parser = [{ return ::parseAtomicUpdateOp(parser, result, false); }];
20  let printer = [{ return ::printAtomicUpdateOp(getOperation(), p); }];
21  let verifier = [{ return ::verifyAtomicUpdateOp(getOperation()); }];
22
23  let arguments = (ins
24    SPV_AnyPtr:$pointer,
25    SPV_ScopeAttr:$memory_scope,
26    SPV_MemorySemanticsAttr:$semantics
27  );
28
29  let results = (outs
30    SPV_Integer:$result
31  );
32}
33
34class SPV_AtomicUpdateWithValueOp<string mnemonic, list<OpTrait> traits = []> :
35  SPV_Op<mnemonic, traits> {
36  let parser = [{ return ::parseAtomicUpdateOp(parser, result, true); }];
37  let printer = [{ return ::printAtomicUpdateOp(getOperation(), p); }];
38  let verifier = [{ return ::verifyAtomicUpdateOp(getOperation()); }];
39
40  let arguments = (ins
41    SPV_AnyPtr:$pointer,
42    SPV_ScopeAttr:$memory_scope,
43    SPV_MemorySemanticsAttr:$semantics,
44    SPV_Integer:$value
45  );
46
47  let results = (outs
48    SPV_Integer:$result
49  );
50
51  let builders = [
52    OpBuilder<
53      [{OpBuilder &builder, OperationState &state, Value pointer,
54        ::mlir::spirv::Scope scope, ::mlir::spirv::MemorySemantics memory,
55        Value value}],
56      [{build(builder, state, value.getType(), pointer, scope, memory, value);}]
57    >
58  ];
59}
60
61// -----
62
63def SPV_AtomicAndOp : SPV_AtomicUpdateWithValueOp<"AtomicAnd", []> {
64  let summary = [{
65    Perform the following steps atomically with respect to any other atomic
66    accesses within Scope to the same location:
67  }];
68
69  let description = [{
70    1) load through Pointer to get an Original Value,
71
72    2) get a New Value by the bitwise AND of Original Value and Value, and
73
74    3) store the New Value back through Pointer.
75
76    The instruction’s result is the Original Value.
77
78    Result Type must be an integer type scalar.
79
80     The type of Value must be the same as Result Type.  The type of the
81    value pointed to by Pointer must be the same as Result Type.
82
83    Memory must be a valid memory Scope.
84
85    <!-- End of AutoGen section -->
86
87    ```
88    scope ::= `"CrossDevice"` | `"Device"` | `"Workgroup"` | ...
89
90    memory-semantics ::= `"None"` | `"Acquire"` | "Release"` | ...
91
92    atomic-and-op ::=
93        `spv.AtomicAnd` scope memory-semantics
94                        ssa-use `,` ssa-use `:` spv-pointer-type
95    ```
96
97    #### Example:
98
99    ```mlir
100    %0 = spv.AtomicAnd "Device" "None" %pointer, %value :
101                       !spv.ptr<i32, StorageBuffer>
102    ```
103  }];
104}
105
106// -----
107
108def SPV_AtomicCompareExchangeWeakOp : SPV_Op<"AtomicCompareExchangeWeak", []> {
109  let summary = "Deprecated (use OpAtomicCompareExchange).";
110
111  let description = [{
112    Has the same semantics as OpAtomicCompareExchange.
113
114    Memory must be a valid memory Scope.
115
116    <!-- End of AutoGen section -->
117
118    ```
119    atomic-compare-exchange-weak-op ::=
120        `spv.AtomicCompareExchangeWeak` scope memory-semantics memory-semantics
121                                        ssa-use `,` ssa-use `,` ssa-use
122                                        `:` spv-pointer-type
123    ```
124
125    #### Example:
126
127    ```mlir
128    %0 = spv.AtomicCompareExchangeWeak "Workgroup" "Acquire" "None"
129                                       %pointer, %value, %comparator
130                                       : !spv.ptr<i32, WorkGroup>
131    ```
132  }];
133
134  let availability = [
135    MinVersion<SPV_V_1_0>,
136    MaxVersion<SPV_V_1_3>,
137    Extension<[]>,
138    Capability<[SPV_C_Kernel]>
139  ];
140
141  let arguments = (ins
142    SPV_AnyPtr:$pointer,
143    SPV_ScopeAttr:$memory_scope,
144    SPV_MemorySemanticsAttr:$equal_semantics,
145    SPV_MemorySemanticsAttr:$unequal_semantics,
146    SPV_Integer:$value,
147    SPV_Integer:$comparator
148  );
149
150  let results = (outs
151    SPV_Integer:$result
152  );
153}
154
155// -----
156
157def SPV_AtomicIAddOp : SPV_AtomicUpdateWithValueOp<"AtomicIAdd", []> {
158  let summary = [{
159    Perform the following steps atomically with respect to any other atomic
160    accesses within Scope to the same location:
161  }];
162
163  let description = [{
164    1) load through Pointer to get an Original Value,
165
166    2) get a New Value by integer addition of Original Value and Value, and
167
168    3) store the New Value back through Pointer.
169
170    The instruction’s result is the Original Value.
171
172    Result Type must be an integer type scalar.
173
174     The type of Value must be the same as Result Type.  The type of the
175    value pointed to by Pointer must be the same as Result Type.
176
177    Memory must be a valid memory Scope.
178
179    <!-- End of AutoGen section -->
180
181    ```
182    atomic-iadd-op ::=
183        `spv.AtomicIAdd` scope memory-semantics
184                         ssa-use `,` ssa-use `:` spv-pointer-type
185    ```
186
187    #### Example:
188
189    ```mlir
190    %0 = spv.AtomicIAdd "Device" "None" %pointer, %value :
191                        !spv.ptr<i32, StorageBuffer>
192    ```
193  }];
194}
195
196// -----
197
198def SPV_AtomicIDecrementOp : SPV_AtomicUpdateOp<"AtomicIDecrement", []> {
199  let summary = [{
200    Perform the following steps atomically with respect to any other atomic
201    accesses within Scope to the same location:
202  }];
203
204  let description = [{
205    1) load through Pointer to get an Original Value,
206
207    2) get a New Value through integer subtraction of 1 from Original Value,
208    and
209
210    3) store the New Value back through Pointer.
211
212    The instruction’s result is the Original Value.
213
214    Result Type must be an integer type scalar.  The type of the value
215    pointed to by Pointer must be the same as Result Type.
216
217    Memory must be a valid memory Scope.
218
219    <!-- End of AutoGen section -->
220
221    ```
222    atomic-idecrement-op ::=
223        `spv.AtomicIDecrement` scope memory-semantics ssa-use
224                               `:` spv-pointer-type
225    ```
226
227    #### Example:
228
229    ```mlir
230    %0 = spv.AtomicIDecrement "Device" "None" %pointer :
231                              !spv.ptr<i32, StorageBuffer>
232    ```
233  }];
234}
235
236// -----
237
238def SPV_AtomicIIncrementOp : SPV_AtomicUpdateOp<"AtomicIIncrement", []> {
239  let summary = [{
240    Perform the following steps atomically with respect to any other atomic
241    accesses within Scope to the same location:
242  }];
243
244  let description = [{
245    1) load through Pointer to get an Original Value,
246
247    2) get a New Value through integer addition of 1 to Original Value, and
248
249    3) store the New Value back through Pointer.
250
251    The instruction’s result is the Original Value.
252
253    Result Type must be an integer type scalar.  The type of the value
254    pointed to by Pointer must be the same as Result Type.
255
256    Memory must be a valid memory Scope.
257
258    <!-- End of AutoGen section -->
259
260    ```
261    atomic-iincrement-op ::=
262        `spv.AtomicIIncrement` scope memory-semantics ssa-use
263                               `:` spv-pointer-type
264    ```
265
266    #### Example:
267
268    ```mlir
269    %0 = spv.AtomicIncrement "Device" "None" %pointer :
270                             !spv.ptr<i32, StorageBuffer>
271    ```
272  }];
273}
274
275// -----
276
277def SPV_AtomicISubOp : SPV_AtomicUpdateWithValueOp<"AtomicISub", []> {
278  let summary = [{
279    Perform the following steps atomically with respect to any other atomic
280    accesses within Scope to the same location:
281  }];
282
283  let description = [{
284    1) load through Pointer to get an Original Value,
285
286    2) get a New Value by integer subtraction of Value from Original Value,
287    and
288
289    3) store the New Value back through Pointer.
290
291    The instruction’s result is the Original Value.
292
293    Result Type must be an integer type scalar.
294
295     The type of Value must be the same as Result Type.  The type of the
296    value pointed to by Pointer must be the same as Result Type.
297
298    Memory must be a valid memory Scope.
299
300    <!-- End of AutoGen section -->
301
302    ```
303    atomic-isub-op ::=
304        `spv.AtomicISub` scope memory-semantics
305                         ssa-use `,` ssa-use `:` spv-pointer-type
306    ```
307
308    #### Example:
309
310    ```mlir
311    %0 = spv.AtomicISub "Device" "None" %pointer, %value :
312                        !spv.ptr<i32, StorageBuffer>
313    ```
314  }];
315}
316
317// -----
318
319def SPV_AtomicOrOp : SPV_AtomicUpdateWithValueOp<"AtomicOr", []> {
320  let summary = [{
321    Perform the following steps atomically with respect to any other atomic
322    accesses within Scope to the same location:
323  }];
324
325  let description = [{
326    1) load through Pointer to get an Original Value,
327
328    2) get a New Value by the bitwise OR of Original Value and Value, and
329
330    3) store the New Value back through Pointer.
331
332    The instruction’s result is the Original Value.
333
334    Result Type must be an integer type scalar.
335
336     The type of Value must be the same as Result Type.  The type of the
337    value pointed to by Pointer must be the same as Result Type.
338
339    Memory must be a valid memory Scope.
340
341    <!-- End of AutoGen section -->
342
343    ```
344    atomic-or-op ::=
345        `spv.AtomicOr` scope memory-semantics
346                       ssa-use `,` ssa-use `:` spv-pointer-type
347    ```
348
349    #### Example:
350
351    ```mlir
352    %0 = spv.AtomicOr "Device" "None" %pointer, %value :
353                      !spv.ptr<i32, StorageBuffer>
354    ```
355  }];
356}
357
358// -----
359
360def SPV_AtomicSMaxOp : SPV_AtomicUpdateWithValueOp<"AtomicSMax", []> {
361  let summary = [{
362    Perform the following steps atomically with respect to any other atomic
363    accesses within Scope to the same location:
364  }];
365
366  let description = [{
367    1) load through Pointer to get an Original Value,
368
369    2) get a New Value by finding the largest signed integer of Original
370    Value and Value, and
371
372    3) store the New Value back through Pointer.
373
374    The instruction’s result is the Original Value.
375
376    Result Type must be an integer type scalar.
377
378     The type of Value must be the same as Result Type.  The type of the
379    value pointed to by Pointer must be the same as Result Type.
380
381    Memory must be a valid memory Scope.
382
383    <!-- End of AutoGen section -->
384
385    ```
386    atomic-smax-op ::=
387        `spv.AtomicSMax` scope memory-semantics
388                         ssa-use `,` ssa-use `:` spv-pointer-type
389    ```
390
391    #### Example:
392
393    ```mlir
394    %0 = spv.AtomicSMax "Device" "None" %pointer, %value :
395                        !spv.ptr<i32, StorageBuffer>
396    ```
397  }];
398}
399
400// -----
401
402def SPV_AtomicSMinOp : SPV_AtomicUpdateWithValueOp<"AtomicSMin", []> {
403  let summary = [{
404    Perform the following steps atomically with respect to any other atomic
405    accesses within Scope to the same location:
406  }];
407
408  let description = [{
409    1) load through Pointer to get an Original Value,
410
411    2) get a New Value by finding the smallest signed integer of Original
412    Value and Value, and
413
414    3) store the New Value back through Pointer.
415
416    The instruction’s result is the Original Value.
417
418    Result Type must be an integer type scalar.
419
420     The type of Value must be the same as Result Type.  The type of the
421    value pointed to by Pointer must be the same as Result Type.
422
423    Memory must be a valid memory Scope.
424
425    <!-- End of AutoGen section -->
426
427    ```
428    atomic-smin-op ::=
429        `spv.AtomicSMin` scope memory-semantics
430                         ssa-use `,` ssa-use `:` spv-pointer-type
431    ```
432
433    #### Example:
434
435    ```mlir
436    %0 = spv.AtomicSMin "Device" "None" %pointer, %value :
437                        !spv.ptr<i32, StorageBuffer>
438    ```
439  }];
440}
441
442// -----
443
444def SPV_AtomicUMaxOp : SPV_AtomicUpdateWithValueOp<"AtomicUMax", []> {
445  let summary = [{
446    Perform the following steps atomically with respect to any other atomic
447    accesses within Scope to the same location:
448  }];
449
450  let description = [{
451    1) load through Pointer to get an Original Value,
452
453    2) get a New Value by finding the largest unsigned integer of Original
454    Value and Value, and
455
456    3) store the New Value back through Pointer.
457
458    The instruction’s result is the Original Value.
459
460    Result Type must be an integer type scalar.
461
462     The type of Value must be the same as Result Type.  The type of the
463    value pointed to by Pointer must be the same as Result Type.
464
465    Memory must be a valid memory Scope.
466
467    <!-- End of AutoGen section -->
468
469    ```
470    atomic-umax-op ::=
471        `spv.AtomicUMax` scope memory-semantics
472                         ssa-use `,` ssa-use `:` spv-pointer-type
473    ```
474
475    #### Example:
476
477    ```mlir
478    %0 = spv.AtomicUMax "Device" "None" %pointer, %value :
479                        !spv.ptr<i32, StorageBuffer>
480    ```
481  }];
482}
483
484// -----
485
486def SPV_AtomicUMinOp : SPV_AtomicUpdateWithValueOp<"AtomicUMin", []> {
487  let summary = [{
488    Perform the following steps atomically with respect to any other atomic
489    accesses within Scope to the same location:
490  }];
491
492  let description = [{
493    1) load through Pointer to get an Original Value,
494
495    2) get a New Value by finding the smallest unsigned integer of Original
496    Value and Value, and
497
498    3) store the New Value back through Pointer.
499
500    The instruction’s result is the Original Value.
501
502    Result Type must be an integer type scalar.
503
504     The type of Value must be the same as Result Type.  The type of the
505    value pointed to by Pointer must be the same as Result Type.
506
507    Memory must be a valid memory Scope.
508
509    <!-- End of AutoGen section -->
510
511    ```
512    atomic-umin-op ::=
513        `spv.AtomicUMin` scope memory-semantics
514                         ssa-use `,` ssa-use `:` spv-pointer-type
515    ```
516
517    #### Example:
518
519    ```mlir
520    %0 = spv.AtomicUMin "Device" "None" %pointer, %value :
521                        !spv.ptr<i32, StorageBuffer>
522    ```
523  }];
524}
525
526// -----
527
528def SPV_AtomicXorOp : SPV_AtomicUpdateWithValueOp<"AtomicXor", []> {
529  let summary = [{
530    Perform the following steps atomically with respect to any other atomic
531    accesses within Scope to the same location:
532  }];
533
534  let description = [{
535    1) load through Pointer to get an Original Value,
536
537    2) get a New Value by the bitwise exclusive OR of Original Value and
538    Value, and
539
540    3) store the New Value back through Pointer.
541
542    The instruction’s result is the Original Value.
543
544    Result Type must be an integer type scalar.
545
546     The type of Value must be the same as Result Type.  The type of the
547    value pointed to by Pointer must be the same as Result Type.
548
549    Memory must be a valid memory Scope.
550
551    <!-- End of AutoGen section -->
552
553    ```
554    atomic-xor-op ::=
555        `spv.AtomicXor` scope memory-semantics
556                        ssa-use `,` ssa-use `:` spv-pointer-type
557    ```
558
559    #### Example:
560
561    ```mlir
562    %0 = spv.AtomicXor "Device" "None" %pointer, %value :
563                       !spv.ptr<i32, StorageBuffer>
564    ```
565  }];
566}
567
568// -----
569
570#endif // SPIRV_ATOMIC_OPS
571