[PATCH 14/17] riscv: add vectorized strpbrk
Pincheng Wang <[email protected]> Thu, 16 Jul 2026 23:00:45 +0800
| Newsgroups | gmane.comp.lib.newlib |
|---|---|
| Message-ID | <[email protected]> |
The vector implementation builds a 256-byte set table on the stack and scans the string in vector-length chunks using fault-only-first loads (vle8ff.v) with an indexed gather into the table, returning a pointer to the first byte in the set or NULL, without ever crossing 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 | 2 + newlib/libc/machine/riscv/strpbrk-asm.S | 55 +++++++++++++++++++++++++ newlib/libc/machine/riscv/strpbrk.c | 5 +++ 3 files changed, 62 insertions(+) create mode 100644 newlib/libc/machine/riscv/strpbrk-asm.S create mode 100644 newlib/libc/machine/riscv/strpbrk.c diff --git a/newlib/libc/machine/riscv/Makefile.inc b/newlib/libc/machine/riscv/Makefile.inc index 1e35cf17d..d145a3024 100644 --- a/newlib/libc/machine/riscv/Makefile.inc +++ b/newlib/libc/machine/riscv/Makefile.inc @@ -42,6 +42,8 @@ libc_a_SOURCES += \ %D%/strncpy.c \ %D%/strnlen-asm.S \ %D%/strnlen.c \ + %D%/strpbrk-asm.S \ + %D%/strpbrk.c \ %D%/strrchr-asm.S \ %D%/strrchr.c \ %D%/strspn-asm.S \ diff --git a/newlib/libc/machine/riscv/strpbrk-asm.S b/newlib/libc/machine/riscv/strpbrk-asm.S new file mode 100644 index 000000000..fdbcf64e0 --- /dev/null +++ b/newlib/libc/machine/riscv/strpbrk-asm.S @@ -0,0 +1,55 @@ +#if defined(__riscv_vector) && __riscv_xlen == 64 && !defined(__OPTIMIZE_SIZE__) && !defined(PREFER_SIZE_OVER_SPEED) +.text +.option push +.option arch, +v +/* char *strpbrk(const char *a0, const char *a1) + Return a pointer to the first byte of a0 that appears in a1, or NULL. + Equivalent to s + strcspn(s, b), returning NULL when that lands on the + terminating NUL. Same page-safe vle8ff scan + stack-table gather as + strcspn; the NUL is marked as a stopper so the scan terminates. */ +.global strpbrk +.type strpbrk, @function +strpbrk: + addi sp, sp, -256 + li t1, 256 + mv t0, sp +.Lzero: + vsetvli t2, t1, e8, m8, ta, ma + vmv.v.i v8, 0 + vse8.v v8, (t0) + add t0, t0, t2 + sub t1, t1, t2 + bnez t1, .Lzero + li t1, 1 + /* mark every byte of a1 (the set), but NOT NUL yet */ +.Lbuild: + lbu t0, 0(a1) + beqz t0, .Lsetnul + add t2, sp, t0 + sb t1, 0(t2) + addi a1, a1, 1 + j .Lbuild +.Lsetnul: + /* mark NUL as a stopper so the scan halts at end of string */ + sb t1, 0(sp) +.Lloop: + vsetvli t3, zero, e8, m1, ta, ma + vle8ff.v v8, (a0) + csrr t3, vl + vluxei8.v v16, (sp), v8 + vmsne.vi v0, v16, 0 + vfirst.m t4, v0 + bgez t4, .Lfound + add a0, a0, t3 + j .Lloop +.Lfound: + add a0, a0, t4 + lbu t5, 0(a0) /* did we stop on a real match or on the NUL? */ + bnez t5, .Ldone + li a0, 0 +.Ldone: + addi sp, sp, 256 + ret +.size strpbrk, .-strpbrk +.option pop +#endif diff --git a/newlib/libc/machine/riscv/strpbrk.c b/newlib/libc/machine/riscv/strpbrk.c new file mode 100644 index 000000000..8b29ca944 --- /dev/null +++ b/newlib/libc/machine/riscv/strpbrk.c @@ -0,0 +1,5 @@ +#if defined(__OPTIMIZE_SIZE__) || defined(PREFER_SIZE_OVER_SPEED) || !defined(__riscv_vector) || __riscv_xlen != 64 +# include "../../string/strpbrk.c" +#else +/* strpbrk defined in strpbrk-asm.S */ +#endif -- 2.39.5