ops_gcc_arm.hpp 61 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397
  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_