From: Yao Zihong Date: Thu, 4 Jun 2026 23:28:06 +0000 (-0500) Subject: riscv: Add RVV memcmp for both multiarch and non-multiarch builds X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2efc702628;p=thirdparty%2Fglibc.git riscv: Add RVV memcmp for both multiarch and non-multiarch builds This patch adds an RVV-optimized implementation of memcmp 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 (__memcmp_vector) is added alongside the generic fallback (__memcmp_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 memcmp(). 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/dl-symbol-redir-ifunc.h b/sysdeps/riscv/multiarch/dl-symbol-redir-ifunc.h index c6f2aacd17..f81e5b7e6d 100644 --- a/sysdeps/riscv/multiarch/dl-symbol-redir-ifunc.h +++ b/sysdeps/riscv/multiarch/dl-symbol-redir-ifunc.h @@ -20,6 +20,7 @@ #define _DL_IFUNC_GENERIC_H #ifndef SHARED +asm ("memcmp = __memcmp_generic"); asm ("memcpy = __memcpy_generic"); asm ("memset = __memset_generic"); asm ("strlen = __strlen_generic"); diff --git a/sysdeps/riscv/multiarch/memcmp-generic.c b/sysdeps/riscv/multiarch/memcmp-generic.c new file mode 100644 index 0000000000..14f6752406 --- /dev/null +++ b/sysdeps/riscv/multiarch/memcmp-generic.c @@ -0,0 +1,30 @@ +/* Re-include the default memcmp 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 MEMCMP __memcmp_generic +# undef libc_hidden_def +# define libc_hidden_def(x) +# undef weak_alias +# define weak_alias(x, x2) +# undef strong_alias +# define strong_alias(x, x2) +# include +#endif diff --git a/sysdeps/riscv/multiarch/memcmp-vector.S b/sysdeps/riscv/multiarch/memcmp-vector.S new file mode 100644 index 0000000000..b447e945a8 --- /dev/null +++ b/sysdeps/riscv/multiarch/memcmp-vector.S @@ -0,0 +1,30 @@ +/* Re-include the RISC-V RVV based memcmp 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 MEMCMP __memcmp_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) +# undef strong_alias +# define strong_alias(name, alias) +# include +#endif diff --git a/sysdeps/riscv/rvv/memcmp.S b/sysdeps/riscv/rvv/memcmp.S new file mode 100644 index 0000000000..004bf538f0 --- /dev/null +++ b/sysdeps/riscv/rvv/memcmp.S @@ -0,0 +1,84 @@ +/* RISC-V RVV based memcmp. + 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 MEMCMP +# define MEMCMP memcmp +#endif + +#define result a0 + +#define src1 a0 +#define src2 a1 +#define num a2 + +#define ivl a3 +#define temp a4 + +#define ELEM_LMUL_SETTING m8 +#define vdata1 v0 +#define vdata2 v8 +#define vmask v16 +#define vtemp1 v16 +#define vtemp2 v24 + +ENTRY (MEMCMP) +.option push +.option arch, +v +L(loop): + vsetvli ivl, num, e8, ELEM_LMUL_SETTING, ta, ma + + vle8.v vdata1, (src1) + vle8.v vdata2, (src2) + + vmsne.vv vmask, vdata1, vdata2 + sub num, num, ivl + vfirst.m temp, vmask + + bgez temp, L(found) + + add src1, src1, ivl + add src2, src2, ivl + + bnez num, L(loop) + + li result, 0 + ret +L(found): + vrgather.vx vtemp1, vdata1, temp + vrgather.vx vtemp2, vdata2, temp + vmv.x.s result, vtemp1 + vmv.x.s temp, vtemp2 + andi result, result, 0xff + andi temp, temp, 0xff + sub result, result, temp + ret +.option pop +END (MEMCMP) +libc_hidden_builtin_def(memcmp) +#ifdef weak_alias +#undef bcmp +weak_alias (MEMCMP, bcmp) +#endif + +#undef __memcmpeq +strong_alias (MEMCMP, __memcmpeq) +libc_hidden_builtin_def (MEMCMP) +libc_hidden_def (__memcmpeq) diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile index 2fdd4af3eb..20ff2bdca2 100644 --- a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile +++ b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile @@ -1,5 +1,8 @@ ifeq ($(subdir),string) sysdep_routines += \ + memcmp \ + memcmp-generic \ + memcmp-vector \ memcpy \ memcpy-generic \ memcpy-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 a6765e5978..1d09cf27a3 100644 --- a/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c +++ b/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c @@ -80,5 +80,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, __strncmp_vector) IFUNC_IMPL_ADD (array, i, strncmp, 1, __strncmp_generic)) + IFUNC_IMPL (i, name, memcmp, + IFUNC_IMPL_ADD (array, i, memcmp, rvv_enabled, + __memcmp_vector) + IFUNC_IMPL_ADD (array, i, memcmp, 1, __memcmp_generic)) + return 0; } diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/memcmp.c b/sysdeps/unix/sysv/linux/riscv/multiarch/memcmp.c new file mode 100644 index 0000000000..20e7b046ab --- /dev/null +++ b/sysdeps/unix/sysv/linux/riscv/multiarch/memcmp.c @@ -0,0 +1,60 @@ +/* Multiple versions of memcmp. + 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 memcmp so that the compiler won't complain about the type + mismatch with the IFUNC selector in strong_alias, below. */ +# undef memcmp +# define memcmp __redirect_memcmp +# include +# include +# include +# include +# include + +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) +{ + unsigned long long 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 __memcmp_vector; + + return __memcmp_generic; +} + +riscv_libc_ifunc (__libc_memcmp, select_memcmp_ifunc); + +# undef memcmp +# undef bcmp +strong_alias (__libc_memcmp, memcmp); +weak_alias (memcmp, bcmp); +# ifdef SHARED +__hidden_ver1 (memcmp, __GI_memcmp, __redirect_memcmp) + __attribute__ ((visibility ("hidden"))) __attribute_copy__ (memcmp); +# endif +#else +# include +#endif