Add new macro (AO_PREFER_GENERALIZED) to favor generalized primitives
authorIvan Maidanski <ivmai@mail.ru>
Thu, 8 Dec 2011 12:39:56 +0000 (16:39 +0400)
committerIvan Maidanski <ivmai@mail.ru>
Thu, 8 Dec 2011 12:39:56 +0000 (16:39 +0400)
over direct assembly-based ones

* configure.ac (AO_PREFER_GENERALIZED): New AC template.
* src/atomic_ops/sysdeps/armcc/arm_v6.h (AO_test_and_set,
AO_HAVE_test_and_set, AO_fetch_and_add, AO_HAVE_fetch_and_add,
AO_fetch_and_add1, AO_HAVE_fetch_and_add1, AO_fetch_and_sub1,
AO_HAVE_fetch_and_sub1): Do not define if AO_PREFER_GENERALIZED.
* src/atomic_ops/sysdeps/gcc/arm.h (AO_test_and_set,
AO_HAVE_test_and_set, AO_fetch_and_add, AO_HAVE_fetch_and_add,
AO_fetch_and_add1, AO_HAVE_fetch_and_add1, AO_fetch_and_sub1,
AO_HAVE_fetch_and_sub1): Likewise.
* src/atomic_ops/sysdeps/gcc/avr32.h (AO_test_and_set_full,
AO_HAVE_test_and_set_full): Likewise.
* src/atomic_ops/sysdeps/gcc/hexagon.h (AO_fetch_and_add,
AO_HAVE_fetch_and_add, AO_test_and_set, AO_HAVE_test_and_set):
Likewise.
* src/atomic_ops/sysdeps/gcc/ia64.h (AO_fetch_and_add1_acquire,
AO_HAVE_fetch_and_add1_acquire, AO_fetch_and_add1_release,
AO_HAVE_fetch_and_add1_release, AO_fetch_and_sub1_acquire,
AO_HAVE_fetch_and_sub1_acquire, AO_fetch_and_sub1_release,
AO_HAVE_fetch_and_sub1_release, AO_int_fetch_and_add1_acquire,
AO_HAVE_int_fetch_and_add1_acquire, AO_int_fetch_and_add1_release,
AO_HAVE_int_fetch_and_add1_release, AO_int_fetch_and_sub1_acquire,
AO_HAVE_int_fetch_and_sub1_acquire, AO_int_fetch_and_sub1_release,
AO_HAVE_int_fetch_and_sub1_release): Likewise.
* src/atomic_ops/sysdeps/gcc/powerpc.h (AO_test_and_set,
AO_HAVE_test_and_set, AO_test_and_set_acquire,
AO_HAVE_test_and_set_acquire, AO_test_and_set_release,
AO_HAVE_test_and_set_release, AO_test_and_set_full,
AO_HAVE_test_and_set_full): Likewise.
* src/atomic_ops/sysdeps/gcc/x86.h (AO_fetch_and_add_full,
AO_HAVE_fetch_and_add_full, AO_and_full, AO_HAVE_and_full,
AO_or_full, AO_HAVE_or_full, AO_xor_full, AO_HAVE_xor_full): Likewise.
* src/atomic_ops/sysdeps/gcc/x86_64.h (AO_fetch_and_add_full,
AO_HAVE_fetch_and_add_full, AO_and_full, AO_HAVE_and_full, AO_or_full,
AO_HAVE_or_full, AO_xor_full, AO_HAVE_xor_full): Likewise.
* src/atomic_ops/sysdeps/hpc/ia64.h (AO_fetch_and_add1_acquire,
AO_HAVE_fetch_and_add1_acquire, AO_fetch_and_add1_release,
AO_HAVE_fetch_and_add1_release, AO_fetch_and_sub1_acquire,
AO_HAVE_fetch_and_sub1_acquire, AO_fetch_and_sub1_release,
AO_HAVE_fetch_and_sub1_release): Likewise.
* src/atomic_ops/sysdeps/ibmc/powerpc.h (AO_test_and_set_acquire,
AO_HAVE_test_and_set_acquire, AO_test_and_set_release,
AO_HAVE_test_and_set_release, AO_test_and_set_full,
AO_HAVE_test_and_set_full): Likewise.
* src/atomic_ops/sysdeps/icc/ia64.h (AO_fetch_and_add1_acquire,
AO_HAVE_fetch_and_add1_acquire, AO_fetch_and_add1_release,
AO_HAVE_fetch_and_add1_release, AO_fetch_and_sub1_acquire,
AO_HAVE_fetch_and_sub1_acquire, AO_fetch_and_sub1_release,
AO_HAVE_fetch_and_sub1_release): Likewise.
* src/atomic_ops/sysdeps/msftc/x86_64.h (AO_fetch_and_add_full,
AO_HAVE_fetch_and_add_full, AO_fetch_and_add1_full,
AO_HAVE_fetch_and_add1_full, AO_fetch_and_sub1_full,
AO_HAVE_fetch_and_sub1_full): Likewise.
* src/atomic_ops/sysdeps/sunc/x86.h (AO_fetch_and_add_full,
AO_HAVE_fetch_and_add_full, AO_and_full, AO_HAVE_and_full,
AO_or_full, AO_HAVE_or_full, AO_xor_full, AO_HAVE_xor_full): Likewise.
* src/atomic_ops/sysdeps/sunc/x86_64.h (AO_fetch_and_add_full,
AO_HAVE_fetch_and_add_full, AO_and_full, AO_HAVE_and_full,
AO_or_full, AO_HAVE_or_full, AO_xor_full, AO_HAVE_xor_full): Likewise.
* src/atomic_ops/sysdeps/gcc/arm.h (AO_test_and_set_full,
AO_HAVE_test_and_set_full): Do not define if AO_PREFER_GENERALIZED
(but only in case of ARMv6+).
* src/atomic_ops/sysdeps/msftc/common32_defs.h (_InterlockedIncrement,
_InterlockedDecrement, _InterlockedExchangeAdd): Do not declare
intrinsic if both AO_PREFER_GENERALIZED and AO_ASSUME_WINDOWS98.
* src/atomic_ops/sysdeps/msftc/common32_defs.h (AO_fetch_and_add_full,
AO_HAVE_fetch_and_add_full, AO_fetch_and_add1_full,
AO_HAVE_fetch_and_add1_full, AO_fetch_and_sub1_full,
AO_HAVE_fetch_and_sub1_full): Do not define if both
AO_PREFER_GENERALIZED and AO_ASSUME_WINDOWS98.
* src/atomic_ops/sysdeps/msftc/x86_64.h (_InterlockedIncrement64,
_InterlockedDecrement64, _InterlockedExchangeAdd64): Do not declare
intrinsic if AO_PREFER_GENERALIZED.

