[PATCH v3 2/3] string: simplify find_zero_ne_all

Matt Turner mattst88@gmail.com
Fri Aug 14 16:11:34 GMT 2026


Build the mask from the raw difference, as find_ne_all () now does.
index_first () and index_last () only need to know which byte holds the
first or the last set bit, and find_zero_all () marks only the bytes that
were zero, so each term of the or marks only its own bytes.

That drops one of the two carry chains from strcmp () and strncmp () on
targets using the generic string-fza.h, and one of the two uqsub8 on
armv6t2.  As in find_ne_all (), only the generic implementation tests
HAVE_BITOPTS_WORKING.

powerpc keeps its existing form, where orc folds the complement of cmpb
into the or and the raw difference saves nothing.  alpha and riscv do not
reach this code with the generic index_first ().
---
 sysdeps/arm/armv6t2/string-fza.h | 6 +++---
 sysdeps/generic/string-fza.h     | 7 +++++++
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git ./sysdeps/arm/armv6t2/string-fza.h ./sysdeps/arm/armv6t2/string-fza.h
index a7ab4c9056..bc37278414 100644
--- ./sysdeps/arm/armv6t2/string-fza.h
+++ ./sysdeps/arm/armv6t2/string-fza.h
@@ -56,9 +56,9 @@ find_zero_eq_all (op_t x1, op_t x2)
 static __always_inline find_t
 find_zero_ne_all (op_t x1, op_t x2)
 {
-  /* Make use of the fact that we'll already have ONES in a register.  */
-  op_t ones = repeat_bytes (0x01);
-  return find_zero_all (x1) | (find_zero_all (x1 ^ x2) ^ ones);
+  /* As in find_ne_all; find_zero_all () sets only 0x01 in a byte that was
+     zero, so each term of the or marks only its own bytes.  */
+  return (x1 ^ x2) | find_zero_all (x1);
 }
 
 /* Identify bytes that are not equal between X1 and X2.  */
diff --git ./sysdeps/generic/string-fza.h ./sysdeps/generic/string-fza.h
index e569d0aa41..d9af795bbf 100644
--- ./sysdeps/generic/string-fza.h
+++ ./sysdeps/generic/string-fza.h
@@ -89,11 +89,18 @@ find_zero_eq_all (op_t x1, op_t x2)
 static __always_inline find_t
 find_zero_ne_all (op_t x1, op_t x2)
 {
+#if HAVE_BITOPTS_WORKING
+  /* As in find_ne_all, the difference does not have to be reduced to one
+     bit per byte.  find_zero_all () sets only 0x80 in a byte that was
+     zero, so each term marks only its own bytes.  */
+  return (x1 ^ x2) | find_zero_all (x1);
+#else
   op_t m = repeat_bytes (0x7f);
   op_t eq = x1 ^ x2;
   op_t nz1 = ((x1 & m) + m) | x1;
   op_t ne2 = ((eq & m) + m) | eq;
   return (ne2 | ~nz1) & ~m;
+#endif
 }
 
 /* With similar caveats, identify bytes that are not equal between X1
-- 
2.54.0



More information about the Libc-alpha mailing list