]> granicus.if.org Git - libatomic_ops/commitdiff
Implement AO_fetch_compare_and_swap for MIPS
authorIvan Maidanski <ivmai@mail.ru>
Wed, 30 Nov 2011 08:30:29 +0000 (12:30 +0400)
committerIvan Maidanski <ivmai@mail.ru>
Wed, 30 Nov 2011 08:30:29 +0000 (12:30 +0400)
* src/atomic_ops/sysdeps/gcc/mips.h (AO_compare_and_swap,
AO_HAVE_compare_and_swap): Do not define if AO_GENERALIZE_ASM_BOOL_CAS.
* src/atomic_ops/sysdeps/gcc/mips.h (AO_fetch_compare_and_swap,
AO_HAVE_fetch_compare_and_swap): Implement (assuming 32-bit ABI);
remove FIXME.

src/atomic_ops/sysdeps/gcc/mips.h

index 1e1ad979f438fa6e861702cbe33f8f5cc3b8eb03..a37c6b556cb5fd04062bf04684bc88ba53e2208b 100644 (file)
@@ -40,38 +40,64 @@ 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_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"
+        "       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 was_equal = 0;
+  register int fetched_val;
   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"
+      "       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 was_equal;
+  return (AO_t)fetched_val;
 }
-#define AO_HAVE_compare_and_swap
+#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.                                          */