[PATCH 05/17] riscv: add vectorized strrchr

Pincheng Wang <[email protected]> Thu, 16 Jul 2026 23:00:36 +0800
Newsgroups gmane.comp.lib.newlib
Message-ID <[email protected]>
The vector implementation makes a single forward pass, loading each chunk
with fault-only-first loads (vle8ff.v) and selecting the highest matching
lane index with a masked max-index reduction, so it 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  |  4 ++-
 newlib/libc/machine/riscv/strrchr-asm.S | 42 +++++++++++++++++++++++++
 newlib/libc/machine/riscv/strrchr.c     |  5 +++
 3 files changed, 50 insertions(+), 1 deletion(-)
 create mode 100644 newlib/libc/machine/riscv/strrchr-asm.S
 create mode 100644 newlib/libc/machine/riscv/strrchr.c

diff --git a/newlib/libc/machine/riscv/Makefile.inc b/newlib/libc/machine/riscv/Makefile.inc
index 3c13fbc1a..4bb7fefbb 100644
--- a/newlib/libc/machine/riscv/Makefile.inc
+++ b/newlib/libc/machine/riscv/Makefile.inc
@@ -29,4 +29,6 @@ libc_a_SOURCES += \
 	%D%/strlen-asm.S \
 	%D%/strlen.c \
 	%D%/strnlen-asm.S \
-	%D%/strnlen.c
+	%D%/strnlen.c \
+	%D%/strrchr-asm.S \
+	%D%/strrchr.c
diff --git a/newlib/libc/machine/riscv/strrchr-asm.S b/newlib/libc/machine/riscv/strrchr-asm.S
new file mode 100644
index 000000000..6bafca841
--- /dev/null
+++ b/newlib/libc/machine/riscv/strrchr-asm.S
@@ -0,0 +1,42 @@
+#if defined(__riscv_vector) && __riscv_xlen == 64 && !defined(__OPTIMIZE_SIZE__) && !defined(PREFER_SIZE_OVER_SPEED)
+.text
+.option push
+.option arch, +v
+/* char *strrchr(const char *a0, int a1)
+   Return the last occurrence of (char)a1 in a0, including the terminating
+   NUL when a1==0, else NULL.  Single forward pass: each chunk is loaded with
+   vle8ff (page-boundary safe) and the highest matching lane index is found
+   with a masked max-index reduction.  */
+.global strrchr
+.type strrchr, @function
+strrchr:
+  li a6, 0                  /* result pointer = NULL so far */
+.Lloop:
+  vsetvli a2, zero, e8, m1, ta, ma
+  vle8ff.v v8, (a0)
+  csrr a2, vl
+  vmseq.vi v1, v8, 0        /* NUL lanes */
+  vfirst.m a3, v1           /* first NUL position (or -1) */
+  vmseq.vx v2, v8, a1       /* lanes equal to (char)c */
+  vmsif.m v3, v1            /* valid lanes: up to & including first NUL */
+  vmand.mm v0, v2, v3       /* candidate matches within the string */
+  vfirst.m a4, v0           /* any candidate in this chunk? */
+  bltz a4, .Lskip
+  /* reduce the maximum lane index over candidate lanes (need e16 to be
+     safe for large VLEN where vl can exceed 255).  */
+  vsetvli zero, a2, e16, m2, ta, ma
+  vid.v v16
+  vmv.s.x v24, x0
+  vredmaxu.vs v24, v16, v24, v0.t
+  vmv.x.s a5, v24
+  add a6, a0, a5
+.Lskip:
+  bgez a3, .Ldone           /* reached end of string */
+  add a0, a0, a2
+  j .Lloop
+.Ldone:
+  mv a0, a6
+  ret
+.size strrchr, .-strrchr
+.option pop
+#endif
diff --git a/newlib/libc/machine/riscv/strrchr.c b/newlib/libc/machine/riscv/strrchr.c
new file mode 100644
index 000000000..2b548f82c
--- /dev/null
+++ b/newlib/libc/machine/riscv/strrchr.c
@@ -0,0 +1,5 @@
+#if defined(__OPTIMIZE_SIZE__) || defined(PREFER_SIZE_OVER_SPEED) || !defined(__riscv_vector) || __riscv_xlen != 64
+# include "../../string/strrchr.c"
+#else
+/* strrchr defined in strrchr-asm.S */
+#endif
-- 
2.39.5