From: Ivan Maidanski Date: Fri, 5 Oct 2012 11:10:40 +0000 (+0400) Subject: Eliminate arithmetic shifts in double-CAS (gcc/arm, msftc/x86) X-Git-Tag: libatomic_ops-7_4_0~90 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=aea70c00bc5bf83a59de1eea883f078f30d0f126;p=libatomic_ops Eliminate arithmetic shifts in double-CAS (gcc/arm, msftc/x86) * src/atomic_ops/sysdeps/gcc/arm.h (AO_compare_double_and_swap_double): Make double values by setting their AO_val1/2 parts instead of using arithmetic shifts; replace old/new_val with old/new_w.AO_whole. * src/atomic_ops/sysdeps/msftc/x86.h (AO_compare_double_and_swap_double_full): Likewise. * src/atomic_ops/sysdeps/msftc/x86.h (AO_double_compare_and_swap_full): Add comment. * src/atomic_ops/sysdeps/msftc/x86.h (AO_double_compare_and_swap_full, AO_compare_double_and_swap_double_full): Cast result of _InterlockedCompareExchange64 to double_ptr_storage (to eliminate signed/unsigned values comparison mismatch compiler warning). --- diff --git a/src/atomic_ops/sysdeps/gcc/arm.h b/src/atomic_ops/sysdeps/gcc/arm.h index a7a947c..29b6e44 100644 --- a/src/atomic_ops/sysdeps/gcc/arm.h +++ b/src/atomic_ops/sysdeps/gcc/arm.h @@ -320,25 +320,27 @@ AO_fetch_compare_and_swap(volatile AO_t *addr, AO_t old_val, AO_t new_val) AO_t old_val1, AO_t old_val2, AO_t new_val1, AO_t new_val2) { - double_ptr_storage old_val = - ((double_ptr_storage)old_val2 << 32) | old_val1; - double_ptr_storage new_val = - ((double_ptr_storage)new_val2 << 32) | new_val1; + AO_double_t old_w; + AO_double_t new_w; double_ptr_storage tmp; int result = 1; + old_w.AO_val1 = old_val1; + old_w.AO_val2 = old_val2; + new_w.AO_val1 = new_val1; + new_w.AO_val2 = new_val2; do { __asm__ __volatile__("@AO_compare_double_and_swap_double\n" " ldrexd %0, [%1]\n" /* get original to r1 & r2 */ : "=&r"(tmp) : "r"(addr) : "cc"); - if (tmp != old_val) + if (tmp != old_w.AO_whole) break; __asm__ __volatile__( " strexd %0, %2, [%3]\n" /* store new one if matched */ : "=&r"(result), "+m"(*addr) - : "r"(new_val), "r"(addr) + : "r"(new_w.AO_whole), "r"(addr) : "cc"); } while (AO_EXPECT_FALSE(result)); return !result; /* if succeded, return 1 else 0 */ diff --git a/src/atomic_ops/sysdeps/msftc/x86.h b/src/atomic_ops/sysdeps/msftc/x86.h index 6919c68..2ee54c4 100644 --- a/src/atomic_ops/sysdeps/msftc/x86.h +++ b/src/atomic_ops/sysdeps/msftc/x86.h @@ -96,22 +96,31 @@ AO_test_and_set_full(volatile AO_TS_t *addr) AO_double_compare_and_swap_full(volatile AO_double_t *addr, AO_double_t old_val, AO_double_t new_val) { - return _InterlockedCompareExchange64((__int64 volatile *)addr, - new_val.AO_whole, old_val.AO_whole) == old_val.AO_whole; + return (double_ptr_storage)_InterlockedCompareExchange64( + (__int64 volatile *)addr, + new_val.AO_whole /* exchange */, + old_val.AO_whole) == old_val.AO_whole; } # define AO_HAVE_double_compare_and_swap_full -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) -{ - __int64 oldv = (__int64)old_val1 | ((__int64)old_val2 << 32); - __int64 newv = (__int64)new_val1 | ((__int64)new_val2 << 32); - return _InterlockedCompareExchange64((__int64 volatile *)addr, - newv, oldv) == oldv; -} -#define AO_HAVE_compare_double_and_swap_double_full + 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 (double_ptr_storage)_InterlockedCompareExchange64( + (__int64 volatile *)addr, + new_w.AO_whole, + old_w.AO_whole) == old_w.AO_whole; + } +# define AO_HAVE_compare_double_and_swap_double_full #endif /* AO_ASSUME_VISTA */