16 files changed:
configure.ac
src/atomic_ops/sysdeps/armcc/arm_v6.h
src/atomic_ops/sysdeps/gcc/arm.h
src/atomic_ops/sysdeps/gcc/avr32.h
src/atomic_ops/sysdeps/gcc/hexagon.h
src/atomic_ops/sysdeps/gcc/ia64.h
src/atomic_ops/sysdeps/gcc/powerpc.h
src/atomic_ops/sysdeps/gcc/x86.h
src/atomic_ops/sysdeps/gcc/x86_64.h
src/atomic_ops/sysdeps/hpc/ia64.h
src/atomic_ops/sysdeps/ibmc/powerpc.h
src/atomic_ops/sysdeps/icc/ia64.h
src/atomic_ops/sysdeps/msftc/common32_defs.h
src/atomic_ops/sysdeps/msftc/x86_64.h
src/atomic_ops/sysdeps/sunc/x86.h
src/atomic_ops/sysdeps/sunc/x86_64.h

index 4427849..763ec56 100644 (file)
@@ -83,6 +83,8 @@ AH_TEMPLATE([AO_TRACE_MALLOC], [Trace AO_malloc/free calls (for debug only)])
 # These macros are tested in public headers
 AH_TEMPLATE([AO_GENERALIZE_ASM_BOOL_CAS],
         [Force compare_and_swap definition via fetch_compare_and_swap])
+AH_TEMPLATE([AO_PREFER_GENERALIZED],
+        [Prefer generalized definitions to direct assembly-based ones])
 AH_TEMPLATE([AO_USE_PTHREAD_DEFS],
         [Emulate atomic operations via slow and async-signal-unsafe \
          pthread locking])
