[PATCH v6 3/3] RISC-V: add riscv vector support for memcpy

daichengrong daichengrong@iscas.ac.cn
Wed Feb 19 07:44:50 GMT 2025


在 2025/2/14 20:59:22, Andrew Waterman 写道:
> On Fri, Feb 14, 2025 at 3:24 AM Andrew Waterman <aswaterman@gmail.com> wrote:
>> This is not what a generic RVV memcpy routine should look like.  It
>> should look like this:
>> https://github.com/riscvarchive/riscv-v-spec/blob/2f68ef7256d6ec53e4d2bd7cb12862f406d64e34/example/memcpy.s#L7
>>
>> The version you are proposing looks like it is optimized for a
>> particular microarchitecture.  That's fine, but it is a
>> de-optimization for other microarchitectures.  The generic version I
>> reference contains fewer branches, fewer static instructions, and
>> fewer dynamic instructions, for any memcpy size > 0.  (And 0 is not a
>> case we should be aggressively optimizing for.)
> My previous message isn't entirely accurate.  The proposed
> implementation does elide a couple ALU ops in the short-vector case,
> but it does so at the cost of another branch.  It remains the case
> that the reference code from the spec will be better for most
> implementations.

The optimization  does not  increase a branch at runtime as eliding a 
couple ALU ops in the short-vector case.

Though it does increasing the number of static instructions, it improves 
performance for small data.

Whether to adopt this optimization depends on how to define 
optimization, but it does get faster.

