[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