[PATCH 2/2] AArch64: Add SVE2 strchrnul

Wilco Dijkstra <[email protected]> Mon, 3 Aug 2026 15:49:59 +0000
Newsgroups gmane.comp.lib.glibc.alpha
Message-ID <PAWPR08MB89824AE3850B4A94F09A1BE283D52@PAWPR08MB8982.eurprd08.prod.outlook.com>
=0A=
Add an SVE2 strchrnul implementation and ifunc support based on strchr-sve.=
S.=0A=
Use MATCH to check for both the input char and NUL.  Performance of=0A=
bench-strchrnul improves ~34% on Neoverse V2.=0A=
=0A=
---=0A=
=0A=
diff --git a/sysdeps/aarch64/multiarch/Makefile b/sysdeps/aarch64/multiarch=
/Makefile=0A=
index 9616231c042c03088384b07ea8c5465d413048d1..8c279a81f7bd53f07bcab49ba17=
680355f57b5ab 100644=0A=
--- a/sysdeps/aarch64/multiarch/Makefile=0A=
+++ b/sysdeps/aarch64/multiarch/Makefile=0A=
@@ -18,6 +18,8 @@ sysdep_routines +=3D \=0A=
   memset_zva64 \=0A=
   strchr_generic \=0A=
   strchr_sve2 \=0A=
+  strchrnul_generic \=0A=
+  strchrnul_sve2 \=0A=
   strlen_asimd \=0A=
   strlen_generic \=0A=
   # sysdep_routines=0A=
diff --git a/sysdeps/aarch64/multiarch/dl-symbol-redir-ifunc.h b/sysdeps/aa=
rch64/multiarch/dl-symbol-redir-ifunc.h=0A=
index 50b2581455c94dc2bd38f8e5ba9a357d1b79e89f..74fdca91baa562316f8f0a4d245=
0e9dd81aabb9c 100644=0A=
--- a/sysdeps/aarch64/multiarch/dl-symbol-redir-ifunc.h=0A=
+++ b/sysdeps/aarch64/multiarch/dl-symbol-redir-ifunc.h=0A=
@@ -23,6 +23,8 @@ asm ("memset =3D __memset_generic");=0A=
 asm ("strlen =3D __strlen_generic");=0A=
 #ifndef SHARED=0A=
 asm ("strchr =3D __strchr_generic");=0A=
+asm ("strchrnul =3D __strchrnul_generic");=0A=
+asm ("__strchrnul =3D __strchrnul_generic");=0A=
 asm ("memcpy =3D __memcpy_generic");=0A=
 asm ("memmove =3D __memmove_generic");=0A=
 asm ("memcmp =3D __memcmp_generic");=0A=
diff --git a/sysdeps/aarch64/multiarch/ifunc-impl-list.c b/sysdeps/aarch64/=
multiarch/ifunc-impl-list.c=0A=
index a0c93147c532d935d562a66ac67ebaa5326dd3bd..5f5350850dd5d8270c2675fdbdc=
3be0f110f7116 100644=0A=
--- a/sysdeps/aarch64/multiarch/ifunc-impl-list.c=0A=
+++ b/sysdeps/aarch64/multiarch/ifunc-impl-list.c=0A=
@@ -63,5 +63,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifu=
nc_impl *array,=0A=
   IFUNC_IMPL (i, name, strchr,=0A=
 	      IFUNC_IMPL_ADD (array, i, strchr, sve2 && !mte, __strchr_sve2)=0A=
 	      IFUNC_IMPL_ADD (array, i, strchr, 1, __strchr_generic))=0A=
+  IFUNC_IMPL (i, name, strchrnul,=0A=
+	      IFUNC_IMPL_ADD (array, i, strchrnul, sve2 && !mte, __strchrnul_sve2=
)=0A=
+	      IFUNC_IMPL_ADD (array, i, strchrnul, 1, __strchrnul_generic))=0A=
   return 0;=0A=
 }=0A=
