update from main archive 961005
[glibc/history.git] / sysdeps / i386 / i486 / strcat.S
blobe82b1c40b22a28eb959264f518d5771f3bfb21ed
1 /* strcat(dest, src) -- Append SRC on the end of DEST.
2 For Intel 80x86, x>=4.
3 Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
4 Contributed by Ulrich Drepper <drepper@ipd.info.uni-karlsruhe.de>.
5 Optimised a little by Alan Modra <Alan@SPRI.Levels.UniSA.Edu.Au>
6 This file is part of the GNU C Library.
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
20 not, 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 L8                   /* yes => return */
42         /* Test the first bytes separately until destination is aligned.  */
43         testl $3, %edx          /* destination pointer aligned? */
44         jz L1                   /* yes => begin scan loop */
45         testb $0xff, (%edx)     /* is end of string? */
46         jz L2                   /* yes => start appending */
47         incl %edx               /* increment source pointer */
49         testl $3, %edx          /* destination pointer aligned? */
50         jz L1                   /* yes => begin scan loop */
51         testb $0xff, (%edx)     /* is end of string? */
52         jz L2                   /* yes => start appending */
53         incl %edx               /* increment source pointer */
55         testl $3, %edx          /* destination pointer aligned? */
56         jz L1                   /* yes => begin scan loop */
57         testb $0xff, (%edx)     /* is end of string? */
58         jz L2                   /* yes => start appending */
59         incl %edx               /* increment source pointer */
61         /* Now we are aligned.  Begin scan loop.  */
62         jmp L1
64         ALIGN(4)
66 L4:     addl $16,%edx           /* increment destination pointer for round */
68 L1:     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 occured in the last byte => it was 0.  */
86         jnc L3
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 L3
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 L5                  /* 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 L5                  /* 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 L6                  /* 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 L6                  /* 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 L7                  /* 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 L4                   /* no byte is NUL => carry on copying */
136 L7:     addl $4, %edx           /* adjust source pointer */
137 L6:     addl $4, %edx
138 L5:     addl $4, %edx
140 L3:     testb %al, %al          /* is first byte NUL? */
141         jz L2                   /* yes => start copying */
142         incl %edx               /* increment source pointer */
144         testb %ah, %ah          /* is second byte NUL? */
145         jz L2                   /* yes => start copying */
146         incl %edx               /* increment source pointer */
148         testl $0xff0000, %eax   /* is third byte NUL? */
149         jz L2                   /* yes => start copying */
150         incl %edx               /* increment source pointer */
152 L2:     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 L29                  /* 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 L8                   /* yes => return */
161         incl %ecx               /* increment pointer */
163         testl $3, %ecx          /* pointer correctly aligned? */
164         jz L29                  /* 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 L8                   /* yes => return */
169         incl %ecx               /* increment pointer */
171         testl $3, %ecx          /* pointer correctly aligned? */
172         jz L29                  /* 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 L8                   /* yes => return */
177         incl %ecx               /* increment pointer */
179         /* Now we are aligned.  */
180         jmp L29                 /* start copy loop */
182         ALIGN(4)
184 L28:    movl %eax, 12(%ecx,%edx)/* store word at destination */
185         addl $16, %ecx          /* adjust pointer for full round */
187 L29:    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 L9                  /* 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 L9                  /* 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 L91                 /* 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 L91                 /* 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 L92                 /* 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 L92                 /* 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 L93                 /* 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 L28                  /* no is NUL => carry on copying */
238 L93:    addl $4, %ecx           /* adjust pointer */
239 L92:    addl $4, %ecx
240 L91:    addl $4, %ecx
242 L9:     movb %al, (%ecx,%edx)   /* store first byte of last word */
243         orb %al, %al            /* is it NUL? */
244         jz L8                   /* yes => return */
246         movb %ah, 1(%ecx,%edx)  /* store second byte of last word */
247         orb %ah, %ah            /* is it NUL? */
248         jz L8                   /* 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 L8                   /* yes => return */
255         movb %ah, 3(%ecx,%edx)  /* store fourth byte of last word */
257 L8:     movl 8(%esp), %eax      /* start address of destination is result */
258         popl %edi               /* restore saved register */
260         ret
261 PSEUDO_END (strcat)