[PATCH v3] atomic: Reinstate HAVE_64B_ATOMICS configure check
Adhemerval Zanella Netto
adhemerval.zanella@linaro.org
Wed Dec 17 19:48:28 GMT 2025
On 17/12/25 16:09, Wilco Dijkstra wrote:
> v3: Fixup header guards on alpha/sparc, remove redundant -mcpu=v8 for leon3
>
> 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.
>
> Passes buildmanyglibc (with trivial fix for leon3).
>
> OK for commit?
>> __atomic_always_lockfree (4, 0) returns 0 with -mcpu=v8 (which seems like a bug in GCC,
>> but I've not investigated it in detail). In any case, compiling one C file with a different
>> (possibly incompatible) CPU setting just seems incorrect, and the comment indicates
>> it was just some hackery to get GLIBC to work for v8 (leon3 was 2005, so much later).
Can you add this on the commit message? The rest look good, thanks.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
>
> ---
>
> diff --git a/config.h.in b/config.h.in
> index abc215850d00da8d8d101b699f13d996af8a60c1..2cd8c90eb663bd5d6b215ccd7ca5cfed6a683f47 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 aa92a122b1818040976f097d2ebdf7270cf9734f..0cd2269859c972ef26037992d859310c51073628 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 ab355fa266ea498c1ea5029f41ad6063f7e7939d..3e4a601c01fc4a82f500edc143c2994b60971bff 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 ed0dfbde3f98af4e9bb094c64c585d4b88891794..d7f9469ffe9d015007773b16227508700ce21a5f 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 <atomic.h> 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 <atomic-machine.h>
>
>
> -# 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 5b1979e6019499f891603168acf5152048ace331..106701c88a38b60410cb858ce03c60ffa05f969a 100644
> --- a/include/atomic_wide_counter.h
> +++ b/include/atomic_wide_counter.h
> @@ -22,7 +22,7 @@
> #include <atomic.h>
> #include <bits/atomic_wide_counter.h>
>
> -#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 65f4288db29387ceb2801ee0edd5cc469854b058..7bdf4f0d2f9d22c267d5c3e037a8e6d76de1b00e 100644
> --- a/misc/atomic_wide_counter.c
> +++ b/misc/atomic_wide_counter.c
> @@ -18,7 +18,7 @@
>
> #include <atomic_wide_counter.h>
>
> -#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 de3580b56fdaeeb53e8146d5479dce5e5e1f663c..60bec96ee571f8416e3cc6b2c90d0f115aea8d5c 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 aed97efd4e3a6deb66bdc56e59a64f2d0b4e67c1..07ac97b9061fdc57a394bb0f2bc93de541057b23 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
> <atomic_wide_counter.h> 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 b7ce8c4726d0a6aa2ab770afc35924e5f1d6d51e..df981d5881c5444c222922e2cbd97ea773481be5 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 <atomic-machine.h>
> +#include <stdint.h>
>
> #define atomic_write_barrier() __asm ("wmb" : : : "memory");
>
> diff --git a/sysdeps/generic/atomic-machine.h b/sysdeps/generic/atomic-machine.h
> index ef72d9ba0d43994d94b9249b146de3519af0beac..9f8528c1f2a7943405d83296760bfe9c7a7d6a65 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 <bits/wordsize.h>
> -
> -/* 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 6205cc4f6b00d8d218eb6ef14356f9e064bbb2b6..a5d32cac001ae2a9e7ea7edf71f9698b1be2dff8 100644
> --- a/sysdeps/generic/atomic-sem_t.h
> +++ b/sysdeps/generic/atomic-sem_t.h
> @@ -18,8 +18,8 @@
> #include <atomic-machine.h>
> #include <sem_t-align.h>
>
> -#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 451cbf2743f32b2d22a586fe67fe99c06b0f5a40..17e7a68e0ba119cce18cfb672d58cc10529f76bc 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 e375c6665e978393654040044f096ece2ce3e592..b6494b3c83703b46c40e8a47e9011d96202dd770 100644
> --- a/sysdeps/riscv/atomic-machine.h
> +++ b/sysdeps/riscv/atomic-machine.h
> @@ -21,8 +21,6 @@
>
> #ifdef __riscv_atomic
>
> -#include_next <atomic-machine.h>
> -
> /* Miscellaneous. */
>
> # define asm_amo(which, ordering, mem, value) ({ \
> diff --git a/sysdeps/sparc/atomic-machine.h b/sysdeps/sparc/atomic-machine.h
> index 2ffcbb2fcf3f3ed4b56c9b87556d48b69c2bad10..92b3ebdf6e16447cd5035084e7e574cddf0ea456 100644
> --- a/sysdeps/sparc/atomic-machine.h
> +++ b/sysdeps/sparc/atomic-machine.h
> @@ -17,9 +17,7 @@
> <https://www.gnu.org/licenses/>. */
>
> #ifndef _SPARC_ATOMIC_MACHINE_H
> -#define _SPARC_ATOMIC_MACHINE_H 1
> -
> -#include_next <atomic-machine.h>
> +#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 167307cc78a95e86fa6f06ead1feb906980d361b..133704a57f3859057a984c104fb566fec50cdf30 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 cfa6b62d323fb72b2be1e55e2ed2c2baf6431f00..0681f57987939ee44a6cfc2e2cee0c573435b1e2 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 */
>
More information about the Libc-alpha
mailing list