x86-64 optimized string function.
authoraj <aj>
Sat, 31 Aug 2002 17:41:24 +0000 (17:41 +0000)
committeraj <aj>
Sat, 31 Aug 2002 17:41:24 +0000 (17:41 +0000)
sysdeps/x86_64/stpcpy.S [new file with mode: 0644]
sysdeps/x86_64/strcat.S [new file with mode: 0644]
sysdeps/x86_64/strchr.S [new file with mode: 0644]
sysdeps/x86_64/strcmp.S [new file with mode: 0644]
sysdeps/x86_64/strcpy.S [new file with mode: 0644]
sysdeps/x86_64/strcspn.S [new file with mode: 0644]
sysdeps/x86_64/strlen.S [new file with mode: 0644]
sysdeps/x86_64/strpbrk.S [new file with mode: 0644]
sysdeps/x86_64/strspn.S [new file with mode: 0644]

diff --git a/sysdeps/x86_64/stpcpy.S b/sysdeps/x86_64/stpcpy.S
new file mode 100644 (file)
index 0000000..b9bbcd9
--- /dev/null
@@ -0,0 +1,7 @@
+#define USE_AS_STPCPY
+#define STRCPY __stpcpy
+
+#include <sysdeps/x86_64/strcpy.S>
+
+weak_alias (__stpcpy, stpcpy)
+libc_hidden_def (__stpcpy)
diff --git a/sysdeps/x86_64/strcat.S b/sysdeps/x86_64/strcat.S
new file mode 100644 (file)
index 0000000..549fd21
--- /dev/null
@@ -0,0 +1,257 @@
+/* strcat(dest, src) -- Append SRC on the end of DEST.
+   Optimized for x86-64.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Andreas Jaeger <aj@suse.de>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include "asm-syntax.h"
+#include "bp-sym.h"
+#include "bp-asm.h"
+
+
+       .text
+ENTRY (BP_SYM (strcat))
+       movq %rdi, %rcx         /* Dest. register. */
+       andl $7, %ecx           /* mask alignment bits */
+       movq %rdi, %rax         /* Duplicate destination pointer.  */
+       movq $0xfefefefefefefeff,%r8
+
+       /* First step: Find end of destination.  */
+       jz 4f                   /* aligned => start loop */
+
+       neg %ecx                /* We need to align to 8 bytes.  */
+       addl $8,%ecx
+       /* Search the first bytes directly.  */
+0:     cmpb $0x0,(%rax)        /* is byte NUL? */
+       je 2f                   /* yes => start copy */
+       incq %rax               /* increment pointer */
+       decl %ecx
+       jnz 0b
+
+
+
+       /* Now the source is aligned.  Scan for NUL byte.  */
+       .p2align 4
+4:
+       /* First unroll.  */
+       movq (%rax), %rcx       /* get double word (= 8 bytes) in question */
+       addq $8,%rax            /* adjust pointer for next word */
+       movq %r8, %rdx          /* magic value */
+       addq %rcx, %rdx         /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc 3f                  /* highest byte is NUL => return pointer */
+       xorq %rcx, %rdx         /* (word+magic)^word */
+       orq %r8, %rdx           /* set all non-carry bits */
+       incq %rdx               /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+       jnz 3f                  /* found NUL => return pointer */
+
+       /* Second unroll.  */
+       movq (%rax), %rcx       /* get double word (= 8 bytes) in question */
+       addq $8,%rax            /* adjust pointer for next word */
+       movq %r8, %rdx          /* magic value */
+       addq %rcx, %rdx         /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc 3f                  /* highest byte is NUL => return pointer */
+       xorq %rcx, %rdx         /* (word+magic)^word */
+       orq %r8, %rdx           /* set all non-carry bits */
+       incq %rdx               /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+       jnz 3f                  /* found NUL => return pointer */
+
+       /* Third unroll.  */
+       movq (%rax), %rcx       /* get double word (= 8 bytes) in question */
+       addq $8,%rax            /* adjust pointer for next word */
+       movq %r8, %rdx          /* magic value */
+       addq %rcx, %rdx         /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc 3f                  /* highest byte is NUL => return pointer */
+       xorq %rcx, %rdx         /* (word+magic)^word */
+       orq %r8, %rdx           /* set all non-carry bits */
+       incq %rdx               /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+       jnz 3f                  /* found NUL => return pointer */
+
+       /* Fourth unroll.  */
+       movq (%rax), %rcx       /* get double word (= 8 bytes) in question */
+       addq $8,%rax            /* adjust pointer for next word */
+       movq %r8, %rdx          /* magic value */
+       addq %rcx, %rdx         /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc 3f                  /* highest byte is NUL => return pointer */
+       xorq %rcx, %rdx         /* (word+magic)^word */
+       orq %r8, %rdx           /* set all non-carry bits */
+       incq %rdx               /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+       jz 4b                   /* no NUL found => continue loop */
+
+       .p2align 4              /* Align, it's a jump target.  */
+3:     subq $8,%rax            /* correct pointer increment.  */
+
+       testb %cl, %cl          /* is first byte NUL? */
+       jz 2f                   /* yes => return */
+       incq %rax               /* increment pointer */
+
+       testb %ch, %ch          /* is second byte NUL? */
+       jz 2f                   /* yes => return */
+       incq %rax               /* increment pointer */
+
+       testl $0x00ff0000, %ecx /* is third byte NUL? */
+       jz 2f                   /* yes => return pointer */
+       incq %rax               /* increment pointer */
+
+       testl $0xff000000, %ecx /* is fourth byte NUL? */
+       jz 2f                   /* yes => return pointer */
+       incq %rax               /* increment pointer */
+
+       shrq $32, %rcx          /* look at other half.  */
+
+       testb %cl, %cl          /* is first byte NUL? */
+       jz 2f                   /* yes => return */
+       incq %rax               /* increment pointer */
+
+       testb %ch, %ch          /* is second byte NUL? */
+       jz 2f                   /* yes => return */
+       incq %rax               /* increment pointer */
+
+       testl $0xff0000, %ecx   /* is third byte NUL? */
+       jz 2f                   /* yes => return pointer */
+       incq %rax               /* increment pointer */
+
+2:
+       /* Second step: Copy source to destination.  */
+
+       movq    %rax, %rcx      /* duplicate  */
+       andl    $7,%ecx         /* mask alignment bits */
+       movq    %rax, %rdx      /* move around */
+       jz      22f             /* aligned => start loop */
+
+       /* Align the source pointer.  */
+21:
+       movb    (%rsi), %al     /* Fetch a byte */
+       testb   %al, %al        /* Is it NUL? */
+       movb    %al, (%rdx)     /* Store it */
+       jz      24f             /* If it was NUL, done! */
+       incq    %rsi
+       incq    %rdx
+       decl    %ecx
+       jnz     21b
+
+       /* Now the sources is aligned.  Unfortunatly we cannot force
+          to have both source and destination aligned, so ignore the
+          alignment of the destination.  */
+       .p2align 4
+22:
+       /* 1st unroll.  */
+       movq    (%rsi), %rax    /* Read double word (8 bytes).  */
+       addq    $8, %rsi        /* Adjust pointer for next word.  */
+       movq    %rax, %r9       /* Save a copy for NUL finding.  */
+       addq    %r8, %r9        /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc     23f             /* highest byte is NUL => return pointer */
+       xorq    %rax, %r9       /* (word+magic)^word */
+       orq     %r8, %r9        /* set all non-carry bits */
+       incq    %r9             /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+
+       jnz     23f             /* found NUL => return pointer */
+
+       movq    %rax, (%rdx)    /* Write value to destination.  */
+       addq    $8, %rdx        /* Adjust pointer.  */
+
+       /* 2nd unroll.  */
+       movq    (%rsi), %rax    /* Read double word (8 bytes).  */
+       addq    $8, %rsi        /* Adjust pointer for next word.  */
+       movq    %rax, %r9       /* Save a copy for NUL finding.  */
+       addq    %r8, %r9        /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc     23f             /* highest byte is NUL => return pointer */
+       xorq    %rax, %r9       /* (word+magic)^word */
+       orq     %r8, %r9        /* set all non-carry bits */
+       incq    %r9             /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+
+       jnz     23f             /* found NUL => return pointer */
+
+       movq    %rax, (%rdx)    /* Write value to destination.  */
+       addq    $8, %rdx        /* Adjust pointer.  */
+
+       /* 3rd unroll.  */
+       movq    (%rsi), %rax    /* Read double word (8 bytes).  */
+       addq    $8, %rsi        /* Adjust pointer for next word.  */
+       movq    %rax, %r9       /* Save a copy for NUL finding.  */
+       addq    %r8, %r9        /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc     23f             /* highest byte is NUL => return pointer */
+       xorq    %rax, %r9       /* (word+magic)^word */
+       orq     %r8, %r9        /* set all non-carry bits */
+       incq    %r9             /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+
+       jnz     23f             /* found NUL => return pointer */
+
+       movq    %rax, (%rdx)    /* Write value to destination.  */
+       addq    $8, %rdx        /* Adjust pointer.  */
+
+       /* 4th unroll.  */
+       movq    (%rsi), %rax    /* Read double word (8 bytes).  */
+       addq    $8, %rsi        /* Adjust pointer for next word.  */
+       movq    %rax, %r9       /* Save a copy for NUL finding.  */
+       addq    %r8, %r9        /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc     23f             /* highest byte is NUL => return pointer */
+       xorq    %rax, %r9       /* (word+magic)^word */
+       orq     %r8, %r9        /* set all non-carry bits */
+       incq    %r9             /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+
+       jnz     23f             /* found NUL => return pointer */
+
+       movq    %rax, (%rdx)    /* Write value to destination.  */
+       addq    $8, %rdx        /* Adjust pointer.  */
+       jmp     22b             /* Next iteration.  */
+
+       /* Do the last few bytes. %rax contains the value to write.
+          The loop is unrolled twice.  */
+       .p2align 4
+23:
+       movb    %al, (%rdx)     /* 1st byte.  */
+       testb   %al, %al        /* Is it NUL.  */
+       jz      24f             /* yes, finish.  */
+       incq    %rdx            /* Increment destination.  */
+       movb    %ah, (%rdx)     /* 2nd byte.  */
+       testb   %ah, %ah        /* Is it NUL?.  */
+       jz      24f             /* yes, finish.  */
+       incq    %rdx            /* Increment destination.  */
+       shrq    $16, %rax       /* Shift...  */
+       jmp     23b             /* and look at next two bytes in %rax.  */
+
+
+24:
+       movq    %rdi, %rax      /* Source is return value.  */
+       retq
+END (BP_SYM (strcat))
diff --git a/sysdeps/x86_64/strchr.S b/sysdeps/x86_64/strchr.S
new file mode 100644 (file)
index 0000000..391f575
--- /dev/null
@@ -0,0 +1,290 @@
+/* strchr (str, ch) -- Return pointer to first occurrence of CH in STR.
+   For AMD x86-64.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include "asm-syntax.h"
+#include "bp-sym.h"
+#include "bp-asm.h"
+
+
+       .text
+ENTRY (BP_SYM (strchr))
+
+       /* Before we start with the main loop we process single bytes
+          until the source pointer is aligned.  This has two reasons:
+          1. aligned 64-bit memory access is faster
+          and (more important)
+          2. we process in the main loop 64 bit in one step although
+             we don't know the end of the string.  But accessing at
+             8-byte alignment guarantees that we never access illegal
+             memory if this would not also be done by the trivial
+             implementation (this is because all processor inherent
+             boundaries are multiples of 8.  */
+
+       movq    %rdi, %rcx
+       andl    $7, %ecx        /* Mask alignment bits  */
+       movq    %rdi, %rax      /* duplicate destination.  */
+       jz      1f              /* aligned => start loop */
+       neg     %ecx
+       addl    $8, %ecx        /* Align to 8 bytes.  */
+
+       /* Search the first bytes directly.  */
+0:     movb    (%rax), %cl     /* load byte  */
+       cmpb    %cl,%sil        /* compare byte.  */
+       je      6f              /* target found */
+       testb   %cl,%cl         /* is byte NUL? */
+       je      7f              /* yes => return NULL */
+       incq    %rax            /* increment pointer */
+       decl    %ecx
+       jnz     0b
+
+
+1:
+       /* At the moment %rsi contains C.  What we need for the
+          algorithm is C in all bytes of the register.  Avoid
+          operations on 16 bit words because these require an
+          prefix byte (and one more cycle).  */
+       /* Populate 8 bit data to full 64-bit.  */
+       movabs  $0x0101010101010101,%r9
+       movzbl  %sil,%edx
+       imul    %rdx,%r9
+
+       movq $0xfefefefefefefeff, %r8 /* Save magic.  */
+
+      /* We exit the loop if adding MAGIC_BITS to LONGWORD fails to
+        change any of the hole bits of LONGWORD.
+
+        1) Is this safe?  Will it catch all the zero bytes?
+        Suppose there is a byte with all zeros.  Any carry bits
+        propagating from its left will fall into the hole at its
+        least significant bit and stop.  Since there will be no
+        carry from its most significant bit, the LSB of the
+        byte to the left will be unchanged, and the zero will be
+        detected.
+
+        2) Is this worthwhile?  Will it ignore everything except
+        zero bytes?  Suppose every byte of QUARDWORD has a bit set
+        somewhere.  There will be a carry into bit 8.  If bit 8
+        is set, this will carry into bit 16.  If bit 8 is clear,
+        one of bits 9-15 must be set, so there will be a carry
+        into bit 16.  Similarly, there will be a carry into bit
+        24 tec..  If one of bits 54-63 is set, there will be a carry
+        into bit 64 (=carry flag), so all of the hole bits will
+        be changed.
+
+        3) But wait!  Aren't we looking for C, not zero?
+        Good point.  So what we do is XOR LONGWORD with a longword,
+        each of whose bytes is C.  This turns each byte that is C
+        into a zero.  */
+
+       .p2align 4
+4:
+       /* Main Loop is unrolled 4 times.  */
+       /* First unroll.  */
+       movq (%rax), %rcx       /* get double word (= 8 bytes) in question */
+       addq $8,%rax            /* adjust pointer for next word */
+       movq %r8, %rdx          /* magic value */
+       xorq %r9, %rcx          /* XOR with qword c|...|c => bytes of str == c
+                                  are now 0 */
+       addq %rcx, %rdx         /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc 3f                  /* highest byte is NUL => return pointer */
+       xorq %rcx, %rdx         /* (word+magic)^word */
+       orq %r8, %rdx           /* set all non-carry bits */
+       incq %rdx               /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+       jnz 3f                  /* found c => return pointer */
+
+       /* The quadword we looked at does not contain the value we're looking
+          for.  Let's search now whether we have reached the end of the
+          string.  */
+       xorq %r9, %rcx          /* restore original dword without reload */
+       movq %r8, %rdx          /* magic value */
+       addq %rcx, %rdx         /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc 7f                  /* highest byte is NUL => return NULL */
+       xorq %rcx, %rdx         /* (word+magic)^word */
+       orq %r8, %rdx           /* set all non-carry bits */
+       incq %rdx               /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+       jnz 7f                  /* found NUL => return NULL */
+
+       /* Second unroll.  */
+       movq (%rax), %rcx       /* get double word (= 8 bytes) in question */
+       addq $8,%rax            /* adjust pointer for next word */
+       movq %r8, %rdx          /* magic value */
+       xorq %r9, %rcx          /* XOR with qword c|...|c => bytes of str == c
+                                  are now 0 */
+       addq %rcx, %rdx         /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc 3f                  /* highest byte is NUL => return pointer */
+       xorq %rcx, %rdx         /* (word+magic)^word */
+       orq %r8, %rdx           /* set all non-carry bits */
+       incq %rdx               /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+       jnz 3f                  /* found c => return pointer */
+
+       /* The quadword we looked at does not contain the value we're looking
+          for.  Let's search now whether we have reached the end of the
+          string.  */
+       xorq %r9, %rcx          /* restore original dword without reload */
+       movq %r8, %rdx          /* magic value */
+       addq %rcx, %rdx         /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc 7f                  /* highest byte is NUL => return NULL */
+       xorq %rcx, %rdx         /* (word+magic)^word */
+       orq %r8, %rdx           /* set all non-carry bits */
+       incq %rdx               /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+       jnz 7f                  /* found NUL => return NULL */
+       /* Third unroll.  */
+       movq (%rax), %rcx       /* get double word (= 8 bytes) in question */
+       addq $8,%rax            /* adjust pointer for next word */
+       movq %r8, %rdx          /* magic value */
+       xorq %r9, %rcx          /* XOR with qword c|...|c => bytes of str == c
+                                  are now 0 */
+       addq %rcx, %rdx         /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc 3f                  /* highest byte is NUL => return pointer */
+       xorq %rcx, %rdx         /* (word+magic)^word */
+       orq %r8, %rdx           /* set all non-carry bits */
+       incq %rdx               /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+       jnz 3f                  /* found c => return pointer */
+
+       /* The quadword we looked at does not contain the value we're looking
+          for.  Let's search now whether we have reached the end of the
+          string.  */
+       xorq %r9, %rcx          /* restore original dword without reload */
+       movq %r8, %rdx          /* magic value */
+       addq %rcx, %rdx         /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc 7f                  /* highest byte is NUL => return NULL */
+       xorq %rcx, %rdx         /* (word+magic)^word */
+       orq %r8, %rdx           /* set all non-carry bits */
+       incq %rdx               /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+       jnz 7f                  /* found NUL => return NULL */
+       /* Fourth unroll.  */
+       movq (%rax), %rcx       /* get double word (= 8 bytes) in question */
+       addq $8,%rax            /* adjust pointer for next word */
+       movq %r8, %rdx          /* magic value */
+       xorq %r9, %rcx          /* XOR with qword c|...|c => bytes of str == c
+                                  are now 0 */
+       addq %rcx, %rdx         /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc 3f                  /* highest byte is NUL => return pointer */
+       xorq %rcx, %rdx         /* (word+magic)^word */
+       orq %r8, %rdx           /* set all non-carry bits */
+       incq %rdx               /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+       jnz 3f                  /* found c => return pointer */
+
+       /* The quadword we looked at does not contain the value we're looking
+          for.  Let's search now whether we have reached the end of the
+          string.  */
+       xorq %r9, %rcx          /* restore original dword without reload */
+       movq %r8, %rdx          /* magic value */
+       addq %rcx, %rdx         /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc 7f                  /* highest byte is NUL => return NULL */
+       xorq %rcx, %rdx         /* (word+magic)^word */
+       orq %r8, %rdx           /* set all non-carry bits */
+       incq %rdx               /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+       jz 4b                   /* no NUL found => restart loop */
+
+
+7:     /* Return NULL.  */
+       xorq %rax, %rax
+       retq
+
+
+       /* We now scan for the byte in which the character was matched.
+          But we have to take care of the case that a NUL char is
+          found before this in the dword.  Note that we XORed %rcx
+          with the byte we're looking for, therefore the tests below look
+          reversed.  */
+
+
+       .p2align 4              /* Align, it's a jump target.  */
+3:     movq    %r9,%rdx        /* move to %rdx so that we can access bytes */
+       subq    $8,%rax         /* correct pointer increment.  */
+       testb %cl, %cl          /* is first byte C? */
+       jz 6f                   /* yes => return pointer */
+       cmpb %dl, %cl           /* is first byte NUL? */
+       je 7b                   /* yes => return NULL */
+       incq %rax               /* increment pointer */
+
+       testb %ch, %ch          /* is second byte C? */
+       jz 6f                   /* yes => return pointer */
+       cmpb %dl, %ch           /* is second byte NUL? */
+       je 7b                   /* yes => return NULL? */
+       incq %rax               /* increment pointer */
+
+       shrq $16, %rcx          /* make upper bytes accessible */
+       testb %cl, %cl          /* is third byte C? */
+       jz 6f                   /* yes => return pointer */
+       cmpb %dl, %cl           /* is third byte NUL? */
+       je 7b                   /* yes => return NULL */
+       incq %rax               /* increment pointer */
+
+       testb %ch, %ch          /* is fourth byte C? */
+       jz 6f                   /* yes => return pointer */
+       cmpb %dl, %ch           /* is fourth byte NUL? */
+       je 7b                   /* yes => return NULL? */
+       incq %rax               /* increment pointer */
+
+       shrq $16, %rcx          /* make upper bytes accessible */
+       testb %cl, %cl          /* is fifth byte C? */
+       jz 6f                   /* yes => return pointer */
+       cmpb %dl, %cl           /* is fifth byte NUL? */
+       je 7b                   /* yes => return NULL */
+       incq %rax               /* increment pointer */
+
+       testb %ch, %ch          /* is sixth byte C? */
+       jz 6f                   /* yes => return pointer */
+       cmpb %dl, %ch           /* is sixth byte NUL? */
+       je 7b                   /* yes => return NULL? */
+       incq %rax               /* increment pointer */
+
+       shrq $16, %rcx          /* make upper bytes accessible */
+       testb %cl, %cl          /* is seventh byte C? */
+       jz 6f                   /* yes => return pointer */
+       cmpb %dl, %cl           /* is seventh byte NUL? */
+       je 7b                   /* yes => return NULL */
+
+       /* It must be in the eigth byte and it cannot be NUL.  */
+       incq %rax
+
+6:
+       nop
+       retq
+END (BP_SYM (strchr))
+
+weak_alias (BP_SYM (strchr), BP_SYM (index))
diff --git a/sysdeps/x86_64/strcmp.S b/sysdeps/x86_64/strcmp.S
new file mode 100644 (file)
index 0000000..6e6bdcb
--- /dev/null
@@ -0,0 +1,44 @@
+/* Highly optimized version for x86-64.
+   Copyright (C) 1999, 2000, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Based on i686 version contributed by Ulrich Drepper
+   <drepper@cygnus.com>, 1999.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include "asm-syntax.h"
+#include "bp-sym.h"
+#include "bp-asm.h"
+
+        .text
+ENTRY (BP_SYM (strcmp))
+L(oop):        movb    (%rdi), %al
+       cmpb    (%rsi), %al
+       jne     L(neq)
+       incq    %rdi
+       incq    %rsi
+       testb   %al, %al
+       jnz     L(oop)
+
+       xorq    %rax, %rax
+       ret
+
+L(neq):        movl    $1, %eax
+       movl    $-1, %ecx
+       cmovbl  %ecx, %eax
+       ret
+END (BP_SYM (strcmp))
diff --git a/sysdeps/x86_64/strcpy.S b/sysdeps/x86_64/strcpy.S
new file mode 100644 (file)
index 0000000..f178b9b
--- /dev/null
@@ -0,0 +1,156 @@
+/* strcpy/stpcpy implementation for x86-64.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Andreas Jaeger <aj@suse.de>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include "asm-syntax.h"
+#include "bp-sym.h"
+#include "bp-asm.h"
+
+#ifndef USE_AS_STPCPY
+# define STRCPY strcpy
+#endif
+
+       .text
+ENTRY (BP_SYM (STRCPY))
+       movq %rsi, %rcx         /* Source register. */
+       andl $7, %ecx           /* mask alignment bits */
+       movq %rdi, %rdx         /* Duplicate destination pointer.  */
+
+       jz 5f                   /* aligned => start loop */
+
+       neg %ecx                /* We need to align to 8 bytes.  */
+       addl $8,%ecx
+       /* Search the first bytes directly.  */
+0:
+       movb    (%rsi), %al     /* Fetch a byte */
+       testb   %al, %al        /* Is it NUL? */
+       movb    %al, (%rdx)     /* Store it */
+       jz      4f              /* If it was NUL, done! */
+       incq    %rsi
+       incq    %rdx
+       decl    %ecx
+       jnz     0b
+
+5:
+       movq $0xfefefefefefefeff,%r8
+
+       /* Now the sources is aligned.  Unfortunatly we cannot force
+          to have both source and destination aligned, so ignore the
+          alignment of the destination.  */
+       .p2align 4
+1:
+       /* 1st unroll.  */
+       movq    (%rsi), %rax    /* Read double word (8 bytes).  */
+       addq    $8, %rsi        /* Adjust pointer for next word.  */
+       movq    %rax, %r9       /* Save a copy for NUL finding.  */
+       addq    %r8, %r9        /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc     3f              /* highest byte is NUL => return pointer */
+       xorq    %rax, %r9       /* (word+magic)^word */
+       orq     %r8, %r9        /* set all non-carry bits */
+       incq    %r9             /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+
+       jnz     3f              /* found NUL => return pointer */
+
+       movq    %rax, (%rdx)    /* Write value to destination.  */
+       addq    $8, %rdx        /* Adjust pointer.  */
+
+       /* 2nd unroll.  */
+       movq    (%rsi), %rax    /* Read double word (8 bytes).  */
+       addq    $8, %rsi        /* Adjust pointer for next word.  */
+       movq    %rax, %r9       /* Save a copy for NUL finding.  */
+       addq    %r8, %r9        /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc     3f              /* highest byte is NUL => return pointer */
+       xorq    %rax, %r9       /* (word+magic)^word */
+       orq     %r8, %r9        /* set all non-carry bits */
+       incq    %r9             /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+
+       jnz     3f              /* found NUL => return pointer */
+
+       movq    %rax, (%rdx)    /* Write value to destination.  */
+       addq    $8, %rdx        /* Adjust pointer.  */
+
+       /* 3rd unroll.  */
+       movq    (%rsi), %rax    /* Read double word (8 bytes).  */
+       addq    $8, %rsi        /* Adjust pointer for next word.  */
+       movq    %rax, %r9       /* Save a copy for NUL finding.  */
+       addq    %r8, %r9        /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc     3f              /* highest byte is NUL => return pointer */
+       xorq    %rax, %r9       /* (word+magic)^word */
+       orq     %r8, %r9        /* set all non-carry bits */
+       incq    %r9             /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+
+       jnz     3f              /* found NUL => return pointer */
+
+       movq    %rax, (%rdx)    /* Write value to destination.  */
+       addq    $8, %rdx        /* Adjust pointer.  */
+
+       /* 4th unroll.  */
+       movq    (%rsi), %rax    /* Read double word (8 bytes).  */
+       addq    $8, %rsi        /* Adjust pointer for next word.  */
+       movq    %rax, %r9       /* Save a copy for NUL finding.  */
+       addq    %r8, %r9        /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc     3f              /* highest byte is NUL => return pointer */
+       xorq    %rax, %r9       /* (word+magic)^word */
+       orq     %r8, %r9        /* set all non-carry bits */
+       incq    %r9             /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+
+       jnz     3f              /* found NUL => return pointer */
+
+       movq    %rax, (%rdx)    /* Write value to destination.  */
+       addq    $8, %rdx        /* Adjust pointer.  */
+       jmp     1b              /* Next iteration.  */
+
+       /* Do the last few bytes. %rax contains the value to write.
+          The loop is unrolled twice.  */
+       .p2align 4
+3:
+       /* Note that stpcpy needs to return with the value of the NUL
+          byte.  */
+       movb    %al, (%rdx)     /* 1st byte.  */
+       testb   %al, %al        /* Is it NUL.  */
+       jz      4f              /* yes, finish.  */
+       incq    %rdx            /* Increment destination.  */
+       movb    %ah, (%rdx)     /* 2nd byte.  */
+       testb   %ah, %ah        /* Is it NUL?.  */
+       jz      4f              /* yes, finish.  */
+       incq    %rdx            /* Increment destination.  */
+       shrq    $16, %rax       /* Shift...  */
+       jmp     3b              /* and look at next two bytes in %rax.  */
+
+4:
+#ifdef USE_AS_STPCPY
+       movq    %rdx, %rax      /* Destination is return value.  */
+#else
+       movq    %rdi, %rax      /* Source is return value.  */
+#endif
+       retq
+END (BP_SYM (STRCPY))
diff --git a/sysdeps/x86_64/strcspn.S b/sysdeps/x86_64/strcspn.S
new file mode 100644 (file)
index 0000000..b488161
--- /dev/null
@@ -0,0 +1,123 @@
+/* strcspn (str, ss) -- Return the length of the initial segment of STR
+                       which contains no characters from SS.
+   For AMD x86-64.
+   Copyright (C) 1994, 1995, 1996, 1997, 2000, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>.
+   Bug fixes by Alan Modra <Alan@SPRI.Levels.UniSA.Edu.Au>.
+   Adopted for x86-64 by Andreas Jaeger <aj@suse.de>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include "asm-syntax.h"
+
+/* BEWARE: `#ifdef strcspn' means that strcspn is redefined as `strpbrk' */
+#define STRPBRK_P (defined strcspn)
+
+       .text
+ENTRY (strcspn)
+
+       movq %rdi, %rdx         /* Save SRC.  */
+
+       /* First we create a table with flags for all possible characters.
+          For the ASCII (7bit/8bit) or ISO-8859-X character sets which are
+          supported by the C string functions we have 256 characters.
+          Before inserting marks for the stop characters we clear the whole
+          table.  */
+       movq %rdi, %r8                  /* Save value.  */
+       subq $256, %rsp                 /* Make space for 256 bytes.  */
+       movq $32,  %rcx                 /* 32*8 bytes = 256 bytes.  */
+       movq %rsp, %rdi
+       xorq %rax, %rax                 /* We store 0s.  */
+       cld
+       rep
+       stosq
+
+       movq %rsi, %rax                 /* Setup skipset.  */
+
+/* For understanding the following code remember that %rcx == 0 now.
+   Although all the following instruction only modify %cl we always
+   have a correct zero-extended 64-bit value in %rcx.  */
+
+       .p2align 4
+L(2):  movb (%rax), %cl        /* get byte from skipset */
+       testb %cl, %cl          /* is NUL char? */
+       jz L(1)                 /* yes => start compare loop */
+       movb %cl, (%rsp,%rcx)   /* set corresponding byte in skipset table */
+
+       movb 1(%rax), %cl       /* get byte from skipset */
+       testb $0xff, %cl        /* is NUL char? */
+       jz L(1)                 /* yes => start compare loop */
+       movb %cl, (%rsp,%rcx)   /* set corresponding byte in skipset table */
+
+       movb 2(%rax), %cl       /* get byte from skipset */
+       testb $0xff, %cl        /* is NUL char? */
+       jz L(1)                 /* yes => start compare loop */
+       movb %cl, (%rsp,%rcx)   /* set corresponding byte in skipset table */
+
+       movb 3(%rax), %cl       /* get byte from skipset */
+       addq $4, %rax           /* increment skipset pointer */
+       movb %cl, (%rsp,%rcx)   /* set corresponding byte in skipset table */
+       testb $0xff, %cl        /* is NUL char? */
+       jnz L(2)                /* no => process next dword from skipset */
+
+L(1):  leaq -4(%rdx), %rax     /* prepare loop */
+
+       /* We use a neat trick for the following loop.  Normally we would
+          have to test for two termination conditions
+          1. a character in the skipset was found
+          and
+          2. the end of the string was found
+          But as a sign that the character is in the skipset we store its
+          value in the table.  But the value of NUL is NUL so the loop
+          terminates for NUL in every case.  */
+
+       .p2align 4
+L(3):  addq $4, %rax           /* adjust pointer for full loop round */
+
+       movb (%rax), %cl        /* get byte from string */
+       cmpb %cl, (%rsp,%rcx)   /* is it contained in skipset? */
+       je L(4)                 /* yes => return */
+
+       movb 1(%rax), %cl       /* get byte from string */
+       cmpb %cl, (%rsp,%rcx)   /* is it contained in skipset? */
+       je L(5)                 /* yes => return */
+
+       movb 2(%rax), %cl       /* get byte from string */
+       cmpb %cl, (%rsp,%rcx)   /* is it contained in skipset? */
+       jz L(6)                 /* yes => return */
+
+       movb 3(%rax), %cl       /* get byte from string */
+       cmpb %cl, (%rsp,%rcx)   /* is it contained in skipset? */
+       jne L(3)                /* no => start loop again */
+
+       incq %rax               /* adjust pointer */
+L(6):  incq %rax
+L(5):  incq %rax
+
+L(4):  addq $256, %rsp         /* remove skipset */
+#if STRPBRK_P
+       xorq %rdx,%rdx
+       orb %cl, %cl            /* was last character NUL? */
+       cmovzq %rdx, %rax       /* Yes: return NULL */
+#else  
+       subq %rdx, %rax         /* we have to return the number of valid
+                                  characters, so compute distance to first
+                                  non-valid character */
+#endif
+       ret
+END (strcspn)
diff --git a/sysdeps/x86_64/strlen.S b/sysdeps/x86_64/strlen.S
new file mode 100644 (file)
index 0000000..4441ba7
--- /dev/null
@@ -0,0 +1,138 @@
+/* strlen(str) -- determine the length of the string STR.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   Based on i486 version contributed by Ulrich Drepper <drepper@redhat.com>.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include "asm-syntax.h"
+#include "bp-sym.h"
+#include "bp-asm.h"
+
+
+       .text
+ENTRY (strlen)
+       movq %rdi, %rcx         /* Duplicate source pointer. */
+       andl $7, %ecx           /* mask alignment bits */
+       movq %rdi, %rax         /* duplicate destination.  */
+       jz 1f                   /* aligned => start loop */
+
+       neg %ecx                /* We need to align to 8 bytes.  */
+       addl $8,%ecx
+       /* Search the first bytes directly.  */
+0:     cmpb $0x0,(%rax)        /* is byte NUL? */
+       je 2f                   /* yes => return */
+       incq %rax               /* increment pointer */
+       decl %ecx
+       jnz 0b
+
+1:     movq $0xfefefefefefefeff,%r8 /* Save magic.  */
+
+       .p2align 4              /* Align loop.  */
+4:     /* Main Loop is unrolled 4 times.  */
+       /* First unroll.  */
+       movq (%rax), %rcx       /* get double word (= 8 bytes) in question */
+       addq $8,%rax            /* adjust pointer for next word */
+       movq %r8, %rdx          /* magic value */
+       addq %rcx, %rdx         /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc 3f                  /* highest byte is NUL => return pointer */
+       xorq %rcx, %rdx         /* (word+magic)^word */
+       orq %r8, %rdx           /* set all non-carry bits */
+       incq %rdx               /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+       jnz 3f                  /* found NUL => return pointer */
+
+       /* Second unroll.  */
+       movq (%rax), %rcx       /* get double word (= 8 bytes) in question */
+       addq $8,%rax            /* adjust pointer for next word */
+       movq %r8, %rdx          /* magic value */
+       addq %rcx, %rdx         /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc 3f                  /* highest byte is NUL => return pointer */
+       xorq %rcx, %rdx         /* (word+magic)^word */
+       orq %r8, %rdx           /* set all non-carry bits */
+       incq %rdx               /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+       jnz 3f                  /* found NUL => return pointer */
+
+       /* Third unroll.  */
+       movq (%rax), %rcx       /* get double word (= 8 bytes) in question */
+       addq $8,%rax            /* adjust pointer for next word */
+       movq %r8, %rdx          /* magic value */
+       addq %rcx, %rdx         /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc 3f                  /* highest byte is NUL => return pointer */
+       xorq %rcx, %rdx         /* (word+magic)^word */
+       orq %r8, %rdx           /* set all non-carry bits */
+       incq %rdx               /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+       jnz 3f                  /* found NUL => return pointer */
+
+       /* Fourth unroll.  */
+       movq (%rax), %rcx       /* get double word (= 8 bytes) in question */
+       addq $8,%rax            /* adjust pointer for next word */
+       movq %r8, %rdx          /* magic value */
+       addq %rcx, %rdx         /* add the magic value to the word.  We get
+                                  carry bits reported for each byte which
+                                  is *not* 0 */
+       jnc 3f                  /* highest byte is NUL => return pointer */
+       xorq %rcx, %rdx         /* (word+magic)^word */
+       orq %r8, %rdx           /* set all non-carry bits */
+       incq %rdx               /* add 1: if one carry bit was *not* set
+                                  the addition will not result in 0.  */
+       jz 4b                   /* no NUL found => continue loop */
+
+       .p2align 4              /* Align, it's a jump target.  */
+3:     subq $8,%rax            /* correct pointer increment.  */
+
+       testb %cl, %cl          /* is first byte NUL? */
+       jz 2f                   /* yes => return */
+       incq %rax               /* increment pointer */
+
+       testb %ch, %ch          /* is second byte NUL? */
+       jz 2f                   /* yes => return */
+       incq %rax               /* increment pointer */
+
+       testl $0x00ff0000, %ecx /* is third byte NUL? */
+       jz 2f                   /* yes => return pointer */
+       incq %rax               /* increment pointer */
+
+       testl $0xff000000, %ecx /* is fourth byte NUL? */
+       jz 2f                   /* yes => return pointer */
+       incq %rax               /* increment pointer */
+
+       shrq $32, %rcx          /* look at other half.  */
+
+       testb %cl, %cl          /* is first byte NUL? */
+       jz 2f                   /* yes => return */
+       incq %rax               /* increment pointer */
+
+       testb %ch, %ch          /* is second byte NUL? */
+       jz 2f                   /* yes => return */
+       incq %rax               /* increment pointer */
+
+       testl $0xff0000, %ecx   /* is third byte NUL? */
+       jz 2f                   /* yes => return pointer */
+       incq %rax               /* increment pointer */
+2:
+       subq %rdi, %rax         /* compute difference to string start */
+       ret
+END (strlen)
diff --git a/sysdeps/x86_64/strpbrk.S b/sysdeps/x86_64/strpbrk.S
new file mode 100644 (file)
index 0000000..9b97ada
--- /dev/null
@@ -0,0 +1,2 @@
+#define strcspn strpbrk
+#include <sysdeps/x86_64/strcspn.S>
diff --git a/sysdeps/x86_64/strspn.S b/sysdeps/x86_64/strspn.S
new file mode 100644 (file)
index 0000000..a8f0c07
--- /dev/null
@@ -0,0 +1,113 @@
+/* strspn (str, ss) -- Return the length of the initial segment of STR
+                       which contains only characters from SS.
+   For AMD x86-64.
+   Copyright (C) 1994, 1995, 1996, 1997, 2000, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>.
+   Bug fixes by Alan Modra <Alan@SPRI.Levels.UniSA.Edu.Au>.
+   Adopted for x86-64 by Andreas Jaeger <aj@suse.de>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+
+       .text
+ENTRY (strspn)
+
+       movq %rdi, %rdx         /* Save SRC.  */
+
+       /* First we create a table with flags for all possible characters.
+          For the ASCII (7bit/8bit) or ISO-8859-X character sets which are
+          supported by the C string functions we have 256 characters.
+          Before inserting marks for the stop characters we clear the whole
+          table.  */
+       movq %rdi, %r8                  /* Save value.  */
+       subq $256, %rsp                 /* Make space for 256 bytes.  */
+       movq $32,  %rcx                 /* 32*8 bytes = 256 bytes.  */
+       movq %rsp, %rdi
+       xorq %rax, %rax                 /* We store 0s.  */
+       cld
+       rep
+       stosq
+
+       movq %rsi, %rax                 /* Setup stopset.  */
+
+/* For understanding the following code remember that %rcx == 0 now.
+   Although all the following instruction only modify %cl we always
+   have a correct zero-extended 64-bit value in %rcx.  */
+
+       .p2align 4
+L(2):  movb (%rax), %cl        /* get byte from stopset */
+       testb %cl, %cl          /* is NUL char? */
+       jz L(1)                 /* yes => start compare loop */
+       movb %cl, (%rsp,%rcx)   /* set corresponding byte in stopset table */
+
+       movb 1(%rax), %cl       /* get byte from stopset */
+       testb $0xff, %cl        /* is NUL char? */
+       jz L(1)                 /* yes => start compare loop */
+       movb %cl, (%rsp,%rcx)   /* set corresponding byte in stopset table */
+
+       movb 2(%rax), %cl       /* get byte from stopset */
+       testb $0xff, %cl        /* is NUL char? */
+       jz L(1)                 /* yes => start compare loop */
+       movb %cl, (%rsp,%rcx)   /* set corresponding byte in stopset table */
+
+       movb 3(%rax), %cl       /* get byte from stopset */
+       addq $4, %rax           /* increment stopset pointer */
+       movb %cl, (%rsp,%rcx)   /* set corresponding byte in stopset table */
+       testb $0xff, %cl        /* is NUL char? */
+       jnz L(2)                /* no => process next dword from stopset */
+
+L(1):  leaq -4(%rdx), %rax     /* prepare loop */
+
+       /* We use a neat trick for the following loop.  Normally we would
+          have to test for two termination conditions
+          1. a character in the stopset was found
+          and
+          2. the end of the string was found
+          But as a sign that the character is in the stopset we store its
+          value in the table.  But the value of NUL is NUL so the loop
+          terminates for NUL in every case.  */
+
+       .p2align 4
+L(3):  addq $4, %rax           /* adjust pointer for full loop round */
+
+       movb (%rax), %cl        /* get byte from string */
+       testb %cl, (%rsp,%rcx)  /* is it contained in skipset? */
+       jz L(4)                 /* no => return */
+
+       movb 1(%rax), %cl       /* get byte from string */
+       testb %cl, (%rsp,%rcx)  /* is it contained in skipset? */
+       jz L(5)                 /* no => return */
+
+       movb 2(%rax), %cl       /* get byte from string */
+       testb %cl, (%rsp,%rcx)  /* is it contained in skipset? */
+       jz L(6)                 /* no => return */
+
+       movb 3(%rax), %cl       /* get byte from string */
+       testb %cl, (%rsp,%rcx)  /* is it contained in skipset? */
+       jnz L(3)                /* yes => start loop again */
+
+       incq %rax               /* adjust pointer */
+L(6):  incq %rax
+L(5):  incq %rax
+
+L(4):  addq $256, %rsp         /* remove stopset */
+       subq %rdx, %rax         /* we have to return the number of valid
+                                  characters, so compute distance to first
+                                  non-valid character */
+       ret
+END (strspn)