xref: /llvm-project/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVAtomicOps.td (revision c63febb1025564b078a5c8e52e6df638e8a1d808)
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 MLIR_DIALECT_SPIRV_IR_ATOMIC_OPS
15#define MLIR_DIALECT_SPIRV_IR_ATOMIC_OPS
16
17include "mlir/Dialect/SPIRV/IR/SPIRVBase.td"
18include "mlir/Interfaces/SideEffectInterfaces.td"
19
20class PointeeTypeMatchTrait<string pointer, string name>
21    : TypesMatchWith<
22      "`" # name # "` type matches pointee type of " # "`" # pointer # "`",
23      pointer, name, "llvm::cast<PointerType>($_self).getPointeeType()">;
24
25// -----
26
27class SPIRV_AtomicUpdateOp<string mnemonic, list<Trait> traits = []>
28    : SPIRV_Op<mnemonic,
29               !listconcat(traits,
30                           [PointeeTypeMatchTrait<"pointer", "result">])> {
31  let arguments = (ins
32    SPIRV_AnyPtr:$pointer,
33    SPIRV_ScopeAttr:$memory_scope,
34    SPIRV_MemorySemanticsAttr:$semantics
35  );
36
37  let results = (outs
38    SPIRV_Integer:$result
39  );
40
41  let assemblyFormat = [{
42    $memory_scope $semantics operands attr-dict `:` type($pointer)
43  }];
44
45  let hasCustomAssemblyFormat = 0;
46}
47
48class SPIRV_AtomicUpdateWithValueOp<string mnemonic, list<Trait> traits = []>
49    : SPIRV_Op<mnemonic, !listconcat(traits, [
50                 PointeeTypeMatchTrait<"pointer", "value">,
51                 PointeeTypeMatchTrait<"pointer", "result">,
52               ])> {
53  let arguments = (ins
54    SPIRV_AnyPtr:$pointer,
55    SPIRV_ScopeAttr:$memory_scope,
56    SPIRV_MemorySemanticsAttr:$semantics,
57    SPIRV_Integer:$value
58  );
59
60  let results = (outs
61    SPIRV_Integer:$result
62  );
63
64  let assemblyFormat = [{
65    $memory_scope $semantics operands attr-dict `:` type($pointer)
66  }];
67
68  let hasCustomAssemblyFormat = 0;
69}
70
71// -----
72
73def SPIRV_AtomicAndOp : SPIRV_AtomicUpdateWithValueOp<"AtomicAnd", []> {
74  let summary = [{
75    Perform the following steps atomically with respect to any other atomic
76    accesses within Scope to the same location:
77  }];
78
79  let description = [{
80    1) load through Pointer to get an Original Value,
81
82    2) get a New Value by the bitwise AND of Original Value and Value, and
83
84    3) store the New Value back through Pointer.
85
86    The instruction’s result is the Original Value.
87
88    Result Type must be an integer type scalar.
89
90     The type of Value must be the same as Result Type.  The type of the
91    value pointed to by Pointer must be the same as Result Type.
92
93    Memory must be a valid memory Scope.
94
95    <!-- End of AutoGen section -->
96
97    #### Example:
98
99    ```mlir
100    %0 = spirv.AtomicAnd <Device> <None> %pointer, %value :
101                       !spirv.ptr<i32, StorageBuffer>
102    ```
103  }];
104}
105
106// -----
107
108def SPIRV_AtomicCompareExchangeOp : SPIRV_Op<"AtomicCompareExchange", [
109  PointeeTypeMatchTrait<"pointer", "result">,
110  PointeeTypeMatchTrait<"pointer", "value">,
111  PointeeTypeMatchTrait<"pointer", "comparator">,
112]> {
113  let summary = [{
114    Perform the following steps atomically with respect to any other atomic
115    accesses within Scope to the same location:
116  }];
117
118  let description = [{
119    1) load through Pointer to get an Original Value,
120
121    2) get a New Value from Value only if Original Value equals Comparator,
122    and
123
124    3) store the New Value back through Pointer'only if 'Original Value
125    equaled Comparator.
126
127    The instruction's result is the Original Value.
128
129    Result Type must be an integer type scalar.
130
131    Use Equal for the memory semantics of this instruction when Value and
132    Original Value compare equal.
133
134    Use Unequal for the memory semantics of this instruction when Value and
135    Original Value compare unequal. Unequal must not be set to Release or
136    Acquire and Release. In addition, Unequal cannot be set to a stronger
137    memory-order then Equal.
138
139     The type of Value must be the same as Result Type.  The type of the
140    value pointed to by Pointer must be the same as Result Type.  This type
141    must also match the type of Comparator.
142
143    Memory is a memory Scope.
144
145    <!-- End of AutoGen section -->
146
147    #### Example:
148
149    ```
150    %0 = spirv.AtomicCompareExchange <Workgroup> <Acquire> <None>
151                                    %pointer, %value, %comparator
152                                    : !spirv.ptr<i32, WorkGroup>
153    ```
154  }];
155
156  let arguments = (ins
157    SPIRV_AnyPtr:$pointer,
158    SPIRV_ScopeAttr:$memory_scope,
159    SPIRV_MemorySemanticsAttr:$equal_semantics,
160    SPIRV_MemorySemanticsAttr:$unequal_semantics,
161    SPIRV_Integer:$value,
162    SPIRV_Integer:$comparator
163  );
164
165  let results = (outs
166    SPIRV_Integer:$result
167  );
168
169  let assemblyFormat = [{
170    $memory_scope $equal_semantics $unequal_semantics operands attr-dict `:`
171      type($pointer)
172  }];
173
174  let hasCustomAssemblyFormat = 0;
175  let hasVerifier = 0;
176}
177
178// -----
179
180def SPIRV_AtomicCompareExchangeWeakOp : SPIRV_Op<"AtomicCompareExchangeWeak", [
181  PointeeTypeMatchTrait<"pointer", "result">,
182  PointeeTypeMatchTrait<"pointer", "value">,
183  PointeeTypeMatchTrait<"pointer", "comparator">,
184]> {
185  let summary = "Deprecated (use OpAtomicCompareExchange).";
186
187  let description = [{
188    Has the same semantics as OpAtomicCompareExchange.
189
190    Memory must be a valid memory Scope.
191
192    <!-- End of AutoGen section -->
193
194    #### Example:
195
196    ```mlir
197    %0 = spirv.AtomicCompareExchangeWeak <Workgroup> <Acquire> <None>
198                                       %pointer, %value, %comparator
199                                       : !spirv.ptr<i32, WorkGroup>
200    ```
201  }];
202
203  let availability = [
204    MinVersion<SPIRV_V_1_0>,
205    MaxVersion<SPIRV_V_1_3>,
206    Extension<[]>,
207    Capability<[SPIRV_C_Kernel]>
208  ];
209
210  let arguments = (ins
211    SPIRV_AnyPtr:$pointer,
212    SPIRV_ScopeAttr:$memory_scope,
213    SPIRV_MemorySemanticsAttr:$equal_semantics,
214    SPIRV_MemorySemanticsAttr:$unequal_semantics,
215    SPIRV_Integer:$value,
216    SPIRV_Integer:$comparator
217  );
218
219  let results = (outs
220    SPIRV_Integer:$result
221  );
222
223  let assemblyFormat = [{
224    $memory_scope $equal_semantics $unequal_semantics operands attr-dict `:`
225      type($pointer)
226  }];
227
228  let hasCustomAssemblyFormat = 0;
229  let hasVerifier = 0;
230}
231
232// -----
233
234def SPIRV_AtomicExchangeOp : SPIRV_Op<"AtomicExchange", [
235  PointeeTypeMatchTrait<"pointer", "value">,
236  PointeeTypeMatchTrait<"pointer", "result">,
237]> {
238  let summary = [{
239    Perform the following steps atomically with respect to any other atomic
240    accesses within Scope to the same location:
241  }];
242
243  let description = [{
244    1) load through Pointer to get an Original Value,
245
246    2) get a New Value from copying Value, and
247
248    3) store the New Value back through Pointer.
249
250    The instruction's result is the Original Value.
251
252    Result Type must be a scalar of integer type or floating-point type.
253
254     The type of Value must be the same as Result Type.  The type of the
255    value pointed to by Pointer must be the same as Result Type.
256
257    Memory is a memory Scope.
258
259    <!-- End of AutoGen section -->
260
261    #### Example:
262
263    ```mlir
264    %0 = spirv.AtomicExchange <Workgroup> <Acquire> %pointer, %value,
265                            : !spirv.ptr<i32, WorkGroup>
266    ```
267  }];
268
269  let arguments = (ins
270    SPIRV_AnyPtr:$pointer,
271    SPIRV_ScopeAttr:$memory_scope,
272    SPIRV_MemorySemanticsAttr:$semantics,
273    SPIRV_Numerical:$value
274  );
275
276  let results = (outs
277    SPIRV_Numerical:$result
278  );
279
280  let assemblyFormat = [{
281    $memory_scope $semantics operands attr-dict `:` type($pointer)
282  }];
283
284  let hasCustomAssemblyFormat = 0;
285  let hasVerifier = 0;
286}
287
288// -----
289
290def SPIRV_EXTAtomicFAddOp : SPIRV_ExtVendorOp<"AtomicFAdd", [
291  PointeeTypeMatchTrait<"pointer", "result">,
292  PointeeTypeMatchTrait<"pointer", "value">,
293]> {
294  let summary = "TBD";
295
296  let description = [{
297
298
299    <!-- End of AutoGen section -->
300
301    Perform the following steps atomically with respect to any other atomic
302    accesses within Scope to the same location:
303
304    1) load through Pointer to get an Original Value,
305
306    2) get a New Value by float addition of Original Value and Value, and
307
308    3) store the New Value back through Pointer.
309
310    The instruction's result is the Original Value.
311
312    Result Type must be a floating-point type scalar.
313
314    The type of Value must be the same as Result Type. The type of the value
315    pointed to by Pointer must be the same as Result Type.
316
317    Memory must be a valid memory Scope.
318
319    #### Example:
320
321    ```mlir
322    %0 = spirv.EXT.AtomicFAdd <Device> <None> %pointer, %value :
323                           !spirv.ptr<f32, StorageBuffer>
324    ```
325  }];
326
327  let availability = [
328    MinVersion<SPIRV_V_1_0>,
329    MaxVersion<SPIRV_V_1_6>,
330    Extension<[SPV_EXT_shader_atomic_float_add]>,
331    Capability<[SPIRV_C_AtomicFloat16AddEXT, SPIRV_C_AtomicFloat32AddEXT, SPIRV_C_AtomicFloat64AddEXT]>
332  ];
333
334  let arguments = (ins
335    SPIRV_AnyPtr:$pointer,
336    SPIRV_ScopeAttr:$memory_scope,
337    SPIRV_MemorySemanticsAttr:$semantics,
338    SPIRV_Float:$value
339  );
340
341  let results = (outs
342    SPIRV_Float:$result
343  );
344
345  let assemblyFormat = [{
346    $memory_scope $semantics operands attr-dict `:` type($pointer)
347  }];
348}
349
350// -----
351
352def SPIRV_AtomicIAddOp : SPIRV_AtomicUpdateWithValueOp<"AtomicIAdd", []> {
353  let summary = [{
354    Perform the following steps atomically with respect to any other atomic
355    accesses within Scope to the same location:
356  }];
357
358  let description = [{
359    1) load through Pointer to get an Original Value,
360
361    2) get a New Value by integer addition of Original Value and Value, and
362
363    3) store the New Value back through Pointer.
364
365    The instruction’s result is the Original Value.
366
367    Result Type must be an integer type scalar.
368
369     The type of Value must be the same as Result Type.  The type of the
370    value pointed to by Pointer must be the same as Result Type.
371
372    Memory must be a valid memory Scope.
373
374    <!-- End of AutoGen section -->
375
376    #### Example:
377
378    ```mlir
379    %0 = spirv.AtomicIAdd <Device> <None> %pointer, %value :
380                        !spirv.ptr<i32, StorageBuffer>
381    ```
382  }];
383}
384
385// -----
386
387def SPIRV_AtomicIDecrementOp : SPIRV_AtomicUpdateOp<"AtomicIDecrement", []> {
388  let summary = [{
389    Perform the following steps atomically with respect to any other atomic
390    accesses within Scope to the same location:
391  }];
392
393  let description = [{
394    1) load through Pointer to get an Original Value,
395
396    2) get a New Value through integer subtraction of 1 from Original Value,
397    and
398
399    3) store the New Value back through Pointer.
400
401    The instruction’s result is the Original Value.
402
403    Result Type must be an integer type scalar.  The type of the value
404    pointed to by Pointer must be the same as Result Type.
405
406    Memory must be a valid memory Scope.
407
408    <!-- End of AutoGen section -->
409
410    #### Example:
411
412    ```mlir
413    %0 = spirv.AtomicIDecrement <Device> <None> %pointer :
414                              !spirv.ptr<i32, StorageBuffer>
415    ```
416  }];
417}
418
419// -----
420
421def SPIRV_AtomicIIncrementOp : SPIRV_AtomicUpdateOp<"AtomicIIncrement", []> {
422  let summary = [{
423    Perform the following steps atomically with respect to any other atomic
424    accesses within Scope to the same location:
425  }];
426
427  let description = [{
428    1) load through Pointer to get an Original Value,
429
430    2) get a New Value through integer addition of 1 to Original Value, and
431
432    3) store the New Value back through Pointer.
433
434    The instruction’s result is the Original Value.
435
436    Result Type must be an integer type scalar.  The type of the value
437    pointed to by Pointer must be the same as Result Type.
438
439    Memory must be a valid memory Scope.
440
441    <!-- End of AutoGen section -->
442
443    #### Example:
444
445    ```mlir
446    %0 = spirv.AtomicIncrement <Device> <None> %pointer :
447                             !spirv.ptr<i32, StorageBuffer>
448    ```
449  }];
450}
451
452// -----
453
454def SPIRV_AtomicISubOp : SPIRV_AtomicUpdateWithValueOp<"AtomicISub", []> {
455  let summary = [{
456    Perform the following steps atomically with respect to any other atomic
457    accesses within Scope to the same location:
458  }];
459
460  let description = [{
461    1) load through Pointer to get an Original Value,
462
463    2) get a New Value by integer subtraction of Value from Original Value,
464    and
465
466    3) store the New Value back through Pointer.
467
468    The instruction’s result is the Original Value.
469
470    Result Type must be an integer type scalar.
471
472     The type of Value must be the same as Result Type.  The type of the
473    value pointed to by Pointer must be the same as Result Type.
474
475    Memory must be a valid memory Scope.
476
477    <!-- End of AutoGen section -->
478
479    #### Example:
480
481    ```mlir
482    %0 = spirv.AtomicISub <Device> <None> %pointer, %value :
483                        !spirv.ptr<i32, StorageBuffer>
484    ```
485  }];
486}
487
488// -----
489
490def SPIRV_AtomicOrOp : SPIRV_AtomicUpdateWithValueOp<"AtomicOr", []> {
491  let summary = [{
492    Perform the following steps atomically with respect to any other atomic
493    accesses within Scope to the same location:
494  }];
495
496  let description = [{
497    1) load through Pointer to get an Original Value,
498
499    2) get a New Value by the bitwise OR of Original Value and Value, and
500
501    3) store the New Value back through Pointer.
502
503    The instruction’s result is the Original Value.
504
505    Result Type must be an integer type scalar.
506
507     The type of Value must be the same as Result Type.  The type of the
508    value pointed to by Pointer must be the same as Result Type.
509
510    Memory must be a valid memory Scope.
511
512    <!-- End of AutoGen section -->
513
514    #### Example:
515
516    ```mlir
517    %0 = spirv.AtomicOr <Device> <None> %pointer, %value :
518                      !spirv.ptr<i32, StorageBuffer>
519    ```
520  }];
521}
522
523// -----
524
525def SPIRV_AtomicSMaxOp : SPIRV_AtomicUpdateWithValueOp<"AtomicSMax", []> {
526  let summary = [{
527    Perform the following steps atomically with respect to any other atomic
528    accesses within Scope to the same location:
529  }];
530
531  let description = [{
532    1) load through Pointer to get an Original Value,
533
534    2) get a New Value by finding the largest signed integer of Original
535    Value and Value, and
536
537    3) store the New Value back through Pointer.
538
539    The instruction’s result is the Original Value.
540
541    Result Type must be an integer type scalar.
542
543     The type of Value must be the same as Result Type.  The type of the
544    value pointed to by Pointer must be the same as Result Type.
545
546    Memory must be a valid memory Scope.
547
548    <!-- End of AutoGen section -->
549
550    #### Example:
551
552    ```mlir
553    %0 = spirv.AtomicSMax <Device> <None> %pointer, %value :
554                        !spirv.ptr<i32, StorageBuffer>
555    ```
556  }];
557}
558
559// -----
560
561def SPIRV_AtomicSMinOp : SPIRV_AtomicUpdateWithValueOp<"AtomicSMin", []> {
562  let summary = [{
563    Perform the following steps atomically with respect to any other atomic
564    accesses within Scope to the same location:
565  }];
566
567  let description = [{
568    1) load through Pointer to get an Original Value,
569
570    2) get a New Value by finding the smallest signed integer of Original
571    Value and Value, and
572
573    3) store the New Value back through Pointer.
574
575    The instruction’s result is the Original Value.
576
577    Result Type must be an integer type scalar.
578
579     The type of Value must be the same as Result Type.  The type of the
580    value pointed to by Pointer must be the same as Result Type.
581
582    Memory must be a valid memory Scope.
583
584    <!-- End of AutoGen section -->
585
586    #### Example:
587
588    ```mlir
589    %0 = spirv.AtomicSMin <Device> <None> %pointer, %value :
590                        !spirv.ptr<i32, StorageBuffer>
591    ```
592  }];
593}
594
595// -----
596
597def SPIRV_AtomicUMaxOp : SPIRV_AtomicUpdateWithValueOp<"AtomicUMax", [UnsignedOp]> {
598  let summary = [{
599    Perform the following steps atomically with respect to any other atomic
600    accesses within Scope to the same location:
601  }];
602
603  let description = [{
604    1) load through Pointer to get an Original Value,
605
606    2) get a New Value by finding the largest unsigned integer of Original
607    Value and Value, and
608
609    3) store the New Value back through Pointer.
610
611    The instruction’s result is the Original Value.
612
613    Result Type must be an integer type scalar.
614
615     The type of Value must be the same as Result Type.  The type of the
616    value pointed to by Pointer must be the same as Result Type.
617
618    Memory must be a valid memory Scope.
619
620    <!-- End of AutoGen section -->
621
622    #### Example:
623
624    ```mlir
625    %0 = spirv.AtomicUMax <Device> <None> %pointer, %value :
626                        !spirv.ptr<i32, StorageBuffer>
627    ```
628  }];
629}
630
631// -----
632
633def SPIRV_AtomicUMinOp : SPIRV_AtomicUpdateWithValueOp<"AtomicUMin", [UnsignedOp]> {
634  let summary = [{
635    Perform the following steps atomically with respect to any other atomic
636    accesses within Scope to the same location:
637  }];
638
639  let description = [{
640    1) load through Pointer to get an Original Value,
641
642    2) get a New Value by finding the smallest unsigned integer of Original
643    Value and Value, and
644
645    3) store the New Value back through Pointer.
646
647    The instruction’s result is the Original Value.
648
649    Result Type must be an integer type scalar.
650
651     The type of Value must be the same as Result Type.  The type of the
652    value pointed to by Pointer must be the same as Result Type.
653
654    Memory must be a valid memory Scope.
655
656    <!-- End of AutoGen section -->
657
658    #### Example:
659
660    ```mlir
661    %0 = spirv.AtomicUMin <Device> <None> %pointer, %value :
662                        !spirv.ptr<i32, StorageBuffer>
663    ```
664  }];
665}
666
667// -----
668
669def SPIRV_AtomicXorOp : SPIRV_AtomicUpdateWithValueOp<"AtomicXor", []> {
670  let summary = [{
671    Perform the following steps atomically with respect to any other atomic
672    accesses within Scope to the same location:
673  }];
674
675  let description = [{
676    1) load through Pointer to get an Original Value,
677
678    2) get a New Value by the bitwise exclusive OR of Original Value and
679    Value, and
680
681    3) store the New Value back through Pointer.
682
683    The instruction’s result is the Original Value.
684
685    Result Type must be an integer type scalar.
686
687     The type of Value must be the same as Result Type.  The type of the
688    value pointed to by Pointer must be the same as Result Type.
689
690    Memory must be a valid memory Scope.
691
692    <!-- End of AutoGen section -->
693
694    #### Example:
695
696    ```mlir
697    %0 = spirv.AtomicXor <Device> <None> %pointer, %value :
698                       !spirv.ptr<i32, StorageBuffer>
699    ```
700  }];
701}
702
703// -----
704
705#endif // MLIR_DIALECT_SPIRV_IR_ATOMIC_OPS
706