summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Maidanski <ivmai@mail.ru>2011-12-14 11:13:46 +0400
committerIvan Maidanski <ivmai@mail.ru>2011-12-14 11:13:46 +0400
commit40d54b7fb87595e89269cec9643f8fa54094bf7a (patch)
tree0fe5a0ebe33c0dbfffc1890280c0a1b96e8f85e9
parentdc5861613cef2cc1f23bc115864b5cf98d2241a4 (diff)
parentd8cd00a386ceeac4c726a153833605fd6db08c26 (diff)
downloadlibatomic_ops-40d54b7fb87595e89269cec9643f8fa54094bf7a.tar.gz
Merge branch 'ao_val_cas'
-rw-r--r--ChangeLog1
-rw-r--r--src/atomic_ops/sysdeps/gcc/mips.h138
2 files changed, 115 insertions, 24 deletions
diff --git a/ChangeLog b/ChangeLog
index 6376410..0b8d26e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -13,6 +13,7 @@
* Eliminate compiler warnings in various functions and macros.
* Generalize AO_compare_and_swap primitives via AO_fetch_compare_and_swap.
* Generalize acquire/release/full CAS primitives for MIPS
+* Implement fetch_and_add, test_and_set primitives for MIPS.
* Improve Makefile for MS VC++; pass '-W3' option to MS compiler.
* Include ao_t_is_int.h from atomic_ops.h after first generalization pass
* Merge all Makefile.am files in src tree.
diff --git a/src/atomic_ops/sysdeps/gcc/mips.h b/src/atomic_ops/sysdeps/gcc/mips.h
index 1e1ad97..525a54a 100644
--- a/src/atomic_ops/sysdeps/gcc/mips.h
+++ b/src/atomic_ops/sysdeps/gcc/mips.h
@@ -26,6 +26,16 @@
/* Data dependence does not imply read ordering. */
#define AO_NO_DD_ORDERING
+#ifdef AO_ICE9A1_LLSC_WAR
+ /* ICE9 rev A1 chip (used in very few systems) is reported to */
+ /* have a low-frequency bug that causes LL to fail. */
+ /* To workaround, just issue the second 'LL'. */
+# define AO_MIPS_LL_FIX(args_str) \
+ " ll " args_str "\n"
+#else
+# define AO_MIPS_LL_FIX(args_str) ""
+#endif
+
AO_INLINE void
AO_nop_full(void)
{
@@ -40,39 +50,119 @@ AO_nop_full(void)
}
#define AO_HAVE_nop_full
-AO_INLINE int
-AO_compare_and_swap(volatile AO_t *addr, AO_t old, AO_t new_val)
+#ifndef AO_PREFER_GENERALIZED
+AO_INLINE AO_t
+AO_fetch_and_add(volatile AO_t *addr, AO_t incr)
{
- register int was_equal = 0;
+ register int result;
register int temp;
__asm__ __volatile__(
- " .set push \n"
- " .set mips2 \n"
- " .set noreorder \n"
- " .set nomacro \n"
- "1: ll %0, %1 \n"
- " bne %0, %4, 2f \n"
- " move %0, %3 \n"
- " sc %0, %1 \n"
- " .set pop \n"
- " beqz %0, 1b \n"
- " li %2, 1 \n"
- "2: "
- : "=&r" (temp), "+R" (*addr), "+r" (was_equal)
- : "r" (new_val), "r" (old)
+
+ " .set push\n"
+ " .set mips2\n"
+ " .set noreorder\n"
+ " .set nomacro\n"
+ "1: ll %0, %2\n"
+ AO_MIPS_LL_FIX("%0, %2")
+ " addu %1, %0, %3\n"
+ " sc %1, %2\n"
+ " beqz %1, 1b\n"
+ " nop\n"
+ " .set pop "
+ : "=&r" (result), "=&r" (temp), "=m" (*addr)
+ : "Ir" (incr)
+ : "memory");
+ return (AO_t)result;
+}
+#define AO_HAVE_fetch_and_add
+
+AO_INLINE AO_TS_VAL_t
+AO_test_and_set(volatile AO_TS_t *addr)
+{
+ register int oldval;
+ register int temp;
+
+ __asm__ __volatile__(
+ " .set push\n"
+ " .set mips2\n"
+ " .set noreorder\n"
+ " .set nomacro\n"
+ "1: ll %0, %2\n"
+ AO_MIPS_LL_FIX("%0, %2")
+ " move %1, %3\n"
+ " sc %1, %2\n"
+ " beqz %1, 1b\n"
+ " nop\n"
+ " .set pop "
+ : "=&r" (oldval), "=&r" (temp), "=m" (*addr)
+ : "r" (1)
: "memory");
- return was_equal;
+ return (AO_TS_VAL_t)oldval;
}
-#define AO_HAVE_compare_and_swap
+#define AO_HAVE_test_and_set
+
+ /* FIXME: Implement AO_and/or/xor primitives directly. */
+#endif /* !AO_PREFER_GENERALIZED */
+
+#ifndef AO_GENERALIZE_ASM_BOOL_CAS
+ AO_INLINE int
+ AO_compare_and_swap(volatile AO_t *addr, AO_t old, AO_t new_val)
+ {
+ register int was_equal = 0;
+ register int temp;
+
+ __asm__ __volatile__(
+ " .set push \n"
+ " .set mips2 \n"
+ " .set noreorder \n"
+ " .set nomacro \n"
+ "1: ll %0, %1 \n"
+ AO_MIPS_LL_FIX("%0, %1")
+ " bne %0, %4, 2f \n"
+ " move %0, %3 \n"
+ " sc %0, %1 \n"
+ " .set pop \n"
+ " beqz %0, 1b \n"
+ " li %2, 1 \n"
+ "2: "
+ : "=&r" (temp), "+R" (*addr), "+r" (was_equal)
+ : "r" (new_val), "r" (old)
+ : "memory");
+ return was_equal;
+ }
+# define AO_HAVE_compare_and_swap
+#endif /* !AO_GENERALIZE_ASM_BOOL_CAS */
+
+AO_INLINE AO_t
+AO_fetch_compare_and_swap(volatile AO_t *addr, AO_t old, AO_t new_val)
+{
+ register int fetched_val;
+ register int temp;
+
+ __asm__ __volatile__(
+ " .set push\n"
+ " .set mips2\n"
+ " .set noreorder\n"
+ " .set nomacro\n"
+ "1: ll %0, %2\n"
+ AO_MIPS_LL_FIX("%0, %2")
+ " bne %0, %4, 2f\n"
+ " move %1, %3\n"
+ " sc %1, %2\n"
+ " beqz %1, 1b\n"
+ " nop\n"
+ " .set pop\n"
+ "2:"
+ : "=&r" (fetched_val), "=&r" (temp), "=m" (*addr)
+ : "r" (new_val), "Jr" (old)
+ : "memory");
+ return (AO_t)fetched_val;
+}
+#define AO_HAVE_fetch_compare_and_swap
/* CAS primitives with acquire, release and full semantics are */
/* generated automatically (and AO_int_... primitives are */
/* defined properly after the first generalization pass). */
-/* FIXME: implement AO_fetch_compare_and_swap */
-
-/* FIXME: We should also implement AO_fetch_and_add, AO_and, AO_or, */
-/* AO_xor primitives directly. */
-
#define AO_T_IS_INT