[RFC PATCH v2 2/4] riscv: Add hwcaps-subdir support for RVA20U64

Yao Zihong zihong.plct@isrc.iscas.ac.cn
Tue Sep 30 00:56:54 GMT 2025


Introduce glibc-hwcaps subdir "rva20u64" and minimal profile-level
infrastructure. This allows ifunc selection (starting with memcpy) to
gate RVA20U64 implementations while keeping generic as fallback.

Signed-off-by: Yao Zihong <zihong.plct@isrc.iscas.ac.cn>
---
 sysdeps/riscv/Makefile                        | 11 ++++
 sysdeps/riscv/get-profile-level.h             | 54 +++++++++++++++
 sysdeps/riscv/multiarch/memcpy-generic.c      |  5 ++
 sysdeps/riscv/multiarch/memcpy_noalignment.S  |  5 ++
 sysdeps/riscv/profile-ifunc-macros.h          | 53 +++++++++++++++
 sysdeps/riscv/profile-level.h                 | 66 +++++++++++++++++++
 sysdeps/riscv/rv64/dl-hwcaps-subdirs.c        | 40 +++++++++++
 .../linux/riscv/multiarch/ifunc-impl-list.c   | 11 ++--
 .../unix/sysv/linux/riscv/multiarch/memcpy.c  | 10 ++-
 9 files changed, 248 insertions(+), 7 deletions(-)
 create mode 100644 sysdeps/riscv/get-profile-level.h
 create mode 100644 sysdeps/riscv/profile-ifunc-macros.h
 create mode 100644 sysdeps/riscv/profile-level.h
 create mode 100644 sysdeps/riscv/rv64/dl-hwcaps-subdirs.c

diff --git a/sysdeps/riscv/Makefile b/sysdeps/riscv/Makefile
index c08753ae8a..4c52f0d1ea 100644
--- a/sysdeps/riscv/Makefile
+++ b/sysdeps/riscv/Makefile
@@ -4,6 +4,17 @@ endif
 
 ifeq ($(subdir),elf)
 gen-as-const-headers += dl-link.sym
+
+$(objpfx)tst-glibc-hwcaps: $(objpfx)libmarkermod2-1.so
+
+$(objpfx)tst-glibc-hwcaps.out: \
+  $(objpfx)libmarkermod2.so \
+	$(objpfx)glibc-hwcaps/rva20u64/libmarkermod2.so \
+
+$(objpfx)glibc-hwcaps/rva20u64/libmarkermod2.so: $(objpfx)libmarkermod2-2.so 
+	$(make-target-directory)
+	cp $< $@
+
 endif
 
 # RISC-V's assembler also needs to know about PIC as it changes the definition
diff --git a/sysdeps/riscv/get-profile-level.h b/sysdeps/riscv/get-profile-level.h
new file mode 100644
index 0000000000..ce98d8f807
--- /dev/null
+++ b/sysdeps/riscv/get-profile-level.h
@@ -0,0 +1,54 @@
+/* Get RISC-V profile level.
+   This file is part of the GNU C Library.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sys/hwprobe.h>
+
+# define PROFILE_MASK_RISCV_RVA20U64 (RISCV_HWPROBE_IMA_FD | RISCV_HWPROBE_IMA_C | \
+                                      RISCV_HWPROBE_EXT_ZICNTR)
+
+static unsigned int
+get_profile_level()
+{
+  unsigned int profile_level = 0;
+  struct riscv_hwprobe pair;
+
+  pair.key = RISCV_HWPROBE_KEY_CPUPERF_0;
+  if (__riscv_hwprobe(&pair, 1, 0, NULL, 0) != 0) {
+    return profile_level;
+  }
+
+  if ((pair.value & RISCV_HWPROBE_MISALIGNED_MASK) == \
+      RISCV_HWPROBE_MISALIGNED_UNSUPPORTED) {
+    return profile_level;
+  }
+
+  pair.key = RISCV_HWPROBE_KEY_IMA_EXT_0;
+  if (__riscv_hwprobe(&pair, 1, 0, NULL, 0) != 0) {
+    return profile_level;
+  }
+
+  // Extensions without explicit detection (yet):
+  //      Ziccif, Ziccrse, Ziccamoa, Za128rs, Zicclsm
+  if ((pair.value & PROFILE_MASK_RISCV_RVA20U64) != \
+      PROFILE_MASK_RISCV_RVA20U64) {
+    return profile_level;
+  }
+  profile_level = 20;
+
+  return profile_level;
+}
diff --git a/sysdeps/riscv/multiarch/memcpy-generic.c b/sysdeps/riscv/multiarch/memcpy-generic.c
index 151dd0e6f9..83fd6ae03f 100644
--- a/sysdeps/riscv/multiarch/memcpy-generic.c
+++ b/sysdeps/riscv/multiarch/memcpy-generic.c
@@ -17,6 +17,9 @@
    <https://www.gnu.org/licenses/>.  */
 
 #include <string.h>