index 0ef50c3..57b8476 100644 (file)
@@ -96,6 +96,7 @@ __asm {
         more flexible, other instructions can be done between the LDREX and STREX accesses.
    "
 */
+#ifndef AO_PREFER_GENERALIZED
 AO_INLINE AO_TS_VAL_t
 AO_test_and_set(volatile AO_TS_t *addr) {
 
@@ -173,6 +174,7 @@ __asm {
         return result;
 }
 #define AO_HAVE_fetch_and_sub1
+#endif /* !AO_PREFER_GENERALIZED */
 
 /* NEC LE-IT: compare and swap */
 #ifndef AO_GENERALIZE_ASM_BOOL_CAS
index 4f14271..4496d9a 100644 (file)
@@ -145,6 +145,7 @@ AO_INLINE void AO_store(volatile AO_t *addr, AO_t value)
       interrupt latencies. LDREX, STREX are more flexible, other instructions
       can be done between the LDREX and STREX accesses."
 */
+#ifndef AO_PREFER_GENERALIZED
 #if !defined(AO_FORCE_USE_SWP) || defined(__thumb2__)
   /* But, on the other hand, there could be a considerable performance  */
   /* degradation in case of a race.  Eg., test_atomic.c executing       */
@@ -238,6 +239,7 @@ AO_fetch_and_sub1(volatile AO_t *p)
   return result;
 }
 #define AO_HAVE_fetch_and_sub1
+#endif /* !AO_PREFER_GENERALIZED */
 
 /* NEC LE-IT: compare and swap */
 #ifndef AO_GENERALIZE_ASM_BOOL_CAS
@@ -351,6 +353,8 @@ AO_fetch_compare_and_swap(volatile AO_t *addr, AO_t old_val, AO_t new_val)
 #endif /* __ARM_ARCH_x */
 
 #if !defined(AO_HAVE_test_and_set_full) && !defined(AO_HAVE_test_and_set) \
+    && (!defined(AO_PREFER_GENERALIZED) \
+        || !defined(AO_HAVE_fetch_compare_and_swap)) \
     && !defined(__ARM_ARCH_2__) && !defined(__ARM_ARCH_6M__)
   AO_INLINE AO_TS_VAL_t
   AO_test_and_set_full(volatile AO_TS_t *addr)
index c1bf56c..c5a12a3 100644 (file)
 
 #include "../test_and_set_t_is_ao_t.h"
 
-AO_INLINE AO_TS_VAL_t
-AO_test_and_set_full(volatile AO_TS_t *addr)
-{
+#ifndef AO_PREFER_GENERALIZED
+  AO_INLINE AO_TS_VAL_t
+  AO_test_and_set_full(volatile AO_TS_t *addr)
+  {
         register long ret;
 
         __asm__ __volatile__(
@@ -40,8 +41,9 @@ AO_test_and_set_full(volatile AO_TS_t *addr)
                 : "memory");
 
         return (AO_TS_VAL_t)ret;
-}
-#define AO_HAVE_test_and_set_full
+  }
+# define AO_HAVE_test_and_set_full
+#endif /* !AO_PREFER_GENERALIZED */
 
 AO_INLINE int
 AO_compare_and_swap_full(volatile AO_t *addr, AO_t old, AO_t new_val)
index 38d73f9..da7eb4e 100644 (file)
@@ -27,6 +27,7 @@ AO_nop_full(void)
 /* The Hexagon has load-locked, store-conditional primitives, and so    */
 /* resulting code is very nearly identical to that of PowerPC.          */
 
+#ifndef AO_PREFER_GENERALIZED
 AO_INLINE AO_t
 AO_fetch_and_add(volatile AO_t *addr, AO_t incr)
 {
@@ -67,6 +68,7 @@ AO_test_and_set(volatile AO_TS_t *addr)
   return (AO_TS_VAL_t)oldval;
 }
 #define AO_HAVE_test_and_set
+#endif /* !AO_PREFER_GENERALIZED */
 
 #ifndef AO_GENERALIZE_ASM_BOOL_CAS
   AO_INLINE int
index 97e325e..88f4c90 100644 (file)
@@ -61,6 +61,7 @@ AO_nop_full(void)
 }
 #define AO_HAVE_nop_full
 
+#ifndef AO_PREFER_GENERALIZED
 AO_INLINE AO_t
 AO_fetch_and_add1_acquire (volatile AO_t *addr)
 {
@@ -108,6 +109,7 @@ AO_fetch_and_sub1_release (volatile AO_t *addr)
   return result;
 }
 #define AO_HAVE_fetch_and_sub1_release
+#endif /* !AO_PREFER_GENERALIZED */
 
 AO_INLINE AO_t
 AO_fetch_compare_and_swap_acquire(volatile AO_t *addr, AO_t old, AO_t new_val)
