linux-atomic.c (__kernel_cmpxchg2): New.

* config/pa/linux-atomic.c (__kernel_cmpxchg2): New.
	(FETCH_AND_OP_2): New.  Use for subword and double word operations.
	(OP_AND_FETCH_2): Likewise.
	(COMPARE_AND_SWAP_2): Likewise.
	(SYNC_LOCK_TEST_AND_SET_2): Likewise.
	(SYNC_LOCK_RELEASE_2): Likewise.
	(SUBWORD_SYNC_OP): Remove.
	(SUBWORD_VAL_CAS): Likewise.
	(SUBWORD_BOOL_CAS): Likewise.
	(FETCH_AND_OP_WORD): Update.
	Consistently use signed types.
	

Co-Authored-By: John David Anglin <danglin@gcc.gnu.org>

From-SVN: r217956
This commit is contained in:
Guy Martin 2014-11-22 01:18:49 +01:00 committed by John David Anglin
parent 16c31bcf02
commit 0cd7c67283
2 changed files with 176 additions and 141 deletions

View File

@ -1,3 +1,18 @@
2014-11-21 Guy Martin <gmsoft@tuxicoman.be>
John David Anglin <danglin@gcc.gnu.org>
* config/pa/linux-atomic.c (__kernel_cmpxchg2): New.
(FETCH_AND_OP_2): New. Use for subword and double word operations.
(OP_AND_FETCH_2): Likewise.
(COMPARE_AND_SWAP_2): Likewise.
(SYNC_LOCK_TEST_AND_SET_2): Likewise.
(SYNC_LOCK_RELEASE_2): Likewise.
(SUBWORD_SYNC_OP): Remove.
(SUBWORD_VAL_CAS): Likewise.
(SUBWORD_BOOL_CAS): Likewise.
(FETCH_AND_OP_WORD): Update.
Consistently use signed types.
2014-11-13 Bernd Schmidt <bernds@codesourcery.com>
Thomas Schwinge <thomas@codesourcery.com>
Ilya Verbin <ilya.verbin@intel.com>

View File

