[glibc] riscv: Add RVV stpncpy for both multiarch and non-multiarch builds
Peter Bergner via Glibc-cvs <[email protected]> Sun, 5 Jul 2026 13:38:06 +0000 (GMT)
| Newsgroups | gmane.comp.lib.glibc.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=df0669d41d753269312374e2eb6bd107bbec9c7b commit df0669d41d753269312374e2eb6bd107bbec9c7b Author: Yao Zihong <[email protected]> Date: Thu Jul 2 03:45:24 2026 +0000 riscv: Add RVV stpncpy for both multiarch and non-multiarch builds This patch adds an RVV-optimized implementation of stpncpy 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 (__stpncpy_vector) is added alongside the generic fallback (__stpncpy_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 stpncpy(). 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/stpncpy-generic.c | 28 +++++++ sysdeps/riscv/multiarch/stpncpy-vector.S | 28 +++++++ sysdeps/riscv/rvv/stpncpy.S | 97 ++++++++++++++++++++++ sysdeps/unix/sysv/linux/riscv/multiarch/Makefile | 3 + .../sysv/linux/riscv/multiarch/ifunc-impl-list.c | 5 ++ sysdeps/unix/sysv/linux/riscv/multiarch/stpncpy.c | 62 ++++++++++++++ 6 files changed, 223 insertions(+) diff --git a/sysdeps/riscv/multiarch/stpncpy-generic.c b/sysdeps/riscv/multiarch/stpncpy-generic.c new file mode 100644 index 0000000000..4be8080d88 --- /dev/null +++ b/sysdeps/riscv/multiarch/stpncpy-generic.c @@ -0,0 +1,28 @@ +/* Re-include the default stpncpy 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 STPNCPY __stpncpy_generic +# undef libc_hidden_def +# define libc_hidden_def(name) +# undef weak_alias +# define weak_alias(x, x2) +# include <string/stpncpy.c> +#endif diff --git a/sysdeps/riscv/multiarch/stpncpy-vector.S b/sysdeps/riscv/multiarch/stpncpy-vector.S new file mode 100644 index 0000000000..e84d28a1e4 --- /dev/null +++ b/sysdeps/riscv/multiarch/stpncpy-vector.S @@ -0,0 +1,28 @@ +/* Re-include the RISC-V RVV based stpncpy 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 STPNCPY __stpncpy_vector +# undef libc_hidden_builtin_def +# define libc_hidden_builtin_def(name) +# undef libc_hidden_def +# define libc_hidden_def(name) +# undef weak_alias +# define weak_alias(name, alias) +# include <sysdeps/riscv/rvv/stpncpy.S> +#endif diff --git a/sysdeps/riscv/rvv/stpncpy.S b/sysdeps/riscv/rvv/stpncpy.S new file mode 100644 index 0000000000..7cfc2f76cc --- /dev/null +++ b/sysdeps/riscv/rvv/stpncpy.S @@ -0,0 +1,97 @@ +/* RISC-V RVV based stpncpy. + 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 STPNCPY +# ifdef weak_alias +# define STPNCPY __stpncpy +weak_alias (__stpncpy, stpncpy) +# else +# define STPNCPY stpncpy +# endif +#endif + +#define dst a0 +#define src a1 +#define length a2 +#define dst_ptr a3 +#define active_elem_pos a4 +#define cur_vl a5 +#define ivl a6 +#define temp a1 + +#define ELEM_LMUL_SETTING m1 +#define vmask1 v0 +#define vmask2 v1 +#define ZERO_FILL_ELEM_LMUL_SETTING m8 +#define vstr1 v8 +#define vstr2 v16 + +ENTRY (STPNCPY) +.option push +.option arch, +v + mv dst_ptr, dst + /* Copy src to dst_ptr. */ +L(stpcpy_loop): + vsetvli zero, length, e8, ELEM_LMUL_SETTING, ta, ma + vle8ff.v vstr1, (src) + vmseq.vx vmask2, vstr1, zero + csrr cur_vl, vl + vfirst.m active_elem_pos, vmask2 + vmsif.m vmask1, vmask2 + add src, src, cur_vl + sub length, length, cur_vl + vse8.v vstr1, (dst_ptr), vmask1.t + add dst_ptr, dst_ptr, cur_vl + bgez active_elem_pos, L(fill_zero) + bnez length, L(stpcpy_loop) + mv dst, dst_ptr + ret + + /* Fill the tail zero. */ +L(fill_zero): + /* We already copied the `\0` to dst, but we use `vfirst.m` to + get the `index` of the `\0` position. We need to adjust by `-1` + to get the correct remaining length for zero filling. */ + sub temp, cur_vl, active_elem_pos + addi temp, temp, -1 + sub dst, dst_ptr, cur_vl + add dst, dst, active_elem_pos + add length, length, temp + /* Return early for the `strlen(src) + 1 == count` case. */ + bnez length, L(do_fill_zero) + ret + +L(do_fill_zero): + sub dst_ptr, dst_ptr, temp + vsetvli zero, length, e8, ZERO_FILL_ELEM_LMUL_SETTING, ta, ma + vmv.v.x vstr2, zero +L(fill_zero_loop): + vsetvli ivl, length, e8, ZERO_FILL_ELEM_LMUL_SETTING, ta, ma + vse8.v vstr2, (dst_ptr) + sub length, length, ivl + add dst_ptr, dst_ptr, ivl + bnez length, L(fill_zero_loop) + ret +.option pop +END (STPNCPY) +#ifdef weak_alias +libc_hidden_def (__stpncpy) +#endif diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile index 929df14a6f..25d8216d2e 100644 --- a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile +++ b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile @@ -19,6 +19,9 @@ sysdep_routines += \ memset \ memset-generic \ memset-vector \ + stpncpy \ + stpncpy-generic \ + stpncpy-vector \ strcat \ strcat-generic \ strcat-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 4c28e22606..755ba9d637 100644 --- a/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c +++ b/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c @@ -110,5 +110,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, __memmove_vector) IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_generic)) + IFUNC_IMPL (i, name, stpncpy, + IFUNC_IMPL_ADD (array, i, stpncpy, rvv_enabled, + __stpncpy_vector) + IFUNC_IMPL_ADD (array, i, stpncpy, 1, __stpncpy_generic)) + return 0; } diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/stpncpy.c b/sysdeps/unix/sysv/linux/riscv/multiarch/stpncpy.c new file mode 100644 index 0000000000..989003f081 --- /dev/null +++ b/sysdeps/unix/sysv/linux/riscv/multiarch/stpncpy.c @@ -0,0 +1,62 @@ +/* Multiple versions of stpncpy. + 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) +#define SYMBOL_NAME stpncpy +# include <ifunc-init.h> + +/* Redefine stpncpy so that the compiler won't complain about the type + mismatch with the IFUNC selector in weak_alias, below. */ +# undef stpncpy +# undef __stpncpy +# define stpncpy REDIRECT_NAME +# define __stpncpy __redirect___stpncpy +# include <string.h> +# undef stpncpy +# undef __stpncpy + +# include <stdint.h> +# include <riscv-ifunc.h> +# include <sys/hwprobe.h> + +extern __typeof (REDIRECT_NAME) __stpncpy; +extern __typeof (REDIRECT_NAME) OPTIMIZE (generic) attribute_hidden; +extern __typeof (REDIRECT_NAME) OPTIMIZE (vector) attribute_hidden; + +static inline __typeof (REDIRECT_NAME) * +select_stpncpy_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 OPTIMIZE (vector); + return OPTIMIZE (generic); +} + +riscv_libc_ifunc (__stpncpy, select_stpncpy_ifunc); + +weak_alias (__stpncpy, stpncpy); + +# ifdef SHARED +__hidden_ver1 (__stpncpy, __GI___stpncpy, __redirect___stpncpy) + __attribute__ ((visibility ("hidden"))); +# endif +#else +# include <string/stpncpy.c> +#endif