Re: [PATCH v5 06/18] riscv: Add RVV memmove for multiarch and non-multiarch

Peter Bergner <[email protected]>
Newsgroups gmane.comp.lib.glibc.alpha
Message-ID <[email protected]>
On 6/9/26 2:56 PM, Peter Bergner wrote:
> I'll note I see the following with the v5 stpncpy patch doing a normal
> glibc build with -march=rv64gc (ie, no vector):
> 
> 
> ./../include/libc-symbols.h:475:33: error: '__EI___stpncpy' aliased to undefined symbol '__GI___stpncpy'
>   475 |   extern thread __typeof (name) __EI_##name \
>       |                                 ^~~~~
> ./../include/libc-symbols.h:471:3: note: in expansion of macro '__hidden_ver2'
>   471 |   __hidden_ver2 (, local, internal, name)
>       |   ^~~~~~~~~~~~~
> ./../include/libc-symbols.h:479:41: note: in expansion of macro '__hidden_ver1'
>   479 | #  define hidden_def(name)              __hidden_ver1(__GI_##name, name, name);
>       |                                         ^~~~~~~~~~~~~
> ./../include/libc-symbols.h:560:32: note: in expansion of macro 'hidden_def'
>   560 | # define libc_hidden_def(name) hidden_def (name)
>       |                                ^~~~~~~~~~
> ../sysdeps/unix/sysv/linux/riscv/multiarch/stpncpy.c:50:1: note: in expansion of macro 'libc_hidden_def'
>    50 | libc_hidden_def (__stpncpy);
>       | ^~~~~~~~~~~~~~~

Given the freeze is coming this weekend, I spent some time fixing this issue, as well as a few others
once this issue is fixed.  Basically, I needed the following patch to fix the compile and
make chack-abi errors:

@@ -19,9 +19,11 @@

 #if IS_IN (libc)
 /* Redefine stpncpy so that the compiler won't complain about the type
-   mismatch with the IFUNC selector in strong_alias, below.  */
+   mismatch with the IFUNC selector in weak_alias, below.  */
 # undef stpncpy
+# undef __stpncpy
 # define stpncpy __redirect_stpncpy
+# define __stpncpy __redirect___stpncpy
 # include <stdint.h>
 # include <string.h>
 # include <ifunc-init.h>
@@ -46,10 +48,11 @@
 riscv_libc_ifunc (__libc_stpncpy, select_stpncpy_ifunc);

 # undef stpncpy
+# undef __stpncpy
 weak_alias (__libc_stpncpy, stpncpy);
-libc_hidden_def (__stpncpy);
+weak_alias (__libc_stpncpy, __stpncpy);
 # ifdef SHARED
-__hidden_ver1 (stpncpy, __GI_stpncpy, __redirect_stpncpy)
+__hidden_ver1 (stpncpy, __GI___stpncpy, __redirect_stpncpy)
   __attribute__ ((visibility ("hidden"))) __attribute_copy__ (stpncpy);
 # endif
 #else

That said, I went a little further and made a couple more changes to stpncpy.c to make our
implementation use the macros defined in ifunc-init.h similar to x86_64's.  I'm including
the full updated patch below which includes some comment fixes in the stpncpy.S file too.
I plan on pushing this commit tomorrow unless someone notices a problem with it.

Peter




riscv: Add RVV stpncpy for both multiarch and non-multiarch builds

This patch adds an RVV-optimized implementation of stpncpy for RISC-V and
enables it for both multiarch (IFUNC) and non-multiarch builds.

The implementation integrates Hau Hsu's 2023 RVV work under a unified
ifunc-based framework. A vectorized version (__stpncpy_vector) is added
alongside the generic fallback (__stpncpy_generic). The runtime resolver
selects the RVV variant when RISCV_HWPROBE_KEY_IMA_EXT_0 reports vector
support (RVV).

Currently, the resolver still selects the RVV variant even when the RVV
extension is disabled via prctl(). As a consequence, any process that
has RVV disabled via prctl() will receive SIGILL when calling stpncpy().

