[glibc] riscv: Add RVV strlen for both multiarch and non-multiarch builds

Peter Bergner via Glibc-cvs <[email protected]>
Newsgroups gmane.comp.lib.glibc.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=07122a9d8d4597321e77d97f9ba18c11a42d8b5b

commit 07122a9d8d4597321e77d97f9ba18c11a42d8b5b
Author: Yao Zihong <[email protected]>
Date:   Thu Apr 30 15:15:36 2026 -0500

    riscv: Add RVV strlen for both multiarch and non-multiarch builds
    
    This patch adds an RVV-optimized implementation of strlen 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 (__strlen_vector) is added
    alongside the generic fallback (__strlen_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 strlen().
    
    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]>

Diff:
---
 sysdeps/riscv/multiarch/strlen-generic.c           | 24 +++++++++
 sysdeps/riscv/multiarch/strlen-vector.S            | 26 ++++++++++
 sysdeps/riscv/rvv/strlen.S                         | 58 ++++++++++++++++++++++
 sysdeps/unix/sysv/linux/riscv/multiarch/Makefile   |  3 ++
 .../sysv/linux/riscv/multiarch/ifunc-impl-list.c   |  5 ++
 sysdeps/unix/sysv/linux/riscv/multiarch/strlen.c   | 56 +++++++++++++++++++++
 6 files changed, 172 insertions(+)

diff --git a/sysdeps/riscv/multiarch/strlen-generic.c b/sysdeps/riscv/multiarch/strlen-generic.c
new file mode 100644
index 0000000000..6317b1cb44
--- /dev/null
+++ b/sysdeps/riscv/multiarch/strlen-generic.c
@@ -0,0 +1,24 @@
+/* Re-include the default strlen 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 STRLEN __strlen_generic
+# include <string/strlen.c>
+#endif
diff --git a/sysdeps/riscv/multiarch/strlen-vector.S b/sysdeps/riscv/multiarch/strlen-vector.S
new file mode 100644
index 0000000000..b7841ed295
--- /dev/null
+++ b/sysdeps/riscv/multiarch/strlen-vector.S
@@ -0,0 +1,26 @@
+/* Re-include the RISC-V RVV based strlen 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 STRLEN __strlen_vector
+# undef libc_hidden_builtin_def
+# define libc_hidden_builtin_def(name)
+# undef weak_alias
+# define weak_alias(name, alias)
+# include <sysdeps/riscv/rvv/strlen.S>
+#endif
diff --git a/sysdeps/riscv/rvv/strlen.S b/sysdeps/riscv/rvv/strlen.S
new file mode 100644
index 0000000000..0a3b18eb0c
--- /dev/null
+++ b/sysdeps/riscv/rvv/strlen.S
@@ -0,0 +1,58 @@
+/* RISC-V RVV based strlen.
+   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 STRLEN
+# define STRLEN __strlen
+#endif
+
+#define result a0
+#define str a0
+#define copy_str a1
+#define ivl a2
+#define cur_vl a2
+#define end_offset a3
+
+#define ELEM_LMUL_SETTING m2
+#define vstr v0
+#define vmask_end v2
+
+ENTRY (STRLEN)
+.option push
+.option arch, +v
+    mv copy_str, str
+L(loop):
+    vsetvli ivl, zero, e8, ELEM_LMUL_SETTING, ta, ma
+    vle8ff.v vstr, (copy_str)
+    csrr cur_vl, vl
+    vmseq.vi vmask_end, vstr, 0
+    vfirst.m end_offset, vmask_end
+    add copy_str, copy_str, cur_vl
+    bltz end_offset, L(loop)
+
+    add str, str, cur_vl
+    add copy_str, copy_str, end_offset
+    sub result, copy_str, result
+
+    ret
+.option pop
+END (STRLEN)
+weak_alias (STRLEN, strlen)
+libc_hidden_builtin_def (strlen)
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
index 32be517d21..2a2b90960f 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
@@ -13,6 +13,9 @@ sysdep_routines += \
   strcpy \
   strcpy-generic \
   strcpy-vector \
+  strlen \
+  strlen-generic \
+  strlen-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 0eb55a5ad8..2501546665 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c
@@ -65,5 +65,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
 			      __strcpy_vector)
 	      IFUNC_IMPL_ADD (array, i, strcpy, 1, __strcpy_generic))
 
+  IFUNC_IMPL (i, name, strlen,
+	      IFUNC_IMPL_ADD (array, i, strlen, rvv_enabled,
+			      __strlen_vector)
+	      IFUNC_IMPL_ADD (array, i, strlen, 1, __strlen_generic))
+
   return 0;
 }
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/strlen.c b/sysdeps/unix/sysv/linux/riscv/multiarch/strlen.c
new file mode 100644
index 0000000000..9975286b85
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/strlen.c
@@ -0,0 +1,56 @@
+/* Multiple versions of strlen.
+   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)
+/* Redefine strlen so that the compiler won't complain about the type
+   mismatch with the IFUNC selector in strong_alias, below.  */
+# undef strlen
+# define strlen __redirect_strlen
+# include <stdint.h>
+# include <string.h>
+# include <ifunc-init.h>
+# include <riscv-ifunc.h>
+# include <sys/hwprobe.h>
+
+extern __typeof (__redirect_strlen) __libc_strlen;
+
+extern __typeof (__redirect_strlen) __strlen_generic attribute_hidden;
+extern __typeof (__redirect_strlen) __strlen_vector attribute_hidden;
+
+static inline __typeof (__redirect_strlen) *
+select_strlen_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 __strlen_vector;
+  return __strlen_generic;
+}
+
+riscv_libc_ifunc (__libc_strlen, select_strlen_ifunc);
+
+# undef strlen
+strong_alias (__libc_strlen, strlen);
+# ifdef SHARED
+__hidden_ver1 (strlen, __GI_strlen, __redirect_strlen)
+  __attribute__ ((visibility ("hidden"))) __attribute_copy__ (strlen);
+# endif
+#else
+# include <string/strlen.c>
+#endif
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.