]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /* |
2 | * Distributed under the Boost Software License, Version 1.0. | |
3 | * (See accompanying file LICENSE_1_0.txt or copy at | |
4 | * http://www.boost.org/LICENSE_1_0.txt) | |
5 | * | |
6 | * Copyright (c) 2009 Helge Bahmann | |
7 | * Copyright (c) 2013 Tim Blechmann | |
20effc67 | 8 | * Copyright (c) 2014, 2020 Andrey Semashev |
7c673cae FG |
9 | */ |
10 | /*! | |
20effc67 | 11 | * \file atomic/detail/core_arch_ops_gcc_arm.hpp |
7c673cae | 12 | * |
20effc67 | 13 | * This header contains implementation of the \c core_arch_operations template. |
7c673cae FG |
14 | */ |
15 | ||
20effc67 TL |
16 | #ifndef BOOST_ATOMIC_DETAIL_CORE_ARCH_OPS_GCC_ARM_HPP_INCLUDED_ |
17 | #define BOOST_ATOMIC_DETAIL_CORE_ARCH_OPS_GCC_ARM_HPP_INCLUDED_ | |
7c673cae | 18 | |
b32b8144 | 19 | #include <cstddef> |
7c673cae FG |
20 | #include <boost/cstdint.hpp> |
21 | #include <boost/memory_order.hpp> | |
22 | #include <boost/atomic/detail/config.hpp> | |
f67539c2 TL |
23 | #include <boost/atomic/detail/storage_traits.hpp> |
24 | #include <boost/atomic/detail/integral_conversions.hpp> | |
20effc67 | 25 | #include <boost/atomic/detail/core_arch_operations_fwd.hpp> |
b32b8144 | 26 | #include <boost/atomic/detail/ops_gcc_arm_common.hpp> |
20effc67 TL |
27 | #include <boost/atomic/detail/gcc_arm_asm_common.hpp> |
28 | #include <boost/atomic/detail/capabilities.hpp> | |
29 | #include <boost/atomic/detail/header.hpp> | |
7c673cae FG |
30 | |
31 | #ifdef BOOST_HAS_PRAGMA_ONCE | |
32 | #pragma once | |
33 | #endif | |
34 | ||
35 | namespace boost { | |
36 | namespace atomics { | |
37 | namespace detail { | |
38 | ||
39 | // From the ARM Architecture Reference Manual for architecture v6: | |
40 | // | |
41 | // LDREX{<cond>} <Rd>, [<Rn>] | |
42 | // <Rd> Specifies the destination register for the memory word addressed by <Rd> | |
43 | // <Rn> Specifies the register containing the address. | |
44 | // | |
45 | // STREX{<cond>} <Rd>, <Rm>, [<Rn>] | |
46 | // <Rd> Specifies the destination register for the returned status value. | |
47 | // 0 if the operation updates memory | |
48 | // 1 if the operation fails to update memory | |
49 | // <Rm> Specifies the register containing the word to be stored to memory. | |
50 | // <Rn> Specifies the register containing the address. | |
51 | // Rd must not be the same register as Rm or Rn. | |
52 | // | |
53 | // ARM v7 is like ARM v6 plus: | |
54 | // There are half-word and byte versions of the LDREX and STREX instructions, | |
55 | // LDREXH, LDREXB, STREXH and STREXB. | |
56 | // There are also double-word versions, LDREXD and STREXD. | |
57 | // (Actually it looks like these are available from version 6k onwards.) | |
7c673cae | 58 | |
20effc67 TL |
59 | template< bool Signed, bool Interprocess > |
60 | struct core_arch_operations< 4u, Signed, Interprocess > : | |
61 | public core_arch_operations_gcc_arm_base | |
7c673cae | 62 | { |
f67539c2 | 63 | typedef typename storage_traits< 4u >::type storage_type; |
7c673cae | 64 | |
b32b8144 | 65 | static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 4u; |
f67539c2 | 66 | static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = 4u; |
b32b8144 | 67 | static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; |
20effc67 | 68 | static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; |
b32b8144 | 69 | |
7c673cae FG |
70 | static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT |
71 | { | |
72 | fence_before(order); | |
73 | storage = v; | |
74 | fence_after_store(order); | |
75 | } | |
76 | ||
77 | static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT | |
78 | { | |
79 | storage_type v = storage; | |
80 | fence_after(order); | |
81 | return v; | |
82 | } | |
83 | ||
84 | static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
85 | { | |
7c673cae | 86 | fence_before(order); |
20effc67 | 87 | storage_type original; |
7c673cae FG |
88 | uint32_t tmp; |
89 | __asm__ __volatile__ | |
90 | ( | |
91 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
92 | "1:\n\t" |
93 | "ldrex %[original], %[storage]\n\t" // load the original value | |
94 | "strex %[tmp], %[value], %[storage]\n\t" // store the replacement, tmp = store failed | |
95 | "teq %[tmp], #0\n\t" // check if store succeeded | |
96 | "bne 1b\n\t" | |
7c673cae FG |
97 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
98 | : [tmp] "=&l" (tmp), [original] "=&r" (original), [storage] "+Q" (storage) | |
99 | : [value] "r" (v) | |
100 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC | |
101 | ); | |
102 | fence_after(order); | |
103 | return original; | |
104 | } | |
105 | ||
106 | static BOOST_FORCEINLINE bool compare_exchange_weak( | |
107 | storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT | |
108 | { | |
109 | fence_before(success_order); | |
20effc67 TL |
110 | bool success = false; |
111 | #if !defined(BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_UNUSED) | |
7c673cae | 112 | uint32_t tmp; |
20effc67 | 113 | #endif |
7c673cae FG |
114 | storage_type original; |
115 | __asm__ __volatile__ | |
116 | ( | |
117 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
118 | "ldrex %[original], %[storage]\n\t" // original = *(&storage) |
119 | "cmp %[original], %[expected]\n\t" // flags = original==expected | |
120 | "itt eq\n\t" // [hint that the following 2 instructions are conditional on flags.equal] | |
121 | "strexeq %[success], %[desired], %[storage]\n\t" // if (flags.equal) *(&storage) = desired, success = store failed | |
122 | "eoreq %[success], %[success], #1\n\t" // if (flags.equal) success ^= 1 (i.e. make it 1 if store succeeded) | |
7c673cae | 123 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
20effc67 TL |
124 | : [original] "=&r" (original), |
125 | [success] "+r" (success), | |
126 | #if !defined(BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_UNUSED) | |
127 | [tmp] "=&l" (tmp), | |
128 | #endif | |
129 | [storage] "+Q" (storage) | |
130 | : [expected] "Ir" (expected), | |
131 | [desired] "r" (desired) | |
7c673cae FG |
132 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
133 | ); | |
134 | if (success) | |
135 | fence_after(success_order); | |
136 | else | |
137 | fence_after(failure_order); | |
138 | expected = original; | |
20effc67 | 139 | return success; |
7c673cae FG |
140 | } |
141 | ||
142 | static BOOST_FORCEINLINE bool compare_exchange_strong( | |
143 | storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT | |
144 | { | |
145 | fence_before(success_order); | |
20effc67 TL |
146 | bool success = false; |
147 | #if !defined(BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_UNUSED) | |
7c673cae | 148 | uint32_t tmp; |
20effc67 | 149 | #endif |
7c673cae FG |
150 | storage_type original; |
151 | __asm__ __volatile__ | |
152 | ( | |
153 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
154 | "1:\n\t" |
155 | "ldrex %[original], %[storage]\n\t" // original = *(&storage) | |
156 | "cmp %[original], %[expected]\n\t" // flags = original==expected | |
157 | "bne 2f\n\t" // if (!flags.equal) goto end | |
158 | "strex %[success], %[desired], %[storage]\n\t" // *(&storage) = desired, success = store failed | |
159 | "eors %[success], %[success], #1\n\t" // success ^= 1 (i.e. make it 1 if store succeeded); flags.equal = success == 0 | |
160 | "beq 1b\n\t" // if (flags.equal) goto retry | |
161 | "2:\n\t" | |
7c673cae | 162 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
20effc67 TL |
163 | : [original] "=&r" (original), |
164 | [success] "+r" (success), | |
165 | #if !defined(BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_UNUSED) | |
166 | [tmp] "=&l" (tmp), | |
167 | #endif | |
168 | [storage] "+Q" (storage) | |
169 | : [expected] "Ir" (expected), | |
170 | [desired] "r" (desired) | |
7c673cae FG |
171 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
172 | ); | |
173 | if (success) | |
174 | fence_after(success_order); | |
175 | else | |
176 | fence_after(failure_order); | |
177 | expected = original; | |
20effc67 | 178 | return success; |
7c673cae FG |
179 | } |
180 | ||
181 | static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
182 | { | |
183 | fence_before(order); | |
184 | uint32_t tmp; | |
185 | storage_type original, result; | |
186 | __asm__ __volatile__ | |
187 | ( | |
188 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
189 | "1:\n\t" |
190 | "ldrex %[original], %[storage]\n\t" // original = *(&storage) | |
191 | "add %[result], %[original], %[value]\n\t" // result = original + value | |
192 | "strex %[tmp], %[result], %[storage]\n\t" // *(&storage) = result, tmp = store failed | |
193 | "teq %[tmp], #0\n\t" // flags = tmp==0 | |
194 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
7c673cae FG |
195 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
196 | : [original] "=&r" (original), // %0 | |
197 | [result] "=&r" (result), // %1 | |
198 | [tmp] "=&l" (tmp), // %2 | |
199 | [storage] "+Q" (storage) // %3 | |
b32b8144 | 200 | : [value] "Ir" (v) // %4 |
7c673cae FG |
201 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
202 | ); | |
203 | fence_after(order); | |
204 | return original; | |
205 | } | |
206 | ||
207 | static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
208 | { | |
209 | fence_before(order); | |
210 | uint32_t tmp; | |
211 | storage_type original, result; | |
212 | __asm__ __volatile__ | |
213 | ( | |
214 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
215 | "1:\n\t" |
216 | "ldrex %[original], %[storage]\n\t" // original = *(&storage) | |
217 | "sub %[result], %[original], %[value]\n\t" // result = original - value | |
218 | "strex %[tmp], %[result], %[storage]\n\t" // *(&storage) = result, tmp = store failed | |
219 | "teq %[tmp], #0\n\t" // flags = tmp==0 | |
220 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
7c673cae FG |
221 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
222 | : [original] "=&r" (original), // %0 | |
223 | [result] "=&r" (result), // %1 | |
224 | [tmp] "=&l" (tmp), // %2 | |
225 | [storage] "+Q" (storage) // %3 | |
b32b8144 | 226 | : [value] "Ir" (v) // %4 |
7c673cae FG |
227 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
228 | ); | |
229 | fence_after(order); | |
230 | return original; | |
231 | } | |
232 | ||
233 | static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
234 | { | |
235 | fence_before(order); | |
236 | uint32_t tmp; | |
237 | storage_type original, result; | |
238 | __asm__ __volatile__ | |
239 | ( | |
240 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
241 | "1:\n\t" |
242 | "ldrex %[original], %[storage]\n\t" // original = *(&storage) | |
243 | "and %[result], %[original], %[value]\n\t" // result = original & value | |
244 | "strex %[tmp], %[result], %[storage]\n\t" // *(&storage) = result, tmp = store failed | |
245 | "teq %[tmp], #0\n\t" // flags = tmp==0 | |
246 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
7c673cae FG |
247 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
248 | : [original] "=&r" (original), // %0 | |
249 | [result] "=&r" (result), // %1 | |
250 | [tmp] "=&l" (tmp), // %2 | |
251 | [storage] "+Q" (storage) // %3 | |
b32b8144 | 252 | : [value] "Ir" (v) // %4 |
7c673cae FG |
253 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
254 | ); | |
255 | fence_after(order); | |
256 | return original; | |
257 | } | |
258 | ||
259 | static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
260 | { | |
261 | fence_before(order); | |
262 | uint32_t tmp; | |
263 | storage_type original, result; | |
264 | __asm__ __volatile__ | |
265 | ( | |
266 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
267 | "1:\n\t" |
268 | "ldrex %[original], %[storage]\n\t" // original = *(&storage) | |
269 | "orr %[result], %[original], %[value]\n\t" // result = original | value | |
270 | "strex %[tmp], %[result], %[storage]\n\t" // *(&storage) = result, tmp = store failed | |
271 | "teq %[tmp], #0\n\t" // flags = tmp==0 | |
272 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
7c673cae FG |
273 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
274 | : [original] "=&r" (original), // %0 | |
275 | [result] "=&r" (result), // %1 | |
276 | [tmp] "=&l" (tmp), // %2 | |
277 | [storage] "+Q" (storage) // %3 | |
b32b8144 | 278 | : [value] "Ir" (v) // %4 |
7c673cae FG |
279 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
280 | ); | |
281 | fence_after(order); | |
282 | return original; | |
283 | } | |
284 | ||
285 | static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
286 | { | |
287 | fence_before(order); | |
288 | uint32_t tmp; | |
289 | storage_type original, result; | |
290 | __asm__ __volatile__ | |
291 | ( | |
292 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
293 | "1:\n\t" |
294 | "ldrex %[original], %[storage]\n\t" // original = *(&storage) | |
295 | "eor %[result], %[original], %[value]\n\t" // result = original ^ value | |
296 | "strex %[tmp], %[result], %[storage]\n\t" // *(&storage) = result, tmp = store failed | |
297 | "teq %[tmp], #0\n\t" // flags = tmp==0 | |
298 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
7c673cae FG |
299 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
300 | : [original] "=&r" (original), // %0 | |
301 | [result] "=&r" (result), // %1 | |
302 | [tmp] "=&l" (tmp), // %2 | |
303 | [storage] "+Q" (storage) // %3 | |
b32b8144 | 304 | : [value] "Ir" (v) // %4 |
7c673cae FG |
305 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
306 | ); | |
307 | fence_after(order); | |
308 | return original; | |
309 | } | |
310 | ||
311 | static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT | |
312 | { | |
313 | return !!exchange(storage, (storage_type)1, order); | |
314 | } | |
315 | ||
316 | static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT | |
317 | { | |
f67539c2 | 318 | store(storage, (storage_type)0, order); |
7c673cae | 319 | } |
b32b8144 FG |
320 | }; |
321 | ||
322 | #if defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXB_STREXB) | |
323 | ||
20effc67 TL |
324 | template< bool Signed, bool Interprocess > |
325 | struct core_arch_operations< 1u, Signed, Interprocess > : | |
326 | public core_arch_operations_gcc_arm_base | |
b32b8144 | 327 | { |
f67539c2 TL |
328 | typedef typename storage_traits< 1u >::type storage_type; |
329 | typedef typename storage_traits< 4u >::type extended_storage_type; | |
b32b8144 FG |
330 | |
331 | static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 1u; | |
f67539c2 | 332 | static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = 1u; |
b32b8144 | 333 | static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; |
20effc67 | 334 | static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; |
b32b8144 FG |
335 | |
336 | static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
337 | { | |
338 | fence_before(order); | |
339 | storage = v; | |
340 | fence_after_store(order); | |
341 | } | |
342 | ||
343 | static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT | |
344 | { | |
345 | storage_type v = storage; | |
346 | fence_after(order); | |
347 | return v; | |
348 | } | |
349 | ||
350 | static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
351 | { | |
b32b8144 | 352 | fence_before(order); |
20effc67 | 353 | extended_storage_type original; |
b32b8144 FG |
354 | uint32_t tmp; |
355 | __asm__ __volatile__ | |
356 | ( | |
357 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
358 | "1:\n\t" |
359 | "ldrexb %[original], %[storage]\n\t" // load the original value and zero-extend to 32 bits | |
360 | "strexb %[tmp], %[value], %[storage]\n\t" // store the replacement, tmp = store failed | |
361 | "teq %[tmp], #0\n\t" // check if store succeeded | |
362 | "bne 1b\n\t" | |
b32b8144 FG |
363 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
364 | : [tmp] "=&l" (tmp), [original] "=&r" (original), [storage] "+Q" (storage) | |
11fdf7f2 | 365 | : [value] "r" (v) |
b32b8144 FG |
366 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
367 | ); | |
368 | fence_after(order); | |
369 | return static_cast< storage_type >(original); | |
370 | } | |
371 | ||
372 | static BOOST_FORCEINLINE bool compare_exchange_weak( | |
373 | storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT | |
374 | { | |
375 | fence_before(success_order); | |
20effc67 TL |
376 | bool success = false; |
377 | #if !defined(BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_UNUSED) | |
b32b8144 | 378 | uint32_t tmp; |
20effc67 | 379 | #endif |
b32b8144 FG |
380 | extended_storage_type original; |
381 | __asm__ __volatile__ | |
382 | ( | |
383 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
384 | "ldrexb %[original], %[storage]\n\t" // original = zero_extend(*(&storage)) |
385 | "cmp %[original], %[expected]\n\t" // flags = original==expected | |
386 | "itt eq\n\t" // [hint that the following 2 instructions are conditional on flags.equal] | |
387 | "strexbeq %[success], %[desired], %[storage]\n\t" // if (flags.equal) *(&storage) = desired, success = store failed | |
388 | "eoreq %[success], %[success], #1\n\t" // if (flags.equal) success ^= 1 (i.e. make it 1 if store succeeded) | |
b32b8144 | 389 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
20effc67 TL |
390 | : [original] "=&r" (original), |
391 | [success] "+r" (success), | |
392 | #if !defined(BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_UNUSED) | |
393 | [tmp] "=&l" (tmp), | |
394 | #endif | |
395 | [storage] "+Q" (storage) | |
396 | : [expected] "Ir" (atomics::detail::zero_extend< extended_storage_type >(expected)), | |
397 | [desired] "r" (desired) | |
b32b8144 FG |
398 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
399 | ); | |
400 | if (success) | |
401 | fence_after(success_order); | |
402 | else | |
403 | fence_after(failure_order); | |
404 | expected = static_cast< storage_type >(original); | |
20effc67 | 405 | return success; |
b32b8144 FG |
406 | } |
407 | ||
408 | static BOOST_FORCEINLINE bool compare_exchange_strong( | |
409 | storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT | |
410 | { | |
411 | fence_before(success_order); | |
20effc67 TL |
412 | bool success = false; |
413 | #if !defined(BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_UNUSED) | |
b32b8144 | 414 | uint32_t tmp; |
20effc67 | 415 | #endif |
b32b8144 FG |
416 | extended_storage_type original; |
417 | __asm__ __volatile__ | |
418 | ( | |
419 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
420 | "1:\n\t" |
421 | "ldrexb %[original], %[storage]\n\t" // original = zero_extend(*(&storage)) | |
422 | "cmp %[original], %[expected]\n\t" // flags = original==expected | |
423 | "bne 2f\n\t" // if (!flags.equal) goto end | |
424 | "strexb %[success], %[desired], %[storage]\n\t" // *(&storage) = desired, success = store failed | |
425 | "eors %[success], %[success], #1\n\t" // success ^= 1 (i.e. make it 1 if store succeeded); flags.equal = success == 0 | |
426 | "beq 1b\n\t" // if (flags.equal) goto retry | |
427 | "2:\n\t" | |
b32b8144 | 428 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
20effc67 TL |
429 | : [original] "=&r" (original), |
430 | [success] "+r" (success), | |
431 | #if !defined(BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_UNUSED) | |
432 | [tmp] "=&l" (tmp), | |
433 | #endif | |
434 | [storage] "+Q" (storage) | |
435 | : [expected] "Ir" (atomics::detail::zero_extend< extended_storage_type >(expected)), | |
436 | [desired] "r" (desired) | |
b32b8144 FG |
437 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
438 | ); | |
439 | if (success) | |
440 | fence_after(success_order); | |
441 | else | |
442 | fence_after(failure_order); | |
443 | expected = static_cast< storage_type >(original); | |
20effc67 | 444 | return success; |
b32b8144 FG |
445 | } |
446 | ||
447 | static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
448 | { | |
449 | fence_before(order); | |
450 | uint32_t tmp; | |
451 | extended_storage_type original, result; | |
452 | __asm__ __volatile__ | |
453 | ( | |
454 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
455 | "1:\n\t" |
456 | "ldrexb %[original], %[storage]\n\t" // original = zero_extend(*(&storage)) | |
457 | "add %[result], %[original], %[value]\n\t" // result = original + value | |
458 | "strexb %[tmp], %[result], %[storage]\n\t" // *(&storage) = result, tmp = store failed | |
459 | "teq %[tmp], #0\n\t" // flags = tmp==0 | |
460 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
b32b8144 FG |
461 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
462 | : [original] "=&r" (original), // %0 | |
463 | [result] "=&r" (result), // %1 | |
464 | [tmp] "=&l" (tmp), // %2 | |
465 | [storage] "+Q" (storage) // %3 | |
11fdf7f2 | 466 | : [value] "Ir" (v) // %4 |
b32b8144 FG |
467 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
468 | ); | |
469 | fence_after(order); | |
470 | return static_cast< storage_type >(original); | |
471 | } | |
472 | ||
473 | static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
474 | { | |
475 | fence_before(order); | |
476 | uint32_t tmp; | |
477 | extended_storage_type original, result; | |
478 | __asm__ __volatile__ | |
479 | ( | |
480 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
481 | "1:\n\t" |
482 | "ldrexb %[original], %[storage]\n\t" // original = zero_extend(*(&storage)) | |
483 | "sub %[result], %[original], %[value]\n\t" // result = original - value | |
484 | "strexb %[tmp], %[result], %[storage]\n\t" // *(&storage) = result, tmp = store failed | |
485 | "teq %[tmp], #0\n\t" // flags = tmp==0 | |
486 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
b32b8144 FG |
487 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
488 | : [original] "=&r" (original), // %0 | |
489 | [result] "=&r" (result), // %1 | |
490 | [tmp] "=&l" (tmp), // %2 | |
491 | [storage] "+Q" (storage) // %3 | |
11fdf7f2 | 492 | : [value] "Ir" (v) // %4 |
b32b8144 FG |
493 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
494 | ); | |
495 | fence_after(order); | |
496 | return static_cast< storage_type >(original); | |
497 | } | |
498 | ||
499 | static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
500 | { | |
501 | fence_before(order); | |
502 | uint32_t tmp; | |
503 | extended_storage_type original, result; | |
504 | __asm__ __volatile__ | |
505 | ( | |
506 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
507 | "1:\n\t" |
508 | "ldrexb %[original], %[storage]\n\t" // original = zero_extend(*(&storage)) | |
509 | "and %[result], %[original], %[value]\n\t" // result = original & value | |
510 | "strexb %[tmp], %[result], %[storage]\n\t" // *(&storage) = result, tmp = store failed | |
511 | "teq %[tmp], #0\n\t" // flags = tmp==0 | |
512 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
b32b8144 FG |
513 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
514 | : [original] "=&r" (original), // %0 | |
515 | [result] "=&r" (result), // %1 | |
516 | [tmp] "=&l" (tmp), // %2 | |
517 | [storage] "+Q" (storage) // %3 | |
11fdf7f2 | 518 | : [value] "Ir" (v) // %4 |
b32b8144 FG |
519 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
520 | ); | |
521 | fence_after(order); | |
522 | return static_cast< storage_type >(original); | |
523 | } | |
524 | ||
525 | static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
526 | { | |
527 | fence_before(order); | |
528 | uint32_t tmp; | |
529 | extended_storage_type original, result; | |
530 | __asm__ __volatile__ | |
531 | ( | |
532 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
533 | "1:\n\t" |
534 | "ldrexb %[original], %[storage]\n\t" // original = zero_extend(*(&storage)) | |
535 | "orr %[result], %[original], %[value]\n\t" // result = original | value | |
536 | "strexb %[tmp], %[result], %[storage]\n\t" // *(&storage) = result, tmp = store failed | |
537 | "teq %[tmp], #0\n\t" // flags = tmp==0 | |
538 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
b32b8144 FG |
539 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
540 | : [original] "=&r" (original), // %0 | |
541 | [result] "=&r" (result), // %1 | |
542 | [tmp] "=&l" (tmp), // %2 | |
543 | [storage] "+Q" (storage) // %3 | |
11fdf7f2 | 544 | : [value] "Ir" (v) // %4 |
b32b8144 FG |
545 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
546 | ); | |
547 | fence_after(order); | |
548 | return static_cast< storage_type >(original); | |
549 | } | |
550 | ||
551 | static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
552 | { | |
553 | fence_before(order); | |
554 | uint32_t tmp; | |
555 | extended_storage_type original, result; | |
556 | __asm__ __volatile__ | |
557 | ( | |
558 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
559 | "1:\n\t" |
560 | "ldrexb %[original], %[storage]\n\t" // original = zero_extend(*(&storage)) | |
561 | "eor %[result], %[original], %[value]\n\t" // result = original ^ value | |
562 | "strexb %[tmp], %[result], %[storage]\n\t" // *(&storage) = result, tmp = store failed | |
563 | "teq %[tmp], #0\n\t" // flags = tmp==0 | |
564 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
b32b8144 FG |
565 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
566 | : [original] "=&r" (original), // %0 | |
567 | [result] "=&r" (result), // %1 | |
568 | [tmp] "=&l" (tmp), // %2 | |
569 | [storage] "+Q" (storage) // %3 | |
11fdf7f2 | 570 | : [value] "Ir" (v) // %4 |
b32b8144 FG |
571 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
572 | ); | |
573 | fence_after(order); | |
574 | return static_cast< storage_type >(original); | |
575 | } | |
7c673cae | 576 | |
b32b8144 | 577 | static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT |
7c673cae | 578 | { |
b32b8144 FG |
579 | return !!exchange(storage, (storage_type)1, order); |
580 | } | |
581 | ||
582 | static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT | |
583 | { | |
f67539c2 | 584 | store(storage, (storage_type)0, order); |
7c673cae FG |
585 | } |
586 | }; | |
587 | ||
b32b8144 | 588 | #else // defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXB_STREXB) |
7c673cae | 589 | |
20effc67 TL |
590 | template< bool Interprocess > |
591 | struct core_arch_operations< 1u, false, Interprocess > : | |
592 | public core_arch_operations< 4u, false, Interprocess > | |
7c673cae | 593 | { |
20effc67 TL |
594 | typedef core_arch_operations< 4u, false, Interprocess > base_type; |
595 | typedef typename base_type::storage_type storage_type; | |
7c673cae FG |
596 | |
597 | static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
598 | { | |
20effc67 | 599 | base_type::fence_before(order); |
7c673cae FG |
600 | uint32_t tmp; |
601 | storage_type original, result; | |
602 | __asm__ __volatile__ | |
603 | ( | |
604 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
605 | "1:\n\t" |
606 | "ldrex %[original], %[storage]\n\t" // original = *(&storage) | |
607 | "add %[result], %[original], %[value]\n\t" // result = original + value | |
608 | "uxtb %[result], %[result]\n\t" // zero extend result from 8 to 32 bits | |
609 | "strex %[tmp], %[result], %[storage]\n\t" // *(&storage) = result, tmp = store failed | |
610 | "teq %[tmp], #0\n\t" // flags = tmp==0 | |
611 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
7c673cae FG |
612 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
613 | : [original] "=&r" (original), // %0 | |
614 | [result] "=&r" (result), // %1 | |
615 | [tmp] "=&l" (tmp), // %2 | |
616 | [storage] "+Q" (storage) // %3 | |
b32b8144 | 617 | : [value] "Ir" (v) // %4 |
7c673cae FG |
618 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
619 | ); | |
20effc67 | 620 | base_type::fence_after(order); |
7c673cae FG |
621 | return original; |
622 | } | |
623 | ||
624 | static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
625 | { | |
20effc67 | 626 | base_type::fence_before(order); |
7c673cae FG |
627 | uint32_t tmp; |
628 | storage_type original, result; | |
629 | __asm__ __volatile__ | |
630 | ( | |
631 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
632 | "1:\n\t" |
633 | "ldrex %[original], %[storage]\n\t" // original = *(&storage) | |
634 | "sub %[result], %[original], %[value]\n\t" // result = original - value | |
635 | "uxtb %[result], %[result]\n\t" // zero extend result from 8 to 32 bits | |
636 | "strex %[tmp], %[result], %[storage]\n\t" // *(&storage) = result, tmp = store failed | |
637 | "teq %[tmp], #0\n\t" // flags = tmp==0 | |
638 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
7c673cae FG |
639 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
640 | : [original] "=&r" (original), // %0 | |
641 | [result] "=&r" (result), // %1 | |
642 | [tmp] "=&l" (tmp), // %2 | |
643 | [storage] "+Q" (storage) // %3 | |
b32b8144 | 644 | : [value] "Ir" (v) // %4 |
7c673cae FG |
645 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
646 | ); | |
20effc67 | 647 | base_type::fence_after(order); |
7c673cae FG |
648 | return original; |
649 | } | |
650 | }; | |
651 | ||
20effc67 TL |
652 | template< bool Interprocess > |
653 | struct core_arch_operations< 1u, true, Interprocess > : | |
654 | public core_arch_operations< 4u, true, Interprocess > | |
7c673cae | 655 | { |
20effc67 TL |
656 | typedef core_arch_operations< 4u, true, Interprocess > base_type; |
657 | typedef typename base_type::storage_type storage_type; | |
7c673cae FG |
658 | |
659 | static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
660 | { | |
20effc67 | 661 | base_type::fence_before(order); |
7c673cae FG |
662 | uint32_t tmp; |
663 | storage_type original, result; | |
664 | __asm__ __volatile__ | |
665 | ( | |
666 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
667 | "1:\n\t" |
668 | "ldrex %[original], %[storage]\n\t" // original = *(&storage) | |
669 | "add %[result], %[original], %[value]\n\t" // result = original + value | |
670 | "sxtb %[result], %[result]\n\t" // sign extend result from 8 to 32 bits | |
671 | "strex %[tmp], %[result], %[storage]\n\t" // *(&storage) = result, tmp = store failed | |
672 | "teq %[tmp], #0\n\t" // flags = tmp==0 | |
673 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
7c673cae FG |
674 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
675 | : [original] "=&r" (original), // %0 | |
676 | [result] "=&r" (result), // %1 | |
677 | [tmp] "=&l" (tmp), // %2 | |
678 | [storage] "+Q" (storage) // %3 | |
b32b8144 | 679 | : [value] "Ir" (v) // %4 |
7c673cae FG |
680 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
681 | ); | |
20effc67 | 682 | base_type::fence_after(order); |
7c673cae FG |
683 | return original; |
684 | } | |
685 | ||
686 | static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
687 | { | |
20effc67 | 688 | base_type::fence_before(order); |
7c673cae FG |
689 | uint32_t tmp; |
690 | storage_type original, result; | |
691 | __asm__ __volatile__ | |
692 | ( | |
693 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
694 | "1:\n\t" |
695 | "ldrex %[original], %[storage]\n\t" // original = *(&storage) | |
696 | "sub %[result], %[original], %[value]\n\t" // result = original - value | |
697 | "sxtb %[result], %[result]\n\t" // sign extend result from 8 to 32 bits | |
698 | "strex %[tmp], %[result], %[storage]\n\t" // *(&storage) = result, tmp = store failed | |
699 | "teq %[tmp], #0\n\t" // flags = tmp==0 | |
700 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
7c673cae FG |
701 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
702 | : [original] "=&r" (original), // %0 | |
703 | [result] "=&r" (result), // %1 | |
704 | [tmp] "=&l" (tmp), // %2 | |
705 | [storage] "+Q" (storage) // %3 | |
b32b8144 | 706 | : [value] "Ir" (v) // %4 |
7c673cae FG |
707 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
708 | ); | |
20effc67 | 709 | base_type::fence_after(order); |
7c673cae FG |
710 | return original; |
711 | } | |
712 | }; | |
713 | ||
b32b8144 FG |
714 | #endif // defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXB_STREXB) |
715 | ||
716 | #if defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXH_STREXH) | |
717 | ||
20effc67 TL |
718 | template< bool Signed, bool Interprocess > |
719 | struct core_arch_operations< 2u, Signed, Interprocess > : | |
720 | public core_arch_operations_gcc_arm_base | |
b32b8144 | 721 | { |
f67539c2 TL |
722 | typedef typename storage_traits< 2u >::type storage_type; |
723 | typedef typename storage_traits< 4u >::type extended_storage_type; | |
b32b8144 FG |
724 | |
725 | static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 2u; | |
f67539c2 | 726 | static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = 2u; |
b32b8144 | 727 | static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; |
20effc67 | 728 | static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; |
b32b8144 FG |
729 | |
730 | static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
731 | { | |
732 | fence_before(order); | |
733 | storage = v; | |
734 | fence_after_store(order); | |
735 | } | |
736 | ||
737 | static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT | |
738 | { | |
739 | storage_type v = storage; | |
740 | fence_after(order); | |
741 | return v; | |
742 | } | |
743 | ||
744 | static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
745 | { | |
b32b8144 | 746 | fence_before(order); |
20effc67 | 747 | extended_storage_type original; |
b32b8144 FG |
748 | uint32_t tmp; |
749 | __asm__ __volatile__ | |
750 | ( | |
751 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
752 | "1:\n\t" |
753 | "ldrexh %[original], %[storage]\n\t" // load the original value and zero-extend to 32 bits | |
754 | "strexh %[tmp], %[value], %[storage]\n\t" // store the replacement, tmp = store failed | |
755 | "teq %[tmp], #0\n\t" // check if store succeeded | |
756 | "bne 1b\n\t" | |
b32b8144 FG |
757 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
758 | : [tmp] "=&l" (tmp), [original] "=&r" (original), [storage] "+Q" (storage) | |
11fdf7f2 | 759 | : [value] "r" (v) |
b32b8144 FG |
760 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
761 | ); | |
762 | fence_after(order); | |
763 | return static_cast< storage_type >(original); | |
764 | } | |
765 | ||
766 | static BOOST_FORCEINLINE bool compare_exchange_weak( | |
767 | storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT | |
768 | { | |
769 | fence_before(success_order); | |
20effc67 TL |
770 | bool success = false; |
771 | #if !defined(BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_UNUSED) | |
b32b8144 | 772 | uint32_t tmp; |
20effc67 | 773 | #endif |
b32b8144 FG |
774 | extended_storage_type original; |
775 | __asm__ __volatile__ | |
776 | ( | |
777 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
778 | "ldrexh %[original], %[storage]\n\t" // original = zero_extend(*(&storage)) |
779 | "cmp %[original], %[expected]\n\t" // flags = original==expected | |
780 | "itt eq\n\t" // [hint that the following 2 instructions are conditional on flags.equal] | |
781 | "strexheq %[success], %[desired], %[storage]\n\t" // if (flags.equal) *(&storage) = desired, success = store failed | |
782 | "eoreq %[success], %[success], #1\n\t" // if (flags.equal) success ^= 1 (i.e. make it 1 if store succeeded) | |
b32b8144 | 783 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
20effc67 TL |
784 | : [original] "=&r" (original), |
785 | [success] "+r" (success), | |
786 | #if !defined(BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_UNUSED) | |
787 | [tmp] "=&l" (tmp), | |
788 | #endif | |
789 | [storage] "+Q" (storage) | |
790 | : [expected] "Ir" (atomics::detail::zero_extend< extended_storage_type >(expected)), | |
791 | [desired] "r" (desired) | |
b32b8144 FG |
792 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
793 | ); | |
794 | if (success) | |
795 | fence_after(success_order); | |
796 | else | |
797 | fence_after(failure_order); | |
798 | expected = static_cast< storage_type >(original); | |
20effc67 | 799 | return success; |
b32b8144 FG |
800 | } |
801 | ||
802 | static BOOST_FORCEINLINE bool compare_exchange_strong( | |
803 | storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT | |
804 | { | |
805 | fence_before(success_order); | |
20effc67 TL |
806 | bool success = false; |
807 | #if !defined(BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_UNUSED) | |
b32b8144 | 808 | uint32_t tmp; |
20effc67 | 809 | #endif |
b32b8144 FG |
810 | extended_storage_type original; |
811 | __asm__ __volatile__ | |
812 | ( | |
813 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
814 | "1:\n\t" |
815 | "ldrexh %[original], %[storage]\n\t" // original = zero_extend(*(&storage)) | |
816 | "cmp %[original], %[expected]\n\t" // flags = original==expected | |
817 | "bne 2f\n\t" // if (!flags.equal) goto end | |
818 | "strexh %[success], %[desired], %[storage]\n\t" // *(&storage) = desired, success = store failed | |
819 | "eors %[success], %[success], #1\n\t" // success ^= 1 (i.e. make it 1 if store succeeded); flags.equal = success == 0 | |
820 | "beq 1b\n\t" // if (flags.equal) goto retry | |
821 | "2:\n\t" | |
b32b8144 | 822 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
20effc67 TL |
823 | : [original] "=&r" (original), |
824 | [success] "+r" (success), | |
825 | #if !defined(BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_UNUSED) | |
826 | [tmp] "=&l" (tmp), | |
827 | #endif | |
828 | [storage] "+Q" (storage) | |
829 | : [expected] "Ir" (atomics::detail::zero_extend< extended_storage_type >(expected)), | |
830 | [desired] "r" (desired) | |
b32b8144 FG |
831 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
832 | ); | |
833 | if (success) | |
834 | fence_after(success_order); | |
835 | else | |
836 | fence_after(failure_order); | |
837 | expected = static_cast< storage_type >(original); | |
20effc67 | 838 | return success; |
b32b8144 FG |
839 | } |
840 | ||
841 | static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
842 | { | |
843 | fence_before(order); | |
844 | uint32_t tmp; | |
845 | extended_storage_type original, result; | |
846 | __asm__ __volatile__ | |
847 | ( | |
848 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
849 | "1:\n\t" |
850 | "ldrexh %[original], %[storage]\n\t" // original = zero_extend(*(&storage)) | |
851 | "add %[result], %[original], %[value]\n\t" // result = original + value | |
852 | "strexh %[tmp], %[result], %[storage]\n\t" // *(&storage) = result, tmp = store failed | |
853 | "teq %[tmp], #0\n\t" // flags = tmp==0 | |
854 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
b32b8144 FG |
855 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
856 | : [original] "=&r" (original), // %0 | |
857 | [result] "=&r" (result), // %1 | |
858 | [tmp] "=&l" (tmp), // %2 | |
859 | [storage] "+Q" (storage) // %3 | |
11fdf7f2 | 860 | : [value] "Ir" (v) // %4 |
b32b8144 FG |
861 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
862 | ); | |
863 | fence_after(order); | |
864 | return static_cast< storage_type >(original); | |
865 | } | |
866 | ||
867 | static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
868 | { | |
869 | fence_before(order); | |
870 | uint32_t tmp; | |
871 | extended_storage_type original, result; | |
872 | __asm__ __volatile__ | |
873 | ( | |
874 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
875 | "1:\n\t" |
876 | "ldrexh %[original], %[storage]\n\t" // original = zero_extend(*(&storage)) | |
877 | "sub %[result], %[original], %[value]\n\t" // result = original - value | |
878 | "strexh %[tmp], %[result], %[storage]\n\t" // *(&storage) = result, tmp = store failed | |
879 | "teq %[tmp], #0\n\t" // flags = tmp==0 | |
880 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
b32b8144 FG |
881 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
882 | : [original] "=&r" (original), // %0 | |
883 | [result] "=&r" (result), // %1 | |
884 | [tmp] "=&l" (tmp), // %2 | |
885 | [storage] "+Q" (storage) // %3 | |
11fdf7f2 | 886 | : [value] "Ir" (v) // %4 |
b32b8144 FG |
887 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
888 | ); | |
889 | fence_after(order); | |
890 | return static_cast< storage_type >(original); | |
891 | } | |
892 | ||
893 | static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
894 | { | |
895 | fence_before(order); | |
896 | uint32_t tmp; | |
897 | extended_storage_type original, result; | |
898 | __asm__ __volatile__ | |
899 | ( | |
900 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
901 | "1:\n\t" |
902 | "ldrexh %[original], %[storage]\n\t" // original = zero_extend(*(&storage)) | |
903 | "and %[result], %[original], %[value]\n\t" // result = original & value | |
904 | "strexh %[tmp], %[result], %[storage]\n\t" // *(&storage) = result, tmp = store failed | |
905 | "teq %[tmp], #0\n\t" // flags = tmp==0 | |
906 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
b32b8144 FG |
907 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
908 | : [original] "=&r" (original), // %0 | |
909 | [result] "=&r" (result), // %1 | |
910 | [tmp] "=&l" (tmp), // %2 | |
911 | [storage] "+Q" (storage) // %3 | |
11fdf7f2 | 912 | : [value] "Ir" (v) // %4 |
b32b8144 FG |
913 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
914 | ); | |
915 | fence_after(order); | |
916 | return static_cast< storage_type >(original); | |
917 | } | |
918 | ||
919 | static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
920 | { | |
921 | fence_before(order); | |
922 | uint32_t tmp; | |
923 | extended_storage_type original, result; | |
924 | __asm__ __volatile__ | |
925 | ( | |
926 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
927 | "1:\n\t" |
928 | "ldrexh %[original], %[storage]\n\t" // original = zero_extend(*(&storage)) | |
929 | "orr %[result], %[original], %[value]\n\t" // result = original | value | |
930 | "strexh %[tmp], %[result], %[storage]\n\t" // *(&storage) = result, tmp = store failed | |
931 | "teq %[tmp], #0\n\t" // flags = tmp==0 | |
932 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
b32b8144 FG |
933 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
934 | : [original] "=&r" (original), // %0 | |
935 | [result] "=&r" (result), // %1 | |
936 | [tmp] "=&l" (tmp), // %2 | |
937 | [storage] "+Q" (storage) // %3 | |
11fdf7f2 | 938 | : [value] "Ir" (v) // %4 |
b32b8144 FG |
939 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
940 | ); | |
941 | fence_after(order); | |
942 | return static_cast< storage_type >(original); | |
943 | } | |
944 | ||
945 | static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
946 | { | |
947 | fence_before(order); | |
948 | uint32_t tmp; | |
949 | extended_storage_type original, result; | |
950 | __asm__ __volatile__ | |
951 | ( | |
952 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
953 | "1:\n\t" |
954 | "ldrexh %[original], %[storage]\n\t" // original = zero_extend(*(&storage)) | |
955 | "eor %[result], %[original], %[value]\n\t" // result = original ^ value | |
956 | "strexh %[tmp], %[result], %[storage]\n\t" // *(&storage) = result, tmp = store failed | |
957 | "teq %[tmp], #0\n\t" // flags = tmp==0 | |
958 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
b32b8144 FG |
959 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
960 | : [original] "=&r" (original), // %0 | |
961 | [result] "=&r" (result), // %1 | |
962 | [tmp] "=&l" (tmp), // %2 | |
963 | [storage] "+Q" (storage) // %3 | |
11fdf7f2 | 964 | : [value] "Ir" (v) // %4 |
b32b8144 FG |
965 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
966 | ); | |
967 | fence_after(order); | |
968 | return static_cast< storage_type >(original); | |
969 | } | |
970 | ||
971 | static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT | |
972 | { | |
973 | return !!exchange(storage, (storage_type)1, order); | |
974 | } | |
975 | ||
976 | static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT | |
977 | { | |
f67539c2 | 978 | store(storage, (storage_type)0, order); |
b32b8144 FG |
979 | } |
980 | }; | |
981 | ||
982 | #else // defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXH_STREXH) | |
7c673cae | 983 | |
20effc67 TL |
984 | template< bool Interprocess > |
985 | struct core_arch_operations< 2u, false, Interprocess > : | |
986 | public core_arch_operations< 4u, false, Interprocess > | |
7c673cae | 987 | { |
20effc67 TL |
988 | typedef core_arch_operations< 4u, false, Interprocess > base_type; |
989 | typedef typename base_type::storage_type storage_type; | |
7c673cae FG |
990 | |
991 | static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
992 | { | |
20effc67 | 993 | base_type::fence_before(order); |
7c673cae FG |
994 | uint32_t tmp; |
995 | storage_type original, result; | |
996 | __asm__ __volatile__ | |
997 | ( | |
998 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
999 | "1:\n\t" |
1000 | "ldrex %[original], %[storage]\n\t" // original = *(&storage) | |
1001 | "add %[result], %[original], %[value]\n\t" // result = original + value | |
1002 | "uxth %[result], %[result]\n\t" // zero extend result from 16 to 32 bits | |
1003 | "strex %[tmp], %[result], %[storage]\n\t" // *(&storage) = result, tmp = store failed | |
1004 | "teq %[tmp], #0\n\t" // flags = tmp==0 | |
1005 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
7c673cae FG |
1006 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
1007 | : [original] "=&r" (original), // %0 | |
1008 | [result] "=&r" (result), // %1 | |
1009 | [tmp] "=&l" (tmp), // %2 | |
1010 | [storage] "+Q" (storage) // %3 | |
b32b8144 | 1011 | : [value] "Ir" (v) // %4 |
7c673cae FG |
1012 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
1013 | ); | |
20effc67 | 1014 | base_type::fence_after(order); |
7c673cae FG |
1015 | return original; |
1016 | } | |
1017 | ||
1018 | static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
1019 | { | |
20effc67 | 1020 | base_type::fence_before(order); |
7c673cae FG |
1021 | uint32_t tmp; |
1022 | storage_type original, result; | |
1023 | __asm__ __volatile__ | |
1024 | ( | |
1025 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
1026 | "1:\n\t" |
1027 | "ldrex %[original], %[storage]\n\t" // original = *(&storage) | |
1028 | "sub %[result], %[original], %[value]\n\t" // result = original - value | |
1029 | "uxth %[result], %[result]\n\t" // zero extend result from 16 to 32 bits | |
1030 | "strex %[tmp], %[result], %[storage]\n\t" // *(&storage) = result, tmp = store failed | |
1031 | "teq %[tmp], #0\n\t" // flags = tmp==0 | |
1032 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
7c673cae FG |
1033 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
1034 | : [original] "=&r" (original), // %0 | |
1035 | [result] "=&r" (result), // %1 | |
1036 | [tmp] "=&l" (tmp), // %2 | |
1037 | [storage] "+Q" (storage) // %3 | |
b32b8144 | 1038 | : [value] "Ir" (v) // %4 |
7c673cae FG |
1039 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
1040 | ); | |
20effc67 | 1041 | base_type::fence_after(order); |
7c673cae FG |
1042 | return original; |
1043 | } | |
1044 | }; | |
1045 | ||
20effc67 TL |
1046 | template< bool Interprocess > |
1047 | struct core_arch_operations< 2u, true, Interprocess > : | |
1048 | public core_arch_operations< 4u, true, Interprocess > | |
7c673cae | 1049 | { |
20effc67 TL |
1050 | typedef core_arch_operations< 4u, true, Interprocess > base_type; |
1051 | typedef typename base_type::storage_type storage_type; | |
7c673cae FG |
1052 | |
1053 | static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
1054 | { | |
20effc67 | 1055 | base_type::fence_before(order); |
7c673cae FG |
1056 | uint32_t tmp; |
1057 | storage_type original, result; | |
1058 | __asm__ __volatile__ | |
1059 | ( | |
1060 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
1061 | "1:\n\t" |
1062 | "ldrex %[original], %[storage]\n\t" // original = *(&storage) | |
1063 | "add %[result], %[original], %[value]\n\t" // result = original + value | |
1064 | "sxth %[result], %[result]\n\t" // sign extend result from 16 to 32 bits | |
1065 | "strex %[tmp], %[result], %[storage]\n\t" // *(&storage) = result, tmp = store failed | |
1066 | "teq %[tmp], #0\n\t" // flags = tmp==0 | |
1067 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
7c673cae FG |
1068 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
1069 | : [original] "=&r" (original), // %0 | |
1070 | [result] "=&r" (result), // %1 | |
1071 | [tmp] "=&l" (tmp), // %2 | |
1072 | [storage] "+Q" (storage) // %3 | |
b32b8144 | 1073 | : [value] "Ir" (v) // %4 |
7c673cae FG |
1074 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
1075 | ); | |
20effc67 | 1076 | base_type::fence_after(order); |
7c673cae FG |
1077 | return original; |
1078 | } | |
1079 | ||
1080 | static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
1081 | { | |
20effc67 | 1082 | base_type::fence_before(order); |
7c673cae FG |
1083 | uint32_t tmp; |
1084 | storage_type original, result; | |
1085 | __asm__ __volatile__ | |
1086 | ( | |
1087 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) | |
20effc67 TL |
1088 | "1:\n\t" |
1089 | "ldrex %[original], %[storage]\n\t" // original = *(&storage) | |
1090 | "sub %[result], %[original], %[value]\n\t" // result = original - value | |
1091 | "sxth %[result], %[result]\n\t" // sign extend result from 16 to 32 bits | |
1092 | "strex %[tmp], %[result], %[storage]\n\t" // *(&storage) = result, tmp = store failed | |
1093 | "teq %[tmp], #0\n\t" // flags = tmp==0 | |
1094 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
7c673cae FG |
1095 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) |
1096 | : [original] "=&r" (original), // %0 | |
1097 | [result] "=&r" (result), // %1 | |
1098 | [tmp] "=&l" (tmp), // %2 | |
1099 | [storage] "+Q" (storage) // %3 | |
b32b8144 | 1100 | : [value] "Ir" (v) // %4 |
7c673cae FG |
1101 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC |
1102 | ); | |
20effc67 | 1103 | base_type::fence_after(order); |
7c673cae FG |
1104 | return original; |
1105 | } | |
1106 | }; | |
1107 | ||
b32b8144 | 1108 | #endif // defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXH_STREXH) |
7c673cae FG |
1109 | |
1110 | #if defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXD_STREXD) | |
1111 | ||
1112 | // Unlike 32-bit operations, for 64-bit loads and stores we must use ldrexd/strexd. | |
1113 | // Any other instructions result in a non-atomic sequence of 32-bit accesses. | |
1114 | // See "ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition", | |
1115 | // Section A3.5.3 "Atomicity in the ARM architecture". | |
1116 | ||
1117 | // In the asm blocks below we have to use 32-bit register pairs to compose 64-bit values. | |
1118 | // In order to pass the 64-bit operands to/from asm blocks, we use undocumented gcc feature: | |
1119 | // the lower half (Rt) of the operand is accessible normally, via the numbered placeholder (e.g. %0), | |
1120 | // and the upper half (Rt2) - via the same placeholder with an 'H' after the '%' sign (e.g. %H0). | |
1121 | // See: http://hardwarebug.org/2010/07/06/arm-inline-asm-secrets/ | |
1122 | ||
20effc67 TL |
1123 | template< bool Signed, bool Interprocess > |
1124 | struct core_arch_operations< 8u, Signed, Interprocess > : | |
1125 | public core_arch_operations_gcc_arm_base | |
7c673cae | 1126 | { |
f67539c2 | 1127 | typedef typename storage_traits< 8u >::type storage_type; |
7c673cae | 1128 | |
b32b8144 | 1129 | static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 8u; |
f67539c2 | 1130 | static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = 8u; |
b32b8144 | 1131 | static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; |
20effc67 | 1132 | static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; |
b32b8144 | 1133 | |
7c673cae FG |
1134 | static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT |
1135 | { | |
1136 | exchange(storage, v, order); | |
1137 | } | |
1138 | ||
1139 | static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT | |
1140 | { | |
20effc67 TL |
1141 | // ARMv7 says ldrex (and other load-exclusive instructions) can be used without a matching strex, see |
1142 | // "ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition", Section A3.4.5 "Load-Exclusive and Store-Exclusive usage restrictions". | |
7c673cae | 1143 | storage_type original; |
20effc67 TL |
1144 | #if defined(BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_UNUSED) |
1145 | __asm__ __volatile__ | |
1146 | ( | |
1147 | "ldrexd %0, %H0, %1\n\t" | |
1148 | : "=&r" (original) // %0 | |
1149 | : "Q" (storage) // %1 | |
1150 | ); | |
1151 | #else | |
7c673cae FG |
1152 | uint32_t tmp; |
1153 | __asm__ __volatile__ | |
1154 | ( | |
1155 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) | |
20effc67 | 1156 | "ldrexd %1, %H1, %2\n\t" |
7c673cae FG |
1157 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) |
1158 | : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 | |
1159 | "=&r" (original) // %1 | |
20effc67 | 1160 | : "Q" (storage) // %2 |
7c673cae | 1161 | ); |
20effc67 | 1162 | #endif |
7c673cae FG |
1163 | fence_after(order); |
1164 | return original; | |
1165 | } | |
1166 | ||
1167 | static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
1168 | { | |
7c673cae | 1169 | fence_before(order); |
20effc67 | 1170 | storage_type original; |
7c673cae FG |
1171 | uint32_t tmp; |
1172 | __asm__ __volatile__ | |
1173 | ( | |
1174 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) | |
20effc67 TL |
1175 | "1:\n\t" |
1176 | "ldrexd %1, %H1, %2\n\t" // load the original value | |
1177 | "strexd %0, %3, %H3, %2\n\t" // store the replacement, tmp = store failed | |
1178 | "teq %0, #0\n\t" // check if store succeeded | |
1179 | "bne 1b\n\t" | |
7c673cae FG |
1180 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) |
1181 | : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 | |
20effc67 TL |
1182 | "=&r" (original), // %1 |
1183 | "+Q" (storage) // %2 | |
1184 | : "r" (v) // %3 | |
1185 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC | |
7c673cae FG |
1186 | ); |
1187 | fence_after(order); | |
1188 | return original; | |
1189 | } | |
1190 | ||
1191 | static BOOST_FORCEINLINE bool compare_exchange_weak( | |
1192 | storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT | |
1193 | { | |
1194 | fence_before(success_order); | |
20effc67 TL |
1195 | storage_type original; |
1196 | bool success = false; | |
7c673cae | 1197 | uint32_t tmp; |
7c673cae FG |
1198 | __asm__ __volatile__ |
1199 | ( | |
1200 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) | |
20effc67 TL |
1201 | "ldrexd %1, %H1, %3\n\t" // original = *(&storage) |
1202 | "cmp %1, %4\n\t" // flags = original.lo==expected.lo | |
1203 | "it eq\n\t" // [hint that the following 1 instruction is conditional on flags.equal] | |
1204 | "cmpeq %H1, %H4\n\t" // if (flags.equal) flags = original.hi==expected.hi | |
1205 | "bne 1f\n\t" | |
1206 | "strexd %2, %5, %H5, %3\n\t" // *(&storage) = desired, success = store failed | |
1207 | "eor %2, %2, #1\n\t" // success ^= 1 (i.e. make it 1 if store succeeded) | |
1208 | "1:\n\t" | |
7c673cae FG |
1209 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) |
1210 | : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 | |
1211 | "=&r" (original), // %1 | |
20effc67 TL |
1212 | "+r" (success), // %2 |
1213 | "+Q" (storage) // %3 | |
1214 | : "r" (expected), // %4 | |
1215 | "r" (desired) // %5 | |
1216 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC | |
7c673cae | 1217 | ); |
7c673cae FG |
1218 | if (success) |
1219 | fence_after(success_order); | |
1220 | else | |
1221 | fence_after(failure_order); | |
1222 | expected = original; | |
20effc67 | 1223 | return success; |
7c673cae FG |
1224 | } |
1225 | ||
1226 | static BOOST_FORCEINLINE bool compare_exchange_strong( | |
1227 | storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT | |
1228 | { | |
1229 | fence_before(success_order); | |
20effc67 TL |
1230 | storage_type original; |
1231 | bool success = false; | |
7c673cae | 1232 | uint32_t tmp; |
7c673cae FG |
1233 | __asm__ __volatile__ |
1234 | ( | |
1235 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) | |
20effc67 TL |
1236 | "1:\n\t" |
1237 | "ldrexd %1, %H1, %3\n\t" // original = *(&storage) | |
1238 | "cmp %1, %4\n\t" // flags = original.lo==expected.lo | |
1239 | "it eq\n\t" // [hint that the following 1 instruction is conditional on flags.equal] | |
1240 | "cmpeq %H1, %H4\n\t" // if (flags.equal) flags = original.hi==expected.hi | |
1241 | "bne 2f\n\t" | |
1242 | "strexd %2, %5, %H5, %3\n\t" // *(&storage) = desired, success = store failed | |
1243 | "eors %2, %2, #1\n\t" // success ^= 1 (i.e. make it 1 if store succeeded), flags.equal = success == 0 | |
1244 | "beq 1b\n\t" // if (flags.equal) goto retry | |
1245 | "2:\n\t" | |
7c673cae FG |
1246 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) |
1247 | : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 | |
1248 | "=&r" (original), // %1 | |
20effc67 TL |
1249 | "+r" (success), // %2 |
1250 | "+Q" (storage) // %3 | |
1251 | : "r" (expected), // %4 | |
1252 | "r" (desired) // %5 | |
1253 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC | |
7c673cae | 1254 | ); |
7c673cae FG |
1255 | if (success) |
1256 | fence_after(success_order); | |
1257 | else | |
1258 | fence_after(failure_order); | |
1259 | expected = original; | |
20effc67 | 1260 | return success; |
7c673cae FG |
1261 | } |
1262 | ||
1263 | static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
1264 | { | |
1265 | fence_before(order); | |
1266 | storage_type original, result; | |
1267 | uint32_t tmp; | |
1268 | __asm__ __volatile__ | |
1269 | ( | |
1270 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) | |
20effc67 TL |
1271 | "1:\n\t" |
1272 | "ldrexd %1, %H1, %3\n\t" // original = *(&storage) | |
1273 | "adds " BOOST_ATOMIC_DETAIL_ARM_ASM_ARG_LO(2) ", " BOOST_ATOMIC_DETAIL_ARM_ASM_ARG_LO(1) ", " BOOST_ATOMIC_DETAIL_ARM_ASM_ARG_LO(4) "\n\t" // result = original + value | |
1274 | "adc " BOOST_ATOMIC_DETAIL_ARM_ASM_ARG_HI(2) ", " BOOST_ATOMIC_DETAIL_ARM_ASM_ARG_HI(1) ", " BOOST_ATOMIC_DETAIL_ARM_ASM_ARG_HI(4) "\n\t" | |
1275 | "strexd %0, %2, %H2, %3\n\t" // *(&storage) = result, tmp = store failed | |
1276 | "teq %0, #0\n\t" // flags = tmp==0 | |
1277 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
7c673cae FG |
1278 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) |
1279 | : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 | |
1280 | "=&r" (original), // %1 | |
20effc67 TL |
1281 | "=&r" (result), // %2 |
1282 | "+Q" (storage) // %3 | |
1283 | : "r" (v) // %4 | |
1284 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC | |
7c673cae FG |
1285 | ); |
1286 | fence_after(order); | |
1287 | return original; | |
1288 | } | |
1289 | ||
1290 | static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
1291 | { | |
1292 | fence_before(order); | |
1293 | storage_type original, result; | |
1294 | uint32_t tmp; | |
1295 | __asm__ __volatile__ | |
1296 | ( | |
1297 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) | |
20effc67 TL |
1298 | "1:\n\t" |
1299 | "ldrexd %1, %H1, %3\n\t" // original = *(&storage) | |
1300 | "subs " BOOST_ATOMIC_DETAIL_ARM_ASM_ARG_LO(2) ", " BOOST_ATOMIC_DETAIL_ARM_ASM_ARG_LO(1) ", " BOOST_ATOMIC_DETAIL_ARM_ASM_ARG_LO(4) "\n\t" // result = original - value | |
1301 | "sbc " BOOST_ATOMIC_DETAIL_ARM_ASM_ARG_HI(2) ", " BOOST_ATOMIC_DETAIL_ARM_ASM_ARG_HI(1) ", " BOOST_ATOMIC_DETAIL_ARM_ASM_ARG_HI(4) "\n\t" | |
1302 | "strexd %0, %2, %H2, %3\n\t" // *(&storage) = result, tmp = store failed | |
1303 | "teq %0, #0\n\t" // flags = tmp==0 | |
1304 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
7c673cae FG |
1305 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) |
1306 | : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 | |
1307 | "=&r" (original), // %1 | |
20effc67 TL |
1308 | "=&r" (result), // %2 |
1309 | "+Q" (storage) // %3 | |
1310 | : "r" (v) // %4 | |
1311 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC | |
7c673cae FG |
1312 | ); |
1313 | fence_after(order); | |
1314 | return original; | |
1315 | } | |
1316 | ||
1317 | static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
1318 | { | |
1319 | fence_before(order); | |
1320 | storage_type original, result; | |
1321 | uint32_t tmp; | |
1322 | __asm__ __volatile__ | |
1323 | ( | |
1324 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) | |
20effc67 TL |
1325 | "1:\n\t" |
1326 | "ldrexd %1, %H1, %3\n\t" // original = *(&storage) | |
1327 | "and %2, %1, %4\n\t" // result = original & value | |
1328 | "and %H2, %H1, %H4\n\t" | |
1329 | "strexd %0, %2, %H2, %3\n\t" // *(&storage) = result, tmp = store failed | |
1330 | "teq %0, #0\n\t" // flags = tmp==0 | |
1331 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
7c673cae FG |
1332 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) |
1333 | : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 | |
1334 | "=&r" (original), // %1 | |
20effc67 TL |
1335 | "=&r" (result), // %2 |
1336 | "+Q" (storage) // %3 | |
1337 | : "r" (v) // %4 | |
1338 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC | |
7c673cae FG |
1339 | ); |
1340 | fence_after(order); | |
1341 | return original; | |
1342 | } | |
1343 | ||
1344 | static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
1345 | { | |
1346 | fence_before(order); | |
1347 | storage_type original, result; | |
1348 | uint32_t tmp; | |
1349 | __asm__ __volatile__ | |
1350 | ( | |
1351 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) | |
20effc67 TL |
1352 | "1:\n\t" |
1353 | "ldrexd %1, %H1, %3\n\t" // original = *(&storage) | |
1354 | "orr %2, %1, %4\n\t" // result = original | value | |
1355 | "orr %H2, %H1, %H4\n\t" | |
1356 | "strexd %0, %2, %H2, %3\n\t" // *(&storage) = result, tmp = store failed | |
1357 | "teq %0, #0\n\t" // flags = tmp==0 | |
1358 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
7c673cae FG |
1359 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) |
1360 | : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 | |
1361 | "=&r" (original), // %1 | |
20effc67 TL |
1362 | "=&r" (result), // %2 |
1363 | "+Q" (storage) // %3 | |
1364 | : "r" (v) // %4 | |
1365 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC | |
7c673cae FG |
1366 | ); |
1367 | fence_after(order); | |
1368 | return original; | |
1369 | } | |
1370 | ||
1371 | static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT | |
1372 | { | |
1373 | fence_before(order); | |
1374 | storage_type original, result; | |
1375 | uint32_t tmp; | |
1376 | __asm__ __volatile__ | |
1377 | ( | |
1378 | BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) | |
20effc67 TL |
1379 | "1:\n\t" |
1380 | "ldrexd %1, %H1, %3\n\t" // original = *(&storage) | |
1381 | "eor %2, %1, %4\n\t" // result = original ^ value | |
1382 | "eor %H2, %H1, %H4\n\t" | |
1383 | "strexd %0, %2, %H2, %3\n\t" // *(&storage) = result, tmp = store failed | |
1384 | "teq %0, #0\n\t" // flags = tmp==0 | |
1385 | "bne 1b\n\t" // if (!flags.equal) goto retry | |
7c673cae FG |
1386 | BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) |
1387 | : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 | |
1388 | "=&r" (original), // %1 | |
20effc67 TL |
1389 | "=&r" (result), // %2 |
1390 | "+Q" (storage) // %3 | |
1391 | : "r" (v) // %4 | |
1392 | : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC | |
7c673cae FG |
1393 | ); |
1394 | fence_after(order); | |
1395 | return original; | |
1396 | } | |
1397 | ||
1398 | static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT | |
1399 | { | |
1400 | return !!exchange(storage, (storage_type)1, order); | |
1401 | } | |
1402 | ||
1403 | static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT | |
1404 | { | |
f67539c2 | 1405 | store(storage, (storage_type)0, order); |
7c673cae | 1406 | } |
7c673cae FG |
1407 | }; |
1408 | ||
1409 | #endif // defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXD_STREXD) | |
1410 | ||
7c673cae FG |
1411 | } // namespace detail |
1412 | } // namespace atomics | |
1413 | } // namespace boost | |
1414 | ||
20effc67 TL |
1415 | #include <boost/atomic/detail/footer.hpp> |
1416 | ||
1417 | #endif // BOOST_ATOMIC_DETAIL_CORE_ARCH_OPS_GCC_ARM_HPP_INCLUDED_ |