[v2,0/1] riscv: add vectorized memset, memcpy and memmove

Message ID 20251225160856.16010-1-pincheng.plct@isrc.iscas.ac.cn
Headers
Series riscv: add vectorized memset, memcpy and memmove |

Message

Pincheng Wang Dec. 25, 2025, 4:08 p.m. UTC
  Hi all,

This v2 patch adds RISC-V Vector (RVV) optimized implementations for
memset, memcpy and memmove.

Changes since v1:
- Switch the conditional compilation macro from __riscv_v to __riscv_vector.
- Replaced '.option arch,+v' with '.option arch,+zve32x'.
- Removed an unnecessary unconditional jump instruction in memmove-asm.S
- In memcpy and memmove, when __riscv_misaligned_fast is not defined,
  the destination address is now aligned to SZREG to improve performance
  on systems with slow misaligned accesses.

These implementations use the RVV extension with e8 element size and m8
LMUL, and are conditionally compiled only when __riscv_vector is
defined, ensuring compatibility with non-vector RISC-V systems.

Benchmark results on Spacemit X60 (Muse-pi) and Canaan K230 show significant
improvements.

memcpy: Up to 4.84x on Muse-pi and 4.66x on K230.
memset: Up to 4.31x on Muse-pi and 3.14x on K230.
memmove: Up to 2.87x on Muse-pi and 1.48x on K230. 

With newly added alignment handling, these improvements are consistent
across both aligned and misaligned memory acesses.

In the v1 review thread, Kito suggested removing the 'sub' instruction in
the RVV memcpy loop and relying solely on the end-pointer-based loop
condition. After careful consideration, I would like to clarify that in
this specific context, the 'sub' cannot actually be eliminated since the
RVV loop still requires the exact number of remaining bytes to be
provided to vsetvli. Therefore, I have retained the orignial loop
structure.

Comments and suggestions are greatly appreciated, Thank you for your
time and review!

Thanks,
Pincheng Wang

Pincheng Wang (1):
  riscv: add vectorized memset, memcpy and memmove

 newlib/libc/machine/riscv/memcpy-asm.S  | 54 +++++++++++++-
 newlib/libc/machine/riscv/memcpy.c      |  2 +-
 newlib/libc/machine/riscv/memmove-asm.S | 95 ++++++++++++++++++++++++-
 newlib/libc/machine/riscv/memmove.c     |  2 +-
 newlib/libc/machine/riscv/memset.S      | 21 +++++-
 5 files changed, 169 insertions(+), 5 deletions(-)
  

Comments

Pincheng Wang Jan. 3, 2026, 3:21 p.m. UTC | #1
Hi all,

Happy new year!

Just a gentle ping on this patch series. Please let me know if there are 
any remaining concerns that I can help address. Happy to update the 
series if needed. :)

Thanks,
Pincheng Wang

