[glibc] riscv: Add RVV strcmp for both multiarch and non-multiarch builds
Peter Bergner via Glibc-cvs <[email protected]> Fri, 8 May 2026 14:32:28 +0000 (GMT)
| Newsgroups | gmane.comp.lib.glibc.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=d62f110fd1d158ca912f944072fe5750b6f09155 commit d62f110fd1d158ca912f944072fe5750b6f09155 Author: Yao Zihong <[email protected]> Date: Tue May 5 16:12:37 2026 -0500 riscv: Add RVV strcmp for both multiarch and non-multiarch builds This patch adds an RVV-optimized implementation of strcmp 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 (__strcmp_vector) is added alongside the generic fallback (__strcmp_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 strcmp(). 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/strcmp-generic.c | 24 ++++++ sysdeps/riscv/multiarch/strcmp-vector.S | 24 ++++++ sysdeps/riscv/rvv/strcmp.S | 93 ++++++++++++++++++++++ sysdeps/unix/sysv/linux/riscv/multiarch/Makefile | 3 + .../sysv/linux/riscv/multiarch/ifunc-impl-list.c | 5 ++ sysdeps/unix/sysv/linux/riscv/multiarch/strcmp.c | 56 +++++++++++++ 6 files changed, 205 insertions(+) diff --git a/sysdeps/riscv/multiarch/strcmp-generic.c b/sysdeps/riscv/multiarch/strcmp-generic.c new file mode 100644 index 0000000000..8ef46a44b9 --- /dev/null +++ b/sysdeps/riscv/multiarch/strcmp-generic.c @@ -0,0 +1,24 @@ +/* Re-include the default strcmp 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 STRCMP __strcmp_generic +# include <string/strcmp.c> +#endif diff --git a/sysdeps/riscv/multiarch/strcmp-vector.S b/sysdeps/riscv/multiarch/strcmp-vector.S new file mode 100644 index 0000000000..b9d9074b24 --- /dev/null +++ b/sysdeps/riscv/multiarch/strcmp-vector.S @@ -0,0 +1,24 @@ +/* Re-include the RISC-V RVV based strcmp 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 STRCMP __strcmp_vector +# undef libc_hidden_builtin_def +# define libc_hidden_builtin_def(name) +# include <sysdeps/riscv/rvv/strcmp.S> +#endif diff --git a/sysdeps/riscv/rvv/strcmp.S b/sysdeps/riscv/rvv/strcmp.S new file mode 100644 index 0000000000..a2f6865581 --- /dev/null +++ b/sysdeps/riscv/rvv/strcmp.S @@ -0,0 +1,93 @@ +/* RISC-V RVV based strcmp. + 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 STRCMP +# define STRCMP strcmp +#endif + +#define result a0 + +#define str1 a0 +#define str2 a1 + +#define ivl a2 +#define temp1 a3 +#define temp2 a4 + +#define vstr1 v0 +#define vstr2 v8 +#define vmask1 v16 +#define vmask2 v17 + +ENTRY (STRCMP) +.option push +.option arch, +v + /* lmul=1 */ +L(Loop): + vsetvli ivl, zero, e8, m1, ta, ma + vle8ff.v vstr1, (str1) + /* Check if vstr1[i] == 0 */ + vmseq.vx vmask1, vstr1, zero + + vle8ff.v vstr2, (str2) + /* Check if vstr1[i] != vstr2[i] */ + vmsne.vv vmask2, vstr1, vstr2 + + /* Find the index x for vstr1[x] == 0 */ + vfirst.m temp1, vmask1 + /* Find the index x for vstr1[x] != vstr2[x] */ + vfirst.m temp2, vmask2 + + bgez temp1, L(check1) + bgez temp2, L(check2) + + /* Get the current vl updated by vle8ff. */ + csrr ivl, vl + add str1, str1, ivl + add str2, str2, ivl + j L(Loop) + + /* temp1 >= 0 */ +L(check1): + bltz temp2, L(return_at_nul) + blt temp2, temp1, L(check2) +L(return_at_nul): + /* temp2 < 0 */ + /* temp2 >= 0 && temp1 < temp2 */ + add str1, str1, temp1 + add str2, str2, temp1 + lbu temp1, 0(str1) + lbu temp2, 0(str2) + sub result, temp1, temp2 + ret + + /* temp1 < 0 */ + /* temp2 >= 0 */ +L(check2): + add str1, str1, temp2 + add str2, str2, temp2 + lbu temp1, 0(str1) + lbu temp2, 0(str2) + sub result, temp1, temp2 + ret +.option pop +END (STRCMP) +libc_hidden_builtin_def (strcmp) diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile index 2a2b90960f..3da0306c5c 100644 --- a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile +++ b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile @@ -10,6 +10,9 @@ sysdep_routines += \ strcat \ strcat-generic \ strcat-vector \ + strcmp \ + strcmp-generic \ + strcmp-vector \ strcpy \ strcpy-generic \ strcpy-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 2501546665..76f68c1650 100644 --- a/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c +++ b/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c @@ -70,5 +70,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, __strlen_vector) IFUNC_IMPL_ADD (array, i, strlen, 1, __strlen_generic)) + IFUNC_IMPL (i, name, strcmp, + IFUNC_IMPL_ADD (array, i, strcmp, rvv_enabled, + __strcmp_vector) + IFUNC_IMPL_ADD (array, i, strcmp, 1, __strcmp_generic)) + return 0; } diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/strcmp.c b/sysdeps/unix/sysv/linux/riscv/multiarch/strcmp.c new file mode 100644 index 0000000000..9398ad4024 --- /dev/null +++ b/sysdeps/unix/sysv/linux/riscv/multiarch/strcmp.c @@ -0,0 +1,56 @@ +/* Multiple versions of strcmp. + 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 strcmp so that the compiler won't complain about the type + mismatch with the IFUNC selector in strong_alias, below. */ +# undef strcmp +# define strcmp __redirect_strcmp +# include <stdint.h> +# include <string.h> +# include <ifunc-init.h> +# include <riscv-ifunc.h> +# include <sys/hwprobe.h> + +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) +{ + 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 __strcmp_vector; + return __strcmp_generic; +} + +riscv_libc_ifunc (__libc_strcmp, select_strcmp_ifunc); + +# undef strcmp +strong_alias (__libc_strcmp, strcmp); +# ifdef SHARED +__hidden_ver1 (strcmp, __GI_strcmp, __redirect_strcmp) + __attribute__ ((visibility ("hidden"))) __attribute_copy__ (strcmp); +# endif +#else +# include <string/strcmp.c> +#endif