Update copyright notices with scripts/update-copyrights
[glibc.git] / ports / sysdeps / m68k / strchr.S
bloba109b3154159dab5a557e737498b8ce721189127
1 /* strchr (str, ch) -- Return pointer to first occurrence of CH in STR.
2    For Motorola 68000.
3    Copyright (C) 1999-2014 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, see
19    <http://www.gnu.org/licenses/>.  */
21 #include <sysdep.h>
22 #include "asm-syntax.h"
24         TEXT
25 ENTRY(strchr)
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)
34         /* Get string pointer and character.  */
35         movel   MEM_DISP(sp,12),R(a0)
36         moveb   MEM_DISP(sp,19),R(d0)
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)
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(L3)
60         addql   #1,R(a0)
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(L3)
73         addql   #1,R(a0)
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(L3)
86         addql   #1,R(a0)
88 L(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)
93       /* We exit the loop if adding MAGIC_BITS to LONGWORD fails to
94          change any of the hole bits of LONGWORD.
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.
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.
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.  */
119 L(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)
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)
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)
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)
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)
144         /* If we don't get zero then at least one byte of the word equals
145            C.  */
146         bne     L(L8)
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)
156         /* Check the fourth carry bit before it is clobbered by the next
157            XOR.  If it is not set we have a hit, and return NULL.  */
158         bcc     L(L3)
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)
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)
170         /* If we don't get zero then at least one byte of the word was NUL
171            and we return NULL.  Otherwise continue with the next longword.  */
172         bne     L(L3)
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)
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)
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)
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)
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)
198         /* If we don't get zero then at least one byte of the word equals
199            C.  */
200         bne     L(L8)
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)
210         /* Check the fourth carry bit before it is clobbered by the next
211            XOR.  If it is not set we have a hit, and return NULL.  */
212         bcc     L(L3)
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)
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)
224         /* If we don't get zero then at least one byte of the word was NUL
225            and we return NULL.  Otherwise continue with the next longword.  */
226         beq     L(L2)
228 L(L3:)
229         /* Return NULL.  */
230         clrl    R(d0)
231         movel   R(d0),R(a0)
232         movel   MEM_POSTINC(sp),R(d3)
233         cfi_remember_state
234         cfi_adjust_cfa_offset (-4)
235         cfi_restore (R(d3))
236         movel   MEM_POSTINC(sp),R(d2)
237         cfi_adjust_cfa_offset (-4)
238         cfi_restore (R(d2))
239         rts
241         cfi_restore_state
242 L(L8:)
243         /* We have a hit.  Check to see which byte it was.  First
244            compensate for the autoincrement in the loop.  */
245         subql   #4,R(a0)
247         moveb   MEM(a0),R(d1)
248         cmpb    R(d0),R(d1)
249         beq     L(L9)
250         tstb    R(d1)
251         beq     L(L3)
252         addql   #1,R(a0)
254         moveb   MEM(a0),R(d1)
255         cmpb    R(d0),R(d1)
256         beq     L(L9)
257         tstb    R(d1)
258         beq     L(L3)
259         addql   #1,R(a0)
261         moveb   MEM(a0),R(d1)
262         cmpb    R(d0),R(d1)
263         beq     L(L9)
264         tstb    R(d1)
265         beq     L(L3)
266         addql   #1,R(a0)
268         /* Otherwise the fourth byte must equal C.  */
269 L(L9:)
270         movel   R(a0),R(d0)
271         movel   MEM_POSTINC(sp),R(d3)
272         cfi_adjust_cfa_offset (-4)
273         cfi_restore (R(d3))
274         movel   MEM_POSTINC(sp),R(d2)
275         cfi_adjust_cfa_offset (-4)
276         cfi_restore (R(d2))
277         rts
278 END(strchr)
280 weak_alias (strchr, index)
281 libc_hidden_builtin_def (strchr)