OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / uClibc / libc / string / x86_64 / strcat.S
1 /* strcat(dest, src) -- Append SRC on the end of DEST.
2    Optimized for x86-64.
3    Copyright (C) 2002 Free Software Foundation, Inc.
4    This file is part of the GNU C Library.
5    Contributed by Andreas Jaeger <aj@suse.de>, 2002.
6
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.
11
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.
16
17    You should have received a copy of the GNU Lesser General Public
18    License along with the GNU C Library; if not, write to the Free
19    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20    02111-1307 USA.  */
21
22 #include "_glibc_inc.h"
23
24 /* Seems to be unrolled too much */
25
26         .text
27 ENTRY (BP_SYM (strcat))
28         movq %rdi, %rcx         /* Dest. register. */
29         andl $7, %ecx           /* mask alignment bits */
30         movq %rdi, %rax         /* Duplicate destination pointer.  */
31         movq $0xfefefefefefefeff,%r8
32
33         /* First step: Find end of destination.  */
34         jz 4f                   /* aligned => start loop */
35
36         neg %ecx                /* We need to align to 8 bytes.  */
37         addl $8,%ecx
38         /* Search the first bytes directly.  */
39 0:      cmpb $0x0,(%rax)        /* is byte NUL? */
40         je 2f                   /* yes => start copy */
41         incq %rax               /* increment pointer */
42         decl %ecx
43         jnz 0b
44
45
46
47         /* Now the source is aligned.  Scan for NUL byte.  */
48
49         /* Next 3 insns are 10 bytes total, make sure we decode them in one go */
50         .p2align 4,,10
51 4:
52         /* First unroll.  */
53         movq (%rax), %rcx       /* get double word (= 8 bytes) in question */
54         addq $8,%rax            /* adjust pointer for next word */
55         movq %r8, %rdx          /* magic value */
56         addq %rcx, %rdx         /* add the magic value to the word.  We get
57                                    carry bits reported for each byte which
58                                    is *not* 0 */
59         jnc 3f                  /* highest byte is NUL => return pointer */
60         xorq %rcx, %rdx         /* (word+magic)^word */
61         orq %r8, %rdx           /* set all non-carry bits */
62         incq %rdx               /* add 1: if one carry bit was *not* set
63                                    the addition will not result in 0.  */
64         jnz 3f                  /* found NUL => return pointer */
65
66         /* Second unroll.  */
67         movq (%rax), %rcx       /* get double word (= 8 bytes) in question */
68         addq $8,%rax            /* adjust pointer for next word */
69         movq %r8, %rdx          /* magic value */
70         addq %rcx, %rdx         /* add the magic value to the word.  We get
71                                    carry bits reported for each byte which
72                                    is *not* 0 */
73         jnc 3f                  /* highest byte is NUL => return pointer */
74         xorq %rcx, %rdx         /* (word+magic)^word */
75         orq %r8, %rdx           /* set all non-carry bits */
76         incq %rdx               /* add 1: if one carry bit was *not* set
77                                    the addition will not result in 0.  */
78         jnz 3f                  /* found NUL => return pointer */
79
80         /* Third unroll.  */
81         movq (%rax), %rcx       /* get double word (= 8 bytes) in question */
82         addq $8,%rax            /* adjust pointer for next word */
83         movq %r8, %rdx          /* magic value */
84         addq %rcx, %rdx         /* add the magic value to the word.  We get
85                                    carry bits reported for each byte which
86                                    is *not* 0 */
87         jnc 3f                  /* highest byte is NUL => return pointer */
88         xorq %rcx, %rdx         /* (word+magic)^word */
89         orq %r8, %rdx           /* set all non-carry bits */
90         incq %rdx               /* add 1: if one carry bit was *not* set
91                                    the addition will not result in 0.  */
92         jnz 3f                  /* found NUL => return pointer */
93
94         /* Fourth unroll.  */
95         movq (%rax), %rcx       /* get double word (= 8 bytes) in question */
96         addq $8,%rax            /* adjust pointer for next word */
97         movq %r8, %rdx          /* magic value */
98         addq %rcx, %rdx         /* add the magic value to the word.  We get
99                                    carry bits reported for each byte which
100                                    is *not* 0 */
101         jnc 3f                  /* highest byte is NUL => return pointer */
102         xorq %rcx, %rdx         /* (word+magic)^word */
103         orq %r8, %rdx           /* set all non-carry bits */
104         incq %rdx               /* add 1: if one carry bit was *not* set
105                                    the addition will not result in 0.  */
106         jz 4b                   /* no NUL found => continue loop */
107
108         /* Align, it is a jump target.  */
109         /* Next 3 insns are 8 bytes total, make sure we decode them in one go */
110         .p2align 3,,8
111 3:
112         subq $8,%rax            /* correct pointer increment.  */
113
114         testb %cl, %cl          /* is first byte NUL? */
115         jz 2f                   /* yes => return */
116         incq %rax               /* increment pointer */
117
118         testb %ch, %ch          /* is second byte NUL? */
119         jz 2f                   /* yes => return */
120         incq %rax               /* increment pointer */
121
122         testl $0x00ff0000, %ecx /* is third byte NUL? */
123         jz 2f                   /* yes => return pointer */
124         incq %rax               /* increment pointer */
125
126         testl $0xff000000, %ecx /* is fourth byte NUL? */
127         jz 2f                   /* yes => return pointer */
128         incq %rax               /* increment pointer */
129
130         shrq $32, %rcx          /* look at other half.  */
131
132         testb %cl, %cl          /* is first byte NUL? */
133         jz 2f                   /* yes => return */
134         incq %rax               /* increment pointer */
135
136         testb %ch, %ch          /* is second byte NUL? */
137         jz 2f                   /* yes => return */
138         incq %rax               /* increment pointer */
139
140         testl $0xff0000, %ecx   /* is third byte NUL? */
141         jz 2f                   /* yes => return pointer */
142         incq %rax               /* increment pointer */
143
144 2:
145         /* Second step: Copy source to destination.  */
146
147         movq    %rsi, %rcx      /* duplicate  */
148         andl    $7,%ecx         /* mask alignment bits */
149         movq    %rax, %rdx      /* move around */
150         jz      22f             /* aligned => start loop */
151
152         neg     %ecx            /* align to 8 bytes.  */
153         addl    $8, %ecx
154         /* Align the source pointer.  */
155 21:
156         movb    (%rsi), %al     /* Fetch a byte */
157         testb   %al, %al        /* Is it NUL? */
158         movb    %al, (%rdx)     /* Store it */
159         jz      24f             /* If it was NUL, done! */
160         incq    %rsi
161         incq    %rdx
162         decl    %ecx
163         jnz     21b
164
165         /* Now the sources is aligned.  Unfortunatly we cannot force
166            to have both source and destination aligned, so ignore the
167            alignment of the destination.  */
168
169         /* Next 3 insns are 10 bytes total, make sure we decode them in one go */
170         .p2align 4,,10
171 22:
172         /* 1st unroll.  */
173         movq    (%rsi), %rax    /* Read double word (8 bytes).  */
174         addq    $8, %rsi        /* Adjust pointer for next word.  */
175         movq    %rax, %r9       /* Save a copy for NUL finding.  */
176         addq    %r8, %r9        /* add the magic value to the word.  We get
177                                    carry bits reported for each byte which
178                                    is *not* 0 */
179         jnc     23f             /* highest byte is NUL => return pointer */
180         xorq    %rax, %r9       /* (word+magic)^word */
181         orq     %r8, %r9        /* set all non-carry bits */
182         incq    %r9             /* add 1: if one carry bit was *not* set
183                                    the addition will not result in 0.  */
184
185         jnz     23f             /* found NUL => return pointer */
186
187         movq    %rax, (%rdx)    /* Write value to destination.  */
188         addq    $8, %rdx        /* Adjust pointer.  */
189
190         /* 2nd unroll.  */
191         movq    (%rsi), %rax    /* Read double word (8 bytes).  */
192         addq    $8, %rsi        /* Adjust pointer for next word.  */
193         movq    %rax, %r9       /* Save a copy for NUL finding.  */
194         addq    %r8, %r9        /* add the magic value to the word.  We get
195                                    carry bits reported for each byte which
196                                    is *not* 0 */
197         jnc     23f             /* highest byte is NUL => return pointer */
198         xorq    %rax, %r9       /* (word+magic)^word */
199         orq     %r8, %r9        /* set all non-carry bits */
200         incq    %r9             /* add 1: if one carry bit was *not* set
201                                    the addition will not result in 0.  */
202
203         jnz     23f             /* found NUL => return pointer */
204
205         movq    %rax, (%rdx)    /* Write value to destination.  */
206         addq    $8, %rdx        /* Adjust pointer.  */
207
208         /* 3rd unroll.  */
209         movq    (%rsi), %rax    /* Read double word (8 bytes).  */
210         addq    $8, %rsi        /* Adjust pointer for next word.  */
211         movq    %rax, %r9       /* Save a copy for NUL finding.  */
212         addq    %r8, %r9        /* add the magic value to the word.  We get
213                                    carry bits reported for each byte which
214                                    is *not* 0 */
215         jnc     23f             /* highest byte is NUL => return pointer */
216         xorq    %rax, %r9       /* (word+magic)^word */
217         orq     %r8, %r9        /* set all non-carry bits */
218         incq    %r9             /* add 1: if one carry bit was *not* set
219                                    the addition will not result in 0.  */
220
221         jnz     23f             /* found NUL => return pointer */
222
223         movq    %rax, (%rdx)    /* Write value to destination.  */
224         addq    $8, %rdx        /* Adjust pointer.  */
225
226         /* 4th unroll.  */
227         movq    (%rsi), %rax    /* Read double word (8 bytes).  */
228         addq    $8, %rsi        /* Adjust pointer for next word.  */
229         movq    %rax, %r9       /* Save a copy for NUL finding.  */
230         addq    %r8, %r9        /* add the magic value to the word.  We get
231                                    carry bits reported for each byte which
232                                    is *not* 0 */
233         jnc     23f             /* highest byte is NUL => return pointer */
234         xorq    %rax, %r9       /* (word+magic)^word */
235         orq     %r8, %r9        /* set all non-carry bits */
236         incq    %r9             /* add 1: if one carry bit was *not* set
237                                    the addition will not result in 0.  */
238
239         jnz     23f             /* found NUL => return pointer */
240
241         movq    %rax, (%rdx)    /* Write value to destination.  */
242         addq    $8, %rdx        /* Adjust pointer.  */
243         jmp     22b             /* Next iteration.  */
244
245         /* Do the last few bytes. %rax contains the value to write.
246            The loop is unrolled twice.  */
247
248         /* Next 3 insns are 6 bytes total, make sure we decode them in one go */
249         .p2align 3,,6
250 23:
251         movb    %al, (%rdx)     /* 1st byte.  */
252         testb   %al, %al        /* Is it NUL.  */
253         jz      24f             /* yes, finish.  */
254         incq    %rdx            /* Increment destination.  */
255         movb    %ah, (%rdx)     /* 2nd byte.  */
256         testb   %ah, %ah        /* Is it NUL?.  */
257         jz      24f             /* yes, finish.  */
258         incq    %rdx            /* Increment destination.  */
259         shrq    $16, %rax       /* Shift...  */
260         jmp     23b             /* and look at next two bytes in %rax.  */
261
262
263 24:
264         movq    %rdi, %rax      /* Source is return value.  */
265         retq
266 END (BP_SYM (strcat))
267
268 libc_hidden_def(strcat)