Update copyright notices with scripts/update-copyrights
[glibc.git] / ports / sysdeps / m68k / strchrnul.S
blobf90d7f093e9f885bf87dd0d7b6d73b7fcadd20a3
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-2014 Free Software Foundation, Inc.
5    This file is part of the GNU C Library.
6    Contributed by Andreas Schwab <schwab@gnu.org>.
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.
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.
18    You should have received a copy of the GNU Lesser General Public
19    License along with the GNU C Library.  If not, see
20    <http://www.gnu.org/licenses/>.  */
22 #include <sysdep.h>
23 #include "asm-syntax.h"
25         TEXT
26 ENTRY(__strchrnul)
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(L9)
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(L9)
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(L9)
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.  */
159         bcc     L(L8)
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
172            NUL.  Otherwise continue with the next longword.  */
173         bne     L(L8)
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.  */
213         bcc     L(L8)
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
226            NUL.  Otherwise continue with the next longword.  */
227         beq     L(L2)
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)
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)
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)
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)
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)
259         cfi_adjust_cfa_offset (-4)
260         cfi_restore (R(d3))
261         movel   MEM_POSTINC(sp),R(d2)
262         cfi_adjust_cfa_offset (-4)
263         cfi_restore (R(d2))
264         rts
265 END(__strchrnul)
267 weak_alias (__strchrnul, strchrnul)