Chris@102
|
1 /*
|
Chris@102
|
2 * Distributed under the Boost Software License, Version 1.0.
|
Chris@102
|
3 * (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@102
|
4 * http://www.boost.org/LICENSE_1_0.txt)
|
Chris@102
|
5 *
|
Chris@102
|
6 * Copyright (c) 2009 Helge Bahmann
|
Chris@102
|
7 * Copyright (c) 2013 Tim Blechmann
|
Chris@102
|
8 * Copyright (c) 2014 Andrey Semashev
|
Chris@102
|
9 */
|
Chris@102
|
10 /*!
|
Chris@102
|
11 * \file atomic/detail/ops_gcc_ppc.hpp
|
Chris@102
|
12 *
|
Chris@102
|
13 * This header contains implementation of the \c operations template.
|
Chris@102
|
14 */
|
Chris@102
|
15
|
Chris@102
|
16 #ifndef BOOST_ATOMIC_DETAIL_OPS_GCC_PPC_HPP_INCLUDED_
|
Chris@102
|
17 #define BOOST_ATOMIC_DETAIL_OPS_GCC_PPC_HPP_INCLUDED_
|
Chris@102
|
18
|
Chris@102
|
19 #include <boost/memory_order.hpp>
|
Chris@102
|
20 #include <boost/atomic/detail/config.hpp>
|
Chris@102
|
21 #include <boost/atomic/detail/storage_type.hpp>
|
Chris@102
|
22 #include <boost/atomic/detail/operations_fwd.hpp>
|
Chris@102
|
23 #include <boost/atomic/capabilities.hpp>
|
Chris@102
|
24
|
Chris@102
|
25 #ifdef BOOST_HAS_PRAGMA_ONCE
|
Chris@102
|
26 #pragma once
|
Chris@102
|
27 #endif
|
Chris@102
|
28
|
Chris@102
|
29 namespace boost {
|
Chris@102
|
30 namespace atomics {
|
Chris@102
|
31 namespace detail {
|
Chris@102
|
32
|
Chris@102
|
33 /*
|
Chris@102
|
34 Refer to: Motorola: "Programming Environments Manual for 32-Bit
|
Chris@102
|
35 Implementations of the PowerPC Architecture", Appendix E:
|
Chris@102
|
36 "Synchronization Programming Examples" for an explanation of what is
|
Chris@102
|
37 going on here (can be found on the web at various places by the
|
Chris@102
|
38 name "MPCFPE32B.pdf", Google is your friend...)
|
Chris@102
|
39
|
Chris@102
|
40 Most of the atomic operations map to instructions in a relatively
|
Chris@102
|
41 straight-forward fashion, but "load"s may at first glance appear
|
Chris@102
|
42 a bit strange as they map to:
|
Chris@102
|
43
|
Chris@102
|
44 lwz %rX, addr
|
Chris@102
|
45 cmpw %rX, %rX
|
Chris@102
|
46 bne- 1f
|
Chris@102
|
47 1:
|
Chris@102
|
48
|
Chris@102
|
49 That is, the CPU is forced to perform a branch that "formally" depends
|
Chris@102
|
50 on the value retrieved from memory. This scheme has an overhead of
|
Chris@102
|
51 about 1-2 clock cycles per load, but it allows to map "acquire" to
|
Chris@102
|
52 the "isync" instruction instead of "sync" uniformly and for all type
|
Chris@102
|
53 of atomic operations. Since "isync" has a cost of about 15 clock
|
Chris@102
|
54 cycles, while "sync" hast a cost of about 50 clock cycles, the small
|
Chris@102
|
55 penalty to atomic loads more than compensates for this.
|
Chris@102
|
56
|
Chris@102
|
57 Byte- and halfword-sized atomic values are realized by encoding the
|
Chris@102
|
58 value to be represented into a word, performing sign/zero extension
|
Chris@102
|
59 as appropriate. This means that after add/sub operations the value
|
Chris@102
|
60 needs fixing up to accurately preserve the wrap-around semantic of
|
Chris@102
|
61 the smaller type. (Nothing special needs to be done for the bit-wise
|
Chris@102
|
62 and the "exchange type" operators as the compiler already sees to
|
Chris@102
|
63 it that values carried in registers are extended appropriately and
|
Chris@102
|
64 everything falls into place naturally).
|
Chris@102
|
65
|
Chris@102
|
66 The register constraint "b" instructs gcc to use any register
|
Chris@102
|
67 except r0; this is sometimes required because the encoding for
|
Chris@102
|
68 r0 is used to signify "constant zero" in a number of instructions,
|
Chris@102
|
69 making r0 unusable in this place. For simplicity this constraint
|
Chris@102
|
70 is used everywhere since I am to lazy to look this up on a
|
Chris@102
|
71 per-instruction basis, and ppc has enough registers for this not
|
Chris@102
|
72 to pose a problem.
|
Chris@102
|
73 */
|
Chris@102
|
74
|
Chris@102
|
75 // A note about memory_order_consume. Technically, this architecture allows to avoid
|
Chris@102
|
76 // unnecessary memory barrier after consume load since it supports data dependency ordering.
|
Chris@102
|
77 // However, some compiler optimizations may break a seemingly valid code relying on data
|
Chris@102
|
78 // dependency tracking by injecting bogus branches to aid out of order execution.
|
Chris@102
|
79 // This may happen not only in Boost.Atomic code but also in user's code, which we have no
|
Chris@102
|
80 // control of. See this thread: http://lists.boost.org/Archives/boost/2014/06/213890.php.
|
Chris@102
|
81 // For this reason we promote memory_order_consume to memory_order_acquire.
|
Chris@102
|
82
|
Chris@102
|
83 struct gcc_ppc_operations_base
|
Chris@102
|
84 {
|
Chris@102
|
85 static BOOST_FORCEINLINE void fence_before(memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
86 {
|
Chris@102
|
87 #if defined(__powerpc64__)
|
Chris@102
|
88 if (order == memory_order_seq_cst)
|
Chris@102
|
89 __asm__ __volatile__ ("sync" ::: "memory");
|
Chris@102
|
90 else if ((order & memory_order_release) != 0)
|
Chris@102
|
91 __asm__ __volatile__ ("lwsync" ::: "memory");
|
Chris@102
|
92 #else
|
Chris@102
|
93 if ((order & memory_order_release) != 0)
|
Chris@102
|
94 __asm__ __volatile__ ("sync" ::: "memory");
|
Chris@102
|
95 #endif
|
Chris@102
|
96 }
|
Chris@102
|
97
|
Chris@102
|
98 static BOOST_FORCEINLINE void fence_after(memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
99 {
|
Chris@102
|
100 if ((order & (memory_order_consume | memory_order_acquire)) != 0)
|
Chris@102
|
101 __asm__ __volatile__ ("isync" ::: "memory");
|
Chris@102
|
102 }
|
Chris@102
|
103
|
Chris@102
|
104 static BOOST_FORCEINLINE void fence_after_store(memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
105 {
|
Chris@102
|
106 if (order == memory_order_seq_cst)
|
Chris@102
|
107 __asm__ __volatile__ ("sync" ::: "memory");
|
Chris@102
|
108 }
|
Chris@102
|
109 };
|
Chris@102
|
110
|
Chris@102
|
111
|
Chris@102
|
112 template< bool Signed >
|
Chris@102
|
113 struct operations< 4u, Signed > :
|
Chris@102
|
114 public gcc_ppc_operations_base
|
Chris@102
|
115 {
|
Chris@102
|
116 typedef typename make_storage_type< 4u, Signed >::type storage_type;
|
Chris@102
|
117
|
Chris@102
|
118 static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
119 {
|
Chris@102
|
120 fence_before(order);
|
Chris@102
|
121 __asm__ __volatile__
|
Chris@102
|
122 (
|
Chris@102
|
123 "stw %1, %0\n"
|
Chris@102
|
124 : "+m" (storage)
|
Chris@102
|
125 : "r" (v)
|
Chris@102
|
126 );
|
Chris@102
|
127 fence_after_store(order);
|
Chris@102
|
128 }
|
Chris@102
|
129
|
Chris@102
|
130 static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
131 {
|
Chris@102
|
132 storage_type v;
|
Chris@102
|
133 __asm__ __volatile__
|
Chris@102
|
134 (
|
Chris@102
|
135 "lwz %0, %1\n"
|
Chris@102
|
136 "cmpw %0, %0\n"
|
Chris@102
|
137 "bne- 1f\n"
|
Chris@102
|
138 "1:\n"
|
Chris@102
|
139 : "=&r" (v)
|
Chris@102
|
140 : "m" (storage)
|
Chris@102
|
141 : "cr0"
|
Chris@102
|
142 );
|
Chris@102
|
143 fence_after(order);
|
Chris@102
|
144 return v;
|
Chris@102
|
145 }
|
Chris@102
|
146
|
Chris@102
|
147 static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
148 {
|
Chris@102
|
149 storage_type original;
|
Chris@102
|
150 fence_before(order);
|
Chris@102
|
151 __asm__ __volatile__
|
Chris@102
|
152 (
|
Chris@102
|
153 "1:\n"
|
Chris@102
|
154 "lwarx %0,%y1\n"
|
Chris@102
|
155 "stwcx. %2,%y1\n"
|
Chris@102
|
156 "bne- 1b\n"
|
Chris@102
|
157 : "=&b" (original), "+Z" (storage)
|
Chris@102
|
158 : "b" (v)
|
Chris@102
|
159 : "cr0"
|
Chris@102
|
160 );
|
Chris@102
|
161 fence_after(order);
|
Chris@102
|
162 return original;
|
Chris@102
|
163 }
|
Chris@102
|
164
|
Chris@102
|
165 static BOOST_FORCEINLINE bool compare_exchange_weak(
|
Chris@102
|
166 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT
|
Chris@102
|
167 {
|
Chris@102
|
168 int success;
|
Chris@102
|
169 fence_before(success_order);
|
Chris@102
|
170 __asm__ __volatile__
|
Chris@102
|
171 (
|
Chris@102
|
172 "li %1, 0\n"
|
Chris@102
|
173 "lwarx %0,%y2\n"
|
Chris@102
|
174 "cmpw %0, %3\n"
|
Chris@102
|
175 "bne- 1f\n"
|
Chris@102
|
176 "stwcx. %4,%y2\n"
|
Chris@102
|
177 "bne- 1f\n"
|
Chris@102
|
178 "li %1, 1\n"
|
Chris@102
|
179 "1:"
|
Chris@102
|
180 : "=&b" (expected), "=&b" (success), "+Z" (storage)
|
Chris@102
|
181 : "b" (expected), "b" (desired)
|
Chris@102
|
182 : "cr0"
|
Chris@102
|
183 );
|
Chris@102
|
184 if (success)
|
Chris@102
|
185 fence_after(success_order);
|
Chris@102
|
186 else
|
Chris@102
|
187 fence_after(failure_order);
|
Chris@102
|
188 return !!success;
|
Chris@102
|
189 }
|
Chris@102
|
190
|
Chris@102
|
191 static BOOST_FORCEINLINE bool compare_exchange_strong(
|
Chris@102
|
192 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT
|
Chris@102
|
193 {
|
Chris@102
|
194 int success;
|
Chris@102
|
195 fence_before(success_order);
|
Chris@102
|
196 __asm__ __volatile__
|
Chris@102
|
197 (
|
Chris@102
|
198 "li %1, 0\n"
|
Chris@102
|
199 "0: lwarx %0,%y2\n"
|
Chris@102
|
200 "cmpw %0, %3\n"
|
Chris@102
|
201 "bne- 1f\n"
|
Chris@102
|
202 "stwcx. %4,%y2\n"
|
Chris@102
|
203 "bne- 0b\n"
|
Chris@102
|
204 "li %1, 1\n"
|
Chris@102
|
205 "1:"
|
Chris@102
|
206 : "=&b" (expected), "=&b" (success), "+Z" (storage)
|
Chris@102
|
207 : "b" (expected), "b" (desired)
|
Chris@102
|
208 : "cr0"
|
Chris@102
|
209 );
|
Chris@102
|
210 if (success)
|
Chris@102
|
211 fence_after(success_order);
|
Chris@102
|
212 else
|
Chris@102
|
213 fence_after(failure_order);
|
Chris@102
|
214 return !!success;
|
Chris@102
|
215 }
|
Chris@102
|
216
|
Chris@102
|
217 static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
218 {
|
Chris@102
|
219 storage_type original, tmp;
|
Chris@102
|
220 fence_before(order);
|
Chris@102
|
221 __asm__ __volatile__
|
Chris@102
|
222 (
|
Chris@102
|
223 "1:\n"
|
Chris@102
|
224 "lwarx %0,%y2\n"
|
Chris@102
|
225 "add %1,%0,%3\n"
|
Chris@102
|
226 "stwcx. %1,%y2\n"
|
Chris@102
|
227 "bne- 1b\n"
|
Chris@102
|
228 : "=&b" (original), "=&b" (tmp), "+Z" (storage)
|
Chris@102
|
229 : "b" (v)
|
Chris@102
|
230 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
|
Chris@102
|
231 );
|
Chris@102
|
232 fence_after(order);
|
Chris@102
|
233 return original;
|
Chris@102
|
234 }
|
Chris@102
|
235
|
Chris@102
|
236 static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
237 {
|
Chris@102
|
238 storage_type original, tmp;
|
Chris@102
|
239 fence_before(order);
|
Chris@102
|
240 __asm__ __volatile__
|
Chris@102
|
241 (
|
Chris@102
|
242 "1:\n"
|
Chris@102
|
243 "lwarx %0,%y2\n"
|
Chris@102
|
244 "sub %1,%0,%3\n"
|
Chris@102
|
245 "stwcx. %1,%y2\n"
|
Chris@102
|
246 "bne- 1b\n"
|
Chris@102
|
247 : "=&b" (original), "=&b" (tmp), "+Z" (storage)
|
Chris@102
|
248 : "b" (v)
|
Chris@102
|
249 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
|
Chris@102
|
250 );
|
Chris@102
|
251 fence_after(order);
|
Chris@102
|
252 return original;
|
Chris@102
|
253 }
|
Chris@102
|
254
|
Chris@102
|
255 static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
256 {
|
Chris@102
|
257 storage_type original, tmp;
|
Chris@102
|
258 fence_before(order);
|
Chris@102
|
259 __asm__ __volatile__
|
Chris@102
|
260 (
|
Chris@102
|
261 "1:\n"
|
Chris@102
|
262 "lwarx %0,%y2\n"
|
Chris@102
|
263 "and %1,%0,%3\n"
|
Chris@102
|
264 "stwcx. %1,%y2\n"
|
Chris@102
|
265 "bne- 1b\n"
|
Chris@102
|
266 : "=&b" (original), "=&b" (tmp), "+Z" (storage)
|
Chris@102
|
267 : "b" (v)
|
Chris@102
|
268 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
|
Chris@102
|
269 );
|
Chris@102
|
270 fence_after(order);
|
Chris@102
|
271 return original;
|
Chris@102
|
272 }
|
Chris@102
|
273
|
Chris@102
|
274 static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
275 {
|
Chris@102
|
276 storage_type original, tmp;
|
Chris@102
|
277 fence_before(order);
|
Chris@102
|
278 __asm__ __volatile__
|
Chris@102
|
279 (
|
Chris@102
|
280 "1:\n"
|
Chris@102
|
281 "lwarx %0,%y2\n"
|
Chris@102
|
282 "or %1,%0,%3\n"
|
Chris@102
|
283 "stwcx. %1,%y2\n"
|
Chris@102
|
284 "bne- 1b\n"
|
Chris@102
|
285 : "=&b" (original), "=&b" (tmp), "+Z" (storage)
|
Chris@102
|
286 : "b" (v)
|
Chris@102
|
287 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
|
Chris@102
|
288 );
|
Chris@102
|
289 fence_after(order);
|
Chris@102
|
290 return original;
|
Chris@102
|
291 }
|
Chris@102
|
292
|
Chris@102
|
293 static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
294 {
|
Chris@102
|
295 storage_type original, tmp;
|
Chris@102
|
296 fence_before(order);
|
Chris@102
|
297 __asm__ __volatile__
|
Chris@102
|
298 (
|
Chris@102
|
299 "1:\n"
|
Chris@102
|
300 "lwarx %0,%y2\n"
|
Chris@102
|
301 "xor %1,%0,%3\n"
|
Chris@102
|
302 "stwcx. %1,%y2\n"
|
Chris@102
|
303 "bne- 1b\n"
|
Chris@102
|
304 : "=&b" (original), "=&b" (tmp), "+Z" (storage)
|
Chris@102
|
305 : "b" (v)
|
Chris@102
|
306 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
|
Chris@102
|
307 );
|
Chris@102
|
308 fence_after(order);
|
Chris@102
|
309 return original;
|
Chris@102
|
310 }
|
Chris@102
|
311
|
Chris@102
|
312 static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
313 {
|
Chris@102
|
314 return !!exchange(storage, (storage_type)1, order);
|
Chris@102
|
315 }
|
Chris@102
|
316
|
Chris@102
|
317 static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
318 {
|
Chris@102
|
319 store(storage, 0, order);
|
Chris@102
|
320 }
|
Chris@102
|
321
|
Chris@102
|
322 static BOOST_FORCEINLINE bool is_lock_free(storage_type const volatile&) BOOST_NOEXCEPT
|
Chris@102
|
323 {
|
Chris@102
|
324 return true;
|
Chris@102
|
325 }
|
Chris@102
|
326 };
|
Chris@102
|
327
|
Chris@102
|
328
|
Chris@102
|
329 template< >
|
Chris@102
|
330 struct operations< 1u, false > :
|
Chris@102
|
331 public operations< 4u, false >
|
Chris@102
|
332 {
|
Chris@102
|
333 typedef operations< 4u, false > base_type;
|
Chris@102
|
334 typedef base_type::storage_type storage_type;
|
Chris@102
|
335
|
Chris@102
|
336 static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
337 {
|
Chris@102
|
338 storage_type original, tmp;
|
Chris@102
|
339 fence_before(order);
|
Chris@102
|
340 __asm__ __volatile__
|
Chris@102
|
341 (
|
Chris@102
|
342 "1:\n"
|
Chris@102
|
343 "lwarx %0,%y2\n"
|
Chris@102
|
344 "add %1,%0,%3\n"
|
Chris@102
|
345 "rlwinm %1, %1, 0, 0xff\n"
|
Chris@102
|
346 "stwcx. %1,%y2\n"
|
Chris@102
|
347 "bne- 1b\n"
|
Chris@102
|
348 : "=&b" (original), "=&b" (tmp), "+Z" (storage)
|
Chris@102
|
349 : "b" (v)
|
Chris@102
|
350 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
|
Chris@102
|
351 );
|
Chris@102
|
352 fence_after(order);
|
Chris@102
|
353 return original;
|
Chris@102
|
354 }
|
Chris@102
|
355
|
Chris@102
|
356 static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
357 {
|
Chris@102
|
358 storage_type original, tmp;
|
Chris@102
|
359 fence_before(order);
|
Chris@102
|
360 __asm__ __volatile__
|
Chris@102
|
361 (
|
Chris@102
|
362 "1:\n"
|
Chris@102
|
363 "lwarx %0,%y2\n"
|
Chris@102
|
364 "sub %1,%0,%3\n"
|
Chris@102
|
365 "rlwinm %1, %1, 0, 0xff\n"
|
Chris@102
|
366 "stwcx. %1,%y2\n"
|
Chris@102
|
367 "bne- 1b\n"
|
Chris@102
|
368 : "=&b" (original), "=&b" (tmp), "+Z" (storage)
|
Chris@102
|
369 : "b" (v)
|
Chris@102
|
370 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
|
Chris@102
|
371 );
|
Chris@102
|
372 fence_after(order);
|
Chris@102
|
373 return original;
|
Chris@102
|
374 }
|
Chris@102
|
375 };
|
Chris@102
|
376
|
Chris@102
|
377 template< >
|
Chris@102
|
378 struct operations< 1u, true > :
|
Chris@102
|
379 public operations< 4u, true >
|
Chris@102
|
380 {
|
Chris@102
|
381 typedef operations< 4u, true > base_type;
|
Chris@102
|
382 typedef base_type::storage_type storage_type;
|
Chris@102
|
383
|
Chris@102
|
384 static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
385 {
|
Chris@102
|
386 storage_type original, tmp;
|
Chris@102
|
387 fence_before(order);
|
Chris@102
|
388 __asm__ __volatile__
|
Chris@102
|
389 (
|
Chris@102
|
390 "1:\n"
|
Chris@102
|
391 "lwarx %0,%y2\n"
|
Chris@102
|
392 "add %1,%0,%3\n"
|
Chris@102
|
393 "extsb %1, %1\n"
|
Chris@102
|
394 "stwcx. %1,%y2\n"
|
Chris@102
|
395 "bne- 1b\n"
|
Chris@102
|
396 : "=&b" (original), "=&b" (tmp), "+Z" (storage)
|
Chris@102
|
397 : "b" (v)
|
Chris@102
|
398 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
|
Chris@102
|
399 );
|
Chris@102
|
400 fence_after(order);
|
Chris@102
|
401 return original;
|
Chris@102
|
402 }
|
Chris@102
|
403
|
Chris@102
|
404 static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
405 {
|
Chris@102
|
406 storage_type original, tmp;
|
Chris@102
|
407 fence_before(order);
|
Chris@102
|
408 __asm__ __volatile__
|
Chris@102
|
409 (
|
Chris@102
|
410 "1:\n"
|
Chris@102
|
411 "lwarx %0,%y2\n"
|
Chris@102
|
412 "sub %1,%0,%3\n"
|
Chris@102
|
413 "extsb %1, %1\n"
|
Chris@102
|
414 "stwcx. %1,%y2\n"
|
Chris@102
|
415 "bne- 1b\n"
|
Chris@102
|
416 : "=&b" (original), "=&b" (tmp), "+Z" (storage)
|
Chris@102
|
417 : "b" (v)
|
Chris@102
|
418 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
|
Chris@102
|
419 );
|
Chris@102
|
420 fence_after(order);
|
Chris@102
|
421 return original;
|
Chris@102
|
422 }
|
Chris@102
|
423 };
|
Chris@102
|
424
|
Chris@102
|
425
|
Chris@102
|
426 template< >
|
Chris@102
|
427 struct operations< 2u, false > :
|
Chris@102
|
428 public operations< 4u, false >
|
Chris@102
|
429 {
|
Chris@102
|
430 typedef operations< 4u, false > base_type;
|
Chris@102
|
431 typedef base_type::storage_type storage_type;
|
Chris@102
|
432
|
Chris@102
|
433 static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
434 {
|
Chris@102
|
435 storage_type original, tmp;
|
Chris@102
|
436 fence_before(order);
|
Chris@102
|
437 __asm__ __volatile__
|
Chris@102
|
438 (
|
Chris@102
|
439 "1:\n"
|
Chris@102
|
440 "lwarx %0,%y2\n"
|
Chris@102
|
441 "add %1,%0,%3\n"
|
Chris@102
|
442 "rlwinm %1, %1, 0, 0xffff\n"
|
Chris@102
|
443 "stwcx. %1,%y2\n"
|
Chris@102
|
444 "bne- 1b\n"
|
Chris@102
|
445 : "=&b" (original), "=&b" (tmp), "+Z" (storage)
|
Chris@102
|
446 : "b" (v)
|
Chris@102
|
447 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
|
Chris@102
|
448 );
|
Chris@102
|
449 fence_after(order);
|
Chris@102
|
450 return original;
|
Chris@102
|
451 }
|
Chris@102
|
452
|
Chris@102
|
453 static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
454 {
|
Chris@102
|
455 storage_type original, tmp;
|
Chris@102
|
456 fence_before(order);
|
Chris@102
|
457 __asm__ __volatile__
|
Chris@102
|
458 (
|
Chris@102
|
459 "1:\n"
|
Chris@102
|
460 "lwarx %0,%y2\n"
|
Chris@102
|
461 "sub %1,%0,%3\n"
|
Chris@102
|
462 "rlwinm %1, %1, 0, 0xffff\n"
|
Chris@102
|
463 "stwcx. %1,%y2\n"
|
Chris@102
|
464 "bne- 1b\n"
|
Chris@102
|
465 : "=&b" (original), "=&b" (tmp), "+Z" (storage)
|
Chris@102
|
466 : "b" (v)
|
Chris@102
|
467 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
|
Chris@102
|
468 );
|
Chris@102
|
469 fence_after(order);
|
Chris@102
|
470 return original;
|
Chris@102
|
471 }
|
Chris@102
|
472 };
|
Chris@102
|
473
|
Chris@102
|
474 template< >
|
Chris@102
|
475 struct operations< 2u, true > :
|
Chris@102
|
476 public operations< 4u, true >
|
Chris@102
|
477 {
|
Chris@102
|
478 typedef operations< 4u, true > base_type;
|
Chris@102
|
479 typedef base_type::storage_type storage_type;
|
Chris@102
|
480
|
Chris@102
|
481 static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
482 {
|
Chris@102
|
483 storage_type original, tmp;
|
Chris@102
|
484 fence_before(order);
|
Chris@102
|
485 __asm__ __volatile__
|
Chris@102
|
486 (
|
Chris@102
|
487 "1:\n"
|
Chris@102
|
488 "lwarx %0,%y2\n"
|
Chris@102
|
489 "add %1,%0,%3\n"
|
Chris@102
|
490 "extsh %1, %1\n"
|
Chris@102
|
491 "stwcx. %1,%y2\n"
|
Chris@102
|
492 "bne- 1b\n"
|
Chris@102
|
493 : "=&b" (original), "=&b" (tmp), "+Z" (storage)
|
Chris@102
|
494 : "b" (v)
|
Chris@102
|
495 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
|
Chris@102
|
496 );
|
Chris@102
|
497 fence_after(order);
|
Chris@102
|
498 return original;
|
Chris@102
|
499 }
|
Chris@102
|
500
|
Chris@102
|
501 static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
502 {
|
Chris@102
|
503 storage_type original, tmp;
|
Chris@102
|
504 fence_before(order);
|
Chris@102
|
505 __asm__ __volatile__
|
Chris@102
|
506 (
|
Chris@102
|
507 "1:\n"
|
Chris@102
|
508 "lwarx %0,%y2\n"
|
Chris@102
|
509 "sub %1,%0,%3\n"
|
Chris@102
|
510 "extsh %1, %1\n"
|
Chris@102
|
511 "stwcx. %1,%y2\n"
|
Chris@102
|
512 "bne- 1b\n"
|
Chris@102
|
513 : "=&b" (original), "=&b" (tmp), "+Z" (storage)
|
Chris@102
|
514 : "b" (v)
|
Chris@102
|
515 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
|
Chris@102
|
516 );
|
Chris@102
|
517 fence_after(order);
|
Chris@102
|
518 return original;
|
Chris@102
|
519 }
|
Chris@102
|
520 };
|
Chris@102
|
521
|
Chris@102
|
522
|
Chris@102
|
523 #if defined(__powerpc64__)
|
Chris@102
|
524
|
Chris@102
|
525 template< bool Signed >
|
Chris@102
|
526 struct operations< 8u, Signed > :
|
Chris@102
|
527 public gcc_ppc_operations_base
|
Chris@102
|
528 {
|
Chris@102
|
529 typedef typename make_storage_type< 8u, Signed >::type storage_type;
|
Chris@102
|
530
|
Chris@102
|
531 static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
532 {
|
Chris@102
|
533 fence_before(order);
|
Chris@102
|
534 __asm__ __volatile__
|
Chris@102
|
535 (
|
Chris@102
|
536 "std %1, %0\n"
|
Chris@102
|
537 : "+m" (storage)
|
Chris@102
|
538 : "r" (v)
|
Chris@102
|
539 );
|
Chris@102
|
540 fence_after_store(order);
|
Chris@102
|
541 }
|
Chris@102
|
542
|
Chris@102
|
543 static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
544 {
|
Chris@102
|
545 storage_type v;
|
Chris@102
|
546 __asm__ __volatile__
|
Chris@102
|
547 (
|
Chris@102
|
548 "ld %0, %1\n"
|
Chris@102
|
549 "cmpd %0, %0\n"
|
Chris@102
|
550 "bne- 1f\n"
|
Chris@102
|
551 "1:\n"
|
Chris@102
|
552 : "=&b" (v)
|
Chris@102
|
553 : "m" (storage)
|
Chris@102
|
554 : "cr0"
|
Chris@102
|
555 );
|
Chris@102
|
556 fence_after(order);
|
Chris@102
|
557 return v;
|
Chris@102
|
558 }
|
Chris@102
|
559
|
Chris@102
|
560 static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
561 {
|
Chris@102
|
562 storage_type original;
|
Chris@102
|
563 fence_before(order);
|
Chris@102
|
564 __asm__ __volatile__
|
Chris@102
|
565 (
|
Chris@102
|
566 "1:\n"
|
Chris@102
|
567 "ldarx %0,%y1\n"
|
Chris@102
|
568 "stdcx. %2,%y1\n"
|
Chris@102
|
569 "bne- 1b\n"
|
Chris@102
|
570 : "=&b" (original), "+Z" (storage)
|
Chris@102
|
571 : "b" (v)
|
Chris@102
|
572 : "cr0"
|
Chris@102
|
573 );
|
Chris@102
|
574 fence_after(order);
|
Chris@102
|
575 return original;
|
Chris@102
|
576 }
|
Chris@102
|
577
|
Chris@102
|
578 static BOOST_FORCEINLINE bool compare_exchange_weak(
|
Chris@102
|
579 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT
|
Chris@102
|
580 {
|
Chris@102
|
581 int success;
|
Chris@102
|
582 fence_before(success_order);
|
Chris@102
|
583 __asm__ __volatile__
|
Chris@102
|
584 (
|
Chris@102
|
585 "li %1, 0\n"
|
Chris@102
|
586 "ldarx %0,%y2\n"
|
Chris@102
|
587 "cmpd %0, %3\n"
|
Chris@102
|
588 "bne- 1f\n"
|
Chris@102
|
589 "stdcx. %4,%y2\n"
|
Chris@102
|
590 "bne- 1f\n"
|
Chris@102
|
591 "li %1, 1\n"
|
Chris@102
|
592 "1:"
|
Chris@102
|
593 : "=&b" (expected), "=&b" (success), "+Z" (storage)
|
Chris@102
|
594 : "b" (expected), "b" (desired)
|
Chris@102
|
595 : "cr0"
|
Chris@102
|
596 );
|
Chris@102
|
597 if (success)
|
Chris@102
|
598 fence_after(success_order);
|
Chris@102
|
599 else
|
Chris@102
|
600 fence_after(failure_order);
|
Chris@102
|
601 return !!success;
|
Chris@102
|
602 }
|
Chris@102
|
603
|
Chris@102
|
604 static BOOST_FORCEINLINE bool compare_exchange_strong(
|
Chris@102
|
605 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT
|
Chris@102
|
606 {
|
Chris@102
|
607 int success;
|
Chris@102
|
608 fence_before(success_order);
|
Chris@102
|
609 __asm__ __volatile__
|
Chris@102
|
610 (
|
Chris@102
|
611 "li %1, 0\n"
|
Chris@102
|
612 "0: ldarx %0,%y2\n"
|
Chris@102
|
613 "cmpd %0, %3\n"
|
Chris@102
|
614 "bne- 1f\n"
|
Chris@102
|
615 "stdcx. %4,%y2\n"
|
Chris@102
|
616 "bne- 0b\n"
|
Chris@102
|
617 "li %1, 1\n"
|
Chris@102
|
618 "1:"
|
Chris@102
|
619 : "=&b" (expected), "=&b" (success), "+Z" (storage)
|
Chris@102
|
620 : "b" (expected), "b" (desired)
|
Chris@102
|
621 : "cr0"
|
Chris@102
|
622 );
|
Chris@102
|
623 if (success)
|
Chris@102
|
624 fence_after(success_order);
|
Chris@102
|
625 else
|
Chris@102
|
626 fence_after(failure_order);
|
Chris@102
|
627 return !!success;
|
Chris@102
|
628 }
|
Chris@102
|
629
|
Chris@102
|
630 static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
631 {
|
Chris@102
|
632 storage_type original, tmp;
|
Chris@102
|
633 fence_before(order);
|
Chris@102
|
634 __asm__ __volatile__
|
Chris@102
|
635 (
|
Chris@102
|
636 "1:\n"
|
Chris@102
|
637 "ldarx %0,%y2\n"
|
Chris@102
|
638 "add %1,%0,%3\n"
|
Chris@102
|
639 "stdcx. %1,%y2\n"
|
Chris@102
|
640 "bne- 1b\n"
|
Chris@102
|
641 : "=&b" (original), "=&b" (tmp), "+Z" (storage)
|
Chris@102
|
642 : "b" (v)
|
Chris@102
|
643 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
|
Chris@102
|
644 );
|
Chris@102
|
645 fence_after(order);
|
Chris@102
|
646 return original;
|
Chris@102
|
647 }
|
Chris@102
|
648
|
Chris@102
|
649 static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
650 {
|
Chris@102
|
651 storage_type original, tmp;
|
Chris@102
|
652 fence_before(order);
|
Chris@102
|
653 __asm__ __volatile__
|
Chris@102
|
654 (
|
Chris@102
|
655 "1:\n"
|
Chris@102
|
656 "ldarx %0,%y2\n"
|
Chris@102
|
657 "sub %1,%0,%3\n"
|
Chris@102
|
658 "stdcx. %1,%y2\n"
|
Chris@102
|
659 "bne- 1b\n"
|
Chris@102
|
660 : "=&b" (original), "=&b" (tmp), "+Z" (storage)
|
Chris@102
|
661 : "b" (v)
|
Chris@102
|
662 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
|
Chris@102
|
663 );
|
Chris@102
|
664 fence_after(order);
|
Chris@102
|
665 return original;
|
Chris@102
|
666 }
|
Chris@102
|
667
|
Chris@102
|
668 static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
669 {
|
Chris@102
|
670 storage_type original, tmp;
|
Chris@102
|
671 fence_before(order);
|
Chris@102
|
672 __asm__ __volatile__
|
Chris@102
|
673 (
|
Chris@102
|
674 "1:\n"
|
Chris@102
|
675 "ldarx %0,%y2\n"
|
Chris@102
|
676 "and %1,%0,%3\n"
|
Chris@102
|
677 "stdcx. %1,%y2\n"
|
Chris@102
|
678 "bne- 1b\n"
|
Chris@102
|
679 : "=&b" (original), "=&b" (tmp), "+Z" (storage)
|
Chris@102
|
680 : "b" (v)
|
Chris@102
|
681 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
|
Chris@102
|
682 );
|
Chris@102
|
683 fence_after(order);
|
Chris@102
|
684 return original;
|
Chris@102
|
685 }
|
Chris@102
|
686
|
Chris@102
|
687 static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
688 {
|
Chris@102
|
689 storage_type original, tmp;
|
Chris@102
|
690 fence_before(order);
|
Chris@102
|
691 __asm__ __volatile__
|
Chris@102
|
692 (
|
Chris@102
|
693 "1:\n"
|
Chris@102
|
694 "ldarx %0,%y2\n"
|
Chris@102
|
695 "or %1,%0,%3\n"
|
Chris@102
|
696 "stdcx. %1,%y2\n"
|
Chris@102
|
697 "bne- 1b\n"
|
Chris@102
|
698 : "=&b" (original), "=&b" (tmp), "+Z" (storage)
|
Chris@102
|
699 : "b" (v)
|
Chris@102
|
700 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
|
Chris@102
|
701 );
|
Chris@102
|
702 fence_after(order);
|
Chris@102
|
703 return original;
|
Chris@102
|
704 }
|
Chris@102
|
705
|
Chris@102
|
706 static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
707 {
|
Chris@102
|
708 storage_type original, tmp;
|
Chris@102
|
709 fence_before(order);
|
Chris@102
|
710 __asm__ __volatile__
|
Chris@102
|
711 (
|
Chris@102
|
712 "1:\n"
|
Chris@102
|
713 "ldarx %0,%y2\n"
|
Chris@102
|
714 "xor %1,%0,%3\n"
|
Chris@102
|
715 "stdcx. %1,%y2\n"
|
Chris@102
|
716 "bne- 1b\n"
|
Chris@102
|
717 : "=&b" (original), "=&b" (tmp), "+Z" (storage)
|
Chris@102
|
718 : "b" (v)
|
Chris@102
|
719 : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC
|
Chris@102
|
720 );
|
Chris@102
|
721 fence_after(order);
|
Chris@102
|
722 return original;
|
Chris@102
|
723 }
|
Chris@102
|
724
|
Chris@102
|
725 static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
726 {
|
Chris@102
|
727 return !!exchange(storage, (storage_type)1, order);
|
Chris@102
|
728 }
|
Chris@102
|
729
|
Chris@102
|
730 static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
731 {
|
Chris@102
|
732 store(storage, 0, order);
|
Chris@102
|
733 }
|
Chris@102
|
734
|
Chris@102
|
735 static BOOST_FORCEINLINE bool is_lock_free(storage_type const volatile&) BOOST_NOEXCEPT
|
Chris@102
|
736 {
|
Chris@102
|
737 return true;
|
Chris@102
|
738 }
|
Chris@102
|
739 };
|
Chris@102
|
740
|
Chris@102
|
741 #endif // defined(__powerpc64__)
|
Chris@102
|
742
|
Chris@102
|
743
|
Chris@102
|
744 BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
745 {
|
Chris@102
|
746 switch (order)
|
Chris@102
|
747 {
|
Chris@102
|
748 case memory_order_consume:
|
Chris@102
|
749 case memory_order_acquire:
|
Chris@102
|
750 __asm__ __volatile__ ("isync" ::: "memory");
|
Chris@102
|
751 break;
|
Chris@102
|
752 case memory_order_release:
|
Chris@102
|
753 #if defined(__powerpc64__)
|
Chris@102
|
754 __asm__ __volatile__ ("lwsync" ::: "memory");
|
Chris@102
|
755 break;
|
Chris@102
|
756 #endif
|
Chris@102
|
757 case memory_order_acq_rel:
|
Chris@102
|
758 case memory_order_seq_cst:
|
Chris@102
|
759 __asm__ __volatile__ ("sync" ::: "memory");
|
Chris@102
|
760 break;
|
Chris@102
|
761 default:;
|
Chris@102
|
762 }
|
Chris@102
|
763 }
|
Chris@102
|
764
|
Chris@102
|
765 BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT
|
Chris@102
|
766 {
|
Chris@102
|
767 if (order != memory_order_relaxed)
|
Chris@102
|
768 __asm__ __volatile__ ("" ::: "memory");
|
Chris@102
|
769 }
|
Chris@102
|
770
|
Chris@102
|
771 } // namespace detail
|
Chris@102
|
772 } // namespace atomics
|
Chris@102
|
773 } // namespace boost
|
Chris@102
|
774
|
Chris@102
|
775 #endif // BOOST_ATOMIC_DETAIL_OPS_GCC_PPC_HPP_INCLUDED_
|