[PATCH v3 13/15] riscv: add vectorized strcspn

Pincheng Wang <[email protected]>
Newsgroups gmane.comp.lib.newlib
Message-ID <[email protected]>
The vector implementation builds a 256-byte stop table on the stack (the
reject bytes plus NUL) 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  |  2 +
 newlib/libc/machine/riscv/strcspn-asm.S | 51 +++++++++++++++++++++++++
 newlib/libc/machine/riscv/strcspn.c     |  5 +++
 3 files changed, 58 insertions(+)
 create mode 100644 newlib/libc/machine/riscv/strcspn-asm.S
 create mode 100644 newlib/libc/machine/riscv/strcspn.c

diff --git a/newlib/libc/machine/riscv/Makefile.inc b/newlib/libc/machine/riscv/Makefile.inc
index 55f137a3c..1e35cf17d 100644
--- a/newlib/libc/machine/riscv/Makefile.inc
+++ b/newlib/libc/machine/riscv/Makefile.inc
@@ -30,6 +30,8 @@ libc_a_SOURCES += \
 	%D%/strcmp.S \
 	%D%/strcpy-asm.S \
 	%D%/strcpy.c \
+	%D%/strcspn-asm.S \
+	%D%/strcspn.c \
 	%D%/strlen-asm.S \
 	%D%/strlen.c \
 	%D%/strncat-asm.S \
diff --git a/newlib/libc/machine/riscv/strcspn-asm.S b/newlib/libc/machine/riscv/strcspn-asm.S
new file mode 100644
index 000000000..106b46e43
--- /dev/null
+++ b/newlib/libc/machine/riscv/strcspn-asm.S
@@ -0,0 +1,51 @@
+#include <sys/asm.h>
+
+#if defined(__riscv_vector) && !defined(__riscv_e) && !defined(__OPTIMIZE_SIZE__) && !defined(PREFER_SIZE_OVER_SPEED)
+/* size_t strcspn(const char *a0, const char *a1)
+   Length of the initial segment of a0 made up of bytes NOT in a1.
+   Build a 256-byte "stop" table on the stack (a1's bytes plus NUL marked),
+   then scan a0: a gathered table entry != 0 ends the segment.  The scan of
+   a0 uses vle8ff so it never loads across a page boundary; the indexed
+   gather only touches the fully-mapped 256-byte table.  */
+ENTRY(strcspn)
+  addi sp, sp, -256
+  /* zero the table */
+  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
+  /* mark NUL as a stopper so the scan halts at end of string */
+  li t1, 1
+  sb t1, 0(sp)
+  /* mark every byte of a1 */
+.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             /* remember start */
+.Lloop:
+  vsetvli t3, zero, e8, m1, ta, ma
+  vle8ff.v v8, (a0)
+  csrr t3, vl
+  vluxei8.v v16, (sp), v8       /* gather table[a0[i]] */
+  vmsne.vi v0, v16, 0           /* lanes that are stoppers */
+  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(strcspn)
+#endif
diff --git a/newlib/libc/machine/riscv/strcspn.c b/newlib/libc/machine/riscv/strcspn.c
new file mode 100644
index 000000000..eb3acf829
--- /dev/null
+++ b/newlib/libc/machine/riscv/strcspn.c
@@ -0,0 +1,5 @@
+#if defined(__OPTIMIZE_SIZE__) || defined(PREFER_SIZE_OVER_SPEED) || !defined(__riscv_vector) || defined(__riscv_e)
+# include "../../string/strcspn.c"
+#else
+/* strcspn defined in strcspn-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.