1/* strcspn (str, ss) -- Return the length of the initial segment of STR 2 which contains only characters from SS. 3 For Intel 80x86, x>=3. 4 Copyright (C) 1994-2022 Free Software Foundation, Inc. 5 This file is part of the GNU C Library. 6 7 The GNU C Library is free software; you can redistribute it and/or 8 modify it under the terms of the GNU Lesser General Public 9 License as published by the Free Software Foundation; either 10 version 2.1 of the License, or (at your option) any later version. 11 12 The GNU C Library is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 Lesser General Public License for more details. 16 17 You should have received a copy of the GNU Lesser General Public 18 License along with the GNU C Library; if not, see 19 <https://www.gnu.org/licenses/>. */ 20 21#include <sysdep.h> 22#include "asm-syntax.h" 23 24#define PARMS 4 /* no space for saved regs */ 25#define STR PARMS 26#define SKIP STR+4 27 28 .text 29ENTRY (strspn) 30 31 movl STR(%esp), %edx 32 movl SKIP(%esp), %eax 33 34 /* First we create a table with flags for all possible characters. 35 For the ASCII (7bit/8bit) or ISO-8859-X character sets which are 36 supported by the C string functions we have 256 characters. 37 Before inserting marks for the stop characters we clear the whole 38 table. The unrolled form is much faster than a loop. */ 39 xorl %ecx, %ecx /* %ecx = 0 !!! */ 40 41 pushl %ecx /* make a 256 bytes long block filled with 0 */ 42 cfi_adjust_cfa_offset (4) 43 pushl %ecx 44 cfi_adjust_cfa_offset (4) 45 pushl %ecx 46 cfi_adjust_cfa_offset (4) 47 pushl %ecx 48 cfi_adjust_cfa_offset (4) 49 pushl %ecx 50 cfi_adjust_cfa_offset (4) 51 pushl %ecx 52 cfi_adjust_cfa_offset (4) 53 pushl %ecx 54 cfi_adjust_cfa_offset (4) 55 pushl %ecx 56 cfi_adjust_cfa_offset (4) 57 pushl %ecx 58 cfi_adjust_cfa_offset (4) 59 pushl %ecx 60 cfi_adjust_cfa_offset (4) 61 pushl %ecx 62 cfi_adjust_cfa_offset (4) 63 pushl %ecx 64 cfi_adjust_cfa_offset (4) 65 pushl %ecx 66 cfi_adjust_cfa_offset (4) 67 pushl %ecx 68 cfi_adjust_cfa_offset (4) 69 pushl %ecx 70 cfi_adjust_cfa_offset (4) 71 pushl %ecx 72 cfi_adjust_cfa_offset (4) 73 pushl %ecx 74 cfi_adjust_cfa_offset (4) 75 pushl %ecx 76 cfi_adjust_cfa_offset (4) 77 pushl %ecx 78 cfi_adjust_cfa_offset (4) 79 pushl %ecx 80 cfi_adjust_cfa_offset (4) 81 pushl %ecx 82 cfi_adjust_cfa_offset (4) 83 pushl %ecx 84 cfi_adjust_cfa_offset (4) 85 pushl %ecx 86 cfi_adjust_cfa_offset (4) 87 pushl %ecx 88 cfi_adjust_cfa_offset (4) 89 pushl %ecx 90 cfi_adjust_cfa_offset (4) 91 pushl %ecx 92 cfi_adjust_cfa_offset (4) 93 pushl %ecx 94 cfi_adjust_cfa_offset (4) 95 pushl %ecx 96 cfi_adjust_cfa_offset (4) 97 pushl %ecx 98 cfi_adjust_cfa_offset (4) 99 pushl %ecx 100 cfi_adjust_cfa_offset (4) 101 pushl %ecx 102 cfi_adjust_cfa_offset (4) 103 pushl %ecx 104 cfi_adjust_cfa_offset (4) 105 pushl %ecx 106 cfi_adjust_cfa_offset (4) 107 pushl %ecx 108 cfi_adjust_cfa_offset (4) 109 pushl %ecx 110 cfi_adjust_cfa_offset (4) 111 pushl %ecx 112 cfi_adjust_cfa_offset (4) 113 pushl %ecx 114 cfi_adjust_cfa_offset (4) 115 pushl %ecx 116 cfi_adjust_cfa_offset (4) 117 pushl %ecx 118 cfi_adjust_cfa_offset (4) 119 pushl %ecx 120 cfi_adjust_cfa_offset (4) 121 pushl %ecx 122 cfi_adjust_cfa_offset (4) 123 pushl %ecx 124 cfi_adjust_cfa_offset (4) 125 pushl %ecx 126 cfi_adjust_cfa_offset (4) 127 pushl %ecx 128 cfi_adjust_cfa_offset (4) 129 pushl %ecx 130 cfi_adjust_cfa_offset (4) 131 pushl %ecx 132 cfi_adjust_cfa_offset (4) 133 pushl %ecx 134 cfi_adjust_cfa_offset (4) 135 pushl %ecx 136 cfi_adjust_cfa_offset (4) 137 pushl %ecx 138 cfi_adjust_cfa_offset (4) 139 pushl %ecx 140 cfi_adjust_cfa_offset (4) 141 pushl %ecx 142 cfi_adjust_cfa_offset (4) 143 pushl %ecx 144 cfi_adjust_cfa_offset (4) 145 pushl %ecx 146 cfi_adjust_cfa_offset (4) 147 pushl %ecx 148 cfi_adjust_cfa_offset (4) 149 pushl %ecx 150 cfi_adjust_cfa_offset (4) 151 pushl %ecx 152 cfi_adjust_cfa_offset (4) 153 pushl %ecx 154 cfi_adjust_cfa_offset (4) 155 pushl %ecx 156 cfi_adjust_cfa_offset (4) 157 pushl $0 /* These immediate values make the label 2 */ 158 cfi_adjust_cfa_offset (4) 159 pushl $0 /* to be aligned on a 16 byte boundary to */ 160 cfi_adjust_cfa_offset (4) 161 pushl $0 /* get a better performance of the loop. */ 162 cfi_adjust_cfa_offset (4) 163 pushl $0 164 cfi_adjust_cfa_offset (4) 165 pushl $0 166 cfi_adjust_cfa_offset (4) 167 pushl $0 168 cfi_adjust_cfa_offset (4) 169 170/* For understanding the following code remember that %ecx == 0 now. 171 Although all the following instruction only modify %cl we always 172 have a correct zero-extended 32-bit value in %ecx. */ 173 174/* Don't change the "testb $0xff,%%cl" to "testb %%cl,%%cl". We want 175 longer instructions so that the next loop aligns without adding nops. */ 176 177L(2): movb (%eax), %cl /* get byte from stopset */ 178 testb %cl, %cl /* is NUL char? */ 179 jz L(1) /* yes => start compare loop */ 180 movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */ 181 182 movb 1(%eax), %cl /* get byte from stopset */ 183 testb $0xff, %cl /* is NUL char? */ 184 jz L(1) /* yes => start compare loop */ 185 movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */ 186 187 movb 2(%eax), %cl /* get byte from stopset */ 188 testb $0xff, %cl /* is NUL char? */ 189 jz L(1) /* yes => start compare loop */ 190 movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */ 191 192 movb 3(%eax), %cl /* get byte from stopset */ 193 addl $4, %eax /* increment stopset pointer */ 194 movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */ 195 testb $0xff, %cl /* is NUL char? */ 196 jnz L(2) /* no => process next dword from stopset */ 197 198L(1): leal -4(%edx), %eax /* prepare loop */ 199 200 /* We use a neat trick for the following loop. Normally we would 201 have to test for two termination conditions 202 1. a character in the stopset was found 203 and 204 2. the end of the string was found 205 But as a sign that the character is in the stopset we store its 206 value in the table. But the value of NUL is NUL so the loop 207 terminates for NUL in every case. */ 208 209L(3): addl $4, %eax /* adjust pointer for full loop round */ 210 211 movb (%eax), %cl /* get byte from string */ 212 testb %cl, (%esp,%ecx) /* is it contained in skipset? */ 213 jz L(4) /* no => return */ 214 215 movb 1(%eax), %cl /* get byte from string */ 216 testb %cl, (%esp,%ecx) /* is it contained in skipset? */ 217 jz L(5) /* no => return */ 218 219 movb 2(%eax), %cl /* get byte from string */ 220 testb %cl, (%esp,%ecx) /* is it contained in skipset? */ 221 jz L(6) /* no => return */ 222 223 movb 3(%eax), %cl /* get byte from string */ 224 testb %cl, (%esp,%ecx) /* is it contained in skipset? */ 225 jnz L(3) /* yes => start loop again */ 226 227 incl %eax /* adjust pointer */ 228L(6): incl %eax 229L(5): incl %eax 230 231L(4): addl $256, %esp /* remove stopset */ 232 cfi_adjust_cfa_offset (-256) 233 subl %edx, %eax /* we have to return the number of valid 234 characters, so compute distance to first 235 non-valid character */ 236 ret 237END (strspn) 238libc_hidden_builtin_def (strspn) 239