// bsls_atomicoperations_powerpc_all_gcc.h -*-C++-*- #ifndef INCLUDED_BSLS_ATOMICOPERATIONS_POWERPC_ALL_GCC #define INCLUDED_BSLS_ATOMICOPERATIONS_POWERPC_ALL_GCC #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide implementations of atomic operations for gcc on PowerPC // //@CLASSES: // bsls::AtomicOperations_POWERPC_ALL_GCC: atomics for gcc on PowerPC // //@DESCRIPTION: This component provides classes necessary to implement atomics // on the PowerPC platform in 32bit/64bit mode with the GCC compiler. The // classes are for private use only. See 'bsls_atomicoperations' and // 'bsls_atomic' for the public interface to atomics. // // 'bsls_atomicoperations_all_all_gccintrinsics.h' is used for gcc 4.7+ and // provides C++11 atomics. The implementation herein is intended for earlier // versions of gcc and will work correctly for 64-bit programs, as well as for // 32-bit programs on AIX 6 or better, where AIX kernel saves and restores // 64-bit registers across context switches and interrupts, even in 32-bit // programs. According to IBM developers, this guarantee is not provided by // the 32-bit ABI when running Linux kernel on POWER hardware, and therefore // 64-bit atomic operations using gcc __sync_* intrinsics might not operate // properly in some circumstances on Linux on POWER. If running on Linux on // POWER, it is highly recommended that gcc 4.7+ be used, such as the IBM // Advanced Toolchain (AT) which currently provides gcc 4.8.3 for POWER, or the // RedHat Developer Toolset (DTS) for POWER. // // IMPLEMENTATION NOTE: there are likely excess explicit barriers since gcc // __sync_* intrinsics may provide their own barriers #include <bsls_atomicoperations_default.h> #include <bsls_platform.h> #include <bsls_types.h> #if defined(BSLS_PLATFORM_CPU_POWERPC) && defined(BSLS_PLATFORM_CMP_GNU) namespace BloombergLP { namespace bsls { struct AtomicOperations_POWERPC_ALL_GCC; typedef AtomicOperations_POWERPC_ALL_GCC AtomicOperations_Imp; // ========================================================== // struct Atomic_TypeTraits<AtomicOperations_POWERPC_ALL_GCC> // ========================================================== template <> struct Atomic_TypeTraits<AtomicOperations_POWERPC_ALL_GCC> { struct __attribute__((__aligned__(sizeof(int)))) Int { int d_value; }; struct __attribute__((__aligned__(sizeof(Types::Int64)))) Int64 { Types::Int64 d_value; }; struct __attribute__((__aligned__(sizeof(unsigned int)))) Uint { unsigned int d_value; }; struct __attribute__((__aligned__(sizeof(Types::Uint64)))) Uint64 { Types::Uint64 d_value; }; struct __attribute__((__aligned__(sizeof(void *)))) Pointer { void * d_value; }; }; // ======================================= // struct AtomicOperations_POWERPC_ALL_GCC // ======================================= struct AtomicOperations_POWERPC_ALL_GCC #ifdef BSLS_PLATFORM_CPU_64_BIT : AtomicOperations_Default64<AtomicOperations_POWERPC_ALL_GCC> #else : AtomicOperations_Default32<AtomicOperations_POWERPC_ALL_GCC> #endif { typedef Atomic_TypeTraits<AtomicOperations_POWERPC_ALL_GCC> AtomicTypes; typedef char AtomicInt_SizeCheck[sizeof(int) == 4 ? 1 : -1]; // compile-time assert // *** atomic functions for int *** static void initInt(AtomicTypes::Int *atomicInt, int value); static int getInt(const AtomicTypes::Int *atomicInt); static int getIntAcquire(const AtomicTypes::Int *atomicInt); static int getIntRelaxed(const AtomicTypes::Int *atomicInt); static void setInt(AtomicTypes::Int *atomicInt, int value); static void setIntRelease(AtomicTypes::Int *atomicInt, int value); static void setIntRelaxed(AtomicTypes::Int *atomicInt, int value); static int swapInt(AtomicTypes::Int *atomicInt, int swapValue); static int swapIntAcqRel(AtomicTypes::Int *atomicInt, int swapValue); static int testAndSwapInt(AtomicTypes::Int *atomicInt, int compareValue, int swapValue); static int testAndSwapIntAcqRel(AtomicTypes::Int *atomicInt, int compareValue, int swapValue); static int addIntNv(AtomicTypes::Int *atomicInt, int value); static int addIntNvAcqRel(AtomicTypes::Int *atomicInt, int value); static int addIntNvRelaxed(AtomicTypes::Int *atomicInt, int value); // *** atomic functions for Int64 *** static void initInt64(AtomicTypes::Int64 *atomicInt, Types::Int64 value); static Types::Int64 getInt64(const AtomicTypes::Int64 *atomicInt); static Types::Int64 getInt64Acquire(const AtomicTypes::Int64 *atomicInt); static Types::Int64 getInt64Relaxed(const AtomicTypes::Int64 *atomicInt); static void setInt64(AtomicTypes::Int64 *atomicInt, Types::Int64 value); static void setInt64Release(AtomicTypes::Int64 *atomicInt, Types::Int64 value); static void setInt64Relaxed(AtomicTypes::Int64 *atomicInt, Types::Int64 value); static Types::Int64 swapInt64(AtomicTypes::Int64 *atomicInt, Types::Int64 swapValue); static Types::Int64 swapInt64AcqRel(AtomicTypes::Int64 *atomicInt, Types::Int64 swapValue); static Types::Int64 testAndSwapInt64(AtomicTypes::Int64 *atomicInt, Types::Int64 compareValue, Types::Int64 swapValue); static Types::Int64 testAndSwapInt64AcqRel(AtomicTypes::Int64 *atomicInt, Types::Int64 compareValue, Types::Int64 swapValue); static Types::Int64 addInt64Nv(AtomicTypes::Int64 *atomicInt, Types::Int64 value); static Types::Int64 addInt64NvAcqRel(AtomicTypes::Int64 *atomicInt, Types::Int64 value); static Types::Int64 addInt64NvRelaxed(AtomicTypes::Int64 *atomicInt, Types::Int64 value); }; // =========================================================================== // INLINE FUNCTION DEFINITIONS // =========================================================================== // --------------------------------------- // struct AtomicOperations_POWERPC_ALL_GCC // --------------------------------------- inline void AtomicOperations_POWERPC_ALL_GCC:: initInt(AtomicTypes::Int *atomicInt, int value) { __asm__ __volatile__ ("stw%U0%X0 %1,%0" :"=m"(atomicInt->d_value) :"r"(value)); } inline int AtomicOperations_POWERPC_ALL_GCC:: getInt(const AtomicTypes::Int *atomicInt) { int rv; __asm__ __volatile__ ("sync":::"memory"); __asm__ __volatile__ ("lwz%U1%X1 %0,%1" :"=r"(rv) :"m"(atomicInt->d_value)); __asm__ __volatile__ ("lwsync":::"memory"); return rv; } inline int AtomicOperations_POWERPC_ALL_GCC:: getIntAcquire(const AtomicTypes::Int *atomicInt) { int rv; __asm__ __volatile__ ("lwz%U1%X1 %0,%1" :"=r"(rv) :"m"(atomicInt->d_value)); __asm__ __volatile__ ("lwsync":::"memory"); return rv; } inline int AtomicOperations_POWERPC_ALL_GCC:: getIntRelaxed(const AtomicTypes::Int *atomicInt) { int rv; __asm__ __volatile__ ("lwz%U1%X1 %0,%1" :"=r"(rv) :"m"(atomicInt->d_value)); return rv; } inline void AtomicOperations_POWERPC_ALL_GCC:: setInt(AtomicTypes::Int *atomicInt, int value) { __asm__ __volatile__ ("sync":::"memory"); __asm__ __volatile__ ("stw%U0%X0 %1,%0" :"=m"(atomicInt->d_value) :"r"(value)); } inline void AtomicOperations_POWERPC_ALL_GCC:: setIntRelease(AtomicTypes::Int *atomicInt, int value) { __asm__ __volatile__ ("lwsync":::"memory"); __asm__ __volatile__ ("stw%U0%X0 %1,%0" :"=m"(atomicInt->d_value) :"r"(value)); } inline void AtomicOperations_POWERPC_ALL_GCC:: setIntRelaxed(AtomicTypes::Int *atomicInt, int value) { __asm__ __volatile__ ("stw%U0%X0 %1,%0" :"=m"(atomicInt->d_value) :"r"(value)); } inline int AtomicOperations_POWERPC_ALL_GCC:: swapInt(AtomicTypes::Int *atomicInt, int swapValue) { __asm__ __volatile__ ("sync":::"memory"); return __sync_lock_test_and_set(&atomicInt->d_value, swapValue); } inline int AtomicOperations_POWERPC_ALL_GCC:: swapIntAcqRel(AtomicTypes::Int *atomicInt, int swapValue) { __asm__ __volatile__ ("lwsync":::"memory"); return __sync_lock_test_and_set(&atomicInt->d_value, swapValue); } inline int AtomicOperations_POWERPC_ALL_GCC:: testAndSwapInt(AtomicTypes::Int *atomicInt, int compareValue, int swapValue) { __asm__ __volatile__ ("sync":::"memory"); return __sync_val_compare_and_swap(&atomicInt->d_value, compareValue, swapValue); } inline int AtomicOperations_POWERPC_ALL_GCC:: testAndSwapIntAcqRel(AtomicTypes::Int *atomicInt, int compareValue, int swapValue) { __asm__ __volatile__ ("lwsync":::"memory"); return __sync_val_compare_and_swap(&atomicInt->d_value, compareValue, swapValue); } inline int AtomicOperations_POWERPC_ALL_GCC:: addIntNv(AtomicTypes::Int *atomicInt, int value) { int rv; __asm__ __volatile__ ("sync":::"memory"); rv = __sync_add_and_fetch(&atomicInt->d_value, value); __asm__ __volatile__ ("lwsync":::"memory"); return rv; } inline int AtomicOperations_POWERPC_ALL_GCC:: addIntNvAcqRel(AtomicTypes::Int *atomicInt, int value) { int rv; __asm__ __volatile__ ("lwsync":::"memory"); rv = __sync_add_and_fetch(&atomicInt->d_value, value); __asm__ __volatile__ ("lwsync":::"memory"); return rv; } inline int AtomicOperations_POWERPC_ALL_GCC:: addIntNvRelaxed(AtomicTypes::Int *atomicInt, int value) { return __sync_add_and_fetch(&atomicInt->d_value, value); } inline void AtomicOperations_POWERPC_ALL_GCC:: initInt64(AtomicTypes::Int64 *atomicInt, Types::Int64 value) { __asm__ __volatile__ ("std%U0%X0 %1,%0" :"=m"(atomicInt->d_value) :"r"(value)); } inline Types::Int64 AtomicOperations_POWERPC_ALL_GCC:: getInt64(const AtomicTypes::Int64 *atomicInt) { Types::Int64 rv; __asm__ __volatile__ ("sync":::"memory"); __asm__ __volatile__ ("ld%U1%X1 %0,%1" :"=r"(rv) :"m"(atomicInt->d_value)); __asm__ __volatile__ ("lwsync":::"memory"); return rv; } inline Types::Int64 AtomicOperations_POWERPC_ALL_GCC:: getInt64Acquire(const AtomicTypes::Int64 *atomicInt) { Types::Int64 rv; __asm__ __volatile__ ("ld%U1%X1 %0,%1" :"=r"(rv) :"m"(atomicInt->d_value)); __asm__ __volatile__ ("lwsync":::"memory"); return rv; } inline Types::Int64 AtomicOperations_POWERPC_ALL_GCC:: getInt64Relaxed(const AtomicTypes::Int64 *atomicInt) { Types::Int64 rv; __asm__ __volatile__ ("ld%U1%X1 %0,%1" :"=r"(rv) :"m"(atomicInt->d_value)); return rv; } inline void AtomicOperations_POWERPC_ALL_GCC:: setInt64(AtomicTypes::Int64 *atomicInt, Types::Int64 value) { __asm__ __volatile__ ("sync":::"memory"); __asm__ __volatile__ ("std%U0%X0 %1,%0" :"=m"(atomicInt->d_value) :"r"(value)); } inline void AtomicOperations_POWERPC_ALL_GCC:: setInt64Release(AtomicTypes::Int64 *atomicInt, Types::Int64 value) { __asm__ __volatile__ ("lwsync":::"memory"); __asm__ __volatile__ ("std%U0%X0 %1,%0" :"=m"(atomicInt->d_value) :"r"(value)); } inline void AtomicOperations_POWERPC_ALL_GCC:: setInt64Relaxed(AtomicTypes::Int64 *atomicInt, Types::Int64 value) { __asm__ __volatile__ ("std%U0%X0 %1,%0" :"=m"(atomicInt->d_value) :"r"(value)); } inline Types::Int64 AtomicOperations_POWERPC_ALL_GCC:: swapInt64(AtomicTypes::Int64 *atomicInt, Types::Int64 swapValue) { __asm__ __volatile__ ("sync":::"memory"); return __sync_lock_test_and_set(&atomicInt->d_value, swapValue); } inline Types::Int64 AtomicOperations_POWERPC_ALL_GCC:: swapInt64AcqRel(AtomicTypes::Int64 *atomicInt, Types::Int64 swapValue) { __asm__ __volatile__ ("lwsync":::"memory"); return __sync_lock_test_and_set(&atomicInt->d_value, swapValue); } inline Types::Int64 AtomicOperations_POWERPC_ALL_GCC:: testAndSwapInt64(AtomicTypes::Int64 *atomicInt, Types::Int64 compareValue, Types::Int64 swapValue) { __asm__ __volatile__ ("sync":::"memory"); return __sync_val_compare_and_swap(&atomicInt->d_value, compareValue, swapValue); } inline Types::Int64 AtomicOperations_POWERPC_ALL_GCC:: testAndSwapInt64AcqRel(AtomicTypes::Int64 *atomicInt, Types::Int64 compareValue, Types::Int64 swapValue) { __asm__ __volatile__ ("lwsync":::"memory"); return __sync_val_compare_and_swap(&atomicInt->d_value, compareValue, swapValue); } inline Types::Int64 AtomicOperations_POWERPC_ALL_GCC:: addInt64Nv(AtomicTypes::Int64 *atomicInt, Types::Int64 value) { Types::Int64 rv; __asm__ __volatile__ ("sync":::"memory"); rv = __sync_add_and_fetch(&atomicInt->d_value, value); __asm__ __volatile__ ("lwsync":::"memory"); return rv; } inline Types::Int64 AtomicOperations_POWERPC_ALL_GCC:: addInt64NvAcqRel(AtomicTypes::Int64 *atomicInt, Types::Int64 value) { Types::Int64 rv; __asm__ __volatile__ ("lwsync":::"memory"); rv = __sync_add_and_fetch(&atomicInt->d_value, value); __asm__ __volatile__ ("lwsync":::"memory"); return rv; } inline Types::Int64 AtomicOperations_POWERPC_ALL_GCC:: addInt64NvRelaxed(AtomicTypes::Int64 *atomicInt, Types::Int64 value) { return __sync_add_and_fetch(&atomicInt->d_value, value); } } // close package namespace } // close enterprise namespace #endif // BSLS_PLATFORM_CPU_POWERPC && BSLS_PLATFORM_CMP_GNU #endif // ---------------------------------------------------------------------------- // Copyright 2013 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------