aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libatomic/config/linux/aarch64/atomic_16.S46
-rw-r--r--libatomic/config/linux/aarch64/host-config.h34
2 files changed, 74 insertions, 6 deletions
diff --git a/libatomic/config/linux/aarch64/atomic_16.S b/libatomic/config/linux/aarch64/atomic_16.S
index c44c31c..5767fba 100644
--- a/libatomic/config/linux/aarch64/atomic_16.S
+++ b/libatomic/config/linux/aarch64/atomic_16.S
@@ -35,16 +35,21 @@
writes, this will be true when using atomics in actual code.
The libat_<op>_16 entry points are ARMv8.0.
- The libat_<op>_16_i1 entry points are used when LSE128 is available.
+ The libat_<op>_16_i1 entry points are used when LSE128 or LRCPC3 is available.
The libat_<op>_16_i2 entry points are used when LSE2 is available. */
#include "auto-config.h"
.arch armv8-a+lse
+/* There is overlap in atomic instructions implemented in RCPC3 and LSE2.
+ Consequently, both _i1 and _i2 suffixes are needed for functions using these.
+ Elsewhere, all extension-specific implementations are mapped to _i1. */
+
+#define LRCPC3(NAME) libat_##NAME##_i1
#define LSE128(NAME) libat_##NAME##_i1
#define LSE(NAME) libat_##NAME##_i1
-#define LSE2(NAME) libat_##NAME##_i1
+#define LSE2(NAME) libat_##NAME##_i2
#define CORE(NAME) libat_##NAME
#define ATOMIC(NAME) __atomic_##NAME
@@ -513,6 +518,43 @@ END (test_and_set_16)
/* ifunc implementations: Carries run-time dependence on the presence of further
architectural extensions. */
+ENTRY_FEAT (load_16, LRCPC3)
+ cbnz w1, 1f
+
+ /* RELAXED. */
+ ldp res0, res1, [x0]
+ ret
+1:
+ cmp w1, SEQ_CST
+ b.eq 2f
+
+ /* ACQUIRE/CONSUME (Load-AcquirePC semantics). */
+ /* ldiapp res0, res1, [x0] */
+ .inst 0xd9411800
+ ret
+
+ /* SEQ_CST. */
+2: ldar tmp0, [x0] /* Block reordering with Store-Release instr. */
+ /* ldiapp res0, res1, [x0] */
+ .inst 0xd9411800
+ ret
+END_FEAT (load_16, LRCPC3)
+
+
+ENTRY_FEAT (store_16, LRCPC3)
+ cbnz w4, 1f
+
+ /* RELAXED. */
+ stp in0, in1, [x0]
+ ret
+
+ /* RELEASE/SEQ_CST. */
+1: /* stilp in0, in1, [x0] */
+ .inst 0xd9031802
+ ret
+END_FEAT (store_16, LRCPC3)
+
+
ENTRY_FEAT (exchange_16, LSE128)
mov tmp0, x0
mov res0, in0
diff --git a/libatomic/config/linux/aarch64/host-config.h b/libatomic/config/linux/aarch64/host-config.h
index d05e9eb..93f367d 100644
--- a/libatomic/config/linux/aarch64/host-config.h
+++ b/libatomic/config/linux/aarch64/host-config.h
@@ -33,6 +33,9 @@
#ifndef HWCAP_USCAT
# define HWCAP_USCAT (1 << 25)
#endif
+#ifndef HWCAP2_LRCPC3
+# define HWCAP2_LRCPC3 (1UL << 46)
+#endif
#ifndef HWCAP2_LSE128
# define HWCAP2_LSE128 (1UL << 47)
#endif
@@ -54,7 +57,7 @@ typedef struct __ifunc_arg_t {
#if defined (LAT_CAS_N)
# define LSE_ATOP
#elif defined (LAT_LOAD_N) || defined (LAT_STORE_N)
-# define LSE2_ATOP
+# define LSE2_LRCPC3_ATOP
#elif defined (LAT_EXCH_N) || defined (LAT_FIOR_N) || defined (LAT_FAND_N)
# define LSE128_ATOP
#endif
@@ -63,9 +66,10 @@ typedef struct __ifunc_arg_t {
# if defined (LSE_ATOP)
# define IFUNC_NCOND(N) 1
# define IFUNC_COND_1 (hwcap & HWCAP_ATOMICS)
-# elif defined (LSE2_ATOP)
-# define IFUNC_NCOND(N) 1
-# define IFUNC_COND_1 (has_lse2 (hwcap, features))
+# elif defined (LSE2_LRCPC3_ATOP)
+# define IFUNC_NCOND(N) 2
+# define IFUNC_COND_1 (has_rcpc3 (hwcap, features))
+# define IFUNC_COND_2 (has_lse2 (hwcap, features))
# elif defined (LSE128_ATOP)
# define IFUNC_NCOND(N) 1
# define IFUNC_COND_1 (has_lse128 (hwcap, features))
@@ -131,6 +135,28 @@ has_lse128 (unsigned long hwcap, const __ifunc_arg_t *features)
return false;
}
+/* LRCPC atomic support encoded in ID_AA64ISAR1_EL1.Atomic, bits[23:20]. The
+ expected value is 0b0011. Check that. */
+
+static inline bool
+has_rcpc3 (unsigned long hwcap, const __ifunc_arg_t *features)
+{
+ if (hwcap & _IFUNC_ARG_HWCAP
+ && features->_hwcap2 & HWCAP2_LRCPC3)
+ return true;
+ /* Try fallback feature check method to guarantee LRCPC3 is not implemented.
+
+ In the absence of HWCAP_CPUID, we are unable to check for RCPC3, return.
+ If feature check available, check LSE2 prerequisite before proceeding. */
+ if (!(hwcap & HWCAP_CPUID) || !(hwcap & HWCAP_USCAT))
+ return false;
+ unsigned long isar1;
+ asm volatile ("mrs %0, ID_AA64ISAR1_EL1" : "=r" (isar1));
+ if (AT_FEAT_FIELD (isar1) >= 3)
+ return true;
+ return false;
+}
+
#endif /* HAVE_IFUNC */
/* All 128-bit atomic functions are defined in aarch64/atomic_16.S. */