Update to LGPL v2.1.
[kopensolaris-gnu/glibc.git] / sysdeps / i386 / strspn.S
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, 1995, 1996, 1997, 2000 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 SKIP    STR+PTR_SIZE
32
33         .text
34 ENTRY (BP_SYM (strspn))
35         ENTER
36
37         movl STR(%esp), %edx
38         movl SKIP(%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         testb %cl, (%esp,%ecx)  /* is it contained in skipset? */
156         jz L(4)                 /* no => return */
157
158         movb 1(%eax), %cl       /* get byte from string */
159         testb %cl, (%esp,%ecx)  /* is it contained in skipset? */
160         jz L(5)                 /* no => return */
161
162         movb 2(%eax), %cl       /* get byte from string */
163         testb %cl, (%esp,%ecx)  /* is it contained in skipset? */
164         jz L(6)                 /* no => return */
165
166         movb 3(%eax), %cl       /* get byte from string */
167         testb %cl, (%esp,%ecx)  /* is it contained in skipset? */
168         jnz L(3)                /* yes => start loop again */
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 (strspn))