|
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