On 2025/12/26 0:08, Pincheng Wang wrote:
> This v2 patch adds RISC-V Vector (RVV) optimized implementations for
> memset, memcpy and memmove.
> 
> Changes since v1:
> - Switch the conditional compilation macro from __riscv_v to __riscv_vector.
> - Replaced '.option arch,+v' with '.option arch,+zve32x'.
> - Removed an unnecessary unconditional jump instruction in memmove-asm.S
> - In memcpy and memmove, when __riscv_misaligned_fast is not defined,
>    the destination address is now aligned to SZREG to improve performance
>    on systems with slow misaligned accesses.
> 
> These implementations use the RVV extension with e8 element size and m8
> LMUL, and are conditionally compiled only when __riscv_vector is
> defined, ensuring compatibility with non-vector RISC-V systems.
> 
> Benchmark results on Spacemit X60 (Muse-pi) and Canaan K230 show significant
> improvements.
> 
> memcpy: Up to 4.84x on Muse-pi and 4.66x on K230.
> memset: Up to 4.31x on Muse-pi and 3.14x on K230.
> memmove: Up to 2.87x on Muse-pi and 1.48x on K230.
> 
> With newly added alignment handling, these improvements are consistent
> across both aligned and misaligned memory acesses.
> 
> In the v1 review thread, Kito suggested removing the 'sub' instruction in
> the RVV memcpy loop and relying solely on the end-pointer-based loop
> condition. After careful consideration, I would like to clarify that in
> this specific context, the 'sub' cannot actually be eliminated since the
> RVV loop still requires the exact number of remaining bytes to be
> provided to vsetvli. Therefore, I have retained the orignial loop
> structure.
> 
> Comments and suggestions are greatly appreciated, Thank you for your
> time and review!
> 
> Thanks,
> Pincheng Wang
> 
> Pincheng Wang (1):
>    riscv: add vectorized memset, memcpy and memmove
> 
>   newlib/libc/machine/riscv/memcpy-asm.S  | 54 +++++++++++++-
>   newlib/libc/machine/riscv/memcpy.c      |  2 +-
>   newlib/libc/machine/riscv/memmove-asm.S | 95 ++++++++++++++++++++++++-
>   newlib/libc/machine/riscv/memmove.c     |  2 +-
>   newlib/libc/machine/riscv/memset.S      | 21 +++++-
>   5 files changed, 169 insertions(+), 5 deletions(-)
>
  
Richárd Szalay Jan. 6, 2026, 11:27 a.m. UTC | #2
On Sat, 3 Jan 2026 at 16:22, Pincheng Wang
<pincheng.plct@isrc.iscas.ac.cn> wrote:
> Hi all,
>
> Happy new year!
>
> Just a gentle ping on this patch series. Please let me know if there are
> any remaining concerns that I can help address. Happy to update the
> series if needed. :)

Dear Pincheng,

I have some high-level questions from a purely user perspective.
Please do not consider this as a "review". :)

> On 2025/12/26 0:08, Pincheng Wang wrote:
> > This v2 patch adds RISC-V Vector (RVV) optimized implementations for
> > memset, memcpy and memmove.
> >
> > Changes since v1:
> > - Switch the conditional compilation macro from __riscv_v to __riscv_vector.
> > - Replaced '.option arch,+v' with '.option arch,+zve32x'.
What is the implication of this change? I'm a newbie to RVV, and
"Zve32x" looks like a subset implementation. Is it possible to compile
the standard library post-patch if a target usually blanket-enables
"+v"? ("rv64imafdcv")

> > - Removed an unnecessary unconditional jump instruction in memmove-asm.S
> > - In memcpy and memmove, when __riscv_misaligned_fast is not defined,
> >    the destination address is now aligned to SZREG to improve performance
> >    on systems with slow misaligned accesses.
> >
> > These implementations use the RVV extension with e8 element size and m8
> > LMUL, and are conditionally compiled only when __riscv_vector is
> > defined, ensuring compatibility with non-vector RISC-V systems.
Is the condition for this conditional compilation decided at the
moment of compiling 'newlib'? So, if someone wants to create a
distribution where it is possible to compile for both non-RVV and
RVV-capable target configurations, this essentially means having to
distribute two versions of the newlib binary archive? Am I right to
think that "pre-compiling" newlib with vectorised mem{cpy,move,set}
and linking it with a binary that is otherwise non-RVV, and execute
the whole image on a non-RVV platform would simply result in a
corrupted execution?

> > Benchmark results on Spacemit X60 (Muse-pi) and Canaan K230 show significant
> > improvements.
> >
> > memcpy: Up to 4.84x on Muse-pi and 4.66x on K230.
> > memset: Up to 4.31x on Muse-pi and 3.14x on K230.
> > memmove: Up to 2.87x on Muse-pi and 1.48x on K230.
> >
> > With newly added alignment handling, these improvements are consistent
> > across both aligned and misaligned memory acesses.
  
Pincheng Wang Jan. 8, 2026, 12:50 p.m. UTC | #3
Hi Richard,

