[PATCH v3 05/15] riscv: add vectorized strrchr
Pincheng Wang
pincheng.plct@isrc.iscas.ac.cn
Fri Aug 14 02:26:46 GMT 2026
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 <pincheng.plct@isrc.iscas.ac.cn>
---
newlib/libc/machine/riscv/Makefile.inc | 4 ++-
newlib/libc/machine/riscv/strrchr-asm.S | 38 +++++++++++++++++++++++++
newlib/libc/machine/riscv/strrchr.c | 5 ++++
3 files changed, 46 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..1bdb84338
--- /dev/null
+++ b/newlib/libc/machine/riscv/strrchr-asm.S
@@ -0,0 +1,38 @@
+#include <sys/asm.h>
+
+#if defined(__riscv_vector) && !defined(__riscv_e) && !defined(__OPTIMIZE_SIZE__) && !defined(PREFER_SIZE_OVER_SPEED)
+/* 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. */
+ENTRY(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
+END(strrchr)
+#endif
diff --git a/newlib/libc/machine/riscv/strrchr.c b/newlib/libc/machine/riscv/strrchr.c
new file mode 100644
index 000000000..d06b31e4c
--- /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) || defined(__riscv_e)
+# include "../../string/strrchr.c"
+#else
+/* strrchr defined in strrchr-asm.S */
+#endif
--
2.39.5
More information about the Newlib
mailing list