[PATCH 07/17] riscv: add vectorized strncmp

Pincheng Wang <[email protected]> Thu, 16 Jul 2026 23:00:38 +0800
Newsgroups gmane.comp.lib.newlib
Message-ID <[email protected]>
The vector implementation compares both operands in vector-length chunks
using fault-only-first loads (vle8ff.v); vl is additionally capped by the
remaining count so it never reads past the n-th byte and never crosses
into an unmapped page.  This provides significant performance improvements
on RVV-capable hardware.  Use conditional compilation to fall back to the
generic implementation when __riscv_vector is not available, maintaining
compatibility with non-vector RISC-V systems.

Signed-off-by: Pincheng Wang <[email protected]>
---
 newlib/libc/machine/riscv/Makefile.inc  |  2 +
 newlib/libc/machine/riscv/strncmp-asm.S | 51 +++++++++++++++++++++++++
 newlib/libc/machine/riscv/strncmp.c     |  5 +++
 3 files changed, 58 insertions(+)
 create mode 100644 newlib/libc/machine/riscv/strncmp-asm.S
 create mode 100644 newlib/libc/machine/riscv/strncmp.c

diff --git a/newlib/libc/machine/riscv/Makefile.inc b/newlib/libc/machine/riscv/Makefile.inc
index 243195b36..015b91799 100644
--- a/newlib/libc/machine/riscv/Makefile.inc
+++ b/newlib/libc/machine/riscv/Makefile.inc
@@ -29,6 +29,8 @@ libc_a_SOURCES += \
 	%D%/strcpy.c \
 	%D%/strlen-asm.S \
 	%D%/strlen.c \
+	%D%/strncmp-asm.S \
+	%D%/strncmp.c \
 	%D%/strnlen-asm.S \
 	%D%/strnlen.c \
 	%D%/strrchr-asm.S \
diff --git a/newlib/libc/machine/riscv/strncmp-asm.S b/newlib/libc/machine/riscv/strncmp-asm.S
new file mode 100644
index 000000000..a4685943d
--- /dev/null
+++ b/newlib/libc/machine/riscv/strncmp-asm.S
@@ -0,0 +1,51 @@
+#if defined(__riscv_vector) && __riscv_xlen == 64 && !defined(__OPTIMIZE_SIZE__) && !defined(PREFER_SIZE_OVER_SPEED)
+.text
+.option push
+.option arch, +v
+.global strncmp
+.type strncmp, @function
+strncmp:
+  beqz a2, .Lzero_length
+.Lloop:
+  vsetvli zero, a2, e8, m1, ta, ma
+
+  vle8ff.v v0, (a0)
+  /* v0[i] == 0.  */
+  vmseq.vx v8, v0, zero
+
+  vle8ff.v v4, (a1)
+  /* v0[i] != v4[i].  */
+  vmsne.vv v9, v0, v4
+
+  csrr a3, vl
+
+  /* r = mask1 | mask2
+     Combine the first NUL in a0 with the first differing byte so a single
+     vfirst.m locates whichever comes first.  */
+  vmor.mm v8, v8, v9
+
+  sub a2, a2, a3
+
+  vfirst.m a4, v8
+
+  bgez a4, .Lend_loop
+
+  add a0, a0, a3
+  add a1, a1, a3
+  bnez a2, .Lloop
+.Lend_loop:
+
+  add a0, a0, a4
+  add a1, a1, a4
+  lbu a4, 0(a0)
+  lbu a5, 0(a1)
+
+  sub a0, a4, a5
+  ret
+
+.Lzero_length:
+  li a0, 0
+  ret
+.size strncmp, .-strncmp
+.option pop
+#endif
diff --git a/newlib/libc/machine/riscv/strncmp.c b/newlib/libc/machine/riscv/strncmp.c
new file mode 100644
index 000000000..cf64b88f6
--- /dev/null
+++ b/newlib/libc/machine/riscv/strncmp.c
@@ -0,0 +1,5 @@
+#if defined(__OPTIMIZE_SIZE__) || defined(PREFER_SIZE_OVER_SPEED) || !defined(__riscv_vector) || __riscv_xlen != 64
+# include "../../string/strncmp.c"
+#else
+/* strncmp defined in strncmp-asm.S */
+#endif
-- 
2.39.5