@@ -202,6 +204,7 @@ AO_short_fetch_compare_and_swap_release(volatile unsigned short *addr,
   /* FIXME: Add compare_double_and_swap_double for the _ILP32 case.     */
 #else
 
+# ifndef AO_PREFER_GENERALIZED
   AO_INLINE unsigned int
   AO_int_fetch_and_add1_acquire(volatile unsigned int *addr)
   {
@@ -245,6 +248,7 @@ AO_short_fetch_compare_and_swap_release(volatile unsigned short *addr,
     return result;
   }
 # define AO_HAVE_int_fetch_and_sub1_release
+# endif /* !AO_PREFER_GENERALIZED */
 
   AO_INLINE unsigned int
   AO_int_fetch_compare_and_swap_acquire(volatile unsigned int *addr,
index e508724..275a277 100644 (file)
@@ -102,6 +102,7 @@ AO_store_release(volatile AO_t *addr, AO_t value)
 }
 #define AO_HAVE_store_release
 
+#ifndef AO_PREFER_GENERALIZED
 /* This is similar to the code in the garbage collector.  Deleting      */
 /* this and having it synthesized from compare_and_swap would probably  */
 /* only cost us a load immediate instruction.                           */
@@ -165,6 +166,7 @@ AO_test_and_set_full(volatile AO_TS_t *addr) {
   return result;
 }
 #define AO_HAVE_test_and_set_full
+#endif /* !AO_PREFER_GENERALIZED */
 
 #ifndef AO_GENERALIZE_ASM_BOOL_CAS
 
@@ -294,6 +296,7 @@ AO_fetch_compare_and_swap_full(volatile AO_t *addr, AO_t old_val,
 }
 #define AO_HAVE_fetch_compare_and_swap_full
 
+#ifndef AO_PREFER_GENERALIZED
 AO_INLINE AO_t
 AO_fetch_and_add(volatile AO_t *addr, AO_t incr) {
   AO_t oldval;
@@ -345,6 +348,7 @@ AO_fetch_and_add_full(volatile AO_t *addr, AO_t incr) {
   return result;
 }
 #define AO_HAVE_fetch_and_add_full
+#endif /* !AO_PREFER_GENERALIZED */
 
 #if defined(__powerpc64__) || defined(__ppc64__) || defined(__64BIT__)
   /* Empty */
index 11ac54b..0c7d703 100644 (file)
@@ -56,6 +56,7 @@ AO_nop_full(void)
 /* currently needed or useful for cached memory accesses.               */
 
 /* Really only works for 486 and later */
+#ifndef AO_PREFER_GENERALIZED
 AO_INLINE AO_t
 AO_fetch_and_add_full (volatile AO_t *p, AO_t incr)
 {
@@ -67,6 +68,7 @@ AO_fetch_and_add_full (volatile AO_t *p, AO_t incr)
   return result;
 }
 #define AO_HAVE_fetch_and_add_full
+#endif /* !AO_PREFER_GENERALIZED */
 
 AO_INLINE unsigned char
 AO_char_fetch_and_add_full (volatile unsigned char *p, unsigned char incr)
@@ -92,6 +94,7 @@ AO_short_fetch_and_add_full (volatile unsigned short *p, unsigned short incr)
 }
 #define AO_HAVE_short_fetch_and_add_full
 
+#ifndef AO_PREFER_GENERALIZED
 /* Really only works for 486 and later */
 AO_INLINE void
 AO_and_full (volatile AO_t *p, AO_t value)
@@ -116,6 +119,7 @@ AO_xor_full (volatile AO_t *p, AO_t value)
                         "=m" (*p) : "r" (value), "m" (*p) : "memory");
 }
 #define AO_HAVE_xor_full
+#endif /* !AO_PREFER_GENERALIZED */
 
 AO_INLINE AO_TS_VAL_t
 AO_test_and_set_full(volatile AO_TS_t *addr)
index 062eeb5..cf46d1e 100644 (file)
@@ -42,6 +42,7 @@ AO_nop_full(void)
 /* As far as we can tell, the lfence and sfence instructions are not    */
 /* currently needed or useful for cached memory accesses.               */
 
+#ifndef AO_PREFER_GENERALIZED
 AO_INLINE AO_t
 AO_fetch_and_add_full (volatile AO_t *p, AO_t incr)
 {
@@ -53,6 +54,7 @@ AO_fetch_and_add_full (volatile AO_t *p, AO_t incr)
   return result;
 }
 #define AO_HAVE_fetch_and_add_full
+#endif /* !AO_PREFER_GENERALIZED */
 
 AO_INLINE unsigned char
 AO_char_fetch_and_add_full (volatile unsigned char *p, unsigned char incr)