diff --git a/sysdeps/aarch64/multiarch/strchrnul.c b/sysdeps/aarch64/multia=
rch/strchrnul.c=0A=
new file mode 100644=0A=
index 0000000000000000000000000000000000000000..d09508880655bada4ca9185a5ce=
df28714d10a31=0A=
--- /dev/null=0A=
+++ b/sysdeps/aarch64/multiarch/strchrnul.c=0A=
@@ -0,0 +1,41 @@=0A=
+/* Multiple versions of strchrnul. AArch64 version.=0A=
+   Copyright (C) 2026 Free Software Foundation, Inc.=0A=
+   This file is part of the GNU C Library.=0A=
+=0A=
+   The GNU C Library is free software; you can redistribute it and/or=0A=
+   modify it under the terms of the GNU Lesser General Public=0A=
+   License as published by the Free Software Foundation; either=0A=
+   version 2.1 of the License, or (at your option) any later version.=0A=
+=0A=
+   The GNU C Library is distributed in the hope that it will be useful,=0A=
+   but WITHOUT ANY WARRANTY; without even the implied warranty of=0A=
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU=0A=
+   Lesser General Public License for more details.=0A=
+=0A=
+   You should have received a copy of the GNU Lesser General Public=0A=
+   License along with the GNU C Library; if not, see=0A=
+   <https://www.gnu.org/licenses/>.  */=0A=
+=0A=
+/* Define multiple versions only for the definition in libc.  */=0A=
+=0A=
+#if IS_IN (libc)=0A=
+/* Redefine strchrnul so that the compiler won't complain about the type=
=0A=
+   mismatch with the IFUNC selector in weak_alias, below.  */=0A=
+# undef strchrnul=0A=
+# undef __strchrnul=0A=
+# define strchrnul __redirect_strchrnul=0A=
+# define __strchrnul __redirect___strchrnul=0A=
+# include <string.h>=0A=
+# include <init-arch.h>=0A=
+# undef strchrnul=0A=
+# undef __strchrnul=0A=
+=0A=
+extern __typeof (__redirect_strchrnul) __strchrnul attribute_hidden;=0A=
+=0A=
+extern __typeof (__redirect_strchrnul) __strchrnul_generic attribute_hidde=
n;=0A=
+extern __typeof (__redirect_strchrnul) __strchrnul_sve2 attribute_hidden;=
=0A=
+=0A=
+libc_ifunc (__strchrnul, (sve2 && !mte ? __strchrnul_sve2 : __strchrnul_ge=
neric));=0A=
+=0A=
+weak_alias (__strchrnul, strchrnul);=0A=
+#endif=0A=
diff --git a/sysdeps/aarch64/multiarch/strchrnul_generic.S b/sysdeps/aarch6=
4/multiarch/strchrnul_generic.S=0A=
new file mode 100644=0A=
index 0000000000000000000000000000000000000000..e5a6380e775eee3b97db575c1e1=
ea99860922f11=0A=
--- /dev/null=0A=
+++ b/sysdeps/aarch64/multiarch/strchrnul_generic.S=0A=
@@ -0,0 +1,38 @@=0A=
+/* A generic optimized strchrnul implementation for AArch64.=0A=
+   Copyright (C) 2026 Free Software Foundation, Inc.=0A=
+   This file is part of the GNU C Library.=0A=
+=0A=
+   The GNU C Library is free software; you can redistribute it and/or=0A=
+   modify it under the terms of the GNU Lesser General Public=0A=
+   License as published by the Free Software Foundation; either=0A=
+   version 2.1 of the License, or (at your option) any later version.=0A=
+=0A=
+   The GNU C Library is distributed in the hope that it will be useful,=0A=
+   but WITHOUT ANY WARRANTY; without even the implied warranty of=0A=
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU=0A=
+   Lesser General Public License for more details.=0A=
+=0A=
+   You should have received a copy of the GNU Lesser General Public=0A=
+   License along with the GNU C Library; if not, see=0A=
+   <https://www.gnu.org/licenses/>.  */=0A=
+=0A=
+#include <sysdep.h>=0A=
+=0A=
+#if IS_IN (libc)=0A=
+=0A=
+# define STRCHRNUL __strchrnul_generic=0A=
+=0A=
+/* Do not hide the generic version of strchr, we use it internally.  */=0A=
+# undef hidden_def=0A=
+# define hidden_def(name)=0A=
+=0A=
+# undef weak_alias=0A=
+# define weak_alias(a, b)=0A=
+=0A=
+# ifdef SHARED=0A=
+/* It doesn't make sense to send libc-internal strchrnul calls through a P=
LT.  */=0A=
+	.globl __GI___strchrnul; __GI___strchrnul =3D __strchrnul_generic=0A=
+# endif=0A=
+#endif=0A=
+=0A=
+#include "../strchrnul.S"=0A=
diff --git a/sysdeps/aarch64/multiarch/strchrnul_sve2.S b/sysdeps/aarch64/m=
ultiarch/strchrnul_sve2.S=0A=
new file mode 100644=0A=
index 0000000000000000000000000000000000000000..3a037446d851e060790369e7ea7=
8be8573fed56b=0A=
--- /dev/null=0A=
+++ b/sysdeps/aarch64/multiarch/strchrnul_sve2.S=0A=
@@ -0,0 +1,22 @@=0A=
+/* Optimized strchrnul for SVE2.=0A=
+   Copyright (C) 2026 Free Software Foundation, Inc.=0A=
+=0A=
+   This file is part of the GNU C Library.=0A=
+=0A=
+   The GNU C Library is free software; you can redistribute it and/or=0A=
+   modify it under the terms of the GNU Lesser General Public=0A=
+   License as published by the Free Software Foundation; either=0A=
+   version 2.1 of the License, or (at your option) any later version.=0A=
+=0A=
+   The GNU C Library is distributed in the hope that it will be useful,=0A=
+   but WITHOUT ANY WARRANTY; without even the implied warranty of=0A=
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU=0A=
+   Lesser General Public License for more details.=0A=
+=0A=
+   You should have received a copy of the GNU Lesser General Public=0A=
+   License along with the GNU C Library.  If not, see=0A=
+   <https://www.gnu.org/licenses/>.  */=0A=
+=0A=
+#define BUILD_STRCHRNUL=0A=
+=0A=
+#include "strchr_sve2.S"=0A=
diff --git a/sysdeps/aarch64/strchrnul.S b/sysdeps/aarch64/strchrnul.S=0A=
index c80807ea73d85493982e60d023c4c137b6c9b311..2bc535fc4f77bed5d558719fad2=
837a9d9791eef 100644=0A=
--- a/sysdeps/aarch64/strchrnul.S=0A=
+++ b/sysdeps/aarch64/strchrnul.S=0A=
@@ -26,6 +26,10 @@=0A=
  * MTE compatible.=0A=
  */=0A=
 =0A=
