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