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-2021 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
266weak_alias (__strchrnul, strchrnul)
267