riscv: Implement Zbb based strlen and prefer it over the RVV based strlen implementation when Zbb is available
Adhemerval Zanella Netto
adhemerval.zanella@linaro.org
Fri Jun 12 12:33:45 GMT 2026
On 11/06/26 18:30, Jeffrey Law wrote:
>
>
> On 6/11/2026 1:51 PM, Adhemerval Zanella Netto wrote:
>> Did you check the generic implementation? Both 3d6fcf1bd7f462d333c36a14efc0e03f2fdd3f9e
>> and 4c966c078036abe0e36bd86c9eaeb4501e552977 added zbb handling, so building with
>> -march=rv64imafdc_zbb -mabi=lp64d with gcc-16 I see:
> It included the generic, but I didn't build with flags that would have flipped Zbb on.
>
> [ ... ]
>
>> The ASM version seems to have an extra cost of li/sub valid-bytes setup, longer
>> first-word path, and the alignment padding nops. I would guess both would have
>> similar performance profiles.
> Yea, I would expect largely similar.
>
>>
>> And there is another question if adding a zbb sysdep is really a good move here.
>> My understanding is chip produces and distros are moving to RVA23U64/RVA23S64,
>> which implies in zbb and thus you can select it without the need to add an
>> specific implementation.
> While I would *love* to see everyone settle on rva23, but I'm highly skeptical based on my conversations with distros and others.
>
> Jeff
Sigh... then I think it would be better to have a way to build zbb optimized
implementations using the generic code, instead of adding zbb assembly routines.
Unfortunately __attribute__ ((target ("arch=+zbb"))) was only added on gcc-14;
and RISC-V lackk any option to add +zbb for the extensions for a translation unit.
One option would be filter out the compiler used zbb, check if zbb is being used
(by parsing the .attribute form the assembly), and compose a -march with the compiler
default *plus* zbb. I think someone has already suggested it, I don't recall exactly.
Something like the below, and you can go even further and add a config.make to avoid
building and selecting zbb if compiler already default to it (as for building to rva23).
I will let this exercise for the reader ;)
diff --git a/sysdeps/unix/sysv/linux/riscv/configure.ac b/sysdeps/unix/sysv/linux/riscv/configure.ac
index 9c736415f72..f84a1669e4a 100644
--- a/sysdeps/unix/sysv/linux/riscv/configure.ac
+++ b/sysdeps/unix/sysv/linux/riscv/configure.ac
@@ -32,6 +32,28 @@ fi
LIBC_CONFIG_VAR([default-abi], [$libc_cv_riscv_int_abi$libc_cv_riscv_float_abi])
+AC_CACHE_CHECK([for the compiler option to enable the Zbb extension],
+ [libc_cv_riscv_zbb_cflags], [dnl
+libc_cv_riscv_zbb_cflags=
+cat > conftest.c <<EOF
+int foo (void) { return 0; }
+EOF
+libc_cv_riscv_arch=`$CC $CFLAGS $CPPFLAGS -S -o - conftest.c 2>/dev/null \
+ | sed -n 's/.*\.attribute@<:@^,@:>@*,@<:@^"@:>@*"\(rv@<:@^"@:>@*\)".*/\1/p'`
+rm -f conftest*
+if test -n "$libc_cv_riscv_arch"; then
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -march=${libc_cv_riscv_arch}_zbb"
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+#ifndef __riscv_zbb
+# error __riscv_zbb is not defined
+#endif
+]])],
+ [libc_cv_riscv_zbb_cflags="-march=${libc_cv_riscv_arch}_zbb"])
+ CFLAGS="$save_CFLAGS"
+fi])
+LIBC_CONFIG_VAR([riscv-zbb-cflags], [$libc_cv_riscv_zbb_cflags])
+
case $libc_cv_riscv_int_abi$libc_cv_riscv_float_abi-$machine in
lp64-riscv/rv64/*)
LIBC_SLIBDIR_RTLDDIR([lib64/lp64], [lib])
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
index 30d92c1ba92..df7fde2fd8d 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
@@ -31,6 +31,7 @@ sysdep_routines += \
strlen \
strlen-generic \
strlen-vector \
+ strlen-zbb \
strncmp \
strncmp-generic \
strncmp-vector \
@@ -40,6 +41,8 @@ sysdep_routines += \
# sysdep_routines
CFLAGS-memcpy_noalignment.c += -mno-strict-align
+CFLAGS-strlen-zbb.c += $(riscv-zbb-cflags)
+
# Called during static initialization
CFLAGS-memset-generic.c += $(no-stack-protector)
CFLAGS-memcpy-generic.c += $(no-stack-protector)
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 80275785293..e598f958487 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/ifunc-impl-list.c
@@ -28,6 +28,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
bool fast_unaligned = false;
bool rvv_enabled = false;
+ bool zbb_enabled = false;
struct riscv_hwprobe pairs[2] = {
{.key = RISCV_HWPROBE_KEY_CPUPERF_0},
@@ -41,6 +42,9 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
if (pairs[1].value & RISCV_HWPROBE_IMA_V)
rvv_enabled = true;
+
+ if (pairs[1].value & RISCV_HWPROBE_EXT_ZBB)
+ zbb_enabled = true;
}
IFUNC_IMPL (i, name, memcpy,
@@ -68,6 +72,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
IFUNC_IMPL (i, name, strlen,
IFUNC_IMPL_ADD (array, i, strlen, rvv_enabled,
__strlen_vector)
+ IFUNC_IMPL_ADD (array, i, strlen, zbb_enabled,
+ __strlen_zbb)
IFUNC_IMPL_ADD (array, i, strlen, 1, __strlen_generic))
IFUNC_IMPL (i, name, strcmp,
diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/strlen.c b/sysdeps/unix/sysv/linux/riscv/multiarch/strlen.c
index 9975286b85a..5ed08ac37e1 100644
--- a/sysdeps/unix/sysv/linux/riscv/multiarch/strlen.c
+++ b/sysdeps/unix/sysv/linux/riscv/multiarch/strlen.c
@@ -32,14 +32,19 @@ extern __typeof (__redirect_strlen) __libc_strlen;
extern __typeof (__redirect_strlen) __strlen_generic attribute_hidden;
extern __typeof (__redirect_strlen) __strlen_vector attribute_hidden;
+extern __typeof (__redirect_strlen) __strlen_zbb 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;
+ if (__riscv_hwprobe_one (hwprobe_func, RISCV_HWPROBE_KEY_IMA_EXT_0, &v) == 0)
+ {
+ if (v & RISCV_HWPROBE_IMA_V)
+ return __strlen_vector;
+ if (v & RISCV_HWPROBE_EXT_ZBB)
+ return __strlen_zbb;
+ }
return __strlen_generic;
}
More information about the Libc-alpha
mailing list