mirror of
git://sourceware.org/git/glibc.git
synced 2026-09-08 23:58:31 +08:00
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. Return the difference unreduced wherever index_first () and index_last () come from the generic string-fzi.h, which uses stdc_trailing_zeros () and stdc_leading_zeros () and so only needs to know which byte holds the first or the last set bit. That covers armv6t2, powerpc and riscv with the bitmap extensions, as well as the generic implementation. Only the generic one tests HAVE_BITOPTS_WORKING, since its fallback ctzb () and clzb () isolate a single bit and expect it at 0x80; the target masks are already incompatible with that fallback and cannot use it either way. riscv without the bitmap extensions takes its string-fza.h from the generic implementation while defining its own index_first () and index_last (), which tested bit 7 of each byte. Test the whole byte instead, so that they accept the unreduced difference. alpha keeps a reduced form, its find_t being a cmpbge mask of one bit per byte throughout. Reviewed-by: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
76 lines
2.4 KiB
C
76 lines
2.4 KiB
C
/* Zero byte detection; basics. ARM version.
|
|
Copyright (C) 2023-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/>. */
|
|
|
|
#ifndef _STRING_FZA_H
|
|
#define _STRING_FZA_H 1
|
|
|
|
#include <string-misc.h>
|
|
#include <string-optype.h>
|
|
#include <arm_acle.h>
|
|
|
|
/* The functions return a byte mask. */
|
|
typedef op_t find_t;
|
|
|
|
/* This function returns at least one bit set within every byte
|
|
of X that is zero. */
|
|
static __always_inline find_t
|
|
find_zero_all (op_t x)
|
|
{
|
|
/* Use unsigned saturated subtraction from 1 in each byte.
|
|
That leaves 1 for every byte that was zero. */
|
|
return __uqsub8 (repeat_bytes (0x01), x);
|
|
}
|
|
|
|
/* Identify bytes that are equal between X1 and X2. */
|
|
static __always_inline find_t
|
|
find_eq_all (op_t x1, op_t x2)
|
|
{
|
|
return find_zero_all (x1 ^ x2);
|
|
}
|
|
|
|
/* Identify zero bytes in X1 or equality between X1 and X2. */
|
|
static __always_inline find_t
|
|
find_zero_eq_all (op_t x1, op_t x2)
|
|
{
|
|
return find_zero_all (x1) | find_zero_all (x1 ^ x2);
|
|
}
|
|
|
|
/* Identify zero bytes in X1 or inequality between X1 and 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);
|
|
}
|
|
|
|
/* Identify bytes that are not equal between X1 and X2. */
|
|
static __always_inline find_t
|
|
find_ne_all (op_t x1, op_t x2)
|
|
{
|
|
/* The difference need not be reduced; see the generic string-fza.h. */
|
|
return 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
|
|
#define find_zero_eq_low find_zero_eq_all
|
|
|
|
#endif /* _STRING_FZA_H */
|