[glibc] riscv: Add RVV strchr for both multiarch and non-multiarch builds
Peter Bergner via Glibc-cvs <[email protected]> Fri, 5 Jun 2026 01:50:14 +0000 (GMT)
| Newsgroups | gmane.comp.lib.glibc.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=bbc3867f8d8f70959cebc7a619e84a1701446948 commit bbc3867f8d8f70959cebc7a619e84a1701446948 Author: Yao Zihong <[email protected]> Date: Thu Jun 4 19:37:35 2026 -0500 riscv: Add RVV strchr for both multiarch and non-multiarch builds This patch adds an RVV-optimized implementation of strchr for RISC-V and enables it for both multiarch (IFUNC) and non-multiarch builds. The implementation integrates Hau Hsu's 2023 RVV work under a unified ifunc-based framework. A vectorized version (__strchr_vector) is added alongside the generic fallback (__strchr_generic). The runtime resolver selects the RVV variant when RISCV_HWPROBE_KEY_IMA_EXT_0 reports vector support (RVV). Currently, the resolver still selects the RVV variant even when the RVV extension is disabled via prctl(). As a consequence, any process that has RVV disabled via prctl() will receive SIGILL when calling strchr(). Co-authored-by: Hau Hsu <[email protected]> Co-authored-by: Jerry Shih <[email protected]> Signed-off-by: Yao Zihong <[email protected]> Reviewed-by: Peter Bergner <[email protected]> Diff: --- sysdeps/riscv/multiarch/strchr-generic.c | 24 ++++++++ sysdeps/riscv/multiarch/strchr-vector.S | 26 +++++++++ sysdeps/riscv/rvv/strchr.S | 65 ++++++++++++++++++++++ sysdeps/unix/sysv/linux/riscv/multiarch/Makefile | 3 + .../sysv/linux/riscv/multiarch/ifunc-impl-list.c | 5 ++ sysdeps/unix/sysv/linux/riscv/multiarch/strchr.c | 58 +++++++++++++++++++ 6 files changed, 181 insertions(+) diff --git a/sysdeps/riscv/multiarch/strchr-generic.c b/sysdeps/riscv/multiarch/strchr-generic.c new file mode 100644 index 0000000000..301b7dc64b --- /dev/null +++ b/sysdeps/riscv/multiarch/strchr-generic.c @@ -0,0 +1,24 @@ +/* Re-include the default strchr implementation. + Copyright (C) 2026 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 <string.h> + +#if IS_IN(libc) +# define STRCHR __strchr_generic +# include <string/strchr.c> +#endif diff --git a/sysdeps/riscv/multiarch/strchr-vector.S b/sysdeps/riscv/multiarch/strchr-vector.S new file mode 100644 index 0000000000..c55a1f993f --- /dev/null +++ b/sysdeps/riscv/multiarch/strchr-vector.S @@ -0,0 +1,26 @@ +/* Re-include the RISC-V RVV based strchr implementation. + Copyright (C) 2026 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/>. */ + +#if IS_IN(libc) +# define STRCHR __strchr_vector +# undef libc_hidden_builtin_def +# define libc_hidden_builtin_def(name) +# undef weak_alias +# define weak_alias(name, alias) +# include <sysdeps/riscv/rvv/strchr.S> +#endif diff --git a/sysdeps/riscv/rvv/strchr.S b/sysdeps/riscv/rvv/strchr.S new file mode 100644 index 0000000000..2fa95c31ba --- /dev/null +++ b/sysdeps/riscv/rvv/strchr.S @@ -0,0 +1,65 @@ +/* RISC-V RVV based strchr. + Copyright (C) 2026 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 <sysdep.h> +#include <sys/asm.h> + +#ifndef STRCHR +# define STRCHR strchr +#endif + +#define str a0 +#define ch a1 +#define end_offset a2 +#define ch_offset a3 +#define temp1 a4 +#define temp2 a5 +#define cur_vl a6 +#define ivl t0 + +#define ELEM_LMUL_SETTING m1 +#define vstr v0 +#define vmask_end v8 +#define vmask_ch v9 + +ENTRY (STRCHR) +.option push +.option arch, +v +L(strchr_loop): + vsetvli ivl, zero, e8, ELEM_LMUL_SETTING, ta, ma + vle8ff.v vstr, (str) + vmseq.vi vmask_end, vstr, 0 + vmseq.vx vmask_ch, vstr, ch + vfirst.m end_offset, vmask_end /* first occurrence of \0 */ + vfirst.m ch_offset, vmask_ch /* first occurrence of ch */ + sltz temp1, ch_offset + sltu temp2, end_offset, ch_offset + or temp1, temp1, temp2 + beqz temp1, L(found_ch) /* Found ch, not preceded by \0? */ + csrr cur_vl, vl + add str, str, cur_vl + bltz end_offset, L(strchr_loop) /* Didn't find \0? */ + li str, 0 + ret +L(found_ch): + add str, str, ch_offset + ret +.option pop +END (STRCHR) +weak_alias (STRCHR, index) +libc_hidden_builtin_def (strchr) diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile index c74b470bd6..2714b9e2d8 100644 --- a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile +++ b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile @@ -19,6 +19,9 @@ sysdep_routines += \ strcat \ strcat-generic \ strcat-vector \ + strchr \ + strchr-generic \ + strchr-vector \ strcmp \ strcmp-generic \ strcmp-vector \ 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 caea83b7d7..f00001097b 100644 --- a/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c +++ b/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c @@ -95,5 +95,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, __memchr_vector) IFUNC_IMPL_ADD (array, i, memchr, 1, __memchr_generic)) + IFUNC_IMPL (i, name, strchr, + IFUNC_IMPL_ADD (array, i, strchr, rvv_enabled, + __strchr_vector) + IFUNC_IMPL_ADD (array, i, strchr, 1, __strchr_generic)) + return 0; } diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/strchr.c b/sysdeps/unix/sysv/linux/riscv/multiarch/strchr.c new file mode 100644 index 0000000000..ef75a2b0a9 --- /dev/null +++ b/sysdeps/unix/sysv/linux/riscv/multiarch/strchr.c @@ -0,0 +1,58 @@ +/* Multiple versions of strchr. + All versions must be listed in ifunc-impl-list.c. + Copyright (C) 2026 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/>. */ + +#if IS_IN (libc) +/* Redefine strchr so that the compiler won't complain about the type + mismatch with the IFUNC selector in strong_alias, below. */ +# undef strchr +# define strchr __redirect_strchr +# include <stdint.h> +# include <string.h> +# include <ifunc-init.h> +# include <riscv-ifunc.h> +# include <sys/hwprobe.h> + +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) +{ + unsigned long long int v; + if (__riscv_hwprobe_one (hwprobe_func, RISCV_HWPROBE_KEY_IMA_EXT_0, &v) == 0 + && (v & RISCV_HWPROBE_IMA_V) == RISCV_HWPROBE_IMA_V) + return __strchr_vector; + return __strchr_generic; +} + +riscv_libc_ifunc (__libc_strchr, select_strchr_ifunc); + +# undef strchr +# undef index +strong_alias (__libc_strchr, strchr); +weak_alias (strchr, index); +# ifdef SHARED +__hidden_ver1 (strchr, __GI_strchr, __redirect_strchr) + __attribute__ ((visibility ("hidden"))) __attribute_copy__ (strchr); +# endif +#else +# include <string/strchr.c> +#endif