#if !defined(AO_ATOMIC_OPS_H) || defined(AO_ATOMIC_OPS_INCLUDED)
# error This file should not be included directly.
#endif
#if (AO_GNUC_PREREQ(4, 8) || AO_CLANG_PREREQ(3, 8)) \
&& !defined(AO_DISABLE_GCC_ATOMICS)
# include "generic.h"
#else
#include "../all_aligned_atomic_load_store.h"
#include "../test_and_set_t_is_ao_t.h"
AO_INLINE void
AO_nop_full(void)
{
__asm__ __volatile__("sync" : : : "memory");
}
#define AO_HAVE_nop_full
AO_INLINE void
AO_lwsync(void)
{
#ifdef __NO_LWSYNC__
__asm__ __volatile__("sync" : : : "memory");
#else
__asm__ __volatile__("lwsync" : : : "memory");
#endif
}
#define AO_nop_write() AO_lwsync()
#define AO_HAVE_nop_write
#define AO_nop_read() AO_lwsync()
#define AO_HAVE_nop_read
#if defined(__powerpc64__) || defined(__ppc64__) || defined(__64BIT__)
# define AO_PPC_LD "ld"
# define AO_PPC_LxARX "ldarx"
# define AO_PPC_CMPx "cmpd"
# define AO_PPC_STxCXd "stdcx."
# define AO_PPC_LOAD_CLOBBER "cr0"
#else
# define AO_PPC_LD "lwz"
# define AO_PPC_LxARX "lwarx"
# define AO_PPC_CMPx "cmpw"
# define AO_PPC_STxCXd "stwcx."
# define AO_PPC_LOAD_CLOBBER "cc"
# define AO_T_IS_INT
#endif
#ifdef _AIX
# define AO_PPC_L(label)
# define AO_PPC_BR_A(labelBF, addr) addr
#else
# define AO_PPC_L(label) label ": "
# define AO_PPC_BR_A(labelBF, addr) labelBF
#endif
AO_INLINE AO_t
AO_load_acquire(const volatile AO_t *addr)
{
AO_t result;
__asm__ __volatile__ (
AO_PPC_LD "%U1%X1 %0,%1\n"
"cmpw %0,%0\n"
"bne- " AO_PPC_BR_A("1f", "$+4") "\n"
AO_PPC_L("1") "isync\n"
: "=r" (result)
: "m"(*addr) : "memory", AO_PPC_LOAD_CLOBBER);
return result;
}
#define AO_HAVE_load_acquire
AO_INLINE void
AO_store_release(volatile AO_t *addr, AO_t value)
{
AO_lwsync();
*addr = value;
}
#define AO_HAVE_store_release
#ifndef AO_PREFER_GENERALIZED
AO_INLINE AO_TS_VAL_t
AO_test_and_set(volatile AO_TS_t *addr) {
AO_t oldval;
AO_t temp = 1;
__asm__ __volatile__(
AO_PPC_L("1") AO_PPC_LxARX " %0,0,%1\n"
AO_PPC_CMPx "i %0, 0\n"
"bne " AO_PPC_BR_A("2f", "$+12") "\n"
AO_PPC_STxCXd " %2,0,%1\n"
"bne- " AO_PPC_BR_A("1b", "$-16") "\n"
AO_PPC_L("2") "\n"
: "=&r"(oldval)
: "r"(addr), "r"(temp)
: "memory", "cr0");
return (AO_TS_VAL_t)oldval;
}
#define AO_HAVE_test_and_set
AO_INLINE AO_TS_VAL_t
AO_test_and_set_acquire(volatile AO_TS_t *addr) {
AO_TS_VAL_t result = AO_test_and_set(addr);
AO_lwsync();
return result;
}
#define AO_HAVE_test_and_set_acquire
AO_INLINE AO_TS_VAL_t
AO_test_and_set_release(volatile AO_TS_t *addr) {
AO_lwsync();
return AO_test_and_set(addr);
}
#define AO_HAVE_test_and_set_release
AO_INLINE AO_TS_VAL_t
AO_test_and_set_full(volatile AO_TS_t *addr) {
AO_TS_VAL_t result;
AO_lwsync();
result = AO_test_and_set(addr);
AO_lwsync();
return result;
}
#define AO_HAVE_test_and_set_full
#endif
#ifndef AO_GENERALIZE_ASM_BOOL_CAS
AO_INLINE int
AO_compare_and_swap(volatile AO_t *addr, AO_t old, AO_t new_val)
{
AO_t oldval;
int result = 0;
__asm__ __volatile__(
AO_PPC_L("1") AO_PPC_LxARX " %0,0,%2\n"
AO_PPC_CMPx " %0, %4\n"
"bne " AO_PPC_BR_A("2f", "$+16") "\n"
AO_PPC_STxCXd " %3,0,%2\n"
"bne- " AO_PPC_BR_A("1b", "$-16") "\n"
"li %1,1\n"
AO_PPC_L("2") "\n"
: "=&r"(oldval), "=&r"(result)
: "r"(addr), "r"(new_val), "r"(old), "1"(result)
: "memory", "cr0");
return result;
}
# define AO_HAVE_compare_and_swap
AO_INLINE int
AO_compare_and_swap_acquire(volatile AO_t *addr, AO_t old, AO_t new_val)
{
int result = AO_compare_and_swap(addr, old, new_val);
AO_lwsync();
return result;
}
# define AO_HAVE_compare_and_swap_acquire
AO_INLINE int
AO_compare_and_swap_release(volatile AO_t *addr, AO_t old, AO_t new_val)
{
AO_lwsync();
return AO_compare_and_swap(addr, old, new_val);
}
# define AO_HAVE_compare_and_swap_release
AO_INLINE int
AO_compare_and_swap_full(volatile AO_t *addr, AO_t old, AO_t new_val)
{
int result;
AO_lwsync();
result = AO_compare_and_swap(addr, old, new_val);
if (result)
AO_lwsync();
return result;
}
# define AO_HAVE_compare_and_swap_full
#endif
AO_INLINE AO_t
AO_fetch_compare_and_swap(volatile AO_t *addr, AO_t old_val, AO_t new_val)
{
AO_t fetched_val;
__asm__ __volatile__(
AO_PPC_L("1") AO_PPC_LxARX " %0,0,%1\n"
AO_PPC_CMPx " %0, %3\n"
"bne " AO_PPC_BR_A("2f", "$+12") "\n"
AO_PPC_STxCXd " %2,0,%1\n"
"bne- " AO_PPC_BR_A("1b", "$-16") "\n"
AO_PPC_L("2") "\n"
: "=&r"(fetched_val)
: "r"(addr), "r"(new_val), "r"(old_val)
: "memory", "cr0");
return fetched_val;
}
#define AO_HAVE_fetch_compare_and_swap
AO_INLINE AO_t
AO_fetch_compare_and_swap_acquire(volatile AO_t *addr, AO_t old_val,
AO_t new_val)
{
AO_t result = AO_fetch_compare_and_swap(addr, old_val, new_val);
AO_lwsync();
return result;
}
#define AO_HAVE_fetch_compare_and_swap_acquire
AO_INLINE AO_t
AO_fetch_compare_and_swap_release(volatile AO_t *addr, AO_t old_val,
AO_t new_val)
{
AO_lwsync();
return AO_fetch_compare_and_swap(addr, old_val, new_val);
}
#define AO_HAVE_fetch_compare_and_swap_release
AO_INLINE AO_t
AO_fetch_compare_and_swap_full(volatile AO_t *addr, AO_t old_val,
AO_t new_val)
{
AO_t result;
AO_lwsync();
result = AO_fetch_compare_and_swap(addr, old_val, new_val);
if (result == old_val)
AO_lwsync();
return result;
}
#define AO_HAVE_fetch_compare_and_swap_full
#ifndef AO_PREFER_GENERALIZED
AO_INLINE AO_t
AO_fetch_and_add(volatile AO_t *addr, AO_t incr) {
AO_t oldval;
AO_t newval;
__asm__ __volatile__(
AO_PPC_L("1") AO_PPC_LxARX " %0,0,%2\n"
"add %1,%0,%3\n"
AO_PPC_STxCXd " %1,0,%2\n"
"bne- " AO_PPC_BR_A("1b", "$-12") "\n"
: "=&r"(oldval), "=&r"(newval)
: "r"(addr), "r"(incr)
: "memory", "cr0");
return oldval;
}
#define AO_HAVE_fetch_and_add
AO_INLINE AO_t
AO_fetch_and_add_acquire(volatile AO_t *addr, AO_t incr) {
AO_t result = AO_fetch_and_add(addr, incr);
AO_lwsync();
return result;
}
#define AO_HAVE_fetch_and_add_acquire
AO_INLINE AO_t
AO_fetch_and_add_release(volatile AO_t *addr, AO_t incr) {
AO_lwsync();
return AO_fetch_and_add(addr, incr);
}
#define AO_HAVE_fetch_and_add_release
AO_INLINE AO_t
AO_fetch_and_add_full(volatile AO_t *addr, AO_t incr) {
AO_t result;
AO_lwsync();
result = AO_fetch_and_add(addr, incr);
AO_lwsync();
return result;
}
#define AO_HAVE_fetch_and_add_full
#endif
#undef AO_PPC_BR_A
#undef AO_PPC_CMPx
#undef AO_PPC_L
#undef AO_PPC_LD
#undef AO_PPC_LOAD_CLOBBER
#undef AO_PPC_LxARX
#undef AO_PPC_STxCXd
#endif