@@ -90,6 +92,7 @@ AO_int_fetch_and_add_full (volatile unsigned int *p, unsigned int incr)
 }
 #define AO_HAVE_int_fetch_and_add_full
 
+#ifndef AO_PREFER_GENERALIZED
 AO_INLINE void
 AO_and_full (volatile AO_t *p, AO_t value)
 {
@@ -113,6 +116,7 @@ AO_xor_full (volatile AO_t *p, AO_t value)
                         "=m" (*p) : "r" (value), "m" (*p) : "memory");
 }
 #define AO_HAVE_xor_full
+#endif /* !AO_PREFER_GENERALIZED */
 
 AO_INLINE AO_TS_VAL_t
 AO_test_and_set_full(volatile AO_TS_t *addr)
index ab0e0e9..6391eda 100644 (file)
@@ -49,6 +49,7 @@ AO_nop_full(void)
 }
 #define AO_HAVE_nop_full
 
+#ifndef AO_PREFER_GENERALIZED
 AO_INLINE AO_t
 AO_fetch_and_add1_acquire (volatile AO_t *p)
 {
@@ -80,6 +81,7 @@ AO_fetch_and_sub1_release (volatile AO_t *p)
                        _LDHINT_NONE, _UP_MEM_FENCE);
 }
 #define AO_HAVE_fetch_and_sub1_release
+#endif /* !AO_PREFER_GENERALIZED */
 
 AO_INLINE AO_t
 AO_fetch_compare_and_swap_acquire(volatile AO_t *addr, AO_t old_val,
index 2c39ec1..2438c8c 100644 (file)
@@ -51,6 +51,7 @@ AO_store_release(volatile AO_t *addr, AO_t value)
 }
 #define AO_HAVE_store_release
 
+#ifndef AO_PREFER_GENERALIZED
 /* This is similar to the code in the garbage collector.  Deleting      */
 /* this and having it synthesized from compare_and_swap would probably  */
 /* only cost us a load immediate instruction.                           */
@@ -84,6 +85,7 @@ AO_test_and_set_full(volatile AO_TS_t *addr) {
   return result;
 }
 #define AO_HAVE_test_and_set_full
