1/* strcspn (str, ss) -- Return the length of the initial segment of STR
2			which contains only characters from SS.
3   For Intel 80x86, x>=3.
4   Copyright (C) 1994-2022 Free Software Foundation, Inc.
5   This file is part of the GNU C Library.
6
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.
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   Lesser General Public License for more details.
16
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/>.  */
20
21#include <sysdep.h>
22#include "asm-syntax.h"
23
24#define PARMS	4		/* no space for saved regs */
25#define STR	PARMS
26#define SKIP	STR+4
27
28	.text
29ENTRY (strspn)
30
31	movl STR(%esp), %edx
32	movl SKIP(%esp), %eax
33
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 !!! */
40
41	pushl %ecx		/* make a 256 bytes long block filled with 0 */
42	cfi_adjust_cfa_offset (4)
43	pushl %ecx
44	cfi_adjust_cfa_offset (4)
45	pushl %ecx
46	cfi_adjust_cfa_offset (4)
47	pushl %ecx
48	cfi_adjust_cfa_offset (4)
49	pushl %ecx
50	cfi_adjust_cfa_offset (4)
51	pushl %ecx
52	cfi_adjust_cfa_offset (4)
53	pushl %ecx
54	cfi_adjust_cfa_offset (4)
55	pushl %ecx
56	cfi_adjust_cfa_offset (4)
57	pushl %ecx
58	cfi_adjust_cfa_offset (4)
59	pushl %ecx
60	cfi_adjust_cfa_offset (4)
61	pushl %ecx
62	cfi_adjust_cfa_offset (4)
63	pushl %ecx
64	cfi_adjust_cfa_offset (4)
65	pushl %ecx
66	cfi_adjust_cfa_offset (4)
67	pushl %ecx
68	cfi_adjust_cfa_offset (4)
69	pushl %ecx
70	cfi_adjust_cfa_offset (4)
71	pushl %ecx
72	cfi_adjust_cfa_offset (4)
73	pushl %ecx
74	cfi_adjust_cfa_offset (4)
75	pushl %ecx
76	cfi_adjust_cfa_offset (4)
77	pushl %ecx
78	cfi_adjust_cfa_offset (4)
79	pushl %ecx
80	cfi_adjust_cfa_offset (4)
81	pushl %ecx
82	cfi_adjust_cfa_offset (4)
83	pushl %ecx
84	cfi_adjust_cfa_offset (4)
85	pushl %ecx
86	cfi_adjust_cfa_offset (4)
87	pushl %ecx
88	cfi_adjust_cfa_offset (4)
89	pushl %ecx
90	cfi_adjust_cfa_offset (4)
91	pushl %ecx
92	cfi_adjust_cfa_offset (4)
93	pushl %ecx
94	cfi_adjust_cfa_offset (4)
95	pushl %ecx
96	cfi_adjust_cfa_offset (4)
97	pushl %ecx
98	cfi_adjust_cfa_offset (4)
99	pushl %ecx
100	cfi_adjust_cfa_offset (4)
101	pushl %ecx
102	cfi_adjust_cfa_offset (4)
103	pushl %ecx
104	cfi_adjust_cfa_offset (4)
105	pushl %ecx
106	cfi_adjust_cfa_offset (4)
107	pushl %ecx
108	cfi_adjust_cfa_offset (4)
109	pushl %ecx
110	cfi_adjust_cfa_offset (4)
111	pushl %ecx
112	cfi_adjust_cfa_offset (4)
113	pushl %ecx
114	cfi_adjust_cfa_offset (4)
115	pushl %ecx
116	cfi_adjust_cfa_offset (4)
117	pushl %ecx
118	cfi_adjust_cfa_offset (4)
119	pushl %ecx
120	cfi_adjust_cfa_offset (4)
121	pushl %ecx
122	cfi_adjust_cfa_offset (4)
123	pushl %ecx
124	cfi_adjust_cfa_offset (4)
125	pushl %ecx
126	cfi_adjust_cfa_offset (4)
127	pushl %ecx
128	cfi_adjust_cfa_offset (4)
129	pushl %ecx
130	cfi_adjust_cfa_offset (4)
131	pushl %ecx
132	cfi_adjust_cfa_offset (4)
133	pushl %ecx
134	cfi_adjust_cfa_offset (4)
135	pushl %ecx
136	cfi_adjust_cfa_offset (4)
137	pushl %ecx
138	cfi_adjust_cfa_offset (4)
139	pushl %ecx
140	cfi_adjust_cfa_offset (4)
141	pushl %ecx
142	cfi_adjust_cfa_offset (4)
143	pushl %ecx
144	cfi_adjust_cfa_offset (4)
145	pushl %ecx
146	cfi_adjust_cfa_offset (4)
147	pushl %ecx
148	cfi_adjust_cfa_offset (4)
149	pushl %ecx
150	cfi_adjust_cfa_offset (4)
151	pushl %ecx
152	cfi_adjust_cfa_offset (4)
153	pushl %ecx
154	cfi_adjust_cfa_offset (4)
155	pushl %ecx
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)
163	pushl $0
164	cfi_adjust_cfa_offset (4)
165	pushl $0
166	cfi_adjust_cfa_offset (4)
167	pushl $0
168	cfi_adjust_cfa_offset (4)
169
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.  */
173
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.  */
176
177L(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 */
181
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 */
186
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 */
191
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 */
197
198L(1):	leal -4(%edx), %eax	/* prepare loop */
199
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
203	   and
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.  */
208
209L(3):	addl $4, %eax		/* adjust pointer for full loop round */
210
211	movb (%eax), %cl	/* get byte from string */
212	testb %cl, (%esp,%ecx)	/* is it contained in skipset? */
213	jz L(4)			/* no => return */
214
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 */
218
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 */
222
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 */
226
227	incl %eax		/* adjust pointer */
228L(6):	incl %eax
229L(5):	incl %eax
230
231L(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 */
236	ret
237END (strspn)
238libc_hidden_builtin_def (strspn)
239