[PATCH 1/1] riscv: add vectorized memset, memcpy and memmove
Pincheng Wang
pincheng.plct@isrc.iscas.ac.cn
Thu Dec 11 13:27:25 GMT 2025
The vector implementations use m8 register grouping and process data in
vector-length chunks, providing significant performance improvements on
RVV-capable hardware. Use conditional compilation to fallback to scalar
implementation when __riscv_v 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/memcpy-asm.S | 23 +++++++++++-
newlib/libc/machine/riscv/memcpy.c | 2 +-
newlib/libc/machine/riscv/memmove-asm.S | 47 ++++++++++++++++++++++++-
newlib/libc/machine/riscv/memmove.c | 2 +-
newlib/libc/machine/riscv/memset.S | 22 ++++++++++++
5 files changed, 92 insertions(+), 4 deletions(-)
diff --git a/newlib/libc/machine/riscv/memcpy-asm.S b/newlib/libc/machine/riscv/memcpy-asm.S
index 2771285f9..9d1d2d4bd 100644
--- a/newlib/libc/machine/riscv/memcpy-asm.S
+++ b/newlib/libc/machine/riscv/memcpy-asm.S
@@ -9,11 +9,11 @@
http://www.opensource.org/licenses.
*/
-#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
.text
.global memcpy
.type memcpy, @function
memcpy:
+#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
mv a3, a0
beqz a2, 2f
@@ -29,4 +29,25 @@ memcpy:
ret
.size memcpy, .-memcpy
+#elif defined(__riscv_v)
+ .option push
+ .option arch, +v
+ mv t0, a0 /* running dst */
+ mv t1, a1 /* running src */
+ beqz a2, .Ldone_copy /* n == 0 then return */
+
+.Lbulk_copy:
+ vsetvli t2, a2, e8, m8, ta, ma /* t2 = vl (bytes) */
+ vle8.v v0, (t1)
+ vse8.v v0, (t0)
+ add t0, t0, t2
+ add t1, t1, t2
+ sub a2, a2, t2
+ bnez a2, .Lbulk_copy
+ /* fallthrough */
+
+.Ldone_copy:
+ ret
+.size memcpy, .-memcpy
+.option pop
#endif
diff --git a/newlib/libc/machine/riscv/memcpy.c b/newlib/libc/machine/riscv/memcpy.c
index a27e0ecb1..cd58c30a5 100644
--- a/newlib/libc/machine/riscv/memcpy.c
+++ b/newlib/libc/machine/riscv/memcpy.c
@@ -10,7 +10,7 @@
http://www.opensource.org/licenses.
*/
-#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
+#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) || defined(__riscv_v)
// memcpy defined in memcpy-asm.S
#else
diff --git a/newlib/libc/machine/riscv/memmove-asm.S b/newlib/libc/machine/riscv/memmove-asm.S
index 061472ca2..5cc2e5143 100644
--- a/newlib/libc/machine/riscv/memmove-asm.S
+++ b/newlib/libc/machine/riscv/memmove-asm.S
@@ -9,11 +9,11 @@
http://www.opensource.org/licenses.
*/
-#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
.text
.global memmove
.type memmove, @function
memmove:
+#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
beqz a2, .Ldone /* in case there are 0 bytes to be copied, return immediately */
mv a4, a0 /* copy the destination address over to a4, since memmove should return that address in a0 at the end */
@@ -37,4 +37,49 @@ memmove:
ret
.size memmove, .-memmove
+#elif defined(__riscv_v)
+ .option push
+ .option arch, +v
+ beqz a2, .Ldone_move /* n == 0 */
+ beq a0, a1, .Ldone_move /* dst == src */
+
+ /* overlap check */
+ bgeu a1, a0, .Lforward_move /* src >= dst then forward move*/
+
+ sub t2, a0, a1 /* t2 = dst - src */
+ bgeu t2, a2, .Lforward_move /* no overlap then forward move */
+
+ /* backward move */
+ add t0, a0, a2 /* running dst_end */
+ add t1, a1, a2 /* running src_end */
+
+.Lbackward_loop:
+ vsetvli t3, a2, e8, m8, ta, ma /* t3 = vl (bytes) */
+ sub t0, t0, t3
+ sub t1, t1, t3
+ vle8.v v0, (t1)
+ vse8.v v0, (t0)
+ sub a2, a2, t3
+ bnez a2, .Lbackward_loop
+ j .Ldone_move
+
+/* forward move, same as memcpy */
+.Lforward_move:
+ mv t0, a0 /* running dst */
+ mv t1, a1 /* running src */
+
+.Lforward_loop:
+ vsetvli t3, a2, e8, m8, ta, ma
+ vle8.v v0, (t1)
+ vse8.v v0, (t0)
+ add t0, t0, t3
+ add t1, t1, t3
+ sub a2, a2, t3
+ bnez a2, .Lforward_loop
+ /* fallthrough */
+
+.Ldone_move:
+ ret
+.size memmove, .-memmove
+.option pop
#endif
diff --git a/newlib/libc/machine/riscv/memmove.c b/newlib/libc/machine/riscv/memmove.c
index 209a75c69..67ce08b02 100644
--- a/newlib/libc/machine/riscv/memmove.c
+++ b/newlib/libc/machine/riscv/memmove.c
@@ -10,7 +10,7 @@
http://www.opensource.org/licenses.
*/
-#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
+#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) || defined(__riscv_v)
/* memmove defined in memmove-asm.S */
#else
diff --git a/newlib/libc/machine/riscv/memset.S b/newlib/libc/machine/riscv/memset.S
index 533f66758..80f43fbaf 100644
--- a/newlib/libc/machine/riscv/memset.S
+++ b/newlib/libc/machine/riscv/memset.S
@@ -63,6 +63,28 @@ memset:
.Ldone:
ret
+#elif defined(__riscv_v)
+ .option push
+ .option arch, +v
+ mv t0, a0 /* running dst; keep a0 as return */
+ beqz a2, .Ldone_vect /* n == 0 then return */
+
+ /* Broadcast fill byte once. */
+ vsetvli t1, zero, e8, m8, ta, ma
+ vmv.v.x v0, a1
+
+.Lbulk_vect:
+ vsetvli t1, a2, e8, m8, ta, ma /* t1 = vl (bytes) */
+ vse8.v v0, (t0)
+ add t0, t0, t1
+ sub a2, a2, t1
+ bnez a2, .Lbulk_vect
+ /* fallthrough */
+
+.Ldone_vect:
+ ret
+ .option pop
+
#else
li REG_TABLE, BYTE_TBL_SZ
mv a3, a0
--
2.39.5
More information about the Newlib
mailing list