Mon Jun 24 19:57:01 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
[kopensolaris-gnu/glibc.git] / sysdeps / i386 / strspn.S
1 /* strcspn (str, ss) -- Return the length of the initial segement of STR
2                         which contains only characters from SS.
3 For Intel 80x86, x>=3.
4 Copyright (C) 1994, 1995 Free Software Foundation, Inc.
5 Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>
6 Bug fixes by Alan Modra <Alan@SPRI.Levels.UniSA.Edu.Au>
7 This file is part of the GNU C Library.
8
9 The GNU C Library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Library General Public License as
11 published by the Free Software Foundation; either version 2 of the
12 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 Library General Public License for more details.
18
19 You should have received a copy of the GNU Library General Public
20 License along with the GNU C Library; see the file COPYING.LIB.  If
21 not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.  */
23
24 #include <sysdep.h>
25 #include "asm-syntax.h"
26
27 /*
28    INPUT PARAMETERS:
29    str          (sp + 4)
30    skipset      (sp + 8)
31 */
32
33         .text
34 ENTRY (strspn)
35         movl 4(%esp), %edx      /* get string pointer */
36         movl 8(%esp), %eax      /* get skipset pointer */
37
38         /* First we create a table with flags for all possible characters.
39            For the ASCII (7bit/8bit) or ISO-8859-X character sets which are
40            supported by the C string functions we have 256 characters.
41            Before inserting marks for the stop characters we clear the whole
42            table.  The unrolled form is much faster than a loop.  */
43         xorl %ecx, %ecx         /* %ecx = 0 !!! */
44
45         pushl %ecx              /* make a 256 bytes long block filled with 0 */
46         pushl %ecx
47         pushl %ecx
48         pushl %ecx
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 $0                /* These immediate values make the label 2 */
104         pushl $0                /* to be aligned on a 16 byte boundary to */
105         pushl $0                /* get a better performance of the loop.  */
106         pushl $0
107         pushl $0
108         pushl $0
109
110 /* For understanding the following code remember that %ecx == 0 now.
111    Although all the following instruction only modify %cl we always
112    have a correct zero-extended 32-bit value in %ecx.  */
113
114 /* Don't change the "testb $0xff,%%cl" to "testb %%cl,%%cl".  We want
115    longer instructions so that the next loop aligns without adding nops.  */
116
117 L2:     movb (%eax), %cl        /* get byte from stopset */
118         testb %cl, %cl          /* is NUL char? */
119         jz L1                   /* yes => start compare loop */
120         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
121
122         movb 1(%eax), %cl       /* get byte from stopset */
123         testb $0xff, %cl        /* is NUL char? */
124         jz L1                   /* yes => start compare loop */
125         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
126
127         movb 2(%eax), %cl       /* get byte from stopset */
128         testb $0xff, %cl        /* is NUL char? */
129         jz L1                   /* yes => start compare loop */
130         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
131
132         movb 3(%eax), %cl       /* get byte from stopset */
133         addl $4, %eax           /* increment stopset pointer */
134         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
135         testb $0xff, %cl        /* is NUL char? */
136         jnz L2                  /* no => process next dword from stopset */
137
138 L1:     leal -4(%edx), %eax     /* prepare loop */
139
140         /* We use a neat trick for the following loop.  Normally we would
141            have to test for two termination conditions
142            1. a character in the stopset was found
143            and
144            2. the end of the string was found
145            But as a sign that the chracter is in the stopset we store its
146            value in the table.  But the value of NUL is NUL so the loop
147            terminates for NUL in every case.  */
148
149 L3:     addl $4, %eax           /* adjust pointer for full loop round */
150
151         movb (%eax), %cl        /* get byte from string */
152         testb %cl, (%esp,%ecx)  /* is it contained in skipset? */
153         jz L4                   /* no => return */
154
155         movb 1(%eax), %cl       /* get byte from string */
156         testb %cl, (%esp,%ecx)  /* is it contained in skipset? */
157         jz L5                   /* no => return */
158
159         movb 2(%eax), %cl       /* get byte from string */
160         testb %cl, (%esp,%ecx)  /* is it contained in skipset? */
161         jz L6                   /* no => return */
162
163         movb 3(%eax), %cl       /* get byte from string */
164         testb %cl, (%esp,%ecx)  /* is it contained in skipset? */
165         jnz L3                  /* yes => start loop again */
166
167         incl %eax               /* adjust pointer */
168 L6:     incl %eax
169 L5:     incl %eax
170
171 L4:     subl %edx, %eax         /* we have to return the number of valid
172                                    characters, so compute distance to first
173                                    non-valid character */
174         addl $256, %esp         /* remove stopset */
175
176         ret