| 1 | /* |
| 2 | * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED |
| 3 | * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. |
| 4 | * |
| 5 | * Permission is hereby granted to use or copy this program |
| 6 | * for any purpose, provided the above notices are retained on all copies. |
| 7 | * Permission to modify the code and to distribute modified code is granted, |
| 8 | * provided the above notices are retained, and a notice that the code was |
| 9 | * modified is included with the above copyright notice. |
| 10 | */ |
| 11 | |
| 12 | #if AO_CLANG_PREREQ(3, 9) && !defined(AO_DISABLE_GCC_ATOMICS) |
| 13 | /* Probably, it could be enabled for earlier clang versions as well. */ |
| 14 | |
| 15 | /* As of clang-3.9, __GCC_HAVE_SYNC_COMPARE_AND_SWAP_n are missing. */ |
| 16 | # define AO_GCC_FORCE_HAVE_CAS |
| 17 | |
| 18 | # define AO_GCC_HAVE_double_SYNC_CAS |
| 19 | # include "../standard_ao_double_t.h" |
| 20 | |
| 21 | # include "generic.h" |
| 22 | |
| 23 | #else /* AO_DISABLE_GCC_ATOMICS */ |
| 24 | |
| 25 | #include "../all_aligned_atomic_load_store.h" |
| 26 | |
| 27 | #include "../test_and_set_t_is_ao_t.h" |
| 28 | |
| 29 | /* There's also "isync" and "barrier"; however, for all current CPU */ |
| 30 | /* versions, "syncht" should suffice. Likewise, it seems that the */ |
| 31 | /* auto-defined versions of *_acquire, *_release or *_full suffice for */ |
| 32 | /* all current ISA implementations. */ |
| 33 | AO_INLINE void |
| 34 | AO_nop_full(void) |
| 35 | { |
| 36 | __asm__ __volatile__("syncht" : : : "memory"); |
| 37 | } |
| 38 | #define AO_HAVE_nop_full |
| 39 | |
| 40 | /* The Hexagon has load-locked, store-conditional primitives, and so */ |
| 41 | /* resulting code is very nearly identical to that of PowerPC. */ |
| 42 | |
| 43 | #ifndef AO_PREFER_GENERALIZED |
| 44 | AO_INLINE AO_t |
| 45 | AO_fetch_and_add(volatile AO_t *addr, AO_t incr) |
| 46 | { |
| 47 | AO_t oldval; |
| 48 | AO_t newval; |
| 49 | __asm__ __volatile__( |
| 50 | "1:\n" |
| 51 | " %0 = memw_locked(%3);\n" /* load and reserve */ |
| 52 | " %1 = add (%0,%4);\n" /* increment */ |
| 53 | " memw_locked(%3,p1) = %1;\n" /* store conditional */ |
| 54 | " if (!p1) jump 1b;\n" /* retry if lost reservation */ |
| 55 | : "=&r"(oldval), "=&r"(newval), "+m"(*addr) |
| 56 | : "r"(addr), "r"(incr) |
| 57 | : "memory", "p1"); |
| 58 | return oldval; |
| 59 | } |
| 60 | #define AO_HAVE_fetch_and_add |
| 61 | |
| 62 | AO_INLINE AO_TS_VAL_t |
| 63 | AO_test_and_set(volatile AO_TS_t *addr) |
| 64 | { |
| 65 | int oldval; |
| 66 | int locked_value = 1; |
| 67 | |
| 68 | __asm__ __volatile__( |
| 69 | "1:\n" |
| 70 | " %0 = memw_locked(%2);\n" /* load and reserve */ |
| 71 | " {\n" |
| 72 | " p2 = cmp.eq(%0,#0);\n" /* if load is not zero, */ |
| 73 | " if (!p2.new) jump:nt 2f;\n" /* we are done */ |
| 74 | " }\n" |
| 75 | " memw_locked(%2,p1) = %3;\n" /* else store conditional */ |
| 76 | " if (!p1) jump 1b;\n" /* retry if lost reservation */ |
| 77 | "2:\n" /* oldval is zero if we set */ |
| 78 | : "=&r"(oldval), "+m"(*addr) |
| 79 | : "r"(addr), "r"(locked_value) |
| 80 | : "memory", "p1", "p2"); |
| 81 | return (AO_TS_VAL_t)oldval; |
| 82 | } |
| 83 | #define AO_HAVE_test_and_set |
| 84 | #endif /* !AO_PREFER_GENERALIZED */ |
| 85 | |
| 86 | #ifndef AO_GENERALIZE_ASM_BOOL_CAS |
| 87 | AO_INLINE int |
| 88 | AO_compare_and_swap(volatile AO_t *addr, AO_t old, AO_t new_val) |
| 89 | { |
| 90 | AO_t __oldval; |
| 91 | int result = 0; |
| 92 | __asm__ __volatile__( |
| 93 | "1:\n" |
| 94 | " %0 = memw_locked(%3);\n" /* load and reserve */ |
| 95 | " {\n" |
| 96 | " p2 = cmp.eq(%0,%4);\n" /* if load is not equal to */ |
| 97 | " if (!p2.new) jump:nt 2f;\n" /* old, fail */ |
| 98 | " }\n" |
| 99 | " memw_locked(%3,p1) = %5;\n" /* else store conditional */ |
| 100 | " if (!p1) jump 1b;\n" /* retry if lost reservation */ |
| 101 | " %1 = #1\n" /* success, result = 1 */ |
| 102 | "2:\n" |
| 103 | : "=&r" (__oldval), "+r" (result), "+m"(*addr) |
| 104 | : "r" (addr), "r" (old), "r" (new_val) |
| 105 | : "p1", "p2", "memory" |
| 106 | ); |
| 107 | return result; |
| 108 | } |
| 109 | # define AO_HAVE_compare_and_swap |
| 110 | #endif /* !AO_GENERALIZE_ASM_BOOL_CAS */ |
| 111 | |
| 112 | AO_INLINE AO_t |
| 113 | AO_fetch_compare_and_swap(volatile AO_t *addr, AO_t old_val, AO_t new_val) |
| 114 | { |
| 115 | AO_t __oldval; |
| 116 | |
| 117 | __asm__ __volatile__( |
| 118 | "1:\n" |
| 119 | " %0 = memw_locked(%2);\n" /* load and reserve */ |
| 120 | " {\n" |
| 121 | " p2 = cmp.eq(%0,%3);\n" /* if load is not equal to */ |
| 122 | " if (!p2.new) jump:nt 2f;\n" /* old_val, fail */ |
| 123 | " }\n" |
| 124 | " memw_locked(%2,p1) = %4;\n" /* else store conditional */ |
| 125 | " if (!p1) jump 1b;\n" /* retry if lost reservation */ |
| 126 | "2:\n" |
| 127 | : "=&r" (__oldval), "+m"(*addr) |
| 128 | : "r" (addr), "r" (old_val), "r" (new_val) |
| 129 | : "p1", "p2", "memory" |
| 130 | ); |
| 131 | return __oldval; |
| 132 | } |
| 133 | #define AO_HAVE_fetch_compare_and_swap |
| 134 | |
| 135 | #define AO_T_IS_INT |
| 136 | |
| 137 | #endif /* AO_DISABLE_GCC_ATOMICS */ |
| 138 | |
| 139 | #undef AO_GCC_FORCE_HAVE_CAS |
| 140 | #undef AO_GCC_HAVE_double_SYNC_CAS |
| 141 | |