[PATCH v3 09/15] riscv: add vectorized strncpy
Pincheng Wang
pincheng.plct@isrc.iscas.ac.cn
Fri Aug 14 02:26:50 GMT 2026
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 <pincheng.plct@isrc.iscas.ac.cn>
---
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
More information about the Newlib
mailing list