]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
LoongArch: Don't mix lock-free and locking 16B atomics
authorXi Ruoyao <xry111@xry111.site>
Thu, 6 Nov 2025 13:32:54 +0000 (21:32 +0800)
committerXi Ruoyao <xry111@xry111.site>
Thu, 13 Nov 2025 15:22:18 +0000 (23:22 +0800)
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.

14 files changed:
gcc/config.in
gcc/config/loongarch/linux.h
gcc/config/loongarch/loongarch-opts.h
gcc/config/loongarch/loongarch-protos.h
gcc/config/loongarch/loongarch.cc
gcc/config/loongarch/sync.md
gcc/configure
gcc/configure.ac
libatomic/Makefile.am
libatomic/Makefile.in
libatomic/config/loongarch/host-config.h [new file with mode: 0644]
libatomic/configure
libatomic/configure.ac
libatomic/configure.tgt

index 0c634dfc538ef7e061860e867e10b84ec207e13b..e67936bfe9ada76ee830612e3ea4327111347843 100644 (file)
 #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
index b95a11f02417d020ecea3dbef9096cefe24ee224..e312f548a9fc5e5f1b9715b16e3590a8457058b0 100644 (file)
@@ -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)
index 1b397b124949ba05f0a259f414407845dbd3edf2..02892099ca927fe149f656424b03414e3308c601 100644 (file)
@@ -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 */
index ffcfa97092a8cd830be29e8c1927e74f3a569742..a84b708cc283787bf4d556d5420b80e4be3848dd 100644 (file)
@@ -203,6 +203,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 *);
index 1f29de5f6e16ef32385cd40f12b7dfa97229225e..e7c291f30563aad0a8c80eae0b811f97bb4e2b43 100644 (file)
@@ -1394,6 +1394,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)
index 2ef8e88d8d750ed8e05b61e8663d2825e6138f96..5784dab92a6866d9b6c9f6cb6c5d3b094467ecb6 100644 (file)
          [(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],
index b38c06b434572d3f7c63134116a31496615593c0..83decfb738c48f6ca8b9493ea73ae1c42fde253a 100755 (executable)
@@ -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
 
     ;;
index 285ee1914e0f27031b092b90bb3b0072aba0b711..dbc216bfabb0fb92dae41d679b88d93c4ad3f964 100644 (file)
@@ -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],
index 6dde874fa3881c77d2646bbe1e01681871ecced7..dcfee411970e5863d1ce4a7b37ff8e571790aa87 100644 (file)
@@ -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
index be06e38e72353738679b0f0511a570c08854a382..95f9c72df582fb38ddc28200ba56e5a8273718c7 100644 (file)
@@ -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 (file)
index 0000000..6a1ea32
--- /dev/null
@@ -0,0 +1,61 @@
+/* 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>
index 349dc3caed6d72b6c365286f857008165c3ad438..b6bd456f0157635e738d948aa46565698a662028 100755 (executable)
@@ -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
index ded3822335623be8231ae055a3b608d3893801ae..3da2f941974248fc2cd9044553905c8f0e0c99ae 100644 (file)
@@ -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,
index 606d249116af5ea82d5b62ce6d90a75b7305f96a..bcbfd8a22a001dda8dcdffa6ec83b0210bca232d 100644 (file)
@@ -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