Co-authored-by: Hau Hsu <[email protected]>
Co-authored-by: Jerry Shih <[email protected]>
Signed-off-by: Yao Zihong <[email protected]>
Reviewed-by: Peter Bergner <[email protected]>
---
 sysdeps/riscv/multiarch/stpncpy-generic.c     | 28 ++++++
 sysdeps/riscv/multiarch/stpncpy-vector.S      | 28 ++++++
 sysdeps/riscv/rvv/stpncpy.S                   | 97 +++++++++++++++++++
 .../unix/sysv/linux/riscv/multiarch/Makefile  |  3 +
 .../linux/riscv/multiarch/ifunc-impl-list.c   |  5 +
 .../unix/sysv/linux/riscv/multiarch/stpncpy.c | 62 ++++++++++++
 6 files changed, 223 insertions(+)
 create mode 100644 sysdeps/riscv/multiarch/stpncpy-generic.c
 create mode 100644 sysdeps/riscv/multiarch/stpncpy-vector.S
 create mode 100644 sysdeps/riscv/rvv/stpncpy.S
 create mode 100644 sysdeps/unix/sysv/linux/riscv/multiarch/stpncpy.c

diff --git a/sysdeps/riscv/multiarch/stpncpy-generic.c b/sysdeps/riscv/multiarch/stpncpy-generic.c
new file mode 100644
index 0000000000..4be8080d88
--- /dev/null
+++ b/sysdeps/riscv/multiarch/stpncpy-generic.c
@@ -0,0 +1,28 @@
+/* Re-include the default stpncpy implementation.
+   Copyright (C) 2026 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 STPNCPY __stpncpy_generic
+# undef libc_hidden_def
+# define libc_hidden_def(name)
+# undef weak_alias
+# define weak_alias(x, x2)
+# include <string/stpncpy.c>
+#endif
diff --git a/sysdeps/riscv/multiarch/stpncpy-vector.S b/sysdeps/riscv/multiarch/stpncpy-vector.S
new file mode 100644
index 0000000000..e84d28a1e4
--- /dev/null
+++ b/sysdeps/riscv/multiarch/stpncpy-vector.S
@@ -0,0 +1,28 @@
+/* Re-include the RISC-V RVV based stpncpy implementation.
+   Copyright (C) 2026 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)
+# define STPNCPY __stpncpy_vector
+# undef libc_hidden_builtin_def
+# define libc_hidden_builtin_def(name)
+# undef libc_hidden_def
+# define libc_hidden_def(name)
+# undef weak_alias
+# define weak_alias(name, alias)
+# include <sysdeps/riscv/rvv/stpncpy.S>
+#endif
diff --git a/sysdeps/riscv/rvv/stpncpy.S b/sysdeps/riscv/rvv/stpncpy.S
new file mode 100644
index 0000000000..7cfc2f76cc
--- /dev/null
+++ b/sysdeps/riscv/rvv/stpncpy.S
@@ -0,0 +1,97 @@
+/* RISC-V RVV based stpncpy.
+   Copyright (C) 2026 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>
+
+#ifndef STPNCPY
+# ifdef weak_alias
+#  define STPNCPY __stpncpy
+weak_alias (__stpncpy, stpncpy)
+# else
+#  define STPNCPY stpncpy
+# endif
+#endif
+
+#define dst a0
+#define src a1
+#define length a2
+#define dst_ptr a3
+#define active_elem_pos a4
+#define cur_vl a5
+#define ivl a6
+#define temp a1
+
+#define ELEM_LMUL_SETTING m1
+#define vmask1 v0
+#define vmask2 v1
+#define ZERO_FILL_ELEM_LMUL_SETTING m8
+#define vstr1 v8
+#define vstr2 v16
+
+ENTRY (STPNCPY)
+.option push
+.option arch, +v
+    mv dst_ptr, dst
+    /* Copy src to dst_ptr.  */
+L(stpcpy_loop):
+    vsetvli zero, length, e8, ELEM_LMUL_SETTING, ta, ma
+    vle8ff.v vstr1, (src)
+    vmseq.vx vmask2, vstr1, zero
+    csrr cur_vl, vl
+    vfirst.m active_elem_pos, vmask2
+    vmsif.m vmask1, vmask2
+    add src, src, cur_vl
+    sub length, length, cur_vl
+    vse8.v vstr1, (dst_ptr), vmask1.t
+    add dst_ptr, dst_ptr, cur_vl
+    bgez active_elem_pos, L(fill_zero)
+    bnez length, L(stpcpy_loop)
+    mv dst, dst_ptr
+    ret
+
+    /* Fill the tail zero.  */
+L(fill_zero):
+    /* We already copied the `\0` to dst, but we use `vfirst.m` to
+       get the `index` of the `\0` position. We need to adjust by `-1`
+       to get the correct remaining length for zero filling.  */
+    sub temp, cur_vl, active_elem_pos
+    addi temp, temp, -1
+    sub dst, dst_ptr, cur_vl
+    add dst, dst, active_elem_pos
+    add length, length, temp
+    /* Return early for the `strlen(src) + 1 == count` case.  */
+    bnez length, L(do_fill_zero)
+    ret
+
+L(do_fill_zero):
+    sub dst_ptr, dst_ptr, temp
+    vsetvli zero, length, e8, ZERO_FILL_ELEM_LMUL_SETTING, ta, ma
+    vmv.v.x vstr2, zero
+L(fill_zero_loop):
+    vsetvli ivl, length, e8, ZERO_FILL_ELEM_LMUL_SETTING, ta, ma
+    vse8.v vstr2, (dst_ptr)
+    sub length, length, ivl
+    add dst_ptr, dst_ptr, ivl
+    bnez length, L(fill_zero_loop)
+    ret
+.option pop
+END (STPNCPY)
+#ifdef weak_alias
+libc_hidden_def (__stpncpy)
+#endif
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
index 929df14a6f..25d8216d2e 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
@@ -19,6 +19,9 @@ sysdep_routines += \
   memset \
   memset-generic \
   memset-vector \
