#endif
+/* Define if your assembler supports LSX and SCQ for 16B atomic. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_AS_16B_ATOMIC
+#endif
+
+
/* Define if your assembler supports AEABI build attributes. */
#ifndef USED_FOR_TARGET
#undef HAVE_AS_AEABI_BUILD_ATTRIBUTES
/* The stack pointer needs to be moved while checking the stack. */
#define STACK_CHECK_MOVING_SP 1
+
+/* Depend on glibc because the libatomic ifunc resolver needs glibc
+ ifunc resolver interface. */
+#define HAVE_IFUNC_FOR_LIBATOMIC_16B (HAVE_AS_16B_ATOMIC && OPTION_GLIBC)
#define HAVE_AS_TLS_LE_RELAXATION 0
#endif
+#ifndef HAVE_AS_16B_ATOMIC
+#define HAVE_AS_16B_ATOMIC 0
+#endif
+
#endif /* LOONGARCH_OPTS_H */
rtx *);
extern void loongarch_expand_vec_widen_hilo (rtx, rtx, rtx, bool,
rtx (*)(rtx, rtx, rtx), rtx (*)(rtx, rtx, rtx));
+extern bool loongarch_16b_atomic_lock_free_p (void);
/* Routines implemented in loongarch-c.c. */
void loongarch_cpu_cpp_builtins (cpp_reader *);
return reload_completed && cfun->machine->frame.total_size == 0;
}
+/* If we want to support lock-free 16B atomic, we must support at least
+ lock-free atomic load, store, and CAS (other operations can be emulated
+ with CAS even if not supported directly). Otherwise, for example if
+ store is lock-free but CAS is not, the store may happen when the CAS
+ operation is holding the lock, breaking the atomicity of CAS.
+
+ We need LSX for load/store and SCQ for CAS, so require both for
+ lock-free 16B atomic.
+
+ If we link a TU (1) compiled with -mlsx -mscq and the TU (2) not, for
+ the same reason we need to ensure the libatomic call invoked by TU (2)
+ always use the lock-free sequence. Thus libatomic must contain the
+ ifuncs built with -mlsx -mscq. Since the ifunc resolver interface is
+ glibc-specific and the hwcap bits are Linux-specific, the resolver
+ implementation in libatomic assumes GNU/Linux and
+ HAVE_IFUNC_FOR_LIBATOMIC_16B is only enabled for it. To support
+ another OS, add the correct ifunc resolver implementation into
+ libatomic/config/loongarch/host-config.h and then define
+ HAVE_IFUNC_FOR_LIBATOMIC_16B for it.
+
+ FIXME: when ifunc is not supported but libatomic is entirely built with
+ -mlsx -mscq, we don't really need ifunc. But we don't have a way to
+ get CFLAGS_FOR_TARGET here... */
+bool
+loongarch_16b_atomic_lock_free_p (void)
+{
+#ifdef HAVE_IFUNC_FOR_LIBATOMIC_16B
+ bool ok_p = HAVE_IFUNC_FOR_LIBATOMIC_16B;
+#else
+ bool ok_p = false;
+#endif
+
+ return (ok_p && targetm.has_ifunc_p ()
+ && TARGET_64BIT && ISA_HAS_LSX && ISA_HAS_SCQ);
+}
+
/* Expand function epilogue using the following insn patterns:
"epilogue" (style == NORMAL_RETURN)
"sibcall_epilogue" (style == SIBCALL_RETURN)
[(match_operand:V2DI 1 "register_operand" "f")
(match_operand:SI 2 "const_int_operand")] ;; model
UNSPEC_ATOMIC_STORE))]
- "ISA_HAS_LSX && TARGET_64BIT"
+ "loongarch_16b_atomic_lock_free_p ()"
{
enum memmodel model = memmodel_base (INTVAL (operands[2]));
}
[(set (attr "length") (const_int 12))])
-(define_insn "atomic_storeti_scq"
- [(set (match_operand:TI 0 "memory_operand" "=m")
- (unspec_volatile:TI
- [(match_operand:TI 1 "register_operand" "r")]
- UNSPEC_ATOMIC_STORE))
- (clobber (match_scratch:DI 2 "=&r"))]
- "TARGET_64BIT && ISA_HAS_SCQ"
- "1:\\n\\tll.d\t$r0,%0\n\tmove\t%2,%1\n\tsc.q\t%2,%t1,%0\n\tbeqz\t%2,1b"
- [(set (attr "length") (const_int 16))])
-
(define_expand "atomic_storeti"
[(match_operand:TI 0 "memory_operand" "=m")
(match_operand:TI 1 "reg_or_0_operand" "rJ")
(match_operand:SI 2 "const_int_operand")]
- "TARGET_64BIT && (ISA_HAS_LSX || ISA_HAS_SCQ)"
+ "loongarch_16b_atomic_lock_free_p ()"
{
- if (!ISA_HAS_LSX)
- {
- emit_insn (gen_atomic_storeti_scq (operands[0], operands[1]));
- DONE;
- }
-
rtx vr = gen_reg_rtx (V2DImode), op1 = operands[1];
rtvec v = rtvec_alloc (2);
}
[(set (attr "length") (const_int 16))])
-(define_mode_iterator ALL_SC [GPR (TI "TARGET_64BIT && ISA_HAS_SCQ")])
+(define_mode_iterator ALL_SC [GPR (TI "loongarch_16b_atomic_lock_free_p ()")])
(define_mode_attr _scq [(SI "") (DI "") (TI "_scq")])
(define_expand "atomic_fetch_nand<mode>"
[(match_operand:ALL_SC 0 "register_operand")
(set (match_dup 1)
(match_operand:TI 2 "register_operand" "rJ"))
(clobber (match_scratch:DI 3 "=&r"))]
- "TARGET_64BIT && ISA_HAS_SCQ"
+ "loongarch_16b_atomic_lock_free_p ()"
{
output_asm_insn ("1:", operands);
output_asm_insn ("ll.d\t%0,%1", operands);
(match_operand:TI 1 "memory_operand" "+ZB")
(match_operand:TI 2 "register_operand" "rJ")
(match_operand:SI 3 "const_int_operand")] ;; model
- "TARGET_64BIT && ISA_HAS_SCQ"
+ "loongarch_16b_atomic_lock_free_p ()"
{
emit_insn (gen_atomic_exchangeti_scq (operands[0], operands[1],
operands[2]));
(ne:FCC (match_dup 1) (match_dup 2)))
(clobber (match_scratch:V2DI 6 "=&f"))
(clobber (match_scratch:DI 7 "=&r"))]
- "TARGET_64BIT && ISA_HAS_SCQ && ISA_HAS_LSX"
+ "loongarch_16b_atomic_lock_free_p ()"
{
output_asm_insn ("1:", operands);
(match_operand:SI 5 "const_int_operand" "") ;; is_weak
(match_operand:SI 6 "const_int_operand" "") ;; mod_s
(match_operand:SI 7 "const_int_operand" "")] ;; mod_f
- "TARGET_64BIT && ISA_HAS_SCQ && ISA_HAS_LSX"
+ "loongarch_16b_atomic_lock_free_p ()"
{
rtx fcc = gen_reg_rtx (FCCmode);
rtx gpr = gen_reg_rtx (DImode);
UNSPEC_TI_FETCH))
(clobber (match_scratch:DI 3 "=&r"))
(clobber (match_scratch:DI 4 "=&r"))]
- "TARGET_64BIT && ISA_HAS_SCQ"
+ "loongarch_16b_atomic_lock_free_p ()"
{
output_asm_insn ("1:", operands);
output_asm_insn ("ll.d\t%0,%1", operands);
(match_operand:TI 2 "reg_or_0_operand" "rJ")]
UNSPEC_TI_FETCH_DIRECT))
(match_operand:SI 3 "const_int_operand")] ;; model
- "TARGET_64BIT && ISA_HAS_SCQ"
+ "loongarch_16b_atomic_lock_free_p ()"
{
/* Model is ignored as sc.q implies a full barrier. */
emit_insn (gen_atomic_fetch_<amop_ti_fetch>ti_scq (operands[0],
$as_echo "#define HAVE_AS_TLS_LE_RELAXATION 1" >>confdefs.h
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for 16-byte atomic support" >&5
+$as_echo_n "checking assembler for 16-byte atomic support... " >&6; }
+if ${gcc_cv_as_loongarch_16_byte_atomic_support+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ gcc_cv_as_loongarch_16_byte_atomic_support=no
+ if test x$gcc_cv_as != x; then
+ $as_echo 'vori.b $vr0, $vr1, 0
+ sc.q $a0, $a1, $a2, 0' > conftest.s
+ if { ac_try='$gcc_cv_as $gcc_cv_as_flags -o conftest.o conftest.s >&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }
+ then
+ gcc_cv_as_loongarch_16_byte_atomic_support=yes
+ else
+ echo "configure: failed program was" >&5
+ cat conftest.s >&5
+ fi
+ rm -f conftest.o conftest.s
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_loongarch_16_byte_atomic_support" >&5
+$as_echo "$gcc_cv_as_loongarch_16_byte_atomic_support" >&6; }
+if test $gcc_cv_as_loongarch_16_byte_atomic_support = yes; then
+
+$as_echo "#define HAVE_AS_16B_ATOMIC 1" >>confdefs.h
+
fi
;;
[lu12i.w $t0,%le_hi20_r(a)],,
[AC_DEFINE(HAVE_AS_TLS_LE_RELAXATION, 1,
[Define if your assembler supports tls le relocation.])])
+ gcc_GAS_CHECK_FEATURE([16-byte atomic support],
+ gcc_cv_as_loongarch_16_byte_atomic_support,,
+ [vori.b $vr0, $vr1, 0
+ sc.q $a0, $a1, $a2, 0],,
+ [AC_DEFINE(HAVE_AS_16B_ATOMIC, 1,
+ [Define if your assembler supports LSX and SCQ for 16B atomic.])])
;;
s390*-*-*)
gcc_GAS_CHECK_FEATURE([.gnu_attribute support],
PAT_N = $(word 2,$(PAT_SPLIT))
PAT_S = $(word 3,$(PAT_SPLIT))
IFUNC_DEF = -DIFUNC_ALT=$(PAT_S)
-IFUNC_OPT = $(word $(PAT_S),$(IFUNC_OPTIONS))
+IFUNC_OPT = $(subst |,$(space),$(word $(PAT_S),$(IFUNC_OPTIONS)))
@AMDEP_TRUE@M_DEPS = -MT $@ -MD -MP -MF $(DEPDIR)/$(@F).Ppo
@AMDEP_FALSE@M_DEPS =
libatomic_la_LIBADD += $(addsuffix _16_1_.lo,$(SIZEOBJS)) \
$(addsuffix _16_2_.lo,$(SIZEOBJS))
endif
+if ARCH_LOONGARCH
+IFUNC_OPTIONS = -mlsx|-mscq
+libatomic_la_LIBADD += $(addsuffix _16_1_.lo,$(SIZEOBJS))
+endif
endif
if ARCH_AARCH64_LINUX
@ARCH_X86_64_TRUE@@HAVE_IFUNC_TRUE@@PARTIAL_VXWORKS_FALSE@am__append_4 = $(addsuffix _16_1_.lo,$(SIZEOBJS)) \
@ARCH_X86_64_TRUE@@HAVE_IFUNC_TRUE@@PARTIAL_VXWORKS_FALSE@ $(addsuffix _16_2_.lo,$(SIZEOBJS))
-@ARCH_AARCH64_LINUX_TRUE@@PARTIAL_VXWORKS_FALSE@am__append_5 = atomic_16.S
+@ARCH_LOONGARCH_TRUE@@HAVE_IFUNC_TRUE@@PARTIAL_VXWORKS_FALSE@am__append_5 = $(addsuffix _16_1_.lo,$(SIZEOBJS))
+@ARCH_AARCH64_LINUX_TRUE@@PARTIAL_VXWORKS_FALSE@am__append_6 = atomic_16.S
subdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \
@PARTIAL_VXWORKS_FALSE@libatomic_la_SOURCES = gload.c gstore.c gcas.c \
@PARTIAL_VXWORKS_FALSE@ gexch.c glfree.c lock.c init.c fenv.c \
-@PARTIAL_VXWORKS_FALSE@ fence.c flag.c $(am__append_5)
+@PARTIAL_VXWORKS_FALSE@ fence.c flag.c $(am__append_6)
@PARTIAL_VXWORKS_TRUE@libatomic_la_SOURCES = fenv.c fence.c flag.c \
-@PARTIAL_VXWORKS_TRUE@ $(am__append_5)
+@PARTIAL_VXWORKS_TRUE@ $(am__append_6)
@PARTIAL_VXWORKS_FALSE@SIZEOBJS = load store cas exch fadd fsub fand fior fxor fnand tas
@PARTIAL_VXWORKS_FALSE@EXTRA_libatomic_la_SOURCES = $(addsuffix _n.c,$(SIZEOBJS))
@PARTIAL_VXWORKS_FALSE@libatomic_la_DEPENDENCIES = $(libatomic_la_LIBADD) $(libatomic_version_dep)
@PARTIAL_VXWORKS_FALSE@PAT_N = $(word 2,$(PAT_SPLIT))
@PARTIAL_VXWORKS_FALSE@PAT_S = $(word 3,$(PAT_SPLIT))
@PARTIAL_VXWORKS_FALSE@IFUNC_DEF = -DIFUNC_ALT=$(PAT_S)
-@PARTIAL_VXWORKS_FALSE@IFUNC_OPT = $(word $(PAT_S),$(IFUNC_OPTIONS))
+@PARTIAL_VXWORKS_FALSE@IFUNC_OPT = $(subst |,$(space),$(word $(PAT_S),$(IFUNC_OPTIONS)))
@PARTIAL_VXWORKS_FALSE@@AMDEP_TRUE@M_DEPS = -MT $@ -MD -MP -MF $(DEPDIR)/$(@F).Ppo
@PARTIAL_VXWORKS_FALSE@@AMDEP_FALSE@M_DEPS =
@PARTIAL_VXWORKS_FALSE@M_SIZE = -DN=$(PAT_N)
@PARTIAL_VXWORKS_FALSE@ s,$(SIZES),$(addsuffix \
@PARTIAL_VXWORKS_FALSE@ _$(s)_.lo,$(SIZEOBJS))) $(am__append_1) \
@PARTIAL_VXWORKS_FALSE@ $(am__append_2) $(am__append_3) \
-@PARTIAL_VXWORKS_FALSE@ $(am__append_4)
+@PARTIAL_VXWORKS_FALSE@ $(am__append_4) $(am__append_5)
@ARCH_AARCH64_LINUX_TRUE@@HAVE_IFUNC_TRUE@@PARTIAL_VXWORKS_FALSE@IFUNC_OPTIONS = -march=armv8-a+lse
@ARCH_ARM_LINUX_TRUE@@HAVE_IFUNC_TRUE@@PARTIAL_VXWORKS_FALSE@IFUNC_OPTIONS = -march=armv7-a+fp -DHAVE_KERNEL64
@ARCH_I386_TRUE@@HAVE_IFUNC_TRUE@@PARTIAL_VXWORKS_FALSE@IFUNC_OPTIONS = -march=i586
+@ARCH_LOONGARCH_TRUE@@HAVE_IFUNC_TRUE@@PARTIAL_VXWORKS_FALSE@IFUNC_OPTIONS = -mlsx|-mscq
@ARCH_X86_64_TRUE@@HAVE_IFUNC_TRUE@@PARTIAL_VXWORKS_FALSE@IFUNC_OPTIONS = -mcx16 -mcx16
libatomic_convenience_la_SOURCES = $(libatomic_la_SOURCES)
libatomic_convenience_la_LIBADD = $(libatomic_la_LIBADD)
--- /dev/null
+/* Copyright (C) 2025 Free Software Foundation, Inc.
+
+ This file is part of the GNU Atomic Library (libatomic).
+
+ Libatomic is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ Libatomic is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#if HAVE_IFUNC
+
+/* We can assume Linux and Glibc here: otherwise GCC won't define
+ __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 (see HAVE_IFUNC_FOR_LIBATOMIC_16B
+ in gcc/config/loongarch/linux.h) and configure.tgt won't set
+ try_ifunc=1. */
+
+#include <sys/auxv.h>
+
+#ifndef HWCAP_LOONGARCH_LSX
+#define HWCAP_LOONGARCH_LSX (1 << 4)
+#endif
+
+#define IFUNC_NCOND(N) (N == 16)
+
+/* We cannot rely on the argument of ifunc resolver due to
+ https://sourceware.org/bugzilla/show_bug.cgi?id=33610. Call getauxval
+ on our own. */
+#define IFUNC_COND_1 ((getauxval (AT_HWCAP) & HWCAP_LOONGARCH_LSX) && \
+ (__builtin_loongarch_cpucfg (2) & (1 << 30)))
+
+#if IFUNC_ALT == 1
+#undef HAVE_ATOMIC_CAS_16
+#define HAVE_ATOMIC_CAS_16 1
+
+#undef HAVE_ATOMIC_LDST_16
+#define HAVE_ATOMIC_LDST_16 1
+
+#undef HAVE_ATOMIC_FETCH_ADD_16
+#define HAVE_ATOMIC_FETCH_ADD_16 1
+
+#undef HAVE_ATOMIC_FETCH_OP_16
+#define HAVE_ATOMIC_FETCH_OP_16 1
+#endif /* IFUNC_ALT == 1 */
+
+#endif /* HAVE_IFUNC */
+
+#include_next <host-config.h>
ARCH_X86_64_TRUE
ARCH_I386_FALSE
ARCH_I386_TRUE
+ARCH_LOONGARCH_FALSE
+ARCH_LOONGARCH_TRUE
ARCH_ARM_LINUX_FALSE
ARCH_ARM_LINUX_TRUE
ARCH_AARCH64_LINUX_FALSE
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11850 "configure"
+#line 11852 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11956 "configure"
+#line 11958 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
ARCH_ARM_LINUX_FALSE=
fi
+ if test "$ARCH" = loongarch; then
+ ARCH_LOONGARCH_TRUE=
+ ARCH_LOONGARCH_FALSE='#'
+else
+ ARCH_LOONGARCH_TRUE='#'
+ ARCH_LOONGARCH_FALSE=
+fi
+
if test "$ARCH" = x86 && test x$libat_cv_wordsize = x4; then
ARCH_I386_TRUE=
ARCH_I386_FALSE='#'
as_fn_error $? "conditional \"ARCH_ARM_LINUX\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
+if test -z "${ARCH_LOONGARCH_TRUE}" && test -z "${ARCH_LOONGARCH_FALSE}"; then
+ as_fn_error $? "conditional \"ARCH_LOONGARCH\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
if test -z "${ARCH_I386_TRUE}" && test -z "${ARCH_I386_FALSE}"; then
as_fn_error $? "conditional \"ARCH_I386\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
[expr "$config_path" : ".* linux/aarch64 .*" > /dev/null])
AM_CONDITIONAL(ARCH_ARM_LINUX,
[expr "$config_path" : ".* linux/arm .*" > /dev/null])
+AM_CONDITIONAL(ARCH_LOONGARCH,
+ [test "$ARCH" = loongarch])
AM_CONDITIONAL(ARCH_I386,
[test "$ARCH" = x86 && test x$libat_cv_wordsize = x4])
AM_CONDITIONAL(ARCH_X86_64,
ARCH=x86
;;
+ loongarch*)
+ cat > conftestx.c <<EOF
+#ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16
+#error lock-free 16-byte atomics is not supported by compiler configuration
+#endif
+EOF
+ if ${CC} ${CFLAGS} -mlsx -mscq -E conftestx.c > /dev/null 2>&1; then
+ cat > conftesty.c <<EOF
+#if defined (__loongarch_sx) && defined (__loongarch_scq)
+#error LSX and SCQ assumed available on target CPU so they are always used
+#endif
+EOF
+ if ${CC} ${CFLAGS} -E conftesty.c > /dev/null 2>&1; then
+ try_ifunc=yes
+ else
+ try_ifunc=no
+ fi
+ else
+ try_ifunc=no
+ fi
+ rm -f conftestx.c conftesty.c
+ ARCH=loongarch
+ ;;
+
*) ARCH="${target_cpu}" ;;
esac