Update.
[glibc/history.git] / sysdeps / i386 / i486 / strcat.S
blobc3893315e7184593e535bfe8f63c4c6a75cabd9f
1 /* strcat(dest, src) -- Append SRC on the end of DEST.
2    For Intel 80x86, x>=4.
3    Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
4    This file is part of the GNU C Library.
5    Contributed by Ulrich Drepper <drepper@ipd.info.uni-karlsruhe.de>.
6    Optimised a little by Alan Modra <Alan@SPRI.Levels.UniSA.Edu.Au>
8    The GNU C Library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Library General Public License as
10    published by the Free Software Foundation; either version 2 of the
11    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    Library General Public License for more details.
18    You should have received a copy of the GNU Library General Public
19    License along with the GNU C Library; see the file COPYING.LIB.  If not,
20    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21    Boston, MA 02111-1307, USA.  */
23 #include <sysdep.h>
24 #include "asm-syntax.h"
27    INPUT PARAMETERS:
28    dest         (sp + 4)
29    src          (sp + 8)
32         .text
33 ENTRY (strcat)
34         pushl %edi              /* Save callee-safe register.  */
36         movl 12(%esp), %ecx     /* load source pointer */
37         movl 8(%esp), %edx      /* load destination pointer */
39         testb $0xff, (%ecx)     /* Is source string empty? */
40         jz L(8)                 /* yes => return */
42         /* Test the first bytes separately until destination is aligned.  */
43         testl $3, %edx          /* destination pointer aligned? */
44         jz L(1)                 /* yes => begin scan loop */
45         testb $0xff, (%edx)     /* is end of string? */
46         jz L(2)                 /* yes => start appending */
47         incl %edx               /* increment source pointer */
49         testl $3, %edx          /* destination pointer aligned? */
50         jz L(1)                 /* yes => begin scan loop */
51         testb $0xff, (%edx)     /* is end of string? */
52         jz L(2)                 /* yes => start appending */
53         incl %edx               /* increment source pointer */
55         testl $3, %edx          /* destination pointer aligned? */
56         jz L(1)                 /* yes => begin scan loop */
57         testb $0xff, (%edx)     /* is end of string? */
58         jz L(2)                 /* yes => start appending */
59         incl %edx               /* increment source pointer */
61         /* Now we are aligned.  Begin scan loop.  */
62         jmp L(1)
64         ALIGN(4)
66 L(4):   addl $16,%edx           /* increment destination pointer for round */
68 L(1):   movl (%edx), %eax       /* get word (= 4 bytes) in question */
69         movl $0xfefefeff, %edi  /* magic value */
71         /* If you compare this with the algorithm in memchr.S you will
72            notice that here is an `xorl' statement missing.  But you must
73            not forget that we are looking for C == 0 and `xorl $0, %eax'
74            is a no-op.  */
76         addl %eax, %edi         /* add the magic value to the word.  We get
77                                    carry bits reported for each byte which
78                                    is *not* 0 */
80         /* According to the algorithm we had to reverse the effect of the
81            XOR first and then test the overflow bits.  But because the
82            following XOR would destroy the carry flag and it would (in a
83            representation with more than 32 bits) not alter then last
84            overflow, we can now test this condition.  If no carry is signaled
85            no overflow must have occurred in the last byte => it was 0. */
86         jnc L(3)
88         /* We are only interested in carry bits that change due to the
89            previous add, so remove original bits */
90         xorl %eax, %edi         /* ((word^charmask)+magic)^(word^charmask) */
92         /* Now test for the other three overflow bits.  */
93         orl $0xfefefeff, %edi   /* set all non-carry bits */
94         incl %edi               /* add 1: if one carry bit was *not* set
95                                    the addition will not result in 0.  */
97         /* If at least one byte of the word is C we don't get 0 in %ecx.  */
98         jnz L(3)
100         movl 4(%edx), %eax      /* get word from source */
101         movl $0xfefefeff, %edi  /* magic value */
102         addl %eax, %edi         /* add the magic value to the word.  We get
103                                    carry bits reported for each byte which
104                                    is *not* 0 */
105         jnc L(5)                /* highest byte is C => stop copying */
106         xorl %eax, %edi         /* ((word^charmask)+magic)^(word^charmask) */
107         orl $0xfefefeff, %edi   /* set all non-carry bits */
108         incl %edi               /* add 1: if one carry bit was *not* set
109                                    the addition will not result in 0.  */
110         jnz L(5)                /* one byte is NUL => stop copying */
112         movl 8(%edx), %eax      /* get word from source */
113         movl $0xfefefeff, %edi  /* magic value */
114         addl %eax, %edi         /* add the magic value to the word.  We get
115                                    carry bits reported for each byte which
116                                    is *not* 0 */
117         jnc L(6)                /* highest byte is C => stop copying */
118         xorl %eax, %edi         /* ((word^charmask)+magic)^(word^charmask) */
119         orl $0xfefefeff, %edi   /* set all non-carry bits */
120         incl %edi               /* add 1: if one carry bit was *not* set
121                                    the addition will not result in 0.  */
122         jnz L(6)                /* one byte is NUL => stop copying */
124         movl 12(%edx), %eax     /* get word from source */
125         movl $0xfefefeff, %edi  /* magic value */
126         addl %eax, %edi         /* add the magic value to the word.  We get
127                                    carry bits reported for each byte which
128                                    is *not* 0 */
129         jnc L(7)                /* highest byte is C => stop copying */
130         xorl %eax, %edi         /* ((word^charmask)+magic)^(word^charmask) */
131         orl $0xfefefeff, %edi   /* set all non-carry bits */
132         incl %edi               /* add 1: if one carry bit was *not* set
133                                    the addition will not result in 0.  */
134         jz L(4)                 /* no byte is NUL => carry on copying */
136 L(7):   addl $4, %edx           /* adjust source pointer */
137 L(6):   addl $4, %edx
138 L(5):   addl $4, %edx
140 L(3):   testb %al, %al          /* is first byte NUL? */
141         jz L(2)                 /* yes => start copying */
142         incl %edx               /* increment source pointer */
144         testb %ah, %ah          /* is second byte NUL? */
145         jz L(2)                 /* yes => start copying */
146         incl %edx               /* increment source pointer */
148         testl $0xff0000, %eax   /* is third byte NUL? */
149         jz L(2)                 /* yes => start copying */
150         incl %edx               /* increment source pointer */
152 L(2):   subl %ecx, %edx         /* reduce number of loop variants */
154         /* Now we have to align the source pointer.  */
155         testl $3, %ecx          /* pointer correctly aligned? */
156         jz L(29)                /* yes => start copy loop */
157         movb (%ecx), %al        /* get first byte */
158         movb %al, (%ecx,%edx)   /* and store it */
159         andb %al, %al           /* is byte NUL? */
160         jz L(8)                 /* yes => return */
161         incl %ecx               /* increment pointer */
163         testl $3, %ecx          /* pointer correctly aligned? */
164         jz L(29)                /* yes => start copy loop */
165         movb (%ecx), %al        /* get first byte */
166         movb %al, (%ecx,%edx)   /* and store it */
167         andb %al, %al           /* is byte NUL? */
168         jz L(8)                 /* yes => return */
169         incl %ecx               /* increment pointer */
171         testl $3, %ecx          /* pointer correctly aligned? */
172         jz L(29)                /* yes => start copy loop */
173         movb (%ecx), %al        /* get first byte */
174         movb %al, (%ecx,%edx)   /* and store it */
175         andb %al, %al           /* is byte NUL? */
176         jz L(8)                 /* yes => return */
177         incl %ecx               /* increment pointer */
179         /* Now we are aligned.  */
180         jmp L(29)               /* start copy loop */
182         ALIGN(4)
184 L(28):  movl %eax, 12(%ecx,%edx)/* store word at destination */
185         addl $16, %ecx          /* adjust pointer for full round */
187 L(29):  movl (%ecx), %eax       /* get word from source */
188         movl $0xfefefeff, %edi  /* magic value */
189         addl %eax, %edi         /* add the magic value to the word.  We get
190                                    carry bits reported for each byte which
191                                    is *not* 0 */
192         jnc L(9)                /* highest byte is C => stop copying */
193         xorl %eax, %edi         /* ((word^charmask)+magic)^(word^charmask) */
194         orl $0xfefefeff, %edi   /* set all non-carry bits */
195         incl %edi               /* add 1: if one carry bit was *not* set
196                                    the addition will not result in 0.  */
197         jnz L(9)                /* one byte is NUL => stop copying */
198         movl %eax, (%ecx,%edx)  /* store word to destination */
200         movl 4(%ecx), %eax      /* get word from source */
201         movl $0xfefefeff, %edi  /* magic value */
202         addl %eax, %edi         /* add the magic value to the word.  We get
203                                    carry bits reported for each byte which
204                                    is *not* 0 */
205         jnc L(91)               /* highest byte is C => stop copying */
206         xorl %eax, %edi         /* ((word^charmask)+magic)^(word^charmask) */
207         orl $0xfefefeff, %edi   /* set all non-carry bits */
208         incl %edi               /* add 1: if one carry bit was *not* set
209                                    the addition will not result in 0.  */
210         jnz L(91)               /* one byte is NUL => stop copying */
211         movl %eax, 4(%ecx,%edx) /* store word to destination */
213         movl 8(%ecx), %eax      /* get word from source */
214         movl $0xfefefeff, %edi  /* magic value */
215         addl %eax, %edi         /* add the magic value to the word.  We get
216                                    carry bits reported for each byte which
217                                    is *not* 0 */
218         jnc L(92)               /* highest byte is C => stop copying */
219         xorl %eax, %edi         /* ((word^charmask)+magic)^(word^charmask) */
220         orl $0xfefefeff, %edi   /* set all non-carry bits */
221         incl %edi               /* add 1: if one carry bit was *not* set
222                                    the addition will not result in 0.  */
223         jnz L(92)               /* one byte is NUL => stop copying */
224         movl %eax, 8(%ecx,%edx) /* store word to destination */
226         movl 12(%ecx), %eax     /* get word from source */
227         movl $0xfefefeff, %edi  /* magic value */
228         addl %eax, %edi         /* add the magic value to the word.  We get
229                                    carry bits reported for each byte which
230                                    is *not* 0 */
231         jnc L(93)               /* highest byte is C => stop copying */
232         xorl %eax, %edi         /* ((word^charmask)+magic)^(word^charmask) */
233         orl $0xfefefeff, %edi   /* set all non-carry bits */
234         incl %edi               /* add 1: if one carry bit was *not* set
235                                    the addition will not result in 0.  */
236         jz L(28)                /* no is NUL => carry on copying */
238 L(93):  addl $4, %ecx           /* adjust pointer */
239 L(92):  addl $4, %ecx
240 L(91):  addl $4, %ecx
242 L(9):   movb %al, (%ecx,%edx)   /* store first byte of last word */
243         orb %al, %al            /* is it NUL? */
244         jz L(8)                 /* yes => return */
246         movb %ah, 1(%ecx,%edx)  /* store second byte of last word */
247         orb %ah, %ah            /* is it NUL? */
248         jz L(8)                 /* yes => return */
250         shrl $16, %eax          /* make upper bytes accessible */
251         movb %al, 2(%ecx,%edx)  /* store third byte of last word */
252         orb %al, %al            /* is it NUL? */
253         jz L(8)                 /* yes => return */
255         movb %ah, 3(%ecx,%edx)  /* store fourth byte of last word */
257 L(8):   movl 8(%esp), %eax      /* start address of destination is result */
258         popl %edi               /* restore saved register */
260         ret
261 END (strcat)