[PATCH v2 4/4] riscv: Enable RVV selection in ifunc resolvers
Yao Zihong
zihong.plct@isrc.iscas.ac.cn
Tue Sep 30 00:34:53 GMT 2025
From: Yao Zihong <zihongyao@outlook.com>
This patch enables runtime selection of the imported RVV variants
via IFUNC for the RISC-V mem*/str* families. It augments
ifunc-impl-list.c and updates per-function resolvers to pick RVV
when the RISC-V V extension is present, otherwise falling back to
generic.
On non-RVV systems, behavior is identical to before.
Signed-off-by: Yao Zihong <zihong.plct@isrc.iscas.ac.cn>
---
.../unix/sysv/linux/riscv/multiarch/Makefile | 29 +++++++++---
.../linux/riscv/multiarch/ifunc-impl-list.c | 44 ++++++++++++++++++-
.../unix/sysv/linux/riscv/multiarch/memchr.c | 3 ++
.../unix/sysv/linux/riscv/multiarch/memcmp.c | 3 ++
.../sysv/linux/riscv/multiarch/memcmpeq.c | 3 ++
.../unix/sysv/linux/riscv/multiarch/memcpy.c | 5 +++
.../unix/sysv/linux/riscv/multiarch/memmove.c | 3 ++
.../unix/sysv/linux/riscv/multiarch/memset.c | 3 ++
.../unix/sysv/linux/riscv/multiarch/strcat.c | 3 ++
.../unix/sysv/linux/riscv/multiarch/strchr.c | 3 ++
.../unix/sysv/linux/riscv/multiarch/strcmp.c | 3 ++
.../unix/sysv/linux/riscv/multiarch/strcpy.c | 3 ++
.../unix/sysv/linux/riscv/multiarch/strlen.c | 3 ++
.../unix/sysv/linux/riscv/multiarch/strncat.c | 3 ++
.../unix/sysv/linux/riscv/multiarch/strncmp.c | 3 ++
.../unix/sysv/linux/riscv/multiarch/strncpy.c | 3 ++
.../unix/sysv/linux/riscv/multiarch/strnlen.c | 3 ++
17 files changed, 112 insertions(+), 8 deletions(-)
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
index 9338db7f94..15a9035452 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
@@ -1,36 +1,51 @@
ifeq ($(subdir),string)
sysdep_routines += \
- memcpy \
- memcpy-generic \
- memcpy_noalignment \
memchr \
memchr-generic \
+ memchr_vector \
memcmp \
memcmp-generic \
+ memcmp_vector \
memcmpeq \
memcmpeq-generic \
+ memcmpeq_vector \
+ memcpy \
+ memcpy-generic \
+ memcpy_noalignment \
+ memcpy_vector \
memmove \
memmove-generic \
+ memmove_vector \
memset \
memset-generic \
+ memset_vector \
strcat \
strcat-generic \
+ strcat_vector \
+ strchr \
+ strchr-generic \
+ strchr_vector \
strcmp \
strcmp-generic \
+ strcmp_vector \
strcpy \
strcpy-generic \
+ strcpy_vector \
strlen \
strlen-generic \
- strnlen \
- strnlen-generic \
+ strlen_vector \
strncat \
strncat-generic \
+ strncat_vector \
strncmp \
strncmp-generic \
+ strncmp_vector \
strncpy \
strncpy-generic \
- strchr \
- strchr-generic \
+ strncpy_vector \
+ strnlen \
+ strnlen-generic \
+ strnlen_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 567a16c723..092211f0c6 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c
@@ -27,52 +27,94 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
size_t i = max;
bool fast_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
&& (pair.value & RISCV_HWPROBE_MISALIGNED_MASK)
== RISCV_HWPROBE_MISALIGNED_FAST)
fast_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,
- IFUNC_IMPL_ADD (array, i, memcpy, fast_unaligned,
+ IFUNC_IMPL_ADD (array, i, memcpy, rvv_ext,
+ __memcpy_vector)
+ IFUNC_IMPL_ADD (array, i, memcpy, fast_unaligned,
__memcpy_noalignment)
IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_generic))
IFUNC_IMPL (i, name, memchr,
+ IFUNC_IMPL_ADD (array, i, memchr, rvv_ext,
+ __memchr_vector)
IFUNC_IMPL_ADD (array, i, memchr, 1, __memchr_generic))
IFUNC_IMPL (i, name, memmove,
+ IFUNC_IMPL_ADD (array, i, memmove, rvv_ext,
+ __memmove_vector)
IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_generic))
IFUNC_IMPL (i, name, memset,
+ IFUNC_IMPL_ADD (array, i, memset, rvv_ext,
+ __memset_vector)
IFUNC_IMPL_ADD (array, i, memset, 1, __memset_generic))
+ IFUNC_IMPL (i, name, memcmp,
+ IFUNC_IMPL_ADD (array, i, memcmp, rvv_ext,
+ __memcmp_vector)
+ IFUNC_IMPL_ADD (array, i, memcmp, 1, __memcmp_generic))
+
+ IFUNC_IMPL (i, name, __memcmpeq,
+ IFUNC_IMPL_ADD (array, i, __memcmpeq, rvv_ext,
+ ____memcmpeq_vector)
+ IFUNC_IMPL_ADD (array, i, __memcmpeq, 1, ____memcmpeq_generic))
+
IFUNC_IMPL (i, name, strcat,
+ IFUNC_IMPL_ADD (array, i, strcat, rvv_ext,
+ __strcat_vector)
IFUNC_IMPL_ADD (array, i, strcat, 1, __strcat_generic))
IFUNC_IMPL (i, name, strcmp,
+ IFUNC_IMPL_ADD (array, i, strcmp, rvv_ext,
+ __strcmp_vector)
IFUNC_IMPL_ADD (array, i, strcmp, 1, __strcmp_generic))
IFUNC_IMPL (i, name, strcpy,
+ IFUNC_IMPL_ADD (array, i, strcpy, rvv_ext,
+ __strcpy_vector)
IFUNC_IMPL_ADD (array, i, strcpy, 1, __strcpy_generic))
IFUNC_IMPL (i, name, strlen,
+ IFUNC_IMPL_ADD (array, i, strlen, rvv_ext,
+ __strlen_vector)
IFUNC_IMPL_ADD (array, i, strlen, 1, __strlen_generic))
IFUNC_IMPL (i, name, strnlen,
+ IFUNC_IMPL_ADD (array, i, strnlen, rvv_ext,
+ __strnlen_vector)
IFUNC_IMPL_ADD (array, i, strnlen, 1, __strnlen_generic))
IFUNC_IMPL (i, name, strncat,
+ IFUNC_IMPL_ADD (array, i, strncat, rvv_ext,
+ __strncat_vector)
IFUNC_IMPL_ADD (array, i, strncat, 1, __strncat_generic))
IFUNC_IMPL (i, name, strncmp,
+ IFUNC_IMPL_ADD (array, i, strncmp, rvv_ext,
+ __strncmp_vector)
IFUNC_IMPL_ADD (array, i, strncmp, 1, __strncmp_generic))
IFUNC_IMPL (i, name, strncpy,
+ IFUNC_IMPL_ADD (array, i, strncpy, rvv_ext,
+ __strncpy_vector)
IFUNC_IMPL_ADD (array, i, strncpy, 1, __strncpy_generic))
IFUNC_IMPL (i, name, strchr,
+ IFUNC_IMPL_ADD (array, i, strchr, rvv_ext,
+ __strchr_vector)
IFUNC_IMPL_ADD (array, i, strchr, 1, __strchr_generic))
return 0;
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/memchr.c b/sysdeps/unix/sysv/linux/riscv/multiarch/memchr.c
index 08a5f36e52..c056a41ca4 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/memchr.c
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/memchr.c
@@ -32,10 +32,13 @@
extern __typeof (__redirect_memchr) __libc_memchr;
extern __typeof (__redirect_memchr) __memchr_generic attribute_hidden;
+extern __typeof (__redirect_memchr) __memchr_vector attribute_hidden;
static inline __typeof (__redirect_memchr) *
select_memchr_ifunc (uint64_t dl_hwcap, __riscv_hwprobe_t hwprobe_func)
{
+ if (dl_hwcap & COMPAT_HWCAP_ISA_V)
+ return __memchr_vector;
return __memchr_generic;
}
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/memcmp.c b/sysdeps/unix/sysv/linux/riscv/multiarch/memcmp.c
index 13c86a8042..9b2f36bd07 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/memcmp.c
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/memcmp.c
@@ -32,10 +32,13 @@
extern __typeof (__redirect_memcmp) __libc_memcmp;
extern __typeof (__redirect_memcmp) __memcmp_generic attribute_hidden;
+extern __typeof (__redirect_memcmp) __memcmp_vector attribute_hidden;
static inline __typeof (__redirect_memcmp) *
select_memcmp_ifunc (uint64_t dl_hwcap, __riscv_hwprobe_t hwprobe_func)
{
+ if (dl_hwcap & COMPAT_HWCAP_ISA_V)
+ return __memcmp_vector;
return __memcmp_generic;
}
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/memcmpeq.c b/sysdeps/unix/sysv/linux/riscv/multiarch/memcmpeq.c
index c963a2ee75..7a9eaa268e 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/memcmpeq.c
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/memcmpeq.c
@@ -32,10 +32,13 @@
extern __typeof (__redirect___memcmpeq) __libc___memcmpeq;
extern __typeof (__redirect___memcmpeq) ____memcmpeq_generic attribute_hidden;
+extern __typeof (__redirect___memcmpeq) ____memcmpeq_vector attribute_hidden;
static inline __typeof (__redirect___memcmpeq) *
select___memcmpeq_ifunc (uint64_t dl_hwcap, __riscv_hwprobe_t hwprobe_func)
{
+ if (dl_hwcap & COMPAT_HWCAP_ISA_V)
+ return ____memcmpeq_vector;
return ____memcmpeq_generic;
}
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/memcpy.c b/sysdeps/unix/sysv/linux/riscv/multiarch/memcpy.c
index 8544f5402a..0e478b3e77 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/memcpy.c
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/memcpy.c
@@ -27,16 +27,21 @@
# include <ifunc-init.h>
# include <riscv-ifunc.h>
# include <sys/hwprobe.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;
+ if (dl_hwcap & COMPAT_HWCAP_ISA_V)
+ return __memcpy_vector;
+
if (__riscv_hwprobe_one (hwprobe_func, RISCV_HWPROBE_KEY_CPUPERF_0, &v) == 0
&& (v & RISCV_HWPROBE_MISALIGNED_MASK) == RISCV_HWPROBE_MISALIGNED_FAST)
return __memcpy_noalignment;
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/memmove.c b/sysdeps/unix/sysv/linux/riscv/multiarch/memmove.c
index 6aca93fd12..6294069c71 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/memmove.c
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/memmove.c
@@ -32,10 +32,13 @@
extern __typeof (__redirect_memmove) __libc_memmove;
extern __typeof (__redirect_memmove) __memmove_generic attribute_hidden;
+extern __typeof (__redirect_memmove) __memmove_vector attribute_hidden;
static inline __typeof (__redirect_memmove) *
select_memmove_ifunc (uint64_t dl_hwcap, __riscv_hwprobe_t hwprobe_func)
{
+ if (dl_hwcap & COMPAT_HWCAP_ISA_V)
+ return __memmove_vector;
return __memmove_generic;
}
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/memset.c b/sysdeps/unix/sysv/linux/riscv/multiarch/memset.c
index 07ebc59575..28de7ef9d3 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/memset.c
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/memset.c
@@ -32,10 +32,13 @@
extern __typeof (__redirect_memset) __libc_memset;
extern __typeof (__redirect_memset) __memset_generic attribute_hidden;
+extern __typeof (__redirect_memset) __memset_vector attribute_hidden;
static inline __typeof (__redirect_memset) *
select_memset_ifunc (uint64_t dl_hwcap, __riscv_hwprobe_t hwprobe_func)
{
+ if (dl_hwcap & COMPAT_HWCAP_ISA_V)
+ return __memset_vector;
return __memset_generic;
}
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/strcat.c b/sysdeps/unix/sysv/linux/riscv/multiarch/strcat.c
index ca3254a018..d39f01b880 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/strcat.c
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/strcat.c
@@ -32,10 +32,13 @@
extern __typeof (__redirect_strcat) __libc_strcat;
extern __typeof (__redirect_strcat) __strcat_generic attribute_hidden;
+extern __typeof (__redirect_strcat) __strcat_vector attribute_hidden;
static inline __typeof (__redirect_strcat) *
select_strcat_ifunc (uint64_t dl_hwcap, __riscv_hwprobe_t hwprobe_func)
{
+ if (dl_hwcap & COMPAT_HWCAP_ISA_V)
+ return __strcat_vector;
return __strcat_generic;
}
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/strchr.c b/sysdeps/unix/sysv/linux/riscv/multiarch/strchr.c
index a898f96bb8..cd043db06a 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/strchr.c
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/strchr.c
@@ -32,10 +32,13 @@
extern __typeof (__redirect_strchr) __libc_strchr;
extern __typeof (__redirect_strchr) __strchr_generic attribute_hidden;
+extern __typeof (__redirect_strchr) __strchr_vector attribute_hidden;
static inline __typeof (__redirect_strchr) *
select_strchr_ifunc (uint64_t dl_hwcap, __riscv_hwprobe_t hwprobe_func)
{
+ if (dl_hwcap & COMPAT_HWCAP_ISA_V)
+ return __strchr_vector;
return __strchr_generic;
}
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/strcmp.c b/sysdeps/unix/sysv/linux/riscv/multiarch/strcmp.c
index 9fd5c530bd..86a312d7f6 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/strcmp.c
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/strcmp.c
@@ -32,10 +32,13 @@
extern __typeof (__redirect_strcmp) __libc_strcmp;
extern __typeof (__redirect_strcmp) __strcmp_generic attribute_hidden;
+extern __typeof (__redirect_strcmp) __strcmp_vector attribute_hidden;
static inline __typeof (__redirect_strcmp) *
select_strcmp_ifunc (uint64_t dl_hwcap, __riscv_hwprobe_t hwprobe_func)
{
+ if (dl_hwcap & COMPAT_HWCAP_ISA_V)
+ return __strcmp_vector;
return __strcmp_generic;
}
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/strcpy.c b/sysdeps/unix/sysv/linux/riscv/multiarch/strcpy.c
index 473fa7768d..04164885c3 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/strcpy.c
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/strcpy.c
@@ -32,10 +32,13 @@
extern __typeof (__redirect_strcpy) __libc_strcpy;
extern __typeof (__redirect_strcpy) __strcpy_generic attribute_hidden;
+extern __typeof (__redirect_strcpy) __strcpy_vector attribute_hidden;
static inline __typeof (__redirect_strcpy) *
select_strcpy_ifunc (uint64_t dl_hwcap, __riscv_hwprobe_t hwprobe_func)
{
+ if (dl_hwcap & COMPAT_HWCAP_ISA_V)
+ return __strcpy_vector;
return __strcpy_generic;
}
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/strlen.c b/sysdeps/unix/sysv/linux/riscv/multiarch/strlen.c
index 4c15269028..e2fd06d2f4 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/strlen.c
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/strlen.c
@@ -32,10 +32,13 @@
extern __typeof (__redirect_strlen) __libc_strlen;
extern __typeof (__redirect_strlen) __strlen_generic attribute_hidden;
+extern __typeof (__redirect_strlen) __strlen_vector attribute_hidden;
static inline __typeof (__redirect_strlen) *
select_strlen_ifunc (uint64_t dl_hwcap, __riscv_hwprobe_t hwprobe_func)
{
+ if (dl_hwcap & COMPAT_HWCAP_ISA_V)
+ return __strlen_vector;
return __strlen_generic;
}
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/strncat.c b/sysdeps/unix/sysv/linux/riscv/multiarch/strncat.c
index 2dd5b98e56..802011835d 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/strncat.c
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/strncat.c
@@ -32,10 +32,13 @@
extern __typeof (__redirect_strncat) __libc_strncat;
extern __typeof (__redirect_strncat) __strncat_generic attribute_hidden;
+extern __typeof (__redirect_strncat) __strncat_vector attribute_hidden;
static inline __typeof (__redirect_strncat) *
select_strncat_ifunc (uint64_t dl_hwcap, __riscv_hwprobe_t hwprobe_func)
{
+ if (dl_hwcap & COMPAT_HWCAP_ISA_V)
+ return __strncat_vector;
return __strncat_generic;
}
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/strncmp.c b/sysdeps/unix/sysv/linux/riscv/multiarch/strncmp.c
index dc2f3dfbda..d5416c1d81 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/strncmp.c
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/strncmp.c
@@ -32,10 +32,13 @@
extern __typeof (__redirect_strncmp) __libc_strncmp;
extern __typeof (__redirect_strncmp) __strncmp_generic attribute_hidden;
+extern __typeof (__redirect_strncmp) __strncmp_vector attribute_hidden;
static inline __typeof (__redirect_strncmp) *
select_strncmp_ifunc (uint64_t dl_hwcap, __riscv_hwprobe_t hwprobe_func)
{
+ if (dl_hwcap & COMPAT_HWCAP_ISA_V)
+ return __strncmp_vector;
return __strncmp_generic;
}
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/strncpy.c b/sysdeps/unix/sysv/linux/riscv/multiarch/strncpy.c
index 87451820d9..827c331695 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/strncpy.c
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/strncpy.c
@@ -32,10 +32,13 @@
extern __typeof (__redirect_strncpy) __libc_strncpy;
extern __typeof (__redirect_strncpy) __strncpy_generic attribute_hidden;
+extern __typeof (__redirect_strncpy) __strncpy_vector attribute_hidden;
static inline __typeof (__redirect_strncpy) *
select_strncpy_ifunc (uint64_t dl_hwcap, __riscv_hwprobe_t hwprobe_func)
{
+ if (dl_hwcap & COMPAT_HWCAP_ISA_V)
+ return __strncpy_vector;
return __strncpy_generic;
}
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/strnlen.c b/sysdeps/unix/sysv/linux/riscv/multiarch/strnlen.c
index 1ce4512651..d2e736ad54 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/strnlen.c
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/strnlen.c
@@ -32,10 +32,13 @@
extern __typeof (__redirect_strnlen) __libc_strnlen;
extern __typeof (__redirect_strnlen) __strnlen_generic attribute_hidden;
+extern __typeof (__redirect_strnlen) __strnlen_vector attribute_hidden;
static inline __typeof (__redirect_strnlen) *
select_strnlen_ifunc (uint64_t dl_hwcap, __riscv_hwprobe_t hwprobe_func)
{
+ if (dl_hwcap & COMPAT_HWCAP_ISA_V)
+ return __strnlen_vector;
return __strnlen_generic;
}
--
2.47.2
More information about the Libc-alpha
mailing list