Add atomic_fcmpset_*() inlines for MIPS

atomic_fcmpset_*() is analogous to atomic_cmpset(), but saves off the
read value from the target memory location into the 'old' pointer.

Reviewed by:	imp, brooks
Requested by:	mjg
Differential Revision:	https://reviews.freebsd.org/D9391
This commit is contained in:
Alexander Kabaev 2017-02-01 05:00:34 +00:00
parent 65ed483615
commit 2733239f37

View File

@ -362,7 +362,7 @@ atomic_load_64(__volatile uint64_t *p, uint64_t *v)
* zero if the compare failed, nonzero otherwise.
*/
static __inline uint32_t
atomic_cmpset_32(__volatile uint32_t* p, uint32_t cmpval, uint32_t newval)
atomic_cmpset_32(__volatile uint32_t *p, uint32_t cmpval, uint32_t newval)
{
uint32_t ret;
@ -405,6 +405,46 @@ atomic_cmpset_rel_32(__volatile uint32_t *p, uint32_t cmpval, uint32_t newval)
return (atomic_cmpset_32(p, cmpval, newval));
}
static __inline uint32_t
atomic_fcmpset_32(__volatile uint32_t *p, uint32_t *cmpval, uint32_t newval)
{
uint32_t ret;
__asm __volatile (
"1:\n\t"
"ll %0, %1\n\t" /* load old value */
"bne %0, %4, 2f\n\t" /* compare */
"move %0, %3\n\t" /* value to store */
"sc %0, %1\n\t" /* attempt to store */
"beqz %0, 1b\n\t" /* if it failed, spin */
"j 3f\n\t"
"2:\n\t"
"sw %0, %2\n\t" /* save old value */
"li %0, 0\n\t"
"3:\n"
: "=&r" (ret), "+m" (*p), "=m" (*cmpval)
: "r" (newval), "r" (*cmpval)
: "memory");
return ret;
}
static __inline uint32_t
atomic_fcmpset_acq_32(__volatile uint32_t *p, uint32_t *cmpval, uint32_t newval)
{
int retval;
retval = atomic_fcmpset_32(p, cmpval, newval);
mips_sync();
return (retval);
}
static __inline uint32_t
atomic_fcmpset_rel_32(__volatile uint32_t *p, uint32_t *cmpval, uint32_t newval)
{
mips_sync();
return (atomic_fcmpset_32(p, cmpval, newval));
}
/*
* Atomically add the value of v to the integer pointed to by p and return
* the previous value of *p.
@ -431,7 +471,7 @@ atomic_fetchadd_32(__volatile uint32_t *p, uint32_t v)
* zero if the compare failed, nonzero otherwise.
*/
static __inline uint64_t
atomic_cmpset_64(__volatile uint64_t* p, uint64_t cmpval, uint64_t newval)
atomic_cmpset_64(__volatile uint64_t *p, uint64_t cmpval, uint64_t newval)
{
uint64_t ret;
@ -475,6 +515,47 @@ atomic_cmpset_rel_64(__volatile uint64_t *p, uint64_t cmpval, uint64_t newval)
return (atomic_cmpset_64(p, cmpval, newval));
}
static __inline uint32_t
atomic_fcmpset_64(__volatile uint64_t *p, uint64_t *cmpval, uint64_t newval)
{
uint32_t ret;
__asm __volatile (
"1:\n\t"
"lld %0, %1\n\t" /* load old value */
"bne %0, %4, 2f\n\t" /* compare */
"move %0, %3\n\t" /* value to store */
"scd %0, %1\n\t" /* attempt to store */
"beqz %0, 1b\n\t" /* if it failed, spin */
"j 3f\n\t"
"2:\n\t"
"sw %0, %2\n\t" /* save old value */
"li %0, 0\n\t"
"3:\n"
: "=&r" (ret), "+m" (*p), "=m" (*cmpval)
: "r" (newval), "r" (*cmpval)
: "memory");
return ret;
}
static __inline uint64_t
atomic_fcmpset_acq_64(__volatile uint64_t *p, uint64_t *cmpval, uint64_t newval)
{
int retval;
retval = atomic_fcmpset_64(p, cmpval, newval);
mips_sync();
return (retval);
}
static __inline uint64_t
atomic_fcmpset_rel_64(__volatile uint64_t *p, uint64_t *cmpval, uint64_t newval)
{
mips_sync();
return (atomic_fcmpset_64(p, cmpval, newval));
}
/*
* Atomically add the value of v to the integer pointed to by p and return
* the previous value of *p.
@ -568,6 +649,9 @@ atomic_thread_fence_seq_cst(void)
#define atomic_cmpset_int atomic_cmpset_32
#define atomic_cmpset_acq_int atomic_cmpset_acq_32
#define atomic_cmpset_rel_int atomic_cmpset_rel_32
#define atomic_fcmpset_int atomic_fcmpset_32
#define atomic_fcmpset_acq_int atomic_fcmpset_acq_32
#define atomic_fcmpset_rel_int atomic_fcmpset_rel_32
#define atomic_load_acq_int atomic_load_acq_32
#define atomic_store_rel_int atomic_store_rel_32
#define atomic_readandclear_int atomic_readandclear_32
@ -597,6 +681,9 @@ atomic_thread_fence_seq_cst(void)
#define atomic_cmpset_long atomic_cmpset_64
#define atomic_cmpset_acq_long atomic_cmpset_acq_64
#define atomic_cmpset_rel_long atomic_cmpset_rel_64
#define atomic_fcmpset_long atomic_fcmpset_64
#define atomic_fcmpset_acq_long atomic_fcmpset_acq_64
#define atomic_fcmpset_rel_long atomic_fcmpset_rel_64
#define atomic_load_acq_long atomic_load_acq_64
#define atomic_store_rel_long atomic_store_rel_64
#define atomic_fetchadd_long atomic_fetchadd_64
@ -638,6 +725,15 @@ atomic_thread_fence_seq_cst(void)
#define atomic_cmpset_rel_long(p, cmpval, newval) \
atomic_cmpset_rel_32((volatile u_int *)(p), (u_int)(cmpval), \
(u_int)(newval))
#define atomic_fcmpset_long(p, cmpval, newval) \
atomic_fcmpset_32((volatile u_int *)(p), (u_int *)(cmpval), \
(u_int)(newval))
#define atomic_fcmpset_acq_long(p, cmpval, newval) \
atomic_fcmpset_acq_32((volatile u_int *)(p), (u_int *)(cmpval), \
(u_int)(newval))
#define atomic_fcmpset_rel_long(p, cmpval, newval) \
atomic_fcmpset_rel_32((volatile u_int *)(p), (u_int *)(cmpval), \
(u_int)(newval))
#define atomic_load_acq_long(p) \
(u_long)atomic_load_acq_32((volatile u_int *)(p))
#define atomic_store_rel_long(p, v) \
@ -665,6 +761,9 @@ atomic_thread_fence_seq_cst(void)
#define atomic_cmpset_ptr atomic_cmpset_long
#define atomic_cmpset_acq_ptr atomic_cmpset_acq_long
#define atomic_cmpset_rel_ptr atomic_cmpset_rel_long
#define atomic_fcmpset_ptr atomic_fcmpset_long
#define atomic_fcmpset_acq_ptr atomic_fcmpset_acq_long
#define atomic_fcmpset_rel_ptr atomic_fcmpset_rel_long
#define atomic_load_acq_ptr atomic_load_acq_long
#define atomic_store_rel_ptr atomic_store_rel_long
#define atomic_readandclear_ptr atomic_readandclear_long