From: Yao Zihong Date: Tue, 5 May 2026 21:22:29 +0000 (-0500) Subject: riscv: Add RVV strncmp for both multiarch and non-multiarch builds X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9b8ff36d0c881bfa08dfece10df89b1c199b23ee;p=thirdparty%2Fglibc.git riscv: Add RVV strncmp for both multiarch and non-multiarch builds This patch adds an RVV-optimized implementation of strncmp 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 (__strncmp_vector) is added alongside the generic fallback (__strncmp_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 strncmp(). Co-authored-by: Hau Hsu Co-authored-by: Jerry Shih Signed-off-by: Yao Zihong Reviewed-by: Peter Bergner --- diff --git a/sysdeps/riscv/multiarch/strncmp-generic.c b/sysdeps/riscv/multiarch/strncmp-generic.c new file mode 100644 index 0000000000..3d61dce1be --- /dev/null +++ b/sysdeps/riscv/multiarch/strncmp-generic.c @@ -0,0 +1,26 @@ +/* Re-include the default strncmp 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 + . */ + +#include + +#if IS_IN(libc) +# define STRNCMP __strncmp_generic +# undef libc_hidden_builtin_def +# define libc_hidden_builtin_def(x) +# include +#endif diff --git a/sysdeps/riscv/multiarch/strncmp-vector.S b/sysdeps/riscv/multiarch/strncmp-vector.S new file mode 100644 index 0000000000..91e25ea826 --- /dev/null +++ b/sysdeps/riscv/multiarch/strncmp-vector.S @@ -0,0 +1,24 @@ +/* Re-include the RISC-V RVV based strncmp 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 + . */ + +#if IS_IN(libc) +# define STRNCMP __strncmp_vector +# undef libc_hidden_builtin_def +# define libc_hidden_builtin_def(name) +# include +#endif diff --git a/sysdeps/riscv/rvv/strncmp.S b/sysdeps/riscv/rvv/strncmp.S new file mode 100644 index 0000000000..79c85f530c --- /dev/null +++ b/sysdeps/riscv/rvv/strncmp.S @@ -0,0 +1,88 @@ +/* RISC-V RVV based strncmp. + 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 + . */ + +#include +#include + +#ifndef STRNCMP +# define STRNCMP strncmp +#endif + +#define result a0 + +#define str1 a0 +#define str2 a1 +#define length a2 + +#define ivl a3 +#define temp1 a4 +#define temp2 a5 + +#define ELEM_LMUL_SETTING m1 +#define vstr1 v0 +#define vstr2 v4 +#define vmask1 v8 +#define vmask2 v9 + +ENTRY (STRNCMP) +.option push +.option arch, +v + beqz length, L(zero_length) +L(loop): + vsetvli zero, length, e8, ELEM_LMUL_SETTING, ta, ma + + vle8ff.v vstr1, (str1) + /* vstr1[i] == 0. */ + vmseq.vx vmask1, vstr1, zero + + vle8ff.v vstr2, (str2) + /* vstr1[i] != vstr2[i]. */ + vmsne.vv vmask2, vstr1, vstr2 + + csrr ivl, vl + + /* r = mask1 | mask2 + We can use vfirst.m to get the first zero char or the + first different char between str1 and str2. */ + vmor.mm vmask1, vmask1, vmask2 + + sub length, length, ivl + + vfirst.m temp1, vmask1 + + bgez temp1, L(end_loop) + + add str1, str1, ivl + add str2, str2, ivl + bnez length, L(loop) + +L(end_loop): + add str1, str1, temp1 + add str2, str2, temp1 + lbu temp1, 0(str1) + lbu temp2, 0(str2) + + sub result, temp1, temp2 + ret + +L(zero_length): + li result, 0 + ret +.option pop +END (STRNCMP) +libc_hidden_builtin_def (strncmp) diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile index 3da0306c5c..2fdd4af3eb 100644 --- a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile +++ b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile @@ -19,6 +19,9 @@ sysdep_routines += \ strlen \ strlen-generic \ strlen-vector \ + strncmp \ + strncmp-generic \ + strncmp-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 76f68c1650..a6765e5978 100644 --- a/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c +++ b/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c @@ -75,5 +75,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, __strcmp_vector) IFUNC_IMPL_ADD (array, i, strcmp, 1, __strcmp_generic)) + IFUNC_IMPL (i, name, strncmp, + IFUNC_IMPL_ADD (array, i, strncmp, rvv_enabled, + __strncmp_vector) + IFUNC_IMPL_ADD (array, i, strncmp, 1, __strncmp_generic)) + return 0; } diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/strncmp.c b/sysdeps/unix/sysv/linux/riscv/multiarch/strncmp.c new file mode 100644 index 0000000000..781e562629 --- /dev/null +++ b/sysdeps/unix/sysv/linux/riscv/multiarch/strncmp.c @@ -0,0 +1,56 @@ +/* Multiple versions of strncmp. + 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 + . */ + +#if IS_IN (libc) +/* Redefine strncmp so that the compiler won't complain about the type + mismatch with the IFUNC selector in strong_alias, below. */ +# undef strncmp +# define strncmp __redirect_strncmp +# include +# include +# include +# include +# include + +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) +{ + 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 __strncmp_vector; + return __strncmp_generic; +} + +riscv_libc_ifunc (__libc_strncmp, select_strncmp_ifunc); + +# undef strncmp +strong_alias (__libc_strncmp, strncmp); +# ifdef SHARED +__hidden_ver1 (strncmp, __GI_strncmp, __redirect_strncmp) + __attribute__ ((visibility ("hidden"))) __attribute_copy__ (strncmp); +# endif +#else +# include +#endif