[PATCH v2 1/3] string: add find_ne_all to string-fza.h
Matt Turner <[email protected]>
| Newsgroups | gmane.comp.lib.glibc.alpha |
|---|---|
| Message-ID | <[email protected]> |
find_zero_ne_all () searches for a zero byte in X1 or a byte that differs
between X1 and X2. A caller that knows X2 contains no NUL byte does not
need the zero test, since a NUL byte in X1 already differs from every
byte of X2.
Add find_ne_all (), which searches for inequality alone, to the generic
implementation and to each target that provides its own string-fza.h.
Dropping the zero test makes it cheaper than find_zero_ne_all () on every
target.
The generic version returns the difference unreduced when
HAVE_BITOPTS_WORKING, since index_first () and index_last () then use
stdc_trailing_zeros () and stdc_leading_zeros (), which only need to know
which byte holds the first or the last set bit. The fallback ctzb () and
clzb () multiply a mask that must hold exactly one bit per byte, so they
keep the reduced form. armv6t2 and powerpc use the generic index_first ()
and index_last (), so they follow the same rule.
riscv is the one target that mixes the two: without the bitmap extensions
its string-fza.h falls back to the generic one while its string-fzi.h
defines an index_first () that tests bit 7 of each byte, which the
unreduced difference would defeat. Give it a string-bitops.h that clears
HAVE_BITOPTS_WORKING in that configuration, where the stdbit.h routines
are unused anyway. alpha needs no such treatment; its find_t is a cmpbge
mask of one bit per byte throughout.
---
sysdeps/alpha/string-fza.h | 7 +++++++
sysdeps/arm/armv6t2/string-fza.h | 14 ++++++++++++++
sysdeps/generic/string-fza.h | 20 ++++++++++++++++++++
sysdeps/powerpc/string-fza.h | 14 ++++++++++++++
sysdeps/riscv/string-bitops.h | 28 ++++++++++++++++++++++++++++
sysdeps/riscv/string-fza.h | 7 +++++++
6 files changed, 90 insertions(+)
create mode 100644 sysdeps/riscv/string-bitops.h
diff --git ./sysdeps/alpha/string-fza.h ./sysdeps/alpha/string-fza.h
index ae5d890a7e..8178e75178 100644
--- ./sysdeps/alpha/string-fza.h
+++ ./sysdeps/alpha/string-fza.h
@@ -52,6 +52,13 @@ find_zero_ne_all (op_t x1, op_t x2)
return find_zero_all (x1) | (find_zero_all (x1 ^ x2) ^ 0xff);
}
+/* Identify bytes that are not equal between X1 and X2. */
+static __always_inline find_t
+find_ne_all (op_t x1, op_t x2)
+{
+ return find_zero_all (x1 ^ x2) ^ 0xff;
+}
+
/* Define the "inexact" versions in terms of the exact versions. */
#define find_zero_low find_zero_all
#define find_eq_low find_eq_all
diff --git ./sysdeps/arm/armv6t2/string-fza.h ./sysdeps/arm/armv6t2/string-fza.h
index 1eab43fdc3..0ae4c79f7d 100644
--- ./sysdeps/arm/armv6t2/string-fza.h
+++ ./sysdeps/arm/armv6t2/string-fza.h
@@ -19,6 +19,7 @@
#ifndef _STRING_FZA_H
#define _STRING_FZA_H 1
+#include <string-bitops.h>
#include <string-misc.h>
#include <string-optype.h>
@@ -61,6 +62,19 @@ find_zero_ne_all (op_t x1, op_t x2)
return find_zero_all (x1) | (find_zero_all (x1 ^ x2) ^ ones);
}
+/* Identify bytes that are not equal between X1 and X2. */
+static __always_inline find_t
+find_ne_all (op_t x1, op_t x2)
+{
+#if HAVE_BITOPTS_WORKING
+ /* The difference need not be reduced; see the generic string-fza.h. */
+ return x1 ^ x2;
+#else
+ op_t ones = repeat_bytes (0x01);
+ return find_zero_all (x1 ^ x2) ^ ones;
+#endif
+}
+
/* Define the "inexact" versions in terms of the exact versions. */
#define find_zero_low find_zero_all
#define find_eq_low find_eq_all
diff --git ./sysdeps/generic/string-fza.h ./sysdeps/generic/string-fza.h
index 362c7a8fe6..3296b09748 100644
--- ./sysdeps/generic/string-fza.h
+++ ./sysdeps/generic/string-fza.h
@@ -19,6 +19,7 @@
#ifndef _STRING_FZA_H
#define _STRING_FZA_H 1
+#include <string-bitops.h>
#include <string-misc.h>
#include <string-optype.h>
@@ -95,4 +96,23 @@ find_zero_ne_all (op_t x1, op_t x2)
return (ne2 | ~nz1) & ~m;
}
+/* With similar caveats, identify bytes that are not equal between X1
+ and X2. */
+static __always_inline find_t
+find_ne_all (op_t x1, op_t x2)
+{
+#if HAVE_BITOPTS_WORKING
+ /* index_first and index_last only need to know which byte holds the first
+ or the last set bit, so the difference does not have to be reduced to
+ one bit per byte. The fallback ctzb and clzb do require the reduced
+ form, as does any target whose own index_first tests a fixed bit of
+ each byte; both clear HAVE_BITOPTS_WORKING. */
+ return x1 ^ x2;
+#else
+ op_t m = repeat_bytes (0x7f);
+ op_t ne = x1 ^ x2;
+ return (((ne & m) + m) | ne) & ~m;
+#endif
+}
+
#endif /* _STRING_FZA_H */
diff --git ./sysdeps/powerpc/string-fza.h ./sysdeps/powerpc/string-fza.h
index 43aa0db952..b09852ef94 100644
--- ./sysdeps/powerpc/string-fza.h
+++ ./sysdeps/powerpc/string-fza.h
@@ -21,6 +21,7 @@
/* PowerISA 2.05 (POWER6) provides cmpb instruction. */
#ifdef _ARCH_PWR6
+# include <string-bitops.h>
# include <string-misc.h>
# include <string-optype.h>
@@ -60,6 +61,19 @@ find_zero_ne_all (op_t x1, op_t x2)
return find_zero_all (x1) | ~find_eq_all (x1, x2);
}
+/* Identify bytes that are not equal between X1 and X2. */
+
+static __always_inline find_t
+find_ne_all (op_t x1, op_t x2)
+{
+#if HAVE_BITOPTS_WORKING
+ /* The difference need not be reduced; see the generic string-fza.h. */
+ return x1 ^ x2;
+#else
+ return ~find_eq_all (x1, x2);
+#endif
+}
+
/* Define the "inexact" versions in terms of the exact versions. */
# define find_zero_low find_zero_all
# define find_eq_low find_eq_all
diff --git ./sysdeps/riscv/string-bitops.h ./sysdeps/riscv/string-bitops.h
new file mode 100644
index 0000000000..b941d69288
--- /dev/null
+++ ./sysdeps/riscv/string-bitops.h
@@ -0,0 +1,28 @@
+/* Zero byte detection, define whether to use stdbit.h. RISC-V version.
+ 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/>. */
+
+/* Without the bitmap extensions string-fzi.h defines its own index_first
+ and index_last, which test bit 7 of each byte, and the stdbit.h routines
+ are not used at all. Clear this so that the generic string-fza.h, which
+ string-fza.h falls back to in that case, reduces its masks to one bit per
+ byte. */
+#if defined __riscv_zbb || defined __riscv_xtheadbb
+# define HAVE_BITOPTS_WORKING 1
+#else
+# define HAVE_BITOPTS_WORKING 0
+#endif
diff --git ./sysdeps/riscv/string-fza.h ./sysdeps/riscv/string-fza.h
index 7df4dfe415..fa2ddc3c46 100644
--- ./sysdeps/riscv/string-fza.h
+++ ./sysdeps/riscv/string-fza.h
@@ -63,6 +63,13 @@ find_zero_ne_all (op_t x1, op_t x2)
return find_zero_all (x1) | ~find_eq_all (x1, x2);
}
+/* Identify bytes that are not equal between X1 and X2. */
+static __always_inline find_t
+find_ne_all (op_t x1, op_t x2)
+{
+ return ~find_eq_all (x1, x2);
+}
+
/* Define the "inexact" versions in terms of the exact versions. */
# define find_zero_low find_zero_all
# define find_eq_low find_eq_all
--
2.54.0