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 <pincheng.plct@isrc.iscas.ac.cn>
---
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
@@ -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 \
new file mode 100644
@@ -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
new file mode 100644
@@ -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