ops_gcc_arm.hpp 61 KB

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