Add string vectorized find and detection functions
[glibc.git] / sysdeps / i386 / strcat.S
blob3f1cda943af8342378b633b418f79f749a7abddc
1 /* strcat(dest, src) -- Append SRC on the end of DEST.
2    For Intel 80x86, x>=4.
3    Copyright (C) 1994-2023 Free Software Foundation, Inc.
4    This file is part of the GNU C Library.
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, see
18    <https://www.gnu.org/licenses/>.  */
20 #include <sysdep.h>
21 #include "asm-syntax.h"
23 #define PARMS   4+4     /* space for 1 saved reg */
24 #define RTN     PARMS
25 #define DEST    RTN
26 #define SRC     DEST+4
28         .text
29 ENTRY (strcat)
31         pushl %edi              /* Save callee-safe register.  */
32         cfi_adjust_cfa_offset (4)
34         movl DEST(%esp), %edx
35         movl SRC(%esp), %ecx
37         testb $0xff, (%ecx)     /* Is source string empty? */
38         jz L(8)                 /* yes => return */
40         /* Test the first bytes separately until destination is aligned.  */
41         testl $3, %edx          /* destination pointer aligned? */
42         jz L(1)                 /* yes => begin scan loop */
43         testb $0xff, (%edx)     /* is end of string? */
44         jz L(2)                 /* yes => start appending */
45         incl %edx               /* increment source pointer */
47         testl $3, %edx          /* destination pointer aligned? */
48         jz L(1)                 /* yes => begin scan loop */
49         testb $0xff, (%edx)     /* is end of string? */
50         jz L(2)                 /* yes => start appending */
51         incl %edx               /* increment source pointer */
53         testl $3, %edx          /* destination pointer aligned? */
54         jz L(1)                 /* yes => begin scan loop */
55         testb $0xff, (%edx)     /* is end of string? */
56         jz L(2)                 /* yes => start appending */
57         incl %edx               /* increment source pointer */
59         /* Now we are aligned.  Begin scan loop.  */
60         jmp L(1)
62         cfi_rel_offset (edi, 0)
63         ALIGN(4)
65 L(4):   addl $16,%edx           /* increment destination pointer for round */
67 L(1):   movl (%edx), %eax       /* get word (= 4 bytes) in question */
68         movl $0xfefefeff, %edi  /* magic value */
70         /* If you compare this with the algorithm in memchr.S you will
71            notice that here is an `xorl' statement missing.  But you must
72            not forget that we are looking for C == 0 and `xorl $0, %eax'
73            is a no-op.  */
75         addl %eax, %edi         /* add the magic value to the word.  We get
76                                    carry bits reported for each byte which
77                                    is *not* 0 */
79         /* According to the algorithm we had to reverse the effect of the
80            XOR first and then test the overflow bits.  But because the
81            following XOR would destroy the carry flag and it would (in a
82            representation with more than 32 bits) not alter then last
83            overflow, we can now test this condition.  If no carry is signaled
84            no overflow must have occurred in the last byte => it was 0. */
85         jnc L(3)
87         /* We are only interested in carry bits that change due to the
88            previous add, so remove original bits */
89         xorl %eax, %edi         /* ((word^charmask)+magic)^(word^charmask) */
91         /* Now test for the other three overflow bits.  */
92         orl $0xfefefeff, %edi   /* set all non-carry bits */
93         incl %edi               /* add 1: if one carry bit was *not* set
94                                    the addition will not result in 0.  */
96         /* If at least one byte of the word is C we don't get 0 in %ecx.  */
97         jnz L(3)
99         movl 4(%edx), %eax      /* get word from source */
100         movl $0xfefefeff, %edi  /* magic value */
101         addl %eax, %edi         /* add the magic value to the word.  We get
102                                    carry bits reported for each byte which
103                                    is *not* 0 */
104         jnc L(5)                /* highest byte is C => stop copying */
105         xorl %eax, %edi         /* ((word^charmask)+magic)^(word^charmask) */
106         orl $0xfefefeff, %edi   /* set all non-carry bits */
107         incl %edi               /* add 1: if one carry bit was *not* set
108                                    the addition will not result in 0.  */
109         jnz L(5)                /* one byte is NUL => stop copying */
111         movl 8(%edx), %eax      /* get word from source */
112         movl $0xfefefeff, %edi  /* magic value */
113         addl %eax, %edi         /* add the magic value to the word.  We get
114                                    carry bits reported for each byte which
115                                    is *not* 0 */
116         jnc L(6)                /* highest byte is C => stop copying */
117         xorl %eax, %edi         /* ((word^charmask)+magic)^(word^charmask) */
118         orl $0xfefefeff, %edi   /* set all non-carry bits */
119         incl %edi               /* add 1: if one carry bit was *not* set
120                                    the addition will not result in 0.  */
121         jnz L(6)                /* one byte is NUL => stop copying */
123         movl 12(%edx), %eax     /* get word from source */
124         movl $0xfefefeff, %edi  /* magic value */
125         addl %eax, %edi         /* add the magic value to the word.  We get
126                                    carry bits reported for each byte which
127                                    is *not* 0 */
128         jnc L(7)                /* highest byte is C => stop copying */
129         xorl %eax, %edi         /* ((word^charmask)+magic)^(word^charmask) */
130         orl $0xfefefeff, %edi   /* set all non-carry bits */
131         incl %edi               /* add 1: if one carry bit was *not* set
132                                    the addition will not result in 0.  */
133         jz L(4)                 /* no byte is NUL => carry on copying */
135 L(7):   addl $4, %edx           /* adjust source pointer */
136 L(6):   addl $4, %edx
137 L(5):   addl $4, %edx
139 L(3):   testb %al, %al          /* is first byte NUL? */
140         jz L(2)                 /* yes => start copying */
141         incl %edx               /* increment source pointer */
143         testb %ah, %ah          /* is second byte NUL? */
144         jz L(2)                 /* yes => start copying */
145         incl %edx               /* increment source pointer */
147         testl $0xff0000, %eax   /* is third byte NUL? */
148         jz L(2)                 /* yes => start copying */
149         incl %edx               /* increment source pointer */
151 L(2):   subl %ecx, %edx         /* reduce number of loop variants */
153         /* Now we have to align the source pointer.  */
154         testl $3, %ecx          /* pointer correctly aligned? */
155         jz L(29)                /* yes => start copy loop */
156         movb (%ecx), %al        /* get first byte */
157         movb %al, (%ecx,%edx)   /* and store it */
158         andb %al, %al           /* is byte NUL? */
159         jz L(8)                 /* yes => return */
160         incl %ecx               /* increment pointer */
162         testl $3, %ecx          /* pointer correctly aligned? */
163         jz L(29)                /* yes => start copy loop */
164         movb (%ecx), %al        /* get first byte */
165         movb %al, (%ecx,%edx)   /* and store it */
166         andb %al, %al           /* is byte NUL? */
167         jz L(8)                 /* yes => return */
168         incl %ecx               /* increment pointer */
170         testl $3, %ecx          /* pointer correctly aligned? */
171         jz L(29)                /* yes => start copy loop */
172         movb (%ecx), %al        /* get first byte */
173         movb %al, (%ecx,%edx)   /* and store it */
174         andb %al, %al           /* is byte NUL? */
175         jz L(8)                 /* yes => return */
176         incl %ecx               /* increment pointer */
178         /* Now we are aligned.  */
179         jmp L(29)               /* start copy loop */
181         ALIGN(4)
183 L(28):  movl %eax, 12(%ecx,%edx)/* store word at destination */
184         addl $16, %ecx          /* adjust pointer for full round */
186 L(29):  movl (%ecx), %eax       /* get word from source */
187         movl $0xfefefeff, %edi  /* magic value */
188         addl %eax, %edi         /* add the magic value to the word.  We get
189                                    carry bits reported for each byte which
190                                    is *not* 0 */
191         jnc L(9)                /* highest byte is C => stop copying */
192         xorl %eax, %edi         /* ((word^charmask)+magic)^(word^charmask) */
193         orl $0xfefefeff, %edi   /* set all non-carry bits */
194         incl %edi               /* add 1: if one carry bit was *not* set
195                                    the addition will not result in 0.  */
196         jnz L(9)                /* one byte is NUL => stop copying */
197         movl %eax, (%ecx,%edx)  /* store word to destination */
199         movl 4(%ecx), %eax      /* get word from source */
200         movl $0xfefefeff, %edi  /* magic value */
201         addl %eax, %edi         /* add the magic value to the word.  We get
202                                    carry bits reported for each byte which
203                                    is *not* 0 */
204         jnc L(91)               /* highest byte is C => stop copying */
205         xorl %eax, %edi         /* ((word^charmask)+magic)^(word^charmask) */
206         orl $0xfefefeff, %edi   /* set all non-carry bits */
207         incl %edi               /* add 1: if one carry bit was *not* set
208                                    the addition will not result in 0.  */
209         jnz L(91)               /* one byte is NUL => stop copying */
210         movl %eax, 4(%ecx,%edx) /* store word to destination */
212         movl 8(%ecx), %eax      /* get word from source */
213         movl $0xfefefeff, %edi  /* magic value */
214         addl %eax, %edi         /* add the magic value to the word.  We get
215                                    carry bits reported for each byte which
216                                    is *not* 0 */
217         jnc L(92)               /* highest byte is C => stop copying */
218         xorl %eax, %edi         /* ((word^charmask)+magic)^(word^charmask) */
219         orl $0xfefefeff, %edi   /* set all non-carry bits */
220         incl %edi               /* add 1: if one carry bit was *not* set
221                                    the addition will not result in 0.  */
222         jnz L(92)               /* one byte is NUL => stop copying */
223         movl %eax, 8(%ecx,%edx) /* store word to destination */
225         movl 12(%ecx), %eax     /* get word from source */
226         movl $0xfefefeff, %edi  /* magic value */
227         addl %eax, %edi         /* add the magic value to the word.  We get
228                                    carry bits reported for each byte which
229                                    is *not* 0 */
230         jnc L(93)               /* highest byte is C => stop copying */
231         xorl %eax, %edi         /* ((word^charmask)+magic)^(word^charmask) */
232         orl $0xfefefeff, %edi   /* set all non-carry bits */
233         incl %edi               /* add 1: if one carry bit was *not* set
234                                    the addition will not result in 0.  */
235         jz L(28)                /* no is NUL => carry on copying */
237 L(93):  addl $4, %ecx           /* adjust pointer */
238 L(92):  addl $4, %ecx
239 L(91):  addl $4, %ecx
241 L(9):   movb %al, (%ecx,%edx)   /* store first byte of last word */
242         orb %al, %al            /* is it NUL? */
243         jz L(8)                 /* yes => return */
245         movb %ah, 1(%ecx,%edx)  /* store second byte of last word */
246         orb %ah, %ah            /* is it NUL? */
247         jz L(8)                 /* yes => return */
249         shrl $16, %eax          /* make upper bytes accessible */
250         movb %al, 2(%ecx,%edx)  /* store third byte of last word */
251         orb %al, %al            /* is it NUL? */
252         jz L(8)                 /* yes => return */
254         movb %ah, 3(%ecx,%edx)  /* store fourth byte of last word */
256 L(8):   movl DEST(%esp), %eax   /* start address of destination is result */
257         popl %edi               /* restore saved register */
258         cfi_adjust_cfa_offset (-4)
259         cfi_restore (edi)
261         ret
262 END (strcat)
263 libc_hidden_builtin_def (strcat)