]> git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/i386/i586/strlen.S
update from main archive 961016
[thirdparty/glibc.git] / sysdeps / i386 / i586 / strlen.S
1 /* strlen -- Compute length og NUL terminated string.
2 Highly optimized version for ix86, x>=5.
3 Copyright (C) 1995, 1996 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
5 Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
6
7 The GNU C Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 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 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public
18 License along with the GNU C Library; see the file COPYING.LIB. If
19 not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22 #include <sysdep.h>
23
24 /* This version is especially optimized for the i586 (and following?)
25 processors. This is mainly done by using the two pipelines. The
26 version optimized for i486 is weak in this aspect because to get
27 as much parallelism we have to executs some *more* instructions.
28
29 The code below is structured to reflect the pairing of the instructions
30 as *I think* it is. I have no processor data book to verify this.
31 If you find something you think is incorrect let me know. */
32
33
34 /* The magic value which is used throughout in the whole code. */
35 #define magic 0xfefefeff
36
37 /*
38 INPUT PARAMETERS:
39 str (sp + 4)
40 */
41
42 .text
43 ENTRY(strlen)
44 movl 4(%esp), %eax /* get string pointer */
45 movl $3, %edx /* load mask (= 3) */
46
47 andl %eax, %edx /* separate last two bits of address */
48
49 jz L1 /* aligned => start loop */
50 jp L0 /* exactly two bits set */
51
52 cmpb %dh, (%eax) /* is byte NUL? */
53 je L2 /* yes => return */
54
55 incl %eax /* increment pointer */
56 cmpb %dh, (%eax) /* is byte NUL? */
57
58 je L2 /* yes => return */
59
60 incl %eax /* increment pointer */
61 xorl $2, %edx
62
63 jz L1
64
65 L0: cmpb %dh, (%eax) /* is byte NUL? */
66 je L2 /* yes => return */
67
68 incl %eax /* increment pointer */
69 xorl %edx, %edx /* We need %edx == 0 for later */
70
71 /* We exit the loop if adding MAGIC_BITS to LONGWORD fails to
72 change any of the hole bits of LONGWORD.
73
74 1) Is this safe? Will it catch all the zero bytes?
75 Suppose there is a byte with all zeros. Any carry bits
76 propagating from its left will fall into the hole at its
77 least significant bit and stop. Since there will be no
78 carry from its most significant bit, the LSB of the
79 byte to the left will be unchanged, and the zero will be
80 detected.
81
82 2) Is this worthwhile? Will it ignore everything except
83 zero bytes? Suppose every byte of LONGWORD has a bit set
84 somewhere. There will be a carry into bit 8. If bit 8
85 is set, this will carry into bit 16. If bit 8 is clear,
86 one of bits 9-15 must be set, so there will be a carry
87 into bit 16. Similarly, there will be a carry into bit
88 24. If one of bits 24-31 is set, there will be a carry
89 into bit 32 (=carry flag), so all of the hole bits will
90 be changed.
91
92 Note: %edx == 0 in any case here. */
93
94 L1:
95 movl (%eax), %ecx /* get word (= 4 bytes) in question */
96 addl $4, %eax /* adjust pointer for *next* word */
97
98 subl %ecx, %edx /* first step to negate word */
99 addl $magic, %ecx /* add magic word */
100
101 decl %edx /* complete negation of word */
102 jnc L3 /* previous addl caused overflow? */
103
104 xorl %ecx, %edx /* (word+magic)^word */
105
106 andl $~magic, %edx /* any of the carry flags set? */
107
108 jne L3 /* yes => determine byte */
109
110
111 movl (%eax), %ecx /* get word (= 4 bytes) in question */
112 addl $4, %eax /* adjust pointer for *next* word */
113
114 subl %ecx, %edx /* first step to negate word */
115 addl $magic, %ecx /* add magic word */
116
117 decl %edx /* complete negation of word */
118 jnc L3 /* previous addl caused overflow? */
119
120 xorl %ecx, %edx /* (word+magic)^word */
121
122 andl $~magic, %edx /* any of the carry flags set? */
123
124 jne L3 /* yes => determine byte */
125
126
127 movl (%eax), %ecx /* get word (= 4 bytes) in question */
128 addl $4, %eax /* adjust pointer for *next* word */
129
130 subl %ecx, %edx /* first step to negate word */
131 addl $magic, %ecx /* add magic word */
132
133 decl %edx /* complete negation of word */
134 jnc L3 /* previous addl caused overflow? */
135
136 xorl %ecx, %edx /* (word+magic)^word */
137
138 andl $~magic, %edx /* any of the carry flags set? */
139
140 jne L3 /* yes => determine byte */
141
142
143 movl (%eax), %ecx /* get word (= 4 bytes) in question */
144 addl $4, %eax /* adjust pointer for *next* word */
145
146 subl %ecx, %edx /* first step to negate word */
147 addl $magic, %ecx /* add magic word */
148
149 decl %edx /* complete negation of word */
150 jnc L3 /* previous addl caused overflow? */
151
152 xorl %ecx, %edx /* (word+magic)^word */
153
154 andl $~magic, %edx /* any of the carry flags set? */
155
156 je L1 /* no => start loop again */
157
158
159 L3: subl $4, %eax /* correct too early pointer increment */
160 subl $magic, %ecx
161
162 cmpb $0, %cl /* lowest byte NUL? */
163 jz L2 /* yes => return */
164
165 inc %eax /* increment pointer */
166 testb %ch, %ch /* second byte NUL? */
167
168 jz L2 /* yes => return */
169
170 shrl $16, %ecx /* make upper bytes accessible */
171 incl %eax /* increment pointer */
172
173 cmpb $0, %cl /* is third byte NUL? */
174 jz L2 /* yes => return */
175
176 incl %eax /* increment pointer */
177
178 L2: subl 4(%esp), %eax /* now compute the length as difference
179 between start and terminating NUL
180 character */
181
182 ret
183 PSEUDO_END (strlen)