atomicops-internals-linuxppc.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
  2. /* Copyright (c) 2008, Google Inc.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are
  7. * met:
  8. *
  9. * * Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * * Redistributions in binary form must reproduce the above
  12. * copyright notice, this list of conditions and the following disclaimer
  13. * in the documentation and/or other materials provided with the
  14. * distribution.
  15. * * Neither the name of Google Inc. nor the names of its
  16. * contributors may be used to endorse or promote products derived from
  17. * this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. *
  31. * ---
  32. */
  33. // Implementation of atomic operations for ppc-linux. This file should not
  34. // be included directly. Clients should instead include
  35. // "base/atomicops.h".
  36. #ifndef BASE_ATOMICOPS_INTERNALS_LINUXPPC_H_
  37. #define BASE_ATOMICOPS_INTERNALS_LINUXPPC_H_
  38. typedef int32_t Atomic32;
  39. #ifdef __PPC64__
  40. #define BASE_HAS_ATOMIC64 1
  41. #endif
  42. namespace base {
  43. namespace subtle {
  44. static inline void _sync(void) {
  45. __asm__ __volatile__("sync": : : "memory");
  46. }
  47. static inline void _lwsync(void) {
  48. // gcc defines __NO_LWSYNC__ when appropriate; see
  49. // http://gcc.gnu.org/ml/gcc-patches/2006-11/msg01238.html
  50. #ifdef __NO_LWSYNC__
  51. __asm__ __volatile__("msync": : : "memory");
  52. #else
  53. __asm__ __volatile__("lwsync": : : "memory");
  54. #endif
  55. }
  56. static inline void _isync(void) {
  57. __asm__ __volatile__("isync": : : "memory");
  58. }
  59. static inline Atomic32 OSAtomicAdd32(Atomic32 amount, Atomic32 *value) {
  60. Atomic32 t;
  61. __asm__ __volatile__(
  62. "1: lwarx %0,0,%3\n\
  63. add %0,%2,%0\n\
  64. stwcx. %0,0,%3 \n\
  65. bne- 1b"
  66. : "=&r" (t), "+m" (*value)
  67. : "r" (amount), "r" (value)
  68. : "cc");
  69. return t;
  70. }
  71. static inline Atomic32 OSAtomicAdd32Barrier(Atomic32 amount, Atomic32 *value) {
  72. Atomic32 t;
  73. _lwsync();
  74. t = OSAtomicAdd32(amount, value);
  75. // This is based on the code snippet in the architecture manual (Vol
  76. // 2, Appendix B). It's a little tricky: correctness depends on the
  77. // fact that the code right before this (in OSAtomicAdd32) has a
  78. // conditional branch with a data dependency on the update.
  79. // Otherwise, we'd have to use sync.
  80. _isync();
  81. return t;
  82. }
  83. static inline bool OSAtomicCompareAndSwap32(Atomic32 old_value,
  84. Atomic32 new_value,
  85. Atomic32 *value) {
  86. Atomic32 prev;
  87. __asm__ __volatile__(
  88. "1: lwarx %0,0,%2\n\
  89. cmpw 0,%0,%3\n\
  90. bne- 2f\n\
  91. stwcx. %4,0,%2\n\
  92. bne- 1b\n\
  93. 2:"
  94. : "=&r" (prev), "+m" (*value)
  95. : "r" (value), "r" (old_value), "r" (new_value)
  96. : "cc");
  97. return prev == old_value;
  98. }
  99. static inline Atomic32 OSAtomicCompareAndSwap32Acquire(Atomic32 old_value,
  100. Atomic32 new_value,
  101. Atomic32 *value) {
  102. Atomic32 t;
  103. t = OSAtomicCompareAndSwap32(old_value, new_value, value);
  104. // This is based on the code snippet in the architecture manual (Vol
  105. // 2, Appendix B). It's a little tricky: correctness depends on the
  106. // fact that the code right before this (in
  107. // OSAtomicCompareAndSwap32) has a conditional branch with a data
  108. // dependency on the update. Otherwise, we'd have to use sync.
  109. _isync();
  110. return t;
  111. }
  112. static inline Atomic32 OSAtomicCompareAndSwap32Release(Atomic32 old_value,
  113. Atomic32 new_value,
  114. Atomic32 *value) {
  115. _lwsync();
  116. return OSAtomicCompareAndSwap32(old_value, new_value, value);
  117. }
  118. typedef int64_t Atomic64;
  119. inline void MemoryBarrier() {
  120. // This can't be _lwsync(); we need to order the immediately
  121. // preceding stores against any load that may follow, but lwsync
  122. // doesn't guarantee that.
  123. _sync();
  124. }
  125. // 32-bit Versions.
  126. inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32 *ptr,
  127. Atomic32 old_value,
  128. Atomic32 new_value) {
  129. Atomic32 prev_value;
  130. do {
  131. if (OSAtomicCompareAndSwap32(old_value, new_value,
  132. const_cast<Atomic32*>(ptr))) {
  133. return old_value;
  134. }
  135. prev_value = *ptr;
  136. } while (prev_value == old_value);
  137. return prev_value;
  138. }
  139. inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32 *ptr,
  140. Atomic32 new_value) {
  141. Atomic32 old_value;
  142. do {
  143. old_value = *ptr;
  144. } while (!OSAtomicCompareAndSwap32(old_value, new_value,
  145. const_cast<Atomic32*>(ptr)));
  146. return old_value;
  147. }
  148. inline Atomic32 Acquire_AtomicExchange(volatile Atomic32 *ptr,
  149. Atomic32 new_value) {
  150. Atomic32 old_value;
  151. do {
  152. old_value = *ptr;
  153. } while (!OSAtomicCompareAndSwap32Acquire(old_value, new_value,
  154. const_cast<Atomic32*>(ptr)));
  155. return old_value;
  156. }
  157. inline Atomic32 Release_AtomicExchange(volatile Atomic32 *ptr,
  158. Atomic32 new_value) {
  159. Atomic32 old_value;
  160. do {
  161. old_value = *ptr;
  162. } while (!OSAtomicCompareAndSwap32Release(old_value, new_value,
  163. const_cast<Atomic32*>(ptr)));
  164. return old_value;
  165. }
  166. inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32 *ptr,
  167. Atomic32 old_value,
  168. Atomic32 new_value) {
  169. Atomic32 prev_value;
  170. do {
  171. if (OSAtomicCompareAndSwap32Acquire(old_value, new_value,
  172. const_cast<Atomic32*>(ptr))) {
  173. return old_value;
  174. }
  175. prev_value = *ptr;
  176. } while (prev_value == old_value);
  177. return prev_value;
  178. }
  179. inline Atomic32 Release_CompareAndSwap(volatile Atomic32 *ptr,
  180. Atomic32 old_value,
  181. Atomic32 new_value) {
  182. Atomic32 prev_value;
  183. do {
  184. if (OSAtomicCompareAndSwap32Release(old_value, new_value,
  185. const_cast<Atomic32*>(ptr))) {
  186. return old_value;
  187. }
  188. prev_value = *ptr;
  189. } while (prev_value == old_value);
  190. return prev_value;
  191. }
  192. #ifdef __PPC64__
  193. // 64-bit Versions.
  194. static inline Atomic64 OSAtomicAdd64(Atomic64 amount, Atomic64 *value) {
  195. Atomic64 t;
  196. __asm__ __volatile__(
  197. "1: ldarx %0,0,%3\n\
  198. add %0,%2,%0\n\
  199. stdcx. %0,0,%3 \n\
  200. bne- 1b"
  201. : "=&r" (t), "+m" (*value)
  202. : "r" (amount), "r" (value)
  203. : "cc");
  204. return t;
  205. }
  206. static inline Atomic64 OSAtomicAdd64Barrier(Atomic64 amount, Atomic64 *value) {
  207. Atomic64 t;
  208. _lwsync();
  209. t = OSAtomicAdd64(amount, value);
  210. // This is based on the code snippet in the architecture manual (Vol
  211. // 2, Appendix B). It's a little tricky: correctness depends on the
  212. // fact that the code right before this (in OSAtomicAdd64) has a
  213. // conditional branch with a data dependency on the update.
  214. // Otherwise, we'd have to use sync.
  215. _isync();
  216. return t;
  217. }
  218. static inline bool OSAtomicCompareAndSwap64(Atomic64 old_value,
  219. Atomic64 new_value,
  220. Atomic64 *value) {
  221. Atomic64 prev;
  222. __asm__ __volatile__(
  223. "1: ldarx %0,0,%2\n\
  224. cmpd 0,%0,%3\n\
  225. bne- 2f\n\
  226. stdcx. %4,0,%2\n\
  227. bne- 1b\n\
  228. 2:"
  229. : "=&r" (prev), "+m" (*value)
  230. : "r" (value), "r" (old_value), "r" (new_value)
  231. : "cc");
  232. return prev == old_value;
  233. }
  234. static inline Atomic64 OSAtomicCompareAndSwap64Acquire(Atomic64 old_value,
  235. Atomic64 new_value,
  236. Atomic64 *value) {
  237. Atomic64 t;
  238. t = OSAtomicCompareAndSwap64(old_value, new_value, value);
  239. // This is based on the code snippet in the architecture manual (Vol
  240. // 2, Appendix B). It's a little tricky: correctness depends on the
  241. // fact that the code right before this (in
  242. // OSAtomicCompareAndSwap64) has a conditional branch with a data
  243. // dependency on the update. Otherwise, we'd have to use sync.
  244. _isync();
  245. return t;
  246. }
  247. static inline Atomic64 OSAtomicCompareAndSwap64Release(Atomic64 old_value,
  248. Atomic64 new_value,
  249. Atomic64 *value) {
  250. _lwsync();
  251. return OSAtomicCompareAndSwap64(old_value, new_value, value);
  252. }
  253. inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64 *ptr,
  254. Atomic64 old_value,
  255. Atomic64 new_value) {
  256. Atomic64 prev_value;
  257. do {
  258. if (OSAtomicCompareAndSwap64(old_value, new_value,
  259. const_cast<Atomic64*>(ptr))) {
  260. return old_value;
  261. }
  262. prev_value = *ptr;
  263. } while (prev_value == old_value);
  264. return prev_value;
  265. }
  266. inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64 *ptr,
  267. Atomic64 new_value) {
  268. Atomic64 old_value;
  269. do {
  270. old_value = *ptr;
  271. } while (!OSAtomicCompareAndSwap64(old_value, new_value,
  272. const_cast<Atomic64*>(ptr)));
  273. return old_value;
  274. }
  275. inline Atomic64 Acquire_AtomicExchange(volatile Atomic64 *ptr,
  276. Atomic64 new_value) {
  277. Atomic64 old_value;
  278. do {
  279. old_value = *ptr;
  280. } while (!OSAtomicCompareAndSwap64Acquire(old_value, new_value,
  281. const_cast<Atomic64*>(ptr)));
  282. return old_value;
  283. }
  284. inline Atomic64 Release_AtomicExchange(volatile Atomic64 *ptr,
  285. Atomic64 new_value) {
  286. Atomic64 old_value;
  287. do {
  288. old_value = *ptr;
  289. } while (!OSAtomicCompareAndSwap64Release(old_value, new_value,
  290. const_cast<Atomic64*>(ptr)));
  291. return old_value;
  292. }
  293. inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64 *ptr,
  294. Atomic64 old_value,
  295. Atomic64 new_value) {
  296. Atomic64 prev_value;
  297. do {
  298. if (OSAtomicCompareAndSwap64Acquire(old_value, new_value,
  299. const_cast<Atomic64*>(ptr))) {
  300. return old_value;
  301. }
  302. prev_value = *ptr;
  303. } while (prev_value == old_value);
  304. return prev_value;
  305. }
  306. inline Atomic64 Release_CompareAndSwap(volatile Atomic64 *ptr,
  307. Atomic64 old_value,
  308. Atomic64 new_value) {
  309. Atomic64 prev_value;
  310. do {
  311. if (OSAtomicCompareAndSwap64Release(old_value, new_value,
  312. const_cast<Atomic64*>(ptr))) {
  313. return old_value;
  314. }
  315. prev_value = *ptr;
  316. } while (prev_value == old_value);
  317. return prev_value;
  318. }
  319. #endif
  320. inline void NoBarrier_Store(volatile Atomic32 *ptr, Atomic32 value) {
  321. *ptr = value;
  322. }
  323. inline void Acquire_Store(volatile Atomic32 *ptr, Atomic32 value) {
  324. *ptr = value;
  325. // This can't be _lwsync(); we need to order the immediately
  326. // preceding stores against any load that may follow, but lwsync
  327. // doesn't guarantee that.
  328. _sync();
  329. }
  330. inline void Release_Store(volatile Atomic32 *ptr, Atomic32 value) {
  331. _lwsync();
  332. *ptr = value;
  333. }
  334. inline Atomic32 NoBarrier_Load(volatile const Atomic32 *ptr) {
  335. return *ptr;
  336. }
  337. inline Atomic32 Acquire_Load(volatile const Atomic32 *ptr) {
  338. Atomic32 value = *ptr;
  339. _lwsync();
  340. return value;
  341. }
  342. inline Atomic32 Release_Load(volatile const Atomic32 *ptr) {
  343. // This can't be _lwsync(); we need to order the immediately
  344. // preceding stores against any load that may follow, but lwsync
  345. // doesn't guarantee that.
  346. _sync();
  347. return *ptr;
  348. }
  349. #ifdef __PPC64__
  350. // 64-bit Versions.
  351. inline void NoBarrier_Store(volatile Atomic64 *ptr, Atomic64 value) {
  352. *ptr = value;
  353. }
  354. inline void Acquire_Store(volatile Atomic64 *ptr, Atomic64 value) {
  355. *ptr = value;
  356. // This can't be _lwsync(); we need to order the immediately
  357. // preceding stores against any load that may follow, but lwsync
  358. // doesn't guarantee that.
  359. _sync();
  360. }
  361. inline void Release_Store(volatile Atomic64 *ptr, Atomic64 value) {
  362. _lwsync();
  363. *ptr = value;
  364. }
  365. inline Atomic64 NoBarrier_Load(volatile const Atomic64 *ptr) {
  366. return *ptr;
  367. }
  368. inline Atomic64 Acquire_Load(volatile const Atomic64 *ptr) {
  369. Atomic64 value = *ptr;
  370. _lwsync();
  371. return value;
  372. }
  373. inline Atomic64 Release_Load(volatile const Atomic64 *ptr) {
  374. // This can't be _lwsync(); we need to order the immediately
  375. // preceding stores against any load that may follow, but lwsync
  376. // doesn't guarantee that.
  377. _sync();
  378. return *ptr;
  379. }
  380. #endif
  381. } // namespace base::subtle
  382. } // namespace base
  383. #endif // BASE_ATOMICOPS_INTERNALS_LINUXPPC_H_