This is the mail archive of the
libc-ports@sources.redhat.com
mailing list for the libc-ports project.
[PATCH 1/3, MIPS] Rewrite MIPS' atomic.h to use __atomic_* builtins.
- From: Maxim Kuvyrkov <maxim at codesourcery dot com>
- To: "Joseph S. Myers" <joseph at codesourcery dot com>
- Cc: <libc-ports at sourceware dot org>, Richard Sandiford <rdsandiford at googlemail dot com>
- Date: Thu, 14 Jun 2012 16:26:43 +1200
- Subject: [PATCH 1/3, MIPS] Rewrite MIPS' atomic.h to use __atomic_* builtins.
This patch rewrites MIPS' atomic.h to use __atomic_* builtins instead of inline assembly. These builtins are available in recent version of GCC and correspond to C++11 memory model support, they also map very well to GLIBC's atomic_* macros.
With the GCC patches posted here [*] applied, the compiler will generate same, or better, assembly code for the atomic macros. XLP processors in particular will see a significant boost as GCC will use XLP-specific SWAP and LDADD instructions for some of the macros instead of LL/SC sequences.
This patch was tested on XLP with no regressions; testing on a non-XLP platform is in progress. Testing was done using GCC mainline with [*] patches applied. OK to apply once 2.16 branches?
Thank you,
--
Maxim Kuvyrkov
CodeSourcery / Mentor Graphics
2012-06-14 Tom de Vries <vries@codesourcery.com>
Maxim Kuvyrkov <maxim@codesourcery.com>
* sysdeps/mips/bit/atomic.h: Rewrite using __atomic_* builtins.
---
sysdeps/mips/bits/atomic.h | 297 +++++++++++++++++---------------------------
1 files changed, 114 insertions(+), 183 deletions(-)
diff --git a/sysdeps/mips/bits/atomic.h b/sysdeps/mips/bits/atomic.h
index 4d51d7f..99d5db1 100644
--- a/sysdeps/mips/bits/atomic.h
+++ b/sysdeps/mips/bits/atomic.h
@@ -1,5 +1,5 @@
/* Low-level functions for atomic operations. Mips version.
- Copyright (C) 2005 Free Software Foundation, Inc.
+ Copyright (C) 2005-2012 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -78,243 +78,174 @@ typedef uintmax_t uatomic_max_t;
#define MIPS_SYNC_STR_1(X) MIPS_SYNC_STR_2(X)
#define MIPS_SYNC_STR MIPS_SYNC_STR_1(MIPS_SYNC)
-/* Compare and exchange. For all of the "xxx" routines, we expect a
- "__prev" and a "__cmp" variable to be provided by the enclosing scope,
- in which values are returned. */
-
-#define __arch_compare_and_exchange_xxx_8_int(mem, newval, oldval, rel, acq) \
- (abort (), __prev = __cmp = 0)
-
-#define __arch_compare_and_exchange_xxx_16_int(mem, newval, oldval, rel, acq) \
- (abort (), __prev = __cmp = 0)
-
-#define __arch_compare_and_exchange_xxx_32_int(mem, newval, oldval, rel, acq) \
- __asm__ __volatile__ ( \
- ".set push\n\t" \
- MIPS_PUSH_MIPS2 \
- rel "\n" \
- "1:\t" \
- "ll %0,%5\n\t" \
- "move %1,$0\n\t" \
- "bne %0,%3,2f\n\t" \
- "move %1,%4\n\t" \
- "sc %1,%2\n\t" \
- R10K_BEQZ_INSN" %1,1b\n" \
- acq "\n\t" \
- ".set pop\n" \
- "2:\n\t" \
- : "=&r" (__prev), "=&r" (__cmp), "=m" (*mem) \
- : "r" (oldval), "r" (newval), "m" (*mem) \
- : "memory")
+/* Compare and exchange.
+ For all "bool" routines, we return FALSE if exchange succesful. */
-#if _MIPS_SIM == _ABIO32
-/* We can't do an atomic 64-bit operation in O32. */
-#define __arch_compare_and_exchange_xxx_64_int(mem, newval, oldval, rel, acq) \
- (abort (), __prev = __cmp = 0)
-#else
-#define __arch_compare_and_exchange_xxx_64_int(mem, newval, oldval, rel, acq) \
- __asm__ __volatile__ ("\n" \
- ".set push\n\t" \
- MIPS_PUSH_MIPS2 \
- rel "\n" \
- "1:\t" \
- "lld %0,%5\n\t" \
- "move %1,$0\n\t" \
- "bne %0,%3,2f\n\t" \
- "move %1,%4\n\t" \
- "scd %1,%2\n\t" \
- R10K_BEQZ_INSN" %1,1b\n" \
- acq "\n\t" \
- ".set pop\n" \
- "2:\n\t" \
- : "=&r" (__prev), "=&r" (__cmp), "=m" (*mem) \
- : "r" (oldval), "r" (newval), "m" (*mem) \
- : "memory")
-#endif
+#define __arch_compare_and_exchange_bool_acq_8_int(mem, newval, oldval) \
+ (abort (), 0)
-/* For all "bool" routines, we return FALSE if exchange succesful. */
+#define __arch_compare_and_exchange_bool_rel_8_int(mem, newval, oldval) \
+ (abort (), 0)
-#define __arch_compare_and_exchange_bool_8_int(mem, new, old, rel, acq) \
-({ typeof (*mem) __prev; int __cmp; \
- __arch_compare_and_exchange_xxx_8_int(mem, new, old, rel, acq); \
- !__cmp; })
+#define __arch_compare_and_exchange_bool_acq_16_int(mem, newval, oldval) \
+ (abort (), 0)
-#define __arch_compare_and_exchange_bool_16_int(mem, new, old, rel, acq) \
-({ typeof (*mem) __prev; int __cmp; \
- __arch_compare_and_exchange_xxx_16_int(mem, new, old, rel, acq); \
- !__cmp; })
+#define __arch_compare_and_exchange_bool_rel_16_int(mem, newval, oldval) \
+ (abort (), 0)
-#define __arch_compare_and_exchange_bool_32_int(mem, new, old, rel, acq) \
-({ typeof (*mem) __prev; int __cmp; \
- __arch_compare_and_exchange_xxx_32_int(mem, new, old, rel, acq); \
- !__cmp; })
+#define __arch_compare_and_exchange_bool_acq_32_int(mem, newval, oldval) \
+ ({ \
+ typeof (*mem) __oldval = (oldval); \
+ !__atomic_compare_exchange_n (mem, &__oldval, newval, 0, \
+ __ATOMIC_ACQUIRE, __ATOMIC_RELAXED); \
+ })
+
+#define __arch_compare_and_exchange_bool_rel_32_int(mem, newval, oldval) \
+ ({ \
+ typeof (*mem) __oldval = (oldval); \
+ !__atomic_compare_exchange_n (mem, &__oldval, newval, 0, \
+ __ATOMIC_RELEASE, __ATOMIC_RELAXED); \
+ })
+
+#define __arch_compare_and_exchange_val_acq_8_int(mem, newval, oldval) \
+ (abort (), 0)
+
+#define __arch_compare_and_exchange_val_rel_8_int(mem, newval, oldval) \
+ (abort (), 0)
+
+#define __arch_compare_and_exchange_val_acq_16_int(mem, newval, oldval) \
+ (abort (), 0)
+
+#define __arch_compare_and_exchange_val_rel_16_int(mem, newval, oldval) \
+ (abort (), 0)
-#define __arch_compare_and_exchange_bool_64_int(mem, new, old, rel, acq) \
-({ typeof (*mem) __prev; int __cmp; \
- __arch_compare_and_exchange_xxx_64_int(mem, new, old, rel, acq); \
- !__cmp; })
+#define __arch_compare_and_exchange_val_acq_32_int(mem, newval, oldval) \
+ ({ \
+ typeof (*mem) __oldval = (oldval); \
+ __atomic_compare_exchange_n (mem, &__oldval, newval, 0, \
+ __ATOMIC_ACQUIRE, __ATOMIC_RELAXED); \
+ __oldval; \
+ })
+
+#define __arch_compare_and_exchange_val_rel_32_int(mem, newval, oldval) \
+ ({ \
+ typeof (*mem) __oldval = (oldval); \
+ __atomic_compare_exchange_n (mem, &__oldval, newval, 0, \
+ __ATOMIC_RELEASE, __ATOMIC_RELAXED); \
+ __oldval; \
+ })
-/* For all "val" routines, return the old value whether exchange
- successful or not. */
+#if _MIPS_SIM == _ABIO32
+ /* We can't do an atomic 64-bit operation in O32. */
+# define __arch_compare_and_exchange_bool_acq_64_int(mem, newval, oldval) \
+ (abort (), 0)
+# define __arch_compare_and_exchange_bool_rel_64_int(mem, newval, oldval) \
+ (abort (), 0)
+# define __arch_compare_and_exchange_val_acq_64_int(mem, newval, oldval) \
+ (abort (), 0)
+# define __arch_compare_and_exchange_val_rel_64_int(mem, newval, oldval) \
+ (abort (), 0)
+#else
+# define __arch_compare_and_exchange_bool_acq_64_int(mem, newval, oldval) \
+ __arch_compare_and_exchange_bool_acq_32_int (mem, newval, oldval)
-#define __arch_compare_and_exchange_val_8_int(mem, new, old, rel, acq) \
-({ typeof (*mem) __prev; int __cmp; \
- __arch_compare_and_exchange_xxx_8_int(mem, new, old, rel, acq); \
- (typeof (*mem))__prev; })
+# define __arch_compare_and_exchange_bool_rel_64_int(mem, newval, oldval) \
+ __arch_compare_and_exchange_bool_rel_32_int (mem, newval, oldval)
-#define __arch_compare_and_exchange_val_16_int(mem, new, old, rel, acq) \
-({ typeof (*mem) __prev; int __cmp; \
- __arch_compare_and_exchange_xxx_16_int(mem, new, old, rel, acq); \
- (typeof (*mem))__prev; })
+# define __arch_compare_and_exchange_val_acq_64_int(mem, newval, oldval) \
+ __arch_compare_and_exchange_val_acq_32_int (mem, newval, oldval)
-#define __arch_compare_and_exchange_val_32_int(mem, new, old, rel, acq) \
-({ typeof (*mem) __prev; int __cmp; \
- __arch_compare_and_exchange_xxx_32_int(mem, new, old, rel, acq); \
- (typeof (*mem))__prev; })
+# define __arch_compare_and_exchange_val_rel_64_int(mem, newval, oldval) \
+ __arch_compare_and_exchange_val_rel_32_int (mem, newval, oldval)
-#define __arch_compare_and_exchange_val_64_int(mem, new, old, rel, acq) \
-({ typeof (*mem) __prev; int __cmp; \
- __arch_compare_and_exchange_xxx_64_int(mem, new, old, rel, acq); \
- (typeof (*mem))__prev; })
+#endif
/* Compare and exchange with "acquire" semantics, ie barrier after. */
-#define atomic_compare_and_exchange_bool_acq(mem, new, old) \
- __atomic_bool_bysize (__arch_compare_and_exchange_bool, int, \
- mem, new, old, "", MIPS_SYNC_STR)
+#define atomic_compare_and_exchange_bool_acq(mem, new, old) \
+ (__atomic_bool_bysize (__arch_compare_and_exchange_bool_acq, int, \
+ mem, new, old))
-#define atomic_compare_and_exchange_val_acq(mem, new, old) \
- __atomic_val_bysize (__arch_compare_and_exchange_val, int, \
- mem, new, old, "", MIPS_SYNC_STR)
+#define atomic_compare_and_exchange_val_acq(mem, new, old) \
+ __atomic_val_bysize (__arch_compare_and_exchange_val_acq, int, \
+ mem, new, old)
/* Compare and exchange with "release" semantics, ie barrier before. */
-#define atomic_compare_and_exchange_bool_rel(mem, new, old) \
- __atomic_bool_bysize (__arch_compare_and_exchange_bool, int, \
- mem, new, old, MIPS_SYNC_STR, "")
-
-#define atomic_compare_and_exchange_val_rel(mem, new, old) \
- __atomic_val_bysize (__arch_compare_and_exchange_val, int, \
- mem, new, old, MIPS_SYNC_STR, "")
+#define atomic_compare_and_exchange_bool_rel(mem, new, old) \
+ (__atomic_bool_bysize (__arch_compare_and_exchange_bool_rel, int, \
+ mem, new, old))
+#define atomic_compare_and_exchange_val_rel(mem, new, old) \
+ __atomic_val_bysize (__arch_compare_and_exchange_val_rel, int, \
+ mem, new, old)
/* Atomic exchange (without compare). */
-#define __arch_exchange_xxx_8_int(mem, newval, rel, acq) \
+#define __arch_exchange_acq_8_int(mem, newval) \
(abort (), 0)
-#define __arch_exchange_xxx_16_int(mem, newval, rel, acq) \
+#define __arch_exchange_rel_8_int(mem, newval) \
(abort (), 0)
-#define __arch_exchange_xxx_32_int(mem, newval, rel, acq) \
-({ typeof (*mem) __prev; int __cmp; \
- __asm__ __volatile__ ("\n" \
- ".set push\n\t" \
- MIPS_PUSH_MIPS2 \
- rel "\n" \
- "1:\t" \
- "ll %0,%4\n\t" \
- "move %1,%3\n\t" \
- "sc %1,%2\n\t" \
- R10K_BEQZ_INSN" %1,1b\n" \
- acq "\n\t" \
- ".set pop\n" \
- "2:\n\t" \
- : "=&r" (__prev), "=&r" (__cmp), "=m" (*mem) \
- : "r" (newval), "m" (*mem) \
- : "memory"); \
- __prev; })
+#define __arch_exchange_acq_16_int(mem, newval) \
+ (abort (), 0)
+
+#define __arch_exchange_rel_16_int(mem, newval) \
+ (abort (), 0)
+
+#define __arch_exchange_acq_32_int(mem, newval) \
+ __atomic_exchange_n (mem, newval, __ATOMIC_ACQUIRE)
+
+#define __arch_exchange_rel_32_int(mem, newval) \
+ __atomic_exchange_n (mem, newval, __ATOMIC_RELEASE)
#if _MIPS_SIM == _ABIO32
/* We can't do an atomic 64-bit operation in O32. */
-#define __arch_exchange_xxx_64_int(mem, newval, rel, acq) \
+# define __arch_exchange_acq_64_int(mem, newval) \
+ (abort (), 0)
+# define __arch_exchange_rel_64_int(mem, newval) \
(abort (), 0)
#else
-#define __arch_exchange_xxx_64_int(mem, newval, rel, acq) \
-({ typeof (*mem) __prev; int __cmp; \
- __asm__ __volatile__ ("\n" \
- ".set push\n\t" \
- MIPS_PUSH_MIPS2 \
- rel "\n" \
- "1:\n" \
- "lld %0,%4\n\t" \
- "move %1,%3\n\t" \
- "scd %1,%2\n\t" \
- R10K_BEQZ_INSN" %1,1b\n" \
- acq "\n\t" \
- ".set pop\n" \
- "2:\n\t" \
- : "=&r" (__prev), "=&r" (__cmp), "=m" (*mem) \
- : "r" (newval), "m" (*mem) \
- : "memory"); \
- __prev; })
+# define __arch_exchange_acq_64_int(mem, newval) \
+ __atomic_exchange_n (mem, newval, __ATOMIC_ACQUIRE)
+
+# define __arch_exchange_rel_64_int(mem, newval) \
+ __atomic_exchange_n (mem, newval, __ATOMIC_RELEASE)
#endif
#define atomic_exchange_acq(mem, value) \
- __atomic_val_bysize (__arch_exchange_xxx, int, mem, value, "", MIPS_SYNC_STR)
+ __atomic_val_bysize (__arch_exchange_acq, int, mem, value)
#define atomic_exchange_rel(mem, value) \
- __atomic_val_bysize (__arch_exchange_xxx, int, mem, value, MIPS_SYNC_STR, "")
+ __atomic_val_bysize (__arch_exchange_rel, int, mem, value)
/* Atomically add value and return the previous (unincremented) value. */
-#define __arch_exchange_and_add_8_int(mem, newval, rel, acq) \
+#define __arch_exchange_and_add_8_int(mem, newval) \
(abort (), (typeof(*mem)) 0)
-#define __arch_exchange_and_add_16_int(mem, newval, rel, acq) \
+#define __arch_exchange_and_add_16_int(mem, newval) \
(abort (), (typeof(*mem)) 0)
-#define __arch_exchange_and_add_32_int(mem, value, rel, acq) \
-({ typeof (*mem) __prev; int __cmp; \
- __asm__ __volatile__ ("\n" \
- ".set push\n\t" \
- MIPS_PUSH_MIPS2 \
- rel "\n" \
- "1:\t" \
- "ll %0,%4\n\t" \
- "addu %1,%0,%3\n\t" \
- "sc %1,%2\n\t" \
- R10K_BEQZ_INSN" %1,1b\n" \
- acq "\n\t" \
- ".set pop\n" \
- "2:\n\t" \
- : "=&r" (__prev), "=&r" (__cmp), "=m" (*mem) \
- : "r" (value), "m" (*mem) \
- : "memory"); \
- __prev; })
+#define __arch_exchange_and_add_32_int(mem, value) \
+ __atomic_fetch_add (mem, value, __ATOMIC_ACQ_REL)
#if _MIPS_SIM == _ABIO32
/* We can't do an atomic 64-bit operation in O32. */
-#define __arch_exchange_and_add_64_int(mem, value, rel, acq) \
+# define __arch_exchange_and_add_64_int(mem, value) \
(abort (), (typeof(*mem)) 0)
#else
-#define __arch_exchange_and_add_64_int(mem, value, rel, acq) \
-({ typeof (*mem) __prev; int __cmp; \
- __asm__ __volatile__ ( \
- ".set push\n\t" \
- MIPS_PUSH_MIPS2 \
- rel "\n" \
- "1:\t" \
- "lld %0,%4\n\t" \
- "daddu %1,%0,%3\n\t" \
- "scd %1,%2\n\t" \
- R10K_BEQZ_INSN" %1,1b\n" \
- acq "\n\t" \
- ".set pop\n" \
- "2:\n\t" \
- : "=&r" (__prev), "=&r" (__cmp), "=m" (*mem) \
- : "r" (value), "m" (*mem) \
- : "memory"); \
- __prev; })
+# define __arch_exchange_and_add_64_int(mem, value) \
+ __atomic_fetch_add (mem, value, __ATOMIC_ACQ_REL)
#endif
/* ??? Barrier semantics for atomic_exchange_and_add appear to be
undefined. Use full barrier for now, as that's safe. */
#define atomic_exchange_and_add(mem, value) \
- __atomic_val_bysize (__arch_exchange_and_add, int, mem, value, \
- MIPS_SYNC_STR, MIPS_SYNC_STR)
+ __atomic_val_bysize (__arch_exchange_and_add, int, mem, value)
/* TODO: More atomic operations could be implemented efficiently; only the
basic requirements are done. */
--
1.7.4.1