+  stpncpy \
+  stpncpy-generic \
+  stpncpy-vector \
   strcat \
   strcat-generic \
   strcat-vector \
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 4c28e22606..755ba9d637 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c
@@ -110,5 +110,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
 			      __memmove_vector)
 	      IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_generic))
 
+  IFUNC_IMPL (i, name, stpncpy,
+	      IFUNC_IMPL_ADD (array, i, stpncpy, rvv_enabled,
+			      __stpncpy_vector)
+	      IFUNC_IMPL_ADD (array, i, stpncpy, 1, __stpncpy_generic))
+
   return 0;
 }
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/stpncpy.c b/sysdeps/unix/sysv/linux/riscv/multiarch/stpncpy.c
new file mode 100644
index 0000000000..989003f081
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/stpncpy.c
@@ -0,0 +1,62 @@
+/* Multiple versions of stpncpy.
+   All versions must be listed in ifunc-impl-list.c.
+   Copyright (C) 2026 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)
+#define SYMBOL_NAME stpncpy
+# include <ifunc-init.h>
+
+/* Redefine stpncpy so that the compiler won't complain about the type
+   mismatch with the IFUNC selector in weak_alias, below.  */
+# undef stpncpy
+# undef __stpncpy
+# define stpncpy REDIRECT_NAME
+# define __stpncpy __redirect___stpncpy
+# include <string.h>
+# undef stpncpy
+# undef __stpncpy
+
+# include <stdint.h>
+# include <riscv-ifunc.h>
+# include <sys/hwprobe.h>
+
+extern __typeof (REDIRECT_NAME) __stpncpy;
+extern __typeof (REDIRECT_NAME) OPTIMIZE (generic) attribute_hidden;
+extern __typeof (REDIRECT_NAME) OPTIMIZE (vector) attribute_hidden;
+
+static inline __typeof (REDIRECT_NAME) *
+select_stpncpy_ifunc (uint64_t dl_hwcap, __riscv_hwprobe_t hwprobe_func)
+{
+  unsigned long long int 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 OPTIMIZE (vector);
+  return OPTIMIZE (generic);
+}
+
+riscv_libc_ifunc (__stpncpy, select_stpncpy_ifunc);
+
+weak_alias (__stpncpy, stpncpy);
+
+# ifdef SHARED
+__hidden_ver1 (__stpncpy, __GI___stpncpy, __redirect___stpncpy)
+  __attribute__ ((visibility ("hidden")));
+# endif
+#else
+# include <string/stpncpy.c>
+#endif
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.