atomic: Reinstate HAVE_64B_ATOMICS configure check

Reinstate HAVE_64B_ATOMICS configure check that was reverted by commit
7fec8a5de6 due to BZ #33632.  This was
fixed by 3dd2cbfa35 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  <adhemerval.zanella@linaro.org>
This commit is contained in:
Wilco Dijkstra
2025-12-15 13:56:14 +00:00
parent 1c588a2187
commit 9da0585852
16 changed files with 101 additions and 87 deletions

View File

@@ -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
/*
*/

42
configure vendored
View File

@@ -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}

View File

@@ -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

View File

@@ -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
/* 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_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)

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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) /

View File

@@ -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;

View File

@@ -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");

View File

@@ -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 */

View File

@@ -18,7 +18,7 @@
#include <atomic-machine.h>
#include <sem_t-align.h>
#if USE_64B_ATOMICS && (SEM_T_ALIGN >= 8 \
#if HAVE_64B_ATOMICS && (SEM_T_ALIGN >= 8 \
|| defined HAVE_UNALIGNED_64B_ATOMICS)
# define USE_64B_ATOMICS_ON_SEM_T 1
#else

View File

@@ -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 \

View File

@@ -21,8 +21,6 @@
#ifdef __riscv_atomic
#include_next <atomic-machine.h>
/* Miscellaneous. */
# define asm_amo(which, ordering, mem, value) ({ \

View File

@@ -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

View File

@@ -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

View File

@@ -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 */