--- /dev/null
+/* Zero byte detection, define whether to use stdbit.h
+ 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
+ <http://www.gnu.org/licenses/>. */
+
+/* These macros define whether index_first/index_last macro can use the
+ stdbit.h routines, otherwise fallback that do not call libgcc is used
+ instead.
+
+ An architecture can override it is it uses a generic string routines
+ on process startup and it can not use the libgcc routines for find
+ trailing/leading zeros. */
+#define HAVE_BITOPTS_WORKING 1
#include <limits.h>
#include <endian.h>
#include <string-fza.h>
+#include <string-bitops.h>
+#include <stdbit.h>
-static __always_inline int
-clz (find_t c)
+static __always_inline unsigned int
+ctzb (find_t c)
{
- if (sizeof (find_t) == sizeof (unsigned long))
- return __builtin_clzl (c);
+#if HAVE_BITOPTS_WORKING
+ return stdc_trailing_zeros (c) / CHAR_BIT;
+#else
+ if (sizeof (find_t) <= 4)
+ return (((c & -c) >> 7) * 0x00010203) >> 24;
else
- return __builtin_clzll (c);
+ return (((c & -c) >> 7) * 0x0001020304050607UL) >> 56;
+#endif
}
-static __always_inline int
-ctz (find_t c)
+static __always_inline unsigned int
+clzb (find_t c)
{
- if (sizeof (find_t) == sizeof (unsigned long))
- return __builtin_ctzl (c);
- else
- return __builtin_ctzll (c);
+#if HAVE_BITOPTS_WORKING
+ return stdc_leading_zeros (c) / CHAR_BIT;
+#else
+# if ULONG_MAX == 0xFFFFFFFFUL
+ c |= c >> 8;
+ c |= c >> 16;
+ return ((c >> 7) * 0x30f0f0f0) >> 28;
+# else
+ c |= c >> 8;
+ c |= c >> 16;
+ c |= c >> 32;
+ return ((c >> 7) * 0x70f0f0f0f0f0f0f0UL) >> 60;
+# endif
+#endif
}
/* A subroutine for the index_zero functions. Given a test word C, return
static __always_inline unsigned int
index_first (find_t c)
{
- int r;
+ unsigned int r;
if (__BYTE_ORDER == __LITTLE_ENDIAN)
- r = ctz (c);
+ r = ctzb (c);
else
- r = clz (c);
- return r / CHAR_BIT;
+ r = clzb (c);
+ return r;
}
/* Similarly, but return the (memory order) index of the last byte that is
static __always_inline unsigned int
index_last (find_t c)
{
- int r;
+ unsigned int r;
if (__BYTE_ORDER == __LITTLE_ENDIAN)
- r = clz (c);
+ r = clzb (c);
else
- r = ctz (c);
- return sizeof (find_t) - 1 - (r / CHAR_BIT);
+ r = ctzb (c);
+ return sizeof (find_t) - 1 - r;
}
#endif /* STRING_FZI_H */