|
35 | 35 |
|
36 | 36 | #if defined(__clang_major__) |
37 | 37 | #define FULL_COMPILER_ATOMIC_SUPPORT |
38 | | -#elif (__GNUC__ > 13) || ((__GNUC__ == 13) && (__GNUC_MINOR__ >= 2)) |
| 38 | +#elif (__GNUC__ > 13) || ((__GNUC__ == 13) && (__GNUC_MINOR__ > 2)) |
39 | 39 | #define FULL_COMPILER_ATOMIC_SUPPORT |
40 | 40 | #endif |
41 | 41 |
|
@@ -114,6 +114,44 @@ inline T Atomic::PlatformCmpxchg<1>::operator()(T volatile* dest __attribute__(( |
114 | 114 | } |
115 | 115 | #endif |
116 | 116 |
|
| 117 | +#ifndef FULL_COMPILER_ATOMIC_SUPPORT |
| 118 | +// The implementation of `__atomic_compare_exchange` lacks sign extensions |
| 119 | +// in GCC 13.2 and lower when using with 32-bit unsigned integers on RV64, |
| 120 | +// so we should implement it manually. |
| 121 | +// GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114130. |
| 122 | +// See also JDK-8326936. |
| 123 | +template<> |
| 124 | +template<typename T> |
| 125 | +inline T Atomic::PlatformCmpxchg<4>::operator()(T volatile* dest __attribute__((unused)), |
| 126 | + T compare_value, |
| 127 | + T exchange_value, |
| 128 | + atomic_memory_order order) const { |
| 129 | + STATIC_ASSERT(4 == sizeof(T)); |
| 130 | + |
| 131 | + int32_t old_value; |
| 132 | + uint64_t rc_temp; |
| 133 | + |
| 134 | + if (order != memory_order_relaxed) { |
| 135 | + FULL_MEM_BARRIER; |
| 136 | + } |
| 137 | + |
| 138 | + __asm__ __volatile__ ( |
| 139 | + "1: lr.w %0, %2 \n\t" |
| 140 | + " bne %0, %3, 2f \n\t" |
| 141 | + " sc.w %1, %4, %2 \n\t" |
| 142 | + " bnez %1, 1b \n\t" |
| 143 | + "2: \n\t" |
| 144 | + : /*%0*/"=&r" (old_value), /*%1*/"=&r" (rc_temp), /*%2*/"+A" (*dest) |
| 145 | + : /*%3*/"r" ((int64_t)(int32_t)compare_value), /*%4*/"r" (exchange_value) |
| 146 | + : "memory" ); |
| 147 | + |
| 148 | + if (order != memory_order_relaxed) { |
| 149 | + FULL_MEM_BARRIER; |
| 150 | + } |
| 151 | + return (T)old_value; |
| 152 | +} |
| 153 | +#endif |
| 154 | + |
117 | 155 | template<size_t byte_size> |
118 | 156 | template<typename T> |
119 | 157 | inline T Atomic::PlatformXchg<byte_size>::operator()(T volatile* dest, |
@@ -148,54 +186,21 @@ inline T Atomic::PlatformCmpxchg<byte_size>::operator()(T volatile* dest __attri |
148 | 186 | atomic_memory_order order) const { |
149 | 187 |
|
150 | 188 | #ifndef FULL_COMPILER_ATOMIC_SUPPORT |
151 | | - STATIC_ASSERT(byte_size >= 4); |
| 189 | + STATIC_ASSERT(byte_size > 4); |
152 | 190 | #endif |
153 | 191 |
|
154 | 192 | STATIC_ASSERT(byte_size == sizeof(T)); |
155 | | - T value = compare_value; |
156 | 193 | if (order != memory_order_relaxed) { |
157 | 194 | FULL_MEM_BARRIER; |
158 | 195 | } |
159 | 196 |
|
160 | | - __atomic_compare_exchange(dest, &value, &exchange_value, /* weak */ false, |
| 197 | + __atomic_compare_exchange(dest, &compare_value, &exchange_value, /* weak */ false, |
161 | 198 | __ATOMIC_RELAXED, __ATOMIC_RELAXED); |
162 | 199 |
|
163 | 200 | if (order != memory_order_relaxed) { |
164 | 201 | FULL_MEM_BARRIER; |
165 | 202 | } |
166 | | - return value; |
167 | | -} |
168 | | - |
169 | | -template<> |
170 | | -template<typename T> |
171 | | -inline T Atomic::PlatformCmpxchg<4>::operator()(T volatile* dest __attribute__((unused)), |
172 | | - T compare_value, |
173 | | - T exchange_value, |
174 | | - atomic_memory_order order) const { |
175 | | - STATIC_ASSERT(4 == sizeof(T)); |
176 | | - |
177 | | - T old_value; |
178 | | - long rc; |
179 | | - |
180 | | - if (order != memory_order_relaxed) { |
181 | | - FULL_MEM_BARRIER; |
182 | | - } |
183 | | - |
184 | | - __asm__ __volatile__ ( |
185 | | - "1: sext.w %1, %3 \n\t" // sign-extend compare_value |
186 | | - " lr.w %0, %2 \n\t" |
187 | | - " bne %0, %1, 2f \n\t" |
188 | | - " sc.w %1, %4, %2 \n\t" |
189 | | - " bnez %1, 1b \n\t" |
190 | | - "2: \n\t" |
191 | | - : /*%0*/"=&r" (old_value), /*%1*/"=&r" (rc), /*%2*/"+A" (*dest) |
192 | | - : /*%3*/"r" (compare_value), /*%4*/"r" (exchange_value) |
193 | | - : "memory" ); |
194 | | - |
195 | | - if (order != memory_order_relaxed) { |
196 | | - FULL_MEM_BARRIER; |
197 | | - } |
198 | | - return old_value; |
| 203 | + return compare_value; |
199 | 204 | } |
200 | 205 |
|
201 | 206 | template<size_t byte_size> |
|
0 commit comments