[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