[PATCH 17/17] riscv: add vectorized strncasecmp
Pincheng Wang
pincheng.plct@isrc.iscas.ac.cn
Thu Jul 16 15:00:48 GMT 2026
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 <pincheng.plct@isrc.iscas.ac.cn>
---
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
More information about the Newlib
mailing list