]>
Commit | Line | Data |
---|---|---|
55dec6d8 AS |
1 | /* strchrnul (str, ch) -- Return pointer to first occurrence of CH in STR |
2 | or the final NUL byte. | |
3 | For Motorola 68000. | |
04277e02 | 4 | Copyright (C) 1999-2019 Free Software Foundation, Inc. |
55dec6d8 AS |
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 | |
3214b89b AJ |
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. | |
55dec6d8 AS |
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 | |
3214b89b | 16 | Lesser General Public License for more details. |
55dec6d8 | 17 | |
3214b89b | 18 | You should have received a copy of the GNU Lesser General Public |
ab84e3ff PE |
19 | License along with the GNU C Library. If not, see |
20 | <http://www.gnu.org/licenses/>. */ | |
55dec6d8 AS |
21 | |
22 | #include <sysdep.h> | |
23 | #include "asm-syntax.h" | |
24 | ||
25 | TEXT | |
26 | ENTRY(__strchrnul) | |
27 | /* Save the callee-saved registers we use. */ | |
28 | movel R(d2),MEM_PREDEC(sp) | |
50e73d13 | 29 | cfi_adjust_cfa_offset (4) |
55dec6d8 | 30 | movel R(d3),MEM_PREDEC(sp) |
50e73d13 AS |
31 | cfi_adjust_cfa_offset (4) |
32 | cfi_rel_offset (R(d2), 4) | |
33 | cfi_rel_offset (R(d3), 0) | |
55dec6d8 AS |
34 | |
35 | /* Get string pointer and character. */ | |
36 | movel MEM_DISP(sp,12),R(a0) | |
37 | moveb MEM_DISP(sp,19),R(d0) | |
38 | ||
39 | /* Distribute the character to all bytes of a longword. */ | |
40 | movel R(d0),R(d1) | |
41 | lsll #8,R(d1) | |
42 | moveb R(d0),R(d1) | |
43 | movel R(d1),R(d0) | |
44 | swap R(d0) | |
45 | movew R(d1),R(d0) | |
46 | ||
47 | /* First search for the character one byte at a time until the | |
48 | pointer is aligned to a longword boundary. */ | |
49 | movel R(a0),R(d1) | |
9c986f87 AS |
50 | #ifdef __mcoldfire__ |
51 | andl #3,R(d1) | |
52 | #else | |
55dec6d8 | 53 | andw #3,R(d1) |
9c986f87 | 54 | #endif |
55dec6d8 | 55 | beq L(L1) |
9c986f87 AS |
56 | moveb MEM(a0),R(d2) |
57 | cmpb R(d0),R(d2) | |
55dec6d8 | 58 | beq L(L9) |
9c986f87 | 59 | tstb R(d2) |
55dec6d8 AS |
60 | beq L(L9) |
61 | addql #1,R(a0) | |
62 | ||
9c986f87 AS |
63 | #ifdef __mcoldfire__ |
64 | subql #3,R(d1) | |
65 | #else | |
66 | subqw #3,R(d1) | |
67 | #endif | |
55dec6d8 | 68 | beq L(L1) |
9c986f87 AS |
69 | moveb MEM(a0),R(d2) |
70 | cmpb R(d0),R(d2) | |
55dec6d8 | 71 | beq L(L9) |
9c986f87 | 72 | tstb R(d2) |
55dec6d8 AS |
73 | beq L(L9) |
74 | addql #1,R(a0) | |
75 | ||
9c986f87 AS |
76 | #ifdef __mcoldfire__ |
77 | addql #1,R(d1) | |
78 | #else | |
79 | addqw #1,R(d1) | |
80 | #endif | |
55dec6d8 | 81 | beq L(L1) |
9c986f87 AS |
82 | moveb MEM(a0),R(d2) |
83 | cmpb R(d0),R(d2) | |
55dec6d8 | 84 | beq L(L9) |
9c986f87 | 85 | tstb R(d2) |
55dec6d8 AS |
86 | beq L(L9) |
87 | addql #1,R(a0) | |
88 | ||
89 | L(L1:) | |
90 | /* Load the magic bits. Unlike the generic implementation we can | |
91 | use the carry bit as the fourth hole. */ | |
92 | movel #0xfefefeff,R(d3) | |
93 | ||
94 | /* We exit the loop if adding MAGIC_BITS to LONGWORD fails to | |
95 | change any of the hole bits of LONGWORD. | |
96 | ||
97 | 1) Is this safe? Will it catch all the zero bytes? | |
98 | Suppose there is a byte with all zeros. Any carry bits | |
99 | propagating from its left will fall into the hole at its | |
100 | least significant bit and stop. Since there will be no | |
101 | carry from its most significant bit, the LSB of the | |
102 | byte to the left will be unchanged, and the zero will be | |
103 | detected. | |
104 | ||
105 | 2) Is this worthwhile? Will it ignore everything except | |
106 | zero bytes? Suppose every byte of LONGWORD has a bit set | |
107 | somewhere. There will be a carry into bit 8. If bit 8 | |
108 | is set, this will carry into bit 16. If bit 8 is clear, | |
109 | one of bits 9-15 must be set, so there will be a carry | |
110 | into bit 16. Similarly, there will be a carry into bit | |
111 | 24. If one of bits 24-31 is set, there will be a carry | |
112 | into bit 32 (=carry flag), so all of the hole bits will | |
113 | be changed. | |
114 | ||
115 | 3) But wait! Aren't we looking for C, not zero? | |
116 | Good point. So what we do is XOR LONGWORD with a longword, | |
117 | each of whose bytes is C. This turns each byte that is C | |
118 | into a zero. */ | |
119 | ||
120 | L(L2:) | |
121 | /* Get the longword in question. */ | |
122 | movel MEM_POSTINC(a0),R(d1) | |
123 | /* XOR with the byte we search for. */ | |
124 | eorl R(d0),R(d1) | |
125 | ||
126 | /* Add the magic value. We get carry bits reported for each byte | |
127 | which is not C. */ | |
128 | movel R(d3),R(d2) | |
129 | addl R(d1),R(d2) | |
130 | ||
131 | /* Check the fourth carry bit before it is clobbered by the next | |
132 | XOR. If it is not set we have a hit. */ | |
133 | bcc L(L8) | |
134 | ||
135 | /* We are only interested in carry bits that change due to the | |
136 | previous add, so remove original bits. */ | |
137 | eorl R(d1),R(d2) | |
138 | ||
139 | /* Now test for the other three overflow bits. | |
140 | Set all non-carry bits. */ | |
141 | orl R(d3),R(d2) | |
142 | /* Add 1 to get zero if all carry bits were set. */ | |
143 | addql #1,R(d2) | |
144 | ||
145 | /* If we don't get zero then at least one byte of the word equals | |
146 | C. */ | |
147 | bne L(L8) | |
148 | ||
149 | /* Next look for a NUL byte. | |
150 | Restore original longword without reload. */ | |
151 | eorl R(d0),R(d1) | |
152 | /* Add the magic value. We get carry bits reported for each byte | |
153 | which is not NUL. */ | |
154 | movel R(d3),R(d2) | |
155 | addl R(d1),R(d2) | |
156 | ||
157 | /* Check the fourth carry bit before it is clobbered by the next | |
158 | XOR. If it is not set we have a hit. */ | |
159 | bcc L(L8) | |
160 | ||
161 | /* We are only interested in carry bits that change due to the | |
162 | previous add, so remove original bits. */ | |
163 | eorl R(d1),R(d2) | |
164 | ||
165 | /* Now test for the other three overflow bits. | |
166 | Set all non-carry bits. */ | |
167 | orl R(d3),R(d2) | |
168 | /* Add 1 to get zero if all carry bits were set. */ | |
169 | addql #1,R(d2) | |
170 | ||
171 | /* If we don't get zero then at least one byte of the word was | |
172 | NUL. Otherwise continue with the next longword. */ | |
173 | bne L(L8) | |
174 | ||
175 | /* Get the longword in question. */ | |
176 | movel MEM_POSTINC(a0),R(d1) | |
177 | /* XOR with the byte we search for. */ | |
178 | eorl R(d0),R(d1) | |
179 | ||
180 | /* Add the magic value. We get carry bits reported for each byte | |
181 | which is not C. */ | |
182 | movel R(d3),R(d2) | |
183 | addl R(d1),R(d2) | |
184 | ||
185 | /* Check the fourth carry bit before it is clobbered by the next | |
186 | XOR. If it is not set we have a hit. */ | |
187 | bcc L(L8) | |
188 | ||
189 | /* We are only interested in carry bits that change due to the | |
190 | previous add, so remove original bits */ | |
191 | eorl R(d1),R(d2) | |
192 | ||
193 | /* Now test for the other three overflow bits. | |
194 | Set all non-carry bits. */ | |
195 | orl R(d3),R(d2) | |
196 | /* Add 1 to get zero if all carry bits were set. */ | |
197 | addql #1,R(d2) | |
198 | ||
199 | /* If we don't get zero then at least one byte of the word equals | |
200 | C. */ | |
201 | bne L(L8) | |
202 | ||
203 | /* Next look for a NUL byte. | |
204 | Restore original longword without reload. */ | |
205 | eorl R(d0),R(d1) | |
206 | /* Add the magic value. We get carry bits reported for each byte | |
207 | which is not NUL. */ | |
208 | movel R(d3),R(d2) | |
209 | addl R(d1),R(d2) | |
210 | ||
211 | /* Check the fourth carry bit before it is clobbered by the next | |
212 | XOR. If it is not set we have a hit. */ | |
213 | bcc L(L8) | |
214 | ||
215 | /* We are only interested in carry bits that change due to the | |
216 | previous add, so remove original bits */ | |
217 | eorl R(d1),R(d2) | |
218 | ||
219 | /* Now test for the other three overflow bits. | |
220 | Set all non-carry bits. */ | |
221 | orl R(d3),R(d2) | |
222 | /* Add 1 to get zero if all carry bits were set. */ | |
223 | addql #1,R(d2) | |
224 | ||
225 | /* If we don't get zero then at least one byte of the word was | |
226 | NUL. Otherwise continue with the next longword. */ | |
227 | beq L(L2) | |
228 | ||
229 | L(L8:) | |
230 | /* We have a hit. Check to see which byte it was. First | |
231 | compensate for the autoincrement in the loop. */ | |
232 | subql #4,R(a0) | |
233 | ||
234 | moveb MEM(a0),R(d1) | |
235 | cmpb R(d0),R(d1) | |
236 | beq L(L9) | |
237 | tstb R(d1) | |
238 | beq L(L9) | |
239 | addql #1,R(a0) | |
240 | ||
241 | moveb MEM(a0),R(d1) | |
242 | cmpb R(d0),R(d1) | |
243 | beq L(L9) | |
244 | tstb R(d1) | |
245 | beq L(L9) | |
246 | addql #1,R(a0) | |
247 | ||
248 | moveb MEM(a0),R(d1) | |
249 | cmpb R(d0),R(d1) | |
250 | beq L(L9) | |
251 | tstb R(d1) | |
252 | beq L(L9) | |
253 | addql #1,R(a0) | |
254 | ||
255 | /* Otherwise the fourth byte must equal C or be NUL. */ | |
256 | L(L9:) | |
257 | movel R(a0),R(d0) | |
258 | movel MEM_POSTINC(sp),R(d3) | |
50e73d13 AS |
259 | cfi_adjust_cfa_offset (-4) |
260 | cfi_restore (R(d3)) | |
55dec6d8 | 261 | movel MEM_POSTINC(sp),R(d2) |
50e73d13 AS |
262 | cfi_adjust_cfa_offset (-4) |
263 | cfi_restore (R(d2)) | |
55dec6d8 AS |
264 | rts |
265 | END(__strchrnul) | |
266 | ||
267 | weak_alias (__strchrnul, strchrnul) |