+#endif /* !AO_PREFER_GENERALIZED */
 
 /*AO_INLINE AO_t
 AO_fetch_compare_and_swap(volatile AO_t *addr, AO_t old_val, AO_t new_val)
index f7b8b58..b43a501 100644 (file)
@@ -104,6 +104,7 @@ AO_nop_full(void)
 }
 #define AO_HAVE_nop_full
 
+#ifndef AO_PREFER_GENERALIZED
 AO_INLINE AO_t
 AO_fetch_and_add1_acquire(volatile AO_t *p)
 {
@@ -131,6 +132,7 @@ AO_fetch_and_sub1_release(volatile AO_t *p)
   return __fetchadd8_rel((unsigned __int64 *)p, -1);
 }
 #define AO_HAVE_fetch_and_sub1_release
+#endif /* !AO_PREFER_GENERALIZED */
 
 AO_INLINE AO_t
 AO_fetch_compare_and_swap_acquire(volatile AO_t *addr, AO_t old_val,
index 4acff0a..989974e 100644 (file)
 #  endif
 # endif /* _MSC_VER < 1400 */
 
-# pragma intrinsic (_InterlockedIncrement)
-# pragma intrinsic (_InterlockedDecrement)
-# pragma intrinsic (_InterlockedExchangeAdd)
+# if !defined(AO_PREFER_GENERALIZED) || !defined(AO_ASSUME_WINDOWS98)
+#   pragma intrinsic (_InterlockedIncrement)
+#   pragma intrinsic (_InterlockedDecrement)
+#   pragma intrinsic (_InterlockedExchangeAdd)
+# endif /* !AO_PREFER_GENERALIZED */
 # pragma intrinsic (_InterlockedCompareExchange)
 
 # define AO_INTERLOCKED_VOLATILE volatile
 
 #endif /* _MSC_VER >= 1310 */
 
+#if !defined(AO_PREFER_GENERALIZED) || !defined(AO_ASSUME_WINDOWS98)
 AO_INLINE AO_t
 AO_fetch_and_add_full(volatile AO_t *p, AO_t incr)
 {
@@ -93,6 +96,7 @@ AO_fetch_and_sub1_full(volatile AO_t *p)
   return _InterlockedDecrement((LONG AO_INTERLOCKED_VOLATILE *)p) + 1;
 }
 #define AO_HAVE_fetch_and_sub1_full
+#endif /* !AO_PREFER_GENERALIZED */
 
 #ifdef AO_ASSUME_WINDOWS98
   AO_INLINE AO_t
index e237b6a..254eec4 100644 (file)
 /* Assume _MSC_VER >= 1400 */
 #include <intrin.h>
 
-#pragma intrinsic (_InterlockedIncrement64)
-#pragma intrinsic (_InterlockedDecrement64)
-#pragma intrinsic (_InterlockedExchangeAdd64)
 #pragma intrinsic (_InterlockedCompareExchange64)
 
+#ifndef AO_PREFER_GENERALIZED
+
+# pragma intrinsic (_InterlockedIncrement64)
+# pragma intrinsic (_InterlockedDecrement64)
+# pragma intrinsic (_InterlockedExchangeAdd64)
+
 AO_INLINE AO_t
 AO_fetch_and_add_full (volatile AO_t *p, AO_t incr)
 {
@@ -71,6 +74,7 @@ AO_fetch_and_sub1_full (volatile AO_t *p)
   return _InterlockedDecrement64((LONGLONG volatile *)p) + 1;
 }
 #define AO_HAVE_fetch_and_sub1_full
+#endif /* !AO_PREFER_GENERALIZED */
 
 AO_INLINE AO_t
 AO_fetch_compare_and_swap_full(volatile AO_t *addr, AO_t old_val,
index 6b55d0a..7cad139 100644 (file)
@@ -53,6 +53,7 @@ AO_nop_full(void)
 /* currently needed or useful for cached memory accesses.               */
 
 /* Really only works for 486 and later */
+#ifndef AO_PREFER_GENERALIZED
 AO_INLINE AO_t
 AO_fetch_and_add_full (volatile AO_t *p, AO_t incr)
 {
@@ -64,6 +65,7 @@ AO_fetch_and_add_full (volatile AO_t *p, AO_t incr)
   return result;
 }
 #define AO_HAVE_fetch_and_add_full
+#endif /* !AO_PREFER_GENERALIZED */
 
 AO_INLINE unsigned char
 AO_char_fetch_and_add_full (volatile unsigned char *p, unsigned char incr)
@@ -89,6 +91,7 @@ AO_short_fetch_and_add_full (volatile unsigned short *p, unsigned short incr)
 }
 #define AO_HAVE_short_fetch_and_add_full
 
+#ifndef AO_PREFER_GENERALIZED
 /* Really only works for 486 and later */
 AO_INLINE void
 AO_and_full (volatile AO_t *p, AO_t value)
@@ -116,6 +119,7 @@ AO_xor_full (volatile AO_t *p, AO_t value)
                         : "memory");
 }
 #define AO_HAVE_xor_full
+#endif /* !AO_PREFER_GENERALIZED */
 
 AO_INLINE AO_TS_VAL_t
 AO_test_and_set_full (volatile AO_TS_t *addr)
index 8162345..a5fe2d4 100644 (file)
@@ -42,6 +42,7 @@ AO_nop_full(void)
 /* As far as we can tell, the lfence and sfence instructions are not    */
 /* currently needed or useful for cached memory accesses.               */
 
+#ifndef AO_PREFER_GENERALIZED
 AO_INLINE AO_t
 AO_fetch_and_add_full (volatile AO_t *p, AO_t incr)
 {
@@ -53,6 +54,7 @@ AO_fetch_and_add_full (volatile AO_t *p, AO_t incr)
   return result;
 }
 #define AO_HAVE_fetch_and_add_full
+#endif /* !AO_PREFER_GENERALIZED */
 
 AO_INLINE unsigned char
 AO_char_fetch_and_add_full (volatile unsigned char *p, unsigned char incr)
@@ -90,6 +92,7 @@ AO_int_fetch_and_add_full (volatile unsigned int *p, unsigned int incr)
 }
 #define AO_HAVE_int_fetch_and_add_full
 
+#ifndef AO_PREFER_GENERALIZED
 AO_INLINE void
 AO_and_full (volatile AO_t *p, AO_t value)
 {
@@ -116,6 +119,7 @@ AO_xor_full (volatile AO_t *p, AO_t value)
                         : "memory");
 }
 #define AO_HAVE_xor_full
+#endif /* !AO_PREFER_GENERALIZED */
 
 AO_INLINE AO_TS_VAL_t
 AO_test_and_set_full (volatile AO_TS_t *addr)