[PATCH 09/17] riscv: add vectorized strncpy
Pincheng Wang <[email protected]> Thu, 16 Jul 2026 23:00:40 +0800
| 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 | 46 +++++++++++++++++++++++++ newlib/libc/machine/riscv/strncpy.c | 5 +++ 3 files changed, 53 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..b220fde44 --- /dev/null +++ b/newlib/libc/machine/riscv/strncpy-asm.S @@ -0,0 +1,46 @@ +#if defined(__riscv_vector) && __riscv_xlen == 64 && !defined(__OPTIMIZE_SIZE__) && !defined(PREFER_SIZE_OVER_SPEED) +.text +.option push +.option arch, +v +/* 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. */ +.global strncpy +.type strncpy, @function +strncpy: + mv a3, a0 /* save dest for return */ + 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 +.size strncpy, .-strncpy +.option pop +#endif diff --git a/newlib/libc/machine/riscv/strncpy.c b/newlib/libc/machine/riscv/strncpy.c new file mode 100644 index 000000000..19f8f47db --- /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) || __riscv_xlen != 64 +# include "../../string/strncpy.c" +#else +/* strncpy defined in strncpy-asm.S */ +#endif -- 2.39.5