[PATCH v3] riscv: Add optimised memcmp implementation using RISC-V RVV extension
Zheng Ziyang
zheng.ziyang@zte.com.cn
Fri Jan 16 06:45:24 GMT 2026
From: zhengziyang <zheng.ziyang@zte.com.cn>
This patch adds an optimized memcmp implementation for RISC-V using the
RVV extension.
The implementation assumes RVV 1.0 with VLEN >= 128, supports arbitrary
VLEN configurations, and works on both RV32 and RV64 platforms. No
page-size assumptions are made.
Performance improvements (relative speedup %) over __memcmp_generic
baseline:
| Test Category | Config (VLENB) | vs. __memcmp_generic |
|--------------------|-----------------------|----------------------|
| **memcmp-default** | XuanTie C920 (128) | +52.6% |
| | Spacemit(R) X60 (256) | +11.2% |
Signed-off-by: Zheng Ziyang <zheng.ziyang@zte.com.cn>
---
string/memcmp.c | 4 +-
sysdeps/riscv/multiarch/memcmp-generic.c | 26 +++++
sysdeps/riscv/multiarch/memcmp-vector.S | 25 +++++
sysdeps/riscv/rvv/memcmp.S | 102 ++++++++++++++++++
.../unix/sysv/linux/riscv/multiarch/Makefile | 3 +
.../linux/riscv/multiarch/ifunc-impl-list.c | 5 +
.../unix/sysv/linux/riscv/multiarch/memcmp.c | 57 ++++++++++
7 files changed, 220 insertions(+), 2 deletions(-)
create mode 100644 sysdeps/riscv/multiarch/memcmp-generic.c
create mode 100644 sysdeps/riscv/multiarch/memcmp-vector.S
create mode 100644 sysdeps/riscv/rvv/memcmp.S
create mode 100644 sysdeps/unix/sysv/linux/riscv/multiarch/memcmp.c
diff --git a/string/memcmp.c b/string/memcmp.c
index cd595ce95e..5f8b0698f0 100644
--- a/string/memcmp.c
+++ b/string/memcmp.c
@@ -353,9 +353,9 @@ MEMCMP (const void *s1, const void *s2, size_t len)
libc_hidden_builtin_def(memcmp)
#ifdef weak_alias
# undef bcmp
-weak_alias (memcmp, bcmp)
+weak_alias (MEMCMP, bcmp)
#endif
#undef __memcmpeq
-strong_alias (memcmp, __memcmpeq)
+strong_alias (MEMCMP, __memcmpeq)
libc_hidden_def(__memcmpeq)
diff --git a/sysdeps/riscv/multiarch/memcmp-generic.c b/sysdeps/riscv/multiarch/memcmp-generic.c
new file mode 100644
index 0000000000..1a52201f1a
--- /dev/null
+++ b/sysdeps/riscv/multiarch/memcmp-generic.c
@@ -0,0 +1,26 @@
+/* Re-include the default memcpy 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 MEMCMP __memcmp_generic
+# undef libc_hidden_builtin_def
+# define libc_hidden_builtin_def(x)
+#endif
+#include <string/memcmp.c>
diff --git a/sysdeps/riscv/multiarch/memcmp-vector.S b/sysdeps/riscv/multiarch/memcmp-vector.S
new file mode 100644
index 0000000000..b3d396e9ab
--- /dev/null
+++ b/sysdeps/riscv/multiarch/memcmp-vector.S
@@ -0,0 +1,25 @@
+
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#if IS_IN(libc)
+# define MEMCMP __memcmp_vector
+# undef libc_hidden_builtin_def
+# define libc_hidden_builtin_def(name)
+#include <sysdeps/riscv/rvv/memcmp.S>
+#endif
diff --git a/sysdeps/riscv/rvv/memcmp.S b/sysdeps/riscv/rvv/memcmp.S
new file mode 100644
index 0000000000..7303087551
--- /dev/null
+++ b/sysdeps/riscv/rvv/memcmp.S
@@ -0,0 +1,102 @@
+/* memcmp for RISC-V, ignoring buffer alignment
+ 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 Lesser General Public License. If not, see
+ <https://www.gnu.org/licenses/>.
+*/
+
+#include <sysdep.h>
+#include <sys/asm.h>
+
+/* ----------------------------------------------------
+ * Register Aliases
+ * ---------------------------------------------------- */
+
+/* Return value: difference between first mismatched bytes */
+#define result a0
+
+/* Function arguments */
+#define src1 a0 /* const void *s1 - first buffer pointer */
+#define src2 a1 /* const void *s2 - second buffer pointer */
+#define num a2 /* size_t n - number of bytes to compare */
+
+/* Temporary registers */
+#define ivl a3
+#define temp a4
+#define temp1 a5
+#define temp2 a6
+
+/* Vector configuration */
+#define ELEM_LMUL_SETTING m8
+#define vdata1 v0
+#define vdata2 v8
+#define vmask v16
+
+
+ENTRY (__memcmp_vector)
+.option push
+.option arch, +v
+
+ /* ----------------------------------------------------
+ * Initial Check
+ * If length is 0, buffers are trivially equal.
+ * ---------------------------------------------------- */
+ beqz num, L(equal)
+
+ vsetvli ivl, num, e8, ELEM_LMUL_SETTING, ta, ma
+
+L(loop):
+ /* Load vector chunks from both source buffers */
+ vle8.v vdata1, (src1)
+ sub num, num, ivl
+ vle8.v vdata2, (src2)
+
+ vmsne.vv vmask, vdata1, vdata2
+ vfirst.m temp, vmask
+
+ /* If temp >= 0, we found a difference - exit loop */
+ bgez temp, L(found)
+
+ /* No difference found in this chunk - advance to next */
+ add src1, src1, ivl
+ add src2, src2, ivl
+ bgeu num, ivl, L(loop)
+
+ /* ----------------------------------------------------
+ * Process remaining bytes (0 < num < ivl).
+ * ---------------------------------------------------- */
+ beqz num, L(equal)
+
+ vsetvli ivl, num, e8, ELEM_LMUL_SETTING, ta, ma
+ vle8.v vdata1, (src1)
+ vle8.v vdata2, (src2)
+ vmsne.vv vmask, vdata1, vdata2
+ vfirst.m temp, vmask
+ bgez temp, L(found)
+
+
+L(equal):
+ li result, 0 /* Set return value to 0 */
+ ret
+
+L(found):
+ add src1, src1, temp
+ add src2, src2, temp
+ lbu temp1, 0(src1)
+ lbu temp2, 0(src2)
+ sub result, temp1, temp2
+ ret
+.option pop
+END (__memcmp_vector)
\ No newline at end of file
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
index 1d26966ded..fa1b5a84ed 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_noalignment \
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 87456f3370..d5cb49aa5c 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c
@@ -53,5 +53,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
__memset_vector)
IFUNC_IMPL_ADD (array, i, memset, 1, __memset_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..d1ba090387
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/memcmp.c
@@ -0,0 +1,57 @@
+/* Multiple versions of memcpy.
+ 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 memcpy 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 <stdint.h>
+# include <string.h>
+# include <ifunc-init.h>
+# include <riscv-ifunc.h>
+# include <sys/hwprobe.h>
+
+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 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 __memcmp_vector;
+
+ return __memcmp_generic;
+}
+
+riscv_libc_ifunc (__libc_memcmp, select_memcmp_ifunc);
+
+# undef memcmp
+strong_alias (__libc_memcmp, memcmp);
+# ifdef SHARED
+__hidden_ver1 (memcmp, __GI_memcmp, __redirect_memcmp)
+ __attribute__ ((visibility ("hidden"))) __attribute_copy__ (memcmp);
+# endif
+#else
+# include <string/memcmp.c>
+#endif
--
2.21.0.windows.1
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://sourceware.org/pipermail/libc-alpha/attachments/20260116/3132cbea/attachment-0001.htm>
More information about the Libc-alpha
mailing list