ARM: Implement *context routines.
[glibc.git] / sysdeps / m68k / strchr.S
blob6c6a08fe2aefc5498733957a89fd571c55a38b49
1 /* strchr (str, ch) -- Return pointer to first occurrence of CH in STR.
2    For Motorola 68000.
3    Copyright (C) 1999, 2003, 2012 Free Software Foundation, Inc.
4    This file is part of the GNU C Library.
5    Contributed by Andreas Schwab <schwab@gnu.org>.
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, write to the Free
19    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20    02111-1307 USA.  */
22 #include <sysdep.h>
23 #include "asm-syntax.h"
25         TEXT
26 ENTRY(strchr)
27         /* Save the callee-saved registers we use.  */
28         movel   R(d2),MEM_PREDEC(sp)
29         cfi_adjust_cfa_offset (4)
30         movel   R(d3),MEM_PREDEC(sp)
31         cfi_adjust_cfa_offset (4)
32         cfi_rel_offset (R(d2),4)
33         cfi_rel_offset (R(d3),0)
35         /* Get string pointer and character.  */
36         movel   MEM_DISP(sp,12),R(a0)
37         moveb   MEM_DISP(sp,19),R(d0)
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)
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)
50 #ifdef __mcoldfire__
51         andl    #3,R(d1)
52 #else
53         andw    #3,R(d1)
54 #endif
55         beq     L(L1)
56         moveb   MEM(a0),R(d2)
57         cmpb    R(d0),R(d2)
58         beq     L(L9)
59         tstb    R(d2)
60         beq     L(L3)
61         addql   #1,R(a0)
63 #ifdef __mcoldfire__
64         subql   #3,R(d1)
65 #else
66         subqw   #3,R(d1)
67 #endif
68         beq     L(L1)
69         moveb   MEM(a0),R(d2)
70         cmpb    R(d0),R(d2)
71         beq     L(L9)
72         tstb    R(d2)
73         beq     L(L3)
74         addql   #1,R(a0)
76 #ifdef __mcoldfire__
77         addql   #1,R(d1)
78 #else
79         addqw   #1,R(d1)
80 #endif
81         beq     L(L1)
82         moveb   MEM(a0),R(d2)
83         cmpb    R(d0),R(d2)
84         beq     L(L9)
85         tstb    R(d2)
86         beq     L(L3)
87         addql   #1,R(a0)
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)
94       /* We exit the loop if adding MAGIC_BITS to LONGWORD fails to
95          change any of the hole bits of LONGWORD.
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.
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.
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.  */
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)
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)
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)
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)
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)
145         /* If we don't get zero then at least one byte of the word equals
146            C.  */
147         bne     L(L8)
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)
157         /* Check the fourth carry bit before it is clobbered by the next
158            XOR.  If it is not set we have a hit, and return NULL.  */
159         bcc     L(L3)
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)
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)
171         /* If we don't get zero then at least one byte of the word was NUL
172            and we return NULL.  Otherwise continue with the next longword.  */
173         bne     L(L3)
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)
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)
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)
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)
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)
199         /* If we don't get zero then at least one byte of the word equals
200            C.  */
201         bne     L(L8)
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)
211         /* Check the fourth carry bit before it is clobbered by the next
212            XOR.  If it is not set we have a hit, and return NULL.  */
213         bcc     L(L3)
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)
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)
225         /* If we don't get zero then at least one byte of the word was NUL
226            and we return NULL.  Otherwise continue with the next longword.  */
227         beq     L(L2)
229 L(L3:)
230         /* Return NULL.  */
231         clrl    R(d0)
232         movel   R(d0),R(a0)
233         movel   MEM_POSTINC(sp),R(d3)
234         cfi_remember_state
235         cfi_adjust_cfa_offset (-4)
236         cfi_restore (R(d3))
237         movel   MEM_POSTINC(sp),R(d2)
238         cfi_adjust_cfa_offset (-4)
239         cfi_restore (R(d2))
240         rts
242         cfi_restore_state
243 L(L8:)
244         /* We have a hit.  Check to see which byte it was.  First
245            compensate for the autoincrement in the loop.  */
246         subql   #4,R(a0)
248         moveb   MEM(a0),R(d1)
249         cmpb    R(d0),R(d1)
250         beq     L(L9)
251         tstb    R(d1)
252         beq     L(L3)
253         addql   #1,R(a0)
255         moveb   MEM(a0),R(d1)
256         cmpb    R(d0),R(d1)
257         beq     L(L9)
258         tstb    R(d1)
259         beq     L(L3)
260         addql   #1,R(a0)
262         moveb   MEM(a0),R(d1)
263         cmpb    R(d0),R(d1)
264         beq     L(L9)
265         tstb    R(d1)
266         beq     L(L3)
267         addql   #1,R(a0)
269         /* Otherwise the fourth byte must equal C.  */
270 L(L9:)
271         movel   R(a0),R(d0)
272         movel   MEM_POSTINC(sp),R(d3)
273         cfi_adjust_cfa_offset (-4)
274         cfi_restore (R(d3))
275         movel   MEM_POSTINC(sp),R(d2)
276         cfi_adjust_cfa_offset (-4)
277         cfi_restore (R(d2))
278         rts
279 END(strchr)
281 weak_alias (strchr, index)
282 libc_hidden_builtin_def (strchr)