As [1] says, we cannot mix up lock-free and locking atomics for one
object. For example assume atom = (0, 0) initially, if we have a
locking "atomic" xor running on T0 and a lock-free store running on T1
concurrently:
T0 | T1
-----------------------------+-------------------------------------
acquire_lock |
t0 = atom[0] |
/* some CPU cycles */ | atom = (1, 1) /* lock-free atomic */
t1 = atom[1] |
t0 ^= 1 |
t1 ^= 1 |
atom[0] = t0 |
atom[1] = t1 |
release_lock |
we get atom = (0, 1), but the atomicity of xor and store should
guarantee that atom is either (0, 0) or (1, 1).
So, if we want to use a lock-free 16B atomic operation, we need both LSX
and SCQ even if that specific operation only needs one of them. To make
things worse, one may link a TU compiled with -mlsx -mscq and another
without them together, then if we want to use the lock-free 16B atomic
operations in the former, we must make libatomic also use the lock-free
16B atomic operation for the latter so we need to add ifuncs for
libatomic, similar to the discussion about i386 vs. i486 in [1].
Implementing and building the ifuncs currently requires:
- Glibc, because the ifunc resolver interface is libc-specific
- Linux, because the HWCAP bit for LSX is kernel-specific
- A recent enough assembler at build time to recognize sc.q
So the approach here is: only allow 16B lock-free atomic operations in
the compiler if the criteria above is satisfied, and ensure libatomic to
use those lock-free operations on capable hardware (via ifunc unless
both LSX and SCQ are already enabled by the builder) if the compiler
allows 16B lock-free atomic.
[1]: https://gcc.gnu.org/wiki/Atomic/GCCMM/LIbrary
gcc/
* configure.ac (HAVE_AS_16B_ATOMIC): Define if the assembler
supports LSX and sc.q.
* configure: Regenerate.
* config.in: Regenerate.
* config/loongarch/loongarch-opts.h (HAVE_AS_16B_ATOMIC):
Defined to 0 if undefined yet.
* config/loongarch/linux.h (HAVE_IFUNC_FOR_LIBATOMIC_16B):
Define as HAVE_AS_16B_ATOMIC && OPTION_GLIBC.
* config/loongarch/loongarch-protos.h
(loongarch_16b_atomic_lock_free_p): New prototype.
* config/loongarch/loongarch.cc
(loongarch_16b_atomic_lock_free_p): Implement.
* config/loongarch/sync.md (atomic_storeti_lsx): Require
loongarch_16b_atomic_lock_free_p.
(atomic_storeti): Likewise.
(atomic_exchangeti_scq): Likewise.
(atomic_exchangeti): Likewise.
(atomic_compare_and_swapti): Likewise.
(atomic_fetch_<amop_ti_fetch>ti_scq): Likewise.
(atomic_fetch_<amop_ti_fetch>ti): Likewise.
(ALL_SC): Likewise for TImode.
(atomic_storeti_scq): Remove.
libatomic/
* configure.ac (ARCH_LOONGARCH): New AM_CONDITIONAL.
* Makefile.am (IFUNC_OPT): Separate the item from IFUNC_OPTIONS
to allow using multiple options for an ISA variant.
(libatomic_la_LIBADD): Add *_16_1_.lo for LoongArch.
(IFUNC_OPTIONS): Build *_16_1_.lo for LoongArch with -mlsx and
-mscq.
* configure: Regenerate.
* Makefile.in: Regenerate.
* configure.tgt (try_ifunc): Set to yes for LoongArch if the
compiler can produce lock-free 16B atomic with -mlsx -mscq.
* config/loongarch/host-config.h: Implement ifunc selector.
---
Bootstrapped and regtested on loongarch64-linux-gnu. Ok for trunk?
gcc/config.in | 6 +++
gcc/config/loongarch/linux.h | 4 ++
gcc/config/loongarch/loongarch-opts.h | 4 ++
gcc/config/loongarch/loongarch-protos.h | 1 +
gcc/config/loongarch/loongarch.cc | 36 +++++++++++++
gcc/config/loongarch/sync.md | 34 ++++--------
gcc/configure | 32 ++++++++++++
gcc/configure.ac | 6 +++
libatomic/Makefile.am | 6 ++-
libatomic/Makefile.in | 12 +++--
libatomic/config/loongarch/host-config.h | 66 ++++++++++++++++++++++++
libatomic/configure | 18 ++++++-
libatomic/configure.ac | 2 +
libatomic/configure.tgt | 24 +++++++++
14 files changed, 218 insertions(+), 33 deletions(-)
create mode 100644 libatomic/config/loongarch/host-config.h
diff --git a/gcc/config.in b/gcc/config.in
index 0c634dfc538..e67936bfe9a 100644
--- a/gcc/config.in
+++ b/gcc/config.in
@@ -361,6 +361,12 @@
#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
diff --git a/gcc/config/loongarch/linux.h b/gcc/config/loongarch/linux.h
index b95a11f0241..e312f548a9f 100644
--- a/gcc/config/loongarch/linux.h
+++ b/gcc/config/loongarch/linux.h
@@ -53,3 +53,7 @@ along with GCC; see the file COPYING3. If not see
/* 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)
diff --git a/gcc/config/loongarch/loongarch-opts.h
b/gcc/config/loongarch/loongarch-opts.h
index 1b397b12494..02892099ca9 100644
--- a/gcc/config/loongarch/loongarch-opts.h
+++ b/gcc/config/loongarch/loongarch-opts.h
@@ -147,4 +147,8 @@ struct loongarch_flags {
#define HAVE_AS_TLS_LE_RELAXATION 0
#endif
+#ifndef HAVE_AS_16B_ATOMIC
+#define HAVE_AS_16B_ATOMIC 0
+#endif
+
#endif /* LOONGARCH_OPTS_H */
diff --git a/gcc/config/loongarch/loongarch-protos.h
b/gcc/config/loongarch/loongarch-protos.h
index e00dd898943..2e889a2bd43 100644
--- a/gcc/config/loongarch/loongarch-protos.h
+++ b/gcc/config/loongarch/loongarch-protos.h
@@ -201,6 +201,7 @@ extern void loongarch_expand_vec_cond_mask_expr
(machine_mode, machine_mode,
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 *);
diff --git a/gcc/config/loongarch/loongarch.cc
b/gcc/config/loongarch/loongarch.cc
index d11fe496a01..17a1e0ffa01 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -1393,6 +1393,42 @@ loongarch_can_use_return_insn (void)
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)
diff --git a/gcc/config/loongarch/sync.md b/gcc/config/loongarch/sync.md
index 2ef8e88d8d7..5784dab92a6 100644
--- a/gcc/config/loongarch/sync.md
+++ b/gcc/config/loongarch/sync.md
@@ -222,7 +222,7 @@ (define_insn "atomic_storeti_lsx"
[(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]));
@@ -243,28 +243,12 @@ (define_insn "atomic_storeti_lsx"
}
[(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);
@@ -330,7 +314,7 @@ (define_insn "atomic_fetch_nand_mask_inverted<mode>"
}
[(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")
@@ -374,7 +358,7 @@ (define_insn "atomic_exchangeti_scq"
(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);
@@ -394,7 +378,7 @@ (define_expand "atomic_exchangeti"
(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]));
@@ -694,7 +678,7 @@ (define_insn "atomic_compare_and_swapti_scq"
(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);
@@ -755,7 +739,7 @@ (define_expand "atomic_compare_and_swapti"
(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);
@@ -945,7 +929,7 @@ (define_insn "atomic_fetch_<amop_ti_fetch>ti_scq"
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);
@@ -998,7 +982,7 @@ (define_expand "atomic_fetch_<amop_ti_fetch>ti"
(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],
diff --git a/gcc/configure b/gcc/configure
index 611f691d7a7..9a3139b8b67 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -31721,6 +31721,38 @@ if test $gcc_cv_as_loongarch_tls_le_relaxation_support
= yes; then
$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
;;
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 1e5f7c3c4d0..2685fad9583 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -5585,6 +5585,12 @@ x:
[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],
diff --git a/libatomic/Makefile.am b/libatomic/Makefile.am
index 6dde874fa38..dcfee411970 100644
--- a/libatomic/Makefile.am
+++ b/libatomic/Makefile.am
@@ -107,7 +107,7 @@ PAT_BASE = $(word 1,$(PAT_SPLIT))
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 =
@@ -152,6 +152,10 @@ IFUNC_OPTIONS = -mcx16 -mcx16
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
diff --git a/libatomic/Makefile.in b/libatomic/Makefile.in
index be06e38e723..95f9c72df58 100644
--- a/libatomic/Makefile.in
+++ b/libatomic/Makefile.in
@@ -100,7 +100,8 @@ target_triplet = @target@
@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 \
@@ -436,9 +437,9 @@ libatomic_la_LDFLAGS = $(libatomic_version_info)
$(libatomic_version_script) \
@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)
@@ -449,7 +450,7 @@ libatomic_la_LDFLAGS = $(libatomic_version_info)
$(libatomic_version_script) \
@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)
@@ -467,10 +468,11 @@ libatomic_la_LDFLAGS = $(libatomic_version_info)
$(libatomic_version_script) \
@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)
diff --git a/libatomic/config/loongarch/host-config.h
b/libatomic/config/loongarch/host-config.h
new file mode 100644
index 00000000000..5ee40cf9ca4
--- /dev/null
+++ b/libatomic/config/loongarch/host-config.h
@@ -0,0 +1,66 @@
+/* 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
+
+typedef struct __ifunc_arg_t {
+ unsigned long _size;
+ unsigned long _hwcap;
+} __ifunc_arg_t;
+
+#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>
diff --git a/libatomic/configure b/libatomic/configure
index 349dc3caed6..b6bd456f015 100755
--- a/libatomic/configure
+++ b/libatomic/configure
@@ -637,6 +637,8 @@ ARCH_X86_64_FALSE
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
@@ -11847,7 +11849,7 @@ else
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
@@ -11953,7 +11955,7 @@ else
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
@@ -16199,6 +16201,14 @@ else
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='#'
@@ -16419,6 +16429,10 @@ if test -z "${ARCH_ARM_LINUX_TRUE}" && test -z
"${ARCH_ARM_LINUX_FALSE}"; then
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
diff --git a/libatomic/configure.ac b/libatomic/configure.ac
index ded38223356..3da2f941974 100644
--- a/libatomic/configure.ac
+++ b/libatomic/configure.ac
@@ -310,6 +310,8 @@ AM_CONDITIONAL(ARCH_AARCH64_LINUX,
[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,
diff --git a/libatomic/configure.tgt b/libatomic/configure.tgt
index 606d249116a..bcbfd8a22a0 100644
--- a/libatomic/configure.tgt
+++ b/libatomic/configure.tgt
@@ -117,6 +117,30 @@ EOF
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
--
2.51.2