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

Reply via email to