annotate DEPENDENCIES/generic/include/boost/atomic/detail/ops_gcc_arm.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents f46d142149f5
children
rev   line source
Chris@102 1 /*
Chris@102 2 * Distributed under the Boost Software License, Version 1.0.
Chris@102 3 * (See accompanying file LICENSE_1_0.txt or copy at
Chris@102 4 * http://www.boost.org/LICENSE_1_0.txt)
Chris@102 5 *
Chris@102 6 * Copyright (c) 2009 Helge Bahmann
Chris@102 7 * Copyright (c) 2013 Tim Blechmann
Chris@102 8 * Copyright (c) 2014 Andrey Semashev
Chris@102 9 */
Chris@102 10 /*!
Chris@102 11 * \file atomic/detail/ops_gcc_arm.hpp
Chris@102 12 *
Chris@102 13 * This header contains implementation of the \c operations template.
Chris@102 14 */
Chris@102 15
Chris@102 16 #ifndef BOOST_ATOMIC_DETAIL_OPS_GCC_ARM_HPP_INCLUDED_
Chris@102 17 #define BOOST_ATOMIC_DETAIL_OPS_GCC_ARM_HPP_INCLUDED_
Chris@102 18
Chris@102 19 #include <boost/cstdint.hpp>
Chris@102 20 #include <boost/memory_order.hpp>
Chris@102 21 #include <boost/atomic/detail/config.hpp>
Chris@102 22 #include <boost/atomic/detail/storage_type.hpp>
Chris@102 23 #include <boost/atomic/detail/operations_fwd.hpp>
Chris@102 24 #include <boost/atomic/detail/ops_extending_cas_based.hpp>
Chris@102 25 #include <boost/atomic/capabilities.hpp>
Chris@102 26
Chris@102 27 #ifdef BOOST_HAS_PRAGMA_ONCE
Chris@102 28 #pragma once
Chris@102 29 #endif
Chris@102 30
Chris@102 31 namespace boost {
Chris@102 32 namespace atomics {
Chris@102 33 namespace detail {
Chris@102 34
Chris@102 35 // From the ARM Architecture Reference Manual for architecture v6:
Chris@102 36 //
Chris@102 37 // LDREX{<cond>} <Rd>, [<Rn>]
Chris@102 38 // <Rd> Specifies the destination register for the memory word addressed by <Rd>
Chris@102 39 // <Rn> Specifies the register containing the address.
Chris@102 40 //
Chris@102 41 // STREX{<cond>} <Rd>, <Rm>, [<Rn>]
Chris@102 42 // <Rd> Specifies the destination register for the returned status value.
Chris@102 43 // 0 if the operation updates memory
Chris@102 44 // 1 if the operation fails to update memory
Chris@102 45 // <Rm> Specifies the register containing the word to be stored to memory.
Chris@102 46 // <Rn> Specifies the register containing the address.
Chris@102 47 // Rd must not be the same register as Rm or Rn.
Chris@102 48 //
Chris@102 49 // ARM v7 is like ARM v6 plus:
Chris@102 50 // There are half-word and byte versions of the LDREX and STREX instructions,
Chris@102 51 // LDREXH, LDREXB, STREXH and STREXB.
Chris@102 52 // There are also double-word versions, LDREXD and STREXD.
Chris@102 53 // (Actually it looks like these are available from version 6k onwards.)
Chris@102 54 // FIXME these are not yet used; should be mostly a matter of copy-and-paste.
Chris@102 55 // I think you can supply an immediate offset to the address.
Chris@102 56 //
Chris@102 57 // A memory barrier is effected using a "co-processor 15" instruction,
Chris@102 58 // though a separate assembler mnemonic is available for it in v7.
Chris@102 59 //
Chris@102 60 // "Thumb 1" is a subset of the ARM instruction set that uses a 16-bit encoding. It
Chris@102 61 // doesn't include all instructions and in particular it doesn't include the co-processor
Chris@102 62 // instruction used for the memory barrier or the load-locked/store-conditional
Chris@102 63 // instructions. So, if we're compiling in "Thumb 1" mode, we need to wrap all of our
Chris@102 64 // asm blocks with code to temporarily change to ARM mode.
Chris@102 65 //
Chris@102 66 // You can only change between ARM and Thumb modes when branching using the bx instruction.
Chris@102 67 // bx takes an address specified in a register. The least significant bit of the address
Chris@102 68 // indicates the mode, so 1 is added to indicate that the destination code is Thumb.
Chris@102 69 // A temporary register is needed for the address and is passed as an argument to these
Chris@102 70 // macros. It must be one of the "low" registers accessible to Thumb code, specified
Chris@102 71 // using the "l" attribute in the asm statement.
Chris@102 72 //
Chris@102 73 // Architecture v7 introduces "Thumb 2", which does include (almost?) all of the ARM
Chris@102 74 // instruction set. (Actually, there was an extension of v6 called v6T2 which supported
Chris@102 75 // "Thumb 2" mode, but its architecture manual is no longer available, referring to v7.)
Chris@102 76 // So in v7 we don't need to change to ARM mode; we can write "universal
Chris@102 77 // assembler" which will assemble to Thumb 2 or ARM code as appropriate. The only thing
Chris@102 78 // we need to do to make this "universal" assembler mode work is to insert "IT" instructions
Chris@102 79 // to annotate the conditional instructions. These are ignored in other modes (e.g. v6),
Chris@102 80 // so they can always be present.
Chris@102 81
Chris@102 82 // A note about memory_order_consume. Technically, this architecture allows to avoid
Chris@102 83 // unnecessary memory barrier after consume load since it supports data dependency ordering.
Chris@102 84 // However, some compiler optimizations may break a seemingly valid code relying on data
Chris@102 85 // dependency tracking by injecting bogus branches to aid out of order execution.
Chris@102 86 // This may happen not only in Boost.Atomic code but also in user's code, which we have no
Chris@102 87 // control of. See this thread: http://lists.boost.org/Archives/boost/2014/06/213890.php.
Chris@102 88 // For this reason we promote memory_order_consume to memory_order_acquire.
Chris@102 89
Chris@102 90 #if defined(__thumb__) && !defined(__thumb2__)
Chris@102 91 #define BOOST_ATOMIC_DETAIL_ARM_ASM_START(TMPREG) "adr " #TMPREG ", 8f\n" "bx " #TMPREG "\n" ".arm\n" ".align 4\n" "8:\n"
Chris@102 92 #define BOOST_ATOMIC_DETAIL_ARM_ASM_END(TMPREG) "adr " #TMPREG ", 9f + 1\n" "bx " #TMPREG "\n" ".thumb\n" ".align 2\n" "9:\n"
Chris@102 93 #define BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(var) "=&l" (var)
Chris@102 94 #else
Chris@102 95 // The tmpreg may be wasted in this case, which is non-optimal.
Chris@102 96 #define BOOST_ATOMIC_DETAIL_ARM_ASM_START(TMPREG)
Chris@102 97 #define BOOST_ATOMIC_DETAIL_ARM_ASM_END(TMPREG)
Chris@102 98 #define BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(var) "=&r" (var)
Chris@102 99 #endif
Chris@102 100
Chris@102 101 struct gcc_arm_operations_base
Chris@102 102 {
Chris@102 103 static BOOST_FORCEINLINE void fence_before(memory_order order) BOOST_NOEXCEPT
Chris@102 104 {
Chris@102 105 if ((order & memory_order_release) != 0)
Chris@102 106 hardware_full_fence();
Chris@102 107 }
Chris@102 108
Chris@102 109 static BOOST_FORCEINLINE void fence_after(memory_order order) BOOST_NOEXCEPT
Chris@102 110 {
Chris@102 111 if ((order & (memory_order_consume | memory_order_acquire)) != 0)
Chris@102 112 hardware_full_fence();
Chris@102 113 }
Chris@102 114
Chris@102 115 static BOOST_FORCEINLINE void fence_after_store(memory_order order) BOOST_NOEXCEPT
Chris@102 116 {
Chris@102 117 if (order == memory_order_seq_cst)
Chris@102 118 hardware_full_fence();
Chris@102 119 }
Chris@102 120
Chris@102 121 static BOOST_FORCEINLINE void hardware_full_fence() BOOST_NOEXCEPT
Chris@102 122 {
Chris@102 123 #if defined(BOOST_ATOMIC_DETAIL_ARM_HAS_DMB)
Chris@102 124 // Older binutils (supposedly, older than 2.21.1) didn't support symbolic or numeric arguments of the "dmb" instruction such as "ish" or "#11".
Chris@102 125 // As a workaround we have to inject encoded bytes of the instruction. There are two encodings for the instruction: ARM and Thumb. See ARM Architecture Reference Manual, A8.8.43.
Chris@102 126 // Since we cannot detect binutils version at compile time, we'll have to always use this hack.
Chris@102 127 __asm__ __volatile__
Chris@102 128 (
Chris@102 129 #if defined(__thumb2__)
Chris@102 130 ".short 0xF3BF, 0x8F5B\n" // dmb ish
Chris@102 131 #else
Chris@102 132 ".word 0xF57FF05B\n" // dmb ish
Chris@102 133 #endif
Chris@102 134 :
Chris@102 135 :
Chris@102 136 : "memory"
Chris@102 137 );
Chris@102 138 #else
Chris@102 139 int tmp;
Chris@102 140 __asm__ __volatile__
Chris@102 141 (
Chris@102 142 BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0)
Chris@102 143 "mcr\tp15, 0, r0, c7, c10, 5\n"
Chris@102 144 BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0)
Chris@102 145 : "=&l" (tmp)
Chris@102 146 :
Chris@102 147 : "memory"
Chris@102 148 );
Chris@102 149 #endif
Chris@102 150 }
Chris@102 151 };
Chris@102 152
Chris@102 153
Chris@102 154 template< bool Signed >
Chris@102 155 struct operations< 4u, Signed > :
Chris@102 156 public gcc_arm_operations_base
Chris@102 157 {
Chris@102 158 typedef typename make_storage_type< 4u, Signed >::type storage_type;
Chris@102 159
Chris@102 160 static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 161 {
Chris@102 162 fence_before(order);
Chris@102 163 storage = v;
Chris@102 164 fence_after_store(order);
Chris@102 165 }
Chris@102 166
Chris@102 167 static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT
Chris@102 168 {
Chris@102 169 storage_type v = storage;
Chris@102 170 fence_after(order);
Chris@102 171 return v;
Chris@102 172 }
Chris@102 173
Chris@102 174 static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 175 {
Chris@102 176 storage_type original;
Chris@102 177 fence_before(order);
Chris@102 178 uint32_t tmp;
Chris@102 179 __asm__ __volatile__
Chris@102 180 (
Chris@102 181 BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp])
Chris@102 182 "1:\n"
Chris@102 183 "ldrex %[original], %[storage]\n" // load the original value
Chris@102 184 "strex %[tmp], %[value], %[storage]\n" // store the replacement, tmp = store failed
Chris@102 185 "teq %[tmp], #0\n" // check if store succeeded
Chris@102 186 "bne 1b\n"
Chris@102 187 BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp])
Chris@102 188 : [tmp] "=&l" (tmp), [original] "=&r" (original), [storage] "+Q" (storage)
Chris@102 189 : [value] "r" (v)
Chris@102 190 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
Chris@102 191 );
Chris@102 192 fence_after(order);
Chris@102 193 return original;
Chris@102 194 }
Chris@102 195
Chris@102 196 static BOOST_FORCEINLINE bool compare_exchange_weak(
Chris@102 197 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT
Chris@102 198 {
Chris@102 199 fence_before(success_order);
Chris@102 200 uint32_t success;
Chris@102 201 uint32_t tmp;
Chris@102 202 storage_type original;
Chris@102 203 __asm__ __volatile__
Chris@102 204 (
Chris@102 205 BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp])
Chris@102 206 "mov %[success], #0\n" // success = 0
Chris@102 207 "ldrex %[original], %[storage]\n" // original = *(&storage)
Chris@102 208 "cmp %[original], %[expected]\n" // flags = original==expected
Chris@102 209 "itt eq\n" // [hint that the following 2 instructions are conditional on flags.equal]
Chris@102 210 "strexeq %[success], %[desired], %[storage]\n" // if (flags.equal) *(&storage) = desired, success = store failed
Chris@102 211 "eoreq %[success], %[success], #1\n" // if (flags.equal) success ^= 1 (i.e. make it 1 if store succeeded)
Chris@102 212 BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp])
Chris@102 213 : [original] "=&r" (original), // %0
Chris@102 214 [success] "=&r" (success), // %1
Chris@102 215 [tmp] "=&l" (tmp), // %2
Chris@102 216 [storage] "+Q" (storage) // %3
Chris@102 217 : [expected] "r" (expected), // %4
Chris@102 218 [desired] "r" (desired) // %5
Chris@102 219 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
Chris@102 220 );
Chris@102 221 if (success)
Chris@102 222 fence_after(success_order);
Chris@102 223 else
Chris@102 224 fence_after(failure_order);
Chris@102 225 expected = original;
Chris@102 226 return !!success;
Chris@102 227 }
Chris@102 228
Chris@102 229 static BOOST_FORCEINLINE bool compare_exchange_strong(
Chris@102 230 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT
Chris@102 231 {
Chris@102 232 fence_before(success_order);
Chris@102 233 uint32_t success;
Chris@102 234 uint32_t tmp;
Chris@102 235 storage_type original;
Chris@102 236 __asm__ __volatile__
Chris@102 237 (
Chris@102 238 BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp])
Chris@102 239 "mov %[success], #0\n" // success = 0
Chris@102 240 "1:\n"
Chris@102 241 "ldrex %[original], %[storage]\n" // original = *(&storage)
Chris@102 242 "cmp %[original], %[expected]\n" // flags = original==expected
Chris@102 243 "bne 2f\n" // if (!flags.equal) goto end
Chris@102 244 "strex %[success], %[desired], %[storage]\n" // *(&storage) = desired, success = store failed
Chris@102 245 "eors %[success], %[success], #1\n" // success ^= 1 (i.e. make it 1 if store succeeded); flags.equal = success == 0
Chris@102 246 "beq 1b\n" // if (flags.equal) goto retry
Chris@102 247 "2:\n"
Chris@102 248 BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp])
Chris@102 249 : [original] "=&r" (original), // %0
Chris@102 250 [success] "=&r" (success), // %1
Chris@102 251 [tmp] "=&l" (tmp), // %2
Chris@102 252 [storage] "+Q" (storage) // %3
Chris@102 253 : [expected] "r" (expected), // %4
Chris@102 254 [desired] "r" (desired) // %5
Chris@102 255 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
Chris@102 256 );
Chris@102 257 if (success)
Chris@102 258 fence_after(success_order);
Chris@102 259 else
Chris@102 260 fence_after(failure_order);
Chris@102 261 expected = original;
Chris@102 262 return !!success;
Chris@102 263 }
Chris@102 264
Chris@102 265 static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 266 {
Chris@102 267 fence_before(order);
Chris@102 268 uint32_t tmp;
Chris@102 269 storage_type original, result;
Chris@102 270 __asm__ __volatile__
Chris@102 271 (
Chris@102 272 BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp])
Chris@102 273 "1:\n"
Chris@102 274 "ldrex %[original], %[storage]\n" // original = *(&storage)
Chris@102 275 "add %[result], %[original], %[value]\n" // result = original + value
Chris@102 276 "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed
Chris@102 277 "teq %[tmp], #0\n" // flags = tmp==0
Chris@102 278 "bne 1b\n" // if (!flags.equal) goto retry
Chris@102 279 BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp])
Chris@102 280 : [original] "=&r" (original), // %0
Chris@102 281 [result] "=&r" (result), // %1
Chris@102 282 [tmp] "=&l" (tmp), // %2
Chris@102 283 [storage] "+Q" (storage) // %3
Chris@102 284 : [value] "r" (v) // %4
Chris@102 285 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
Chris@102 286 );
Chris@102 287 fence_after(order);
Chris@102 288 return original;
Chris@102 289 }
Chris@102 290
Chris@102 291 static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 292 {
Chris@102 293 fence_before(order);
Chris@102 294 uint32_t tmp;
Chris@102 295 storage_type original, result;
Chris@102 296 __asm__ __volatile__
Chris@102 297 (
Chris@102 298 BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp])
Chris@102 299 "1:\n"
Chris@102 300 "ldrex %[original], %[storage]\n" // original = *(&storage)
Chris@102 301 "sub %[result], %[original], %[value]\n" // result = original - value
Chris@102 302 "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed
Chris@102 303 "teq %[tmp], #0\n" // flags = tmp==0
Chris@102 304 "bne 1b\n" // if (!flags.equal) goto retry
Chris@102 305 BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp])
Chris@102 306 : [original] "=&r" (original), // %0
Chris@102 307 [result] "=&r" (result), // %1
Chris@102 308 [tmp] "=&l" (tmp), // %2
Chris@102 309 [storage] "+Q" (storage) // %3
Chris@102 310 : [value] "r" (v) // %4
Chris@102 311 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
Chris@102 312 );
Chris@102 313 fence_after(order);
Chris@102 314 return original;
Chris@102 315 }
Chris@102 316
Chris@102 317 static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 318 {
Chris@102 319 fence_before(order);
Chris@102 320 uint32_t tmp;
Chris@102 321 storage_type original, result;
Chris@102 322 __asm__ __volatile__
Chris@102 323 (
Chris@102 324 BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp])
Chris@102 325 "1:\n"
Chris@102 326 "ldrex %[original], %[storage]\n" // original = *(&storage)
Chris@102 327 "and %[result], %[original], %[value]\n" // result = original & value
Chris@102 328 "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed
Chris@102 329 "teq %[tmp], #0\n" // flags = tmp==0
Chris@102 330 "bne 1b\n" // if (!flags.equal) goto retry
Chris@102 331 BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp])
Chris@102 332 : [original] "=&r" (original), // %0
Chris@102 333 [result] "=&r" (result), // %1
Chris@102 334 [tmp] "=&l" (tmp), // %2
Chris@102 335 [storage] "+Q" (storage) // %3
Chris@102 336 : [value] "r" (v) // %4
Chris@102 337 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
Chris@102 338 );
Chris@102 339 fence_after(order);
Chris@102 340 return original;
Chris@102 341 }
Chris@102 342
Chris@102 343 static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 344 {
Chris@102 345 fence_before(order);
Chris@102 346 uint32_t tmp;
Chris@102 347 storage_type original, result;
Chris@102 348 __asm__ __volatile__
Chris@102 349 (
Chris@102 350 BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp])
Chris@102 351 "1:\n"
Chris@102 352 "ldrex %[original], %[storage]\n" // original = *(&storage)
Chris@102 353 "orr %[result], %[original], %[value]\n" // result = original | value
Chris@102 354 "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed
Chris@102 355 "teq %[tmp], #0\n" // flags = tmp==0
Chris@102 356 "bne 1b\n" // if (!flags.equal) goto retry
Chris@102 357 BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp])
Chris@102 358 : [original] "=&r" (original), // %0
Chris@102 359 [result] "=&r" (result), // %1
Chris@102 360 [tmp] "=&l" (tmp), // %2
Chris@102 361 [storage] "+Q" (storage) // %3
Chris@102 362 : [value] "r" (v) // %4
Chris@102 363 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
Chris@102 364 );
Chris@102 365 fence_after(order);
Chris@102 366 return original;
Chris@102 367 }
Chris@102 368
Chris@102 369 static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 370 {
Chris@102 371 fence_before(order);
Chris@102 372 uint32_t tmp;
Chris@102 373 storage_type original, result;
Chris@102 374 __asm__ __volatile__
Chris@102 375 (
Chris@102 376 BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp])
Chris@102 377 "1:\n"
Chris@102 378 "ldrex %[original], %[storage]\n" // original = *(&storage)
Chris@102 379 "eor %[result], %[original], %[value]\n" // result = original ^ value
Chris@102 380 "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed
Chris@102 381 "teq %[tmp], #0\n" // flags = tmp==0
Chris@102 382 "bne 1b\n" // if (!flags.equal) goto retry
Chris@102 383 BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp])
Chris@102 384 : [original] "=&r" (original), // %0
Chris@102 385 [result] "=&r" (result), // %1
Chris@102 386 [tmp] "=&l" (tmp), // %2
Chris@102 387 [storage] "+Q" (storage) // %3
Chris@102 388 : [value] "r" (v) // %4
Chris@102 389 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
Chris@102 390 );
Chris@102 391 fence_after(order);
Chris@102 392 return original;
Chris@102 393 }
Chris@102 394
Chris@102 395 static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
Chris@102 396 {
Chris@102 397 return !!exchange(storage, (storage_type)1, order);
Chris@102 398 }
Chris@102 399
Chris@102 400 static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
Chris@102 401 {
Chris@102 402 store(storage, 0, order);
Chris@102 403 }
Chris@102 404
Chris@102 405 static BOOST_FORCEINLINE bool is_lock_free(storage_type const volatile&) BOOST_NOEXCEPT
Chris@102 406 {
Chris@102 407 return true;
Chris@102 408 }
Chris@102 409 };
Chris@102 410
Chris@102 411
Chris@102 412 template< >
Chris@102 413 struct operations< 1u, false > :
Chris@102 414 public operations< 4u, false >
Chris@102 415 {
Chris@102 416 typedef operations< 4u, false > base_type;
Chris@102 417 typedef base_type::storage_type storage_type;
Chris@102 418
Chris@102 419 static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 420 {
Chris@102 421 fence_before(order);
Chris@102 422 uint32_t tmp;
Chris@102 423 storage_type original, result;
Chris@102 424 __asm__ __volatile__
Chris@102 425 (
Chris@102 426 BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp])
Chris@102 427 "1:\n"
Chris@102 428 "ldrex %[original], %[storage]\n" // original = *(&storage)
Chris@102 429 "add %[result], %[original], %[value]\n" // result = original + value
Chris@102 430 "uxtb %[result], %[result]\n" // zero extend result from 8 to 32 bits
Chris@102 431 "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed
Chris@102 432 "teq %[tmp], #0\n" // flags = tmp==0
Chris@102 433 "bne 1b\n" // if (!flags.equal) goto retry
Chris@102 434 BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp])
Chris@102 435 : [original] "=&r" (original), // %0
Chris@102 436 [result] "=&r" (result), // %1
Chris@102 437 [tmp] "=&l" (tmp), // %2
Chris@102 438 [storage] "+Q" (storage) // %3
Chris@102 439 : [value] "r" (v) // %4
Chris@102 440 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
Chris@102 441 );
Chris@102 442 fence_after(order);
Chris@102 443 return original;
Chris@102 444 }
Chris@102 445
Chris@102 446 static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 447 {
Chris@102 448 fence_before(order);
Chris@102 449 uint32_t tmp;
Chris@102 450 storage_type original, result;
Chris@102 451 __asm__ __volatile__
Chris@102 452 (
Chris@102 453 BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp])
Chris@102 454 "1:\n"
Chris@102 455 "ldrex %[original], %[storage]\n" // original = *(&storage)
Chris@102 456 "sub %[result], %[original], %[value]\n" // result = original - value
Chris@102 457 "uxtb %[result], %[result]\n" // zero extend result from 8 to 32 bits
Chris@102 458 "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed
Chris@102 459 "teq %[tmp], #0\n" // flags = tmp==0
Chris@102 460 "bne 1b\n" // if (!flags.equal) goto retry
Chris@102 461 BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp])
Chris@102 462 : [original] "=&r" (original), // %0
Chris@102 463 [result] "=&r" (result), // %1
Chris@102 464 [tmp] "=&l" (tmp), // %2
Chris@102 465 [storage] "+Q" (storage) // %3
Chris@102 466 : [value] "r" (v) // %4
Chris@102 467 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
Chris@102 468 );
Chris@102 469 fence_after(order);
Chris@102 470 return original;
Chris@102 471 }
Chris@102 472 };
Chris@102 473
Chris@102 474 template< >
Chris@102 475 struct operations< 1u, true > :
Chris@102 476 public operations< 4u, true >
Chris@102 477 {
Chris@102 478 typedef operations< 4u, true > base_type;
Chris@102 479 typedef base_type::storage_type storage_type;
Chris@102 480
Chris@102 481 static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 482 {
Chris@102 483 fence_before(order);
Chris@102 484 uint32_t tmp;
Chris@102 485 storage_type original, result;
Chris@102 486 __asm__ __volatile__
Chris@102 487 (
Chris@102 488 BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp])
Chris@102 489 "1:\n"
Chris@102 490 "ldrex %[original], %[storage]\n" // original = *(&storage)
Chris@102 491 "add %[result], %[original], %[value]\n" // result = original + value
Chris@102 492 "sxtb %[result], %[result]\n" // sign extend result from 8 to 32 bits
Chris@102 493 "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed
Chris@102 494 "teq %[tmp], #0\n" // flags = tmp==0
Chris@102 495 "bne 1b\n" // if (!flags.equal) goto retry
Chris@102 496 BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp])
Chris@102 497 : [original] "=&r" (original), // %0
Chris@102 498 [result] "=&r" (result), // %1
Chris@102 499 [tmp] "=&l" (tmp), // %2
Chris@102 500 [storage] "+Q" (storage) // %3
Chris@102 501 : [value] "r" (v) // %4
Chris@102 502 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
Chris@102 503 );
Chris@102 504 fence_after(order);
Chris@102 505 return original;
Chris@102 506 }
Chris@102 507
Chris@102 508 static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 509 {
Chris@102 510 fence_before(order);
Chris@102 511 uint32_t tmp;
Chris@102 512 storage_type original, result;
Chris@102 513 __asm__ __volatile__
Chris@102 514 (
Chris@102 515 BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp])
Chris@102 516 "1:\n"
Chris@102 517 "ldrex %[original], %[storage]\n" // original = *(&storage)
Chris@102 518 "sub %[result], %[original], %[value]\n" // result = original - value
Chris@102 519 "sxtb %[result], %[result]\n" // sign extend result from 8 to 32 bits
Chris@102 520 "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed
Chris@102 521 "teq %[tmp], #0\n" // flags = tmp==0
Chris@102 522 "bne 1b\n" // if (!flags.equal) goto retry
Chris@102 523 BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp])
Chris@102 524 : [original] "=&r" (original), // %0
Chris@102 525 [result] "=&r" (result), // %1
Chris@102 526 [tmp] "=&l" (tmp), // %2
Chris@102 527 [storage] "+Q" (storage) // %3
Chris@102 528 : [value] "r" (v) // %4
Chris@102 529 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
Chris@102 530 );
Chris@102 531 fence_after(order);
Chris@102 532 return original;
Chris@102 533 }
Chris@102 534 };
Chris@102 535
Chris@102 536
Chris@102 537 template< >
Chris@102 538 struct operations< 2u, false > :
Chris@102 539 public operations< 4u, false >
Chris@102 540 {
Chris@102 541 typedef operations< 4u, false > base_type;
Chris@102 542 typedef base_type::storage_type storage_type;
Chris@102 543
Chris@102 544 static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 545 {
Chris@102 546 fence_before(order);
Chris@102 547 uint32_t tmp;
Chris@102 548 storage_type original, result;
Chris@102 549 __asm__ __volatile__
Chris@102 550 (
Chris@102 551 BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp])
Chris@102 552 "1:\n"
Chris@102 553 "ldrex %[original], %[storage]\n" // original = *(&storage)
Chris@102 554 "add %[result], %[original], %[value]\n" // result = original + value
Chris@102 555 "uxth %[result], %[result]\n" // zero extend result from 16 to 32 bits
Chris@102 556 "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed
Chris@102 557 "teq %[tmp], #0\n" // flags = tmp==0
Chris@102 558 "bne 1b\n" // if (!flags.equal) goto retry
Chris@102 559 BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp])
Chris@102 560 : [original] "=&r" (original), // %0
Chris@102 561 [result] "=&r" (result), // %1
Chris@102 562 [tmp] "=&l" (tmp), // %2
Chris@102 563 [storage] "+Q" (storage) // %3
Chris@102 564 : [value] "r" (v) // %4
Chris@102 565 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
Chris@102 566 );
Chris@102 567 fence_after(order);
Chris@102 568 return original;
Chris@102 569 }
Chris@102 570
Chris@102 571 static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 572 {
Chris@102 573 fence_before(order);
Chris@102 574 uint32_t tmp;
Chris@102 575 storage_type original, result;
Chris@102 576 __asm__ __volatile__
Chris@102 577 (
Chris@102 578 BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp])
Chris@102 579 "1:\n"
Chris@102 580 "ldrex %[original], %[storage]\n" // original = *(&storage)
Chris@102 581 "sub %[result], %[original], %[value]\n" // result = original - value
Chris@102 582 "uxth %[result], %[result]\n" // zero extend result from 16 to 32 bits
Chris@102 583 "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed
Chris@102 584 "teq %[tmp], #0\n" // flags = tmp==0
Chris@102 585 "bne 1b\n" // if (!flags.equal) goto retry
Chris@102 586 BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp])
Chris@102 587 : [original] "=&r" (original), // %0
Chris@102 588 [result] "=&r" (result), // %1
Chris@102 589 [tmp] "=&l" (tmp), // %2
Chris@102 590 [storage] "+Q" (storage) // %3
Chris@102 591 : [value] "r" (v) // %4
Chris@102 592 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
Chris@102 593 );
Chris@102 594 fence_after(order);
Chris@102 595 return original;
Chris@102 596 }
Chris@102 597 };
Chris@102 598
Chris@102 599 template< >
Chris@102 600 struct operations< 2u, true > :
Chris@102 601 public operations< 4u, true >
Chris@102 602 {
Chris@102 603 typedef operations< 4u, true > base_type;
Chris@102 604 typedef base_type::storage_type storage_type;
Chris@102 605
Chris@102 606 static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 607 {
Chris@102 608 fence_before(order);
Chris@102 609 uint32_t tmp;
Chris@102 610 storage_type original, result;
Chris@102 611 __asm__ __volatile__
Chris@102 612 (
Chris@102 613 BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp])
Chris@102 614 "1:\n"
Chris@102 615 "ldrex %[original], %[storage]\n" // original = *(&storage)
Chris@102 616 "add %[result], %[original], %[value]\n" // result = original + value
Chris@102 617 "sxth %[result], %[result]\n" // sign extend result from 16 to 32 bits
Chris@102 618 "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed
Chris@102 619 "teq %[tmp], #0\n" // flags = tmp==0
Chris@102 620 "bne 1b\n" // if (!flags.equal) goto retry
Chris@102 621 BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp])
Chris@102 622 : [original] "=&r" (original), // %0
Chris@102 623 [result] "=&r" (result), // %1
Chris@102 624 [tmp] "=&l" (tmp), // %2
Chris@102 625 [storage] "+Q" (storage) // %3
Chris@102 626 : [value] "r" (v) // %4
Chris@102 627 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
Chris@102 628 );
Chris@102 629 fence_after(order);
Chris@102 630 return original;
Chris@102 631 }
Chris@102 632
Chris@102 633 static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 634 {
Chris@102 635 fence_before(order);
Chris@102 636 uint32_t tmp;
Chris@102 637 storage_type original, result;
Chris@102 638 __asm__ __volatile__
Chris@102 639 (
Chris@102 640 BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp])
Chris@102 641 "1:\n"
Chris@102 642 "ldrex %[original], %[storage]\n" // original = *(&storage)
Chris@102 643 "sub %[result], %[original], %[value]\n" // result = original - value
Chris@102 644 "sxth %[result], %[result]\n" // sign extend result from 16 to 32 bits
Chris@102 645 "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed
Chris@102 646 "teq %[tmp], #0\n" // flags = tmp==0
Chris@102 647 "bne 1b\n" // if (!flags.equal) goto retry
Chris@102 648 BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp])
Chris@102 649 : [original] "=&r" (original), // %0
Chris@102 650 [result] "=&r" (result), // %1
Chris@102 651 [tmp] "=&l" (tmp), // %2
Chris@102 652 [storage] "+Q" (storage) // %3
Chris@102 653 : [value] "r" (v) // %4
Chris@102 654 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
Chris@102 655 );
Chris@102 656 fence_after(order);
Chris@102 657 return original;
Chris@102 658 }
Chris@102 659 };
Chris@102 660
Chris@102 661
Chris@102 662 #if defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXD_STREXD)
Chris@102 663
Chris@102 664 // Unlike 32-bit operations, for 64-bit loads and stores we must use ldrexd/strexd.
Chris@102 665 // Any other instructions result in a non-atomic sequence of 32-bit accesses.
Chris@102 666 // See "ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition",
Chris@102 667 // Section A3.5.3 "Atomicity in the ARM architecture".
Chris@102 668
Chris@102 669 // In the asm blocks below we have to use 32-bit register pairs to compose 64-bit values.
Chris@102 670 // In order to pass the 64-bit operands to/from asm blocks, we use undocumented gcc feature:
Chris@102 671 // the lower half (Rt) of the operand is accessible normally, via the numbered placeholder (e.g. %0),
Chris@102 672 // and the upper half (Rt2) - via the same placeholder with an 'H' after the '%' sign (e.g. %H0).
Chris@102 673 // See: http://hardwarebug.org/2010/07/06/arm-inline-asm-secrets/
Chris@102 674
Chris@102 675 template< bool Signed >
Chris@102 676 struct operations< 8u, Signed > :
Chris@102 677 public gcc_arm_operations_base
Chris@102 678 {
Chris@102 679 typedef typename make_storage_type< 8u, Signed >::type storage_type;
Chris@102 680
Chris@102 681 static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 682 {
Chris@102 683 exchange(storage, v, order);
Chris@102 684 }
Chris@102 685
Chris@102 686 static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT
Chris@102 687 {
Chris@102 688 storage_type original;
Chris@102 689 uint32_t tmp;
Chris@102 690 __asm__ __volatile__
Chris@102 691 (
Chris@102 692 BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0)
Chris@102 693 "ldrexd %1, %H1, [%2]\n"
Chris@102 694 BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0)
Chris@102 695 : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0
Chris@102 696 "=&r" (original) // %1
Chris@102 697 : "r" (&storage) // %2
Chris@102 698 );
Chris@102 699 fence_after(order);
Chris@102 700 return original;
Chris@102 701 }
Chris@102 702
Chris@102 703 static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 704 {
Chris@102 705 storage_type original;
Chris@102 706 fence_before(order);
Chris@102 707 uint32_t tmp;
Chris@102 708 __asm__ __volatile__
Chris@102 709 (
Chris@102 710 BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0)
Chris@102 711 "1:\n"
Chris@102 712 "ldrexd %1, %H1, [%3]\n" // load the original value
Chris@102 713 "strexd %0, %2, %H2, [%3]\n" // store the replacement, tmp = store failed
Chris@102 714 "teq %0, #0\n" // check if store succeeded
Chris@102 715 "bne 1b\n"
Chris@102 716 BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0)
Chris@102 717 : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0
Chris@102 718 "=&r" (original) // %1
Chris@102 719 : "r" (v), // %2
Chris@102 720 "r" (&storage) // %3
Chris@102 721 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"
Chris@102 722 );
Chris@102 723 fence_after(order);
Chris@102 724 return original;
Chris@102 725 }
Chris@102 726
Chris@102 727 static BOOST_FORCEINLINE bool compare_exchange_weak(
Chris@102 728 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT
Chris@102 729 {
Chris@102 730 fence_before(success_order);
Chris@102 731 uint32_t tmp;
Chris@102 732 storage_type original, old_val = expected;
Chris@102 733 __asm__ __volatile__
Chris@102 734 (
Chris@102 735 BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0)
Chris@102 736 "ldrexd %1, %H1, [%3]\n" // original = *(&storage)
Chris@102 737 "cmp %1, %2\n" // flags = original.lo==old_val.lo
Chris@102 738 "ittt eq\n" // [hint that the following 3 instructions are conditional on flags.equal]
Chris@102 739 "cmpeq %H1, %H2\n" // if (flags.equal) flags = original.hi==old_val.hi
Chris@102 740 "strexdeq %0, %4, %H4, [%3]\n" // if (flags.equal) *(&storage) = desired, tmp = store failed
Chris@102 741 "teqeq %0, #0\n" // if (flags.equal) flags = tmp==0
Chris@102 742 "ite eq\n" // [hint that the following 2 instructions are conditional on flags.equal]
Chris@102 743 "moveq %2, #1\n" // if (flags.equal) old_val.lo = 1
Chris@102 744 "movne %2, #0\n" // if (!flags.equal) old_val.lo = 0
Chris@102 745 BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0)
Chris@102 746 : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0
Chris@102 747 "=&r" (original), // %1
Chris@102 748 "+r" (old_val) // %2
Chris@102 749 : "r" (&storage), // %3
Chris@102 750 "r" (desired) // %4
Chris@102 751 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"
Chris@102 752 );
Chris@102 753 const uint32_t success = (uint32_t)old_val;
Chris@102 754 if (success)
Chris@102 755 fence_after(success_order);
Chris@102 756 else
Chris@102 757 fence_after(failure_order);
Chris@102 758 expected = original;
Chris@102 759 return !!success;
Chris@102 760 }
Chris@102 761
Chris@102 762 static BOOST_FORCEINLINE bool compare_exchange_strong(
Chris@102 763 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT
Chris@102 764 {
Chris@102 765 fence_before(success_order);
Chris@102 766 uint32_t tmp;
Chris@102 767 storage_type original, old_val = expected;
Chris@102 768 __asm__ __volatile__
Chris@102 769 (
Chris@102 770 BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0)
Chris@102 771 "1:\n"
Chris@102 772 "ldrexd %1, %H1, [%3]\n" // original = *(&storage)
Chris@102 773 "cmp %1, %2\n" // flags = original.lo==old_val.lo
Chris@102 774 "it eq\n" // [hint that the following instruction is conditional on flags.equal]
Chris@102 775 "cmpeq %H1, %H2\n" // if (flags.equal) flags = original.hi==old_val.hi
Chris@102 776 "bne 2f\n" // if (!flags.equal) goto end
Chris@102 777 "strexd %0, %4, %H4, [%3]\n" // *(&storage) = desired, tmp = store failed
Chris@102 778 "teq %0, #0\n" // flags.equal = tmp == 0
Chris@102 779 "bne 1b\n" // if (flags.equal) goto retry
Chris@102 780 "2:\n"
Chris@102 781 "ite eq\n" // [hint that the following 2 instructions are conditional on flags.equal]
Chris@102 782 "moveq %2, #1\n" // if (flags.equal) old_val.lo = 1
Chris@102 783 "movne %2, #0\n" // if (!flags.equal) old_val.lo = 0
Chris@102 784 BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0)
Chris@102 785 : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0
Chris@102 786 "=&r" (original), // %1
Chris@102 787 "+r" (old_val) // %2
Chris@102 788 : "r" (&storage), // %3
Chris@102 789 "r" (desired) // %4
Chris@102 790 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"
Chris@102 791 );
Chris@102 792 const uint32_t success = (uint32_t)old_val;
Chris@102 793 if (success)
Chris@102 794 fence_after(success_order);
Chris@102 795 else
Chris@102 796 fence_after(failure_order);
Chris@102 797 expected = original;
Chris@102 798 return !!success;
Chris@102 799 }
Chris@102 800
Chris@102 801 static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 802 {
Chris@102 803 fence_before(order);
Chris@102 804 storage_type original, result;
Chris@102 805 uint32_t tmp;
Chris@102 806 __asm__ __volatile__
Chris@102 807 (
Chris@102 808 BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0)
Chris@102 809 "1:\n"
Chris@102 810 "ldrexd %1, %H1, [%3]\n" // original = *(&storage)
Chris@102 811 "adds %2, %1, %4\n" // result = original + value
Chris@102 812 "adc %H2, %H1, %H4\n"
Chris@102 813 "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed
Chris@102 814 "teq %0, #0\n" // flags = tmp==0
Chris@102 815 "bne 1b\n" // if (!flags.equal) goto retry
Chris@102 816 BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0)
Chris@102 817 : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0
Chris@102 818 "=&r" (original), // %1
Chris@102 819 "=&r" (result) // %2
Chris@102 820 : "r" (&storage), // %3
Chris@102 821 "r" (v) // %4
Chris@102 822 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"
Chris@102 823 );
Chris@102 824 fence_after(order);
Chris@102 825 return original;
Chris@102 826 }
Chris@102 827
Chris@102 828 static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 829 {
Chris@102 830 fence_before(order);
Chris@102 831 storage_type original, result;
Chris@102 832 uint32_t tmp;
Chris@102 833 __asm__ __volatile__
Chris@102 834 (
Chris@102 835 BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0)
Chris@102 836 "1:\n"
Chris@102 837 "ldrexd %1, %H1, [%3]\n" // original = *(&storage)
Chris@102 838 "subs %2, %1, %4\n" // result = original - value
Chris@102 839 "sbc %H2, %H1, %H4\n"
Chris@102 840 "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed
Chris@102 841 "teq %0, #0\n" // flags = tmp==0
Chris@102 842 "bne 1b\n" // if (!flags.equal) goto retry
Chris@102 843 BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0)
Chris@102 844 : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0
Chris@102 845 "=&r" (original), // %1
Chris@102 846 "=&r" (result) // %2
Chris@102 847 : "r" (&storage), // %3
Chris@102 848 "r" (v) // %4
Chris@102 849 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"
Chris@102 850 );
Chris@102 851 fence_after(order);
Chris@102 852 return original;
Chris@102 853 }
Chris@102 854
Chris@102 855 static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 856 {
Chris@102 857 fence_before(order);
Chris@102 858 storage_type original, result;
Chris@102 859 uint32_t tmp;
Chris@102 860 __asm__ __volatile__
Chris@102 861 (
Chris@102 862 BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0)
Chris@102 863 "1:\n"
Chris@102 864 "ldrexd %1, %H1, [%3]\n" // original = *(&storage)
Chris@102 865 "and %2, %1, %4\n" // result = original & value
Chris@102 866 "and %H2, %H1, %H4\n"
Chris@102 867 "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed
Chris@102 868 "teq %0, #0\n" // flags = tmp==0
Chris@102 869 "bne 1b\n" // if (!flags.equal) goto retry
Chris@102 870 BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0)
Chris@102 871 : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0
Chris@102 872 "=&r" (original), // %1
Chris@102 873 "=&r" (result) // %2
Chris@102 874 : "r" (&storage), // %3
Chris@102 875 "r" (v) // %4
Chris@102 876 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"
Chris@102 877 );
Chris@102 878 fence_after(order);
Chris@102 879 return original;
Chris@102 880 }
Chris@102 881
Chris@102 882 static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 883 {
Chris@102 884 fence_before(order);
Chris@102 885 storage_type original, result;
Chris@102 886 uint32_t tmp;
Chris@102 887 __asm__ __volatile__
Chris@102 888 (
Chris@102 889 BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0)
Chris@102 890 "1:\n"
Chris@102 891 "ldrexd %1, %H1, [%3]\n" // original = *(&storage)
Chris@102 892 "orr %2, %1, %4\n" // result = original | value
Chris@102 893 "orr %H2, %H1, %H4\n"
Chris@102 894 "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed
Chris@102 895 "teq %0, #0\n" // flags = tmp==0
Chris@102 896 "bne 1b\n" // if (!flags.equal) goto retry
Chris@102 897 BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0)
Chris@102 898 : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0
Chris@102 899 "=&r" (original), // %1
Chris@102 900 "=&r" (result) // %2
Chris@102 901 : "r" (&storage), // %3
Chris@102 902 "r" (v) // %4
Chris@102 903 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"
Chris@102 904 );
Chris@102 905 fence_after(order);
Chris@102 906 return original;
Chris@102 907 }
Chris@102 908
Chris@102 909 static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 910 {
Chris@102 911 fence_before(order);
Chris@102 912 storage_type original, result;
Chris@102 913 uint32_t tmp;
Chris@102 914 __asm__ __volatile__
Chris@102 915 (
Chris@102 916 BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0)
Chris@102 917 "1:\n"
Chris@102 918 "ldrexd %1, %H1, [%3]\n" // original = *(&storage)
Chris@102 919 "eor %2, %1, %4\n" // result = original ^ value
Chris@102 920 "eor %H2, %H1, %H4\n"
Chris@102 921 "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed
Chris@102 922 "teq %0, #0\n" // flags = tmp==0
Chris@102 923 "bne 1b\n" // if (!flags.equal) goto retry
Chris@102 924 BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0)
Chris@102 925 : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0
Chris@102 926 "=&r" (original), // %1
Chris@102 927 "=&r" (result) // %2
Chris@102 928 : "r" (&storage), // %3
Chris@102 929 "r" (v) // %4
Chris@102 930 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"
Chris@102 931 );
Chris@102 932 fence_after(order);
Chris@102 933 return original;
Chris@102 934 }
Chris@102 935
Chris@102 936 static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
Chris@102 937 {
Chris@102 938 return !!exchange(storage, (storage_type)1, order);
Chris@102 939 }
Chris@102 940
Chris@102 941 static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
Chris@102 942 {
Chris@102 943 store(storage, 0, order);
Chris@102 944 }
Chris@102 945
Chris@102 946 static BOOST_FORCEINLINE bool is_lock_free(storage_type const volatile&) BOOST_NOEXCEPT
Chris@102 947 {
Chris@102 948 return true;
Chris@102 949 }
Chris@102 950 };
Chris@102 951
Chris@102 952 #endif // defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXD_STREXD)
Chris@102 953
Chris@102 954
Chris@102 955 BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT
Chris@102 956 {
Chris@102 957 if (order != memory_order_relaxed)
Chris@102 958 gcc_arm_operations_base::hardware_full_fence();
Chris@102 959 }
Chris@102 960
Chris@102 961 BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT
Chris@102 962 {
Chris@102 963 if (order != memory_order_relaxed)
Chris@102 964 __asm__ __volatile__ ("" ::: "memory");
Chris@102 965 }
Chris@102 966
Chris@102 967 } // namespace detail
Chris@102 968 } // namespace atomics
Chris@102 969 } // namespace boost
Chris@102 970
Chris@102 971 #endif // BOOST_ATOMIC_DETAIL_OPS_GCC_ARM_HPP_INCLUDED_