+#include <profile-level.h>
+
+#if PROFILE_SHOULD_BUILD (0)
 
 #if IS_IN(libc)
 # define MEMCPY __memcpy_generic
@@ -24,3 +27,5 @@
 # define libc_hidden_builtin_def(x)
 #endif
 #include <string/memcpy.c>
+
+#endif
diff --git a/sysdeps/riscv/multiarch/memcpy_noalignment.S b/sysdeps/riscv/multiarch/memcpy_noalignment.S
index dd135f4a4d..8f892ba550 100644
--- a/sysdeps/riscv/multiarch/memcpy_noalignment.S
+++ b/sysdeps/riscv/multiarch/memcpy_noalignment.S
@@ -18,6 +18,9 @@
 
 #include <sysdep.h>
 #include <sys/asm.h>
+#include <profile-level.h>
+
+#if PROFILE_SHOULD_BUILD (20)
 
 /* memcpy optimization for CPUs with fast unaligned support
    (RISCV_HWPROBE_MISALIGNED_FAST).
@@ -160,3 +163,5 @@ L(word_copy_adjust):
 	mv	a3, a5
 	j	L(word_copy)
 END (__memcpy_noalignment)
+
+#endif
diff --git a/sysdeps/riscv/profile-ifunc-macros.h b/sysdeps/riscv/profile-ifunc-macros.h
new file mode 100644
index 0000000000..33a16af241
--- /dev/null
+++ b/sysdeps/riscv/profile-ifunc-macros.h
@@ -0,0 +1,53 @@
+/* Common ifunc selection utils
+   All versions must be listed in ifunc-impl-list.c.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _PROFILE_IFUNC_MACROS_H
+#define _PROFILE_IFUNC_MACROS_H
+
+#include <profile-level.h>
+#include <sys/cdefs.h>
+#include <stdlib.h>
+
+/* Only include at the level of the minimum build profile or higher. I.e
+   if built with profile lower than RVA20, then include all implementations.
+   On the other hand if built with profile=RVA22/RVA23 only include RVA22/RVA23
+   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 <= 20
+# define RISCV_IFUNC_RESOLVE_RVA20(cond, impl) {if(cond) { return impl; }}
+# define RISCV_IFUNC_IMPL_ADD_RVA20(...) IFUNC_IMPL_ADD (__VA_ARGS__)
+#else
+# define RISCV_IFUNC_RESOLVE_RVA20(cond, impl) 
+# define RISCV_IFUNC_IMPL_ADD_RVA20(...)
+#endif
+
+#if MINIMUM_RISCV_PROFILE_LEVEL <= 0
+# define RISCV_IFUNC_RESOLVE_INIT(cond, impl) {if(cond) { return impl; }}
+# define RISCV_IFUNC_IMPL_ADD_INIT(...) IFUNC_IMPL_ADD (__VA_ARGS__)
+#else
+# define RISCV_IFUNC_RESOLVE_INIT(cond, impl)
+# define RISCV_IFUNC_IMPL_ADD_INIT(...)
+#endif
+
+#define RISCV_PROFILE_COND(cond, name)                                    \
+  (((name##_RISCV_PROFILE_LEVEL) <= MINIMUM_RISCV_PROFILE_LEVEL)           \
+   || cond)
+
+#endif
diff --git a/sysdeps/riscv/profile-level.h b/sysdeps/riscv/profile-level.h
new file mode 100644
index 0000000000..c846e1beb1
--- /dev/null
+++ b/sysdeps/riscv/profile-level.h
@@ -0,0 +1,66 @@
+/* Header defining the RISC-V Profile level
+   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.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file with other
+   programs, and to distribute those programs without any restriction
+   coming from the use of this file.  (The Lesser General Public
+   License restrictions do apply in other respects; for example, they
+   cover modification of the file, and distribution when not linked
+   into another program.)
+
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _PROFILE_LEVEL_H
+#define _PROFILE_LEVEL_H
+
+# define MINIMUM_RISCV_PROFILE_LEVEL 0
+
+#if defined __riscv_i && defined __riscv_m && defined __riscv_a && \
+    defined __riscv_f && defined __riscv_d && defined __riscv_c
+# define __RISCV_GC 1
+#else
+# define __RISCV_GC 0
+#endif
+
+#if __RISCV_GC && defined __riscv_zicsr && defined __riscv_zicntr && \
+                  defined __riscv_ziccif && defined __riscv_ziccrse && \
+                  defined __riscv_ziccamoa && defined __riscv_za128rs && \
+                  defined __riscv_zicclsm
+# define __RISCV_PROFILE_RVA20 1
+# undef MINIMUM_RISCV_PROFILE_LEVEL
+# define MINIMUM_RISCV_PROFILE_LEVEL 20
+#else
+# define __RISCV_PROFILE_RVA20 0
+#endif
+
+/* Profile level >= 20 guaranteed includes.  */
+#define FD_RISCV_PROFILE_LEVEL 20
+#define A_RISCV_PROFILE_LEVEL 20
+#define C_RISCV_PROFILE_LEVEL 20
+#define ZICSR_RISCV_PROFILE_LEVEL 20
+#define ZICNTR_RISCV_PROFILE_LEVEL 20
+#define ZICCIF_RISCV_PROFILE_LEVEL 20
+#define ZICCRSE_RISCV_PROFILE_LEVEL 20
+#define ZICCAMOA_RISCV_PROFILE_LEVEL 20
+#define ZA128RS_RISCV_PROFILE_LEVEL 20
+#define ZICCLSM_RISCV_PROFILE_LEVEL 20
+
+#define PROFILE_SHOULD_BUILD(profile_build_level)                              \
+  (MINIMUM_RISCV_PROFILE_LEVEL <= (profile_build_level))
+
+#endif 
diff --git a/sysdeps/riscv/rv64/dl-hwcaps-subdirs.c b/sysdeps/riscv/rv64/dl-hwcaps-subdirs.c
new file mode 100644
index 0000000000..3a88271ebd
--- /dev/null
+++ b/sysdeps/riscv/rv64/dl-hwcaps-subdirs.c
@@ -0,0 +1,40 @@
+/* Architecture-specific glibc-hwcaps subdirectories.  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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <dl-hwcaps.h>
+#include <ldsodefs.h>
+#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.  */
+
+uint32_t
+_dl_hwcaps_subdirs_active (void)
+{
+  int active = 0;
+
+  /* Test in reverse preference order. */
+  /* v1: RVA20U64 */
+  int profile_level = get_profile_level();
+  if(profile_level < 20) {
+    return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active);
+  }
+  ++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/ifunc-impl-list.c b/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c
index 1c1deca8f6..f0271679fd 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c
@@ -19,6 +19,7 @@
 #include <ifunc-impl-list.h>
 #include <string.h>
 #include <sys/hwprobe.h>
