Re: [PATCH 1/1] riscv: add vectorized memset, memcpy and memmove
Kito Cheng <[email protected]> Fri, 12 Dec 2025 16:33:42 +0800
| Newsgroups | gmane.comp.lib.newlib |
|---|---|
| Message-ID | <CA+yXCZAB_m66dsxOXCaYD3Bcw9=1MCYZtaJBeZWin+q29N6D3g@mail.gmail.com> |
> 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__)
This seems not right change to me, memcpy-asm.S is NOT conditional
compile in the Makefile, so that mean if we didn't defined
PREFER_SIZE_OVER_SPEED, __OPTIMIZE_SIZE__ or __riscv_v, we will have a
empty memcpy in memcpy-asm.o and then this will included in libc.a
Same issue for memmove-asm.S
> mv a3, a0
> beqz a2, 2f
>
> @@ -29,4 +29,25 @@ memcpy:
> ret
>
> .size memcpy, .-memcpy
> +#elif defined(__riscv_v)
Suggest use __riscv_vector rather than __riscv_v, so that we can also
use that logic for zve* extensions.
> + .option push
> + .option arch, +v
and arch, +zve32x here rather than +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
This sub can be drop
> + bnez a2, .Lbulk_copy
You can use either src(a1)+len(a2) or dst(a0)+len(a2) for loop condition:
something like:
void *
memcpy(unsigned char *dst, const unsigned char *src,
const size_t sz)
{
const unsigned char *end = dst + sz;
while (dst != end)
*dst++ = *src++;
return dst;
}
This optimization could be applied on other function as well
> + /* 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
`ret` rather than `j .Ldone_move` here, ret and j are both one
instruction, so let just return to save one more jump :)