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