* sysdeps/unix/sysv/linux/dl-sysdep.h: Use __ASSEMBLER__ instead
[glibc.git] / sysdeps / i386 / i486 / strlen.S
blob7557b2d2176470d075df89802a9393f6d1ca3b4a
1 /* strlen(str) -- determine the length of the string STR.
2    Optimized for Intel 80x86, x>=4.
3    Copyright (C) 1991-1997, 2000, 2003 Free Software Foundation, Inc.
4    Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>.
5    This file is part of the GNU C Library.
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.
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.
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.  */
22 #include <sysdep.h>
23 #include "asm-syntax.h"
24 #include "bp-sym.h"
25 #include "bp-asm.h"
27 #define PARMS   LINKAGE         /* no space for saved regs */
28 #define STR     PARMS
30         .text
31 ENTRY (BP_SYM (strlen))
32         ENTER
34         movl STR(%esp), %ecx
35         CHECK_BOUNDS_LOW (%ecx, STR(%esp))
36         movl %ecx, %eax         /* duplicate it */
38         andl $3, %ecx           /* mask alignment bits */
39         jz L(1)                 /* aligned => start loop */
40         cmpb %ch, (%eax)        /* is byte NUL? */
41         je L(2)                 /* yes => return */
42         incl %eax               /* increment pointer */
44         xorl $3, %ecx           /* was alignment = 3? */
45         jz L(1)                 /* yes => now it is aligned and start loop */
46         cmpb %ch, (%eax)        /* is byte NUL? */
47         je L(2)                 /* yes => return */
48         addl $1, %eax           /* increment pointer */
50         subl $1, %ecx           /* was alignment = 2? */
51         jz L(1)                 /* yes => now it is aligned and start loop */
52         cmpb %ch, (%eax)        /* is byte NUL? */
53         je L(2)                 /* yes => return */
55 /* Don't change the above `addl $1,%eax' and `subl $1, %ecx' into `incl %eax'
56    and `decl %ecx' resp.  The additional two byte per instruction make the
57    label 4 to be aligned on a 16 byte boundary with nops.
59    The following `sub $15, %eax' is part of this trick, too.  Together with
60    the next instruction (`addl $16, %eax') it is in fact a `incl %eax', just
61    as expected from the algorithm.  But doing so has the advantage that
62    no jump to label 1 is necessary and so the pipeline is not flushed.  */
64         subl $15, %eax          /* effectively +1 */
67 L(4):   addl $16, %eax          /* adjust pointer for full loop */
69 L(1):   movl (%eax), %ecx       /* get word (= 4 bytes) in question */
70         movl $0xfefefeff, %edx  /* magic value */
71         addl %ecx, %edx         /* add the magic value to the word.  We get
72                                    carry bits reported for each byte which
73                                    is *not* 0 */
74         jnc L(3)                /* highest byte is NUL => return pointer */
75         xorl %ecx, %edx         /* (word+magic)^word */
76         orl $0xfefefeff, %edx   /* set all non-carry bits */
77         incl %edx               /* add 1: if one carry bit was *not* set
78                                    the addition will not result in 0.  */
79         jnz L(3)                /* found NUL => return pointer */
81         movl 4(%eax), %ecx      /* get word (= 4 bytes) in question */
82         movl $0xfefefeff, %edx  /* magic value */
83         addl %ecx, %edx         /* add the magic value to the word.  We get
84                                    carry bits reported for each byte which
85                                    is *not* 0 */
86         jnc L(5)                /* highest byte is NUL => return pointer */
87         xorl %ecx, %edx         /* (word+magic)^word */
88         orl $0xfefefeff, %edx   /* set all non-carry bits */
89         incl %edx               /* add 1: if one carry bit was *not* set
90                                    the addition will not result in 0.  */
91         jnz L(5)                /* found NUL => return pointer */
93         movl 8(%eax), %ecx      /* get word (= 4 bytes) in question */
94         movl $0xfefefeff, %edx  /* magic value */
95         addl %ecx, %edx         /* add the magic value to the word.  We get
96                                    carry bits reported for each byte which
97                                    is *not* 0 */
98         jnc L(6)                /* highest byte is NUL => return pointer */
99         xorl %ecx, %edx         /* (word+magic)^word */
100         orl $0xfefefeff, %edx   /* set all non-carry bits */
101         incl %edx               /* add 1: if one carry bit was *not* set
102                                    the addition will not result in 0.  */
103         jnz L(6)                /* found NUL => return pointer */
105         movl 12(%eax), %ecx     /* get word (= 4 bytes) in question */
106         movl $0xfefefeff, %edx  /* magic value */
107         addl %ecx, %edx         /* add the magic value to the word.  We get
108                                    carry bits reported for each byte which
109                                    is *not* 0 */
110         jnc L(7)                /* highest byte is NUL => return pointer */
111         xorl %ecx, %edx         /* (word+magic)^word */
112         orl $0xfefefeff, %edx   /* set all non-carry bits */
113         incl %edx               /* add 1: if one carry bit was *not* set
114                                    the addition will not result in 0.  */
115         jz L(4)                 /* no NUL found => continue loop */
117 L(7):   addl $4, %eax           /* adjust pointer */
118 L(6):   addl $4, %eax
119 L(5):   addl $4, %eax
121 L(3):   testb %cl, %cl          /* is first byte NUL? */
122         jz L(2)                 /* yes => return */
123         incl %eax               /* increment pointer */
125         testb %ch, %ch          /* is second byte NUL? */
126         jz L(2)                 /* yes => return */
127         incl %eax               /* increment pointer */
129         testl $0xff0000, %ecx   /* is third byte NUL? */
130         jz L(2)                 /* yes => return pointer */
131         incl %eax               /* increment pointer */
133 L(2):   CHECK_BOUNDS_HIGH (%eax, STR(%esp), jb)
134         subl STR(%esp), %eax    /* compute difference to string start */
136         LEAVE
137         ret
138 END (BP_SYM (strlen))
139 libc_hidden_builtin_def (strlen)