Thank you for the insightful questions, and sorry for the late reply. 
Below is the clarifications.

About ".option arch, +zve32x":
This directive tells the assembler to accept instructions from the 
Zve32x vector subset for this file only. It is a local override used 
when build systems do not pass "-march" flags that include vector 
extensions. The intent is to ensure that assembly succeeds as long as 
the toolchain supports Zve32x, without requireing full "+v".

Why Zve32x instead of V:
Zve32x is the *base* embedded-profile vector extension and guarantees 
availability of byte-vector operations(vle8 & vse8) used in my patch 
series. Full V extension is a superset and always compatible, but not 
all embedded targets implement it. Selecting Zve32x therefore avoids 
excluding MCUs and bare-metal systems that support Zve extensions but do 
not implement the full V extension.

About conditional compilation and distribution implications:
You are correct, "__riscv_vector" is evaluated at newlib build time.
A binary compiled with the vectorized implementations assumes the 
presence of vector hardware. Executing such a binary on a non-RVV system 
would result in illegal-instruction traps or undefined behavior. 
Therefore, a distribution that wishes to support both RVV and non-RVV 
targets would typically need to ship two builds, or rely on a multi-lib 
strategy if their build workflows allow it.

Best regards,
Pincheng Wang

On 2026/1/6 19:27, Richárd Szalay wrote:
> On Sat, 3 Jan 2026 at 16:22, Pincheng Wang
> <pincheng.plct@isrc.iscas.ac.cn> wrote:
>> Hi all,
>>
>> Happy new year!
>>
>> Just a gentle ping on this patch series. Please let me know if there are
>> any remaining concerns that I can help address. Happy to update the
>> series if needed. :)
> 
> Dear Pincheng,
> 
> I have some high-level questions from a purely user perspective.
> Please do not consider this as a "review". :)
> 
>> On 2025/12/26 0:08, Pincheng Wang wrote:
>>> This v2 patch adds RISC-V Vector (RVV) optimized implementations for
>>> memset, memcpy and memmove.
>>>
>>> Changes since v1:
>>> - Switch the conditional compilation macro from __riscv_v to __riscv_vector.
>>> - Replaced '.option arch,+v' with '.option arch,+zve32x'.
> What is the implication of this change? I'm a newbie to RVV, and
> "Zve32x" looks like a subset implementation. Is it possible to compile
> the standard library post-patch if a target usually blanket-enables
> "+v"? ("rv64imafdcv")
> 
>>> - Removed an unnecessary unconditional jump instruction in memmove-asm.S
>>> - In memcpy and memmove, when __riscv_misaligned_fast is not defined,
>>>     the destination address is now aligned to SZREG to improve performance
>>>     on systems with slow misaligned accesses.
>>>
>>> These implementations use the RVV extension with e8 element size and m8
>>> LMUL, and are conditionally compiled only when __riscv_vector is
>>> defined, ensuring compatibility with non-vector RISC-V systems.
> Is the condition for this conditional compilation decided at the
> moment of compiling 'newlib'? So, if someone wants to create a
> distribution where it is possible to compile for both non-RVV and
> RVV-capable target configurations, this essentially means having to
> distribute two versions of the newlib binary archive? Am I right to
> think that "pre-compiling" newlib with vectorised mem{cpy,move,set}
> and linking it with a binary that is otherwise non-RVV, and execute
> the whole image on a non-RVV platform would simply result in a
> corrupted execution?
> 
>>> Benchmark results on Spacemit X60 (Muse-pi) and Canaan K230 show significant
>>> improvements.
>>>
>>> memcpy: Up to 4.84x on Muse-pi and 4.66x on K230.
>>> memset: Up to 4.31x on Muse-pi and 3.14x on K230.
>>> memmove: Up to 2.87x on Muse-pi and 1.48x on K230.
>>>
>>> With newly added alignment handling, these improvements are consistent
>>> across both aligned and misaligned memory acesses.