2006-02-24 Roland McGrath <roland@redhat.com>
[kopensolaris-gnu/glibc.git] / sysdeps / x86_64 / strlen.S
1 /* strlen(str) -- determine the length of the string STR.
2    Copyright (C) 2002, 2003 Free Software Foundation, Inc.
3    Based on i486 version contributed by Ulrich Drepper <drepper@redhat.com>.
4    This file is part of the GNU C Library.
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
27         .text
28 ENTRY (strlen)
29         movq %rdi, %rcx         /* Duplicate source pointer. */
30         andl $7, %ecx           /* mask alignment bits */
31         movq %rdi, %rax         /* duplicate destination.  */
32         jz 1f                   /* aligned => start loop */
33
34         neg %ecx                /* We need to align to 8 bytes.  */
35         addl $8,%ecx
36         /* Search the first bytes directly.  */
37 0:      cmpb $0x0,(%rax)        /* is byte NUL? */
38         je 2f                   /* yes => return */
39         incq %rax               /* increment pointer */
40         decl %ecx
41         jnz 0b
42
43 1:      movq $0xfefefefefefefeff,%r8 /* Save magic.  */
44
45         .p2align 4              /* Align loop.  */
46 4:      /* Main Loop is unrolled 4 times.  */
47         /* First unroll.  */
48         movq (%rax), %rcx       /* get double word (= 8 bytes) in question */
49         addq $8,%rax            /* adjust pointer for next word */
50         movq %r8, %rdx          /* magic value */
51         addq %rcx, %rdx         /* add the magic value to the word.  We get
52                                    carry bits reported for each byte which
53                                    is *not* 0 */
54         jnc 3f                  /* highest byte is NUL => return pointer */
55         xorq %rcx, %rdx         /* (word+magic)^word */
56         orq %r8, %rdx           /* set all non-carry bits */
57         incq %rdx               /* add 1: if one carry bit was *not* set
58                                    the addition will not result in 0.  */
59         jnz 3f                  /* found NUL => return pointer */
60
61         /* Second unroll.  */
62         movq (%rax), %rcx       /* get double word (= 8 bytes) in question */
63         addq $8,%rax            /* adjust pointer for next word */
64         movq %r8, %rdx          /* magic value */
65         addq %rcx, %rdx         /* add the magic value to the word.  We get
66                                    carry bits reported for each byte which
67                                    is *not* 0 */
68         jnc 3f                  /* highest byte is NUL => return pointer */
69         xorq %rcx, %rdx         /* (word+magic)^word */
70         orq %r8, %rdx           /* set all non-carry bits */
71         incq %rdx               /* add 1: if one carry bit was *not* set
72                                    the addition will not result in 0.  */
73         jnz 3f                  /* found NUL => return pointer */
74
75         /* Third unroll.  */
76         movq (%rax), %rcx       /* get double word (= 8 bytes) in question */
77         addq $8,%rax            /* adjust pointer for next word */
78         movq %r8, %rdx          /* magic value */
79         addq %rcx, %rdx         /* add the magic value to the word.  We get
80                                    carry bits reported for each byte which
81                                    is *not* 0 */
82         jnc 3f                  /* highest byte is NUL => return pointer */
83         xorq %rcx, %rdx         /* (word+magic)^word */
84         orq %r8, %rdx           /* set all non-carry bits */
85         incq %rdx               /* add 1: if one carry bit was *not* set
86                                    the addition will not result in 0.  */
87         jnz 3f                  /* found NUL => return pointer */
88
89         /* Fourth unroll.  */
90         movq (%rax), %rcx       /* get double word (= 8 bytes) in question */
91         addq $8,%rax            /* adjust pointer for next word */
92         movq %r8, %rdx          /* magic value */
93         addq %rcx, %rdx         /* add the magic value to the word.  We get
94                                    carry bits reported for each byte which
95                                    is *not* 0 */
96         jnc 3f                  /* highest byte is NUL => return pointer */
97         xorq %rcx, %rdx         /* (word+magic)^word */
98         orq %r8, %rdx           /* set all non-carry bits */
99         incq %rdx               /* add 1: if one carry bit was *not* set
100                                    the addition will not result in 0.  */
101         jz 4b                   /* no NUL found => continue loop */
102
103         .p2align 4              /* Align, it's a jump target.  */
104 3:      subq $8,%rax            /* correct pointer increment.  */
105
106         testb %cl, %cl          /* is first byte NUL? */
107         jz 2f                   /* yes => return */
108         incq %rax               /* increment pointer */
109
110         testb %ch, %ch          /* is second byte NUL? */
111         jz 2f                   /* yes => return */
112         incq %rax               /* increment pointer */
113
114         testl $0x00ff0000, %ecx /* is third byte NUL? */
115         jz 2f                   /* yes => return pointer */
116         incq %rax               /* increment pointer */
117
118         testl $0xff000000, %ecx /* is fourth byte NUL? */
119         jz 2f                   /* yes => return pointer */
120         incq %rax               /* increment pointer */
121
122         shrq $32, %rcx          /* look at other half.  */
123
124         testb %cl, %cl          /* is first byte NUL? */
125         jz 2f                   /* yes => return */
126         incq %rax               /* increment pointer */
127
128         testb %ch, %ch          /* is second byte NUL? */
129         jz 2f                   /* yes => return */
130         incq %rax               /* increment pointer */
131
132         testl $0xff0000, %ecx   /* is third byte NUL? */
133         jz 2f                   /* yes => return pointer */
134         incq %rax               /* increment pointer */
135 2:
136         subq %rdi, %rax         /* compute difference to string start */
137         ret
138 END (strlen)
139 libc_hidden_builtin_def (strlen)