Bug fix
[kopensolaris-gnu/glibc.git] / sysdeps / x86_64 / strtok.S
1 /* strtok (str, delim) -- Return next DELIM separated token from STR.
2    For AMD x86-64.
3    Copyright (C) 1998,2000-2003,2005,2006 Free Software Foundation, Inc.
4    This file is part of the GNU C Library.
5    Based on i686 version contributed by Ulrich Drepper
6    <drepper@cygnus.com>, 1998.
7
8    The GNU C Library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public
10    License as published by the Free Software Foundation; either
11    version 2.1 of the License, or (at your option) any later version.
12
13    The GNU C Library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with the GNU C Library; if not, write to the Free
20    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21    02111-1307 USA.  */
22
23 #include <sysdep.h>
24 #include "asm-syntax.h"
25 #include "bp-sym.h"
26 #include "bp-asm.h"
27
28 /* This file can be used for the strtok and strtok_r functions:
29
30    strtok:
31         INPUT PARAMETER:
32         str             %rdi
33         delim           %rsi
34
35    strtok_r:
36         INPUT PARAMETER:
37         str             %rdi
38         delim           %rsi
39         save_ptr        %rdx
40
41    We do a common implementation here.  */
42
43 #ifdef USE_AS_STRTOK_R
44 # define SAVE_PTR (%r9)
45 #else
46         .bss
47         .local save_ptr
48         ASM_TYPE_DIRECTIVE (save_ptr, @object)
49         .size save_ptr, 8
50 save_ptr:
51         .space 8
52
53 # ifdef PIC
54 #  define SAVE_PTR save_ptr(%rip)
55 # else
56 #  define SAVE_PTR save_ptr
57 # endif
58
59 # define FUNCTION strtok
60 #endif
61
62         .text
63 ENTRY (BP_SYM (FUNCTION))
64         /* First we create a table with flags for all possible characters.
65            For the ASCII (7bit/8bit) or ISO-8859-X character sets which are
66            supported by the C string functions we have 256 characters.
67            Before inserting marks for the stop characters we clear the whole
68            table.  */
69         movq %rdi, %r8                  /* Save value.  */
70         subq $256, %rsp                 /* Make space for 256 bytes.  */
71         cfi_adjust_cfa_offset(256)
72         movl $32,  %ecx                 /* 32*8 bytes = 256 bytes.  */
73         movq %rsp, %rdi
74         xorl %eax, %eax                 /* We store 0s.  */
75         cld
76         rep
77         stosq
78
79         /* Note: %rcx = 0 !!! */
80
81 #ifdef USE_AS_STRTOK_R
82         /* The value is stored in the third argument.  */
83         movq %rdx, %rax
84         movq %rdx, %r9          /* Save value - see def. of SAVE_PTR.  */
85         movq (%rax), %rax
86 #else
87         /* The value is in the local variable defined above.  But
88            we have to take care for PIC code.  */
89         movq SAVE_PTR, %rax
90 #endif
91         movq %r8, %rdx          /* Get start of string.  */
92
93         /* If the pointer is NULL we have to use the stored value of
94            the last run.  */
95         cmpq $0, %rdx
96         cmove %rax, %rdx
97         testq %rdx, %rdx
98         jz L(returnNULL)
99         movq %rsi, %rax         /* Get start of delimiter set.  */
100
101 /* For understanding the following code remember that %rcx == 0 now.
102    Although all the following instruction only modify %cl we always
103    have a correct zero-extended 64-bit value in %rcx.  */
104
105 L(2):   movb (%rax), %cl        /* get byte from stopset */
106         testb %cl, %cl          /* is NUL char? */
107         jz L(1)                 /* yes => start compare loop */
108         movb %cl, (%rsp,%rcx)   /* set corresponding byte in stopset table */
109
110         movb 1(%rax), %cl       /* get byte from stopset */
111         testb $0xff, %cl        /* is NUL char? */
112         jz L(1)                 /* yes => start compare loop */
113         movb %cl, (%rsp,%rcx)   /* set corresponding byte in stopset table */
114
115         movb 2(%rax), %cl       /* get byte from stopset */
116         testb $0xff, %cl        /* is NUL char? */
117         jz L(1)                 /* yes => start compare loop */
118         movb %cl, (%rsp,%rcx)   /* set corresponding byte in stopset table */
119
120         movb 3(%rax), %cl       /* get byte from stopset */
121         addq $4, %rax           /* increment stopset pointer */
122         movb %cl, (%rsp,%rcx)   /* set corresponding byte in stopset table */
123         testb $0xff, %cl        /* is NUL char? */
124         jnz L(2)                /* no => process next dword from stopset */
125
126 L(1):
127
128         leaq -4(%rdx), %rax     /* prepare loop */
129
130         /* We use a neat trick for the following loop.  Normally we would
131            have to test for two termination conditions
132            1. a character in the stopset was found
133            and
134            2. the end of the string was found
135            As a sign that the character is in the stopset we store its
136            value in the table.  The value of NUL is NUL so the loop
137            terminates for NUL in every case.  */
138
139 L(3):   addq $4, %rax           /* adjust pointer for full loop round */
140
141         movb (%rax), %cl        /* get byte from string */
142         testb %cl, (%rsp,%rcx)  /* is it contained in stopset? */
143         jz L(4)                 /* no => start of token */
144
145         movb 1(%rax), %cl       /* get byte from string */
146         testb %cl, (%rsp,%rcx)  /* is it contained in stopset? */
147         jz L(5)                 /* no => start of token */
148
149         movb 2(%rax), %cl       /* get byte from string */
150         testb %cl, (%rsp,%rcx)  /* is it contained in stopset? */
151         jz L(6)                 /* no => start of token */
152
153         movb 3(%rax), %cl       /* get byte from string */
154         testb %cl, (%rsp,%rcx)  /* is it contained in stopset? */
155         jnz L(3)                /* yes => start of loop */
156
157         incq %rax               /* adjust pointer */
158 L(6):   incq %rax
159 L(5):   incq %rax
160
161         /* Now we have to terminate the string.  */
162
163 L(4):   leaq -4(%rax), %rdx     /* We use %rDX for the next run.  */
164
165 L(7):   addq $4, %rdx           /* adjust pointer for full loop round */
166
167         movb (%rdx), %cl        /* get byte from string */
168         cmpb %cl, (%rsp,%rcx)   /* is it contained in skipset? */
169         je L(8)                 /* yes => return */
170
171         movb 1(%rdx), %cl       /* get byte from string */
172         cmpb %cl, (%rsp,%rcx)   /* is it contained in skipset? */
173         je L(9)                 /* yes => return */
174
175         movb 2(%rdx), %cl       /* get byte from string */
176         cmpb %cl, (%rsp,%rcx)   /* is it contained in skipset? */
177         je L(10)                /* yes => return */
178
179         movb 3(%rdx), %cl       /* get byte from string */
180         cmpb %cl, (%rsp,%rcx)   /* is it contained in skipset? */
181         jne L(7)                /* no => start loop again */
182
183         incq %rdx               /* adjust pointer */
184 L(10):  incq %rdx
185 L(9):   incq %rdx
186
187 L(8):   cmpq %rax, %rdx
188         je L(returnNULL)        /* There was no token anymore.  */
189
190         movb $0, (%rdx)         /* Terminate string.  */
191
192         /* Are we at end of string?  */
193         cmpb $0, %cl
194         leaq 1(%rdx), %rcx
195         cmovne %rcx, %rdx
196
197         /* Store the pointer to the next character.  */
198         movq %rdx, SAVE_PTR
199
200 L(epilogue):
201         /* Remove the stopset table.  */
202         addq $256, %rsp
203         cfi_adjust_cfa_offset(-256)
204         retq
205
206 L(returnNULL):
207         xorl %eax, %eax
208         /* Store the pointer to the next character.  */
209         movq %rdx, SAVE_PTR
210         jmp L(epilogue)
211
212 END (BP_SYM (FUNCTION))