1 // Copyright 2014 Bloomberg Finance LP. All rights reserved.
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 //     * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 //     * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 //     * Neither the name of Bloomberg Finance LP. nor the names of its
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 // This file is an internal atomic implementation, use atomicops.h instead.
30 
31 #ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_AIX_H_
32 #define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_AIX_H_
33 
34 namespace google {
35 namespace protobuf {
36 namespace internal {
37 
NoBarrier_CompareAndSwap(volatile Atomic32 * ptr,Atomic32 old_value,Atomic32 new_value)38 inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
39                                          Atomic32 old_value,
40                                          Atomic32 new_value) {
41   Atomic32 result;
42 
43   asm volatile (
44       "1:     lwarx %[res], %[zero], %[obj]   \n\t"  // load and reserve
45       "       cmpw %[cmp], %[res]             \n\t"  // compare values
46       "       bne- 2f                         \n\t"
47       "       stwcx. %[val], %[zero], %[obj]  \n\t"  // store new value
48       "       bne- 1b                         \n\t"
49       "2:                                     \n\t"
50               : [res]  "=&b" (result)
51               : [obj]  "b"   (ptr),
52                 [cmp]  "b"   (old_value),
53                 [val]  "b"   (new_value),
54                 [zero] "i"   (0)
55               : "cr0", "ctr");
56 
57   return result;
58 }
59 
NoBarrier_AtomicExchange(volatile Atomic32 * ptr,Atomic32 new_value)60 inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
61                                          Atomic32 new_value) {
62   Atomic32 result;
63 
64   asm volatile (
65       "1:     lwarx %[res], %[zero], %[obj]       \n\t"
66       "       stwcx. %[val], %[zero], %[obj]      \n\t"
67       "       bne- 1b                             \n\t"
68               : [res]  "=&b" (result)
69               : [obj]  "b"   (ptr),
70                 [val]  "b"   (new_value),
71                 [zero] "i"   (0)
72               : "cr0", "ctr");
73 
74   return result;
75 }
76 
NoBarrier_AtomicIncrement(volatile Atomic32 * ptr,Atomic32 increment)77 inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
78                                           Atomic32 increment) {
79   Atomic32 result;
80 
81   asm volatile (
82       "1:     lwarx %[res], %[zero], %[obj]   \n\t"  // load and reserve
83       "       add %[res], %[val], %[res]      \n\t"  // add the operand
84       "       stwcx. %[res], %[zero], %[obj]  \n\t"  // store old value
85                                                      // if still reserved
86       "       bne- 1b                         \n\t"
87               : [res]  "=&b" (result)
88               : [obj]  "b"   (ptr),
89                 [val]  "b"   (increment),
90                 [zero] "i"   (0)
91               : "cr0", "ctr");
92 
93   return result;
94 }
95 
MemoryBarrier(void)96 inline void MemoryBarrier(void) {
97   asm volatile (
98       "       lwsync                          \n\t"
99       "       isync                           \n\t"
100               :
101               :
102               : "memory");
103 }
104 
Barrier_AtomicIncrement(volatile Atomic32 * ptr,Atomic32 increment)105 inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
106                                         Atomic32 increment) {
107   Atomic32 result;
108 
109   asm volatile (
110       "       lwsync                          \n\t"
111 
112       "1:     lwarx %[res], %[zero], %[obj]   \n\t"  // load and reserve
113       "       add %[res], %[val], %[res]      \n\t"  // add the operand
114       "       stwcx. %[res], %[zero], %[obj]  \n\t"  // store old value
115                                                      // if still reserved
116       "       bne- 1b                         \n\t"
117       "       isync                           \n\t"
118               : [res]  "=&b" (result)
119               : [obj]  "b"   (ptr),
120                 [val]  "b"   (increment),
121                 [zero] "i"   (0)
122               : "cr0", "ctr");
123 
124   return result;
125 }
126 
Acquire_CompareAndSwap(volatile Atomic32 * ptr,Atomic32 old_value,Atomic32 new_value)127 inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
128                                        Atomic32 old_value,
129                                        Atomic32 new_value) {
130   Atomic32 result;
131 
132   asm volatile (
133       "1:     lwarx %[res], %[zero], %[obj]   \n\t"  // load and reserve
134       "       cmpw %[cmp], %[res]             \n\t"  // compare values
135       "       bne- 2f                         \n\t"
136       "       stwcx. %[val], %[zero], %[obj]  \n\t"  // store new value
137       "       bne- 1b                         \n\t"
138 
139       "       isync                           \n\t"
140       "2:                                     \n\t"
141               : [res]  "=&b" (result)
142               : [obj]  "b"   (ptr),
143                 [cmp]  "b"   (old_value),
144                 [val]  "b"   (new_value),
145                 [zero] "i"   (0)
146               : "cr0", "ctr");
147 
148   return result;
149 }
150 
Release_CompareAndSwap(volatile Atomic32 * ptr,Atomic32 old_value,Atomic32 new_value)151 inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
152                                        Atomic32 old_value,
153                                        Atomic32 new_value) {
154   Atomic32 result;
155 
156   asm volatile (
157       "       lwsync                          \n\t"
158 
159       "1:     lwarx %[res], %[zero], %[obj]   \n\t"  // load and reserve
160       "       cmpw %[cmp], %[res]             \n\t"  // compare values
161       "       bne- 2f                         \n\t"
162       "       stwcx. %[val], %[zero], %[obj]  \n\t"  // store new value
163       "       bne- 1b                         \n\t"
164 
165       "2:                                     \n\t"
166               : [res]  "=&b" (result)
167               : [obj]  "b"   (ptr),
168                 [cmp]  "b"   (old_value),
169                 [val]  "b"   (new_value),
170                 [zero] "i"   (0)
171               : "cr0", "ctr");
172 
173   return result;
174 }
175 
NoBarrier_Store(volatile Atomic32 * ptr,Atomic32 value)176 inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
177   *ptr = value;
178 }
179 
Acquire_Store(volatile Atomic32 * ptr,Atomic32 value)180 inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
181   asm volatile (
182       "       stw %[val], %[obj]      \n\t"
183       "       isync                   \n\t"
184               : [obj] "=m" (*ptr)
185               : [val]  "b"  (value));
186 }
187 
Release_Store(volatile Atomic32 * ptr,Atomic32 value)188 inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
189   asm volatile (
190       "       lwsync                  \n\t"
191       "       stw %[val], %[obj]      \n\t"
192               : [obj] "=m" (*ptr)
193               : [val]  "b"  (value));
194 }
195 
NoBarrier_Load(volatile const Atomic32 * ptr)196 inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
197   return *ptr;
198 }
199 
Acquire_Load(volatile const Atomic32 * ptr)200 inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
201   Atomic32 result;
202 
203   asm volatile (
204       "1:     lwz %[res], %[obj]              \n\t"
205       "       cmpw %[res], %[res]             \n\t" // create data
206                                                     // dependency for
207                                                     // load/load ordering
208       "       bne- 1b                         \n\t" // never taken
209 
210       "       isync                           \n\t"
211               : [res]  "=b" (result)
212               : [obj]  "m"  (*ptr),
213                 [zero] "i"  (0)
214               : "cr0", "ctr");
215 
216   return result;
217 }
218 
Release_Load(volatile const Atomic32 * ptr)219 inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
220   Atomic32 result;
221 
222   asm volatile (
223       "       lwsync                          \n\t"
224 
225       "1:     lwz %[res], %[obj]              \n\t"
226       "       cmpw %[res], %[res]             \n\t" // create data
227                                                     // dependency for
228                                                     // load/load ordering
229       "       bne- 1b                         \n\t" // never taken
230               : [res]  "=b" (result)
231               : [obj]  "m"  (*ptr),
232                 [zero] "i"  (0)
233               : "cr0", "ctr");
234 
235   return result;
236 }
237 
238 #ifdef GOOGLE_PROTOBUF_ARCH_64_BIT
NoBarrier_CompareAndSwap(volatile Atomic64 * ptr,Atomic64 old_value,Atomic64 new_value)239 inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
240                                          Atomic64 old_value,
241                                          Atomic64 new_value) {
242   Atomic64 result;
243 
244   asm volatile (
245       "1:     ldarx %[res], %[zero], %[obj]   \n\t"  // load and reserve
246       "       cmpd %[cmp], %[res]             \n\t"  // compare values
247       "       bne- 2f                         \n\t"
248 
249       "       stdcx. %[val], %[zero], %[obj]  \n\t"  // store the new value
250       "       bne- 1b                         \n\t"
251       "2:                                     \n\t"
252               : [res]  "=&b" (result)
253               : [obj]  "b"   (ptr),
254                 [cmp]  "b"   (old_value),
255                 [val]  "b"   (new_value),
256                 [zero] "i"   (0)
257               : "cr0", "ctr");
258 
259   return result;
260 }
261 
NoBarrier_AtomicExchange(volatile Atomic64 * ptr,Atomic64 new_value)262 inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
263                                          Atomic64 new_value) {
264   Atomic64 result;
265 
266   asm volatile (
267       "1:     ldarx %[res], %[zero], %[obj]       \n\t"
268       "       stdcx. %[val], %[zero], %[obj]      \n\t"
269       "       bne- 1b                             \n\t"
270               : [res]  "=&b" (result)
271               : [obj]  "b"   (ptr),
272                 [val]  "b"   (new_value),
273                 [zero] "i"   (0)
274               : "cr0", "ctr");
275 
276   return result;
277 }
278 
NoBarrier_AtomicIncrement(volatile Atomic64 * ptr,Atomic64 increment)279 inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
280                                           Atomic64 increment) {
281   Atomic64 result;
282 
283   asm volatile (
284       "1:     ldarx %[res], %[zero], %[obj]   \n\t" // load and reserve
285       "       add %[res], %[res], %[val]      \n\t" // add the operand
286       "       stdcx. %[res], %[zero], %[obj]  \n\t" // store old value if
287                                                     // still reserved
288 
289       "       bne- 1b                         \n\t"
290               : [res]  "=&b" (result)
291               : [obj]  "b"   (ptr),
292                 [val]  "b"   (increment),
293                 [zero] "i"   (0)
294               : "cr0", "ctr");
295 
296   return result;
297 }
298 
Barrier_AtomicIncrement(volatile Atomic64 * ptr,Atomic64 increment)299 inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
300                                         Atomic64 increment) {
301 
302   Atomic64 result;
303 
304   asm volatile (
305       "       lwsync                          \n\t"
306 
307       "1:     ldarx %[res], %[zero], %[obj]   \n\t" // load and reserve
308       "       add %[res], %[res], %[val]      \n\t" // add the operand
309       "       stdcx. %[res], %[zero], %[obj]  \n\t" // store old value if
310                                                     // still reserved
311 
312       "       bne- 1b                         \n\t"
313 
314       "       isync                           \n\t"
315               : [res]  "=&b" (result)
316               : [obj]  "b"   (ptr),
317                 [val]  "b"   (increment),
318                 [zero] "i"   (0)
319               : "cr0", "ctr");
320 
321   return result;
322 }
323 
Acquire_CompareAndSwap(volatile Atomic64 * ptr,Atomic64 old_value,Atomic64 new_value)324 inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
325                                        Atomic64 old_value,
326                                        Atomic64 new_value) {
327   Atomic64 result;
328 
329   asm volatile (
330       "1:     ldarx %[res], %[zero], %[obj]   \n\t"  // load and reserve
331       "       cmpd %[cmp], %[res]             \n\t"  // compare values
332       "       bne- 2f                         \n\t"
333 
334       "       stdcx. %[val], %[zero], %[obj]  \n\t"  // store the new value
335       "       bne- 1b                         \n\t"
336       "       isync                           \n\t"
337       "2:                                     \n\t"
338               : [res]  "=&b" (result)
339               : [obj]  "b"   (ptr),
340                 [cmp]  "b"   (old_value),
341                 [val]  "b"   (new_value),
342                 [zero] "i"   (0)
343               : "cr0", "ctr");
344 
345   return result;
346 }
347 
Release_CompareAndSwap(volatile Atomic64 * ptr,Atomic64 old_value,Atomic64 new_value)348 inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
349                                        Atomic64 old_value,
350                                        Atomic64 new_value) {
351   Atomic64 result;
352 
353   asm volatile (
354       "       lwsync                          \n\t"
355 
356       "1:     ldarx %[res], %[zero], %[obj]   \n\t"  // load and reserve
357       "       cmpd %[cmp], %[res]             \n\t"  // compare values
358       "       bne- 2f                         \n\t"
359 
360       "       stdcx. %[val], %[zero], %[obj]  \n\t"  // store the new value
361       "       bne- 1b                         \n\t"
362       "2:                                     \n\t"
363               : [res]  "=&b" (result)
364               : [obj]  "b"   (ptr),
365                 [cmp]  "b"   (old_value),
366                 [val]  "b"   (new_value),
367                 [zero] "i"   (0)
368               : "cr0", "ctr");
369 
370   return result;
371 }
372 
NoBarrier_Store(volatile Atomic64 * ptr,Atomic64 value)373 inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
374   *ptr = value;
375 }
376 
Acquire_Store(volatile Atomic64 * ptr,Atomic64 value)377 inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
378   asm volatile (
379       "       std %[val], %[obj]          \n\t"
380       "       isync                       \n\t"
381               : [obj] "=m" (*ptr)
382               : [val] "b"  (value));
383 }
384 
Release_Store(volatile Atomic64 * ptr,Atomic64 value)385 inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
386   asm volatile (
387       "       lwsync                      \n\t"
388       "       std %[val], %[obj]          \n\t"
389               : [obj] "=m" (*ptr)
390               : [val] "b"  (value));
391 }
392 
NoBarrier_Load(volatile const Atomic64 * ptr)393 inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
394   return *ptr;
395 }
396 
Acquire_Load(volatile const Atomic64 * ptr)397 inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
398   Atomic64 result;
399 
400   asm volatile (
401       "1:     ld %[res], %[obj]                   \n\t"
402       "       cmpd %[res], %[res]                 \n\t" // create data
403                                                         // dependency for
404                                                         // load/load ordering
405       "       bne- 1b                             \n\t" // never taken
406 
407       "       isync                               \n\t"
408               : [res]  "=b" (result)
409               : [obj]  "m"  (*ptr),
410                 [zero] "i"  (0)
411               : "cr0", "ctr");
412 
413   return result;
414 }
415 
Release_Load(volatile const Atomic64 * ptr)416 inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
417   Atomic64 result;
418 
419   asm volatile (
420       "       lwsync                              \n\t"
421 
422       "1:     ld %[res], %[obj]                   \n\t"
423       "       cmpd %[res], %[res]                 \n\t" // create data
424                                                         // dependency for
425                                                         // load/load ordering
426       "       bne- 1b                             \n\t" // never taken
427               : [res]  "=b" (result)
428               : [obj]  "m"  (*ptr),
429                 [zero] "i"  (0)
430               : "cr0", "ctr");
431 
432   return result;
433 }
434 #endif
435 
436 }  // namespace internal
437 }  // namespace protobuf
438 }  // namespace google
439 
440 #endif  // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_SPARC_GCC_H_
441