[PATCH v3 12/15] riscv: add vectorized strspn

Pincheng Wang <[email protected]>
Newsgroups gmane.comp.lib.newlib
Message-ID <[email protected]>
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 <[email protected]>
---
 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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.