[PATCH v3 1/1] riscv: Add RVV memset via multiarch/IFUNC

Darius Rad darius@bluespec.com
Thu Nov 20 18:56:21 GMT 2025


On Thu, Nov 20, 2025 at 06:21:25PM +0800, Yao Zihong wrote:
> This patch adds an RVV-optimized implementation of memset for RISC-V and
> enables it through the existing multiarch/IFUNC mechanism.
> 
> The implementation integrates Hau Hsu's 2023 RVV work under a unified
> ifunc-based framework. A vectorized version (__memset_vector) is added
> alongside the generic fallback (__memset_generic). The runtime resolver
> selects the RVV variant when RISCV_HWPROBE_KEY_IMA_EXT_0 reports vector
> support (V).
> 
> Tested on MUSE-Pi (SpacemiT M1). No regressions were observed compared
> with glibc master when the RVV extension was not disabled via prctl().
> 
> Currently, the resolver still selects the RVV variant even when the V
> extension is disabled via prctl().

It is disingenuous not to state plainly what the consequence of this is.

> 
> Co-authored-by: Jerry Shih <jerry.shih@sifive.com>
> Co-authored-by: Jeff Law <jeffreyalaw@gmail.com>
> Signed-off-by: Yao Zihong <zihong.plct@isrc.iscas.ac.cn>
> ---
>  .../riscv/multiarch/dl-symbol-redir-ifunc.h   | 27 +++++++++
>  sysdeps/riscv/multiarch/memset-generic.c      | 26 +++++++++
>  sysdeps/riscv/multiarch/memset_vector.S       | 52 +++++++++++++++++
>  .../unix/sysv/linux/riscv/multiarch/Makefile  |  3 +
>  .../linux/riscv/multiarch/ifunc-impl-list.c   | 22 +++++--
>  .../unix/sysv/linux/riscv/multiarch/memset.c  | 58 +++++++++++++++++++
>  6 files changed, 184 insertions(+), 4 deletions(-)
>  create mode 100644 sysdeps/riscv/multiarch/dl-symbol-redir-ifunc.h
>  create mode 100644 sysdeps/riscv/multiarch/memset-generic.c
>  create mode 100644 sysdeps/riscv/multiarch/memset_vector.S
>  create mode 100644 sysdeps/unix/sysv/linux/riscv/multiarch/memset.c
> 
> diff --git a/sysdeps/riscv/multiarch/dl-symbol-redir-ifunc.h b/sysdeps/riscv/multiarch/dl-symbol-redir-ifunc.h
> new file mode 100644
> index 0000000000..d7c8d0b7e3
> --- /dev/null
> +++ b/sysdeps/riscv/multiarch/dl-symbol-redir-ifunc.h
> @@ -0,0 +1,27 @@
> +/* Symbol redirection for loader/static initialization code.
> +   Copyright (C) 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/>.  */
> +
> +#ifndef _DL_IFUNC_GENERIC_H
> +#define _DL_IFUNC_GENERIC_H
> +
> +#ifndef SHARED
> +asm ("memset = __memset_generic");
> +asm ("memcpy = __memcpy_generic");
> +#endif
> +
> +#endif
> diff --git a/sysdeps/riscv/multiarch/memset-generic.c b/sysdeps/riscv/multiarch/memset-generic.c
> new file mode 100644
> index 0000000000..c93bb43c8f
> --- /dev/null
> +++ b/sysdeps/riscv/multiarch/memset-generic.c
> @@ -0,0 +1,26 @@
> +/* Re-include the default memset implementation.
> +   Copyright (C) 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 <string.h>
> +
> +#if IS_IN(libc)
> +# define MEMSET __memset_generic
> +# undef libc_hidden_builtin_def
> +# define libc_hidden_builtin_def(x)
> +#endif
> +#include <string/memset.c>
> diff --git a/sysdeps/riscv/multiarch/memset_vector.S b/sysdeps/riscv/multiarch/memset_vector.S
> new file mode 100644
> index 0000000000..e54e356ad3
> --- /dev/null
> +++ b/sysdeps/riscv/multiarch/memset_vector.S
> @@ -0,0 +1,52 @@
> +/* RISC-V RVV based memset.
> +   Copyright (C) 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
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include <sysdep.h>
> +#include <sys/asm.h>
> +
> +#if IS_IN(libc)
> +
> +#define dst a0
> +#define value a1
> +#define num a2
> +
> +#define ivl a3
> +#define dst_ptr a5
> +
> +#define ELEM_LMUL_SETTING m8
> +#define vdata v0
> +
> +ENTRY (__memset_vector)
> +.option push
> +.option arch, +v
> +    mv dst_ptr, dst
> +
> +    vsetvli ivl, num, e8, ELEM_LMUL_SETTING, ta, ma
> +    vmv.v.x vdata, value
> +L(loop):
> +    vse8.v vdata, (dst_ptr)
> +    sub num, num, ivl
> +    add dst_ptr, dst_ptr, ivl
> +    vsetvli ivl, num, e8, ELEM_LMUL_SETTING, ta, ma
> +    bnez num, L(loop)
> +
> +    ret
> +.option pop
> +END (__memset_vector)
> +
> +#endif
> diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
> index fcef5659d4..de8024b86d 100644
> --- a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
> +++ b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
> @@ -3,6 +3,9 @@ sysdep_routines += \
>    memcpy \
>    memcpy-generic \
>    memcpy_noalignment \
> +  memset \
> +  memset-generic \
> +  memset_vector \
>    # sysdep_routines
>  
>  CFLAGS-memcpy_noalignment.c += -mno-strict-align
> 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..66902ee88c 100644
> --- a/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c
> +++ b/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c
> @@ -27,17 +27,31 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
>    size_t i = max;
>  
>    bool fast_unaligned = false;
> +  bool rvv_ext = false;
>  
> -  struct riscv_hwprobe pair = { .key = RISCV_HWPROBE_KEY_CPUPERF_0 };
> -  if (__riscv_hwprobe (&pair, 1, 0, NULL, 0) == 0
> -      && (pair.value & RISCV_HWPROBE_MISALIGNED_MASK)
> +  struct riscv_hwprobe pairs[2] = {
> +    {.key = RISCV_HWPROBE_KEY_CPUPERF_0},
> +    {.key = RISCV_HWPROBE_KEY_IMA_EXT_0}
> +  };
> +
> +  if (__riscv_hwprobe (pairs, 2, 0, NULL, 0) == 0) {
> +    if ((pairs[0].value & RISCV_HWPROBE_MISALIGNED_MASK)
>            == RISCV_HWPROBE_MISALIGNED_FAST)
> -    fast_unaligned = true;
> +      fast_unaligned = true;
> +
> +    if (pairs[1].value & RISCV_HWPROBE_IMA_V)
> +      rvv_ext = true;
> +  }
>  
>    IFUNC_IMPL (i, name, memcpy,
>  	      IFUNC_IMPL_ADD (array, i, memcpy, fast_unaligned,
>  			      __memcpy_noalignment)
>  	      IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_generic))
>  
> +  IFUNC_IMPL (i, name, memset,
> +	      IFUNC_IMPL_ADD (array, i, memset, rvv_ext,
> +			      __memset_vector)
> +	      IFUNC_IMPL_ADD (array, i, memset, 1, __memset_generic))
> +
>    return 0;
>  }
> diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/memset.c b/sysdeps/unix/sysv/linux/riscv/multiarch/memset.c
> new file mode 100644
> index 0000000000..166427bff8
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/riscv/multiarch/memset.c
> @@ -0,0 +1,58 @@
> +/* Multiple versions of memset.
> +   All versions must be listed in ifunc-impl-list.c.
> +   Copyright (C) 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/>.  */
> +
> +#if IS_IN (libc)
> +/* Redefine memset so that the compiler won't complain about the type
> +   mismatch with the IFUNC selector in strong_alias, below.  */
> +# undef memset
> +# define memset __redirect_memset
> +# include <stdint.h>
> +# include <string.h>
> +# include <ifunc-init.h>
> +# include <riscv-ifunc.h>
> +# include <sys/hwprobe.h>
> +
> +extern __typeof (__redirect_memset) __libc_memset;
> +
> +extern __typeof (__redirect_memset) __memset_generic attribute_hidden;
> +extern __typeof (__redirect_memset) __memset_vector attribute_hidden;
> +
> +static inline __typeof (__redirect_memset) *
> +select_memset_ifunc (uint64_t dl_hwcap, __riscv_hwprobe_t hwprobe_func)
> +{
> +  unsigned long long v;
> +
> +  if (__riscv_hwprobe_one (hwprobe_func, RISCV_HWPROBE_KEY_IMA_EXT_0, &v) == 0
> +      && (v & RISCV_HWPROBE_IMA_V) == RISCV_HWPROBE_IMA_V)
> +    return __memset_vector;
> +
> +  return __memset_generic;
> +}
> +
> +riscv_libc_ifunc (__libc_memset, select_memset_ifunc);
> +
> +# undef memset
> +strong_alias (__libc_memset, memset);
> +# ifdef SHARED
> +__hidden_ver1 (memset, __GI_memset, __redirect_memset)
> +  __attribute__ ((visibility ("hidden"))) __attribute_copy__ (memset);
> +# endif
> +#else
> +# include <string/memset.c>
> +#endif
> -- 
> 2.47.2
> 


More information about the Libc-alpha mailing list