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