1/* strtok (str, delim) -- Return next DELIM separated token from STR.
2 For AMD x86-64.
3 Copyright (C) 1998-2016 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, see
20 <http://www.gnu.org/licenses/>. */
21
22#include <sysdep.h>
23#include "asm-syntax.h"
24
25/* This file can be used for the strtok and strtok_r functions:
26
27 strtok:
28 INPUT PARAMETER:
29 str %rdi
30 delim %rsi
31
32 strtok_r:
33 INPUT PARAMETER:
34 str %rdi
35 delim %rsi
36 save_ptr %rdx
37
38 We do a common implementation here. */
39
40#ifdef USE_AS_STRTOK_R
41# define SAVE_PTR (%r9)
42#else
43 .bss
44 .local save_ptr
45 .type save_ptr, @object
46 .size save_ptr, LP_SIZE
47save_ptr:
48 .space LP_SIZE
49
50# ifdef PIC
51# define SAVE_PTR save_ptr(%rip)
52# else
53# define SAVE_PTR save_ptr
54# endif
55
56# define FUNCTION strtok
57#endif
58
59 .text
60ENTRY (FUNCTION)
61 /* First we create a table with flags for all possible characters.
62 For the ASCII (7bit/8bit) or ISO-8859-X character sets which are
63 supported by the C string functions we have 256 characters.
64 Before inserting marks for the stop characters we clear the whole
65 table. */
66 movq %rdi, %r8 /* Save value. */
67 subq $256, %rsp /* Make space for 256 bytes. */
68 cfi_adjust_cfa_offset(256)
69 movl $32, %ecx /* 32*8 bytes = 256 bytes. */
70 movq %rsp, %rdi
71 xorl %eax, %eax /* We store 0s. */
72 cld
73 rep
74 stosq
75
76 /* Note: %rcx = 0 !!! */
77
78#ifdef USE_AS_STRTOK_R
79 /* The value is stored in the third argument. */
80 mov %RDX_LP, %R9_LP /* Save value - see def. of SAVE_PTR. */
81 mov (%rdx), %RAX_LP
82#else
83 /* The value is in the local variable defined above. But
84 we have to take care for PIC code. */
85 mov SAVE_PTR, %RAX_LP
86#endif
87 movq %r8, %rdx /* Get start of string. */
88
89 /* If the pointer is NULL we have to use the stored value of
90 the last run. */
91 cmpq $0, %rdx
92 cmove %rax, %rdx
93 testq %rdx, %rdx
94 jz L(returnNULL)
95 movq %rsi, %rax /* Get start of delimiter set. */
96
97/* For understanding the following code remember that %rcx == 0 now.
98 Although all the following instruction only modify %cl we always
99 have a correct zero-extended 64-bit value in %rcx. */
100
101L(2): movb (%rax), %cl /* get byte from stopset */
102 testb %cl, %cl /* is NUL char? */
103 jz L(1) /* yes => start compare loop */
104 movb %cl, (%rsp,%rcx) /* set corresponding byte in stopset table */
105
106 movb 1(%rax), %cl /* get byte from stopset */
107 testb $0xff, %cl /* is NUL char? */
108 jz L(1) /* yes => start compare loop */
109 movb %cl, (%rsp,%rcx) /* set corresponding byte in stopset table */
110
111 movb 2(%rax), %cl /* get byte from stopset */
112 testb $0xff, %cl /* is NUL char? */
113 jz L(1) /* yes => start compare loop */
114 movb %cl, (%rsp,%rcx) /* set corresponding byte in stopset table */
115
116 movb 3(%rax), %cl /* get byte from stopset */
117 addq $4, %rax /* increment stopset pointer */
118 movb %cl, (%rsp,%rcx) /* set corresponding byte in stopset table */
119 testb $0xff, %cl /* is NUL char? */
120 jnz L(2) /* no => process next dword from stopset */
121
122L(1):
123
124 leaq -4(%rdx), %rax /* prepare loop */
125
126 /* We use a neat trick for the following loop. Normally we would
127 have to test for two termination conditions
128 1. a character in the stopset was found
129 and
130 2. the end of the string was found
131 As a sign that the character is in the stopset we store its
132 value in the table. The value of NUL is NUL so the loop
133 terminates for NUL in every case. */
134
135L(3): addq $4, %rax /* adjust pointer for full loop round */
136
137 movb (%rax), %cl /* get byte from string */
138 testb %cl, (%rsp,%rcx) /* is it contained in stopset? */
139 jz L(4) /* no => start of token */
140
141 movb 1(%rax), %cl /* get byte from string */
142 testb %cl, (%rsp,%rcx) /* is it contained in stopset? */
143 jz L(5) /* no => start of token */
144
145 movb 2(%rax), %cl /* get byte from string */
146 testb %cl, (%rsp,%rcx) /* is it contained in stopset? */
147 jz L(6) /* no => start of token */
148
149 movb 3(%rax), %cl /* get byte from string */
150 testb %cl, (%rsp,%rcx) /* is it contained in stopset? */
151 jnz L(3) /* yes => start of loop */
152
153 incq %rax /* adjust pointer */
154L(6): incq %rax
155L(5): incq %rax
156
157 /* Now we have to terminate the string. */
158
159L(4): leaq -4(%rax), %rdx /* We use %rDX for the next run. */
160
161L(7): addq $4, %rdx /* adjust pointer for full loop round */
162
163 movb (%rdx), %cl /* get byte from string */
164 cmpb %cl, (%rsp,%rcx) /* is it contained in skipset? */
165 je L(8) /* yes => return */
166
167 movb 1(%rdx), %cl /* get byte from string */
168 cmpb %cl, (%rsp,%rcx) /* is it contained in skipset? */
169 je L(9) /* yes => return */
170
171 movb 2(%rdx), %cl /* get byte from string */
172 cmpb %cl, (%rsp,%rcx) /* is it contained in skipset? */
173 je L(10) /* yes => return */
174
175 movb 3(%rdx), %cl /* get byte from string */
176 cmpb %cl, (%rsp,%rcx) /* is it contained in skipset? */
177 jne L(7) /* no => start loop again */
178
179 incq %rdx /* adjust pointer */
180L(10): incq %rdx
181L(9): incq %rdx
182
183L(8): cmpq %rax, %rdx
184 je L(returnNULL) /* There was no token anymore. */
185
186 movb $0, (%rdx) /* Terminate string. */
187
188 /* Are we at end of string? */
189 cmpb $0, %cl
190 leaq 1(%rdx), %rcx
191 cmovne %rcx, %rdx
192
193 /* Store the pointer to the next character. */
194 mov %RDX_LP, SAVE_PTR
195
196L(epilogue):
197 /* Remove the stopset table. */
198 addq $256, %rsp
199 cfi_adjust_cfa_offset(-256)
200 retq
201
202L(returnNULL):
203 xorl %eax, %eax
204 /* Store the pointer to the next character. */
205 mov %RDX_LP, SAVE_PTR
206 jmp L(epilogue)
207
208END (FUNCTION)
209