1 /* strcspn (str, ss) -- Return the length of the initial segment of STR
2 which contains only characters from SS.
4 Copyright (C) 1994-2023 Free Software Foundation, Inc.
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, see
19 <https://www.gnu.org/licenses/>. */
22 #include "asm-syntax.h"
24 #define PARMS 4 /* no space for saved regs */
34 /* First we create a table with flags for all possible characters.
35 For the ASCII (7bit/8bit) or ISO-8859-X character sets which are
36 supported by the C string functions we have 256 characters.
37 Before inserting marks for the stop characters we clear the whole
38 table. The unrolled form is much faster than a loop. */
39 xorl %ecx, %ecx /* %ecx = 0 !!! */
41 pushl %ecx /* make a 256 bytes long block filled with 0 */
42 cfi_adjust_cfa_offset (4)
44 cfi_adjust_cfa_offset (4)
46 cfi_adjust_cfa_offset (4)
48 cfi_adjust_cfa_offset (4)
50 cfi_adjust_cfa_offset (4)
52 cfi_adjust_cfa_offset (4)
54 cfi_adjust_cfa_offset (4)
56 cfi_adjust_cfa_offset (4)
58 cfi_adjust_cfa_offset (4)
60 cfi_adjust_cfa_offset (4)
62 cfi_adjust_cfa_offset (4)
64 cfi_adjust_cfa_offset (4)
66 cfi_adjust_cfa_offset (4)
68 cfi_adjust_cfa_offset (4)
70 cfi_adjust_cfa_offset (4)
72 cfi_adjust_cfa_offset (4)
74 cfi_adjust_cfa_offset (4)
76 cfi_adjust_cfa_offset (4)
78 cfi_adjust_cfa_offset (4)
80 cfi_adjust_cfa_offset (4)
82 cfi_adjust_cfa_offset (4)
84 cfi_adjust_cfa_offset (4)
86 cfi_adjust_cfa_offset (4)
88 cfi_adjust_cfa_offset (4)
90 cfi_adjust_cfa_offset (4)
92 cfi_adjust_cfa_offset (4)
94 cfi_adjust_cfa_offset (4)
96 cfi_adjust_cfa_offset (4)
98 cfi_adjust_cfa_offset (4)
100 cfi_adjust_cfa_offset (4)
102 cfi_adjust_cfa_offset (4)
104 cfi_adjust_cfa_offset (4)
106 cfi_adjust_cfa_offset (4)
108 cfi_adjust_cfa_offset (4)
110 cfi_adjust_cfa_offset (4)
112 cfi_adjust_cfa_offset (4)
114 cfi_adjust_cfa_offset (4)
116 cfi_adjust_cfa_offset (4)
118 cfi_adjust_cfa_offset (4)
120 cfi_adjust_cfa_offset (4)
122 cfi_adjust_cfa_offset (4)
124 cfi_adjust_cfa_offset (4)
126 cfi_adjust_cfa_offset (4)
128 cfi_adjust_cfa_offset (4)
130 cfi_adjust_cfa_offset (4)
132 cfi_adjust_cfa_offset (4)
134 cfi_adjust_cfa_offset (4)
136 cfi_adjust_cfa_offset (4)
138 cfi_adjust_cfa_offset (4)
140 cfi_adjust_cfa_offset (4)
142 cfi_adjust_cfa_offset (4)
144 cfi_adjust_cfa_offset (4)
146 cfi_adjust_cfa_offset (4)
148 cfi_adjust_cfa_offset (4)
150 cfi_adjust_cfa_offset (4)
152 cfi_adjust_cfa_offset (4)
154 cfi_adjust_cfa_offset (4)
156 cfi_adjust_cfa_offset (4)
157 pushl $0 /* These immediate values make the label 2 */
158 cfi_adjust_cfa_offset (4)
159 pushl $0 /* to be aligned on a 16 byte boundary to */
160 cfi_adjust_cfa_offset (4)
161 pushl $0 /* get a better performance of the loop. */
162 cfi_adjust_cfa_offset (4)
164 cfi_adjust_cfa_offset (4)
166 cfi_adjust_cfa_offset (4)
168 cfi_adjust_cfa_offset (4)
170 /* For understanding the following code remember that %ecx == 0 now.
171 Although all the following instruction only modify %cl we always
172 have a correct zero-extended 32-bit value in %ecx. */
174 /* Don't change the "testb $0xff,%%cl" to "testb %%cl,%%cl". We want
175 longer instructions so that the next loop aligns without adding nops. */
177 L(2): movb (%eax), %cl /* get byte from stopset */
178 testb %cl, %cl /* is NUL char? */
179 jz L(1) /* yes => start compare loop */
180 movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */
182 movb 1(%eax), %cl /* get byte from stopset */
183 testb $0xff, %cl /* is NUL char? */
184 jz L(1) /* yes => start compare loop */
185 movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */
187 movb 2(%eax), %cl /* get byte from stopset */
188 testb $0xff, %cl /* is NUL char? */
189 jz L(1) /* yes => start compare loop */
190 movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */
192 movb 3(%eax), %cl /* get byte from stopset */
193 addl $4, %eax /* increment stopset pointer */
194 movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */
195 testb $0xff, %cl /* is NUL char? */
196 jnz L(2) /* no => process next dword from stopset */
198 L(1): leal -4(%edx), %eax /* prepare loop */
200 /* We use a neat trick for the following loop. Normally we would
201 have to test for two termination conditions
202 1. a character in the stopset was found
204 2. the end of the string was found
205 But as a sign that the character is in the stopset we store its
206 value in the table. But the value of NUL is NUL so the loop
207 terminates for NUL in every case. */
209 L(3): addl $4, %eax /* adjust pointer for full loop round */
211 movb (%eax), %cl /* get byte from string */
212 testb %cl, (%esp,%ecx) /* is it contained in skipset? */
213 jz L(4) /* no => return */
215 movb 1(%eax), %cl /* get byte from string */
216 testb %cl, (%esp,%ecx) /* is it contained in skipset? */
217 jz L(5) /* no => return */
219 movb 2(%eax), %cl /* get byte from string */
220 testb %cl, (%esp,%ecx) /* is it contained in skipset? */
221 jz L(6) /* no => return */
223 movb 3(%eax), %cl /* get byte from string */
224 testb %cl, (%esp,%ecx) /* is it contained in skipset? */
225 jnz L(3) /* yes => start loop again */
227 incl %eax /* adjust pointer */
231 L(4): addl $256, %esp /* remove stopset */
232 cfi_adjust_cfa_offset (-256)
233 subl %edx, %eax /* we have to return the number of valid
234 characters, so compute distance to first
235 non-valid character */
238 libc_hidden_builtin_def (strspn)