[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