Properly fix compare_double_and_swap_double for gcc/x32 (use built-in CAS)
authorIvan Maidanski <ivmai@mail.ru>
Mon, 8 Oct 2012 10:51:30 +0000 (14:51 +0400)
committerIvan Maidanski <ivmai@mail.ru>
Mon, 8 Oct 2012 10:53:07 +0000 (14:53 +0400)
* src/atomic_ops/sysdeps/gcc/x86.h (AO_double_compare_and_swap_full):
New function (only if __x86_64__) implemented using GCC built-in
__sync CAS primitive available for x32.
* src/atomic_ops/sysdeps/gcc/x86.h
(AO_HAVE_double_compare_and_swap_full): New macro (for x32 only).
* src/atomic_ops/sysdeps/gcc/x86.h
(AO_compare_double_and_swap_double_full): Implement using
double_compare_and_swap_full instead of cmpxchg8b for x32 (since
x86_64 has available cmpxchg and cmpxchg16b but not cmpxchg8b).

src/atomic_ops/sysdeps/gcc/x86.h

index 6cdacd1..c8d8ade 100644 (file)
@@ -176,6 +176,8 @@ AO_fetch_compare_and_swap_full(volatile AO_t *addr, AO_t old_val,
 }
 #define AO_HAVE_fetch_compare_and_swap_full
 
+#if !defined(__x86_64__)
+
 /* Returns nonzero if the comparison succeeded. */
 /* Really requires at least a Pentium.          */
 AO_INLINE int
@@ -238,4 +240,38 @@ AO_compare_double_and_swap_double_full(volatile AO_double_t *addr,
 }
 #define AO_HAVE_compare_double_and_swap_double_full
 
+#else /* x86_64 && ILP32 */
+
+  /* X32 has native support for 64-bit integer operations (AO_double_t  */
+  /* is a 64-bit integer and we could use 64-bit cmpxchg).              */
+  /* This primitive is used by compare_double_and_swap_double_full.     */
+  AO_INLINE int
+  AO_double_compare_and_swap_full(volatile AO_double_t *addr,
+                                  AO_double_t old_val, AO_double_t new_val)
+  {
+    /* It is safe to use __sync CAS built-in here.      */
+    return __sync_bool_compare_and_swap(&addr->AO_whole,
+                                        old_val.AO_whole, new_val.AO_whole
+                                        /* empty protection list */);
+  }
+# define AO_HAVE_double_compare_and_swap_full
+
+  /* TODO: Remove if generalized.       */
+  AO_INLINE int
+  AO_compare_double_and_swap_double_full(volatile AO_double_t *addr,
+                                         AO_t old_val1, AO_t old_val2,
+                                         AO_t new_val1, AO_t new_val2)
+  {
+    AO_double_t old_w;
+    AO_double_t new_w;
+    old_w.AO_val1 = old_val1;
+    old_w.AO_val2 = old_val2;
+    new_w.AO_val1 = new_val1;
+    new_w.AO_val2 = new_val2;
+    return AO_double_compare_and_swap_full(addr, old_w, new_w);
+  }
+# define AO_HAVE_compare_double_and_swap_double_full
+
+#endif /* x86_64 && ILP32 */
+
 #define AO_T_IS_INT