[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=