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