[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.