1 /* memchr - find a character in a memory zone using base integer registers
3 Copyright (C) 2018 Free Software Foundation, Inc.
5 This file is part of the GNU C Library.
7 The GNU C Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 The GNU C Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with the GNU C Library. If not, see
19 <https://www.gnu.org/licenses/>. */
26 * Use base integer registers.
30 # define MEMCHR __memchr_nosimd
33 /* Arguments and results. */
61 #define REP8_01 0x0101010101010101
62 #define REP8_7f 0x7f7f7f7f7f7f7f7f
65 ENTRY_ALIGN (MEMCHR, 6)
70 /* Do not dereference srcin if no bytes to compare. */
71 cbz cntin, L(none_chr)
73 /* Start address is 16-byte aligned or not? */
78 and repchr, chrin, 255
79 /* Generate a qword integer as |c|c|c|c|c|c|c|c|. */
80 mul repchr, repchr, zeroones
82 add srcend, srcin, cntin
84 * srcend16 is address of the block following the last block.
86 * [A block is 16-byte aligned and sized.]
88 add srcend16, srcend, 15
89 bic srcend16, srcend16, 15
93 /* Load the first block containing start address. */
94 ldp data1, data2, [src], 16
103 /* Start address is in the first or the second qword? */
107 * Transform any byte in the block to zero using XOR operation,
108 * if that byte equals the char to search. In this way, searching
109 * the char becomes detecting zero in the resulting two qwords.
111 eor data1, data1, repchr
112 eor data2, data2, repchr
115 * Set those unused bytes(before start address) to 0xff, so
116 * that they will not hit any zero detection.
118 orn tmp1, data1, tmp3
119 orn tmp2, data2, tmp3
121 csinv data1, tmp1, xzr, eq
122 csel data2, data2, tmp2, eq
125 * When the first and last block are the same, there are two cases:
126 * o. Memory range to search is just in one block.
127 * ( start address - end address) < 0
129 * o. Memory range is so large that end address wrap-around.
130 * ( start address - end address) > 0
133 ccmp src, srcend16, 0, mi
139 ldp data1, data2, [src], 16
141 subs anymore, src, srcend16
144 * Transform any byte in the block to zero using XOR operation,
145 * if that byte equals the char to search.
147 eor data1, data1, repchr
148 eor data2, data2, repchr
152 * Use the following integer test to find out if any byte in a
153 * qword is zero. If do not contain zero-valued byte, test result
156 * (qword - 0x0101010101010101) & ~(qword) & 0x8080808080808080
158 * (qword - 0x0101010101010101) & ~(qword | 0x7f7f7f7f7f7f7f7f)
161 sub tmp1, data1, zeroones
162 sub tmp2, data2, zeroones
164 orr tmp3, data1, REP8_7f
165 orr tmp4, data2, REP8_7f
167 bic has_chr1, tmp1, tmp3
168 bic has_chr2, tmp2, tmp4
170 orr tmp1, has_chr1, has_chr2
180 rev has_chr1, has_chr1
184 1: cbz has_chr2, L(none_chr)
189 rev has_chr1, has_chr2
195 * For big-endian, can not directly use has_chr1/has_chr2 because
196 * two qwords has been reversed after loading from memory.
197 * Thus, have to perform char detection on two qwords again, which
198 * should be byte-swapped this time.
200 sub tmp1, data1, zeroones
201 orr tmp3, data1, REP8_7f
202 bic has_chr1, tmp1, tmp3
203 rev has_chr1, has_chr1
207 * If the specified char is found in a qword, the corresponding
208 * byte of in has_chr has value of 1, while this is only true for
209 * the first occurrence, not other occurrences.
213 add result, result, tmp1, lsr 3
214 ccmp result, srcend, 8, eq /* NZCV = 8000 */
215 csel result, result, xzr, mi
223 libc_hidden_builtin_def (MEMCHR)