(__strncat_g): Improve last patch.
[kopensolaris-gnu/glibc.git] / sysdeps / i386 / strpbrk.S
1 /* strcspn (str, ss) -- Return the length of the initial segement of STR
2                         which contains no characters from SS.
3    For Intel 80x86, x>=3.
4    Copyright (C) 1994-1997, 2000, 2003 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 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 RTN     PARMS
31 #define STR     RTN+RTN_SIZE
32 #define STOP    STR+PTR_SIZE
33
34         .text
35 ENTRY (BP_SYM (strpbrk))
36         ENTER
37
38         movl STR(%esp), %edx
39         movl STOP(%esp), %eax
40         CHECK_BOUNDS_LOW (%edx, STR(%esp))
41
42         /* First we create a table with flags for all possible characters.
43            For the ASCII (7bit/8bit) or ISO-8859-X character sets which are
44            supported by the C string functions we have 256 characters.
45            Before inserting marks for the stop characters we clear the whole
46            table.  The unrolled form is much faster than a loop.  */
47         xorl %ecx, %ecx         /* %ecx = 0 !!! */
48
49         pushl %ecx              /* make a 256 bytes long block filled with 0 */
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 %ecx
107         pushl $0                /* These immediate values make the label 2 */
108         pushl $0                /* to be aligned on a 16 byte boundary to */
109         pushl $0                /* get a better performance of the loop.  */
110         pushl $0
111         pushl $0
112         pushl $0
113
114 /* For understanding the following code remember that %ecx == 0 now.
115    Although all the following instruction only modify %cl we always
116    have a correct zero-extended 32-bit value in %ecx.  */
117
118 /* Don't change the "testb $0xff,%%cl" to "testb %%cl,%%cl".  We want
119    longer instructions so that the next loop aligns without adding nops.  */
120
121 L(2):   movb (%eax), %cl        /* get byte from stopset */
122         testb %cl, %cl          /* is NUL char? */
123         jz L(1)                 /* yes => start compare loop */
124         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
125
126         movb 1(%eax), %cl       /* get byte from stopset */
127         testb $0xff, %cl        /* is NUL char? */
128         jz L(1)                 /* yes => start compare loop */
129         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
130
131         movb 2(%eax), %cl       /* get byte from stopset */
132         testb $0xff, %cl        /* is NUL char? */
133         jz L(1)                 /* yes => start compare loop */
134         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
135
136         movb 3(%eax), %cl       /* get byte from stopset */
137         addl $4, %eax           /* increment stopset pointer */
138         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
139         testb $0xff, %cl        /* is NUL char? */
140         jnz L(2)                /* no => process next dword from stopset */
141
142 L(1):   leal -4(%edx), %eax     /* prepare loop */
143
144         /* We use a neat trick for the following loop.  Normally we would
145            have to test for two termination conditions
146            1. a character in the stopset was found
147            and
148            2. the end of the string was found
149            But as a sign that the chracter is in the stopset we store its
150            value in the table.  But the value of NUL is NUL so the loop
151            terminates for NUL in every case.  */
152
153 L(3):   addl $4, %eax           /* adjust pointer for full loop round */
154
155         movb (%eax), %cl        /* get byte from string */
156         cmpb %cl, (%esp,%ecx)   /* is it contained in stopset? */
157         je L(4)                 /* yes => return */
158
159         movb 1(%eax), %cl       /* get byte from string */
160         cmpb %cl, (%esp,%ecx)   /* is it contained in stopset? */
161         je L(5)                 /* yes => return */
162
163         movb 2(%eax), %cl       /* get byte from string */
164         cmpb %cl, (%esp,%ecx)   /* is it contained in stopset? */
165         je L(6)                 /* yes => return */
166
167         movb 3(%eax), %cl       /* get byte from string */
168         cmpb %cl, (%esp,%ecx)   /* is it contained in stopset? */
169         jne L(3)                        /* yes => return */
170
171         incl %eax               /* adjust pointer */
172 L(6):   incl %eax
173 L(5):   incl %eax
174
175 L(4):   addl $256, %esp         /* remove stopset */
176
177         CHECK_BOUNDS_HIGH (%eax, STR(%esp), jb)
178         orb %cl, %cl            /* was last character NUL? */
179         jnz L(7)                /* no => return pointer */
180         xorl %eax, %eax
181         RETURN_NULL_BOUNDED_POINTER
182
183         LEAVE
184         RET_PTR
185
186 L(7):   RETURN_BOUNDED_POINTER (STR(%esp))
187
188         LEAVE
189         RET_PTR
190 END (BP_SYM (strpbrk))
191 libc_hidden_builtin_def (strpbrk)