+#include <profile-ifunc-macros.h>
 
 size_t
 __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
@@ -26,18 +27,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
 {
   size_t i = max;
 
-  bool fast_unaligned = false;
+  bool unaligned = false;
 
   struct riscv_hwprobe pair = { .key = RISCV_HWPROBE_KEY_CPUPERF_0 };
   if (__riscv_hwprobe (&pair, 1, 0, NULL, 0) == 0
       && (pair.value & RISCV_HWPROBE_MISALIGNED_MASK)
-          == RISCV_HWPROBE_MISALIGNED_FAST)
-    fast_unaligned = true;
+          != RISCV_HWPROBE_MISALIGNED_UNSUPPORTED)
+    unaligned = true;
 
   IFUNC_IMPL (i, name, memcpy,
-	      IFUNC_IMPL_ADD (array, i, memcpy, fast_unaligned,
+	      RISCV_IFUNC_IMPL_ADD_RVA20 (array, i, memcpy, unaligned,
 			      __memcpy_noalignment)
-	      IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_generic))
+	      RISCV_IFUNC_IMPL_ADD_INIT (array, i, memcpy, 1, __memcpy_generic))
 
   return 0;
 }
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/memcpy.c b/sysdeps/unix/sysv/linux/riscv/multiarch/memcpy.c
index 8544f5402a..353eace6bb 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/memcpy.c
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/memcpy.c
@@ -27,6 +27,7 @@
 # include <ifunc-init.h>
 # include <riscv-ifunc.h>
 # include <sys/hwprobe.h>
+# include <profile-ifunc-macros.h>
 
 extern __typeof (__redirect_memcpy) __libc_memcpy;
 
@@ -37,10 +38,15 @@ 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;
   if (__riscv_hwprobe_one (hwprobe_func, RISCV_HWPROBE_KEY_CPUPERF_0, &v) == 0
-      && (v & RISCV_HWPROBE_MISALIGNED_MASK) == RISCV_HWPROBE_MISALIGNED_FAST)
+      && (v & RISCV_HWPROBE_MISALIGNED_MASK) != RISCV_HWPROBE_MISALIGNED_UNSUPPORTED)
+    unaligned = true;
+  
+  if(RISCV_PROFILE_COND(unaligned, ZICCLSM)) {
     return __memcpy_noalignment;
-
+  }
+  
   return __memcpy_generic;
 }
 
-- 
2.47.2



More information about the Libc-alpha mailing list