[PATCH 16/17] riscv: add vectorized strcasecmp

Pincheng Wang <[email protected]> Thu, 16 Jul 2026 23:00:47 +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), so a vector
load is never forced across a page boundary into an unmapped page.  The
case folding covers the ASCII letters A-Z only, matching the C/POSIX
locale; builds that need locale-aware folding are handled by the guard
below.  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/strcasecmp-asm.S | 65 ++++++++++++++++++++++
 newlib/libc/machine/riscv/strcasecmp.c     |  5 ++
 3 files changed, 72 insertions(+)
 create mode 100644 newlib/libc/machine/riscv/strcasecmp-asm.S
 create mode 100644 newlib/libc/machine/riscv/strcasecmp.c

diff --git a/newlib/libc/machine/riscv/Makefile.inc b/newlib/libc/machine/riscv/Makefile.inc
index c2d918d03..2988f191f 100644
--- a/newlib/libc/machine/riscv/Makefile.inc
+++ b/newlib/libc/machine/riscv/Makefile.inc
@@ -20,6 +20,8 @@ libc_a_SOURCES += \
 	%D%/memset.S \
 	%D%/setjmp.S \
 	%D%/stpcpy.c \
+	%D%/strcasecmp-asm.S \
+	%D%/strcasecmp.c \
 	%D%/strcat-asm.S \
 	%D%/strcat.c \
 	%D%/strchr-asm.S \
diff --git a/newlib/libc/machine/riscv/strcasecmp-asm.S b/newlib/libc/machine/riscv/strcasecmp-asm.S
new file mode 100644
index 000000000..3b07ea164
--- /dev/null
+++ b/newlib/libc/machine/riscv/strcasecmp-asm.S
@@ -0,0 +1,65 @@
+#if defined(__riscv_vector) && __riscv_xlen == 64 && !defined(__OPTIMIZE_SIZE__) && !defined(PREFER_SIZE_OVER_SPEED)
+.text
+.option push
+.option arch, +v
+/* int strcasecmp(const char *a0, const char *a1)
+   Case-insensitive compare.  Scans with vle8ff so a vector load is never
+   forced across a page boundary into an unmapped page: element 0 is always
+   loaded, and a fault on any later element merely truncates vl.  The case
+   folding covers the ASCII letters A-Z only (the C/POSIX locale).  */
+.global strcasecmp
+.type strcasecmp, @function
+strcasecmp:
+  li t0, 65            /* 'A' */
+  li t1, 26            /* range of upper-case letters */
+  li t2, 32            /* 'a' - 'A' */
+.Lloop:
+  vsetvli a2, zero, e8, m1, ta, mu
+  vle8ff.v v8, (a0)
+  vle8ff.v v16, (a1)
+  csrr a2, vl
+  /* fold left: if (b-'A') <u 26 then b += 32 */
+  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
+  /* compare folded bytes */
+  vmseq.vi v1, v8, 0       /* NUL in left */
+  vmsne.vv v2, v8, v16     /* mismatch */
+  vfirst.m a3, v1
+  vfirst.m a4, v2
+  bgez a3, .Lnul
+  bgez a4, .Ldiff
+  add a0, a0, a2
+  add a1, a1, a2
+  j .Lloop
+.Lnul:                   /* a3 >= 0 (NUL position) */
+  bltz a4, .Lend
+  bge a4, a3, .Lend    /* NUL at or before mismatch */
+  mv a3, a4
+  j .Lend
+.Ldiff:                  /* a3 < 0, a4 >= 0 */
+  mv a3, a4
+.Lend:
+  add a0, a0, a3
+  add a1, a1, a3
+  lbu a4, 0(a0)
+  lbu a5, 0(a1)
+  /* tolower(a4) */
+  addi a6, a4, -65
+  sltiu a6, a6, 26
+  slli a6, a6, 5
+  add a4, a4, a6
+  /* tolower(a5) */
+  addi a6, a5, -65
+  sltiu a6, a6, 26
+  slli a6, a6, 5
+  add a5, a5, a6
+  sub a0, a4, a5
+  ret
+.size strcasecmp, .-strcasecmp
+.option pop
+#endif
diff --git a/newlib/libc/machine/riscv/strcasecmp.c b/newlib/libc/machine/riscv/strcasecmp.c
new file mode 100644
index 000000000..d603d09bc
--- /dev/null
+++ b/newlib/libc/machine/riscv/strcasecmp.c
@@ -0,0 +1,5 @@
+#if defined(__OPTIMIZE_SIZE__) || defined(PREFER_SIZE_OVER_SPEED) || !defined(__riscv_vector) || __riscv_xlen != 64
+# include "../../string/strcasecmp.c"
+#else
+/* strcasecmp defined in strcasecmp-asm.S */
+#endif
-- 
2.39.5