Update.
[glibc/history.git] / sysdeps / i386 / strcspn.S
blobf2c53122b547f27b6053adb44da021bb1c5ffd76
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 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>
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.
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.
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 not,
21    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22    Boston, MA 02111-1307, USA.  */
24 #include <sysdep.h>
25 #include "asm-syntax.h"
28    INPUT PARAMETERS:
29    str          (sp + 4)
30    stopset      (sp + 8)
33         .text
34 ENTRY (strcspn)
35         movl 4(%esp), %edx      /* get string pointer */
36         movl 8(%esp), %eax      /* get stopset pointer */
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 !!! */
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
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.  */
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.  */
117 L(2):   movb (%eax), %cl        /* get byte from stopset */
118         testb %cl, %cl          /* is NUL char? */
119         jz L(1)                 /* yes => start compare loop */
120         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
122         movb 1(%eax), %cl       /* get byte from stopset */
123         testb $0xff, %cl        /* is NUL char? */
124         jz L(1)                 /* yes => start compare loop */
125         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
127         movb 2(%eax), %cl       /* get byte from stopset */
128         testb $0xff, %cl        /* is NUL char? */
129         jz L(1)                 /* yes => start compare loop */
130         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
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 L(2)                /* no => process next dword from stopset */
138 L(1):   leal -4(%edx), %eax     /* prepare loop */
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 character 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.  */
149 L(3):   addl $4, %eax           /* adjust pointer for full loop round */
151         movb (%eax), %cl        /* get byte from string */
152         cmpb %cl, (%esp,%ecx)   /* is it contained in stopset? */
153         je L(4)                 /* yes => return */
155         movb 1(%eax), %cl       /* get byte from string */
156         cmpb %cl, (%esp,%ecx)   /* is it contained in stopset? */
157         je L(5)                 /* yes => return */
159         movb 2(%eax), %cl       /* get byte from string */
160         cmpb %cl, (%esp,%ecx)   /* is it contained in stopset? */
161         je L(6)                 /* yes => return */
163         movb 3(%eax), %cl       /* get byte from string */
164         cmpb %cl, (%esp,%ecx)   /* is it contained in stopset? */
165         jne L(3)                /* yes => return */
167         incl %eax               /* adjust pointer */
168 L(6):   incl %eax
169 L(5):   incl %eax
171 L(4):   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 */
176         ret
177 END (strcspn)