+#ifndef STRCHRNUL=0A=
+# define STRCHRNUL __strchrnul=0A=
+#endif=0A=
+=0A=
 #define srcin		x0=0A=
 #define chrin		w1=0A=
 #define result		x0=0A=
@@ -50,7 +54,7 @@=0A=
    which things occur in the original string, counting leading zeros ident=
ifies=0A=
    exactly which byte matched.  */=0A=
 =0A=
-ENTRY (__strchrnul)=0A=
+ENTRY (STRCHRNUL)=0A=
 	bic	src, srcin, 15=0A=
 	dup	vrepchr.16b, chrin=0A=
 	ld1	{vdata.16b}, [src]=0A=
@@ -93,6 +97,6 @@ L(end):=0A=
 	add	result, src, tmp1, lsr 2=0A=
 	ret=0A=
 =0A=
-END(__strchrnul)=0A=
-libc_hidden_def (__strchrnul)=0A=
-weak_alias (__strchrnul, strchrnul)=0A=
+END(STRCHRNUL)=0A=
+hidden_def (__strchrnul)=0A=
+weak_alias (STRCHRNUL, strchrnul)=0A=
diff --git a/sysdeps/aarch64/strspn.S b/sysdeps/aarch64/strspn.S=0A=
index 42f3b82a944503aa726bc8bdb61105721d0b959a..f70047bec04fe601a942895140e=
7cd98cdb6a522 100644=0A=
--- a/sysdeps/aarch64/strspn.S=0A=
+++ b/sysdeps/aarch64/strspn.S=0A=
@@ -51,7 +51,7 @@=0A=
 #define table_b	v5=0A=
 #define sevens	v7.16b=0A=
 =0A=
-ENTRY(STRSPN)=0A=
+ENTRY (STRSPN)=0A=
 	ldrb	w2, [set]=0A=
 	cbz	w2, L(early)=0A=
 #ifdef USE_AS_STRCSPN=0A=
@@ -128,7 +128,7 @@ L(early):=0A=
 	mov	w1, w2=0A=
 	mov	fp, sp=0A=
 	mov	x19, x0=0A=
-	bl	__strchrnul=0A=
+	bl	HIDDEN_JUMPTARGET (__strchrnul)=0A=
 	sub	x0, x0, x19=0A=
 	ldr	x19, [sp, 16]=0A=
 	ldp	fp, lr, [sp], 32=0A=
@@ -140,7 +140,7 @@ L(early):=0A=
 	mov	w0, 0=0A=
 #endif=0A=
 	ret=0A=
-END(STRSPN)=0A=
+END (STRSPN)=0A=
 =0A=
 #undef set=0A=
-libc_hidden_def(STRSPN)=0A=
+libc_hidden_def (STRSPN)=0A=
=0A=