[PATCH 17/17] riscv: add vectorized strncasecmp

Pincheng Wang <[email protected]> Thu, 16 Jul 2026 23:00:48 +0800
Newsgroups gmane.comp.lib.newlib
Message-ID <[email protected]>
The vector implementation folds and 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.  The case folding
covers the ASCII letters A-Z only, matching the C/POSIX locale.  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/strncasecmp-asm.S | 63 +++++++++++++++++++++
 newlib/libc/machine/riscv/strncasecmp.c     |  5 ++
 3 files changed, 70 insertions(+)
 create mode 100644 newlib/libc/machine/riscv/strncasecmp-asm.S
 create mode 100644 newlib/libc/machine/riscv/strncasecmp.c

diff --git a/newlib/libc/machine/riscv/Makefile.inc b/newlib/libc/machine/riscv/Makefile.inc
index 2988f191f..6461aacd4 100644
--- a/newlib/libc/machine/riscv/Makefile.inc
+++ b/newlib/libc/machine/riscv/Makefile.inc
@@ -36,6 +36,8 @@ libc_a_SOURCES += \
 	%D%/strcspn.c \
 	%D%/strlen-asm.S \
 	%D%/strlen.c \
+	%D%/strncasecmp-asm.S \
+	%D%/strncasecmp.c \
 	%D%/strncat-asm.S \
 	%D%/strncat.c \
 	%D%/strncmp-asm.S \
diff --git a/newlib/libc/machine/riscv/strncasecmp-asm.S b/newlib/libc/machine/riscv/strncasecmp-asm.S
new file mode 100644
index 000000000..03f4d8df0
--- /dev/null
+++ b/newlib/libc/machine/riscv/strncasecmp-asm.S
@@ -0,0 +1,63 @@
+#if defined(__riscv_vector) && __riscv_xlen == 64 && !defined(__OPTIMIZE_SIZE__) && !defined(PREFER_SIZE_OVER_SPEED)
+.text
+.option push
+.option arch, +v
+/* int strncasecmp(const char *a0, const char *a1, size_t a2)
+   Case-insensitive compare of at most a2 bytes.  vle8ff keeps loads from
+   crossing a page boundary; vl is also capped by the remaining count so we
+   never read past the n-th byte.  The case folding covers the ASCII letters
+   A-Z only (the C/POSIX locale).  */
+.global strncasecmp
+.type strncasecmp, @function
+strncasecmp:
+  beqz a2, .Lzero
+  li t0, 65            /* 'A' */
+  li t1, 26
+  li t2, 32
+.Lloop:
+  vsetvli zero, a2, e8, m1, ta, mu
+  vle8ff.v v8, (a0)
+  vle8ff.v v16, (a1)
+  csrr a3, vl
+  /* fold left */
+  vsub.vx v24, v8, t0
+  vmsltu.vx v0, v24, t1
+  vadd.vx v8, v8, t2, v0.t
+  /* fold right */
+  vsub.vx v24, v16, t0
+  vmsltu.vx v0, v24, t1
+  vadd.vx v16, v16, t2, v0.t
+  /* NUL in left or mismatch */
+  vmseq.vi v1, v8, 0
+  vmsne.vv v2, v8, v16
+  vmor.mm v1, v1, v2
+  sub a2, a2, a3
+  vfirst.m a4, v1
+  bgez a4, .Lend
+  add a0, a0, a3
+  add a1, a1, a3
+  bnez a2, .Lloop
+  /* exhausted n with no NUL/diff: all compared bytes were equal -> 0 */
+  li a0, 0
+  ret
+.Lend:
+  add a0, a0, a4
+  add a1, a1, a4
+  lbu a4, 0(a0)
+  lbu a5, 0(a1)
+  addi a6, a4, -65
+  sltiu a6, a6, 26
+  slli a6, a6, 5
+  add a4, a4, a6
+  addi a6, a5, -65
+  sltiu a6, a6, 26
+  slli a6, a6, 5
+  add a5, a5, a6
+  sub a0, a4, a5
+  ret
+.Lzero:
+  li a0, 0
+  ret
+.size strncasecmp, .-strncasecmp
+.option pop
+#endif
diff --git a/newlib/libc/machine/riscv/strncasecmp.c b/newlib/libc/machine/riscv/strncasecmp.c
new file mode 100644
index 000000000..30f71d169
--- /dev/null
+++ b/newlib/libc/machine/riscv/strncasecmp.c
@@ -0,0 +1,5 @@
+#if defined(__OPTIMIZE_SIZE__) || defined(PREFER_SIZE_OVER_SPEED) || !defined(__riscv_vector) || __riscv_xlen != 64
+# include "../../string/strncasecmp.c"
+#else
+/* strncasecmp defined in strncasecmp-asm.S */
+#endif
-- 
2.39.5