[PATCH v3 12/15] riscv: add vectorized strspn
Pincheng Wang
pincheng.plct@isrc.iscas.ac.cn
Fri Aug 14 02:26:53 GMT 2026
The vector implementation builds a 256-byte accept 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, so the scan never
crosses into an unmapped page and the gather only touches the fully-mapped
table. 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/strspn-asm.S | 47 ++++++++++++++++++++++++++
newlib/libc/machine/riscv/strspn.c | 5 +++
3 files changed, 55 insertions(+), 1 deletion(-)
create mode 100644 newlib/libc/machine/riscv/strspn-asm.S
create mode 100644 newlib/libc/machine/riscv/strspn.c
diff --git a/newlib/libc/machine/riscv/Makefile.inc b/newlib/libc/machine/riscv/Makefile.inc
index fae228e43..55f137a3c 100644
--- a/newlib/libc/machine/riscv/Makefile.inc
+++ b/newlib/libc/machine/riscv/Makefile.inc
@@ -41,4 +41,6 @@ libc_a_SOURCES += \
%D%/strnlen-asm.S \
%D%/strnlen.c \
%D%/strrchr-asm.S \
- %D%/strrchr.c
+ %D%/strrchr.c \
+ %D%/strspn-asm.S \
+ %D%/strspn.c
diff --git a/newlib/libc/machine/riscv/strspn-asm.S b/newlib/libc/machine/riscv/strspn-asm.S
new file mode 100644
index 000000000..03f3a6b25
--- /dev/null
+++ b/newlib/libc/machine/riscv/strspn-asm.S
@@ -0,0 +1,47 @@
+#include <sys/asm.h>
+
+#if defined(__riscv_vector) && !defined(__riscv_e) && !defined(__OPTIMIZE_SIZE__) && !defined(PREFER_SIZE_OVER_SPEED)
+/* size_t strspn(const char *a0, const char *a1)
+ Length of the initial segment of a0 made up entirely of bytes in a1.
+ Build a 256-byte "accept" table from a1 (NUL is never marked, since a1 is
+ a string), then scan a0 and stop at the first byte not in the set; a NUL
+ in a0 stops the scan naturally. The scan uses vle8ff (page-boundary safe);
+ the gather only touches the fully-mapped 256-byte table. */
+ENTRY(strspn)
+ 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
+.Lbuild:
+ lbu t0, 0(a1)
+ beqz t0, .Lscan
+ add t2, sp, t0
+ sb t1, 0(t2)
+ addi a1, a1, 1
+ j .Lbuild
+.Lscan:
+ mv a2, a0
+.Lloop:
+ vsetvli t3, zero, e8, m1, ta, ma
+ vle8ff.v v8, (a0)
+ csrr t3, vl
+ vluxei8.v v16, (sp), v8 /* gather accept[a0[i]] */
+ vmseq.vi v0, v16, 0 /* lanes NOT in the accept set */
+ vfirst.m t4, v0
+ bgez t4, .Lfound
+ add a0, a0, t3
+ j .Lloop
+.Lfound:
+ add a0, a0, t4
+ sub a0, a0, a2
+ addi sp, sp, 256
+ ret
+END(strspn)
+#endif
diff --git a/newlib/libc/machine/riscv/strspn.c b/newlib/libc/machine/riscv/strspn.c
new file mode 100644
index 000000000..8d9d3fba9
--- /dev/null
+++ b/newlib/libc/machine/riscv/strspn.c
@@ -0,0 +1,5 @@
+#if defined(__OPTIMIZE_SIZE__) || defined(PREFER_SIZE_OVER_SPEED) || !defined(__riscv_vector) || defined(__riscv_e)
+# include "../../string/strspn.c"
+#else
+/* strspn defined in strspn-asm.S */
+#endif
--
2.39.5
More information about the Newlib
mailing list