OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / uClibc / libc / string / x86_64 / strcpy.S
1 /* strcpy/stpcpy implementation for x86-64.
2    Copyright (C) 2002 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Andreas Jaeger <aj@suse.de>, 2002.
5
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.
10
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.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, write to the Free
18    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
20
21 #include "_glibc_inc.h"
22
23 /* Seems to be unrolled too much */
24
25 #ifndef USE_AS_STPCPY
26 # define STRCPY strcpy
27 #endif
28
29         .text
30 ENTRY (BP_SYM (STRCPY))
31         movq %rsi, %rcx         /* Source register. */
32         andl $7, %ecx           /* mask alignment bits */
33         movq %rdi, %rdx         /* Duplicate destination pointer.  */
34
35         jz 5f                   /* aligned => start loop */
36
37         neg %ecx                /* We need to align to 8 bytes.  */
38         addl $8,%ecx
39         /* Search the first bytes directly.  */
40 0:
41         movb    (%rsi), %al     /* Fetch a byte */
42         testb   %al, %al        /* Is it NUL? */
43         movb    %al, (%rdx)     /* Store it */
44         jz      4f              /* If it was NUL, done! */
45         incq    %rsi
46         incq    %rdx
47         decl    %ecx
48         jnz     0b
49
50 5:
51         movq $0xfefefefefefefeff,%r8
52
53         /* Now the sources is aligned.  Unfortunatly we cannot force
54            to have both source and destination aligned, so ignore the
55            alignment of the destination.  */
56
57         /* Next 3 insns are 10 bytes total, make sure we decode them in one go */
58         .p2align 4,,10
59 1:
60         /* 1st unroll.  */
61         movq    (%rsi), %rax    /* Read double word (8 bytes).  */
62         addq    $8, %rsi        /* Adjust pointer for next word.  */
63         movq    %rax, %r9       /* Save a copy for NUL finding.  */
64         addq    %r8, %r9        /* add the magic value to the word.  We get
65                                    carry bits reported for each byte which
66                                    is *not* 0 */
67         jnc     3f              /* highest byte is NUL => return pointer */
68         xorq    %rax, %r9       /* (word+magic)^word */
69         orq     %r8, %r9        /* set all non-carry bits */
70         incq    %r9             /* add 1: if one carry bit was *not* set
71                                    the addition will not result in 0.  */
72
73         jnz     3f              /* found NUL => return pointer */
74
75         movq    %rax, (%rdx)    /* Write value to destination.  */
76         addq    $8, %rdx        /* Adjust pointer.  */
77
78         /* 2nd unroll.  */
79         movq    (%rsi), %rax    /* Read double word (8 bytes).  */
80         addq    $8, %rsi        /* Adjust pointer for next word.  */
81         movq    %rax, %r9       /* Save a copy for NUL finding.  */
82         addq    %r8, %r9        /* add the magic value to the word.  We get
83                                    carry bits reported for each byte which
84                                    is *not* 0 */
85         jnc     3f              /* highest byte is NUL => return pointer */
86         xorq    %rax, %r9       /* (word+magic)^word */
87         orq     %r8, %r9        /* set all non-carry bits */
88         incq    %r9             /* add 1: if one carry bit was *not* set
89                                    the addition will not result in 0.  */
90
91         jnz     3f              /* found NUL => return pointer */
92
93         movq    %rax, (%rdx)    /* Write value to destination.  */
94         addq    $8, %rdx        /* Adjust pointer.  */
95
96         /* 3rd unroll.  */
97         movq    (%rsi), %rax    /* Read double word (8 bytes).  */
98         addq    $8, %rsi        /* Adjust pointer for next word.  */
99         movq    %rax, %r9       /* Save a copy for NUL finding.  */
100         addq    %r8, %r9        /* add the magic value to the word.  We get
101                                    carry bits reported for each byte which
102                                    is *not* 0 */
103         jnc     3f              /* highest byte is NUL => return pointer */
104         xorq    %rax, %r9       /* (word+magic)^word */
105         orq     %r8, %r9        /* set all non-carry bits */
106         incq    %r9             /* add 1: if one carry bit was *not* set
107                                    the addition will not result in 0.  */
108
109         jnz     3f              /* found NUL => return pointer */
110
111         movq    %rax, (%rdx)    /* Write value to destination.  */
112         addq    $8, %rdx        /* Adjust pointer.  */
113
114         /* 4th unroll.  */
115         movq    (%rsi), %rax    /* Read double word (8 bytes).  */
116         addq    $8, %rsi        /* Adjust pointer for next word.  */
117         movq    %rax, %r9       /* Save a copy for NUL finding.  */
118         addq    %r8, %r9        /* add the magic value to the word.  We get
119                                    carry bits reported for each byte which
120                                    is *not* 0 */
121         jnc     3f              /* highest byte is NUL => return pointer */
122         xorq    %rax, %r9       /* (word+magic)^word */
123         orq     %r8, %r9        /* set all non-carry bits */
124         incq    %r9             /* add 1: if one carry bit was *not* set
125                                    the addition will not result in 0.  */
126
127         jnz     3f              /* found NUL => return pointer */
128
129         movq    %rax, (%rdx)    /* Write value to destination.  */
130         addq    $8, %rdx        /* Adjust pointer.  */
131         jmp     1b              /* Next iteration.  */
132
133         /* Do the last few bytes. %rax contains the value to write.
134            The loop is unrolled twice.  */
135
136         /* Next 3 insns are 6 bytes total, make sure we decode them in one go */
137         .p2align 3,,6
138 3:
139         /* Note that stpcpy needs to return with the value of the NUL
140            byte.  */
141         movb    %al, (%rdx)     /* 1st byte.  */
142         testb   %al, %al        /* Is it NUL.  */
143         jz      4f              /* yes, finish.  */
144         incq    %rdx            /* Increment destination.  */
145         movb    %ah, (%rdx)     /* 2nd byte.  */
146         testb   %ah, %ah        /* Is it NUL?.  */
147         jz      4f              /* yes, finish.  */
148         incq    %rdx            /* Increment destination.  */
149         shrq    $16, %rax       /* Shift...  */
150         jmp     3b              /* and look at next two bytes in %rax.  */
151
152 4:
153 #ifdef USE_AS_STPCPY
154         movq    %rdx, %rax      /* Destination is return value.  */
155 #else
156         movq    %rdi, %rax      /* Source is return value.  */
157 #endif
158         retq
159 END (BP_SYM (STRCPY))
160 #ifndef USE_AS_STPCPY
161 libc_hidden_def(strcpy)
162 #endif