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_ppc.hpp
12 *
13 * This header contains implementation of the \c operations template.
14 */
15
16 #ifndef BOOST_ATOMIC_DETAIL_OPS_GCC_PPC_HPP_INCLUDED_
17 #define BOOST_ATOMIC_DETAIL_OPS_GCC_PPC_HPP_INCLUDED_
18
19 #include <cstddef>
20 #include <boost/memory_order.hpp>
21 #include <boost/atomic/detail/config.hpp>
22 #include <boost/atomic/detail/storage_type.hpp>
23 #include <boost/atomic/detail/operations_fwd.hpp>
24 #include <boost/atomic/detail/ops_gcc_ppc_common.hpp>
25 #include <boost/atomic/capabilities.hpp>
26
27 #ifdef BOOST_HAS_PRAGMA_ONCE
28 #pragma once
29 #endif
30
31 namespace boost {
32 namespace atomics {
33 namespace detail {
34
35 // The implementation below uses information from this document:
36 // http://www.rdrop.com/users/paulmck/scalability/paper/N2745r.2010.02.19a.html
37
38 /*
39 Refer to: Motorola: "Programming Environments Manual for 32-Bit
40 Implementations of the PowerPC Architecture", Appendix E:
41 "Synchronization Programming Examples" for an explanation of what is
42 going on here (can be found on the web at various places by the
43 name "MPCFPE32B.pdf", Google is your friend...)
44
45 Most of the atomic operations map to instructions in a relatively
46 straight-forward fashion, but "load"s may at first glance appear
47 a bit strange as they map to:
48
49 lwz %rX, addr
50 cmpw %rX, %rX
51 bne- 1f
52 1:
53
54 That is, the CPU is forced to perform a branch that "formally" depends
55 on the value retrieved from memory. This scheme has an overhead of
56 about 1-2 clock cycles per load, but it allows to map "acquire" to
57 the "isync" instruction instead of "sync" uniformly and for all type
58 of atomic operations. Since "isync" has a cost of about 15 clock
59 cycles, while "sync" hast a cost of about 50 clock cycles, the small
60 penalty to atomic loads more than compensates for this.
61
62 Byte- and halfword-sized atomic values are implemented in two ways.
63 When 8 and 16-bit instructions are available (in Power8 and later),
64 they are used. Otherwise operations are realized by encoding the
65 value to be represented into a word, performing sign/zero extension
66 as appropriate. This means that after add/sub operations the value
67 needs fixing up to accurately preserve the wrap-around semantic of
68 the smaller type. (Nothing special needs to be done for the bit-wise
69 and the "exchange type" operators as the compiler already sees to
70 it that values carried in registers are extended appropriately and
71 everything falls into place naturally).
72
73 The register constraint "b" instructs gcc to use any register
74 except r0; this is sometimes required because the encoding for
75 r0 is used to signify "constant zero" in a number of instructions,
76 making r0 unusable in this place. For simplicity this constraint
77 is used everywhere since I am to lazy to look this up on a
78 per-instruction basis, and ppc has enough registers for this not
79 to pose a problem.
80 */
81
82 template< bool Signed >
83 struct operations< 4u, Signed > :
84 public gcc_ppc_operations_base
85 {
86 typedef typename make_storage_type< 4u >::type storage_type;
87 typedef typename make_storage_type< 4u >::aligned aligned_storage_type;
88
89 static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 4u;
90 static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed;
91
storeboost::atomics::detail::operations92 static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
93 {
94 fence_before(order);
95 __asm__ __volatile__
96 (
97 "stw %1, %0\n\t"
98 : "+m" (storage)
99 : "r" (v)
100 );
101 }
102
loadboost::atomics::detail::operations103 static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT
104 {
105 storage_type v;
106 if (order == memory_order_seq_cst)
107 __asm__ __volatile__ ("sync" ::: "memory");
108 if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u)
109 {
110 __asm__ __volatile__
111 (
112 "lwz %0, %1\n\t"
113 "cmpw %0, %0\n\t"
114 "bne- 1f\n\t"
115 "1:\n\t"
116 "isync\n\t"
117 : "=&r" (v)
118 : "m" (storage)
119 : "cr0", "memory"
120 );
121 }
122 else
123 {
124 __asm__ __volatile__
125 (
126 "lwz %0, %1\n\t"
127 : "=&r" (v)
128 : "m" (storage)
129 );
130 }
131 return v;
132 }
133
exchangeboost::atomics::detail::operations134 static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
135 {
136 storage_type original;
137 fence_before(order);
138 __asm__ __volatile__
139 (
140 "1:\n\t"
141 "lwarx %0,%y1\n\t"
142 "stwcx. %2,%y1\n\t"
143 "bne- 1b\n\t"
144 : "=&b" (original), "+Z" (storage)
145 : "b" (v)
146 : "cr0"
147 );
148 fence_after(order);
149 return original;
150 }
151
compare_exchange_weakboost::atomics::detail::operations152 static BOOST_FORCEINLINE bool compare_exchange_weak(
153 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT
154 {
155 int success;
156 fence_before(success_order);
157 __asm__ __volatile__
158 (
159 "li %1, 0\n\t"
160 "lwarx %0,%y2\n\t"
161 "cmpw %0, %3\n\t"
162 "bne- 1f\n\t"
163 "stwcx. %4,%y2\n\t"
164 "bne- 1f\n\t"
165 "li %1, 1\n\t"
166 "1:\n\t"
167 : "=&b" (expected), "=&b" (success), "+Z" (storage)
168 : "b" (expected), "b" (desired)
169 : "cr0"
170 );
171 if (success)
172 fence_after(success_order);
173 else
174 fence_after(failure_order);
175 return !!success;
176 }
177
compare_exchange_strongboost::atomics::detail::operations178 static BOOST_FORCEINLINE bool compare_exchange_strong(
179 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT
180 {
181 int success;
182 fence_before(success_order);
183 __asm__ __volatile__
184 (
185 "li %1, 0\n\t"
186 "0: lwarx %0,%y2\n\t"
187 "cmpw %0, %3\n\t"
188 "bne- 1f\n\t"
189 "stwcx. %4,%y2\n\t"
190 "bne- 0b\n\t"
191 "li %1, 1\n\t"
192 "1:\n\t"
193 : "=&b" (expected), "=&b" (success), "+Z" (storage)
194 : "b" (expected), "b" (desired)
195 : "cr0"
196 );
197 if (success)
198 fence_after(success_order);
199 else
200 fence_after(failure_order);
201 return !!success;
202 }
203
fetch_addboost::atomics::detail::operations204 static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
205 {
206 storage_type original, result;
207 fence_before(order);
208 __asm__ __volatile__
209 (
210 "1:\n\t"
211 "lwarx %0,%y2\n\t"
212 "add %1,%0,%3\n\t"
213 "stwcx. %1,%y2\n\t"
214 "bne- 1b\n\t"
215 : "=&b" (original), "=&b" (result), "+Z" (storage)
216 : "b" (v)
217 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
218 );
219 fence_after(order);
220 return original;
221 }
222
fetch_subboost::atomics::detail::operations223 static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
224 {
225 storage_type original, result;
226 fence_before(order);
227 __asm__ __volatile__
228 (
229 "1:\n\t"
230 "lwarx %0,%y2\n\t"
231 "sub %1,%0,%3\n\t"
232 "stwcx. %1,%y2\n\t"
233 "bne- 1b\n\t"
234 : "=&b" (original), "=&b" (result), "+Z" (storage)
235 : "b" (v)
236 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
237 );
238 fence_after(order);
239 return original;
240 }
241
fetch_andboost::atomics::detail::operations242 static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
243 {
244 storage_type original, result;
245 fence_before(order);
246 __asm__ __volatile__
247 (
248 "1:\n\t"
249 "lwarx %0,%y2\n\t"
250 "and %1,%0,%3\n\t"
251 "stwcx. %1,%y2\n\t"
252 "bne- 1b\n\t"
253 : "=&b" (original), "=&b" (result), "+Z" (storage)
254 : "b" (v)
255 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
256 );
257 fence_after(order);
258 return original;
259 }
260
fetch_orboost::atomics::detail::operations261 static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
262 {
263 storage_type original, result;
264 fence_before(order);
265 __asm__ __volatile__
266 (
267 "1:\n\t"
268 "lwarx %0,%y2\n\t"
269 "or %1,%0,%3\n\t"
270 "stwcx. %1,%y2\n\t"
271 "bne- 1b\n\t"
272 : "=&b" (original), "=&b" (result), "+Z" (storage)
273 : "b" (v)
274 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
275 );
276 fence_after(order);
277 return original;
278 }
279
fetch_xorboost::atomics::detail::operations280 static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
281 {
282 storage_type original, result;
283 fence_before(order);
284 __asm__ __volatile__
285 (
286 "1:\n\t"
287 "lwarx %0,%y2\n\t"
288 "xor %1,%0,%3\n\t"
289 "stwcx. %1,%y2\n\t"
290 "bne- 1b\n\t"
291 : "=&b" (original), "=&b" (result), "+Z" (storage)
292 : "b" (v)
293 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
294 );
295 fence_after(order);
296 return original;
297 }
298
test_and_setboost::atomics::detail::operations299 static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
300 {
301 return !!exchange(storage, (storage_type)1, order);
302 }
303
clearboost::atomics::detail::operations304 static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
305 {
306 store(storage, 0, order);
307 }
308 };
309
310 #if defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LBARX_STBCX)
311
312 template< bool Signed >
313 struct operations< 1u, Signed > :
314 public gcc_ppc_operations_base
315 {
316 typedef typename make_storage_type< 1u >::type storage_type;
317 typedef typename make_storage_type< 1u >::aligned aligned_storage_type;
318
319 static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 1u;
320 static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed;
321
storeboost::atomics::detail::operations322 static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
323 {
324 fence_before(order);
325 __asm__ __volatile__
326 (
327 "stb %1, %0\n\t"
328 : "+m" (storage)
329 : "r" (v)
330 );
331 }
332
loadboost::atomics::detail::operations333 static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT
334 {
335 storage_type v;
336 if (order == memory_order_seq_cst)
337 __asm__ __volatile__ ("sync" ::: "memory");
338 if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u)
339 {
340 __asm__ __volatile__
341 (
342 "lbz %0, %1\n\t"
343 "cmpw %0, %0\n\t"
344 "bne- 1f\n\t"
345 "1:\n\t"
346 "isync\n\t"
347 : "=&r" (v)
348 : "m" (storage)
349 : "cr0", "memory"
350 );
351 }
352 else
353 {
354 __asm__ __volatile__
355 (
356 "lbz %0, %1\n\t"
357 : "=&r" (v)
358 : "m" (storage)
359 );
360 }
361 return v;
362 }
363
exchangeboost::atomics::detail::operations364 static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
365 {
366 storage_type original;
367 fence_before(order);
368 __asm__ __volatile__
369 (
370 "1:\n\t"
371 "lbarx %0,%y1\n\t"
372 "stbcx. %2,%y1\n\t"
373 "bne- 1b\n\t"
374 : "=&b" (original), "+Z" (storage)
375 : "b" (v)
376 : "cr0"
377 );
378 fence_after(order);
379 return original;
380 }
381
compare_exchange_weakboost::atomics::detail::operations382 static BOOST_FORCEINLINE bool compare_exchange_weak(
383 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT
384 {
385 int success;
386 fence_before(success_order);
387 __asm__ __volatile__
388 (
389 "li %1, 0\n\t"
390 "lbarx %0,%y2\n\t"
391 "cmpw %0, %3\n\t"
392 "bne- 1f\n\t"
393 "stbcx. %4,%y2\n\t"
394 "bne- 1f\n\t"
395 "li %1, 1\n\t"
396 "1:\n\t"
397 : "=&b" (expected), "=&b" (success), "+Z" (storage)
398 : "b" (expected), "b" (desired)
399 : "cr0"
400 );
401 if (success)
402 fence_after(success_order);
403 else
404 fence_after(failure_order);
405 return !!success;
406 }
407
compare_exchange_strongboost::atomics::detail::operations408 static BOOST_FORCEINLINE bool compare_exchange_strong(
409 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT
410 {
411 int success;
412 fence_before(success_order);
413 __asm__ __volatile__
414 (
415 "li %1, 0\n\t"
416 "0: lbarx %0,%y2\n\t"
417 "cmpw %0, %3\n\t"
418 "bne- 1f\n\t"
419 "stbcx. %4,%y2\n\t"
420 "bne- 0b\n\t"
421 "li %1, 1\n\t"
422 "1:\n\t"
423 : "=&b" (expected), "=&b" (success), "+Z" (storage)
424 : "b" (expected), "b" (desired)
425 : "cr0"
426 );
427 if (success)
428 fence_after(success_order);
429 else
430 fence_after(failure_order);
431 return !!success;
432 }
433
fetch_addboost::atomics::detail::operations434 static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
435 {
436 storage_type original, result;
437 fence_before(order);
438 __asm__ __volatile__
439 (
440 "1:\n\t"
441 "lbarx %0,%y2\n\t"
442 "add %1,%0,%3\n\t"
443 "stbcx. %1,%y2\n\t"
444 "bne- 1b\n\t"
445 : "=&b" (original), "=&b" (result), "+Z" (storage)
446 : "b" (v)
447 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
448 );
449 fence_after(order);
450 return original;
451 }
452
fetch_subboost::atomics::detail::operations453 static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
454 {
455 storage_type original, result;
456 fence_before(order);
457 __asm__ __volatile__
458 (
459 "1:\n\t"
460 "lbarx %0,%y2\n\t"
461 "sub %1,%0,%3\n\t"
462 "stbcx. %1,%y2\n\t"
463 "bne- 1b\n\t"
464 : "=&b" (original), "=&b" (result), "+Z" (storage)
465 : "b" (v)
466 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
467 );
468 fence_after(order);
469 return original;
470 }
471
fetch_andboost::atomics::detail::operations472 static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
473 {
474 storage_type original, result;
475 fence_before(order);
476 __asm__ __volatile__
477 (
478 "1:\n\t"
479 "lbarx %0,%y2\n\t"
480 "and %1,%0,%3\n\t"
481 "stbcx. %1,%y2\n\t"
482 "bne- 1b\n\t"
483 : "=&b" (original), "=&b" (result), "+Z" (storage)
484 : "b" (v)
485 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
486 );
487 fence_after(order);
488 return original;
489 }
490
fetch_orboost::atomics::detail::operations491 static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
492 {
493 storage_type original, result;
494 fence_before(order);
495 __asm__ __volatile__
496 (
497 "1:\n\t"
498 "lbarx %0,%y2\n\t"
499 "or %1,%0,%3\n\t"
500 "stbcx. %1,%y2\n\t"
501 "bne- 1b\n\t"
502 : "=&b" (original), "=&b" (result), "+Z" (storage)
503 : "b" (v)
504 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
505 );
506 fence_after(order);
507 return original;
508 }
509
fetch_xorboost::atomics::detail::operations510 static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
511 {
512 storage_type original, result;
513 fence_before(order);
514 __asm__ __volatile__
515 (
516 "1:\n\t"
517 "lbarx %0,%y2\n\t"
518 "xor %1,%0,%3\n\t"
519 "stbcx. %1,%y2\n\t"
520 "bne- 1b\n\t"
521 : "=&b" (original), "=&b" (result), "+Z" (storage)
522 : "b" (v)
523 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
524 );
525 fence_after(order);
526 return original;
527 }
528
test_and_setboost::atomics::detail::operations529 static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
530 {
531 return !!exchange(storage, (storage_type)1, order);
532 }
533
clearboost::atomics::detail::operations534 static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
535 {
536 store(storage, 0, order);
537 }
538 };
539
540 #else // defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LBARX_STBCX)
541
542 template< >
543 struct operations< 1u, false > :
544 public operations< 4u, false >
545 {
546 typedef operations< 4u, false > base_type;
547 typedef base_type::storage_type storage_type;
548
fetch_addboost::atomics::detail::operations549 static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
550 {
551 storage_type original, result;
552 fence_before(order);
553 __asm__ __volatile__
554 (
555 "1:\n\t"
556 "lwarx %0,%y2\n\t"
557 "add %1,%0,%3\n\t"
558 "rlwinm %1, %1, 0, 0xff\n\t"
559 "stwcx. %1,%y2\n\t"
560 "bne- 1b\n\t"
561 : "=&b" (original), "=&b" (result), "+Z" (storage)
562 : "b" (v)
563 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
564 );
565 fence_after(order);
566 return original;
567 }
568
fetch_subboost::atomics::detail::operations569 static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
570 {
571 storage_type original, result;
572 fence_before(order);
573 __asm__ __volatile__
574 (
575 "1:\n\t"
576 "lwarx %0,%y2\n\t"
577 "sub %1,%0,%3\n\t"
578 "rlwinm %1, %1, 0, 0xff\n\t"
579 "stwcx. %1,%y2\n\t"
580 "bne- 1b\n\t"
581 : "=&b" (original), "=&b" (result), "+Z" (storage)
582 : "b" (v)
583 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
584 );
585 fence_after(order);
586 return original;
587 }
588 };
589
590 template< >
591 struct operations< 1u, true > :
592 public operations< 4u, true >
593 {
594 typedef operations< 4u, true > base_type;
595 typedef base_type::storage_type storage_type;
596
fetch_addboost::atomics::detail::operations597 static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
598 {
599 storage_type original, result;
600 fence_before(order);
601 __asm__ __volatile__
602 (
603 "1:\n\t"
604 "lwarx %0,%y2\n\t"
605 "add %1,%0,%3\n\t"
606 "extsb %1, %1\n\t"
607 "stwcx. %1,%y2\n\t"
608 "bne- 1b\n\t"
609 : "=&b" (original), "=&b" (result), "+Z" (storage)
610 : "b" (v)
611 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
612 );
613 fence_after(order);
614 return original;
615 }
616
fetch_subboost::atomics::detail::operations617 static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
618 {
619 storage_type original, result;
620 fence_before(order);
621 __asm__ __volatile__
622 (
623 "1:\n\t"
624 "lwarx %0,%y2\n\t"
625 "sub %1,%0,%3\n\t"
626 "extsb %1, %1\n\t"
627 "stwcx. %1,%y2\n\t"
628 "bne- 1b\n\t"
629 : "=&b" (original), "=&b" (result), "+Z" (storage)
630 : "b" (v)
631 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
632 );
633 fence_after(order);
634 return original;
635 }
636 };
637
638 #endif // defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LBARX_STBCX)
639
640 #if defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LHARX_STHCX)
641
642 template< bool Signed >
643 struct operations< 2u, Signed > :
644 public gcc_ppc_operations_base
645 {
646 typedef typename make_storage_type< 2u >::type storage_type;
647 typedef typename make_storage_type< 2u >::aligned aligned_storage_type;
648
649 static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 2u;
650 static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed;
651
storeboost::atomics::detail::operations652 static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
653 {
654 fence_before(order);
655 __asm__ __volatile__
656 (
657 "sth %1, %0\n\t"
658 : "+m" (storage)
659 : "r" (v)
660 );
661 }
662
loadboost::atomics::detail::operations663 static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT
664 {
665 storage_type v;
666 if (order == memory_order_seq_cst)
667 __asm__ __volatile__ ("sync" ::: "memory");
668 if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u)
669 {
670 __asm__ __volatile__
671 (
672 "lhz %0, %1\n\t"
673 "cmpw %0, %0\n\t"
674 "bne- 1f\n\t"
675 "1:\n\t"
676 "isync\n\t"
677 : "=&r" (v)
678 : "m" (storage)
679 : "cr0", "memory"
680 );
681 }
682 else
683 {
684 __asm__ __volatile__
685 (
686 "lhz %0, %1\n\t"
687 : "=&r" (v)
688 : "m" (storage)
689 );
690 }
691 return v;
692 }
693
exchangeboost::atomics::detail::operations694 static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
695 {
696 storage_type original;
697 fence_before(order);
698 __asm__ __volatile__
699 (
700 "1:\n\t"
701 "lharx %0,%y1\n\t"
702 "sthcx. %2,%y1\n\t"
703 "bne- 1b\n\t"
704 : "=&b" (original), "+Z" (storage)
705 : "b" (v)
706 : "cr0"
707 );
708 fence_after(order);
709 return original;
710 }
711
compare_exchange_weakboost::atomics::detail::operations712 static BOOST_FORCEINLINE bool compare_exchange_weak(
713 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT
714 {
715 int success;
716 fence_before(success_order);
717 __asm__ __volatile__
718 (
719 "li %1, 0\n\t"
720 "lharx %0,%y2\n\t"
721 "cmpw %0, %3\n\t"
722 "bne- 1f\n\t"
723 "sthcx. %4,%y2\n\t"
724 "bne- 1f\n\t"
725 "li %1, 1\n\t"
726 "1:\n\t"
727 : "=&b" (expected), "=&b" (success), "+Z" (storage)
728 : "b" (expected), "b" (desired)
729 : "cr0"
730 );
731 if (success)
732 fence_after(success_order);
733 else
734 fence_after(failure_order);
735 return !!success;
736 }
737
compare_exchange_strongboost::atomics::detail::operations738 static BOOST_FORCEINLINE bool compare_exchange_strong(
739 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT
740 {
741 int success;
742 fence_before(success_order);
743 __asm__ __volatile__
744 (
745 "li %1, 0\n\t"
746 "0: lharx %0,%y2\n\t"
747 "cmpw %0, %3\n\t"
748 "bne- 1f\n\t"
749 "sthcx. %4,%y2\n\t"
750 "bne- 0b\n\t"
751 "li %1, 1\n\t"
752 "1:\n\t"
753 : "=&b" (expected), "=&b" (success), "+Z" (storage)
754 : "b" (expected), "b" (desired)
755 : "cr0"
756 );
757 if (success)
758 fence_after(success_order);
759 else
760 fence_after(failure_order);
761 return !!success;
762 }
763
fetch_addboost::atomics::detail::operations764 static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
765 {
766 storage_type original, result;
767 fence_before(order);
768 __asm__ __volatile__
769 (
770 "1:\n\t"
771 "lharx %0,%y2\n\t"
772 "add %1,%0,%3\n\t"
773 "sthcx. %1,%y2\n\t"
774 "bne- 1b\n\t"
775 : "=&b" (original), "=&b" (result), "+Z" (storage)
776 : "b" (v)
777 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
778 );
779 fence_after(order);
780 return original;
781 }
782
fetch_subboost::atomics::detail::operations783 static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
784 {
785 storage_type original, result;
786 fence_before(order);
787 __asm__ __volatile__
788 (
789 "1:\n\t"
790 "lharx %0,%y2\n\t"
791 "sub %1,%0,%3\n\t"
792 "sthcx. %1,%y2\n\t"
793 "bne- 1b\n\t"
794 : "=&b" (original), "=&b" (result), "+Z" (storage)
795 : "b" (v)
796 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
797 );
798 fence_after(order);
799 return original;
800 }
801
fetch_andboost::atomics::detail::operations802 static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
803 {
804 storage_type original, result;
805 fence_before(order);
806 __asm__ __volatile__
807 (
808 "1:\n\t"
809 "lharx %0,%y2\n\t"
810 "and %1,%0,%3\n\t"
811 "sthcx. %1,%y2\n\t"
812 "bne- 1b\n\t"
813 : "=&b" (original), "=&b" (result), "+Z" (storage)
814 : "b" (v)
815 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
816 );
817 fence_after(order);
818 return original;
819 }
820
fetch_orboost::atomics::detail::operations821 static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
822 {
823 storage_type original, result;
824 fence_before(order);
825 __asm__ __volatile__
826 (
827 "1:\n\t"
828 "lharx %0,%y2\n\t"
829 "or %1,%0,%3\n\t"
830 "sthcx. %1,%y2\n\t"
831 "bne- 1b\n\t"
832 : "=&b" (original), "=&b" (result), "+Z" (storage)
833 : "b" (v)
834 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
835 );
836 fence_after(order);
837 return original;
838 }
839
fetch_xorboost::atomics::detail::operations840 static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
841 {
842 storage_type original, result;
843 fence_before(order);
844 __asm__ __volatile__
845 (
846 "1:\n\t"
847 "lharx %0,%y2\n\t"
848 "xor %1,%0,%3\n\t"
849 "sthcx. %1,%y2\n\t"
850 "bne- 1b\n\t"
851 : "=&b" (original), "=&b" (result), "+Z" (storage)
852 : "b" (v)
853 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
854 );
855 fence_after(order);
856 return original;
857 }
858
test_and_setboost::atomics::detail::operations859 static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
860 {
861 return !!exchange(storage, (storage_type)1, order);
862 }
863
clearboost::atomics::detail::operations864 static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
865 {
866 store(storage, 0, order);
867 }
868 };
869
870 #else // defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LHARX_STHCX)
871
872 template< >
873 struct operations< 2u, false > :
874 public operations< 4u, false >
875 {
876 typedef operations< 4u, false > base_type;
877 typedef base_type::storage_type storage_type;
878
fetch_addboost::atomics::detail::operations879 static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
880 {
881 storage_type original, result;
882 fence_before(order);
883 __asm__ __volatile__
884 (
885 "1:\n\t"
886 "lwarx %0,%y2\n\t"
887 "add %1,%0,%3\n\t"
888 "rlwinm %1, %1, 0, 0xffff\n\t"
889 "stwcx. %1,%y2\n\t"
890 "bne- 1b\n\t"
891 : "=&b" (original), "=&b" (result), "+Z" (storage)
892 : "b" (v)
893 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
894 );
895 fence_after(order);
896 return original;
897 }
898
fetch_subboost::atomics::detail::operations899 static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
900 {
901 storage_type original, result;
902 fence_before(order);
903 __asm__ __volatile__
904 (
905 "1:\n\t"
906 "lwarx %0,%y2\n\t"
907 "sub %1,%0,%3\n\t"
908 "rlwinm %1, %1, 0, 0xffff\n\t"
909 "stwcx. %1,%y2\n\t"
910 "bne- 1b\n\t"
911 : "=&b" (original), "=&b" (result), "+Z" (storage)
912 : "b" (v)
913 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
914 );
915 fence_after(order);
916 return original;
917 }
918 };
919
920 template< >
921 struct operations< 2u, true > :
922 public operations< 4u, true >
923 {
924 typedef operations< 4u, true > base_type;
925 typedef base_type::storage_type storage_type;
926
fetch_addboost::atomics::detail::operations927 static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
928 {
929 storage_type original, result;
930 fence_before(order);
931 __asm__ __volatile__
932 (
933 "1:\n\t"
934 "lwarx %0,%y2\n\t"
935 "add %1,%0,%3\n\t"
936 "extsh %1, %1\n\t"
937 "stwcx. %1,%y2\n\t"
938 "bne- 1b\n\t"
939 : "=&b" (original), "=&b" (result), "+Z" (storage)
940 : "b" (v)
941 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
942 );
943 fence_after(order);
944 return original;
945 }
946
fetch_subboost::atomics::detail::operations947 static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
948 {
949 storage_type original, result;
950 fence_before(order);
951 __asm__ __volatile__
952 (
953 "1:\n\t"
954 "lwarx %0,%y2\n\t"
955 "sub %1,%0,%3\n\t"
956 "extsh %1, %1\n\t"
957 "stwcx. %1,%y2\n\t"
958 "bne- 1b\n\t"
959 : "=&b" (original), "=&b" (result), "+Z" (storage)
960 : "b" (v)
961 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
962 );
963 fence_after(order);
964 return original;
965 }
966 };
967
968 #endif // defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LHARX_STHCX)
969
970 #if defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LDARX_STDCX)
971
972 template< bool Signed >
973 struct operations< 8u, Signed > :
974 public gcc_ppc_operations_base
975 {
976 typedef typename make_storage_type< 8u >::type storage_type;
977 typedef typename make_storage_type< 8u >::aligned aligned_storage_type;
978
979 static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 8u;
980 static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed;
981
storeboost::atomics::detail::operations982 static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
983 {
984 fence_before(order);
985 __asm__ __volatile__
986 (
987 "std %1, %0\n\t"
988 : "+m" (storage)
989 : "r" (v)
990 );
991 }
992
loadboost::atomics::detail::operations993 static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT
994 {
995 storage_type v;
996 if (order == memory_order_seq_cst)
997 __asm__ __volatile__ ("sync" ::: "memory");
998 if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u)
999 {
1000 __asm__ __volatile__
1001 (
1002 "ld %0, %1\n\t"
1003 "cmpd %0, %0\n\t"
1004 "bne- 1f\n\t"
1005 "1:\n\t"
1006 "isync\n\t"
1007 : "=&b" (v)
1008 : "m" (storage)
1009 : "cr0", "memory"
1010 );
1011 }
1012 else
1013 {
1014 __asm__ __volatile__
1015 (
1016 "ld %0, %1\n\t"
1017 : "=&b" (v)
1018 : "m" (storage)
1019 );
1020 }
1021 return v;
1022 }
1023
exchangeboost::atomics::detail::operations1024 static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
1025 {
1026 storage_type original;
1027 fence_before(order);
1028 __asm__ __volatile__
1029 (
1030 "1:\n\t"
1031 "ldarx %0,%y1\n\t"
1032 "stdcx. %2,%y1\n\t"
1033 "bne- 1b\n\t"
1034 : "=&b" (original), "+Z" (storage)
1035 : "b" (v)
1036 : "cr0"
1037 );
1038 fence_after(order);
1039 return original;
1040 }
1041
compare_exchange_weakboost::atomics::detail::operations1042 static BOOST_FORCEINLINE bool compare_exchange_weak(
1043 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT
1044 {
1045 int success;
1046 fence_before(success_order);
1047 __asm__ __volatile__
1048 (
1049 "li %1, 0\n\t"
1050 "ldarx %0,%y2\n\t"
1051 "cmpd %0, %3\n\t"
1052 "bne- 1f\n\t"
1053 "stdcx. %4,%y2\n\t"
1054 "bne- 1f\n\t"
1055 "li %1, 1\n\t"
1056 "1:"
1057 : "=&b" (expected), "=&b" (success), "+Z" (storage)
1058 : "b" (expected), "b" (desired)
1059 : "cr0"
1060 );
1061 if (success)
1062 fence_after(success_order);
1063 else
1064 fence_after(failure_order);
1065 return !!success;
1066 }
1067
compare_exchange_strongboost::atomics::detail::operations1068 static BOOST_FORCEINLINE bool compare_exchange_strong(
1069 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT
1070 {
1071 int success;
1072 fence_before(success_order);
1073 __asm__ __volatile__
1074 (
1075 "li %1, 0\n\t"
1076 "0: ldarx %0,%y2\n\t"
1077 "cmpd %0, %3\n\t"
1078 "bne- 1f\n\t"
1079 "stdcx. %4,%y2\n\t"
1080 "bne- 0b\n\t"
1081 "li %1, 1\n\t"
1082 "1:\n\t"
1083 : "=&b" (expected), "=&b" (success), "+Z" (storage)
1084 : "b" (expected), "b" (desired)
1085 : "cr0"
1086 );
1087 if (success)
1088 fence_after(success_order);
1089 else
1090 fence_after(failure_order);
1091 return !!success;
1092 }
1093
fetch_addboost::atomics::detail::operations1094 static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
1095 {
1096 storage_type original, result;
1097 fence_before(order);
1098 __asm__ __volatile__
1099 (
1100 "1:\n\t"
1101 "ldarx %0,%y2\n\t"
1102 "add %1,%0,%3\n\t"
1103 "stdcx. %1,%y2\n\t"
1104 "bne- 1b\n\t"
1105 : "=&b" (original), "=&b" (result), "+Z" (storage)
1106 : "b" (v)
1107 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
1108 );
1109 fence_after(order);
1110 return original;
1111 }
1112
fetch_subboost::atomics::detail::operations1113 static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
1114 {
1115 storage_type original, result;
1116 fence_before(order);
1117 __asm__ __volatile__
1118 (
1119 "1:\n\t"
1120 "ldarx %0,%y2\n\t"
1121 "sub %1,%0,%3\n\t"
1122 "stdcx. %1,%y2\n\t"
1123 "bne- 1b\n\t"
1124 : "=&b" (original), "=&b" (result), "+Z" (storage)
1125 : "b" (v)
1126 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
1127 );
1128 fence_after(order);
1129 return original;
1130 }
1131
fetch_andboost::atomics::detail::operations1132 static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
1133 {
1134 storage_type original, result;
1135 fence_before(order);
1136 __asm__ __volatile__
1137 (
1138 "1:\n\t"
1139 "ldarx %0,%y2\n\t"
1140 "and %1,%0,%3\n\t"
1141 "stdcx. %1,%y2\n\t"
1142 "bne- 1b\n\t"
1143 : "=&b" (original), "=&b" (result), "+Z" (storage)
1144 : "b" (v)
1145 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
1146 );
1147 fence_after(order);
1148 return original;
1149 }
1150
fetch_orboost::atomics::detail::operations1151 static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
1152 {
1153 storage_type original, result;
1154 fence_before(order);
1155 __asm__ __volatile__
1156 (
1157 "1:\n\t"
1158 "ldarx %0,%y2\n\t"
1159 "or %1,%0,%3\n\t"
1160 "stdcx. %1,%y2\n\t"
1161 "bne- 1b\n\t"
1162 : "=&b" (original), "=&b" (result), "+Z" (storage)
1163 : "b" (v)
1164 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
1165 );
1166 fence_after(order);
1167 return original;
1168 }
1169
fetch_xorboost::atomics::detail::operations1170 static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
1171 {
1172 storage_type original, result;
1173 fence_before(order);
1174 __asm__ __volatile__
1175 (
1176 "1:\n\t"
1177 "ldarx %0,%y2\n\t"
1178 "xor %1,%0,%3\n\t"
1179 "stdcx. %1,%y2\n\t"
1180 "bne- 1b\n\t"
1181 : "=&b" (original), "=&b" (result), "+Z" (storage)
1182 : "b" (v)
1183 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
1184 );
1185 fence_after(order);
1186 return original;
1187 }
1188
test_and_setboost::atomics::detail::operations1189 static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
1190 {
1191 return !!exchange(storage, (storage_type)1, order);
1192 }
1193
clearboost::atomics::detail::operations1194 static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
1195 {
1196 store(storage, 0, order);
1197 }
1198 };
1199
1200 #endif // defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LDARX_STDCX)
1201
1202
thread_fence(memory_order order)1203 BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT
1204 {
1205 if (order != memory_order_relaxed)
1206 {
1207 #if defined(__powerpc64__) || defined(__PPC64__)
1208 if (order != memory_order_seq_cst)
1209 __asm__ __volatile__ ("lwsync" ::: "memory");
1210 else
1211 __asm__ __volatile__ ("sync" ::: "memory");
1212 #else
1213 __asm__ __volatile__ ("sync" ::: "memory");
1214 #endif
1215 }
1216 }
1217
signal_fence(memory_order order)1218 BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT
1219 {
1220 if (order != memory_order_relaxed)
1221 #if defined(__ibmxl__) || defined(__IBMCPP__)
1222 __fence();
1223 #else
1224 __asm__ __volatile__ ("" ::: "memory");
1225 #endif
1226 }
1227
1228 } // namespace detail
1229 } // namespace atomics
1230 } // namespace boost
1231
1232 #endif // BOOST_ATOMIC_DETAIL_OPS_GCC_PPC_HPP_INCLUDED_
1233