]> git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/i386/strcspn.S
Update.
[thirdparty/glibc.git] / sysdeps / i386 / strcspn.S
1 /* strcspn (str, ss) -- Return the length of the initial segment of STR
2 which contains no characters from SS.
3 For Intel 80x86, x>=3.
4 Copyright (C) 1994,1995,1996,1997,2000,2003 Free Software Foundation, Inc.
5 This file is part of the GNU C Library.
6 Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>
7 Bug fixes by Alan Modra <Alan@SPRI.Levels.UniSA.Edu.Au>
8
9 The GNU C Library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Lesser General Public
11 License as published by the Free Software Foundation; either
12 version 2.1 of the License, or (at your option) any later version.
13
14 The GNU C Library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public
20 License along with the GNU C Library; if not, write to the Free
21 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
22 02111-1307 USA. */
23
24 #include <sysdep.h>
25 #include "asm-syntax.h"
26 #include "bp-sym.h"
27 #include "bp-asm.h"
28
29 #define PARMS LINKAGE /* no space for saved regs */
30 #define STR PARMS
31 #define STOP STR+PTR_SIZE
32
33 .text
34 ENTRY (BP_SYM (strcspn))
35 ENTER
36
37 movl STR(%esp), %edx
38 movl STOP(%esp), %eax
39 CHECK_BOUNDS_LOW (%edx, STR(%esp))
40
41 /* First we create a table with flags for all possible characters.
42 For the ASCII (7bit/8bit) or ISO-8859-X character sets which are
43 supported by the C string functions we have 256 characters.
44 Before inserting marks for the stop characters we clear the whole
45 table. The unrolled form is much faster than a loop. */
46 xorl %ecx, %ecx /* %ecx = 0 !!! */
47
48 pushl %ecx /* make a 256 bytes long block filled with 0 */
49 pushl %ecx
50 pushl %ecx
51 pushl %ecx
52 pushl %ecx
53 pushl %ecx
54 pushl %ecx
55 pushl %ecx
56 pushl %ecx
57 pushl %ecx
58 pushl %ecx
59 pushl %ecx
60 pushl %ecx
61 pushl %ecx
62 pushl %ecx
63 pushl %ecx
64 pushl %ecx
65 pushl %ecx
66 pushl %ecx
67 pushl %ecx
68 pushl %ecx
69 pushl %ecx
70 pushl %ecx
71 pushl %ecx
72 pushl %ecx
73 pushl %ecx
74 pushl %ecx
75 pushl %ecx
76 pushl %ecx
77 pushl %ecx
78 pushl %ecx
79 pushl %ecx
80 pushl %ecx
81 pushl %ecx
82 pushl %ecx
83 pushl %ecx
84 pushl %ecx
85 pushl %ecx
86 pushl %ecx
87 pushl %ecx
88 pushl %ecx
89 pushl %ecx
90 pushl %ecx
91 pushl %ecx
92 pushl %ecx
93 pushl %ecx
94 pushl %ecx
95 pushl %ecx
96 pushl %ecx
97 pushl %ecx
98 pushl %ecx
99 pushl %ecx
100 pushl %ecx
101 pushl %ecx
102 pushl %ecx
103 pushl %ecx
104 pushl %ecx
105 pushl %ecx
106 pushl $0 /* These immediate values make the label 2 */
107 pushl $0 /* to be aligned on a 16 byte boundary to */
108 pushl $0 /* get a better performance of the loop. */
109 pushl $0
110 pushl $0
111 pushl $0
112
113 /* For understanding the following code remember that %ecx == 0 now.
114 Although all the following instruction only modify %cl we always
115 have a correct zero-extended 32-bit value in %ecx. */
116
117 /* Don't change the "testb $0xff,%%cl" to "testb %%cl,%%cl". We want
118 longer instructions so that the next loop aligns without adding nops. */
119
120 L(2): movb (%eax), %cl /* get byte from stopset */
121 testb %cl, %cl /* is NUL char? */
122 jz L(1) /* yes => start compare loop */
123 movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */
124
125 movb 1(%eax), %cl /* get byte from stopset */
126 testb $0xff, %cl /* is NUL char? */
127 jz L(1) /* yes => start compare loop */
128 movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */
129
130 movb 2(%eax), %cl /* get byte from stopset */
131 testb $0xff, %cl /* is NUL char? */
132 jz L(1) /* yes => start compare loop */
133 movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */
134
135 movb 3(%eax), %cl /* get byte from stopset */
136 addl $4, %eax /* increment stopset pointer */
137 movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */
138 testb $0xff, %cl /* is NUL char? */
139 jnz L(2) /* no => process next dword from stopset */
140
141 L(1): leal -4(%edx), %eax /* prepare loop */
142
143 /* We use a neat trick for the following loop. Normally we would
144 have to test for two termination conditions
145 1. a character in the stopset was found
146 and
147 2. the end of the string was found
148 But as a sign that the character is in the stopset we store its
149 value in the table. But the value of NUL is NUL so the loop
150 terminates for NUL in every case. */
151
152 L(3): addl $4, %eax /* adjust pointer for full loop round */
153
154 movb (%eax), %cl /* get byte from string */
155 cmpb %cl, (%esp,%ecx) /* is it contained in stopset? */
156 je L(4) /* yes => return */
157
158 movb 1(%eax), %cl /* get byte from string */
159 cmpb %cl, (%esp,%ecx) /* is it contained in stopset? */
160 je L(5) /* yes => return */
161
162 movb 2(%eax), %cl /* get byte from string */
163 cmpb %cl, (%esp,%ecx) /* is it contained in stopset? */
164 je L(6) /* yes => return */
165
166 movb 3(%eax), %cl /* get byte from string */
167 cmpb %cl, (%esp,%ecx) /* is it contained in stopset? */
168 jne L(3) /* yes => return */
169
170 incl %eax /* adjust pointer */
171 L(6): incl %eax
172 L(5): incl %eax
173
174 L(4): addl $256, %esp /* remove stopset */
175 CHECK_BOUNDS_HIGH (%eax, STR(%esp), jb)
176 subl %edx, %eax /* we have to return the number of valid
177 characters, so compute distance to first
178 non-valid character */
179 LEAVE
180 ret
181 END (BP_SYM (strcspn))
182 libc_hidden_builtin_def (strcspn)