1/* strchrnul (str, ch) -- Return pointer to first occurrence of CH in STR
2 or the final NUL byte.
3 For Motorola 68000.
4 Copyright (C) 1999-2024 Free Software Foundation, Inc.
5 This file is part of the GNU C Library.
6
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.
11
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.
16
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/>. */
20
21#include <sysdep.h>
22#include "asm-syntax.h"
23
24 TEXT
25ENTRY(__strchrnul)
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)
33
34 /* Get string pointer and character. */
35 movel MEM_DISP(sp,12),R(a0)
36 moveb MEM_DISP(sp,19),R(d0)
37
38 /* Distribute the character to all bytes of a longword. */
39 movel R(d0),R(d1)
40 lsll #8,R(d1)
41 moveb R(d0),R(d1)
42 movel R(d1),R(d0)
43 swap R(d0)
44 movew R(d1),R(d0)
45
46 /* First search for the character one byte at a time until the
47 pointer is aligned to a longword boundary. */
48 movel R(a0),R(d1)
49#ifdef __mcoldfire__
50 andl #3,R(d1)
51#else
52 andw #3,R(d1)
53#endif
54 beq L(L1)
55 moveb MEM(a0),R(d2)
56 cmpb R(d0),R(d2)
57 beq L(L9)
58 tstb R(d2)
59 beq L(L9)
60 addql #1,R(a0)
61
62#ifdef __mcoldfire__
63 subql #3,R(d1)
64#else
65 subqw #3,R(d1)
66#endif
67 beq L(L1)
68 moveb MEM(a0),R(d2)
69 cmpb R(d0),R(d2)
70 beq L(L9)
71 tstb R(d2)
72 beq L(L9)
73 addql #1,R(a0)
74
75#ifdef __mcoldfire__
76 addql #1,R(d1)
77#else
78 addqw #1,R(d1)
79#endif
80 beq L(L1)
81 moveb MEM(a0),R(d2)
82 cmpb R(d0),R(d2)
83 beq L(L9)
84 tstb R(d2)
85 beq L(L9)
86 addql #1,R(a0)
87
88L(L1:)
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)
92
93 /* We exit the loop if adding MAGIC_BITS to LONGWORD fails to
94 change any of the hole bits of LONGWORD.
95
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
102 detected.
103
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
112 be changed.
113
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
117 into a zero. */
118
119L(L2:)
120 /* Get the longword in question. */
121 movel MEM_POSTINC(a0),R(d1)
122 /* XOR with the byte we search for. */
123 eorl R(d0),R(d1)
124
125 /* Add the magic value. We get carry bits reported for each byte
126 which is not C. */
127 movel R(d3),R(d2)
128 addl R(d1),R(d2)
129
130 /* Check the fourth carry bit before it is clobbered by the next
131 XOR. If it is not set we have a hit. */
132 bcc L(L8)
133
134 /* We are only interested in carry bits that change due to the
135 previous add, so remove original bits. */
136 eorl R(d1),R(d2)
137
138 /* Now test for the other three overflow bits.
139 Set all non-carry bits. */
140 orl R(d3),R(d2)
141 /* Add 1 to get zero if all carry bits were set. */
142 addql #1,R(d2)
143
144 /* If we don't get zero then at least one byte of the word equals
145 C. */
146 bne L(L8)
147
148 /* Next look for a NUL byte.
149 Restore original longword without reload. */
150 eorl R(d0),R(d1)
151 /* Add the magic value. We get carry bits reported for each byte
152 which is not NUL. */
153 movel R(d3),R(d2)
154 addl R(d1),R(d2)
155
156 /* Check the fourth carry bit before it is clobbered by the next
157 XOR. If it is not set we have a hit. */
158 bcc L(L8)
159
160 /* We are only interested in carry bits that change due to the
161 previous add, so remove original bits. */
162 eorl R(d1),R(d2)
163
164 /* Now test for the other three overflow bits.
165 Set all non-carry bits. */
166 orl R(d3),R(d2)
167 /* Add 1 to get zero if all carry bits were set. */
168 addql #1,R(d2)
169
170 /* If we don't get zero then at least one byte of the word was
171 NUL. Otherwise continue with the next longword. */
172 bne L(L8)
173
174 /* Get the longword in question. */
175 movel MEM_POSTINC(a0),R(d1)
176 /* XOR with the byte we search for. */
177 eorl R(d0),R(d1)
178
179 /* Add the magic value. We get carry bits reported for each byte
180 which is not C. */
181 movel R(d3),R(d2)
182 addl R(d1),R(d2)
183
184 /* Check the fourth carry bit before it is clobbered by the next
185 XOR. If it is not set we have a hit. */
186 bcc L(L8)
187
188 /* We are only interested in carry bits that change due to the
189 previous add, so remove original bits */
190 eorl R(d1),R(d2)
191
192 /* Now test for the other three overflow bits.
193 Set all non-carry bits. */
194 orl R(d3),R(d2)
195 /* Add 1 to get zero if all carry bits were set. */
196 addql #1,R(d2)
197
198 /* If we don't get zero then at least one byte of the word equals
199 C. */
200 bne L(L8)
201
202 /* Next look for a NUL byte.
203 Restore original longword without reload. */
204 eorl R(d0),R(d1)
205 /* Add the magic value. We get carry bits reported for each byte
206 which is not NUL. */
207 movel R(d3),R(d2)
208 addl R(d1),R(d2)
209
210 /* Check the fourth carry bit before it is clobbered by the next
211 XOR. If it is not set we have a hit. */
212 bcc L(L8)
213
214 /* We are only interested in carry bits that change due to the
215 previous add, so remove original bits */
216 eorl R(d1),R(d2)
217
218 /* Now test for the other three overflow bits.
219 Set all non-carry bits. */
220 orl R(d3),R(d2)
221 /* Add 1 to get zero if all carry bits were set. */
222 addql #1,R(d2)
223
224 /* If we don't get zero then at least one byte of the word was
225 NUL. Otherwise continue with the next longword. */
226 beq L(L2)
227
228L(L8:)
229 /* We have a hit. Check to see which byte it was. First
230 compensate for the autoincrement in the loop. */
231 subql #4,R(a0)
232
233 moveb MEM(a0),R(d1)
234 cmpb R(d0),R(d1)
235 beq L(L9)
236 tstb R(d1)
237 beq L(L9)
238 addql #1,R(a0)
239
240 moveb MEM(a0),R(d1)
241 cmpb R(d0),R(d1)
242 beq L(L9)
243 tstb R(d1)
244 beq L(L9)
245 addql #1,R(a0)
246
247 moveb MEM(a0),R(d1)
248 cmpb R(d0),R(d1)
249 beq L(L9)
250 tstb R(d1)
251 beq L(L9)
252 addql #1,R(a0)
253
254 /* Otherwise the fourth byte must equal C or be NUL. */
255L(L9:)
256 movel R(a0),R(d0)
257 movel MEM_POSTINC(sp),R(d3)
258 cfi_adjust_cfa_offset (-4)
259 cfi_restore (R(d3))
260 movel MEM_POSTINC(sp),R(d2)
261 cfi_adjust_cfa_offset (-4)
262 cfi_restore (R(d2))
263 rts
264END(__strchrnul)
265
266libc_hidden_def (__strchrnul)
267weak_alias (__strchrnul, strchrnul)
268

source code of glibc/sysdeps/m68k/strchrnul.S