From: Wilco Dijkstra Date: Mon, 15 Dec 2025 13:56:14 +0000 (+0000) Subject: atomic: Reinstate HAVE_64B_ATOMICS configure check X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9da0585852e5599ad6e849ccdf2f6f9b04038a3c;p=thirdparty%2Fglibc.git atomic: Reinstate HAVE_64B_ATOMICS configure check Reinstate HAVE_64B_ATOMICS configure check that was reverted by commit 7fec8a5de6826ef9ae440238d698f0fe5a5fb372 due to BZ #33632. This was fixed by 3dd2cbfa35e0e6e0345633079bd5a83bb822c2d8 by only allowing 64-bit atomics on sem_t if its type is 8-byte aligned. Rebase and add in cleanups in include/atomic.h that were omitted. Fix an issue with sparcv8-linux-gnu-leon3 forcing -mcpu=v8 for rtld.c which overrules -mcpu=leon3 and causes __atomic_always_lock_free (4, 0) to incorrectly return 0 and trigger asserts in atomics. Remove this as it seems to be a workaround for an issue in 1997. Reviewed-by: Adhemerval Zanella  --- diff --git a/config.h.in b/config.h.in index abc215850d..2cd8c90eb6 100644 --- a/config.h.in +++ b/config.h.in @@ -225,6 +225,9 @@ /* Define if __builtin_fmod/__builtin_remainder is inlined on x86. */ #undef HAVE_X86_INLINE_FMOD +/* Set to 1 if 64 bit atomics are supported. */ +#undef HAVE_64B_ATOMICS + /* */ diff --git a/configure b/configure index aa92a122b1..0cd2269859 100755 --- a/configure +++ b/configure @@ -7679,6 +7679,48 @@ if test "$libc_cv_gcc_builtin_memset" = yes ; then fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 64-bit atomic support" >&5 +printf %s "checking for 64-bit atomic support... " >&6; } +if test ${libc_cv_gcc_has_64b_atomics+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) cat > conftest.c <<\EOF +typedef struct { long long t; } X; +extern void has_64b_atomics(void); +void f(void) +{ + X x; + /* Use address of structure with 64-bit type. This avoids incorrect + implementations which return true even if long long is not 64-bit aligned. + This works on GCC and LLVM - other cases have bugs and they disagree. */ + _Static_assert (__atomic_always_lock_free (sizeof (x), &x), "no_64b_atomics"); +} +EOF +if { ac_try='${CC-cc} -O2 -S conftest.c' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 + (eval $ac_try) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; +then + libc_cv_gcc_has_64b_atomics=yes +else + libc_cv_gcc_has_64b_atomics=no +fi +rm -f conftest* ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_gcc_has_64b_atomics" >&5 +printf "%s\n" "$libc_cv_gcc_has_64b_atomics" >&6; } +if test "$libc_cv_gcc_has_64b_atomics" = yes; then + printf "%s\n" "#define HAVE_64B_ATOMICS 1" >>confdefs.h + +else + printf "%s\n" "#define HAVE_64B_ATOMICS 0" >>confdefs.h + +fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for compiler option to disable generation of FMA instructions" >&5 printf %s "checking for compiler option to disable generation of FMA instructions... " >&6; } if test ${libc_cv_cc_nofma+y} diff --git a/configure.ac b/configure.ac index ab355fa266..3e4a601c01 100644 --- a/configure.ac +++ b/configure.ac @@ -1485,6 +1485,33 @@ if test "$libc_cv_gcc_builtin_memset" = yes ; then AC_DEFINE(HAVE_BUILTIN_MEMSET) fi +AC_CACHE_CHECK(for 64-bit atomic support, libc_cv_gcc_has_64b_atomics, [dnl +cat > conftest.c <<\EOF +typedef struct { long long t; } X; +extern void has_64b_atomics(void); +void f(void) +{ + X x; + /* Use address of structure with 64-bit type. This avoids incorrect + implementations which return true even if long long is not 64-bit aligned. + This works on GCC and LLVM - other cases have bugs and they disagree. */ + _Static_assert (__atomic_always_lock_free (sizeof (x), &x), "no_64b_atomics"); +} +EOF +dnl +if AC_TRY_COMMAND([${CC-cc} -O2 -S conftest.c]); +then + libc_cv_gcc_has_64b_atomics=yes +else + libc_cv_gcc_has_64b_atomics=no +fi +rm -f conftest* ]) +if test "$libc_cv_gcc_has_64b_atomics" = yes; then + AC_DEFINE(HAVE_64B_ATOMICS, 1) +else + AC_DEFINE(HAVE_64B_ATOMICS, 0) +fi + dnl Determine how to disable generation of FMA instructions. AC_CACHE_CHECK([for compiler option to disable generation of FMA instructions], libc_cv_cc_nofma, [dnl diff --git a/include/atomic.h b/include/atomic.h index ed0dfbde3f..d7f9469ffe 100644 --- a/include/atomic.h +++ b/include/atomic.h @@ -27,11 +27,6 @@ - support functions like barriers. They also have the prefix "atomic_". - Architectures must provide a few lowlevel macros (the compare - and exchange definitions). All others are optional. They - should only be provided if the architecture has specific - support for the operation. - As macros are usually heavily nested and often use local variables to make sure side-effects are evaluated properly, use for macro local variables a per-macro unique prefix. This file uses @@ -42,7 +37,6 @@ #include -# undef atomic_compare_and_exchange_val_acq # define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \ ({ \ __typeof (*(mem)) __atg3_old = (oldval); \ @@ -50,7 +44,6 @@ __atg3_old; \ }) -# undef atomic_compare_and_exchange_val_rel # define atomic_compare_and_exchange_val_rel(mem, newval, oldval) \ ({ \ __typeof (*(mem)) __atg3_old = (oldval); \ @@ -58,7 +51,6 @@ __atg3_old; \ }) -# undef atomic_compare_and_exchange_bool_acq # define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \ ({ \ __typeof (*(mem)) __atg3_old = (oldval); \ @@ -121,55 +113,33 @@ C11. Usually, a function named atomic_OP_MO(args) is equivalent to C11's atomic_OP_explicit(args, memory_order_MO); exceptions noted below. */ -/* We require 32b atomic operations; some archs also support 64b atomic - operations. */ -void __atomic_link_error (void); -# if USE_64B_ATOMICS == 1 -# define __atomic_check_size(mem) \ - if ((sizeof (*mem) != 4) && (sizeof (*mem) != 8)) \ - __atomic_link_error (); -# else -# define __atomic_check_size(mem) \ - if (sizeof (*mem) != 4) \ - __atomic_link_error (); -# endif -/* We additionally provide 8b and 16b atomic loads and stores; we do not yet - need other atomic operations of such sizes, and restricting the support to - loads and stores makes this easier for archs that do not have native - support for atomic operations to less-than-word-sized data. */ -# if USE_64B_ATOMICS == 1 -# define __atomic_check_size_ls(mem) \ - if ((sizeof (*mem) != 1) && (sizeof (*mem) != 2) && (sizeof (*mem) != 4) \ - && (sizeof (*mem) != 8)) \ - __atomic_link_error (); -# else -# define __atomic_check_size_ls(mem) \ - if ((sizeof (*mem) != 1) && (sizeof (*mem) != 2) && sizeof (*mem) != 4) \ - __atomic_link_error (); -# endif - -# define atomic_thread_fence_acquire() \ - __atomic_thread_fence (__ATOMIC_ACQUIRE) -# define atomic_thread_fence_release() \ - __atomic_thread_fence (__ATOMIC_RELEASE) -# define atomic_thread_fence_seq_cst() \ - __atomic_thread_fence (__ATOMIC_SEQ_CST) +/* Check atomic operations are lock free. Since this doesn't work correctly + on all targets (eg. if uint64_t is 4-byte aligned), use__HAVE_64B_ATOMICS + for 64-bit types. */ +#define __atomic_check_size(mem) \ + _Static_assert (__atomic_always_lock_free (sizeof (*(mem)), 0) && \ + !(sizeof (*(mem)) == 8 && HAVE_64B_ATOMICS == 0), \ + "atomic not lock free!") + +#define atomic_thread_fence_acquire() __atomic_thread_fence (__ATOMIC_ACQUIRE) +#define atomic_thread_fence_release() __atomic_thread_fence (__ATOMIC_RELEASE) +#define atomic_thread_fence_seq_cst() __atomic_thread_fence (__ATOMIC_SEQ_CST) # define atomic_load_relaxed(mem) \ - ({ __atomic_check_size_ls((mem)); \ + ({ __atomic_check_size((mem)); \ __atomic_load_n ((mem), __ATOMIC_RELAXED); }) # define atomic_load_acquire(mem) \ - ({ __atomic_check_size_ls((mem)); \ + ({ __atomic_check_size((mem)); \ __atomic_load_n ((mem), __ATOMIC_ACQUIRE); }) # define atomic_store_relaxed(mem, val) \ do { \ - __atomic_check_size_ls((mem)); \ + __atomic_check_size((mem)); \ __atomic_store_n ((mem), (val), __ATOMIC_RELAXED); \ } while (0) # define atomic_store_release(mem, val) \ do { \ - __atomic_check_size_ls((mem)); \ + __atomic_check_size((mem)); \ __atomic_store_n ((mem), (val), __ATOMIC_RELEASE); \ } while (0) diff --git a/include/atomic_wide_counter.h b/include/atomic_wide_counter.h index 5b1979e601..106701c88a 100644 --- a/include/atomic_wide_counter.h +++ b/include/atomic_wide_counter.h @@ -22,7 +22,7 @@ #include #include -#if USE_64B_ATOMICS +#if HAVE_64B_ATOMICS static inline uint64_t __atomic_wide_counter_load_relaxed (__atomic_wide_counter *c) @@ -65,7 +65,7 @@ __atomic_wide_counter_fetch_xor_release (__atomic_wide_counter *c, return atomic_fetch_xor_release (&c->__value64, val); } -#else /* !USE_64B_ATOMICS */ +#else /* !HAVE_64B_ATOMICS */ uint64_t __atomic_wide_counter_load_relaxed (__atomic_wide_counter *c) attribute_hidden; @@ -98,6 +98,6 @@ __atomic_wide_counter_add_relaxed (__atomic_wide_counter *c, __atomic_wide_counter_fetch_add_relaxed (c, val); } -#endif /* !USE_64B_ATOMICS */ +#endif /* !HAVE_64B_ATOMICS */ #endif /* _ATOMIC_WIDE_COUNTER_H */ diff --git a/misc/atomic_wide_counter.c b/misc/atomic_wide_counter.c index 65f4288db2..7bdf4f0d2f 100644 --- a/misc/atomic_wide_counter.c +++ b/misc/atomic_wide_counter.c @@ -18,7 +18,7 @@ #include -#if !USE_64B_ATOMICS +#if !HAVE_64B_ATOMICS /* Values we add or xor are less than or equal to 1<<31, so we only have to make overflow-and-addition atomic wrt. to concurrent load @@ -124,4 +124,4 @@ __atomic_wide_counter_load_relaxed (__atomic_wide_counter *c) return ((uint64_t) (h & ~((unsigned int) 1 << 31)) << 31) + l; } -#endif /* !USE_64B_ATOMICS */ +#endif /* !HAVE_64B_ATOMICS */ diff --git a/nptl/pthread_cond_common.c b/nptl/pthread_cond_common.c index de3580b56f..60bec96ee5 100644 --- a/nptl/pthread_cond_common.c +++ b/nptl/pthread_cond_common.c @@ -52,7 +52,7 @@ __condvar_add_g1_start_relaxed (pthread_cond_t *cond, unsigned int val) __atomic_wide_counter_add_relaxed (&cond->__data.__g1_start, val); } -#if USE_64B_ATOMICS == 1 +#if HAVE_64B_ATOMICS == 1 static inline uint64_t __condvar_fetch_xor_wseq_release (pthread_cond_t *cond, unsigned int val) @@ -60,7 +60,7 @@ __condvar_fetch_xor_wseq_release (pthread_cond_t *cond, unsigned int val) return atomic_fetch_xor_release (&cond->__data.__wseq.__value64, val); } -#else /* !USE_64B_ATOMICS */ +#else /* !HAVE_64B_ATOMICS */ /* The xor operation needs to be an atomic read-modify-write. The write itself is not an issue as it affects just the lower-order half but not bits @@ -103,7 +103,7 @@ __condvar_fetch_xor_wseq_release (pthread_cond_t *cond, unsigned int val) return ((uint64_t) h << 31) + l2; } -#endif /* !USE_64B_ATOMICS */ +#endif /* !HAVE_64B_ATOMICS */ /* The lock that signalers use. See pthread_cond_wait_common for uses. The lock is our normal three-state lock: not acquired (0) / acquired (1) / diff --git a/stdlib/setenv.h b/stdlib/setenv.h index aed97efd4e..07ac97b906 100644 --- a/stdlib/setenv.h +++ b/stdlib/setenv.h @@ -61,7 +61,7 @@ __environ_is_from_array_list (char **ep) but given that counter wrapround is probably impossible to hit (2**32 operations in unsetenv concurrently with getenv), using seems unnecessary. */ -#if USE_64B_ATOMICS +#if HAVE_64B_ATOMICS typedef uint64_t environ_counter; #else typedef uint32_t environ_counter; diff --git a/sysdeps/alpha/atomic-machine.h b/sysdeps/alpha/atomic-machine.h index b7ce8c4726..df981d5881 100644 --- a/sysdeps/alpha/atomic-machine.h +++ b/sysdeps/alpha/atomic-machine.h @@ -18,7 +18,7 @@ #ifndef _ALPHA_ATOMIC_MACHINE_H #define _ALPHA_ATOMIC_MACHINE_H -#include_next +#include #define atomic_write_barrier() __asm ("wmb" : : : "memory"); diff --git a/sysdeps/generic/atomic-machine.h b/sysdeps/generic/atomic-machine.h index ef72d9ba0d..9f8528c1f2 100644 --- a/sysdeps/generic/atomic-machine.h +++ b/sysdeps/generic/atomic-machine.h @@ -34,16 +34,4 @@ and adaptive mutexes to optimize spin-wait loops. */ -#include - -/* NB: The NPTL semaphore code casts a sem_t to a new_sem and issues a 64-bit - atomic operation for USE_64B_ATOMICS. However, the sem_t has 32-bit - alignment on 32-bit architectures, which prevents using 64-bit atomics even - if the ABI supports it. */ -#if __WORDSIZE == 64 -# define USE_64B_ATOMICS 1 -#else -# define USE_64B_ATOMICS 0 -#endif - #endif /* atomic-machine.h */ diff --git a/sysdeps/generic/atomic-sem_t.h b/sysdeps/generic/atomic-sem_t.h index 6205cc4f6b..a5d32cac00 100644 --- a/sysdeps/generic/atomic-sem_t.h +++ b/sysdeps/generic/atomic-sem_t.h @@ -18,8 +18,8 @@ #include #include -#if USE_64B_ATOMICS && (SEM_T_ALIGN >= 8 \ - || defined HAVE_UNALIGNED_64B_ATOMICS) +#if HAVE_64B_ATOMICS && (SEM_T_ALIGN >= 8 \ + || defined HAVE_UNALIGNED_64B_ATOMICS) # define USE_64B_ATOMICS_ON_SEM_T 1 #else # define USE_64B_ATOMICS_ON_SEM_T 0 diff --git a/sysdeps/nptl/rseq-access.h b/sysdeps/nptl/rseq-access.h index 451cbf2743..17e7a68e0b 100644 --- a/sysdeps/nptl/rseq-access.h +++ b/sysdeps/nptl/rseq-access.h @@ -28,7 +28,7 @@ /* Static assert for types that can't be loaded/stored atomically on the current architecture. */ -#if USE_64B_ATOMICS +#if HAVE_64B_ATOMICS #define __RSEQ_ASSERT_ATOMIC(member) \ _Static_assert (sizeof (RSEQ_SELF()->member) == 1 \ || sizeof (RSEQ_SELF()->member) == 4 \ diff --git a/sysdeps/riscv/atomic-machine.h b/sysdeps/riscv/atomic-machine.h index e375c6665e..b6494b3c83 100644 --- a/sysdeps/riscv/atomic-machine.h +++ b/sysdeps/riscv/atomic-machine.h @@ -21,8 +21,6 @@ #ifdef __riscv_atomic -#include_next - /* Miscellaneous. */ # define asm_amo(which, ordering, mem, value) ({ \ diff --git a/sysdeps/sparc/atomic-machine.h b/sysdeps/sparc/atomic-machine.h index 2ffcbb2fcf..92b3ebdf6e 100644 --- a/sysdeps/sparc/atomic-machine.h +++ b/sysdeps/sparc/atomic-machine.h @@ -17,9 +17,7 @@ . */ #ifndef _SPARC_ATOMIC_MACHINE_H -#define _SPARC_ATOMIC_MACHINE_H 1 - -#include_next +#define _SPARC_ATOMIC_MACHINE_H #ifdef __sparc_v9__ # define atomic_full_barrier() \ @@ -34,4 +32,4 @@ extern void __cpu_relax (void); # define atomic_spin_nop() __cpu_relax () #endif -#endif /* _ATOMIC_MACHINE_H */ +#endif diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/Makefile b/sysdeps/unix/sysv/linux/sparc/sparc32/Makefile index 167307cc78..133704a57f 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/Makefile +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/Makefile @@ -9,12 +9,6 @@ ifeq ($(subdir),stdlib) gen-as-const-headers += ucontext_i.sym endif -# When I get this to work, this is the right thing -ifeq ($(subdir),elf) -CFLAGS-rtld.c += -mcpu=v8 -#rtld-routines += dl-sysdepsparc -endif # elf - ifeq ($(subdir),math) # These 2 routines are normally in libgcc{.a,_s.so.1}. # However, sparc32 -mlong-double-128 libgcc relies on diff --git a/sysdeps/x86/atomic-machine.h b/sysdeps/x86/atomic-machine.h index cfa6b62d32..0681f57987 100644 --- a/sysdeps/x86/atomic-machine.h +++ b/sysdeps/x86/atomic-machine.h @@ -19,12 +19,6 @@ #ifndef _X86_ATOMIC_MACHINE_H #define _X86_ATOMIC_MACHINE_H 1 -#ifdef __x86_64__ -# define USE_64B_ATOMICS 1 -#else -# define USE_64B_ATOMICS 0 -#endif - #define atomic_spin_nop() __asm ("pause") #endif /* atomic-machine.h */