1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153
|
/****************************************************************
* *
* Copyright (c) 2024 Fidelity National Information *
* Services, Inc. and/or its subsidiaries. All rights reserved. *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
* under a license. If you do not know the terms of *
* the license, please stop and do not read further. *
* *
****************************************************************/
#ifndef GTM_ATOMIC_H_INCLUDED
#define GTM_ATOMIC_H_INCLUDED
#include <stddef.h>
#include <stdbool.h>
/* USAGE
* This header provides a standard, C11-like interface to atomics for use in GT.M.
* This includes atomic types, generally with names which are prefixed with 'gtm_' but otherwise identical to the c11 ones provided
* in any stdatomic.h, along with macros for all the major atomic operations. These operations have the same interface across
* all supported platforms, but may have different performance profiles due to architectural differences. The atomic operations are
* generally of the form ATOMIC_$OP, where $OP is the operation to perform. The following operations are supported:
*
* ATOMIC_LOAD(PTR, ORD);
* @returns value of *PTR
* @param PTR - pointer to a gtm_atomic object
* @param ORD - memory ordering constraint
*
* ATOMIC_STORE(PTR, VAL, ORD)
* @returns void
* @param PTR - pointer to a gtm_atomic object
* @param VAL - value to store in the pointed-to object
* @param ORD - memory ordering constraint
*
* ATOMIC_FETCH_{ADD,SUB,XOR,OR,AND}(PTR, VAL, ORD)
* ATOMIC_EXCHANGE(PTR, VAL, ORD) (instead of performing an operation with VAL, this sets *PTR to VAL)
* @returns value of *PTR just before the operation atomically took place
* @param PTR - pointer to a gtm_atomic object
* @param VAL - value to use in the operation on the pointed-to object (eg for ATOMIC_FETCH_ADD, this is the increment value)
* @param ORD - memory ordering constraint
*
* ATOMIC_COMPARE_EXCHANGE_{STRONG,WEAK}(OBJ_PTR, EXP_PTR, VAL, SUCCESS_ORD, FAIL_ORD)
* @returns bool - true if the compare-and-swap succeeded, false if it failed
* @param OBJ_PTR - pointer to the gtm_atomic object on which to perform the compare-and-swap
* @param EXP_PTR - pointer to the expected value. If *OBJ_PTR matches *EXP_PTR, it will atomically be set
* to equal VAL. If it does not equal *EXP_PTR, !!!(*EXP_PTR) is set to equal the actual value of *OBJ_PTR!!!
* @param VAL - value to set the object to if the comparison succeeds
* @param SUCCESS_ORD - memory ordering constraint to adopt if the comparison succeeds
* @param FAIL_ORD - memory ordering constraint to adopt if the comparison fails
*
* So far this has made no substantive comment on the memory orderings. The best source on them is the C or C++ standards, which
* are broadly compatible on this subject. But some comment here on how and when to use them is necessary. The possible memory
* orders are as follows:
* memory_order_relaxed
* memory_order_acquire
* memory_order_release
* memory_order_acq_rel
* memory_order_seq_cst
*
* This implementation follows the major compilers in not implementing memory_order_consume, and GT.M developers should not use it.
* The memory orders impose constraints on whether and how aggressively the CPU and/or compiler may do things which undermine a
* sequential order of operations across all cores. However, such a consistency with respect to a single atomic variable is
* guaranteed even in the case of a memory_order_relaxed operation. That is: if you have a reader reading an atomic variable
* and a writer incrementing it atomically, memory_order_relaxed is sufficient to guarantee that the reader never sees descending
* values (except for integer overflow). However memory_order_relaxed permits reordering of surrounding loads and stores around
* the atomic operations in general, so atomicity itself only guarantees that operations on a single variable are serializeable,
* not that operations on multiple are.
*
* memory_order_acquire and memory_order_release can be understood as the corresponding operations on a mutex (acquire and release)
* from which they take their names. Memory_order_acquire can only apply to a read, and memory_order_release can only apply to a
* write. An acquire in one thread synchronizes with a release in another thread to guarantee that if the acquire load observes
* the state of the variable created by the release store or a later state then all side effects which were visible to the writer
* at the time of the release will be visible to the reader at the time of the acquire. This can create a 'critical section',
* since it guarantees essentially that the operations which took place before the releaser releases will be contained within
* the critical section and visible to the next acquirer who reads the released value. memory_order_acq_rel is a combination
* constraint that makes sense only for atomic read-modify-write operations, like compare_and_swap or fetch_and_add
*
* memory_order_seq_cst is a little trickier to understand, but is more costly: developers should not default to this due to
* uncertainty. In addition to the guarantee provided by acquire/release orderings, memory_order_seq_cst guarantees a single
* total order of modifications that contain this constraint, even across atomic objects, and that this order will be
* observed by any loads which carry this constraint. Developers should consult the C and C++ standards for documentation.
*
* PITFALLS AND CAUTIONS
* - Developers should not declare gtm_atomic variables as volatile, as every ATOMIC_* access is converted to volatile
* by this code, either by a cast or function argument qualifier. Every access to the target gtm_atomic_* object through
* these interfaces will be a volatile one, and developers are encouraged to use the ATOMIC_* macros for every access to
* a so-declared object for this and other reasons.
* - Accesses to gtm_atomic_* objects which do not take place through the ATOMIC_* macros are subject to different
* semantics on different platforms. Where this header imports C11 atomics, for example, a ++gtm_atomic_var will compile
* to an atomic increment, whereas on other platforms this will compile to a non-atomic increment. Developers should always
* use the ATOMIC_* macros for any access of a gtm_atomic_* variable.
* - Available performance data supports the contention that the ATOMIC_LOAD and ATOMIC_STORE macros are cost-free compared
* to ordinary volatile loads and stores when given a memory_order_relaxed constraint.
*/
#ifdef __STDC_VERSION__
# if (__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_ATOMICS__)
# ifdef __has_include
# if __has_include(<stdatomic.h>)
# define GTM_USES_C11_ATOMICS
# endif
# endif
# endif
#endif
#ifdef GTM_USES_C11_ATOMICS
#include <stdatomic.h>
/* gtm_atomic types below, which generally map to atomic_* counterparts from stdatomic.h. */
typedef atomic_bool gtm_atomic_bool;
typedef atomic_char gtm_atomic_char;
typedef atomic_schar gtm_atomic_schar;
typedef atomic_uchar gtm_atomic_uchar;
typedef atomic_short gtm_atomic_short;
typedef atomic_ushort gtm_atomic_ushort;
typedef atomic_int gtm_atomic_int;
typedef atomic_uint gtm_atomic_uint;
typedef atomic_long gtm_atomic_long;
typedef atomic_ulong gtm_atomic_ulong;
typedef atomic_llong gtm_atomic_llong;
typedef atomic_ullong gtm_atomic_ullong;
typedef atomic_char16_t gtm_atomic_char16_t;
typedef atomic_char32_t gtm_atomic_char32_t;
typedef atomic_wchar_t gtm_atomic_wchar_t;
typedef atomic_int_least8_t gtm_atomic_int_least8_t;
typedef atomic_uint_least8_t gtm_atomic_uint_least8_t;
typedef atomic_int_least16_t gtm_atomic_int_least16_t;
typedef atomic_uint_least16_t gtm_atomic_uint_least16_t;
typedef atomic_int_least32_t gtm_atomic_int_least32_t;
typedef atomic_uint_least32_t gtm_atomic_uint_least32_t;
typedef atomic_int_least64_t gtm_atomic_int_least64_t;
typedef atomic_uint_least64_t gtm_atomic_uint_least64_t;
typedef atomic_int_fast8_t gtm_atomic_int_fast8_t;
typedef atomic_uint_fast8_t gtm_atomic_uint_fast8_t;
typedef atomic_int_fast16_t gtm_atomic_int_fast16_t;
typedef atomic_uint_fast16_t gtm_atomic_uint_fast16_t;
typedef atomic_int_fast32_t gtm_atomic_int_fast32_t;
typedef atomic_uint_fast32_t gtm_atomic_uint_fast32_t;
typedef atomic_int_fast64_t gtm_atomic_int_fast64_t;
typedef atomic_uint_fast64_t gtm_atomic_uint_fast64_t;
typedef atomic_intptr_t gtm_atomic_intptr_t;
typedef atomic_uintptr_t gtm_atomic_uintptr_t;
typedef atomic_size_t gtm_atomic_size_t;
typedef atomic_ptrdiff_t gtm_atomic_ptrdiff_t;
typedef atomic_intmax_t gtm_atomic_intmax_t;
typedef atomic_uintmax_t gtm_atomic_uintmax_t;
#define DEFINE_ATOMIC_OP(...)
#define DEFINE_ALL_ATOMIC_OPS(TYPE)
/* Operations for use with pointers to gtm_atomic types; most of the standard C11 operations are covered. */
#define COMPILER_FENCE(ORD) atomic_signal_fence(ORD)
#define ATOMIC_FETCH_ADD(OBJ_PTR, VAL, ORD) atomic_fetch_add_explicit((volatile __typeof__(OBJ_PTR))OBJ_PTR, VAL, ORD)
#define ATOMIC_FETCH_SUB(OBJ_PTR, VAL, ORD) atomic_fetch_sub_explicit((volatile __typeof__(OBJ_PTR))OBJ_PTR, VAL, ORD)
#define ATOMIC_COMPARE_EXCHANGE_WEAK(OBJ_PTR, EXP_PTR, VAL, SUCCESS_ORD, FAIL_ORD) \
atomic_compare_exchange_weak_explicit((volatile __typeof__(OBJ_PTR))OBJ_PTR, EXP_PTR, VAL, SUCCESS_ORD, FAIL_ORD)
#define ATOMIC_COMPARE_EXCHANGE_STRONG(OBJ_PTR, EXP_PTR, VAL, SUCCESS_ORD, FAIL_ORD) \
atomic_compare_exchange_strong_explicit((volatile __typeof__(OBJ_PTR))OBJ_PTR, EXP_PTR, VAL, SUCCESS_ORD, FAIL_ORD)
#define ATOMIC_EXCHANGE(OBJ_PTR, VAL, ORD) atomic_exchange_explicit((volatile __typeof__(OBJ_PTR))OBJ_PTR, VAL, ORD)
#define ATOMIC_FETCH_OR(OBJ_PTR, VAL, ORD) atomic_fetch_or_explicit((volatile __typeof__(OBJ_PTR))OBJ_PTR, VAL, ORD)
#define ATOMIC_FETCH_XOR(OBJ_PTR, VAL, ORD) atomic_fetch_xor_explicit((volatile __typeof__(OBJ_PTR))OBJ_PTR, VAL, ORD)
#define ATOMIC_FETCH_AND(OBJ_PTR, VAL, ORD) atomic_fetch_and_explicit((volatile __typeof__(OBJ_PTR))OBJ_PTR, VAL, ORD)
#define ATOMIC_LOAD(OBJ_PTR, ORD) atomic_load_explicit((volatile __typeof__(OBJ_PTR))OBJ_PTR, ORD)
#define ATOMIC_STORE(OBJ_PTR, VAL, ORD) atomic_store_explicit((volatile __typeof__(OBJ_PTR))OBJ_PTR, VAL, ORD)
#else /* GTM_USES_C11_ATOMICS undefined */
#include <uchar.h>
#include <wchar.h>
#include <stdint.h>
#include <limits.h>
#include <inttypes.h>
/* On platforms where C11 atomics are not supported, the gtm_atomic types map to ordinary non-volatile equivalents.
* Each access through the ATOMIC_* operations is guaranteed to be volatile, though, and developers should always use the ATOMIC_
* prefixed operations for anything involving such a variable.
*/
typedef _Bool gtm_atomic_bool;
typedef char gtm_atomic_char;
typedef signed char gtm_atomic_schar;
typedef unsigned char gtm_atomic_uchar;
typedef short gtm_atomic_short;
typedef unsigned short gtm_atomic_ushort;
typedef int gtm_atomic_int;
typedef unsigned int gtm_atomic_uint;
typedef long gtm_atomic_long;
typedef unsigned long gtm_atomic_ulong;
typedef long long gtm_atomic_llong;
typedef unsigned long long gtm_atomic_ullong;
typedef char16_t gtm_atomic_char16_t;
typedef char32_t gtm_atomic_char32_t;
typedef wchar_t gtm_atomic_wchar_t;
typedef int_least8_t gtm_atomic_int_least8_t;
typedef uint_least8_t gtm_atomic_uint_least8_t;
typedef int_least16_t gtm_atomic_int_least16_t;
typedef uint_least16_t gtm_atomic_uint_least16_t;
typedef int_least32_t gtm_atomic_int_least32_t;
typedef uint_least32_t gtm_atomic_uint_least32_t;
typedef int_least64_t gtm_atomic_int_least64_t;
typedef uint_least64_t gtm_atomic_uint_least64_t;
typedef int_fast8_t gtm_atomic_int_fast8_t;
typedef uint_fast8_t gtm_atomic_uint_fast8_t;
typedef int_fast16_t gtm_atomic_int_fast16_t;
typedef uint_fast16_t gtm_atomic_uint_fast16_t;
typedef int_fast32_t gtm_atomic_int_fast32_t;
typedef uint_fast32_t gtm_atomic_uint_fast32_t;
typedef int_fast64_t gtm_atomic_int_fast64_t;
typedef uint_fast64_t gtm_atomic_uint_fast64_t;
typedef intptr_t gtm_atomic_intptr_t;
typedef uintptr_t gtm_atomic_uintptr_t;
typedef size_t gtm_atomic_size_t;
typedef ptrdiff_t gtm_atomic_ptrdiff_t;
typedef intmax_t gtm_atomic_intmax_t;
typedef uintmax_t gtm_atomic_uintmax_t;
#if defined(__linux__) || defined(__open_xl__)
enum gtm_memory_order {
memory_order_relaxed = __ATOMIC_RELAXED,
memory_order_consume = __ATOMIC_CONSUME,
memory_order_acquire = __ATOMIC_ACQUIRE,
memory_order_release = __ATOMIC_RELEASE,
memory_order_acq_rel = __ATOMIC_ACQ_REL,
memory_order_seq_cst = __ATOMIC_SEQ_CST
};
#define DEFINE_ATOMIC_OP(...)
#define DEFINE_ALL_ATOMIC_OPS(TYPE)
#define COMPILER_FENCE(ORD) __atomic_signal_fence(ORD)
#define ATOMIC_FETCH_ADD(OBJ_PTR, VAL, ORD) __atomic_fetch_add((volatile __typeof__(OBJ_PTR))OBJ_PTR, VAL, ORD)
#define ATOMIC_FETCH_SUB(OBJ_PTR, VAL, ORD) __atomic_fetch_sub((volatile __typeof__(OBJ_PTR))OBJ_PTR, VAL, ORD)
#define ATOMIC_COMPARE_EXCHANGE_WEAK(OBJ_PTR, EXP_PTR, VAL, SUCCESS_ORD, FAIL_ORD) \
__atomic_compare_exchange_n((volatile __typeof__(OBJ_PTR))OBJ_PTR, EXP_PTR, VAL, true, SUCCESS_ORD, FAIL_ORD)
#define ATOMIC_COMPARE_EXCHANGE_STRONG(OBJ_PTR, EXP_PTR, VAL, SUCCESS_ORD, FAIL_ORD) \
__atomic_compare_exchange_n((volatile __typeof__(OBJ_PTR))OBJ_PTR, EXP_PTR, VAL, false, SUCCESS_ORD, FAIL_ORD)
#define ATOMIC_EXCHANGE(OBJ_PTR, VAL, ORD) __atomic_exchange_n((volatile __typeof__(OBJ_PTR))OBJ_PTR, VAL, ORD)
#define ATOMIC_FETCH_OR(OBJ_PTR, VAL, ORD) __atomic_fetch_or((volatile __typeof__(OBJ_PTR))OBJ_PTR, VAL, ORD)
#define ATOMIC_FETCH_XOR(OBJ_PTR, VAL, ORD) __atomic_fetch_xor((volatile __typeof__(OBJ_PTR))OBJ_PTR, VAL, ORD)
#define ATOMIC_FETCH_AND(OBJ_PTR, VAL, ORD) __atomic_fetch_and((volatile __typeof__(OBJ_PTR))OBJ_PTR, VAL, ORD)
#define ATOMIC_LOAD(OBJ_PTR, ORD) __atomic_load_n((volatile __typeof__(OBJ_PTR))OBJ_PTR, ORD)
#define ATOMIC_STORE(OBJ_PTR, VAL, ORD) __atomic_store_n((volatile __typeof__(OBJ_PTR))OBJ_PTR, VAL, ORD)
#elif defined (_AIX)
/* All code past this point is aix-specific, and makes extensive use of inline assembly.
* Since, as of this writing, inline assembly is uncommon in the GT.M codebase, its use deserves some explanation and justification.
* The ground truth source for all information on inline assembly syntax is the xlc user manual's page on the inline assembly
* extension.
*
* The reason for using assembly at all is that there are specific necessary constructions that would be optimized out
* by any C compiler but provide crucial ordering guarantees. The most important of these is the branch-isync construction,
* where a branch (often of a condition that is guaranteed true) is followed by an isync; the branch makes sure that whatever
* operations the branch depends on has completed prior to the isync and the isync discards all prefetched instructions. It's
* impossible to write C code that can be guaranteed to compile down to this sequence. As for why the assembly is inline rather
* than in its own files, the justification is performance: by allowing the compiler to choose the best registers for each
* operand, this code avoids forcing use of one or more registers which have hot variables.
*
* Most of the basics necessary to understand and/or edit this assembly can be understood from the xlc documentation mentioned
* above, but a few words here on some particular constructions used by this code:
* - Powerpc in some cases expects an address in a register as an operand (such as for the load-linked/store-conditional
* lwarx/stwcx. pair) but in other cases expects an offsettable memory address (also in a register but handled differently
* in specifying it in the inline assembly), such as for a bare load and/or store. Whenever able, it is good to specify
* the memory operand "m" as the output and/or input operand. Why? One important purpose of operand specification is to
* tell the compiler which registers and/or memory locations will be changed by the assembly. If "+m" (*OBJ_PTR) is given,
* then the compiler will know that the location of *OBJ_PTR is read and modified by the assembly, and any registers which
* had cached that value will need to be refreshed. When it is impossible to use the memory operand directly (such as in
* the load-linked/store-conditional cases) this code still passes the memory location written to and/or read from in this
* way, even if the named operand is not actually invoked in the assembly, so as to inform the compiler that this location
* is affected without needing to include a "memory" clobber.
* - Generally this code has avoided passing a "memory" clobber on the basis of the effectiveness of what was described
* above and the view that any access which is genuinely volatile will be made as such by the surrounding code. The volatile
* specifier of the asm string itself guarantees no compiler reordering around the implicit fences at the beginning and end
* of the assembly, but does not, for example, universally invalidate all pointer values held in registers as if the assembly
* string could have written to any and every variable on the stack or in the heap. This decision rests on the justified
* premise that the compiler will not ignore the clobber implications of an unused memory operand, which has been validated
* by extensive testing. But the view should be re-examined if atomics testing starts to turn up failures.
*/
/* Internally we depend on the following invariants to ensure we're using the correct precsision of loads/stores and sign-extending
* where necessary.
*/
#define GTM_ATOMIC_BOOL_WIDTH 1
#define GTM_ATOMIC_CHAR_WIDTH 1
#define GTM_ATOMIC_SCHAR_WIDTH 1
#define GTM_ATOMIC_UCHAR_WIDTH 1
#define GTM_ATOMIC_SHORT_WIDTH 2
#define GTM_ATOMIC_USHORT_WIDTH 2
#define GTM_ATOMIC_INT_WIDTH 4
#define GTM_ATOMIC_UINT_WIDTH 4
#define GTM_ATOMIC_LONG_WIDTH 8
#define GTM_ATOMIC_ULONG_WIDTH 8
#define GTM_ATOMIC_LLONG_WIDTH 8
#define GTM_ATOMIC_ULLONG_WIDTH 8
_Static_assert(GTM_ATOMIC_BOOL_WIDTH == sizeof(gtm_atomic_bool),
"Preprocessor size of gtm_atomic_bool incorrect");
_Static_assert(GTM_ATOMIC_CHAR_WIDTH == sizeof(gtm_atomic_char),
"Preprocessor size of gtm_atomic_char incorrect");
_Static_assert(GTM_ATOMIC_SCHAR_WIDTH == sizeof(gtm_atomic_schar),
"Preprocessor size of gtm_atomic_schar incorrect");
_Static_assert(GTM_ATOMIC_UCHAR_WIDTH == sizeof(gtm_atomic_uchar),
"Preprocessor size of gtm_atomic_uchar incorrect");
_Static_assert(GTM_ATOMIC_SHORT_WIDTH == sizeof(gtm_atomic_short),
"Preprocessor size of gtm_atomic_short incorrect");
_Static_assert(GTM_ATOMIC_USHORT_WIDTH == sizeof(gtm_atomic_ushort),
"Preprocessor size of gtm_atomic_ushort incorrect");
_Static_assert(GTM_ATOMIC_INT_WIDTH == sizeof(gtm_atomic_int),
"Preprocessor size of gtm_atomic_int incorrect");
_Static_assert(GTM_ATOMIC_UINT_WIDTH == sizeof(gtm_atomic_uint),
"Preprocessor size of gtm_atomic_uint incorrect");
_Static_assert(GTM_ATOMIC_LONG_WIDTH == sizeof(gtm_atomic_long),
"Preprocessor size of gtm_atomic_long incorrect");
_Static_assert(GTM_ATOMIC_ULONG_WIDTH == sizeof(gtm_atomic_ulong),
"Preprocessor size of gtm_atomic_ulong incorrect");
_Static_assert(GTM_ATOMIC_LLONG_WIDTH == sizeof(gtm_atomic_llong),
"Preprocessor size of gtm_atomic_llong incorrect");
_Static_assert(GTM_ATOMIC_ULLONG_WIDTH == sizeof(gtm_atomic_ullong),
"Preprocessor size of gtm_atomic_ullong incorrect");
_Static_assert(sizeof(gtm_atomic_short) == sizeof(gtm_atomic_char16_t),
"Preprocessor size of gtm_atomic_char16_t incorrect");
_Static_assert(sizeof(gtm_atomic_int) == sizeof(gtm_atomic_char32_t),
"Preprocessor size of gtm_atomic_char32_t incorrect");
_Static_assert(sizeof(gtm_atomic_int) == sizeof(gtm_atomic_wchar_t),
"Preprocessor size of gtm_atomic_wchar_t incorrect");
_Static_assert(sizeof(gtm_atomic_schar) == sizeof(gtm_atomic_int_least8_t),
"Preprocessor size of gtm_atomic_int_least8_t incorrect");
_Static_assert(sizeof(gtm_atomic_uchar) == sizeof(gtm_atomic_uint_least8_t),
"Preprocessor size of gtm_atomic_uint_least8_t incorrect");
_Static_assert(sizeof(gtm_atomic_short) == sizeof(gtm_atomic_int_least16_t),
"Preprocessor size of gtm_atomic_int_least16_t incorrect");
_Static_assert(sizeof(gtm_atomic_ushort) == sizeof(gtm_atomic_uint_least16_t),
"Preprocessor size of gtm_atomic_uint_least16_t incorrect");
_Static_assert(sizeof(gtm_atomic_int) == sizeof(gtm_atomic_int_least32_t),
"Preprocessor size of gtm_atomic_int_least32_t incorrect");
_Static_assert(sizeof(gtm_atomic_uint) == sizeof(gtm_atomic_uint_least32_t),
"Preprocessor size of gtm_atomic_uint_least32_t incorrect");
_Static_assert(sizeof(gtm_atomic_long) == sizeof(gtm_atomic_int_least64_t),
"Preprocessor size of gtm_atomic_int_least64_t incorrect");
_Static_assert(sizeof(gtm_atomic_ulong) == sizeof(gtm_atomic_uint_least64_t),
"Preprocessor size of gtm_atomic_uint_least64_t incorrect");
_Static_assert(sizeof(gtm_atomic_schar) == sizeof(gtm_atomic_int_fast8_t),
"Preprocessor size of gtm_atomic_int_fast8_t incorrect");
_Static_assert(sizeof(gtm_atomic_uchar) == sizeof(gtm_atomic_uint_fast8_t),
"Preprocessor size of gtm_atomic_uint_fast8_t incorrect");
_Static_assert(sizeof(gtm_atomic_short) == sizeof(gtm_atomic_int_fast16_t),
"Preprocessor size of gtm_atomic_int_fast16_t incorrect");
_Static_assert(sizeof(gtm_atomic_ushort) == sizeof(gtm_atomic_uint_fast16_t),
"Preprocessor size of gtm_atomic_uint_fast16_t incorrect");
_Static_assert(sizeof(gtm_atomic_int) == sizeof(gtm_atomic_int_fast32_t),
"Preprocessor size of gtm_atomic_int_fast32_t incorrect");
_Static_assert(sizeof(gtm_atomic_uint) == sizeof(gtm_atomic_uint_fast32_t),
"Preprocessor size of gtm_atomic_uint_fast32_t incorrect");
_Static_assert(sizeof(gtm_atomic_long) == sizeof(gtm_atomic_int_fast64_t),
"Preprocessor size of gtm_atomic_int_fast64_t incorrect");
_Static_assert(sizeof(gtm_atomic_ulong) == sizeof(gtm_atomic_uint_fast64_t),
"Preprocessor size of gtm_atomic_uint_fast64_t incorrect");
_Static_assert(sizeof(gtm_atomic_long) == sizeof(gtm_atomic_intptr_t),
"Preprocessor size of gtm_atomic_intptr_t incorrect");
_Static_assert(sizeof(gtm_atomic_ulong) == sizeof(gtm_atomic_uintptr_t),
"Preprocessor size of gtm_atomic_uintptr_t incorrect");
_Static_assert(sizeof(gtm_atomic_ulong) == sizeof(gtm_atomic_size_t),
"Preprocessor size of gtm_atomic_size_t incorrect");
_Static_assert(sizeof(gtm_atomic_long) == sizeof(gtm_atomic_ptrdiff_t),
"Preprocessor size of gtm_atomic_ptrdiff_t incorrect");
_Static_assert(sizeof(gtm_atomic_long) == sizeof(gtm_atomic_intmax_t),
"Preprocessor size of gtm_atomic_intmax_t incorrect");
_Static_assert(sizeof(gtm_atomic_ulong) == sizeof(gtm_atomic_uintmax_t),
"Preprocessor size of gtm_atomic_uintmax_t incorrect");
/* The following macros provide the name of the atomic function to call, given the operation, type, and memory order. */
#ifdef _ARCH_PWR8
#define FOP_TYPE_ORD_MNEMONIC(OP, OBJ_PTR, ORD) _Generic(((__typeof__(OBJ_PTR)){ 0 }), \
gtm_atomic_bool *: OP##__gtm_atomic_bool__##ORD, \
gtm_atomic_char *: OP##__gtm_atomic_char__##ORD, \
gtm_atomic_schar *: OP##__gtm_atomic_schar__##ORD, \
gtm_atomic_uchar *: OP##__gtm_atomic_uchar__##ORD, \
gtm_atomic_short *: OP##__gtm_atomic_short__##ORD, \
gtm_atomic_ushort *: OP##__gtm_atomic_ushort__##ORD, \
gtm_atomic_int *: OP##__gtm_atomic_int__##ORD, \
gtm_atomic_uint *: OP##__gtm_atomic_uint__##ORD, \
gtm_atomic_long *: OP##__gtm_atomic_long__##ORD, \
gtm_atomic_ulong *: OP##__gtm_atomic_ulong__##ORD, \
gtm_atomic_llong *: OP##__gtm_atomic_llong__##ORD, \
gtm_atomic_ullong *: OP##__gtm_atomic_ullong__##ORD)
#else
#define FOP_TYPE_ORD_MNEMONIC(OP, OBJ_PTR, ORD) _Generic(((__typeof__(OBJ_PTR)){ 0 }), \
gtm_atomic_int *: OP##__gtm_atomic_int__##ORD, \
gtm_atomic_uint *: OP##__gtm_atomic_uint__##ORD, \
gtm_atomic_long *: OP##__gtm_atomic_long__##ORD, \
gtm_atomic_ulong *: OP##__gtm_atomic_ulong__##ORD, \
gtm_atomic_llong *: OP##__gtm_atomic_llong__##ORD, \
gtm_atomic_ullong *: OP##__gtm_atomic_ullong__##ORD)
#endif
#define OP_TYPE_ORD_MNEMONIC(OP, OBJ_PTR, ORD) _Generic(((__typeof__(OBJ_PTR)){ 0 }), \
gtm_atomic_bool *: OP##__gtm_atomic_bool__##ORD, \
gtm_atomic_char *: OP##__gtm_atomic_char__##ORD, \
gtm_atomic_schar *: OP##__gtm_atomic_schar__##ORD, \
gtm_atomic_uchar *: OP##__gtm_atomic_uchar__##ORD, \
gtm_atomic_short *: OP##__gtm_atomic_short__##ORD, \
gtm_atomic_ushort *: OP##__gtm_atomic_ushort__##ORD, \
gtm_atomic_int *: OP##__gtm_atomic_int__##ORD, \
gtm_atomic_uint *: OP##__gtm_atomic_uint__##ORD, \
gtm_atomic_long *: OP##__gtm_atomic_long__##ORD, \
gtm_atomic_ulong *: OP##__gtm_atomic_ulong__##ORD, \
gtm_atomic_llong *: OP##__gtm_atomic_llong__##ORD, \
gtm_atomic_ullong *: OP##__gtm_atomic_ullong__##ORD)
/* Powerpc assembly for stores, for each supported type-width. */
#define PPC_ASM_ST__gtm_atomic_char__(OBJ_PTR, VAL, PRE_BARRIER, POST_BARRIER) \
asm volatile ( "0:"PRE_BARRIER \
"\tstb %[value],%[obj]\n" \
POST_BARRIER \
: [obj] "=m" (*OBJ_PTR) \
: [value] "r" (VAL) \
:)
#define PPC_ASM_ST__gtm_atomic_short__(OBJ_PTR, VAL, PRE_BARRIER, POST_BARRIER) \
asm volatile ( "0:"PRE_BARRIER \
"\tsth %[value],%[obj]\n" \
POST_BARRIER \
: [obj] "=m" (*OBJ_PTR) \
: [value] "r" (VAL) \
:)
#define PPC_ASM_ST__gtm_atomic_int__(OBJ_PTR, VAL, PRE_BARRIER, POST_BARRIER) \
asm volatile ( "0:"PRE_BARRIER \
"\tstw %[value],%[obj]\n" \
POST_BARRIER \
: [obj] "=m" (*OBJ_PTR) \
: [value] "r" (VAL) \
:)
#define PPC_ASM_ST__gtm_atomic_long__(OBJ_PTR, VAL, PRE_BARRIER, POST_BARRIER) \
asm volatile ( "0:"PRE_BARRIER \
"\tstd %[value],%[obj]\n" \
POST_BARRIER \
: [obj] "=m" (*OBJ_PTR) \
: [value] "r" (VAL) \
:)
#define PPC_ASM_ST__gtm_atomic_bool__ PPC_ASM_ST__gtm_atomic_char__
#define PPC_ASM_ST__gtm_atomic_schar__ PPC_ASM_ST__gtm_atomic_char__
#define PPC_ASM_ST__gtm_atomic_uchar__ PPC_ASM_ST__gtm_atomic_char__
#define PPC_ASM_ST__gtm_atomic_ushort__ PPC_ASM_ST__gtm_atomic_short__
#define PPC_ASM_ST__gtm_atomic_uint__ PPC_ASM_ST__gtm_atomic_int__
#define PPC_ASM_ST__gtm_atomic_ulong__ PPC_ASM_ST__gtm_atomic_long__
#define PPC_ASM_ST__gtm_atomic_llong__ PPC_ASM_ST__gtm_atomic_long__
#define PPC_ASM_ST__gtm_atomic_ullong__ PPC_ASM_ST__gtm_atomic_long__
/* Powerpc assembly for loads, for each supported sign/type-width combination. */
#define PPC_ASM_LD__gtm_atomic_uchar__(OBJ_PTR, RET, PRE_BARRIER, POST_BARRIER) \
asm volatile ( "0:"PRE_BARRIER \
"\tlbz %[retval],%[obj]\n" \
POST_BARRIER \
: [retval] "=r" (RET) \
: [obj] "m" (*OBJ_PTR) \
:)
#define PPC_ASM_LD__gtm_atomic_schar__(OBJ_PTR, RET, PRE_BARRIER, POST_BARRIER) \
asm volatile ( "0:"PRE_BARRIER \
"\tlbz %[retval],%[obj]\n" \
"\textsb %[retval],%[retval]\n" \
POST_BARRIER \
: [retval] "=r" (RET) \
: [obj] "m" (*OBJ_PTR) \
:)
#define PPC_ASM_LD__gtm_atomic_ushort__(OBJ_PTR, RET, PRE_BARRIER, POST_BARRIER) \
asm volatile ( "0:"PRE_BARRIER \
"\tlhz %[retval],%[obj]\n" \
POST_BARRIER \
: [retval] "=r" (RET) \
: [obj] "m" (*OBJ_PTR) \
:)
#define PPC_ASM_LD__gtm_atomic_short__(OBJ_PTR, RET, PRE_BARRIER, POST_BARRIER) \
asm volatile ( "0:"PRE_BARRIER \
"\tlha %[retval],%[obj]\n" \
POST_BARRIER \
: [retval] "=r" (RET) \
: [obj] "m" (*OBJ_PTR) \
:)
#define PPC_ASM_LD__gtm_atomic_uint__(OBJ_PTR, RET, PRE_BARRIER, POST_BARRIER) \
asm volatile ( "0:"PRE_BARRIER \
"\tlwz %[retval],%[obj]\n" \
POST_BARRIER \
: [retval] "=r" (RET) \
: [obj] "m" (*OBJ_PTR) \
:)
#define PPC_ASM_LD__gtm_atomic_int__(OBJ_PTR, RET, PRE_BARRIER, POST_BARRIER) \
asm volatile ( "0:"PRE_BARRIER \
"\tlwa %[retval],%[obj]\n" \
POST_BARRIER \
: [retval] "=r" (RET) \
: [obj] "m" (*OBJ_PTR) \
:)
#define PPC_ASM_LD__gtm_atomic_long__(OBJ_PTR, RET, PRE_BARRIER, POST_BARRIER) \
asm volatile ( "0:"PRE_BARRIER \
"\tld %[retval],%[obj]\n" \
POST_BARRIER \
: [retval] "=r" (RET) \
: [obj] "m" (*OBJ_PTR) \
:)
#ifdef __CHAR_SIGNED__
#define PPC_ASM_LD__gtm_atomic_char__ PPC_ASM_LD__gtm_atomic_schar__
#else
#define PPC_ASM_LD__gtm_atomic_char__ PPC_ASM_LD__gtm_atomic_uchar__
#endif
#define PPC_ASM_LD__gtm_atomic_bool__ PPC_ASM_LD__gtm_atomic_char__
#define PPC_ASM_LD__gtm_atomic_ulong__ PPC_ASM_LD__gtm_atomic_long__
#define PPC_ASM_LD__gtm_atomic_llong__ PPC_ASM_LD__gtm_atomic_long__
#define PPC_ASM_LD__gtm_atomic_ullong__ PPC_ASM_LD__gtm_atomic_long__
/* Powerpc assembly for loads with trailing branch-conditionals, for each supported sign/type-width combination. */
#define PPC_ASM_LDCMP__gtm_atomic_uchar__(OBJ_PTR, RET, PRE_BARRIER, POST_BARRIER) \
asm volatile ( "0:"PRE_BARRIER \
"\tlbz %[retval],%[obj]\n" \
"\tcmp 0,0,%[retval],%[retval]\n" \
"\tbne- 0b\n" \
POST_BARRIER \
: [retval] "=r" (RET) \
: [obj] "m" (*OBJ_PTR) \
: "cr0")
#define PPC_ASM_LDCMP__gtm_atomic_schar__(OBJ_PTR, RET, PRE_BARRIER, POST_BARRIER) \
asm volatile ( "0:"PRE_BARRIER \
"\tlbz %[retval],%[obj]\n" \
"\textsb %[retval],%[retval]\n" \
"\tcmp 0,0,%[retval],%[retval]\n" \
"\tbne- 0b\n" \
POST_BARRIER \
: [retval] "=r" (RET) \
: [obj] "m" (*OBJ_PTR) \
: "cr0")
#define PPC_ASM_LDCMP__gtm_atomic_ushort__(OBJ_PTR, RET, PRE_BARRIER, POST_BARRIER) \
asm volatile ( "0:"PRE_BARRIER \
"\tlha %[retval],%[obj]\n" \
"\tcmp 0,0,%[retval],%[retval]\n" \
"\tbne- 0b\n" \
POST_BARRIER \
: [retval] "=r" (RET) \
: [obj] "m" (*OBJ_PTR) \
: "cr0")
#define PPC_ASM_LDCMP__gtm_atomic_short__(OBJ_PTR, RET, PRE_BARRIER, POST_BARRIER) \
asm volatile ( "0:"PRE_BARRIER \
"\tlhz %[retval],%[obj]\n" \
"\tcmp 0,0,%[retval],%[retval]\n" \
"\tbne- 0b\n" \
POST_BARRIER \
: [retval] "=r" (RET) \
: [obj] "m" (*OBJ_PTR) \
: "cr0")
#define PPC_ASM_LDCMP__gtm_atomic_uint__(OBJ_PTR, RET, PRE_BARRIER, POST_BARRIER) \
asm volatile ( "0:"PRE_BARRIER \
"\tlwz %[retval],%[obj]\n" \
"\tcmp 0,0,%[retval],%[retval]\n" \
"\tbne- 0b\n" \
POST_BARRIER \
: [retval] "=r" (RET) \
: [obj] "m" (*OBJ_PTR) \
: "cr0")
#define PPC_ASM_LDCMP__gtm_atomic_int__(OBJ_PTR, RET, PRE_BARRIER, POST_BARRIER) \
asm volatile ( "0:"PRE_BARRIER \
"\tlwa %[retval],%[obj]\n" \
"\tcmp 0,0,%[retval],%[retval]\n" \
"\tbne- 0b\n" \
POST_BARRIER \
: [retval] "=r" (RET) \
: [obj] "m" (*OBJ_PTR) \
: "cr0")
#define PPC_ASM_LDCMP__gtm_atomic_long__(OBJ_PTR, RET, PRE_BARRIER, POST_BARRIER) \
asm volatile ( "0:"PRE_BARRIER \
"\tld %[retval],%[obj]\n" \
"\tcmp 0,1,%[retval],%[retval]\n" \
"\tbne- 0b\n" \
POST_BARRIER \
: [retval] "=r" (RET) \
: [obj] "m" (*OBJ_PTR) \
: "cr0")
#define PPC_ASM_LDCMP__gtm_atomic_bool__ PPC_ASM_LDCMP__gtm_atomic_uchar__
#ifdef __CHAR_SIGNED__
#define PPC_ASM_LDCMP__gtm_atomic_char__ PPC_ASM_LDCMP__gtm_atomic_schar__
#else
#define PPC_ASM_LDCMP__gtm_atomic_char__ PPC_ASM_LDCMP__gtm_atomic_uchar__
#endif
#define PPC_ASM_LDCMP__gtm_atomic_ulong__ PPC_ASM_LDCMP__gtm_atomic_long__
#define PPC_ASM_LDCMP__gtm_atomic_llong__ PPC_ASM_LDCMP__gtm_atomic_long__
#define PPC_ASM_LDCMP__gtm_atomic_ullong__ PPC_ASM_LDCMP__gtm_atomic_long__
/* Load-linked/store-conditional with (ATOMIC_FETCH_*) and without (ATOMIC_EXCHANGE) intervening operation.
* Sign- vs zero- extension handling necessary here because the FETCH_* op returns the value, which surrounding assembly may expect
* will be sign-or-zero-extended.
*/
#ifdef _ARCH_PWR8
#define PPC_ASM_XCHG__gtm_atomic_uchar__(OBJ_PTR, VAL, RET, PRE_BARRIER, POST_BARRIER) \
asm volatile ( PRE_BARRIER \
"0:\tlbarx %[retval],0,%[obj_ptr]\n" \
"\tstbcx. %[val],0,%[obj_ptr]\n" \
"\tbne- 0b\n" \
POST_BARRIER \
: [retval] "=&r" (RET), \
[obj] "+m" (*OBJ_PTR) \
: [val] "r" (VAL), \
[obj_ptr] "r" (OBJ_PTR) \
: "cr0")
#define PPC_ASM_LLSC__gtm_atomic_uchar__(OBJ_PTR, VAL, RET, ASM_OP, PRE_BARRIER, POST_BARRIER) \
asm volatile ( PRE_BARRIER \
"0:\tlbarx %[retval],0,%[obj_ptr]\n" \
ASM_OP \
"\tstbcx. %[scratch],0,%[obj_ptr]\n" \
"\tbne- 0b\n" \
POST_BARRIER \
: [retval] "=&r" (RET), \
[obj] "+m" (*OBJ_PTR), \
[scratch] "=&r" (((__typeof__(VAL)){ 0 })) \
: [val] "r" (VAL), \
[obj_ptr] "r" (OBJ_PTR) \
: "cr0")
#define PPC_ASM_XCHG__gtm_atomic_schar__(OBJ_PTR, VAL, RET, PRE_BARRIER, POST_BARRIER) \
asm volatile ( PRE_BARRIER \
"0:\tlbarx %[retval],0,%[obj_ptr]\n" \
"\tstbcx. %[val],0,%[obj_ptr]\n" \
"\tbne- 0b\n" \
"\textsb %[retval],%[retval]\n" \
POST_BARRIER \
: [retval] "=&r" (RET), \
[obj] "+m" (*OBJ_PTR) \
: [val] "r" (VAL), \
[obj_ptr] "r" (OBJ_PTR) \
: "cr0")
#define PPC_ASM_LLSC__gtm_atomic_schar__(OBJ_PTR, VAL, RET, ASM_OP, PRE_BARRIER, POST_BARRIER) \
asm volatile ( PRE_BARRIER \
"0:\tlbarx %[retval],0,%[obj_ptr]\n" \
"\textsb %[retval],%[retval]\n" \
ASM_OP \
"\tstbcx. %[scratch],0,%[obj_ptr]\n" \
"\tbne- 0b\n" \
POST_BARRIER \
: [retval] "=&r" (RET), \
[obj] "+m" (*OBJ_PTR), \
[scratch] "=&r" (((__typeof__(VAL)){ 0 })) \
: [val] "r" (VAL), \
[obj_ptr] "r" (OBJ_PTR) \
: "cr0")
#define PPC_ASM_XCHG__gtm_atomic_ushort__(OBJ_PTR, VAL, RET, PRE_BARRIER, POST_BARRIER) \
asm volatile ( PRE_BARRIER \
"0:\tlharx %[retval],0,%[obj_ptr]\n" \
"\tsthcx. %[val],0,%[obj_ptr]\n" \
"\tbne- 0b\n" \
POST_BARRIER \
: [retval] "=&r" (RET), \
[obj] "+m" (*OBJ_PTR) \
: [val] "r" (VAL), \
[obj_ptr] "r" (OBJ_PTR) \
: "cr0")
#define PPC_ASM_LLSC__gtm_atomic_ushort__(OBJ_PTR, VAL, RET, ASM_OP, PRE_BARRIER, POST_BARRIER) \
asm volatile ( PRE_BARRIER \
"0:\tlharx %[retval],0,%[obj_ptr]\n" \
ASM_OP \
"\tsthcx. %[scratch],0,%[obj_ptr]\n" \
"\tbne- 0b\n" \
POST_BARRIER \
: [retval] "=&r" (RET), \
[obj] "+m" (*OBJ_PTR), \
[scratch] "=&r" (((__typeof__(VAL)){ 0 })) \
: [val] "r" (VAL), \
[obj_ptr] "r" (OBJ_PTR) \
: "cr0")
#define PPC_ASM_XCHG__gtm_atomic_short__(OBJ_PTR, VAL, RET, PRE_BARRIER, POST_BARRIER) \
asm volatile ( PRE_BARRIER \
"0:\tlharx %[retval],0,%[obj_ptr]\n" \
"\tsthcx. %[val],0,%[obj_ptr]\n" \
"\tbne- 0b\n" \
"\textsh %[retval],%[retval]\n" \
POST_BARRIER \
: [retval] "=&r" (RET), \
[obj] "+m" (*OBJ_PTR) \
: [val] "r" (VAL), \
[obj_ptr] "r" (OBJ_PTR) \
: "cr0")
#define PPC_ASM_LLSC__gtm_atomic_short__(OBJ_PTR, VAL, RET, ASM_OP, PRE_BARRIER, POST_BARRIER) \
asm volatile ( PRE_BARRIER \
"0:\tlharx %[retval],0,%[obj_ptr]\n" \
"\textsh %[retval],%[retval]\n" \
ASM_OP \
"\tsthcx. %[scratch],0,%[obj_ptr]\n" \
"\tbne- 0b\n" \
POST_BARRIER \
: [retval] "=&r" (RET), \
[obj] "+m" (*OBJ_PTR), \
[scratch] "=&r" (((__typeof__(VAL)){ 0 })) \
: [val] "r" (VAL), \
[obj_ptr] "r" (OBJ_PTR) \
: "cr0")
#endif
#define PPC_ASM_XCHG__gtm_atomic_uint__(OBJ_PTR, VAL, RET, PRE_BARRIER, POST_BARRIER) \
asm volatile ( PRE_BARRIER \
"0:\tlwarx %[retval],0,%[obj_ptr]\n" \
"\tstwcx. %[val],0,%[obj_ptr]\n" \
"\tbne- 0b\n" \
POST_BARRIER \
: [retval] "=&r" (RET), \
[obj] "+m" (*OBJ_PTR) \
: [val] "r" (VAL), \
[obj_ptr] "r" (OBJ_PTR) \
: "cr0")
#define PPC_ASM_LLSC__gtm_atomic_uint__(OBJ_PTR, VAL, RET, ASM_OP, PRE_BARRIER, POST_BARRIER) \
asm volatile ( PRE_BARRIER \
"0:\tlwarx %[retval],0,%[obj_ptr]\n" \
ASM_OP \
"\tstwcx. %[scratch],0,%[obj_ptr]\n" \
"\tbne- 0b\n" \
POST_BARRIER \
: [retval] "=&r" (RET), \
[obj] "+m" (*OBJ_PTR), \
[scratch] "=&r" (((__typeof__(VAL)){ 0 })) \
: [val] "r" (VAL), \
[obj_ptr] "r" (OBJ_PTR) \
: "cr0")
#define PPC_ASM_XCHG__gtm_atomic_int__(OBJ_PTR, VAL, RET, PRE_BARRIER, POST_BARRIER) \
asm volatile ( PRE_BARRIER \
"0:\tlwarx %[retval],0,%[obj_ptr]\n" \
"\tstwcx. %[val],0,%[obj_ptr]\n" \
"\tbne- 0b\n" \
"\textsw %[retval],%[retval]\n" \
POST_BARRIER \
: [retval] "=&r" (RET), \
[obj] "+m" (*OBJ_PTR) \
: [val] "r" (VAL), \
[obj_ptr] "r" (OBJ_PTR) \
: "cr0")
#define PPC_ASM_LLSC__gtm_atomic_int__(OBJ_PTR, VAL, RET, ASM_OP, PRE_BARRIER, POST_BARRIER) \
asm volatile ( PRE_BARRIER \
"0:\tlwarx %[retval],0,%[obj_ptr]\n" \
"\textsw %[retval],%[retval]\n" \
ASM_OP \
"\tstwcx. %[scratch],0,%[obj_ptr]\n" \
"\tbne- 0b\n" \
POST_BARRIER \
: [retval] "=&r" (RET), \
[obj] "+m" (*OBJ_PTR), \
[scratch] "=&r" (((__typeof__(VAL)){ 0 })) \
: [val] "r" (VAL), \
[obj_ptr] "r" (OBJ_PTR) \
: "cr0")
#define PPC_ASM_XCHG__gtm_atomic_long__(OBJ_PTR, VAL, RET, PRE_BARRIER, POST_BARRIER) \
asm volatile ( PRE_BARRIER \
"0:\tldarx %[retval],0,%[obj_ptr]\n" \
"\tstdcx. %[val],0,%[obj_ptr]\n" \
"\tbne- 0b\n" \
POST_BARRIER \
: [retval] "=&r" (RET), \
[obj] "+m" (*OBJ_PTR) \
: [val] "r" (VAL), \
[obj_ptr] "r" (OBJ_PTR) \
: "cr0")
#define PPC_ASM_LLSC__gtm_atomic_long__(OBJ_PTR, VAL, RET, ASM_OP, PRE_BARRIER, POST_BARRIER) \
asm volatile ( PRE_BARRIER \
"0:\tldarx %[retval],0,%[obj_ptr]\n" \
ASM_OP \
"\tstdcx. %[scratch],0,%[obj_ptr]\n" \
"\tbne- 0b\n" \
POST_BARRIER \
: [retval] "=&r" (RET), \
[obj] "+m" (*OBJ_PTR), \
[scratch] "=&r" (((__typeof__(VAL)){ 0 })) \
: [val] "r" (VAL), \
[obj_ptr] "r" (OBJ_PTR) \
: "cr0")
#ifdef _ARCH_PWR8
#define PPC_ASM_LLSC__gtm_atomic_bool__ PPC_ASM_LLSC__gtm_atomic_uchar__
#define PPC_ASM_XCHG__gtm_atomic_bool__ PPC_ASM_XCHG__gtm_atomic_uchar__
#ifdef __CHAR_SIGNED__
#define PPC_ASM_LLSC__gtm_atomic_char__ PPC_ASM_LLSC__gtm_atomic_schar__
#define PPC_ASM_XCHG__gtm_atomic_char__ PPC_ASM_XCHG__gtm_atomic_schar__
#else
#define PPC_ASM_LLSC__gtm_atomic_char__ PPC_ASM_LLSC__gtm_atomic_uchar__
#define PPC_ASM_XCHG__gtm_atomic_char__ PPC_ASM_XCHG__gtm_atomic_uchar__
#endif
#endif
#define PPC_ASM_LLSC__gtm_atomic_ulong__ PPC_ASM_LLSC__gtm_atomic_long__
#define PPC_ASM_LLSC__gtm_atomic_llong__ PPC_ASM_LLSC__gtm_atomic_long__
#define PPC_ASM_LLSC__gtm_atomic_ullong__ PPC_ASM_LLSC__gtm_atomic_long__
#define PPC_ASM_XCHG__gtm_atomic_ulong__ PPC_ASM_XCHG__gtm_atomic_long__
#define PPC_ASM_XCHG__gtm_atomic_llong__ PPC_ASM_XCHG__gtm_atomic_long__
#define PPC_ASM_XCHG__gtm_atomic_ullong__ PPC_ASM_XCHG__gtm_atomic_long__
/* Compare-and-swap assembly for powerpc for all supported type-width/sign combinations.
* Since we return a bool and write to EXP_PTR using the fixed-with store operations, sign-handling
* is only necessary to make sure the comparison is correct and we leave the exp_reg in an alright state
* if we are identifying it as an output register (even though the compiler should force a re-load from memory
* since the location is always a write-out "=m" operand). So for the widths that don't have width-compares
* (cmp x,1,x,x means long-compare and cmp x,0,x,x means 32-bit compare), we use clrldi to zero out everything
* but the bits inside the width, so compares with l{h,b}arx-loaded values will come out right. In case the compiler
* thinks the register is still valid, we also reset it with an extsh or extsb as appropriate at the end.
*/
#ifdef _ARCH_PWR8
#define PPC_ASM_CMPSWAP__gtm_atomic_uchar__(OBJ_PTR, EXP_PTR, VAL, RET, PRE_BARRIER, SUCCESS_BARRIER, FAIL_BARRIER) \
asm volatile ( "\tli %[retval],1\n" \
PRE_BARRIER \
"0:\tlbarx %[scratch],0,%[obj_ptr]\n" \
"\tcmp 0,0,%[scratch],%[exp_reg]\n" \
"\tbne- 1f\n" \
"\tstbcx. %[val],0,%[obj_ptr]\n" \
"\tbne- 0b\n" \
SUCCESS_BARRIER \
"\tb 2f\n" \
"1:"FAIL_BARRIER \
"\tli %[retval],0\n" \
"\tstb %[scratch],%[exp]\n" \
"2:\t\n" \
: [exp] "=m" (*EXP_PTR), \
[obj] "+m" (*OBJ_PTR), \
[scratch] "=&r" (((__typeof__(VAL)){ 0 })), \
[retval] "=&r" (RET) \
: [exp_reg] "r" (*(volatile __typeof__(EXP_PTR))EXP_PTR), \
[val] "r" (VAL), \
[obj_ptr] "r" (OBJ_PTR) \
: "cr0")
#define PPC_ASM_CMPSWAP__gtm_atomic_schar__(OBJ_PTR, EXP_PTR, VAL, RET, PRE_BARRIER, SUCCESS_BARRIER, FAIL_BARRIER) \
asm volatile ( "\tli %[retval],1\n" \
"\tclrldi %[exp_reg],%[exp_reg],56\n" \
PRE_BARRIER \
"0:\tlbarx %[scratch],0,%[obj_ptr]\n" \
"\tcmp 0,0,%[scratch],%[exp_reg]\n" \
"\tbne- 1f\n" \
"\tstbcx. %[val],0,%[obj_ptr]\n" \
"\tbne- 0b\n" \
SUCCESS_BARRIER \
"\tb 2f\n" \
"1:"FAIL_BARRIER \
"\tli %[retval],0\n" \
"\tstb %[scratch],%[exp]\n" \
"2:\textsb %[exp_reg],%[exp_reg]\n" \
: [exp_reg] "+&r" (*(volatile __typeof__(EXP_PTR))EXP_PTR), \
[exp] "=m" (*EXP_PTR), \
[obj] "+m" (*OBJ_PTR), \
[scratch] "=&r" (((__typeof__(VAL)){ 0 })), \
[retval] "=&r" (RET) \
: [val] "r" (VAL), \
[obj_ptr] "r" (OBJ_PTR) \
: "cr0")
#define PPC_ASM_CMPSWAP__gtm_atomic_ushort__(OBJ_PTR, EXP_PTR, VAL, RET, PRE_BARRIER, SUCCESS_BARRIER, FAIL_BARRER) \
asm volatile ( "\tli %[retval],1\n" \
PRE_BARRIER \
"0:\tlharx %[scratch],0,%[obj_ptr]\n" \
"\tcmp 0,0,%[scratch],%[exp_reg]\n" \
"\tbne- 1f\n" \
"\tsthcx. %[val],0,%[obj_ptr]\n" \
"\tbne- 0b\n" \
SUCCESS_BARRIER \
"\tb 2f\n" \
"1:"FAIL_BARRIER \
"\tli %[retval],0\n" \
"\tsth %[scratch],%[exp]\n" \
"2:\t\n" \
: [exp] "=m" (*EXP_PTR), \
[obj] "+m" (*OBJ_PTR), \
[scratch] "=&r" (((__typeof__(VAL)){ 0 })), \
[retval] "=&r" (RET) \
: [exp_reg] "r" (*(volatile __typeof__(EXP_PTR))EXP_PTR), \
[val] "r" (VAL), \
[obj_ptr] "r" (OBJ_PTR) \
: "cr0")
#define PPC_ASM_CMPSWAP__gtm_atomic_short__(OBJ_PTR, EXP_PTR, VAL, RET, PRE_BARRIER, SUCCESS_BARRIER, FAIL_BARRIER) \
asm volatile ( "\tli %[retval],1\n" \
"\tclrldi %[exp_reg],%[exp_reg],48\n" \
PRE_BARRIER \
"0:\tlharx %[scratch],0,%[obj_ptr]\n" \
"\tcmp 0,0,%[scratch],%[exp_reg]\n" \
"\tbne- 1f\n" \
"\tsthcx. %[val],0,%[obj_ptr]\n" \
"\tbne- 0b\n" \
SUCCESS_BARRIER \
"\tb 2f\n" \
"1:"FAIL_BARRIER \
"\tli %[retval],0\n" \
"\tsth %[scratch],%[exp]\n" \
"2:\textsh %[exp_reg],%[exp_reg]\n" \
: [exp_reg] "+&r" (*(volatile __typeof__(EXP_PTR))EXP_PTR), \
[exp] "=m" (*EXP_PTR), \
[obj] "+m" (*OBJ_PTR), \
[scratch] "=&r" (((__typeof__(VAL)){ 0 })), \
[retval] "=&r" (RET) \
: [val] "r" (VAL), \
[obj_ptr] "r" (OBJ_PTR) \
: "cr0")
#endif
#define PPC_ASM_CMPSWAP__gtm_atomic_int__(OBJ_PTR, EXP_PTR, VAL, RET, PRE_BARRIER, SUCCESS_BARRIER, FAIL_BARRIER) \
asm volatile ( "\tli %[retval],1\n" \
PRE_BARRIER \
"0:\tlwarx %[scratch],0,%[obj_ptr]\n" \
"\tcmp 0,0,%[scratch],%[exp_reg]\n" \
"\tbne- 1f\n" \
"\tstwcx. %[val],0,%[obj_ptr]\n" \
"\tbne- 0b\n" \
SUCCESS_BARRIER \
"\tb 2f\n" \
"1:"FAIL_BARRIER \
"\tli %[retval],0\n" \
"\tstw %[scratch],%[exp]\n" \
"2:\t\n" \
: [exp] "=m" (*EXP_PTR), \
[obj] "+m" (*OBJ_PTR), \
[scratch] "=&r" (((__typeof__(VAL)){ 0 })), \
[retval] "=&r" (RET) \
: [exp_reg] "r" (*(volatile __typeof__(EXP_PTR))EXP_PTR), \
[val] "r" (VAL), \
[obj_ptr] "r" (OBJ_PTR) \
: "cr0")
#define PPC_ASM_CMPSWAP__gtm_atomic_long__(OBJ_PTR, EXP_PTR, VAL, RET, PRE_BARRIER, SUCCESS_BARRIER, FAIL_BARRIER) \
asm volatile ( "\tli %[retval],1\n" \
PRE_BARRIER \
"0:\tldarx %[scratch],0,%[obj_ptr]\n" \
"\tcmp 0,1,%[scratch],%[exp_reg]\n" \
"\tbne- 1f\n" \
"\tstdcx. %[val],0,%[obj_ptr]\n" \
"\tbne- 0b\n" \
SUCCESS_BARRIER \
"\tb 2f\n" \
"1:"FAIL_BARRIER \
"\tli %[retval],0\n" \
"\tstd %[scratch],%[exp]\n" \
"2:\t\n" \
: [exp] "=m" (*EXP_PTR), \
[obj] "+m" (*OBJ_PTR), \
[scratch] "=&r" (((__typeof__(VAL)){ 0 })), \
[retval] "=&r" (RET) \
: [exp_reg] "r" (*(volatile __typeof__(EXP_PTR))EXP_PTR), \
[val] "r" (VAL), \
[obj_ptr] "r" (OBJ_PTR) \
: "cr0")
#ifdef _ARCH_PWR8
#define PPC_ASM_CMPSWAP__gtm_atomic_bool__ PPC_ASM_CMPSWAP__gtm_atomic_uchar__
#ifdef __CHAR_SIGNED__
#define PPC_ASM_CMPSWAP__gtm_atomic_char__ PPC_ASM_CMPSWAP__gtm_atomic_schar__
#else
#define PPC_ASM_CMPSWAP__gtm_atomic_char__ PPC_ASM_CMPSWAP__gtm_atomic_uchar__
#endif
#endif
#define PPC_ASM_CMPSWAP__gtm_atomic_uint__ PPC_ASM_CMPSWAP__gtm_atomic_int__
#define PPC_ASM_CMPSWAP__gtm_atomic_ulong__ PPC_ASM_CMPSWAP__gtm_atomic_long__
#define PPC_ASM_CMPSWAP__gtm_atomic_llong__ PPC_ASM_CMPSWAP__gtm_atomic_long__
#define PPC_ASM_CMPSWAP__gtm_atomic_ullong__ PPC_ASM_CMPSWAP__gtm_atomic_long__
/* Powerpc assembly strings for the various FETCH_* combinations. */
#define PPC_ASMSTR_ADD "\tadd %[scratch],%[val],%[retval]\n"
#define PPC_ASMSTR_SUB "\tsubf %[scratch],%[val],%[retval]\n"
#define PPC_ASMSTR_AND "\tand %[scratch],%[val],%[retval]\n"
#define PPC_ASMSTR_OR "\tor %[scratch],%[val],%[retval]\n"
#define PPC_ASMSTR_XOR "\txor %[scratch],%[val],%[retval]\n"
/* Utility macros to define the inline functions which map to the ATOMIC_* macros, necessary because some of them return a value. */
#define DEFINE_ATOMIC_LOAD(OBJ_TYPE, ORD, PRE_BARRIER, POST_BARRIER) \
static inline OBJ_TYPE atomic_load__##OBJ_TYPE##__##ORD(const volatile OBJ_TYPE *p) \
{ \
OBJ_TYPE ret; \
PPC_ASM_LD##__##OBJ_TYPE##__(p, ret, PRE_BARRIER, POST_BARRIER); \
return ret; \
}
#define DEFINE_CMP_ATOMIC_LOAD(OBJ_TYPE, ORD, PRE_BARRIER, POST_BARRIER) \
static inline OBJ_TYPE atomic_load__##OBJ_TYPE##__##ORD(const volatile OBJ_TYPE *p) \
{ \
OBJ_TYPE ret; \
PPC_ASM_LDCMP##__##OBJ_TYPE##__(p, ret, PRE_BARRIER, POST_BARRIER); \
return ret; \
}
#define DEFINE_ATOMIC_STORE(OBJ_TYPE, ORD, PRE_BARRIER, POST_BARRIER) \
static inline void atomic_store__##OBJ_TYPE##__##ORD(volatile OBJ_TYPE *p, OBJ_TYPE v) \
{ \
PPC_ASM_ST##__##OBJ_TYPE##__(p, v, PRE_BARRIER, POST_BARRIER); \
return; \
}
#define DEFINE_ATOMIC_LL_SC_OP(OBJ_TYPE, ORD, OPNAME, ASM, PRE_BARRIER, POST_BARRIER) \
static inline OBJ_TYPE OPNAME##OBJ_TYPE##__##ORD(volatile OBJ_TYPE *p, OBJ_TYPE v) \
{ \
OBJ_TYPE ret; \
PPC_ASM_LLSC##__##OBJ_TYPE##__(p, v, ret, ASM, PRE_BARRIER, POST_BARRIER); \
return ret; \
}
#define DEFINE_ATOMIC_XCHG(OBJ_TYPE, ORD, PRE_BARRIER, POST_BARRIER) \
static inline OBJ_TYPE atomic_exchange__##OBJ_TYPE##__##ORD(volatile OBJ_TYPE *p, OBJ_TYPE v) \
{ \
OBJ_TYPE ret; \
PPC_ASM_XCHG##__##OBJ_TYPE##__(p, v, ret, PRE_BARRIER, POST_BARRIER); \
return ret; \
}
#define DEFINE_ATOMIC_COMPARE_EXCHANGE(OBJ_TYPE, SUCCESS_ORD, FAIL_ORD, PRE_BARRIER, SUCCESS_BARRIER, FAIL_BARRIER) \
static inline bool atomic_compare_exchange__##OBJ_TYPE##__##SUCCESS_ORD##__##FAIL_ORD(volatile OBJ_TYPE *p, OBJ_TYPE *e, \
OBJ_TYPE d) \
{ \
bool ret; \
PPC_ASM_CMPSWAP##__##OBJ_TYPE##__(p, e, d, ret, PRE_BARRIER, SUCCESS_BARRIER, FAIL_BARRIER); \
return ret; \
}
#define DEFINE_ATOMIC_FETCH_ADD(OBJ_TYPE, ORD, PRE_BARRIER, POST_BARRIER) DEFINE_ATOMIC_LL_SC_OP(OBJ_TYPE, ORD, \
atomic_fetch_add__, PPC_ASMSTR_ADD, PRE_BARRIER, POST_BARRIER)
#define DEFINE_ATOMIC_FETCH_SUB(OBJ_TYPE, ORD, PRE_BARRIER, POST_BARRIER) DEFINE_ATOMIC_LL_SC_OP(OBJ_TYPE, ORD, \
atomic_fetch_sub__, PPC_ASMSTR_SUB, PRE_BARRIER, POST_BARRIER)
#define DEFINE_ATOMIC_FETCH_OR(OBJ_TYPE, ORD, PRE_BARRIER, POST_BARRIER) DEFINE_ATOMIC_LL_SC_OP(OBJ_TYPE, ORD, \
atomic_fetch_or__, PPC_ASMSTR_OR, PRE_BARRIER, POST_BARRIER)
#define DEFINE_ATOMIC_FETCH_XOR(OBJ_TYPE, ORD, PRE_BARRIER, POST_BARRIER) DEFINE_ATOMIC_LL_SC_OP(OBJ_TYPE, ORD, \
atomic_fetch_xor__, PPC_ASMSTR_XOR, PRE_BARRIER, POST_BARRIER)
#define DEFINE_ATOMIC_FETCH_AND(OBJ_TYPE, ORD, PRE_BARRIER, POST_BARRIER) DEFINE_ATOMIC_LL_SC_OP(OBJ_TYPE, ORD, \
atomic_fetch_and__, PPC_ASMSTR_AND, PRE_BARRIER, POST_BARRIER)
#define DEFINE_ALL_LL_SC_OPS(OBJ_TYPE, ORD, PRE_BARRIER, POST_BARRIER) \
DEFINE_ATOMIC_FETCH_ADD(OBJ_TYPE, ORD, PRE_BARRIER, POST_BARRIER) \
DEFINE_ATOMIC_FETCH_SUB(OBJ_TYPE, ORD, PRE_BARRIER, POST_BARRIER) \
DEFINE_ATOMIC_FETCH_OR(OBJ_TYPE, ORD, PRE_BARRIER, POST_BARRIER) \
DEFINE_ATOMIC_FETCH_XOR(OBJ_TYPE, ORD, PRE_BARRIER, POST_BARRIER) \
DEFINE_ATOMIC_FETCH_AND(OBJ_TYPE, ORD, PRE_BARRIER, POST_BARRIER) \
DEFINE_ATOMIC_XCHG(OBJ_TYPE, ORD, PRE_BARRIER, POST_BARRIER)
/* What follows is the definitions themselves. The PRE_BARRIER and POST_BARRIER are generally powerpc memory ordering primitives
* used to create the various ordering constraints.
*/
#define DEFINE_memory_order_relaxed_ATOMIC_STORE(TYPE) \
DEFINE_ATOMIC_STORE(TYPE, memory_order_relaxed, "\tnop\n", "\tnop\n")
#define DEFINE_memory_order_release_ATOMIC_STORE(TYPE) \
DEFINE_ATOMIC_STORE(TYPE, memory_order_release, "\tlwsync\n", "\tnop\n")
#define DEFINE_memory_order_seq_cst_ATOMIC_STORE(TYPE) \
DEFINE_ATOMIC_STORE(TYPE, memory_order_seq_cst, "\tsync\n", "\tnop\n")
#define DEFINE_memory_order_relaxed_ATOMIC_LOAD(TYPE) \
DEFINE_ATOMIC_LOAD(TYPE, memory_order_relaxed, "\tnop\n", "\tnop\n")
#define DEFINE_memory_order_acquire_ATOMIC_LOAD(TYPE) \
DEFINE_CMP_ATOMIC_LOAD(TYPE, memory_order_acquire, "\tnop\n", "\tisync\n")
#define DEFINE_memory_order_seq_cst_ATOMIC_LOAD(TYPE) \
DEFINE_CMP_ATOMIC_LOAD(TYPE, memory_order_seq_cst, "\tsync\n", "\tisync\n")
#define DEFINE_memory_order_relaxed_ATOMIC_XCHG(TYPE) \
DEFINE_ATOMIC_XCHG(TYPE, memory_order_relaxed, "\tnop\n", "\tnop\n")
#define DEFINE_memory_order_acquire_ATOMIC_XCHG(TYPE) \
DEFINE_ATOMIC_XCHG(TYPE, memory_order_acquire, "\tnop\n", "\tisync\n")
#define DEFINE_memory_order_release_ATOMIC_XCHG(TYPE) \
DEFINE_ATOMIC_XCHG(TYPE, memory_order_release, "\tlwsync\n", "\tnop\n")
#define DEFINE_memory_order_acq_rel_ATOMIC_XCHG(TYPE) \
DEFINE_ATOMIC_XCHG(TYPE, memory_order_acq_rel, "\tlwsync\n", "\tisync\n")
#define DEFINE_memory_order_seq_cst_ATOMIC_XCHG(TYPE) \
DEFINE_ATOMIC_XCHG(TYPE, memory_order_seq_cst, "\tsync\n", "\tisync\n")
#define DEFINE_memory_order_relaxed_ATOMIC_FETCH_ADD(TYPE) \
DEFINE_ATOMIC_FETCH_ADD(TYPE, memory_order_relaxed, "\tnop\n", "\tnop\n")
#define DEFINE_memory_order_acquire_ATOMIC_FETCH_ADD(TYPE) \
DEFINE_ATOMIC_FETCH_ADD(TYPE, memory_order_acquire, "\tnop\n", "\tisync\n")
#define DEFINE_memory_order_release_ATOMIC_FETCH_ADD(TYPE) \
DEFINE_ATOMIC_FETCH_ADD(TYPE, memory_order_release, "\tlwsync\n", "\tnop\n")
#define DEFINE_memory_order_acq_rel_ATOMIC_FETCH_ADD(TYPE) \
DEFINE_ATOMIC_FETCH_ADD(TYPE, memory_order_acq_rel, "\tlwsync\n", "\tisync\n")
#define DEFINE_memory_order_seq_cst_ATOMIC_FETCH_ADD(TYPE) \
DEFINE_ATOMIC_FETCH_ADD(TYPE, memory_order_seq_cst, "\tsync\n", "\tisync\n")
#define DEFINE_memory_order_relaxed_ATOMIC_FETCH_SUB(TYPE) \
DEFINE_ATOMIC_FETCH_SUB(TYPE, memory_order_relaxed, "\tnop\n", "\tnop\n")
#define DEFINE_memory_order_acquire_ATOMIC_FETCH_SUB(TYPE) \
DEFINE_ATOMIC_FETCH_SUB(TYPE, memory_order_acquire, "\tnop\n", "\tisync\n")
#define DEFINE_memory_order_release_ATOMIC_FETCH_SUB(TYPE) \
DEFINE_ATOMIC_FETCH_SUB(TYPE, memory_order_release, "\tlwsync\n", "\tnop\n")
#define DEFINE_memory_order_acq_rel_ATOMIC_FETCH_SUB(TYPE) \
DEFINE_ATOMIC_FETCH_SUB(TYPE, memory_order_acq_rel, "\tlwsync\n", "\tisync\n")
#define DEFINE_memory_order_seq_cst_ATOMIC_FETCH_SUB(TYPE) \
DEFINE_ATOMIC_FETCH_SUB(TYPE, memory_order_seq_cst, "\tsync\n", "\tisync\n")
#define DEFINE_memory_order_relaxed_ATOMIC_FETCH_OR(TYPE) \
DEFINE_ATOMIC_FETCH_OR(TYPE, memory_order_relaxed, "\tnop\n", "\tnop\n")
#define DEFINE_memory_order_acquire_ATOMIC_FETCH_OR(TYPE) \
DEFINE_ATOMIC_FETCH_OR(TYPE, memory_order_acquire, "\tnop\n", "\tisync\n")
#define DEFINE_memory_order_release_ATOMIC_FETCH_OR(TYPE) \
DEFINE_ATOMIC_FETCH_OR(TYPE, memory_order_release, "\tlwsync\n", "\tnop\n")
#define DEFINE_memory_order_acq_rel_ATOMIC_FETCH_OR(TYPE) \
DEFINE_ATOMIC_FETCH_OR(TYPE, memory_order_acq_rel, "\tlwsync\n", "\tisync\n")
#define DEFINE_memory_order_seq_cst_ATOMIC_FETCH_OR(TYPE) \
DEFINE_ATOMIC_FETCH_OR(TYPE, memory_order_seq_cst, "\tsync\n", "\tisync\n")
#define DEFINE_memory_order_relaxed_ATOMIC_FETCH_XOR(TYPE) \
DEFINE_ATOMIC_FETCH_XOR(TYPE, memory_order_relaxed, "\tnop\n", "\tnop\n")
#define DEFINE_memory_order_acquire_ATOMIC_FETCH_XOR(TYPE) \
DEFINE_ATOMIC_FETCH_XOR(TYPE, memory_order_acquire, "\tnop\n", "\tisync\n")
#define DEFINE_memory_order_release_ATOMIC_FETCH_XOR(TYPE) \
DEFINE_ATOMIC_FETCH_XOR(TYPE, memory_order_release, "\tlwsync\n", "\tnop\n")
#define DEFINE_memory_order_acq_rel_ATOMIC_FETCH_XOR(TYPE) \
DEFINE_ATOMIC_FETCH_XOR(TYPE, memory_order_acq_rel, "\tlwsync\n", "\tisync\n")
#define DEFINE_memory_order_seq_cst_ATOMIC_FETCH_XOR(TYPE) \
DEFINE_ATOMIC_FETCH_XOR(TYPE, memory_order_seq_cst, "\tsync\n", "\tisync\n")
#define DEFINE_memory_order_relaxed_ATOMIC_FETCH_AND(TYPE) \
DEFINE_ATOMIC_FETCH_AND(TYPE, memory_order_relaxed, "\tnop\n", "\tnop\n")
#define DEFINE_memory_order_acquire_ATOMIC_FETCH_AND(TYPE) \
DEFINE_ATOMIC_FETCH_AND(TYPE, memory_order_acquire, "\tnop\n", "\tisync\n")
#define DEFINE_memory_order_release_ATOMIC_FETCH_AND(TYPE) \
DEFINE_ATOMIC_FETCH_AND(TYPE, memory_order_release, "\tlwsync\n", "\tnop\n")
#define DEFINE_memory_order_acq_rel_ATOMIC_FETCH_AND(TYPE) \
DEFINE_ATOMIC_FETCH_AND(TYPE, memory_order_acq_rel, "\tlwsync\n", "\tisync\n")
#define DEFINE_memory_order_seq_cst_ATOMIC_FETCH_AND(TYPE) \
DEFINE_ATOMIC_FETCH_AND(TYPE, memory_order_seq_cst, "\tsync\n", "\tisync\n")
#define DEFINE_memory_order_relaxed_memory_order_relaxed_ATOMIC_COMPARE_EXCHANGE(TYPE) \
DEFINE_ATOMIC_COMPARE_EXCHANGE(TYPE, memory_order_relaxed, memory_order_relaxed, "\tnop\n", "\tnop\n", "\tnop\n")
#define DEFINE_memory_order_relaxed_memory_order_acquire_ATOMIC_COMPARE_EXCHANGE(TYPE) \
DEFINE_ATOMIC_COMPARE_EXCHANGE(TYPE, memory_order_relaxed, memory_order_acquire, "\tnop\n", "\tnop\n", "\tisync\n")
#define DEFINE_memory_order_acquire_memory_order_relaxed_ATOMIC_COMPARE_EXCHANGE(TYPE) \
DEFINE_ATOMIC_COMPARE_EXCHANGE(TYPE, memory_order_acquire, memory_order_relaxed, "\tnop\n", "\tisync\n", "\tnop\n")
#define DEFINE_memory_order_acquire_memory_order_acquire_ATOMIC_COMPARE_EXCHANGE(TYPE) \
DEFINE_ATOMIC_COMPARE_EXCHANGE(TYPE, memory_order_acquire, memory_order_acquire, "\tnop\n", "\tisync\n", "\tnop\n")
#define DEFINE_memory_order_release_memory_order_relaxed_ATOMIC_COMPARE_EXCHANGE(TYPE) \
DEFINE_ATOMIC_COMPARE_EXCHANGE(TYPE, memory_order_release, memory_order_relaxed, "\tlwsync\n", "\tnop\n", "\tnop\n")
#define DEFINE_memory_order_release_memory_order_acquire_ATOMIC_COMPARE_EXCHANGE(TYPE) \
DEFINE_ATOMIC_COMPARE_EXCHANGE(TYPE, memory_order_release, memory_order_acquire, "\tlwsync\n", "\tnop\n", "\tisync\n")
#define DEFINE_memory_order_acq_rel_memory_order_relaxed_ATOMIC_COMPARE_EXCHANGE(TYPE) \
DEFINE_ATOMIC_COMPARE_EXCHANGE(TYPE, memory_order_acq_rel, memory_order_relaxed, "\tlwsync\n", "\tisync\n", "\tnop\n")
#define DEFINE_memory_order_acq_rel_memory_order_acquire_ATOMIC_COMPARE_EXCHANGE(TYPE) \
DEFINE_ATOMIC_COMPARE_EXCHANGE(TYPE, memory_order_acq_rel, memory_order_acquire, "\tlwsync\n", "\tisync\n", "\tisync\n")
#define DEFINE_memory_order_seq_cst_memory_order_relaxed_ATOMIC_COMPARE_EXCHANGE(TYPE) \
DEFINE_ATOMIC_COMPARE_EXCHANGE(TYPE, memory_order_seq_cst, memory_order_relaxed, "\tsync\n", "\tisync\n", "\tnop\n")
#define DEFINE_memory_order_seq_cst_memory_order_acquire_ATOMIC_COMPARE_EXCHANGE(TYPE) \
DEFINE_ATOMIC_COMPARE_EXCHANGE(TYPE, memory_order_seq_cst, memory_order_acquire, "\tsync\n", "\tisync\n", "\tisync\n")
#define DEFINE_memory_order_seq_cst_memory_order_seq_cst_ATOMIC_COMPARE_EXCHANGE(TYPE) \
DEFINE_ATOMIC_COMPARE_EXCHANGE(TYPE, memory_order_seq_cst, memory_order_seq_cst, "\tsync\n", "\tisync\n", "\tisync\n")
#define DEFINE_REGULAR_ATOMIC_OP(TYPE, OPERATION, MEM_ORDER) DEFINE_##MEM_ORDER##_##OPERATION(TYPE)
#define DEFINE_CE_ATOMIC_OP(TYPE, OPERATION, MEM_ORDER_1, MEM_ORDER_2) \
DEFINE_##MEM_ORDER_1##_##MEM_ORDER_2##_##ATOMIC_COMPARE_EXCHANGE(TYPE)
#define GET_OPDEF_TYPE(_1, _2, _3, _4, OPNAME, ...) DEFINE_##OPNAME##_ATOMIC_OP
#define DEFINE_ATOMIC_OP(...) GET_OPDEF_TYPE(__VA_ARGS__, CE, REGULAR)(__VA_ARGS__)
#define DEFINE_ALL_ATOMIC_OPS(TYPE) \
DEFINE_memory_order_relaxed_ATOMIC_STORE(TYPE) \
DEFINE_memory_order_release_ATOMIC_STORE(TYPE) \
DEFINE_memory_order_seq_cst_ATOMIC_STORE(TYPE) \
DEFINE_memory_order_relaxed_ATOMIC_LOAD(TYPE) \
DEFINE_memory_order_acquire_ATOMIC_LOAD(TYPE) \
DEFINE_memory_order_seq_cst_ATOMIC_LOAD(TYPE) \
DEFINE_memory_order_relaxed_ATOMIC_XCHG(TYPE) \
DEFINE_memory_order_acquire_ATOMIC_XCHG(TYPE) \
DEFINE_memory_order_release_ATOMIC_XCHG(TYPE) \
DEFINE_memory_order_acq_rel_ATOMIC_XCHG(TYPE) \
DEFINE_memory_order_seq_cst_ATOMIC_XCHG(TYPE) \
DEFINE_memory_order_relaxed_ATOMIC_FETCH_ADD(TYPE) \
DEFINE_memory_order_acquire_ATOMIC_FETCH_ADD(TYPE) \
DEFINE_memory_order_release_ATOMIC_FETCH_ADD(TYPE) \
DEFINE_memory_order_acq_rel_ATOMIC_FETCH_ADD(TYPE) \
DEFINE_memory_order_seq_cst_ATOMIC_FETCH_ADD(TYPE) \
DEFINE_memory_order_relaxed_ATOMIC_FETCH_SUB(TYPE) \
DEFINE_memory_order_acquire_ATOMIC_FETCH_SUB(TYPE) \
DEFINE_memory_order_release_ATOMIC_FETCH_SUB(TYPE) \
DEFINE_memory_order_acq_rel_ATOMIC_FETCH_SUB(TYPE) \
DEFINE_memory_order_seq_cst_ATOMIC_FETCH_SUB(TYPE) \
DEFINE_memory_order_relaxed_ATOMIC_FETCH_OR(TYPE) \
DEFINE_memory_order_acquire_ATOMIC_FETCH_OR(TYPE) \
DEFINE_memory_order_release_ATOMIC_FETCH_OR(TYPE) \
DEFINE_memory_order_acq_rel_ATOMIC_FETCH_OR(TYPE) \
DEFINE_memory_order_seq_cst_ATOMIC_FETCH_OR(TYPE) \
DEFINE_memory_order_relaxed_ATOMIC_FETCH_XOR(TYPE) \
DEFINE_memory_order_acquire_ATOMIC_FETCH_XOR(TYPE) \
DEFINE_memory_order_release_ATOMIC_FETCH_XOR(TYPE) \
DEFINE_memory_order_acq_rel_ATOMIC_FETCH_XOR(TYPE) \
DEFINE_memory_order_seq_cst_ATOMIC_FETCH_XOR(TYPE) \
DEFINE_memory_order_relaxed_ATOMIC_FETCH_AND(TYPE) \
DEFINE_memory_order_acquire_ATOMIC_FETCH_AND(TYPE) \
DEFINE_memory_order_release_ATOMIC_FETCH_AND(TYPE) \
DEFINE_memory_order_acq_rel_ATOMIC_FETCH_AND(TYPE) \
DEFINE_memory_order_seq_cst_ATOMIC_FETCH_AND(TYPE) \
DEFINE_memory_order_relaxed_memory_order_relaxed_ATOMIC_COMPARE_EXCHANGE(TYPE) \
DEFINE_memory_order_relaxed_memory_order_acquire_ATOMIC_COMPARE_EXCHANGE(TYPE) \
DEFINE_memory_order_acquire_memory_order_relaxed_ATOMIC_COMPARE_EXCHANGE(TYPE) \
DEFINE_memory_order_acquire_memory_order_acquire_ATOMIC_COMPARE_EXCHANGE(TYPE) \
DEFINE_memory_order_release_memory_order_relaxed_ATOMIC_COMPARE_EXCHANGE(TYPE) \
DEFINE_memory_order_release_memory_order_acquire_ATOMIC_COMPARE_EXCHANGE(TYPE) \
DEFINE_memory_order_acq_rel_memory_order_relaxed_ATOMIC_COMPARE_EXCHANGE(TYPE) \
DEFINE_memory_order_acq_rel_memory_order_acquire_ATOMIC_COMPARE_EXCHANGE(TYPE) \
DEFINE_memory_order_seq_cst_memory_order_relaxed_ATOMIC_COMPARE_EXCHANGE(TYPE) \
DEFINE_memory_order_seq_cst_memory_order_acquire_ATOMIC_COMPARE_EXCHANGE(TYPE) \
DEFINE_memory_order_seq_cst_memory_order_seq_cst_ATOMIC_COMPARE_EXCHANGE(TYPE)
/* Mapping of ATOMIC_* macros to inline functions defined above. */
#define COMPILER_FENCE(ORD) __fence()
#define ATOMIC_LOAD(OBJ_PTR, ORD) OP_TYPE_ORD_MNEMONIC(atomic_load, OBJ_PTR, ORD)(OBJ_PTR)
#define ATOMIC_STORE(OBJ_PTR, VAL, ORD) OP_TYPE_ORD_MNEMONIC(atomic_store, OBJ_PTR, ORD)(OBJ_PTR, VAL)
#define ATOMIC_FETCH_ADD(OBJ_PTR, VAL, ORD) FOP_TYPE_ORD_MNEMONIC(atomic_fetch_add, OBJ_PTR, ORD)(OBJ_PTR, VAL)
#define ATOMIC_FETCH_SUB(OBJ_PTR, VAL, ORD) FOP_TYPE_ORD_MNEMONIC(atomic_fetch_sub, OBJ_PTR, ORD)(OBJ_PTR, VAL)
#define ATOMIC_FETCH_OR(OBJ_PTR, VAL, ORD) FOP_TYPE_ORD_MNEMONIC(atomic_fetch_or, OBJ_PTR, ORD)(OBJ_PTR, VAL)
#define ATOMIC_FETCH_XOR(OBJ_PTR, VAL, ORD) FOP_TYPE_ORD_MNEMONIC(atomic_fetch_xor, OBJ_PTR, ORD)(OBJ_PTR, VAL)
#define ATOMIC_FETCH_AND(OBJ_PTR, VAL, ORD) FOP_TYPE_ORD_MNEMONIC(atomic_fetch_and, OBJ_PTR, ORD)(OBJ_PTR, VAL)
#define ATOMIC_EXCHANGE(OBJ_PTR, VAL, ORD) FOP_TYPE_ORD_MNEMONIC(atomic_exchange, OBJ_PTR, ORD)(OBJ_PTR, VAL)
#define ATOMIC_COMPARE_EXCHANGE(OBJ_PTR, EXP_PTR, VAL, SUCCESS_ORD, FAIL_ORD) \
FOP_TYPE_ORD_MNEMONIC(atomic_compare_exchange, OBJ_PTR, SUCCESS_ORD##__##FAIL_ORD)(OBJ_PTR, EXP_PTR, VAL)
#define ATOMIC_COMPARE_EXCHANGE_STRONG(OBJ_PTR, EXP_PTR, VAL, SUCCESS_ORD, FAIL_ORD) \
ATOMIC_COMPARE_EXCHANGE(OBJ_PTR, EXP_PTR, VAL, SUCCESS_ORD, FAIL_ORD)
#define ATOMIC_COMPARE_EXCHANGE_WEAK(OBJ_PTR, EXP_PTR, VAL, SUCCESS_ORD, FAIL_ORD) \
ATOMIC_COMPARE_EXCHANGE_STRONG(OBJ_PTR, EXP_PTR, VAL, SUCCESS_ORD, FAIL_ORD)
#else /* If not AIX, but also no GCC or C11 atomics */
#error "Unsupported platform"
#endif /* If linux elif aix else unsupported */
#endif /* if C11 atomics */
#endif /* ifndef GTM_ATOMIC_H_INCLUDED */
|