[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