/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
/*
* (C) 2008 by Argonne National Laboratory.
* See COPYRIGHT in top-level directory.
*/
#ifndef OPA_GCC_INTEL_32_64_OPS_H_INCLUDED
#define OPA_GCC_INTEL_32_64_OPS_H_INCLUDED
#ifndef OPA_SIZEOF_INT
#error OPA_SIZEOF_INT is not defined
#endif
/* Set OPA_SS (Size Suffix) which is to be appended to asm ops for
specifying 4 or 8 byte operands */
#if OPA_SIZEOF_INT == 4
#define OPA_SS "l"
#elif OPA_SIZEOF_INT == 8
#define OPA_SS "q"
#else
#error OPA_SIZEOF_INT is not 4 or 8
#endif
/* XXX DJG FIXME do we need to align these? */
typedef struct {
volatile int v;
} OPA_int_t;
typedef struct {
void *volatile v;
} OPA_ptr_t;
#define OPA_INT_T_INITIALIZER(val_) { (val_) }
#define OPA_PTR_T_INITIALIZER(val_) { (val_) }
/* Aligned loads and stores are atomic on x86(-64). */
static _opa_inline int OPA_load_int(_opa_const OPA_int_t * ptr)
{
return ptr->v;
}
/* Aligned loads and stores are atomic on x86(-64). */
static _opa_inline void OPA_store_int(OPA_int_t * ptr, int val)
{
ptr->v = val;
}
/* Aligned loads and stores are atomic on x86(-64). */
static _opa_inline void *OPA_load_ptr(_opa_const OPA_ptr_t * ptr)
{
return ptr->v;
}
/* Aligned loads and stores are atomic on x86(-64). */
static _opa_inline void OPA_store_ptr(OPA_ptr_t * ptr, void *val)
{
ptr->v = val;
}
/* NOTE-X86-1 x86 and x86_64 processors execute instructions such that their
* effects are visible in issue order, with one exception: earlier stores may
* pass later loads. Also, non-temporal stores (with the "movnt*" instructions)
* do not follow these ordering constraints. So all normal load/store
* instructions on x86(_64) already have acquire/release semantics. We just
* have to make sure that the compiler does not reorder the instructions. */
static _opa_inline int OPA_load_acquire_int(_opa_const OPA_int_t * ptr)
{
int tmp;
tmp = ptr->v;
OPA_compiler_barrier(); /* NOTE-X86-1 */
return tmp;
}
static _opa_inline void OPA_store_release_int(OPA_int_t * ptr, int val)
{
OPA_compiler_barrier(); /* NOTE-X86-1 */
ptr->v = val;
}
static _opa_inline void *OPA_load_acquire_ptr(_opa_const OPA_ptr_t * ptr)
{
void *tmp;
tmp = ptr->v;
OPA_compiler_barrier(); /* NOTE-X86-1 */
return tmp;
}
static _opa_inline void OPA_store_release_ptr(OPA_ptr_t * ptr, void *val)
{
OPA_compiler_barrier(); /* NOTE-X86-1 */
ptr->v = val;
}
static _opa_inline void OPA_add_int(OPA_int_t * ptr, int val)
{
__asm__ __volatile__("lock ; add" OPA_SS " %1,%0":"=m"(ptr->v)
:"ir"(val), "m"(ptr->v));
return;
}
static _opa_inline void OPA_incr_int(OPA_int_t * ptr)
{
__asm__ __volatile__("lock ; inc" OPA_SS " %0":"=m"(ptr->v)
:"m"(ptr->v));
return;
}
static _opa_inline void OPA_decr_int(OPA_int_t * ptr)
{
__asm__ __volatile__("lock ; dec" OPA_SS " %0":"=m"(ptr->v)
:"m"(ptr->v));
return;
}
static _opa_inline int OPA_decr_and_test_int(OPA_int_t * ptr)
{
char result;
__asm__ __volatile__("lock ; dec" OPA_SS " %0; setz %1":"=m"(ptr->v), "=q"(result)
:"m"(ptr->v));
return result;
}
static _opa_inline int OPA_fetch_and_add_int(OPA_int_t * ptr, int val)
{
__asm__ __volatile__("lock ; xadd %0,%1":"=r"(val), "=m"(ptr->v)
:"0"(val), "m"(ptr->v));
return val;
}
#define OPA_fetch_and_incr_int_by_faa OPA_fetch_and_incr_int
#define OPA_fetch_and_decr_int_by_faa OPA_fetch_and_decr_int
static _opa_inline void *OPA_cas_ptr(OPA_ptr_t * ptr, void *oldv, void *newv)
{
void *prev;
__asm__ __volatile__("lock ; cmpxchg %3,%4":"=a"(prev), "=m"(ptr->v)
:"0"(oldv), "q"(newv), "m"(ptr->v));
return prev;
}
static _opa_inline int OPA_cas_int(OPA_int_t * ptr, int oldv, int newv)
{
int prev;
__asm__ __volatile__("lock ; cmpxchg %3,%4":"=a"(prev), "=m"(ptr->v)
:"0"(oldv), "q"(newv), "m"(ptr->v));
return prev;
}
static _opa_inline void *OPA_swap_ptr(OPA_ptr_t * ptr, void *val)
{
__asm__ __volatile__("xchg %0,%1":"=r"(val), "=m"(ptr->v)
:"0"(val), "m"(ptr->v));
return val;
}
static _opa_inline int OPA_swap_int(OPA_int_t * ptr, int val)
{
__asm__ __volatile__("xchg %0,%1":"=r"(val), "=m"(ptr->v)
:"0"(val), "m"(ptr->v));
return val;
}
#undef OPA_SS
#endif /* OPA_GCC_INTEL_32_64_OPS_H_INCLUDED */