blob: b52fdf0d1ec58797691ea101825d1762b5f69236 [file] [log] [blame]
Austin Schuh745610d2015-09-06 18:19:50 -07001// -*- 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
34// Implementation of atomic operations for ppc-linux. This file should not
35// be included directly. Clients should instead include
36// "base/atomicops.h".
37
38#ifndef BASE_ATOMICOPS_INTERNALS_LINUXPPC_H_
39#define BASE_ATOMICOPS_INTERNALS_LINUXPPC_H_
40
41typedef int32_t Atomic32;
42
43#ifdef __PPC64__
44#define BASE_HAS_ATOMIC64 1
45#endif
46
47namespace base {
48namespace subtle {
49
50static inline void _sync(void) {
51 __asm__ __volatile__("sync": : : "memory");
52}
53
54static inline void _lwsync(void) {
55 // gcc defines __NO_LWSYNC__ when appropriate; see
56 // http://gcc.gnu.org/ml/gcc-patches/2006-11/msg01238.html
57#ifdef __NO_LWSYNC__
58 __asm__ __volatile__("msync": : : "memory");
59#else
60 __asm__ __volatile__("lwsync": : : "memory");
61#endif
62}
63
64static inline void _isync(void) {
65 __asm__ __volatile__("isync": : : "memory");
66}
67
68static inline Atomic32 OSAtomicAdd32(Atomic32 amount, Atomic32 *value) {
69 Atomic32 t;
70 __asm__ __volatile__(
71"1: lwarx %0,0,%3\n\
72 add %0,%2,%0\n\
73 stwcx. %0,0,%3 \n\
74 bne- 1b"
75 : "=&r" (t), "+m" (*value)
76 : "r" (amount), "r" (value)
77 : "cc");
78 return t;
79}
80
81static inline Atomic32 OSAtomicAdd32Barrier(Atomic32 amount, Atomic32 *value) {
82 Atomic32 t;
83 _lwsync();
84 t = OSAtomicAdd32(amount, value);
85 // This is based on the code snippet in the architecture manual (Vol
86 // 2, Appendix B). It's a little tricky: correctness depends on the
87 // fact that the code right before this (in OSAtomicAdd32) has a
88 // conditional branch with a data dependency on the update.
89 // Otherwise, we'd have to use sync.
90 _isync();
91 return t;
92}
93
94static inline bool OSAtomicCompareAndSwap32(Atomic32 old_value,
95 Atomic32 new_value,
96 Atomic32 *value) {
97 Atomic32 prev;
98 __asm__ __volatile__(
99"1: lwarx %0,0,%2\n\
100 cmpw 0,%0,%3\n\
101 bne- 2f\n\
102 stwcx. %4,0,%2\n\
103 bne- 1b\n\
1042:"
105 : "=&r" (prev), "+m" (*value)
106 : "r" (value), "r" (old_value), "r" (new_value)
107 : "cc");
108 return prev == old_value;
109}
110
111static inline Atomic32 OSAtomicCompareAndSwap32Acquire(Atomic32 old_value,
112 Atomic32 new_value,
113 Atomic32 *value) {
114 Atomic32 t;
115 t = OSAtomicCompareAndSwap32(old_value, new_value, value);
116 // This is based on the code snippet in the architecture manual (Vol
117 // 2, Appendix B). It's a little tricky: correctness depends on the
118 // fact that the code right before this (in
119 // OSAtomicCompareAndSwap32) has a conditional branch with a data
120 // dependency on the update. Otherwise, we'd have to use sync.
121 _isync();
122 return t;
123}
124
125static inline Atomic32 OSAtomicCompareAndSwap32Release(Atomic32 old_value,
126 Atomic32 new_value,
127 Atomic32 *value) {
128 _lwsync();
129 return OSAtomicCompareAndSwap32(old_value, new_value, value);
130}
131
132typedef int64_t Atomic64;
133
134inline void MemoryBarrier() {
135 // This can't be _lwsync(); we need to order the immediately
136 // preceding stores against any load that may follow, but lwsync
137 // doesn't guarantee that.
138 _sync();
139}
140
141// 32-bit Versions.
142
143inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32 *ptr,
144 Atomic32 old_value,
145 Atomic32 new_value) {
146 Atomic32 prev_value;
147 do {
148 if (OSAtomicCompareAndSwap32(old_value, new_value,
149 const_cast<Atomic32*>(ptr))) {
150 return old_value;
151 }
152 prev_value = *ptr;
153 } while (prev_value == old_value);
154 return prev_value;
155}
156
157inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32 *ptr,
158 Atomic32 new_value) {
159 Atomic32 old_value;
160 do {
161 old_value = *ptr;
162 } while (!OSAtomicCompareAndSwap32(old_value, new_value,
163 const_cast<Atomic32*>(ptr)));
164 return old_value;
165}
166
167inline Atomic32 Acquire_AtomicExchange(volatile Atomic32 *ptr,
168 Atomic32 new_value) {
169 Atomic32 old_value;
170 do {
171 old_value = *ptr;
172 } while (!OSAtomicCompareAndSwap32Acquire(old_value, new_value,
173 const_cast<Atomic32*>(ptr)));
174 return old_value;
175}
176
177inline Atomic32 Release_AtomicExchange(volatile Atomic32 *ptr,
178 Atomic32 new_value) {
179 Atomic32 old_value;
180 do {
181 old_value = *ptr;
182 } while (!OSAtomicCompareAndSwap32Release(old_value, new_value,
183 const_cast<Atomic32*>(ptr)));
184 return old_value;
185}
186
187inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32 *ptr,
188 Atomic32 old_value,
189 Atomic32 new_value) {
190 Atomic32 prev_value;
191 do {
192 if (OSAtomicCompareAndSwap32Acquire(old_value, new_value,
193 const_cast<Atomic32*>(ptr))) {
194 return old_value;
195 }
196 prev_value = *ptr;
197 } while (prev_value == old_value);
198 return prev_value;
199}
200
201inline Atomic32 Release_CompareAndSwap(volatile Atomic32 *ptr,
202 Atomic32 old_value,
203 Atomic32 new_value) {
204 Atomic32 prev_value;
205 do {
206 if (OSAtomicCompareAndSwap32Release(old_value, new_value,
207 const_cast<Atomic32*>(ptr))) {
208 return old_value;
209 }
210 prev_value = *ptr;
211 } while (prev_value == old_value);
212 return prev_value;
213}
214
215#ifdef __PPC64__
216
217// 64-bit Versions.
218
219static inline Atomic64 OSAtomicAdd64(Atomic64 amount, Atomic64 *value) {
220 Atomic64 t;
221 __asm__ __volatile__(
222"1: ldarx %0,0,%3\n\
223 add %0,%2,%0\n\
224 stdcx. %0,0,%3 \n\
225 bne- 1b"
226 : "=&r" (t), "+m" (*value)
227 : "r" (amount), "r" (value)
228 : "cc");
229 return t;
230}
231
232static inline Atomic64 OSAtomicAdd64Barrier(Atomic64 amount, Atomic64 *value) {
233 Atomic64 t;
234 _lwsync();
235 t = OSAtomicAdd64(amount, value);
236 // This is based on the code snippet in the architecture manual (Vol
237 // 2, Appendix B). It's a little tricky: correctness depends on the
238 // fact that the code right before this (in OSAtomicAdd64) has a
239 // conditional branch with a data dependency on the update.
240 // Otherwise, we'd have to use sync.
241 _isync();
242 return t;
243}
244
245static inline bool OSAtomicCompareAndSwap64(Atomic64 old_value,
246 Atomic64 new_value,
247 Atomic64 *value) {
248 Atomic64 prev;
249 __asm__ __volatile__(
250"1: ldarx %0,0,%2\n\
251 cmpd 0,%0,%3\n\
252 bne- 2f\n\
253 stdcx. %4,0,%2\n\
254 bne- 1b\n\
2552:"
256 : "=&r" (prev), "+m" (*value)
257 : "r" (value), "r" (old_value), "r" (new_value)
258 : "cc");
259 return prev == old_value;
260}
261
262static inline Atomic64 OSAtomicCompareAndSwap64Acquire(Atomic64 old_value,
263 Atomic64 new_value,
264 Atomic64 *value) {
265 Atomic64 t;
266 t = OSAtomicCompareAndSwap64(old_value, new_value, value);
267 // This is based on the code snippet in the architecture manual (Vol
268 // 2, Appendix B). It's a little tricky: correctness depends on the
269 // fact that the code right before this (in
270 // OSAtomicCompareAndSwap64) has a conditional branch with a data
271 // dependency on the update. Otherwise, we'd have to use sync.
272 _isync();
273 return t;
274}
275
276static inline Atomic64 OSAtomicCompareAndSwap64Release(Atomic64 old_value,
277 Atomic64 new_value,
278 Atomic64 *value) {
279 _lwsync();
280 return OSAtomicCompareAndSwap64(old_value, new_value, value);
281}
282
283
284inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64 *ptr,
285 Atomic64 old_value,
286 Atomic64 new_value) {
287 Atomic64 prev_value;
288 do {
289 if (OSAtomicCompareAndSwap64(old_value, new_value,
290 const_cast<Atomic64*>(ptr))) {
291 return old_value;
292 }
293 prev_value = *ptr;
294 } while (prev_value == old_value);
295 return prev_value;
296}
297
298inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64 *ptr,
299 Atomic64 new_value) {
300 Atomic64 old_value;
301 do {
302 old_value = *ptr;
303 } while (!OSAtomicCompareAndSwap64(old_value, new_value,
304 const_cast<Atomic64*>(ptr)));
305 return old_value;
306}
307
308inline Atomic64 Acquire_AtomicExchange(volatile Atomic64 *ptr,
309 Atomic64 new_value) {
310 Atomic64 old_value;
311 do {
312 old_value = *ptr;
313 } while (!OSAtomicCompareAndSwap64Acquire(old_value, new_value,
314 const_cast<Atomic64*>(ptr)));
315 return old_value;
316}
317
318inline Atomic64 Release_AtomicExchange(volatile Atomic64 *ptr,
319 Atomic64 new_value) {
320 Atomic64 old_value;
321 do {
322 old_value = *ptr;
323 } while (!OSAtomicCompareAndSwap64Release(old_value, new_value,
324 const_cast<Atomic64*>(ptr)));
325 return old_value;
326}
327
328inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64 *ptr,
329 Atomic64 old_value,
330 Atomic64 new_value) {
331 Atomic64 prev_value;
332 do {
333 if (OSAtomicCompareAndSwap64Acquire(old_value, new_value,
334 const_cast<Atomic64*>(ptr))) {
335 return old_value;
336 }
337 prev_value = *ptr;
338 } while (prev_value == old_value);
339 return prev_value;
340}
341
342inline Atomic64 Release_CompareAndSwap(volatile Atomic64 *ptr,
343 Atomic64 old_value,
344 Atomic64 new_value) {
345 Atomic64 prev_value;
346 do {
347 if (OSAtomicCompareAndSwap64Release(old_value, new_value,
348 const_cast<Atomic64*>(ptr))) {
349 return old_value;
350 }
351 prev_value = *ptr;
352 } while (prev_value == old_value);
353 return prev_value;
354}
355
356#endif
357
358inline void NoBarrier_Store(volatile Atomic32 *ptr, Atomic32 value) {
359 *ptr = value;
360}
361
362inline void Acquire_Store(volatile Atomic32 *ptr, Atomic32 value) {
363 *ptr = value;
364 // This can't be _lwsync(); we need to order the immediately
365 // preceding stores against any load that may follow, but lwsync
366 // doesn't guarantee that.
367 _sync();
368}
369
370inline void Release_Store(volatile Atomic32 *ptr, Atomic32 value) {
371 _lwsync();
372 *ptr = value;
373}
374
375inline Atomic32 NoBarrier_Load(volatile const Atomic32 *ptr) {
376 return *ptr;
377}
378
379inline Atomic32 Acquire_Load(volatile const Atomic32 *ptr) {
380 Atomic32 value = *ptr;
381 _lwsync();
382 return value;
383}
384
385inline Atomic32 Release_Load(volatile const Atomic32 *ptr) {
386 // This can't be _lwsync(); we need to order the immediately
387 // preceding stores against any load that may follow, but lwsync
388 // doesn't guarantee that.
389 _sync();
390 return *ptr;
391}
392
393#ifdef __PPC64__
394
395// 64-bit Versions.
396
397inline void NoBarrier_Store(volatile Atomic64 *ptr, Atomic64 value) {
398 *ptr = value;
399}
400
401inline void Acquire_Store(volatile Atomic64 *ptr, Atomic64 value) {
402 *ptr = value;
403 // This can't be _lwsync(); we need to order the immediately
404 // preceding stores against any load that may follow, but lwsync
405 // doesn't guarantee that.
406 _sync();
407}
408
409inline void Release_Store(volatile Atomic64 *ptr, Atomic64 value) {
410 _lwsync();
411 *ptr = value;
412}
413
414inline Atomic64 NoBarrier_Load(volatile const Atomic64 *ptr) {
415 return *ptr;
416}
417
418inline Atomic64 Acquire_Load(volatile const Atomic64 *ptr) {
419 Atomic64 value = *ptr;
420 _lwsync();
421 return value;
422}
423
424inline Atomic64 Release_Load(volatile const Atomic64 *ptr) {
425 // This can't be _lwsync(); we need to order the immediately
426 // preceding stores against any load that may follow, but lwsync
427 // doesn't guarantee that.
428 _sync();
429 return *ptr;
430}
431
432#endif
433
434} // namespace base::subtle
435} // namespace base
436
437#endif // BASE_ATOMICOPS_INTERNALS_LINUXPPC_H_