[PATCH 11/17] riscv: add vectorized strncat

Pincheng Wang <[email protected]> Thu, 16 Jul 2026 23:00:42 +0800
Newsgroups gmane.comp.lib.newlib
Message-ID <[email protected]>
The vector implementation locates the end of the destination and appends
at most n bytes of 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 across an unmapped page, and the result is always
NUL-terminated.  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/strncat-asm.S | 47 +++++++++++++++++++++++++
 newlib/libc/machine/riscv/strncat.c     |  5 +++
 3 files changed, 54 insertions(+)
 create mode 100644 newlib/libc/machine/riscv/strncat-asm.S
 create mode 100644 newlib/libc/machine/riscv/strncat.c

diff --git a/newlib/libc/machine/riscv/Makefile.inc b/newlib/libc/machine/riscv/Makefile.inc
index b8f4d2f9c..fae228e43 100644
--- a/newlib/libc/machine/riscv/Makefile.inc
+++ b/newlib/libc/machine/riscv/Makefile.inc
@@ -32,6 +32,8 @@ libc_a_SOURCES += \
 	%D%/strcpy.c \
 	%D%/strlen-asm.S \
 	%D%/strlen.c \
+	%D%/strncat-asm.S \
+	%D%/strncat.c \
 	%D%/strncmp-asm.S \
 	%D%/strncmp.c \
 	%D%/strncpy-asm.S \
diff --git a/newlib/libc/machine/riscv/strncat-asm.S b/newlib/libc/machine/riscv/strncat-asm.S
new file mode 100644
index 000000000..b5ae54328
--- /dev/null
+++ b/newlib/libc/machine/riscv/strncat-asm.S
@@ -0,0 +1,47 @@
+#if defined(__riscv_vector) && __riscv_xlen == 64 && !defined(__OPTIMIZE_SIZE__) && !defined(PREFER_SIZE_OVER_SPEED)
+.text
+.option push
+.option arch, +v
+.global strncat
+.type strncat, @function
+strncat:
+  mv a3, a0
+  /* the strlen of a0.  */
+.Lstrlen_loop:
+  vsetvli a4, zero, e8, m1, ta, ma
+
+  vle8ff.v v8, (a3)
+  /* find the '\0'.  */
+  vmseq.vx v0, v8, zero
+  csrr a4, vl
+  vfirst.m a5, v0
+  add a3, a3, a4
+  bltz a5, .Lstrlen_loop
+
+  sub a3, a3, a4
+  add a3, a3, a5
+
+  /* copy at most a2 bytes of a1 to a3.  */
+.Lstrcpy_loop:
+  vsetvli zero, a2, e8, m1, ta, ma
+
+  vle8ff.v v8, (a1)
+  vmseq.vx v1, v8, zero
+  csrr a4, vl
+  vfirst.m a5, v1
+  vmsif.m v0, v1
+  add a1, a1, a4
+  sub a2, a2, a4
+  vse8.v v8, (a3), v0.t
+  add a3, a3, a4
+  beqz a2, .Lfill_zero
+  bltz a5, .Lstrcpy_loop
+  ret
+.Lfill_zero:
+  bgez a5, .Lfill_zero_end
+  sb zero, (a3)
+.Lfill_zero_end:
+  ret
+.size strncat, .-strncat
+.option pop
+#endif
diff --git a/newlib/libc/machine/riscv/strncat.c b/newlib/libc/machine/riscv/strncat.c
new file mode 100644
index 000000000..186f2158e
--- /dev/null
+++ b/newlib/libc/machine/riscv/strncat.c
@@ -0,0 +1,5 @@
+#if defined(__OPTIMIZE_SIZE__) || defined(PREFER_SIZE_OVER_SPEED) || !defined(__riscv_vector) || __riscv_xlen != 64
+# include "../../string/strncat.c"
+#else
+/* strncat defined in strncat-asm.S */
+#endif
-- 
2.39.5