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