[PATCH v3 09/15] riscv: add vectorized strncpy

Pincheng Wang <[email protected]>
Newsgroups gmane.comp.lib.newlib
Message-ID <[email protected]>
The vector implementation copies the source in vector-length chunks using
fault-only-first loads (vle8ff.v); vl is capped by the remaining count so
the source is never read past byte n or across an unmapped page, and the
tail after a NUL is zero-filled with wide m8 stores.  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/strncpy-asm.S | 42 +++++++++++++++++++++++++
 newlib/libc/machine/riscv/strncpy.c     |  5 +++
 3 files changed, 49 insertions(+)
 create mode 100644 newlib/libc/machine/riscv/strncpy-asm.S
 create mode 100644 newlib/libc/machine/riscv/strncpy.c

diff --git a/newlib/libc/machine/riscv/Makefile.inc b/newlib/libc/machine/riscv/Makefile.inc
index 334d4351b..db572be82 100644
--- a/newlib/libc/machine/riscv/Makefile.inc
+++ b/newlib/libc/machine/riscv/Makefile.inc
@@ -32,6 +32,8 @@ libc_a_SOURCES += \
 	%D%/strlen.c \
 	%D%/strncmp-asm.S \
 	%D%/strncmp.c \
+	%D%/strncpy-asm.S \
+	%D%/strncpy.c \
 	%D%/strnlen-asm.S \
 	%D%/strnlen.c \
 	%D%/strrchr-asm.S \
diff --git a/newlib/libc/machine/riscv/strncpy-asm.S b/newlib/libc/machine/riscv/strncpy-asm.S
new file mode 100644
index 000000000..00232fcfd
--- /dev/null
+++ b/newlib/libc/machine/riscv/strncpy-asm.S
@@ -0,0 +1,42 @@
+#include <sys/asm.h>
+
+#if defined(__riscv_vector) && !defined(__OPTIMIZE_SIZE__) && !defined(PREFER_SIZE_OVER_SPEED)
+/* char *strncpy(char *a0, const char *a1, size_t a2)
+   Copy at most a2 bytes; if a NUL is met in src, the rest of dest is
+   zero-filled.  Source is read with vle8ff (page-boundary safe) and vl is
+   also capped by the remaining count so we never read past byte a2.  */
+ENTRY(strncpy)
+  mv a3, a0                 /* keep a running destination pointer */
+  beqz a2, .Ldone
+.Lloop:
+  vsetvli zero, a2, e8, m1, ta, ma
+  vle8ff.v v8, (a1)
+  vmseq.vi v1, v8, 0        /* NUL mask */
+  csrr a4, vl               /* actual count (may be truncated by fault) */
+  vfirst.m a5, v1
+  bgez a5, .Lnul
+  /* no NUL: copy whole chunk */
+  vse8.v v8, (a3)
+  add a1, a1, a4
+  add a3, a3, a4
+  sub a2, a2, a4
+  bnez a2, .Lloop
+  j .Ldone
+.Lnul:
+  /* NUL at index a5: copy the [0,a5) prefix, then zero-fill the rest */
+  vmsbf.m v0, v1            /* mask = elements before first NUL */
+  vse8.v v8, (a3), v0.t
+  add a3, a3, a5
+  sub a2, a2, a5            /* remaining bytes to zero (>=1) */
+.Lfill:
+  beqz a2, .Ldone
+  vsetvli a4, a2, e8, m8, ta, ma
+  vmv.v.i v8, 0
+  vse8.v v8, (a3)
+  add a3, a3, a4
+  sub a2, a2, a4
+  bnez a2, .Lfill
+.Ldone:
+  ret
+END(strncpy)
+#endif
diff --git a/newlib/libc/machine/riscv/strncpy.c b/newlib/libc/machine/riscv/strncpy.c
new file mode 100644
index 000000000..54ded52cb
--- /dev/null
+++ b/newlib/libc/machine/riscv/strncpy.c
@@ -0,0 +1,5 @@
+#if defined(__OPTIMIZE_SIZE__) || defined(PREFER_SIZE_OVER_SPEED) || !defined(__riscv_vector)
+# include "../../string/strncpy.c"
+#else
+/* strncpy defined in strncpy-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.