[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