https://gcc.gnu.org/g:1b6d733c9812c3e23155bfd0f41afd186921eeb7
commit r16-5226-g1b6d733c9812c3e23155bfd0f41afd186921eeb7 Author: Xi Ruoyao <[email protected]> Date: Thu Nov 6 21:32:54 2025 +0800 LoongArch: Don't mix lock-free and locking 16B atomics 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. Diff: --- 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 | 61 ++++++++++++++++++++++++++++++++ libatomic/configure | 18 ++++++++-- libatomic/configure.ac | 2 ++ libatomic/configure.tgt | 24 +++++++++++++ 14 files changed, 213 insertions(+), 33 deletions(-) diff --git a/gcc/config.in b/gcc/config.in index 0c634dfc538e..e67936bfe9ad 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 b95a11f02417..e312f548a9fc 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 1b397b124949..02892099ca92 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 ffcfa97092a8..a84b708cc283 100644 --- a/gcc/config/loongarch/loongarch-protos.h +++ b/gcc/config/loongarch/loongarch-protos.h @@ -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 *); diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc index 1f29de5f6e16..e7c291f30563 100644 --- a/gcc/config/loongarch/loongarch.cc +++ b/gcc/config/loongarch/loongarch.cc @@ -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) diff --git a/gcc/config/loongarch/sync.md b/gcc/config/loongarch/sync.md index 2ef8e88d8d75..5784dab92a68 100644 --- a/gcc/config/loongarch/sync.md +++ b/gcc/config/loongarch/sync.md @@ -222,7 +222,7 @@ [(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 @@ } [(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 @@ } [(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 @@ (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 @@ (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 @@ (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 @@ (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 @@ 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 @@ (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 b38c06b43457..83decfb738c4 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 285ee1914e0f..dbc216bfabb0 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 6dde874fa388..dcfee411970e 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 be06e38e7235..95f9c72df582 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 000000000000..6a1ea324a670 --- /dev/null +++ b/libatomic/config/loongarch/host-config.h @@ -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> diff --git a/libatomic/configure b/libatomic/configure index 349dc3caed6d..b6bd456f0157 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 ded382233562..3da2f9419742 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 606d249116af..bcbfd8a22a00 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
