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
34namespace google {
35namespace protobuf {
36namespace internal {
37
38inline 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
60inline 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
77inline 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
96inline void MemoryBarrier(void) {
97  asm volatile (
98      "       lwsync                          \n\t"
99      "       isync                           \n\t"
100              :
101              :
102              : "memory");
103}
104
105inline 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
127inline 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
151inline 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
176inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
177  *ptr = value;
178}
179
180inline 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
188inline 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
196inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
197  return *ptr;
198}
199
200inline 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
219inline 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
239inline 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
262inline 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
279inline 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
299inline 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
324inline 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
348inline 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
373inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
374  *ptr = value;
375}
376
377inline 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
385inline 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
393inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
394  return *ptr;
395}
396
397inline 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
416inline 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