1 /* strchrnul (str, ch) -- Return pointer to first occurrence of CH in STR
4 Copyright (C) 1999-2023 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/>. */
22 #include "asm-syntax.h"
26 /* Save the callee-saved registers we use. */
27 movel R(d2),MEM_PREDEC(sp)
28 cfi_adjust_cfa_offset (4)
29 movel R(d3),MEM_PREDEC(sp)
30 cfi_adjust_cfa_offset (4)
31 cfi_rel_offset (R(d2), 4)
32 cfi_rel_offset (R(d3), 0)
34 /* Get string pointer and character. */
35 movel MEM_DISP(sp,12),R(a0)
36 moveb MEM_DISP(sp,19),R(d0)
38 /* Distribute the character to all bytes of a longword. */
46 /* First search for the character one byte at a time until the
47 pointer is aligned to a longword boundary. */
89 /* Load the magic bits. Unlike the generic implementation we can
90 use the carry bit as the fourth hole. */
91 movel #0xfefefeff,R(d3)
93 /* We exit the loop if adding MAGIC_BITS to LONGWORD fails to
94 change any of the hole bits of LONGWORD.
96 1) Is this safe? Will it catch all the zero bytes?
97 Suppose there is a byte with all zeros. Any carry bits
98 propagating from its left will fall into the hole at its
99 least significant bit and stop. Since there will be no
100 carry from its most significant bit, the LSB of the
101 byte to the left will be unchanged, and the zero will be
104 2) Is this worthwhile? Will it ignore everything except
105 zero bytes? Suppose every byte of LONGWORD has a bit set
106 somewhere. There will be a carry into bit 8. If bit 8
107 is set, this will carry into bit 16. If bit 8 is clear,
108 one of bits 9-15 must be set, so there will be a carry
109 into bit 16. Similarly, there will be a carry into bit
110 24. If one of bits 24-31 is set, there will be a carry
111 into bit 32 (=carry flag), so all of the hole bits will
114 3) But wait! Aren't we looking for C, not zero?
115 Good point. So what we do is XOR LONGWORD with a longword,
116 each of whose bytes is C. This turns each byte that is C
120 /* Get the longword in question. */
121 movel MEM_POSTINC(a0),R(d1)
122 /* XOR with the byte we search for. */
125 /* Add the magic value. We get carry bits reported for each byte
130 /* Check the fourth carry bit before it is clobbered by the next
131 XOR. If it is not set we have a hit. */
134 /* We are only interested in carry bits that change due to the
135 previous add, so remove original bits. */
138 /* Now test for the other three overflow bits.
139 Set all non-carry bits. */
141 /* Add 1 to get zero if all carry bits were set. */
144 /* If we don't get zero then at least one byte of the word equals
148 /* Next look for a NUL byte.
149 Restore original longword without reload. */
151 /* Add the magic value. We get carry bits reported for each byte
156 /* Check the fourth carry bit before it is clobbered by the next
157 XOR. If it is not set we have a hit. */
160 /* We are only interested in carry bits that change due to the
161 previous add, so remove original bits. */
164 /* Now test for the other three overflow bits.
165 Set all non-carry bits. */
167 /* Add 1 to get zero if all carry bits were set. */
170 /* If we don't get zero then at least one byte of the word was
171 NUL. Otherwise continue with the next longword. */
174 /* Get the longword in question. */
175 movel MEM_POSTINC(a0),R(d1)
176 /* XOR with the byte we search for. */
179 /* Add the magic value. We get carry bits reported for each byte
184 /* Check the fourth carry bit before it is clobbered by the next
185 XOR. If it is not set we have a hit. */
188 /* We are only interested in carry bits that change due to the
189 previous add, so remove original bits */
192 /* Now test for the other three overflow bits.
193 Set all non-carry bits. */
195 /* Add 1 to get zero if all carry bits were set. */
198 /* If we don't get zero then at least one byte of the word equals
202 /* Next look for a NUL byte.
203 Restore original longword without reload. */
205 /* Add the magic value. We get carry bits reported for each byte
210 /* Check the fourth carry bit before it is clobbered by the next
211 XOR. If it is not set we have a hit. */
214 /* We are only interested in carry bits that change due to the
215 previous add, so remove original bits */
218 /* Now test for the other three overflow bits.
219 Set all non-carry bits. */
221 /* Add 1 to get zero if all carry bits were set. */
224 /* If we don't get zero then at least one byte of the word was
225 NUL. Otherwise continue with the next longword. */
229 /* We have a hit. Check to see which byte it was. First
230 compensate for the autoincrement in the loop. */
254 /* Otherwise the fourth byte must equal C or be NUL. */
257 movel MEM_POSTINC(sp),R(d3)
258 cfi_adjust_cfa_offset (-4)
260 movel MEM_POSTINC(sp),R(d2)
261 cfi_adjust_cfa_offset (-4)
266 weak_alias (__strchrnul, strchrnul)