@ -45,7 +45,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#define ABORT_INSTRUCTION asm ("iitlbp %r0,(%sr0, %r0)")
/* Determine kernel LWS function call (0=32-bit, 1=64-bit userspace). */
#define LWS_CAS (sizeof(unsigned long) == 4 ? 0 : 1)
#define LWS_CAS (sizeof(long) == 4 ? 0 : 1)
/* Kernel helper for compare-and-exchange a 32-bit value. */
static inline long
@ -75,6 +75,30 @@ __kernel_cmpxchg (int oldval, int newval, int *mem)
return lws_errno;
}
static inline long
__kernel_cmpxchg2 (void * oldval, void * newval, void *mem, int val_size)
{
register unsigned long lws_mem asm("r26") = (unsigned long) (mem);
register long lws_ret asm("r28");
register long lws_errno asm("r21");
register unsigned long lws_old asm("r25") = (unsigned long) oldval;
register unsigned long lws_new asm("r24") = (unsigned long) newval;
register int lws_size asm("r23") = val_size;
asm volatile ( "ble 0xb0(%%sr2, %%r0) \n\t"
"ldi %2, %%r20 \n\t"
: "=r" (lws_ret), "=r" (lws_errno)
: "i" (2), "r" (lws_mem), "r" (lws_old), "r" (lws_new), "r" (lws_size)
: "r1", "r20", "r22", "r29", "r31", "fr4", "memory"
);
if (__builtin_expect (lws_errno == -EFAULT || lws_errno == -ENOSYS, 0))
ABORT_INSTRUCTION;
/* If the kernel LWS call fails, retrun EBUSY */
if (!lws_errno && lws_ret)
lws_errno = -EBUSY;
return lws_errno;
}
#define HIDDEN __attribute__ ((visibility ("hidden")))
/* Big endian masks */
@ -84,6 +108,80 @@ __kernel_cmpxchg (int oldval, int newval, int *mem)
#define MASK_1 0xffu
#define MASK_2 0xffffu
#define FETCH_AND_OP_2(OP, PFX_OP, INF_OP, TYPE, WIDTH, INDEX) \
TYPE HIDDEN \
__sync_fetch_and_##OP##_##WIDTH (TYPE *ptr, TYPE val) \
{ \
TYPE tmp, newval; \
int failure; \
\
do { \
tmp = *ptr; \
newval = PFX_OP (tmp INF_OP val); \
failure = __kernel_cmpxchg2 (&tmp, &newval, ptr, INDEX); \
} while (failure != 0); \
\
return tmp; \
}
FETCH_AND_OP_2 (add, , +, long long, 8, 3)
FETCH_AND_OP_2 (sub, , -, long long, 8, 3)
FETCH_AND_OP_2 (or, , |, long long, 8, 3)
FETCH_AND_OP_2 (and, , &, long long, 8, 3)
FETCH_AND_OP_2 (xor, , ^, long long, 8, 3)
FETCH_AND_OP_2 (nand, ~, &, long long, 8, 3)
FETCH_AND_OP_2 (add, , +, short, 2, 1)
FETCH_AND_OP_2 (sub, , -, short, 2, 1)
FETCH_AND_OP_2 (or, , |, short, 2, 1)
FETCH_AND_OP_2 (and, , &, short, 2, 1)
FETCH_AND_OP_2 (xor, , ^, short, 2, 1)
FETCH_AND_OP_2 (nand, ~, &, short, 2, 1)
FETCH_AND_OP_2 (add, , +, signed char, 1, 0)
FETCH_AND_OP_2 (sub, , -, signed char, 1, 0)
FETCH_AND_OP_2 (or, , |, signed char, 1, 0)
FETCH_AND_OP_2 (and, , &, signed char, 1, 0)
FETCH_AND_OP_2 (xor, , ^, signed char, 1, 0)
FETCH_AND_OP_2 (nand, ~, &, signed char, 1, 0)
#define OP_AND_FETCH_2(OP, PFX_OP, INF_OP, TYPE, WIDTH, INDEX) \
TYPE HIDDEN \
__sync_##OP##_and_fetch_##WIDTH (TYPE *ptr, TYPE val) \
{ \
TYPE tmp, newval; \
int failure; \
\
do { \
tmp = *ptr; \
newval = PFX_OP (tmp INF_OP val); \
failure = __kernel_cmpxchg2 (&tmp, &newval, ptr, INDEX); \
} while (failure != 0); \
\
return PFX_OP (tmp INF_OP val); \
}
OP_AND_FETCH_2 (add, , +, long long, 8, 3)
OP_AND_FETCH_2 (sub, , -, long long, 8, 3)
OP_AND_FETCH_2 (or, , |, long long, 8, 3)
OP_AND_FETCH_2 (and, , &, long long, 8, 3)
OP_AND_FETCH_2 (xor, , ^, long long, 8, 3)
OP_AND_FETCH_2 (nand, ~, &, long long, 8, 3)
OP_AND_FETCH_2 (add, , +, short, 2, 1)
OP_AND_FETCH_2 (sub, , -, short, 2, 1)
OP_AND_FETCH_2 (or, , |, short, 2, 1)
OP_AND_FETCH_2 (and, , &, short, 2, 1)
OP_AND_FETCH_2 (xor, , ^, short, 2, 1)
OP_AND_FETCH_2 (nand, ~, &, short, 2, 1)
OP_AND_FETCH_2 (add, , +, signed char, 1, 0)
OP_AND_FETCH_2 (sub, , -, signed char, 1, 0)
OP_AND_FETCH_2 (or, , |, signed char, 1, 0)
OP_AND_FETCH_2 (and, , &, signed char, 1, 0)
OP_AND_FETCH_2 (xor, , ^, signed char, 1, 0)
OP_AND_FETCH_2 (nand, ~, &, signed char, 1, 0)
#define FETCH_AND_OP_WORD(OP, PFX_OP, INF_OP) \
int HIDDEN \
__sync_fetch_and_##OP##_4 (int *ptr, int val) \
@ -105,48 +203,6 @@ FETCH_AND_OP_WORD (and, , &)
FETCH_AND_OP_WORD (xor, , ^)
FETCH_AND_OP_WORD (nand, ~, &)
#define NAME_oldval(OP, WIDTH) __sync_fetch_and_##OP##_##WIDTH
#define NAME_newval(OP, WIDTH) __sync_##OP##_and_fetch_##WIDTH
/* Implement both __sync_<op>_and_fetch and __sync_fetch_and_<op> for
subword-sized quantities. */
#define SUBWORD_SYNC_OP(OP, PFX_OP, INF_OP, TYPE, WIDTH, RETURN) \
TYPE HIDDEN \
NAME##_##RETURN (OP, WIDTH) (TYPE *ptr, TYPE val) \
{ \
int *wordptr = (int *) ((unsigned long) ptr & ~3); \
unsigned int mask, shift, oldval, newval; \
int failure; \
\
shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \
mask = MASK_##WIDTH << shift; \
\
do { \
oldval = *wordptr; \
newval = ((PFX_OP (((oldval & mask) >> shift) \
INF_OP (unsigned int) val)) << shift) & mask; \
newval |= oldval & ~mask; \
failure = __kernel_cmpxchg (oldval, newval, wordptr); \
} while (failure != 0); \
\
return (RETURN & mask) >> shift; \
}
SUBWORD_SYNC_OP (add, , +, unsigned short, 2, oldval)
SUBWORD_SYNC_OP (sub, , -, unsigned short, 2, oldval)
SUBWORD_SYNC_OP (or, , |, unsigned short, 2, oldval)
SUBWORD_SYNC_OP (and, , &, unsigned short, 2, oldval)
SUBWORD_SYNC_OP (xor, , ^, unsigned short, 2, oldval)
SUBWORD_SYNC_OP (nand, ~, &, unsigned short, 2, oldval)
SUBWORD_SYNC_OP (add, , +, unsigned char, 1, oldval)
SUBWORD_SYNC_OP (sub, , -, unsigned char, 1, oldval)
SUBWORD_SYNC_OP (or, , |, unsigned char, 1, oldval)
SUBWORD_SYNC_OP (and, , &, unsigned char, 1, oldval)
SUBWORD_SYNC_OP (xor, , ^, unsigned char, 1, oldval)
SUBWORD_SYNC_OP (nand, ~, &, unsigned char, 1, oldval)
#define OP_AND_FETCH_WORD(OP, PFX_OP, INF_OP) \
int HIDDEN \
__sync_##OP##_and_fetch_4 (int *ptr, int val) \
@ -168,19 +224,41 @@ OP_AND_FETCH_WORD (and, , &)
OP_AND_FETCH_WORD (xor, , ^)
OP_AND_FETCH_WORD (nand, ~, &)
SUBWORD_SYNC_OP (add, , +, unsigned short, 2, newval)
SUBWORD_SYNC_OP (sub, , -, unsigned short, 2, newval)
SUBWORD_SYNC_OP (or, , |, unsigned short, 2, newval)
SUBWORD_SYNC_OP (and, , &, unsigned short, 2, newval)
SUBWORD_SYNC_OP (xor, , ^, unsigned short, 2, newval)
SUBWORD_SYNC_OP (nand, ~, &, unsigned short, 2, newval)
typedef unsigned char bool;
SUBWORD_SYNC_OP (add, , +, unsigned char, 1, newval)
SUBWORD_SYNC_OP (sub, , -, unsigned char, 1, newval)
SUBWORD_SYNC_OP (or, , |, unsigned char, 1, newval)
SUBWORD_SYNC_OP (and, , &, unsigned char, 1, newval)
SUBWORD_SYNC_OP (xor, , ^, unsigned char, 1, newval)
SUBWORD_SYNC_OP (nand, ~, &, unsigned char, 1, newval)
#define COMPARE_AND_SWAP_2(TYPE, WIDTH, INDEX) \
TYPE HIDDEN \
__sync_val_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \
TYPE newval) \
{ \
TYPE actual_oldval; \
int fail; \
\
while (1) \
{ \
actual_oldval = *ptr; \
\
if (__builtin_expect (oldval != actual_oldval, 0)) \
return actual_oldval; \
\
fail = __kernel_cmpxchg2 (&actual_oldval, &newval, ptr, INDEX); \
\
if (__builtin_expect (!fail, 1)) \
return actual_oldval; \
} \
} \
\
bool HIDDEN \
__sync_bool_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \
TYPE newval) \
{ \
int failure = __kernel_cmpxchg2 (&oldval, &newval, ptr, INDEX); \
return (failure != 0); \
}
COMPARE_AND_SWAP_2 (long long, 8, 3)
COMPARE_AND_SWAP_2 (short, 2, 1)
COMPARE_AND_SWAP_2 (char, 1, 0)
int HIDDEN
__sync_val_compare_and_swap_4 (int *ptr, int oldval, int newval)
@ -201,41 +279,6 @@ __sync_val_compare_and_swap_4 (int *ptr, int oldval, int newval)
}
}
#define SUBWORD_VAL_CAS(TYPE, WIDTH) \
TYPE HIDDEN \
__sync_val_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \
TYPE newval) \
{ \
int *wordptr = (int *)((unsigned long) ptr & ~3), fail; \
unsigned int mask, shift, actual_oldval, actual_newval; \
\
shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \
mask = MASK_##WIDTH << shift; \
\
while (1) \
{ \
actual_oldval = *wordptr; \
\
if (__builtin_expect (((actual_oldval & mask) >> shift) \
!= (unsigned int) oldval, 0)) \
return (actual_oldval & mask) >> shift; \
\
actual_newval = (actual_oldval & ~mask) \
| (((unsigned int) newval << shift) & mask); \
\
fail = __kernel_cmpxchg (actual_oldval, actual_newval, \
wordptr); \
\
if (__builtin_expect (!fail, 1)) \
return (actual_oldval & mask) >> shift; \
} \
}
SUBWORD_VAL_CAS (unsigned short, 2)
SUBWORD_VAL_CAS (unsigned char, 1)
typedef unsigned char bool;
bool HIDDEN
__sync_bool_compare_and_swap_4 (int *ptr, int oldval, int newval)
{
@ -243,18 +286,24 @@ __sync_bool_compare_and_swap_4 (int *ptr, int oldval, int newval)
return (failure == 0);
}
#define SUBWORD_BOOL_CAS(TYPE, WIDTH) \
bool HIDDEN \
__sync_bool_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \
TYPE newval) \
#define SYNC_LOCK_TEST_AND_SET_2(TYPE, WIDTH, INDEX) \
TYPE HIDDEN \
__sync_lock_test_and_set_##WIDTH (TYPE *ptr, TYPE val) \
{ \
TYPE actual_oldval \
= __sync_val_compare_and_swap_##WIDTH (ptr, oldval, newval); \
return (oldval == actual_oldval); \
TYPE oldval; \
int failure; \
\
do { \
oldval = *ptr; \
failure = __kernel_cmpxchg2 (&oldval, &val, ptr, INDEX); \
} while (failure != 0); \
\
return oldval; \
}
SUBWORD_BOOL_CAS (unsigned short, 2)
SUBWORD_BOOL_CAS (unsigned char, 1)
SYNC_LOCK_TEST_AND_SET_2 (long long, 8, 3)
SYNC_LOCK_TEST_AND_SET_2 (short, 2, 1)
SYNC_LOCK_TEST_AND_SET_2 (signed char, 1, 0)
int HIDDEN
__sync_lock_test_and_set_4 (int *ptr, int val)
@ -269,29 +318,21 @@ __sync_lock_test_and_set_4 (int *ptr, int val)
return oldval;
}
#define SUBWORD_TEST_AND_SET(TYPE, WIDTH) \
TYPE HIDDEN \
__sync_lock_test_and_set_##WIDTH (TYPE *ptr, TYPE val) \
{ \
int failure; \
unsigned int oldval, newval, shift, mask; \
int *wordptr = (int *) ((unsigned long) ptr & ~3); \
\
shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \
mask = MASK_##WIDTH << shift; \
\
do { \
oldval = *wordptr; \
newval = (oldval & ~mask) \
| (((unsigned int) val << shift) & mask); \
failure = __kernel_cmpxchg (oldval, newval, wordptr); \
} while (failure != 0); \
\
return (oldval & mask) >> shift; \
#define SYNC_LOCK_RELEASE_2(TYPE, WIDTH, INDEX) \
void HIDDEN \
__sync_lock_release_##WIDTH (TYPE *ptr) \
{ \
TYPE failure, oldval, zero = 0; \
\
do { \
oldval = *ptr; \
failure = __kernel_cmpxchg2 (&oldval, &zero, ptr, INDEX); \
} while (failure != 0); \
}
SUBWORD_TEST_AND_SET (unsigned short, 2)
SUBWORD_TEST_AND_SET (unsigned char, 1)
SYNC_LOCK_RELEASE_2 (long long, 8, 3)
SYNC_LOCK_RELEASE_2 (short, 2, 1)
SYNC_LOCK_RELEASE_2 (signed char, 1, 0)
void HIDDEN
__sync_lock_release_4 (int *ptr)
@ -303,24 +344,3 @@ __sync_lock_release_4 (int *ptr)
failure = __kernel_cmpxchg (oldval, 0, ptr);
} while (failure != 0);
}
#define SYNC_LOCK_RELEASE(TYPE, WIDTH) \
void HIDDEN \
__sync_lock_release_##WIDTH (TYPE *ptr) \
{ \
int failure; \
unsigned int oldval, newval, shift, mask; \
int *wordptr = (int *) ((unsigned long) ptr & ~3); \
\
shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \
mask = MASK_##WIDTH << shift; \
\
do { \
oldval = *wordptr; \
newval = oldval & ~mask; \
failure = __kernel_cmpxchg (oldval, newval, wordptr); \
} while (failure != 0); \
}
SYNC_LOCK_RELEASE (short, 2)
SYNC_LOCK_RELEASE (char, 1)