]> git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/m68k/strchrnul.S
Update to LGPL v2.1.
[thirdparty/glibc.git] / sysdeps / m68k / strchrnul.S
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 Free Software Foundation, Inc.
5 This file is part of the GNU C Library.
6 Contributed by Andreas Schwab <schwab@gnu.org>.
7
8 The GNU C Library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version.
12
13 The GNU C Library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with the GNU C Library; if not, write to the Free
20 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 02111-1307 USA. */
22
23 #include <sysdep.h>
24 #include "asm-syntax.h"
25
26 TEXT
27 ENTRY(__strchrnul)
28 /* Save the callee-saved registers we use. */
29 movel R(d2),MEM_PREDEC(sp)
30 movel R(d3),MEM_PREDEC(sp)
31
32 /* Get string pointer and character. */
33 movel MEM_DISP(sp,12),R(a0)
34 moveb MEM_DISP(sp,19),R(d0)
35
36 /* Distribute the character to all bytes of a longword. */
37 movel R(d0),R(d1)
38 lsll #8,R(d1)
39 moveb R(d0),R(d1)
40 movel R(d1),R(d0)
41 swap R(d0)
42 movew R(d1),R(d0)
43
44 /* First search for the character one byte at a time until the
45 pointer is aligned to a longword boundary. */
46 movel R(a0),R(d1)
47 andw #3,R(d1)
48 beq L(L1)
49 moveb MEM(a0),R(d1)
50 cmpb R(d0),R(d1)
51 beq L(L9)
52 tstb R(d1)
53 beq L(L9)
54 addql #1,R(a0)
55
56 movel R(a0),R(d1)
57 andw #3,R(d1)
58 beq L(L1)
59 moveb MEM(a0),R(d1)
60 cmpb R(d0),R(d1)
61 beq L(L9)
62 tstb R(d1)
63 beq L(L9)
64 addql #1,R(a0)
65
66 movel R(a0),R(d1)
67 andw #3,R(d1)
68 beq L(L1)
69 moveb MEM(a0),R(d1)
70 cmpb R(d0),R(d1)
71 beq L(L9)
72 tstb R(d1)
73 beq L(L9)
74 addql #1,R(a0)
75
76 L(L1:)
77 /* Load the magic bits. Unlike the generic implementation we can
78 use the carry bit as the fourth hole. */
79 movel #0xfefefeff,R(d3)
80
81 /* We exit the loop if adding MAGIC_BITS to LONGWORD fails to
82 change any of the hole bits of LONGWORD.
83
84 1) Is this safe? Will it catch all the zero bytes?
85 Suppose there is a byte with all zeros. Any carry bits
86 propagating from its left will fall into the hole at its
87 least significant bit and stop. Since there will be no
88 carry from its most significant bit, the LSB of the
89 byte to the left will be unchanged, and the zero will be
90 detected.
91
92 2) Is this worthwhile? Will it ignore everything except
93 zero bytes? Suppose every byte of LONGWORD has a bit set
94 somewhere. There will be a carry into bit 8. If bit 8
95 is set, this will carry into bit 16. If bit 8 is clear,
96 one of bits 9-15 must be set, so there will be a carry
97 into bit 16. Similarly, there will be a carry into bit
98 24. If one of bits 24-31 is set, there will be a carry
99 into bit 32 (=carry flag), so all of the hole bits will
100 be changed.
101
102 3) But wait! Aren't we looking for C, not zero?
103 Good point. So what we do is XOR LONGWORD with a longword,
104 each of whose bytes is C. This turns each byte that is C
105 into a zero. */
106
107 L(L2:)
108 /* Get the longword in question. */
109 movel MEM_POSTINC(a0),R(d1)
110 /* XOR with the byte we search for. */
111 eorl R(d0),R(d1)
112
113 /* Add the magic value. We get carry bits reported for each byte
114 which is not C. */
115 movel R(d3),R(d2)
116 addl R(d1),R(d2)
117
118 /* Check the fourth carry bit before it is clobbered by the next
119 XOR. If it is not set we have a hit. */
120 bcc L(L8)
121
122 /* We are only interested in carry bits that change due to the
123 previous add, so remove original bits. */
124 eorl R(d1),R(d2)
125
126 /* Now test for the other three overflow bits.
127 Set all non-carry bits. */
128 orl R(d3),R(d2)
129 /* Add 1 to get zero if all carry bits were set. */
130 addql #1,R(d2)
131
132 /* If we don't get zero then at least one byte of the word equals
133 C. */
134 bne L(L8)
135
136 /* Next look for a NUL byte.
137 Restore original longword without reload. */
138 eorl R(d0),R(d1)
139 /* Add the magic value. We get carry bits reported for each byte
140 which is not NUL. */
141 movel R(d3),R(d2)
142 addl R(d1),R(d2)
143
144 /* Check the fourth carry bit before it is clobbered by the next
145 XOR. If it is not set we have a hit. */
146 bcc L(L8)
147
148 /* We are only interested in carry bits that change due to the
149 previous add, so remove original bits. */
150 eorl R(d1),R(d2)
151
152 /* Now test for the other three overflow bits.
153 Set all non-carry bits. */
154 orl R(d3),R(d2)
155 /* Add 1 to get zero if all carry bits were set. */
156 addql #1,R(d2)
157
158 /* If we don't get zero then at least one byte of the word was
159 NUL. Otherwise continue with the next longword. */
160 bne L(L8)
161
162 /* Get the longword in question. */
163 movel MEM_POSTINC(a0),R(d1)
164 /* XOR with the byte we search for. */
165 eorl R(d0),R(d1)
166
167 /* Add the magic value. We get carry bits reported for each byte
168 which is not C. */
169 movel R(d3),R(d2)
170 addl R(d1),R(d2)
171
172 /* Check the fourth carry bit before it is clobbered by the next
173 XOR. If it is not set we have a hit. */
174 bcc L(L8)
175
176 /* We are only interested in carry bits that change due to the
177 previous add, so remove original bits */
178 eorl R(d1),R(d2)
179
180 /* Now test for the other three overflow bits.
181 Set all non-carry bits. */
182 orl R(d3),R(d2)
183 /* Add 1 to get zero if all carry bits were set. */
184 addql #1,R(d2)
185
186 /* If we don't get zero then at least one byte of the word equals
187 C. */
188 bne L(L8)
189
190 /* Next look for a NUL byte.
191 Restore original longword without reload. */
192 eorl R(d0),R(d1)
193 /* Add the magic value. We get carry bits reported for each byte
194 which is not NUL. */
195 movel R(d3),R(d2)
196 addl R(d1),R(d2)
197
198 /* Check the fourth carry bit before it is clobbered by the next
199 XOR. If it is not set we have a hit. */
200 bcc L(L8)
201
202 /* We are only interested in carry bits that change due to the
203 previous add, so remove original bits */
204 eorl R(d1),R(d2)
205
206 /* Now test for the other three overflow bits.
207 Set all non-carry bits. */
208 orl R(d3),R(d2)
209 /* Add 1 to get zero if all carry bits were set. */
210 addql #1,R(d2)
211
212 /* If we don't get zero then at least one byte of the word was
213 NUL. Otherwise continue with the next longword. */
214 beq L(L2)
215
216 L(L8:)
217 /* We have a hit. Check to see which byte it was. First
218 compensate for the autoincrement in the loop. */
219 subql #4,R(a0)
220
221 moveb MEM(a0),R(d1)
222 cmpb R(d0),R(d1)
223 beq L(L9)
224 tstb R(d1)
225 beq L(L9)
226 addql #1,R(a0)
227
228 moveb MEM(a0),R(d1)
229 cmpb R(d0),R(d1)
230 beq L(L9)
231 tstb R(d1)
232 beq L(L9)
233 addql #1,R(a0)
234
235 moveb MEM(a0),R(d1)
236 cmpb R(d0),R(d1)
237 beq L(L9)
238 tstb R(d1)
239 beq L(L9)
240 addql #1,R(a0)
241
242 /* Otherwise the fourth byte must equal C or be NUL. */
243 L(L9:)
244 movel R(a0),R(d0)
245 movel MEM_POSTINC(sp),R(d3)
246 movel MEM_POSTINC(sp),R(d2)
247 rts
248 END(__strchrnul)
249
250 weak_alias (__strchrnul, strchrnul)