2006-02-24 Roland McGrath <roland@redhat.com>
[kopensolaris-gnu/glibc.git] / sysdeps / 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 <sysdep.h>
22 #include "asm-syntax.h"
23 #include "bp-sym.h"
24 #include "bp-asm.h"
25
26 #ifndef USE_AS_STPCPY
27 # define STRCPY strcpy
28 #endif
29
30         .text
31 ENTRY (BP_SYM (STRCPY))
32         movq %rsi, %rcx         /* Source register. */
33         andl $7, %ecx           /* mask alignment bits */
34         movq %rdi, %rdx         /* Duplicate destination pointer.  */
35
36         jz 5f                   /* aligned => start loop */
37
38         neg %ecx                /* We need to align to 8 bytes.  */
39         addl $8,%ecx
40         /* Search the first bytes directly.  */
41 0:
42         movb    (%rsi), %al     /* Fetch a byte */
43         testb   %al, %al        /* Is it NUL? */
44         movb    %al, (%rdx)     /* Store it */
45         jz      4f              /* If it was NUL, done! */
46         incq    %rsi
47         incq    %rdx
48         decl    %ecx
49         jnz     0b
50
51 5:
52         movq $0xfefefefefefefeff,%r8
53
54         /* Now the sources is aligned.  Unfortunatly we cannot force
55            to have both source and destination aligned, so ignore the
56            alignment of the destination.  */
57         .p2align 4
58 1:
59         /* 1st unroll.  */
60         movq    (%rsi), %rax    /* Read double word (8 bytes).  */
61         addq    $8, %rsi        /* Adjust pointer for next word.  */
62         movq    %rax, %r9       /* Save a copy for NUL finding.  */
63         addq    %r8, %r9        /* add the magic value to the word.  We get
64                                    carry bits reported for each byte which
65                                    is *not* 0 */
66         jnc     3f              /* highest byte is NUL => return pointer */
67         xorq    %rax, %r9       /* (word+magic)^word */
68         orq     %r8, %r9        /* set all non-carry bits */
69         incq    %r9             /* add 1: if one carry bit was *not* set
70                                    the addition will not result in 0.  */
71
72         jnz     3f              /* found NUL => return pointer */
73
74         movq    %rax, (%rdx)    /* Write value to destination.  */
75         addq    $8, %rdx        /* Adjust pointer.  */
76
77         /* 2nd unroll.  */
78         movq    (%rsi), %rax    /* Read double word (8 bytes).  */
79         addq    $8, %rsi        /* Adjust pointer for next word.  */
80         movq    %rax, %r9       /* Save a copy for NUL finding.  */
81         addq    %r8, %r9        /* add the magic value to the word.  We get
82                                    carry bits reported for each byte which
83                                    is *not* 0 */
84         jnc     3f              /* highest byte is NUL => return pointer */
85         xorq    %rax, %r9       /* (word+magic)^word */
86         orq     %r8, %r9        /* set all non-carry bits */
87         incq    %r9             /* add 1: if one carry bit was *not* set
88                                    the addition will not result in 0.  */
89
90         jnz     3f              /* found NUL => return pointer */
91
92         movq    %rax, (%rdx)    /* Write value to destination.  */
93         addq    $8, %rdx        /* Adjust pointer.  */
94
95         /* 3rd unroll.  */
96         movq    (%rsi), %rax    /* Read double word (8 bytes).  */
97         addq    $8, %rsi        /* Adjust pointer for next word.  */
98         movq    %rax, %r9       /* Save a copy for NUL finding.  */
99         addq    %r8, %r9        /* add the magic value to the word.  We get
100                                    carry bits reported for each byte which
101                                    is *not* 0 */
102         jnc     3f              /* highest byte is NUL => return pointer */
103         xorq    %rax, %r9       /* (word+magic)^word */
104         orq     %r8, %r9        /* set all non-carry bits */
105         incq    %r9             /* add 1: if one carry bit was *not* set
106                                    the addition will not result in 0.  */
107
108         jnz     3f              /* found NUL => return pointer */
109
110         movq    %rax, (%rdx)    /* Write value to destination.  */
111         addq    $8, %rdx        /* Adjust pointer.  */
112
113         /* 4th unroll.  */
114         movq    (%rsi), %rax    /* Read double word (8 bytes).  */
115         addq    $8, %rsi        /* Adjust pointer for next word.  */
116         movq    %rax, %r9       /* Save a copy for NUL finding.  */
117         addq    %r8, %r9        /* add the magic value to the word.  We get
118                                    carry bits reported for each byte which
119                                    is *not* 0 */
120         jnc     3f              /* highest byte is NUL => return pointer */
121         xorq    %rax, %r9       /* (word+magic)^word */
122         orq     %r8, %r9        /* set all non-carry bits */
123         incq    %r9             /* add 1: if one carry bit was *not* set
124                                    the addition will not result in 0.  */
125
126         jnz     3f              /* found NUL => return pointer */
127
128         movq    %rax, (%rdx)    /* Write value to destination.  */
129         addq    $8, %rdx        /* Adjust pointer.  */
130         jmp     1b              /* Next iteration.  */
131
132         /* Do the last few bytes. %rax contains the value to write.
133            The loop is unrolled twice.  */
134         .p2align 4
135 3:
136         /* Note that stpcpy needs to return with the value of the NUL
137            byte.  */
138         movb    %al, (%rdx)     /* 1st byte.  */
139         testb   %al, %al        /* Is it NUL.  */
140         jz      4f              /* yes, finish.  */
141         incq    %rdx            /* Increment destination.  */
142         movb    %ah, (%rdx)     /* 2nd byte.  */
143         testb   %ah, %ah        /* Is it NUL?.  */
144         jz      4f              /* yes, finish.  */
145         incq    %rdx            /* Increment destination.  */
146         shrq    $16, %rax       /* Shift...  */
147         jmp     3b              /* and look at next two bytes in %rax.  */
148
149 4:
150 #ifdef USE_AS_STPCPY
151         movq    %rdx, %rax      /* Destination is return value.  */
152 #else
153         movq    %rdi, %rax      /* Source is return value.  */
154 #endif
155         retq
156 END (BP_SYM (STRCPY))
157 #ifndef USE_AS_STPCPY
158 libc_hidden_builtin_def (strcpy)
159 #endif