> Separately, there is a subtle bug in the proposed code; the bgt should
> be bgtu, otherwise lengths >= 2^(XLEN-1) will be incorrectly handled.
Thanks!
>> On Fri, Feb 14, 2025 at 12:52 AM <daichengrong@iscas.ac.cn> wrote:
>>> From: daichengrong <daichengrong@iscas.ac.cn>
>>>
>>> Change in v6:
>>>    Optimize the RVV memcpy for small lengths less than VLEN/8 bytes
>>>
>>> Changes in v5:
>>>     fix Indentation in memcpy.c
>>>     check ifunc-impl-list memcpy vector support with by dl_hwcap
>>>
>>> Changes in v4:
>>>    update rvv memcpy support by compiler
>>>    check whether rvv enabled by dl_hwcap
>>>
>>> Changes in v3:
>>>    Remove unnecessary whitespace
>>>
>>> Changes in v2:
>>>    delete size-0 branch
>>>
>>> ---
>>>   sysdeps/riscv/multiarch/memcpy_vector.S       | 43 +++++++++++++++++++
>>>   .../unix/sysv/linux/riscv/multiarch/Makefile  |  8 ++++
>>>   .../linux/riscv/multiarch/ifunc-impl-list.c   | 13 ++++++
>>>   .../unix/sysv/linux/riscv/multiarch/memcpy.c  |  7 +++
>>>   4 files changed, 71 insertions(+)
>>>   create mode 100644 sysdeps/riscv/multiarch/memcpy_vector.S
>>>
>>> diff --git a/sysdeps/riscv/multiarch/memcpy_vector.S b/sysdeps/riscv/multiarch/memcpy_vector.S
>>> new file mode 100644
>>> index 0000000000..4783640776
>>> --- /dev/null
>>> +++ b/sysdeps/riscv/multiarch/memcpy_vector.S
>>> @@ -0,0 +1,43 @@
>>> +/* memcpy for RISC-V Vector.
>>> +   Copyright (C) 2024-2025 Free Software Foundation, Inc.
>>> +   This file is part of the GNU C Library.
>>> +
>>> +   The GNU C Library is free software; you can redistribute it and/or
>>> +   modify it under the terms of the GNU Lesser General Public
>>> +   License as published by the Free Software Foundation; either
>>> +   version 2.1 of the License, or (at your option) any later version.
>>> +
>>> +   The GNU C Library is distributed in the hope that it will be useful,
>>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>> +   Lesser General Public License for more details.
>>> +
>>> +   You should have received a copy of the GNU Lesser General Public
>>> +   License along with the GNU C Library; if not, see
>>> +   <https://www.gnu.org/licenses/>.  */
>>> +
>>> +
>>> +#include <sysdep.h>
>>> +#include <sys/asm.h>
>>> +
>>> +ENTRY (__memcpy_vector)
>>> +    beq        a2, zero, L(ret)
>>> +    mv     a6, a0
>>> +
>>> +    /* if LEN > VLMAX jump to block_copy handling.  */
>>> +    vsetvli a4,zero,e8,m1,ta,ma
>>> +    bgt a2,a4,L(block_copy)
>>> +    vle8.v  v8,(a1)
>>> +    vse8.v  v8,(a6)
>>> +    ret
>>> +L(block_copy):
>>> +    vsetvli a3,a2,e8,m8,ta,ma
>>> +    vle8.v  v8,(a1)
>>> +    vse8.v  v8,(a6)
>>> +    add     a1,a1,a3
>>> +    add     a6,a6,a3
>>> +    sub     a2,a2,a3
>>> +    bnez    a2,L(block_copy)
>>> +L(ret):
>>> +    ret
>>> +END (__memcpy_vector)
>>> diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
>>> index fcef5659d4..394033e077 100644
>>> --- a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
>>> +++ b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
>>> @@ -5,5 +5,13 @@ sysdep_routines += \
>>>     memcpy_noalignment \
>>>     # sysdep_routines
>>>
>>> +ifeq ($(have-gcc-riscv-rvv),yes)
>>> +sysdep_routines += \
>>> +  memcpy_vector \
>>> +  # rvv sysdep_routines
>>> +
>>> +ASFLAGS-memcpy_vector.S += -march=rv64gcv
>>> +endif
>>> +
>>>   CFLAGS-memcpy_noalignment.c += -mno-strict-align
>>>   endif
>>> diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c b/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c
>>> index 1c1deca8f6..2088097558 100644
>>> --- a/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c
>>> +++ b/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c
>>> @@ -19,6 +19,7 @@
>>>   #include <ifunc-impl-list.h>
>>>   #include <string.h>
>>>   #include <sys/hwprobe.h>
>>> +#include <ldsodefs.h>
>>>
>>>   size_t
>>>   __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
>>> @@ -27,6 +28,9 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
>>>     size_t i = max;
>>>
>>>     bool fast_unaligned = false;
>>> +#if defined(HAVE_RISCV_ASM_VECTOR_SUPPORT)
>>> +  bool rvv_ext = false;
>>> +#endif
>>>
>>>     struct riscv_hwprobe pair = { .key = RISCV_HWPROBE_KEY_CPUPERF_0 };
>>>     if (__riscv_hwprobe (&pair, 1, 0, NULL, 0) == 0
>>> @@ -34,7 +38,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
>>>             == RISCV_HWPROBE_MISALIGNED_FAST)
>>>       fast_unaligned = true;
>>>
>>> +#if defined(HAVE_RISCV_ASM_VECTOR_SUPPORT)
>>> +  if (GLRO(dl_hwcap) & COMPAT_HWCAP_ISA_V)
>>> +    rvv_ext = true;
>>> +#endif
>>> +
>>>     IFUNC_IMPL (i, name, memcpy,
>>> +#if defined(HAVE_RISCV_ASM_VECTOR_SUPPORT)
>>> +             IFUNC_IMPL_ADD (array, i, memcpy, rvv_ext,
>>> +                             __memcpy_vector)
>>> +#endif
>>>                IFUNC_IMPL_ADD (array, i, memcpy, fast_unaligned,
>>>                                __memcpy_noalignment)
>>>                IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_generic))
>>> diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/memcpy.c b/sysdeps/unix/sysv/linux/riscv/multiarch/memcpy.c
>>> index 8544f5402a..1982e4ab65 100644
>>> --- a/sysdeps/unix/sysv/linux/riscv/multiarch/memcpy.c
>>> +++ b/sysdeps/unix/sysv/linux/riscv/multiarch/memcpy.c
>>> @@ -32,11 +32,18 @@ extern __typeof (__redirect_memcpy) __libc_memcpy;
>>>
>>>   extern __typeof (__redirect_memcpy) __memcpy_generic attribute_hidden;
>>>   extern __typeof (__redirect_memcpy) __memcpy_noalignment attribute_hidden;
>>> +extern __typeof (__redirect_memcpy) __memcpy_vector attribute_hidden;
>>>
>>>   static inline __typeof (__redirect_memcpy) *
>>>   select_memcpy_ifunc (uint64_t dl_hwcap, __riscv_hwprobe_t hwprobe_func)
>>>   {
>>>     unsigned long long int v;
>>> +
>>> +#if defined(HAVE_RISCV_ASM_VECTOR_SUPPORT)
>>> +  if (dl_hwcap & COMPAT_HWCAP_ISA_V)
>>> +    return __memcpy_vector;
>>> +#endif
>>> +
>>>     if (__riscv_hwprobe_one (hwprobe_func, RISCV_HWPROBE_KEY_CPUPERF_0, &v) == 0
>>>         && (v & RISCV_HWPROBE_MISALIGNED_MASK) == RISCV_HWPROBE_MISALIGNED_FAST)
>>>       return __memcpy_noalignment;
>>> --
>>> 2.25.1
>>>



More information about the Libc-alpha mailing list