linux: Extend internal clone3 documentation
[glibc.git] / sysdeps / m68k / strchrnul.S
blobf4759a0fb3701fd5b484492364babc5ca48ba00d
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-2023 Free Software Foundation, Inc.
5    This file is part of the GNU C Library.
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    <https://www.gnu.org/licenses/>.  */
21 #include <sysdep.h>
22 #include "asm-syntax.h"
24         TEXT
25 ENTRY(__strchrnul)
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(L9)
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(L9)
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(L9)
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.  */
158         bcc     L(L8)
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
171            NUL.  Otherwise continue with the next longword.  */
172         bne     L(L8)
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.  */
212         bcc     L(L8)
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
225            NUL.  Otherwise continue with the next longword.  */
226         beq     L(L2)
228 L(L8:)
229         /* We have a hit.  Check to see which byte it was.  First
230            compensate for the autoincrement in the loop.  */
231         subql   #4,R(a0)
233         moveb   MEM(a0),R(d1)
234         cmpb    R(d0),R(d1)
235         beq     L(L9)
236         tstb    R(d1)
237         beq     L(L9)
238         addql   #1,R(a0)
240         moveb   MEM(a0),R(d1)
241         cmpb    R(d0),R(d1)
242         beq     L(L9)
243         tstb    R(d1)
244         beq     L(L9)
245         addql   #1,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(L9)
252         addql   #1,R(a0)
254         /* Otherwise the fourth byte must equal C or be NUL.  */
255 L(L9:)
256         movel   R(a0),R(d0)
257         movel   MEM_POSTINC(sp),R(d3)
258         cfi_adjust_cfa_offset (-4)
259         cfi_restore (R(d3))
260         movel   MEM_POSTINC(sp),R(d2)
261         cfi_adjust_cfa_offset (-4)
262         cfi_restore (R(d2))
263         rts
264 END(__strchrnul)
266 weak_alias (__strchrnul, strchrnul)