[RFC PATCH v2 3/4] riscv: Add hwcaps-subdir support for RVA22U64 and RVA23U64
Yao Zihong
zihong.plct@isrc.iscas.ac.cn
Tue Sep 30 00:56:55 GMT 2025
Add glibc-hwcaps subdirs "rva22u64" and "rva23u64" with minimal
profile-level wiring, and extend memcpy ifunc gating:
- prefer RVV __memcpy_vector at RVA23,
- prefer __memcpy_noalignment at RVA20 to RVA22,
- keep generic as fallback.
Note: the RVV memcpy here is only introduced as an example. It is based
on the earlier strcpy_vector proposal from
https://inbox.sourceware.org/libc-alpha/20230504074851.38763-1-hau.hsu@sifive.com/,
with comments, naming adjusted and '.option' directives added.
Signed-off-by: Yao Zihong <zihong.plct@isrc.iscas.ac.cn>
---
sysdeps/riscv/Makefile | 30 ++++++++--
sysdeps/riscv/get-profile-level.h | 28 +++++++++
sysdeps/riscv/multiarch/memcpy_noalignment.S | 2 +-
sysdeps/riscv/multiarch/memcpy_vector.S | 54 +++++++++++++++++
sysdeps/riscv/profile-ifunc-macros.h | 16 +++++
sysdeps/riscv/profile-level.h | 59 ++++++++++++++++++-
sysdeps/riscv/rv64/dl-hwcaps-subdirs.c | 12 +++-
.../unix/sysv/linux/riscv/multiarch/Makefile | 1 +
.../linux/riscv/multiarch/ifunc-impl-list.c | 10 +++-
.../unix/sysv/linux/riscv/multiarch/memcpy.c | 8 +++
10 files changed, 210 insertions(+), 10 deletions(-)
create mode 100644 sysdeps/riscv/multiarch/memcpy_vector.S
diff --git a/sysdeps/riscv/Makefile b/sysdeps/riscv/Makefile
index 4c52f0d1ea..7d149d42e6 100644
--- a/sysdeps/riscv/Makefile
+++ b/sysdeps/riscv/Makefile
@@ -5,13 +5,35 @@ endif
ifeq ($(subdir),elf)
gen-as-const-headers += dl-link.sym
-$(objpfx)tst-glibc-hwcaps: $(objpfx)libmarkermod2-1.so
-
+$(objpfx)tst-glibc-hwcaps: $(objpfx)libmarkermod2-1.so \
+ $(objpfx)libmarkermod3-1.so $(objpfx)libmarkermod4-1.so
$(objpfx)tst-glibc-hwcaps.out: \
$(objpfx)libmarkermod2.so \
- $(objpfx)glibc-hwcaps/rva20u64/libmarkermod2.so \
+ $(objpfx)glibc-hwcaps/rva20u64/libmarkermod2.so \
+ $(objpfx)libmarkermod3.so \
+ $(objpfx)glibc-hwcaps/rva20u64/libmarkermod3.so \
+ $(objpfx)glibc-hwcaps/rva22u64/libmarkermod3.so \
+ $(objpfx)libmarkermod4.so \
+ $(objpfx)glibc-hwcaps/rva20u64/libmarkermod4.so \
+ $(objpfx)glibc-hwcaps/rva22u64/libmarkermod4.so \
+ $(objpfx)glibc-hwcaps/rva23u64/libmarkermod4.so \
-$(objpfx)glibc-hwcaps/rva20u64/libmarkermod2.so: $(objpfx)libmarkermod2-2.so
+$(objpfx)glibc-hwcaps/rva20u64/libmarkermod2.so: $(objpfx)libmarkermod2-2.so
+ $(make-target-directory)
+ cp $< $@
+$(objpfx)glibc-hwcaps/rva20u64/libmarkermod3.so: $(objpfx)libmarkermod3-2.so
+ $(make-target-directory)
+ cp $< $@
+$(objpfx)glibc-hwcaps/rva22u64/libmarkermod3.so: $(objpfx)libmarkermod3-3.so
+ $(make-target-directory)
+ cp $< $@
+$(objpfx)glibc-hwcaps/rva20u64/libmarkermod4.so: $(objpfx)libmarkermod4-2.so
+ $(make-target-directory)
+ cp $< $@
+$(objpfx)glibc-hwcaps/rva22u64/libmarkermod4.so: $(objpfx)libmarkermod4-3.so
+ $(make-target-directory)
+ cp $< $@
+$(objpfx)glibc-hwcaps/rva23u64/libmarkermod4.so: $(objpfx)libmarkermod4-4.so
$(make-target-directory)
cp $< $@
diff --git a/sysdeps/riscv/get-profile-level.h b/sysdeps/riscv/get-profile-level.h
index ce98d8f807..a0327a8d7b 100644
--- a/sysdeps/riscv/get-profile-level.h
+++ b/sysdeps/riscv/get-profile-level.h
@@ -21,6 +21,21 @@
# define PROFILE_MASK_RISCV_RVA20U64 (RISCV_HWPROBE_IMA_FD | RISCV_HWPROBE_IMA_C | \
RISCV_HWPROBE_EXT_ZICNTR)
+# define PROFILE_MASK_RISCV_RVA22U64 (PROFILE_MASK_RISCV_RVA20U64 | \
+ RISCV_HWPROBE_EXT_ZIHINTPAUSE | RISCV_HWPROBE_EXT_ZBA | \
+ RISCV_HWPROBE_EXT_ZBB | RISCV_HWPROBE_EXT_ZBS | \
+ RISCV_HWPROBE_EXT_ZICBOM | RISCV_HWPROBE_EXT_ZICBOZ | \
+ RISCV_HWPROBE_EXT_ZFHMIN | RISCV_HWPROBE_EXT_ZKT)
+
+# define PROFILE_MASK_RISCV_RVA23U64 (PROFILE_MASK_RISCV_RVA22U64 | \
+ RISCV_HWPROBE_IMA_V | RISCV_HWPROBE_EXT_ZVFHMIN | \
+ RISCV_HWPROBE_EXT_ZVBB | RISCV_HWPROBE_EXT_ZVKT | \
+ RISCV_HWPROBE_EXT_ZIHINTNTL | RISCV_HWPROBE_EXT_ZICOND | \
+ RISCV_HWPROBE_EXT_ZICOND | RISCV_HWPROBE_EXT_ZIMOP | \
+ RISCV_HWPROBE_EXT_ZCMOP | RISCV_HWPROBE_EXT_ZCB | \
+ RISCV_HWPROBE_EXT_ZFA | RISCV_HWPROBE_EXT_ZAWRS | \
+ RISCV_HWPROBE_EXT_SUPM)
+
static unsigned int
get_profile_level()
{
@@ -50,5 +65,18 @@ get_profile_level()
}
profile_level = 20;
+ // Extensions without explicit detection (yet):
+ // Zic64b, Zicbop
+ if ((pair.value & PROFILE_MASK_RISCV_RVA22U64) != \
+ PROFILE_MASK_RISCV_RVA22U64) {
+ return profile_level;
+ }
+ profile_level = 22;
+
+ if ((pair.value & PROFILE_MASK_RISCV_RVA23U64) != \
+ PROFILE_MASK_RISCV_RVA23U64) {
+ return profile_level;
+ }
+ profile_level = 23;
return profile_level;
}
diff --git a/sysdeps/riscv/multiarch/memcpy_noalignment.S b/sysdeps/riscv/multiarch/memcpy_noalignment.S
index 8f892ba550..42f719f6c6 100644
--- a/sysdeps/riscv/multiarch/memcpy_noalignment.S
+++ b/sysdeps/riscv/multiarch/memcpy_noalignment.S
@@ -20,7 +20,7 @@
#include <sys/asm.h>
#include <profile-level.h>
-#if PROFILE_SHOULD_BUILD (20)
+#if PROFILE_SHOULD_BUILD (22)
/* memcpy optimization for CPUs with fast unaligned support
(RISCV_HWPROBE_MISALIGNED_FAST).
diff --git a/sysdeps/riscv/multiarch/memcpy_vector.S b/sysdeps/riscv/multiarch/memcpy_vector.S
new file mode 100644
index 0000000000..9bca323ab5
--- /dev/null
+++ b/sysdeps/riscv/multiarch/memcpy_vector.S
@@ -0,0 +1,54 @@
+/* RVV versions memcpy. RISC-V version.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+#include <sys/asm.h>
+#include <profile-level.h>
+
+#if PROFILE_SHOULD_BUILD (23)
+
+#define dst a0
+#define src a1
+#define num a2
+
+#define ivl a3
+#define dst_ptr a4
+
+#define ELEM_LMUL_SETTING m8
+#define vdata v0
+
+ENTRY (__memcpy_vector)
+.option push
+.option arch, +v
+ mv dst_ptr, dst
+L(loop):
+ vsetvli ivl, num, e8, ELEM_LMUL_SETTING, ta, ma
+
+ vle8.v vdata, (src)
+ sub num, num, ivl
+ add src, src, ivl
+ vse8.v vdata, (dst_ptr)
+ add dst_ptr, dst_ptr, ivl
+
+ bnez num, L(loop)
+
+ ret
+.option pop
+END (__memcpy_vector)
+
+#endif
diff --git a/sysdeps/riscv/profile-ifunc-macros.h b/sysdeps/riscv/profile-ifunc-macros.h
index 33a16af241..52b11fd4f5 100644
--- a/sysdeps/riscv/profile-ifunc-macros.h
+++ b/sysdeps/riscv/profile-ifunc-macros.h
@@ -30,6 +30,22 @@
implementations. If there is no implementation at or above the
minimum build profile level, then include the highest profile level
implementation. */
+#if MINIMUM_RISCV_PROFILE_LEVEL <= 23
+# define RISCV_IFUNC_RESOLVE_RVA23(cond, impl) {if(cond) { return impl; }}
+# define RISCV_IFUNC_IMPL_ADD_RVA23(...) IFUNC_IMPL_ADD (__VA_ARGS__)
+#else
+# define RISCV_IFUNC_RESOLVE_RVA23(cond, impl)
+# define RISCV_IFUNC_IMPL_ADD_RVA23(...)
+#endif
+
+#if MINIMUM_RISCV_PROFILE_LEVEL <= 22
+# define RISCV_IFUNC_RESOLVE_RVA22(cond, impl) {if(cond) { return impl; }}
+# define RISCV_IFUNC_IMPL_ADD_RVA22(...) IFUNC_IMPL_ADD (__VA_ARGS__)
+#else
+# define RISCV_IFUNC_RESOLVE_RVA22(cond, impl)
+# define RISCV_IFUNC_IMPL_ADD_RVA22(...)
+#endif
+
#if MINIMUM_RISCV_PROFILE_LEVEL <= 20
# define RISCV_IFUNC_RESOLVE_RVA20(cond, impl) {if(cond) { return impl; }}
# define RISCV_IFUNC_IMPL_ADD_RVA20(...) IFUNC_IMPL_ADD (__VA_ARGS__)
diff --git a/sysdeps/riscv/profile-level.h b/sysdeps/riscv/profile-level.h
index c846e1beb1..280ca86766 100644
--- a/sysdeps/riscv/profile-level.h
+++ b/sysdeps/riscv/profile-level.h
@@ -39,8 +39,8 @@
#if __RISCV_GC && defined __riscv_zicsr && defined __riscv_zicntr && \
defined __riscv_ziccif && defined __riscv_ziccrse && \
- defined __riscv_ziccamoa && defined __riscv_za128rs && \
- defined __riscv_zicclsm
+ defined __riscv_ziccamoa && defined __riscv_zicclsm && \
+ (defined __riscv_za128rs || defined __riscv_za64rs)
# define __RISCV_PROFILE_RVA20 1
# undef MINIMUM_RISCV_PROFILE_LEVEL
# define MINIMUM_RISCV_PROFILE_LEVEL 20
@@ -48,6 +48,61 @@
# define __RISCV_PROFILE_RVA20 0
#endif
+#if __RISCV_PROFILE_RVA20 && defined __riscv_zic64b && \
+ defined __riscv_za64rs && defined __riscv_zihintpause && \
+ defined __riscv_zba && defined __riscv_zbb && \
+ defined __riscv_zicbom && defined __riscv_zicbop && \
+ defined __riscv_zicboz && defined __riscv_zfhmin && \
+ defined __riscv_zkt
+# define __RISCV_PROFILE_RVA22 1
+# undef MINIMUM_RISCV_PROFILE_LEVEL
+# define MINIMUM_RISCV_PROFILE_LEVEL 22
+#else
+# define __RISCV_PROFILE_RVA22 0
+#endif
+
+#if __RISCV_PROFILE_RVA22 && defined __riscv_v && \
+ defined __riscv_zvfhmin && defined __riscv_zvbb && \
+ defined __riscv_zvkt && defined __riscv_zihintntl && \
+ defined __riscv_zicond && defined __riscv_zimop && \
+ defined __riscv_zcmop && defined __riscv_zcb && \
+ defined __riscv_zfa && defined __riscv_zawrs && \
+ defined __riscv_supm
+# define __RISCV_PROFILE_RVA23 1
+# undef MINIMUM_RISCV_PROFILE_LEVEL
+# define MINIMUM_RISCV_PROFILE_LEVEL 23
+#else
+# define __RISCV_PROFILE_RVA23 0
+#endif
+
+/* Profile level >= 23 guaranteed includes. */
+#define V_RISCV_PROFILE_LEVEL 23
+#define ZVFHMIN_RISCV_PROFILE_LEVEL 23
+#define ZVBB_RISCV_PROFILE_LEVEL 23
+#define ZVKT_RISCV_PROFILE_LEVEL 23
+#define ZIHINTNTL_RISCV_PROFILE_LEVEL 23
+#define ZICOND_RISCV_PROFILE_LEVEL 23
+#define ZIMOP_RISCV_PROFILE_LEVEL 23
+#define ZCMOP_RISCV_PROFILE_LEVEL 23
+#define ZCB_RISCV_PROFILE_LEVEL 23
+#define ZFA_RISCV_PROFILE_LEVEL 23
+#define ZAWRS_RISCV_PROFILE_LEVEL 23
+#define SUPM_RISCV_PROFILE_LEVEL 23
+
+/* Profile level >= 22 guaranteed includes. */
+#define HPM_RISCV_PROFILE_LEVEL 22
+#define ZA64RS_RISCV_PROFILE_LEVEL 22
+#define ZIHINTPAUSE_ISCV_PROFILE_LEVEL 22
+#define ZBA_RISCV_PROFILE_LEVEL 22
+#define ZBB_RISCV_PROFILE_LEVEL 22
+#define ZBS_RISCV_PROFILE_LEVEL 22
+#define ZIC64B_RISCV_PROFILE_LEVEL 22
+#define ZICBOM_RISCV_PROFILE_LEVEL 22
+#define ZICBOP_RISCV_PROFILE_LEVEL 22
+#define ZICBOZ_RISCV_PROFILE_LEVEL 22
+#define ZFHMIN_RISCV_PROFILE_LEVEL 22
+#define ZKT_RISCV_PROFILE_LEVEL 22
+
/* Profile level >= 20 guaranteed includes. */
#define FD_RISCV_PROFILE_LEVEL 20
#define A_RISCV_PROFILE_LEVEL 20
diff --git a/sysdeps/riscv/rv64/dl-hwcaps-subdirs.c b/sysdeps/riscv/rv64/dl-hwcaps-subdirs.c
index 3a88271ebd..ec807b9360 100644
--- a/sysdeps/riscv/rv64/dl-hwcaps-subdirs.c
+++ b/sysdeps/riscv/rv64/dl-hwcaps-subdirs.c
@@ -21,8 +21,8 @@
#include <sys/hwprobe.h>
#include <get-profile-level.h>
-const char _dl_hwcaps_subdirs[] = "rva20u64";
-enum { subdirs_count = 1 }; /* Number of components in _dl_hwcaps_subdirs. */
+const char _dl_hwcaps_subdirs[] = "rva23u64:rva22u64:rva20u64";
+enum { subdirs_count = 3 }; /* Number of components in _dl_hwcaps_subdirs. */
uint32_t
_dl_hwcaps_subdirs_active (void)
@@ -36,5 +36,13 @@ _dl_hwcaps_subdirs_active (void)
return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
}
++active;
+
+ /* v2: RVA22U64 */
+ if(profile_level < 22) {
+ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
+ }
+
+ /* v3: RVA23U64 */
+ ++active;
return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
}
\ No newline at end of file
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
index fcef5659d4..8d3df8edcf 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
@@ -3,6 +3,7 @@ sysdep_routines += \
memcpy \
memcpy-generic \
memcpy_noalignment \
+ memcpy_vector \
# sysdep_routines
CFLAGS-memcpy_noalignment.c += -mno-strict-align
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c b/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c
index f0271679fd..e9b96f31d4 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c
@@ -28,6 +28,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
size_t i = max;
bool unaligned = false;
+ bool rvv_ext = false;
struct riscv_hwprobe pair = { .key = RISCV_HWPROBE_KEY_CPUPERF_0 };
if (__riscv_hwprobe (&pair, 1, 0, NULL, 0) == 0
@@ -35,8 +36,15 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
!= RISCV_HWPROBE_MISALIGNED_UNSUPPORTED)
unaligned = true;
+ struct riscv_hwprobe ext_pair = { .key = RISCV_HWPROBE_KEY_IMA_EXT_0 };
+ if (__riscv_hwprobe (&ext_pair, 1, 0, NULL, 0) == 0
+ && (ext_pair.value & RISCV_HWPROBE_IMA_V))
+ rvv_ext = true;
+
IFUNC_IMPL (i, name, memcpy,
- RISCV_IFUNC_IMPL_ADD_RVA20 (array, i, memcpy, unaligned,
+ RISCV_IFUNC_IMPL_ADD_RVA23 (array, i, memcpy, rvv_ext,
+ __memcpy_vector)
+ RISCV_IFUNC_IMPL_ADD_RVA22 (array, i, memcpy, unaligned,
__memcpy_noalignment)
RISCV_IFUNC_IMPL_ADD_INIT (array, i, memcpy, 1, __memcpy_generic))
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/memcpy.c b/sysdeps/unix/sysv/linux/riscv/multiarch/memcpy.c
index 353eace6bb..6eb550ec26 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/memcpy.c
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/memcpy.c
@@ -28,20 +28,28 @@
# include <riscv-ifunc.h>
# include <sys/hwprobe.h>
# include <profile-ifunc-macros.h>
+# include <asm/hwcap.h>
extern __typeof (__redirect_memcpy) __libc_memcpy;
extern __typeof (__redirect_memcpy) __memcpy_generic attribute_hidden;
extern __typeof (__redirect_memcpy) __memcpy_noalignment attribute_hidden;
+extern __typeof (__redirect_memcpy) __memcpy_vector attribute_hidden;
static inline __typeof (__redirect_memcpy) *
select_memcpy_ifunc (uint64_t dl_hwcap, __riscv_hwprobe_t hwprobe_func)
{
unsigned long long int v;
bool unaligned = false;
+ bool rvv_ext = false;
+
if (__riscv_hwprobe_one (hwprobe_func, RISCV_HWPROBE_KEY_CPUPERF_0, &v) == 0
&& (v & RISCV_HWPROBE_MISALIGNED_MASK) != RISCV_HWPROBE_MISALIGNED_UNSUPPORTED)
unaligned = true;
+
+ if(RISCV_PROFILE_COND(rvv_ext, V)) {
+ return __memcpy_vector;
+ }
if(RISCV_PROFILE_COND(unaligned, ZICCLSM)) {
return __memcpy_noalignment;
--
2.47.2
More information about the Libc-alpha
mailing list