summaryrefslogtreecommitdiff
path: root/sysdeps/i386
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>1995-10-16 01:37:51 +0000
committerRoland McGrath <roland@gnu.org>1995-10-16 01:37:51 +0000
commit8f5ca04bc7fd53741d80117df992995ace8f6d2d (patch)
treee39c13fc198b22ec55647259a8080051988e8c69 /sysdeps/i386
parent5d82cf5c55f56ae10d3b0a205d1fcc7de1cf56a0 (diff)
Sat Oct 14 02:52:36 1995 Ulrich Drepper <drepper@ipd.info.uni-karlsruhe.de>
* malloc/malloc.c (_malloc_internal): Performance fix. Move if statement out of loop. * stdio/_itoa.c, stdio/_itoa.h: Complete rewrite. Much faster implementation using GMP functions. Contributed by Torbjorn Granlund and Ulrich Drepper. * stdio/test_rdwr.c: Include <errno.h>. * sysdeps/i386/i586/Implies: New file. New highly optimized string functions for i[345]86. * sysdeps/i386/memchr.S, sysdeps/i386/memcmp.S: New files. * sysdeps/i386/stpcpy.S, sysdeps/i386/stpncpy.S: New files. * sysdeps/i386/strchr.S, sysdeps/i386/strcspn.S: New files. * sysdeps/i386/strpbrk.S, sysdeps/i386/strrchr.S: New files. * sysdeps/i386/strspn.S, sysdeps/i386/i486/strcat.S: New files. * sysdeps/i386/i486/strlen.S, sysdeps/i386/i586/strchr.S: New files. * sysdeps/i386/i586/strlen.S: New file. * sysdeps/i386/memchr.c: Removed. There is now an assembler version. * sysdeps/i386/i586/memcopy.h (WORD_COPY_BWD): Parameters did not correspond to used values. * sysdeps/unix/sysv/linux/nfs/nfs.h: New file. Simply a wrapper around a kernel header file. * sysdeps/unix/sysv/linux/Dist: Add it. * sysdeps/unix/sysv/linux/Makefile [$(subdir)=sunrpc] (headers): Likewise. * sysdeps/unix/sysv/linux/local_lim.h: Rewrite. Instead of defining ourself we use a kernel header file. * sysdeps/unix/sysv/linux/i386/sysdep.h (DO_CALL): Optimize system call handler for i586. * sysdeps/unix/sysv/linux/sys/param.h: Add copyright and clean up. Sat Oct 14 02:52:36 1995 Ulrich Drepper <drepper@ipd.info.uni-karlsruhe.de> * malloc/malloc.c (_malloc_internal): Performance fix. Move if statement out of loop. * stdio/_itoa.c, stdio/_itoa.h: Complete rewrite. Much faster implementation using GMP functions. Contributed by Torbjorn Granlund and Ulrich Drepper. * stdio/test_rdwr.c: Include <errno.h>. * sysdeps/i386/i586/Implies: New file. New highly optimized string functions for i[345]86. * sysdeps/i386/memchr.S, sysdeps/i386/memcmp.S: New files. * sysdeps/i386/stpcpy.S, sysdeps/i386/stpncpy.S: New files. * sysdeps/i386/strchr.S, sysdeps/i386/strcspn.S: New files. * sysdeps/i386/strpbrk.S, sysdeps/i386/strrchr.S: New files. * sysdeps/i386/strspn.S, sysdeps/i386/i486/strcat.S: New files. * sysdeps/i386/i486/strlen.S, sysdeps/i386/i586/strchr.S: New files. * sysdeps/i386/i586/strlen.S: New file. * sysdeps/i386/memchr.c: Removed. There is now an assembler version. * sysdeps/i386/i586/memcopy.h (WORD_COPY_BWD): Parameters did not correspond to used values. * sysdeps/unix/sysv/linux/nfs/nfs.h: New file. Simply a wrapper around a kernel header file. * sysdeps/unix/sysv/linux/Dist: Add it. * sysdeps/unix/sysv/linux/Makefile [$(subdir)=sunrpc] (headers): Likewise. * sysdeps/unix/sysv/linux/local_lim.h: Rewrite. Instead of defining ourself we use a kernel header file. * sysdeps/unix/sysv/linux/i386/sysdep.h (DO_CALL): Optimize system call handler for i586. * sysdeps/unix/sysv/linux/sys/param.h: Add copyright and clean up.
Diffstat (limited to 'sysdeps/i386')
-rw-r--r--sysdeps/i386/add_n.S18
-rw-r--r--sysdeps/i386/gmp-mparam.h28
-rw-r--r--sysdeps/i386/i486/strcat.S260
-rw-r--r--sysdeps/i386/i486/strlen.S132
-rw-r--r--sysdeps/i386/i586/Implies2
-rw-r--r--sysdeps/i386/i586/add_n.S136
-rw-r--r--sysdeps/i386/i586/addmul_1.S84
-rw-r--r--sysdeps/i386/i586/lshift.S213
-rw-r--r--sysdeps/i386/i586/memcopy.h6
-rw-r--r--sysdeps/i386/i586/mul_1.S78
-rw-r--r--sysdeps/i386/i586/rshift.S213
-rw-r--r--sysdeps/i386/i586/strchr.S334
-rw-r--r--sysdeps/i386/i586/strlen.S185
-rw-r--r--sysdeps/i386/i586/sub_n.S136
-rw-r--r--sysdeps/i386/i586/submul_1.S82
-rw-r--r--sysdeps/i386/memchr.S315
-rw-r--r--sysdeps/i386/memchr.c48
-rw-r--r--sysdeps/i386/memcmp.S68
-rw-r--r--sysdeps/i386/stpcpy.S87
-rw-r--r--sysdeps/i386/stpncpy.S143
-rw-r--r--sysdeps/i386/strchr.S278
-rw-r--r--sysdeps/i386/strcspn.S176
-rw-r--r--sysdeps/i386/strpbrk.S177
-rw-r--r--sysdeps/i386/strrchr.S321
-rw-r--r--sysdeps/i386/strspn.S176
-rw-r--r--sysdeps/i386/sub_n.S26
26 files changed, 3653 insertions, 69 deletions
diff --git a/sysdeps/i386/add_n.S b/sysdeps/i386/add_n.S
index c4e71ea8c7..c3b3c3e4e1 100644
--- a/sysdeps/i386/add_n.S
+++ b/sysdeps/i386/add_n.S
@@ -1,7 +1,7 @@
/* i80386 __mpn_add_n -- Add two limb vectors of the same length > 0 and store
sum in a third limb vector.
-Copyright (C) 1992, 1994 Free Software Foundation, Inc.
+Copyright (C) 1992, 1994, 1995 Free Software Foundation, Inc.
This file is part of the GNU MP Library.
@@ -54,14 +54,18 @@ C_SYMBOL_NAME(__mpn_add_n:)
subl %eax,%edx /* ... enter the loop */
shrl $2,%eax /* restore previous value */
#ifdef PIC
- call here
-here: leal (Loop - 3 - here)(%eax,%eax,8),%eax
- addl %eax,(%esp)
- ret
+/* Calculate start address in loop for PIC. Due to limitations in some
+ assemblers, Loop-L0-3 cannot be put into the leal */
+ call L0
+L0: leal (%eax,%eax,8),%eax
+ addl (%esp),%eax
+ addl $(Loop-L0-3),%eax
+ addl $4,%esp
#else
- leal (Loop - 3)(%eax,%eax,8),%eax /* calc start addr in loop */
- jmp *%eax /* jump into loop */
+/* Calculate start address in loop for non-PIC. */
+ leal (Loop - 3)(%eax,%eax,8),%eax
#endif
+ jmp *%eax /* jump into loop */
ALIGN (3)
Loop: movl (%esi),%eax
adcl (%edx),%eax
diff --git a/sysdeps/i386/gmp-mparam.h b/sysdeps/i386/gmp-mparam.h
new file mode 100644
index 0000000000..687f12aa35
--- /dev/null
+++ b/sysdeps/i386/gmp-mparam.h
@@ -0,0 +1,28 @@
+/* gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright (C) 1991, 1993, 1994 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Library General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+The GNU MP 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 Library General Public
+License for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define BITS_PER_MP_LIMB 32
+#define BYTES_PER_MP_LIMB 4
+#define BITS_PER_LONGINT 32
+#define BITS_PER_INT 32
+#define BITS_PER_SHORTINT 16
+#define BITS_PER_CHAR 8
+
+#define IEEE_DOUBLE_BIG_ENDIAN 0
diff --git a/sysdeps/i386/i486/strcat.S b/sysdeps/i386/i486/strcat.S
new file mode 100644
index 0000000000..e3d2181bdb
--- /dev/null
+++ b/sysdeps/i386/i486/strcat.S
@@ -0,0 +1,260 @@
+/* strcat(dest, src) -- Append SRC on the end of DEST.
+For Intel 80x86, x>=4.
+Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+Contributed by Ulrich Drepper <drepper@ipd.info.uni-karlsruhe.de>.
+Optimised a little by Alan Modra <Alan@SPRI.Levels.UniSA.Edu.Au>
+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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. 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"
+
+/*
+ INPUT PARAMETERS:
+ dest (sp + 4)
+ src (sp + 8)
+*/
+
+ .text
+ENTRY (strcat)
+ pushl %edi /* Save callee-safe register. */
+
+ movl 12(%esp), %ecx /* load source pointer */
+ movl 8(%esp), %edx /* load destination pointer */
+
+ testb $0xff, (%ecx) /* Is source string empty? */
+ jz L8 /* yes => return */
+
+ /* Test the first bytes separately until destination is aligned. */
+ testb $3, %edx /* destination pointer aligned? */
+ jz L1 /* yes => begin scan loop */
+ testb $0xff, (%edx) /* is end of string? */
+ jz L2 /* yes => start appending */
+ incl %edx /* increment source pointer */
+
+ testb $3, %edx /* destination pointer aligned? */
+ jz L1 /* yes => begin scan loop */
+ testb $0xff, (%edx) /* is end of string? */
+ jz L2 /* yes => start appending */
+ incl %edx /* increment source pointer */
+
+ testb $3, %edx /* destination pointer aligned? */
+ jz L1 /* yes => begin scan loop */
+ testb $0xff, (%edx) /* is end of string? */
+ jz L2 /* yes => start appending */
+ incl %edx /* increment source pointer */
+
+ /* Now we are aligned. Begin scan loop. */
+ jmp L1
+
+ ALIGN(4)
+
+L4: addl $16,%edx /* increment destination pointer for round */
+
+L1: movl (%edx), %eax /* get word (= 4 bytes) in question */
+ movl $0xfefefeff, %edi /* magic value */
+
+ /* If you compare this with the algorithm in memchr.S you will
+ notice that here is an `xorl' statement missing. But you must
+ not forget that we are looking for C == 0 and `xorl $0, %eax'
+ is a no-op. */
+
+ addl %eax, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+
+ /* According to the algorithm we had to reverse the effect of the
+ XOR first and then test the overflow bits. But because the
+ following XOR would destroy the carry flag and it would (in a
+ representation with more than 32 bits) not alter then last
+ overflow, we can now test this condition. If no carry is signaled
+ no overflow must have occured in the last byte => it was 0. */
+ jnc L3
+
+ /* We are only interested in carry bits that change due to the
+ previous add, so remove original bits */
+ xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
+
+ /* Now test for the other three overflow bits. */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+
+ /* If at least one byte of the word is C we don't get 0 in %ecx. */
+ jnz L3
+
+ movl 4(%edx), %eax /* get word from source */
+ movl $0xfefefeff, %edi /* magic value */
+ addl %eax, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L5 /* highest byte is C => stop copying */
+ xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jnz L5 /* one byte is NUL => stop copying */
+
+ movl 8(%edx), %eax /* get word from source */
+ movl $0xfefefeff, %edi /* magic value */
+ addl %eax, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L6 /* highest byte is C => stop copying */
+ xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jnz L6 /* one byte is NUL => stop copying */
+
+ movl 12(%edx), %eax /* get word from source */
+ movl $0xfefefeff, %edi /* magic value */
+ addl %eax, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L7 /* highest byte is C => stop copying */
+ xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jz L4 /* no byte is NUL => carry on copying */
+
+L7: addl $4, %edx /* adjust source pointer */
+L6: addl $4, %edx
+L5: addl $4, %edx
+
+L3: testb %al, %al /* is first byte NUL? */
+ jz L2 /* yes => start copying */
+ incl %edx /* increment source pointer */
+
+ testb %ah, %ah /* is second byte NUL? */
+ jz L2 /* yes => start copying */
+ incl %edx /* increment source pointer */
+
+ testl $0xff0000, %eax /* is third byte NUL? */
+ jz L2 /* yes => start copying */
+ incl %edx /* increment source pointer */
+
+L2: subl %ecx, %edx /* reduce number of loop variants */
+
+ /* Now we have to align the source pointer. */
+ testb $3, %ecx /* pointer correctly aligned? */
+ jz L29 /* yes => start copy loop */
+ movb (%ecx), %al /* get first byte */
+ movb %al, (%ecx,%edx) /* and store it */
+ andl %al, %al /* is byte NUL? */
+ jz L8 /* yes => return */
+ incl %ecx /* increment pointer */
+
+ testb $3, %ecx /* pointer correctly aligned? */
+ jz L29 /* yes => start copy loop */
+ movb (%ecx), %al /* get first byte */
+ movb %al, (%ecx,%edx) /* and store it */
+ andl %al, %al /* is byte NUL? */
+ jz L8 /* yes => return */
+ incl %ecx /* increment pointer */
+
+ testb $3, %ecx /* pointer correctly aligned? */
+ jz L29 /* yes => start copy loop */
+ movb (%ecx), %al /* get first byte */
+ movb %al, (%ecx,%edx) /* and store it */
+ andl %al, %al /* is byte NUL? */
+ jz L8 /* yes => return */
+ incl %ecx /* increment pointer */
+
+ /* Now we are aligned. */
+ jmp L29 /* start copy loop */
+
+ ALIGN(4)
+
+L28: movl %eax, 12(%ecx,%edx)/* store word at destination */
+ addl $16, %ecx /* adjust pointer for full round */
+
+L29: movl (%ecx), %eax /* get word from source */
+ movl $0xfefefeff, %edi /* magic value */
+ addl %eax, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L9 /* highest byte is C => stop copying */
+ xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jnz L9 /* one byte is NUL => stop copying */
+ movl %eax, (%ecx,%edx) /* store word to destination */
+
+ movl 4(%ecx), %eax /* get word from source */
+ movl $0xfefefeff, %edi /* magic value */
+ addl %eax, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L91 /* highest byte is C => stop copying */
+ xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jnz L91 /* one byte is NUL => stop copying */
+ movl %eax, 4(%ecx,%edx) /* store word to destination */
+
+ movl 8(%ecx), %eax /* get word from source */
+ movl $0xfefefeff, %edi /* magic value */
+ addl %eax, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L92 /* highest byte is C => stop copying */
+ xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jnz L92 /* one byte is NUL => stop copying */
+ movl %eax, 8(%ecx,%edx) /* store word to destination */
+
+ movl 12(%ecx), %eax /* get word from source */
+ movl $0xfefefeff, %edi /* magic value */
+ addl %eax, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L93 /* highest byte is C => stop copying */
+ xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jz L28 /* no is NUL => carry on copying */
+
+L93: addl $4, %ecx /* adjust pointer */
+L92: addl $4, %ecx
+L91: addl $4, %ecx
+
+L9: movb %al, (%ecx,%edx) /* store first byte of last word */
+ orb %al, %al /* is it NUL? */
+ jz L8 /* yes => return */
+
+ movb %ah, 1(%ecx,%edx) /* store second byte of last word */
+ orb %ah, %ah /* is it NUL? */
+ jz L8 /* yes => return */
+
+ shrl $16, %eax /* make upper bytes accessible */
+ movb %al, 2(%ecx,%edx) /* store third byte of last word */
+ orb %al, %al /* is it NUL? */
+ jz L8 /* yes => return */
+
+ movb %ah, 3(%ecx,%edx) /* store fourth byte of last word */
+
+L8: movl 8(%esp), %eax /* start address of destination is result */
+ popl %edi /* restore saved register */
+
+ ret
diff --git a/sysdeps/i386/i486/strlen.S b/sysdeps/i386/i486/strlen.S
new file mode 100644
index 0000000000..276563b11a
--- /dev/null
+++ b/sysdeps/i386/i486/strlen.S
@@ -0,0 +1,132 @@
+/* strlen(str) -- determine the length of the string STR.
+Optimized for Intel 80x86, x>=4.
+Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>.
+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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. 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"
+
+/*
+ INPUT PARAMETERS:
+ str (sp + 4)
+*/
+
+ .text
+ENTRY (strlen)
+ movl 4(%esp), %ecx /* get string pointer */
+ movl %ecx, %eax /* duplicate it */
+
+ andl $3, %ecx /* mask alignment bits */
+ jz L1 /* aligned => start loop */
+ cmpb %ch, (%eax) /* is byte NUL? */
+ je L2 /* yes => return */
+ incl %eax /* increment pointer */
+
+ xorl $3, %ecx /* was alignment = 3? */
+ jz L1 /* yes => now it is aligned and start loop */
+ cmpb %ch, (%eax) /* is byte NUL? */
+ je L2 /* yes => return */
+ addl $1, %eax /* increment pointer */
+
+ subl $1, %ecx /* was alignment = 2? */
+ jz L1 /* yes => now it is aligned and start loop */
+ cmpb %ch, (%eax) /* is byte NUL? */
+ je L2 /* yes => return */
+
+/* Don't change the above `addl $1,%eax' and `subl $1, %ecx' into `incl %eax'
+ and `decl %ecx' resp. The additional two byte per instruction make the
+ label 4 to be aligned on a 16 byte boundary with nops.
+
+ The following `sub $15, %eax' is part of this trick, too. Together with
+ the next instruction (`addl $16, %eax') it is in fact a `incl %eax', just
+ as expected from the algorithm. But doing so has the advantage that
+ no jump to label 1 is necessary and so the pipeline is not flushed. */
+
+ subl $15, %eax /* effectively +1 */
+
+
+L4: addl $16, %eax /* adjust pointer for full loop */
+
+L1: movl (%eax), %ecx /* get word (= 4 bytes) in question */
+ movl $0xfefefeff, %edx /* magic value */
+ addl %ecx, %edx /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L3 /* highest byte is NUL => return pointer */
+ xorl %ecx, %edx /* (word+magic)^word */
+ orl $0xfefefeff, %edx /* set all non-carry bits */
+ incl %edx /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jnz L3 /* found NUL => return pointer */
+
+ movl 4(%eax), %ecx /* get word (= 4 bytes) in question */
+ movl $0xfefefeff, %edx /* magic value */
+ addl %ecx, %edx /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L5 /* highest byte is NUL => return pointer */
+ xorl %ecx, %edx /* (word+magic)^word */
+ orl $0xfefefeff, %edx /* set all non-carry bits */
+ incl %edx /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jnz L5 /* found NUL => return pointer */
+
+ movl 8(%eax), %ecx /* get word (= 4 bytes) in question */
+ movl $0xfefefeff, %edx /* magic value */
+ addl %ecx, %edx /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L6 /* highest byte is NUL => return pointer */
+ xorl %ecx, %edx /* (word+magic)^word */
+ orl $0xfefefeff, %edx /* set all non-carry bits */
+ incl %edx /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jnz L6 /* found NUL => return pointer */
+
+ movl 12(%eax), %ecx /* get word (= 4 bytes) in question */
+ movl $0xfefefeff, %edx /* magic value */
+ addl %ecx, %edx /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L7 /* highest byte is NUL => return pointer */
+ xorl %ecx, %edx /* (word+magic)^word */
+ orl $0xfefefeff, %edx /* set all non-carry bits */
+ incl %edx /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jz L4 /* no NUL found => continue loop */
+
+L7: addl $4, %eax /* adjust pointer */
+L6: addl $4, %eax
+L5: addl $4, %eax
+
+L3: testb %cl, %cl /* is first byte NUL? */
+ jz L2 /* yes => return */
+ incl %eax /* increment pointer */
+
+ testb %ch, %ch /* is second byte NUL? */
+ jz L2 /* yes => return */
+ incl %eax /* increment pointer */
+
+ testl $0xff0000, %ecx /* is third byte NUL? */
+ jz L2 /* yes => return pointer */
+ incl %eax /* increment pointer */
+
+L2: subl 4(%esp), %eax /* compute difference to string start */
+
+ ret
diff --git a/sysdeps/i386/i586/Implies b/sysdeps/i386/i586/Implies
new file mode 100644
index 0000000000..477cd741ce
--- /dev/null
+++ b/sysdeps/i386/i586/Implies
@@ -0,0 +1,2 @@
+# Code optimized for i486 is better than simple i386 code.
+i386/i486
diff --git a/sysdeps/i386/i586/add_n.S b/sysdeps/i386/i586/add_n.S
new file mode 100644
index 0000000000..9be45ed93b
--- /dev/null
+++ b/sysdeps/i386/i586/add_n.S
@@ -0,0 +1,136 @@
+/* Pentium __mpn_add_n -- Add two limb vectors of the same length > 0 and store
+ sum in a third limb vector.
+
+Copyright (C) 1992, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Library General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+The GNU MP 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 Library General Public
+License for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ INPUT PARAMETERS
+ res_ptr (sp + 4)
+ s1_ptr (sp + 8)
+ s2_ptr (sp + 12)
+ size (sp + 16)
+*/
+
+#define r1 %eax
+#define r2 %edx
+#define src1 %esi
+#define src2 %ebp
+#define dst %edi
+#define x %ebx
+
+#include "sysdep.h"
+#include "asm-syntax.h"
+
+.text
+ ALIGN (3)
+ .globl C_SYMBOL_NAME(__mpn_add_n)
+C_SYMBOL_NAME(__mpn_add_n:)
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+ pushl %ebp
+
+ movl 20(%esp),dst /* res_ptr */
+ movl 24(%esp),src1 /* s1_ptr */
+ movl 28(%esp),src2 /* s2_ptr */
+ movl 32(%esp),%ecx /* size */
+
+ movl (src2),x
+
+ decl %ecx
+ movl %ecx,r2
+ shrl $3,%ecx
+ andl $7,r2
+ testl %ecx,%ecx /* zero carry flag */
+ jz Lend
+ pushl r2
+
+ ALIGN (3)
+Loop: movl 28(dst),%eax /* fetch destination cache line */
+ leal 32(dst),dst
+
+L1: movl (src1),r1
+ movl 4(src1),r2
+ adcl x,r1
+ movl 4(src2),x
+ adcl x,r2
+ movl 8(src2),x
+ movl r1,-32(dst)
+ movl r2,-28(dst)
+
+L2: movl 8(src1),r1
+ movl 12(src1),r2
+ adcl x,r1
+ movl 12(src2),x
+ adcl x,r2
+ movl 16(src2),x
+ movl r1,-24(dst)
+ movl r2,-20(dst)
+
+L3: movl 16(src1),r1
+ movl 20(src1),r2
+ adcl x,r1
+ movl 20(src2),x
+ adcl x,r2
+ movl 24(src2),x
+ movl r1,-16(dst)
+ movl r2,-12(dst)
+
+L4: movl 24(src1),r1
+ movl 28(src1),r2
+ adcl x,r1
+ movl 28(src2),x
+ adcl x,r2
+ movl 32(src2),x
+ movl r1,-8(dst)
+ movl r2,-4(dst)
+
+ leal 32(src1),src1
+ leal 32(src2),src2
+ decl %ecx
+ jnz Loop
+
+ popl r2
+Lend:
+ decl r2 /* test r2 w/o clobbering carry */
+ js Lend2
+ incl r2
+Loop2:
+ leal 4(dst),dst
+ movl (src1),r1
+ adcl x,r1
+ movl 4(src2),x
+ movl r1,-4(dst)
+ leal 4(src1),src1
+ leal 4(src2),src2
+ decl r2
+ jnz Loop2
+Lend2:
+ movl (src1),r1
+ adcl x,r1
+ movl r1,(dst)
+
+ sbbl %eax,%eax
+ negl %eax
+
+ popl %ebp
+ popl %ebx
+ popl %esi
+ popl %edi
+ ret
diff --git a/sysdeps/i386/i586/addmul_1.S b/sysdeps/i386/i586/addmul_1.S
new file mode 100644
index 0000000000..b222840591
--- /dev/null
+++ b/sysdeps/i386/i586/addmul_1.S
@@ -0,0 +1,84 @@
+/* Pentium __mpn_addmul_1 -- Multiply a limb vector with a limb and add
+ the result to a second limb vector.
+
+Copyright (C) 1992, 1994 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Library General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+The GNU MP 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 Library General Public
+License for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ INPUT PARAMETERS
+ res_ptr (sp + 4)
+ s1_ptr (sp + 8)
+ size (sp + 12)
+ s2_limb (sp + 16)
+*/
+
+#include "sysdep.h"
+#include "asm-syntax.h"
+
+#define res_ptr edi
+#define s1_ptr esi
+#define s2_limb ebp
+
+ TEXT
+ ALIGN (3)
+ GLOBL C_SYMBOL_NAME(__mpn_addmul_1)
+ .type C_SYMBOL_NAME(__mpn_addmul_1),@function
+C_SYMBOL_NAME(__mpn_addmul_1:)
+
+ INSN1(push,l ,R(edi))
+ INSN1(push,l ,R(esi))
+ INSN1(push,l ,R(ebx))
+ INSN1(push,l ,R(ebp))
+
+ INSN2(mov,l ,R(res_ptr),MEM_DISP(esp,20))
+ INSN2(mov,l ,R(s1_ptr),MEM_DISP(esp,24))
+ INSN2(mov,l ,R(ecx),MEM_DISP(esp,28))
+ INSN2(mov,l ,R(s2_limb),MEM_DISP(esp,32))
+
+ INSN2(lea,l ,R(res_ptr),MEM_INDEX(res_ptr,ecx,4))
+ INSN2(lea,l ,R(s1_ptr),MEM_INDEX(s1_ptr,ecx,4))
+ INSN1(neg,l ,R(ecx))
+ INSN2(xor,l ,R(edx),R(edx))
+ ALIGN (3)
+Loop:
+ INSN2(mov,l ,R(ebx),R(edx))
+ INSN2(mov,l ,R(eax),MEM_INDEX(s1_ptr,ecx,4))
+
+ INSN1(mul,l ,R(s2_limb))
+
+ INSN2(add,l ,R(eax),R(ebx))
+ INSN2(mov,l ,R(ebx),MEM_INDEX(res_ptr,ecx,4))
+
+ INSN2(adc,l ,R(edx),$0)
+ INSN2(add,l ,R(ebx),R(eax))
+
+ INSN2(adc,l ,R(edx),$0)
+ INSN2(mov,l ,MEM_INDEX(res_ptr,ecx,4),R(ebx))
+
+ INSN1(inc,l ,R(ecx))
+ INSN1(jnz, ,Loop)
+
+
+ INSN2(mov,l ,R(eax),R(edx))
+ INSN1(pop,l ,R(ebp))
+ INSN1(pop,l ,R(ebx))
+ INSN1(pop,l ,R(esi))
+ INSN1(pop,l ,R(edi))
+ ret
+Lfe1:
+ .size C_SYMBOL_NAME(__mpn_addmul_1),Lfe1-C_SYMBOL_NAME(__mpn_addmul_1)
diff --git a/sysdeps/i386/i586/lshift.S b/sysdeps/i386/i586/lshift.S
new file mode 100644
index 0000000000..b9f8131297
--- /dev/null
+++ b/sysdeps/i386/i586/lshift.S
@@ -0,0 +1,213 @@
+/* Pentium optimized __mpn_lshift --
+
+Copyright (C) 1992, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Library General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+The GNU MP 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 Library General Public
+License for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ INPUT PARAMETERS
+ res_ptr (sp + 4)
+ s_ptr (sp + 8)
+ size (sp + 12)
+ cnt (sp + 16)
+*/
+
+#include "sysdep.h"
+#include "asm-syntax.h"
+
+.text
+ ALIGN (3)
+ .globl C_SYMBOL_NAME(__mpn_lshift)
+C_SYMBOL_NAME(__mpn_lshift:)
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+ pushl %ebp
+
+ movl 20(%esp),%edi /* res_ptr */
+ movl 24(%esp),%esi /* s_ptr */
+ movl 28(%esp),%ebp /* size */
+ movl 32(%esp),%ecx /* cnt */
+
+ cmp $1,%ecx
+ jne Lnormal
+ movl %edi,%eax
+ subl %esi,%eax
+ cmpl %ebp,%eax
+ jnc Lspecial
+
+Lnormal:
+ leal -4(%edi,%ebp,4),%edi
+ leal -4(%esi,%ebp,4),%esi
+
+ movl (%esi),%edx
+ subl $4,%esi
+ xorl %eax,%eax
+ shldl %cl,%edx,%eax /* compute carry limb */
+ pushl %eax /* push carry limb onto stack */
+
+ decl %ebp
+ pushl %ebp
+ shrl $3,%ebp
+ jz Lend
+
+ movl (%edi),%eax /* fetch destination cache line */
+
+ ALIGN (2)
+Loop: movl -28(%edi),%eax /* fetch destination cache line */
+ movl %edx,%ebx
+
+ movl (%esi),%eax
+ movl -4(%esi),%edx
+ shldl %cl,%eax,%ebx
+ shldl %cl,%edx,%eax
+ movl %ebx,(%edi)
+ movl %eax,-4(%edi)
+
+ movl -8(%esi),%ebx
+ movl -12(%esi),%eax
+ shldl %cl,%ebx,%edx
+ shldl %cl,%eax,%ebx
+ movl %edx,-8(%edi)
+ movl %ebx,-12(%edi)
+
+ movl -16(%esi),%edx
+ movl -20(%esi),%ebx
+ shldl %cl,%edx,%eax
+ shldl %cl,%ebx,%edx
+ movl %eax,-16(%edi)
+ movl %edx,-20(%edi)
+
+ movl -24(%esi),%eax
+ movl -28(%esi),%edx
+ shldl %cl,%eax,%ebx
+ shldl %cl,%edx,%eax
+ movl %ebx,-24(%edi)
+ movl %eax,-28(%edi)
+
+ subl $32,%esi
+ subl $32,%edi
+ decl %ebp
+ jnz Loop
+
+Lend: popl %ebp
+ andl $7,%ebp
+ jz Lend2
+Loop2: movl (%esi),%eax
+ shldl %cl,%eax,%edx
+ movl %edx,(%edi)
+ movl %eax,%edx
+ subl $4,%esi
+ subl $4,%edi
+ decl %ebp
+ jnz Loop2
+
+Lend2: shll %cl,%edx /* compute least significant limb */
+ movl %edx,(%edi) /* store it */
+
+ popl %eax /* pop carry limb */
+
+ popl %ebp
+ popl %ebx
+ popl %esi
+ popl %edi
+ ret
+
+/* We loop from least significant end of the arrays, which is only
+ permissable if the source and destination don't overlap, since the
+ function is documented to work for overlapping source and destination.
+*/
+
+Lspecial:
+ movl (%esi),%edx
+ addl $4,%esi
+
+ decl %ebp
+ pushl %ebp
+ shrl $3,%ebp
+
+ addl %edx,%edx
+ incl %ebp
+ decl %ebp
+ jz LLend
+
+ movl (%edi),%eax /* fetch destination cache line */
+
+ ALIGN (2)
+LLoop: movl 28(%edi),%eax /* fetch destination cache line */
+ movl %edx,%ebx
+
+ movl (%esi),%eax
+ movl 4(%esi),%edx
+ adcl %eax,%eax
+ movl %ebx,(%edi)
+ adcl %edx,%edx
+ movl %eax,4(%edi)
+
+ movl 8(%esi),%ebx
+ movl 12(%esi),%eax
+ adcl %ebx,%ebx
+ movl %edx,8(%edi)
+ adcl %eax,%eax
+ movl %ebx,12(%edi)
+
+ movl 16(%esi),%edx
+ movl 20(%esi),%ebx
+ adcl %edx,%edx
+ movl %eax,16(%edi)
+ adcl %ebx,%ebx
+ movl %edx,20(%edi)
+
+ movl 24(%esi),%eax
+ movl 28(%esi),%edx
+ adcl %eax,%eax
+ movl %ebx,24(%edi)
+ adcl %edx,%edx
+ movl %eax,28(%edi)
+
+ leal 32(%esi),%esi /* use leal not to clobber carry */
+ leal 32(%edi),%edi
+ decl %ebp
+ jnz LLoop
+
+LLend: popl %ebp
+ sbbl %eax,%eax /* save carry in %eax */
+ andl $7,%ebp
+ jz LLend2
+ addl %eax,%eax /* restore carry from eax */
+LLoop2: movl %edx,%ebx
+ movl (%esi),%edx
+ adcl %edx,%edx
+ movl %ebx,(%edi)
+
+ leal 4(%esi),%esi /* use leal not to clobber carry */
+ leal 4(%edi),%edi
+ decl %ebp
+ jnz LLoop2
+
+ jmp LL1
+LLend2: addl %eax,%eax /* restore carry from eax */
+LL1: movl %edx,(%edi) /* store last limb */
+
+ sbbl %eax,%eax
+ negl %eax
+
+ popl %ebp
+ popl %ebx
+ popl %esi
+ popl %edi
+ ret
diff --git a/sysdeps/i386/i586/memcopy.h b/sysdeps/i386/i586/memcopy.h
index a9bb9e7a40..0a8768788e 100644
--- a/sysdeps/i386/i586/memcopy.h
+++ b/sysdeps/i386/i586/memcopy.h
@@ -1,5 +1,5 @@
/* memcopy.h -- definitions for memory copy functions. Pentium version.
- Copyright (C) 1994 Free Software Foundation, Inc.
+ Copyright (C) 1994, 1995 Free Software Foundation, Inc.
Contributed by Torbjorn Granlund (tege@sics.se).
This file is part of the GNU C Library.
@@ -88,7 +88,7 @@ Cambridge, MA 02139, USA. */
"subl $32,%2\n" \
"jns 1b\n" \
"2: addl $32,%2" : \
- "=r" (dst_bp), "=r" (src_bp), "=r" (nbytes_left) : \
- "0" (dst_bp), "1" (src_bp), "2" (nbytes) : \
+ "=r" (dst_ep), "=r" (src_ep), "=r" (nbytes_left) : \
+ "0" (dst_ep), "1" (src_ep), "2" (nbytes) : \
"ax", "dx"); \
} while (0)
diff --git a/sysdeps/i386/i586/mul_1.S b/sysdeps/i386/i586/mul_1.S
new file mode 100644
index 0000000000..2b7258e130
--- /dev/null
+++ b/sysdeps/i386/i586/mul_1.S
@@ -0,0 +1,78 @@
+/* Pentium __mpn_mul_1 -- Multiply a limb vector with a limb and store
+ the result in a second limb vector.
+
+Copyright (C) 1992, 1994 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Library General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+The GNU MP 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 Library General Public
+License for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ INPUT PARAMETERS
+ res_ptr (sp + 4)
+ s1_ptr (sp + 8)
+ size (sp + 12)
+ s2_limb (sp + 16)
+*/
+
+#include "sysdep.h"
+#include "asm-syntax.h"
+
+#define res_ptr edi
+#define s1_ptr esi
+#define size ecx
+#define s2_limb ebp
+
+ TEXT
+ ALIGN (3)
+ GLOBL C_SYMBOL_NAME(__mpn_mul_1)
+C_SYMBOL_NAME(__mpn_mul_1:)
+
+ INSN1(push,l ,R(edi))
+ INSN1(push,l ,R(esi))
+ INSN1(push,l ,R(ebx))
+ INSN1(push,l ,R(ebp))
+
+ INSN2(mov,l ,R(res_ptr),MEM_DISP(esp,20))
+ INSN2(mov,l ,R(s1_ptr),MEM_DISP(esp,24))
+ INSN2(mov,l ,R(size),MEM_DISP(esp,28))
+ INSN2(mov,l ,R(s2_limb),MEM_DISP(esp,32))
+
+ INSN2(lea,l ,R(res_ptr),MEM_INDEX(res_ptr,size,4))
+ INSN2(lea,l ,R(s1_ptr),MEM_INDEX(s1_ptr,size,4))
+ INSN1(neg,l ,R(size))
+ INSN2(xor,l ,R(edx),R(edx))
+ ALIGN (3)
+Loop:
+ INSN2(mov,l ,R(ebx),R(edx))
+ INSN2(mov,l ,R(eax),MEM_INDEX(s1_ptr,size,4))
+
+ INSN1(mul,l ,R(s2_limb))
+
+ INSN2(add,l ,R(eax),R(ebx))
+
+ INSN2(adc,l ,R(edx),$0)
+ INSN2(mov,l ,MEM_INDEX(res_ptr,size,4),R(eax))
+
+ INSN1(inc,l ,R(size))
+ INSN1(jnz, ,Loop)
+
+
+ INSN2(mov,l ,R(eax),R(edx))
+ INSN1(pop,l ,R(ebp))
+ INSN1(pop,l ,R(ebx))
+ INSN1(pop,l ,R(esi))
+ INSN1(pop,l ,R(edi))
+ ret
diff --git a/sysdeps/i386/i586/rshift.S b/sysdeps/i386/i586/rshift.S
new file mode 100644
index 0000000000..51cde8f07f
--- /dev/null
+++ b/sysdeps/i386/i586/rshift.S
@@ -0,0 +1,213 @@
+/* Pentium optimized __mpn_rshift --
+
+Copyright (C) 1992, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Library General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+The GNU MP 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 Library General Public
+License for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ INPUT PARAMETERS
+ res_ptr (sp + 4)
+ s_ptr (sp + 8)
+ size (sp + 12)
+ cnt (sp + 16)
+*/
+
+#include "sysdep.h"
+#include "asm-syntax.h"
+
+.text
+ ALIGN (3)
+ .globl C_SYMBOL_NAME(__mpn_rshift)
+C_SYMBOL_NAME(__mpn_rshift:)
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+ pushl %ebp
+
+ movl 20(%esp),%edi /* res_ptr */
+ movl 24(%esp),%esi /* s_ptr */
+ movl 28(%esp),%ebp /* size */
+ movl 32(%esp),%ecx /* cnt */
+
+ cmp $1,%ecx
+ jne Lnormal
+ movl %edi,%eax
+ subl %esi,%eax
+ cmpl %ebp,%eax
+ jnc Lspecial
+
+Lnormal:
+ movl (%esi),%edx
+ addl $4,%esi
+ xorl %eax,%eax
+ shrdl %cl,%edx,%eax /* compute carry limb */
+ pushl %eax /* push carry limb onto stack */
+
+ decl %ebp
+ pushl %ebp
+ shrl $3,%ebp
+ jz Lend
+
+ movl (%edi),%eax /* fetch destination cache line */
+
+ ALIGN (2)
+Loop: movl 28(%edi),%eax /* fetch destination cache line */
+ movl %edx,%ebx
+
+ movl (%esi),%eax
+ movl 4(%esi),%edx
+ shrdl %cl,%eax,%ebx
+ shrdl %cl,%edx,%eax
+ movl %ebx,(%edi)
+ movl %eax,4(%edi)
+
+ movl 8(%esi),%ebx
+ movl 12(%esi),%eax
+ shrdl %cl,%ebx,%edx
+ shrdl %cl,%eax,%ebx
+ movl %edx,8(%edi)
+ movl %ebx,12(%edi)
+
+ movl 16(%esi),%edx
+ movl 20(%esi),%ebx
+ shrdl %cl,%edx,%eax
+ shrdl %cl,%ebx,%edx
+ movl %eax,16(%edi)
+ movl %edx,20(%edi)
+
+ movl 24(%esi),%eax
+ movl 28(%esi),%edx
+ shrdl %cl,%eax,%ebx
+ shrdl %cl,%edx,%eax
+ movl %ebx,24(%edi)
+ movl %eax,28(%edi)
+
+ addl $32,%esi
+ addl $32,%edi
+ decl %ebp
+ jnz Loop
+
+Lend: popl %ebp
+ andl $7,%ebp
+ jz Lend2
+Loop2: movl (%esi),%eax
+ shrdl %cl,%eax,%edx /* compute result limb */
+ movl %edx,(%edi)
+ movl %eax,%edx
+ addl $4,%esi
+ addl $4,%edi
+ decl %ebp
+ jnz Loop2
+
+Lend2: shrl %cl,%edx /* compute most significant limb */
+ movl %edx,(%edi) /* store it */
+
+ popl %eax /* pop carry limb */
+
+ popl %ebp
+ popl %ebx
+ popl %esi
+ popl %edi
+ ret
+
+/* We loop from least significant end of the arrays, which is only
+ permissable if the source and destination don't overlap, since the
+ function is documented to work for overlapping source and destination.
+*/
+
+Lspecial:
+ leal -4(%edi,%ebp,4),%edi
+ leal -4(%esi,%ebp,4),%esi
+
+ movl (%esi),%edx
+ subl $4,%esi
+
+ decl %ebp
+ pushl %ebp
+ shrl $3,%ebp
+
+ shrl $1,%edx
+ incl %ebp
+ decl %ebp
+ jz LLend
+
+ movl (%edi),%eax /* fetch destination cache line */
+
+ ALIGN (2)
+LLoop: movl -28(%edi),%eax /* fetch destination cache line */
+ movl %edx,%ebx
+
+ movl (%esi),%eax
+ movl -4(%esi),%edx
+ rcrl $1,%eax
+ movl %ebx,(%edi)
+ rcrl $1,%edx
+ movl %eax,-4(%edi)
+
+ movl -8(%esi),%ebx
+ movl -12(%esi),%eax
+ rcrl $1,%ebx
+ movl %edx,-8(%edi)
+ rcrl $1,%eax
+ movl %ebx,-12(%edi)
+
+ movl -16(%esi),%edx
+ movl -20(%esi),%ebx
+ rcrl $1,%edx
+ movl %eax,-16(%edi)
+ rcrl $1,%ebx
+ movl %edx,-20(%edi)
+
+ movl -24(%esi),%eax
+ movl -28(%esi),%edx
+ rcrl $1,%eax
+ movl %ebx,-24(%edi)
+ rcrl $1,%edx
+ movl %eax,-28(%edi)
+
+ leal -32(%esi),%esi /* use leal not to clobber carry */
+ leal -32(%edi),%edi
+ decl %ebp
+ jnz LLoop
+
+LLend: popl %ebp
+ sbbl %eax,%eax /* save carry in %eax */
+ andl $7,%ebp
+ jz LLend2
+ addl %eax,%eax /* restore carry from eax */
+LLoop2: movl %edx,%ebx
+ movl (%esi),%edx
+ rcrl $1,%edx
+ movl %ebx,(%edi)
+
+ leal -4(%esi),%esi /* use leal not to clobber carry */
+ leal -4(%edi),%edi
+ decl %ebp
+ jnz LLoop2
+
+ jmp LL1
+LLend2: addl %eax,%eax /* restore carry from eax */
+LL1: movl %edx,(%edi) /* store last limb */
+
+ movl $0,%eax
+ rcrl $1,%eax
+
+ popl %ebp
+ popl %ebx
+ popl %esi
+ popl %edi
+ ret
diff --git a/sysdeps/i386/i586/strchr.S b/sysdeps/i386/i586/strchr.S
new file mode 100644
index 0000000000..982c80ec9a
--- /dev/null
+++ b/sysdeps/i386/i586/strchr.S
@@ -0,0 +1,334 @@
+/* strchr -- find character CH in a NUL terminated string.
+Highly optimized version for ix85, x>=5.
+Copyright (C) 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <sysdep.h>
+
+/* This version is especially optimized for the i586 (and following?)
+ processors. This is mainly done by using the two pipelines. The
+ version optimized for i486 is weak in this aspect because to get
+ as much parallelism we have to executs some *more* instructions.
+
+ The code below is structured to reflect the pairing of the instructions
+ as *I think* it is. I have no processor data book to verify this.
+ If you find something you think is incorrect let me know. */
+
+
+/* The magic value which is used throughout in the whole code. */
+#define magic 0xfefefeff
+
+/*
+ INPUT PARAMETERS:
+ str (sp + 4)
+ ch (sp + 8)
+*/
+
+ .text
+ENTRY (strchr)
+ pushl %edi /* Save callee-safe registers. */
+ pushl %esi
+
+ pushl %ebx
+ pushl %ebp
+
+ movl 20(%esp), %eax /* get string pointer */
+ movl 24(%esp), %edx /* get character we are looking for */
+
+ movl %eax, %edi /* duplicate string pointer for later */
+ xorl %ecx, %ecx /* clear %ecx */
+
+ /* At the moment %edx contains C. What we need for the
+ algorithm is C in all bytes of the dword. Avoid
+ operations on 16 bit words because these require an
+ prefix byte (and one more cycle). */
+ movb %dl, %dh /* now it is 0|0|c|c */
+ movb %dl, %cl /* we construct the lower half in %ecx */
+
+ shll $16, %edx /* now %edx is c|c|0|0 */
+ movb %cl, %ch /* now %ecx is 0|0|c|c */
+
+ orl %ecx, %edx /* and finally c|c|c|c */
+ andl $3, %edi /* mask alignment bits */
+
+ jz L11 /* alignment is 0 => start loop */
+
+ movb (%eax), %cl /* load single byte */
+ cmpb %cl, %dl /* is byte == C? */
+
+ je L2 /* aligned => return pointer */
+
+ cmp $0, %cl /* is byte NUL? */
+ je L3 /* yes => return NULL */
+
+ incl %eax /* increment pointer */
+ cmp $3, %edi /* was alignment == 3? */
+
+ je L11 /* yes => start loop */
+
+ movb (%eax), %cl /* load single byte */
+ cmpb %cl, %dl /* is byte == C? */
+
+ je L2 /* aligned => return pointer */
+
+ cmp $0, %cl /* is byte NUL? */
+ je L3 /* yes => return NULL */
+
+ incl %eax /* increment pointer */
+ cmp $2, %edi /* was alignment == 2? */
+
+ je L11 /* yes => start loop */
+
+ movb (%eax), %cl /* load single byte */
+ cmpb %cl, %dl /* is byte == C? */
+
+ je L2 /* aligned => return pointer */
+
+ cmp $0, %cl /* is byte NUL? */
+ je L3 /* yes => return NULL */
+
+ incl %eax /* increment pointer */
+
+ /* The following code is the preparation for the loop. The
+ four instruction up to `L1' will not be executed in the loop
+ because the same code is found at the end of the loop, but
+ there it is executed in parallel with other instructions. */
+L11: movl (%eax), %ecx
+ movl $magic, %ebp
+
+ movl $magic, %edi
+ addl %ecx, %ebp
+
+ /* The main loop: it looks complex and indeed it is. I would
+ love to say `it was hard to write, so it should he hard to
+ read' but I will give some more hints. To fully understand
+ this code you should first take a look at the i486 version.
+ The basic algorithm is the same, but here the code organized
+ in a way which permits to use both pipelines all the time.
+
+ I tried to make it a bit more understandable by indenting
+ the code according to stage in the algorithm. It goes as
+ follows:
+ check for 0 in 1st word
+ check for C in 1st word
+ check for 0 in 2nd word
+ check for C in 2nd word
+ check for 0 in 3rd word
+ check for C in 3rd word
+ check for 0 in 4th word
+ check for C in 4th word
+
+ Please note that doing the test for NUL before the test for
+ C allows us to overlap the test for 0 in the next word with
+ the test for C. */
+
+L1: xorl %ecx, %ebp /* (word^magic) */
+ addl %ecx, %edi /* add magic word */
+
+ leal 4(%eax), %eax /* increment pointer */
+ jnc L4 /* previous addl caused overflow? */
+
+ movl %ecx, %ebx /* duplicate original word */
+ orl $magic, %ebp /* (word^magic)|magic */
+
+ addl $1, %ebp /* (word^magic)|magic == 0xffffffff? */
+ jne L4 /* yes => we found word with NUL */
+
+ movl $magic, %esi /* load magic value */
+ xorl %edx, %ebx /* clear words which are C */
+
+ movl (%eax), %ecx
+ addl %ebx, %esi /* (word+magic) */
+
+ movl $magic, %edi
+ jnc L5 /* previous addl caused overflow? */
+
+ movl %edi, %ebp
+ xorl %ebx, %esi /* (word+magic)^word */
+
+ addl %ecx, %ebp
+ orl $magic, %esi /* ((word+magic)^word)|magic */
+
+ addl $1, %esi /* ((word+magic)^word)|magic==0xf..f?*/
+ jne L5 /* yes => we found word with C */
+
+ xorl %ecx, %ebp
+ addl %ecx, %edi
+
+ leal 4(%eax), %eax
+ jnc L4
+
+ movl %ecx, %ebx
+ orl $magic, %ebp
+
+ addl $1, %ebp
+ jne L4
+
+ movl $magic, %esi
+ xorl %edx, %ebx
+
+ movl (%eax), %ecx
+ addl %ebx, %esi
+
+ movl $magic, %edi
+ jnc L5
+
+ movl %edi, %ebp
+ xorl %ebx, %esi
+
+ addl %ecx, %ebp
+ orl $magic, %esi
+
+ addl $1, %esi
+ jne L5
+
+ xorl %ecx, %ebp
+ addl %ecx, %edi
+
+ leal 4(%eax), %eax
+ jnc L4
+
+ movl %ecx, %ebx
+ orl $magic, %ebp
+
+ addl $1, %ebp
+ jne L4
+
+ movl $magic, %esi
+ xorl %edx, %ebx
+
+ movl (%eax), %ecx
+ addl %ebx, %esi
+
+ movl $magic, %edi
+ jnc L5
+
+ movl %edi, %ebp
+ xorl %ebx, %esi
+
+ addl %ecx, %ebp
+ orl $magic, %esi
+
+ addl $1, %esi
+ jne L5
+
+ xorl %ecx, %ebp
+ addl %ecx, %edi
+
+ leal 4(%eax), %eax
+ jnc L4
+
+ movl %ecx, %ebx
+ orl $magic, %ebp
+
+ addl $1, %ebp
+ jne L4
+
+ movl $magic, %esi
+ xorl %edx, %ebx
+
+ movl (%eax), %ecx
+ addl %ebx, %esi
+
+ movl $magic, %edi
+ jnc L5
+
+ movl %edi, %ebp
+ xorl %ebx, %esi
+
+ addl %ecx, %ebp
+ orl $magic, %esi
+
+ addl $1, %esi
+
+ je L1
+
+ /* We know there is no NUL byte but a C byte in the word.
+ %ebx contains NUL in this particular byte. */
+L5: subl $4, %eax /* adjust pointer */
+ testb %bl, %bl /* first byte == C? */
+
+ jz L2 /* yes => return pointer */
+
+ incl %eax /* increment pointer */
+ testb %bh, %bh /* second byte == C? */
+
+ jz L2 /* yes => return pointer */
+
+ shrl $16, %ebx /* make upper bytes accessible */
+ incl %eax /* increment pointer */
+
+ cmp $0, %bl /* third byte == C */
+ je L2 /* yes => return pointer */
+
+ incl %eax /* increment pointer */
+
+L2: popl %ebp /* restore saved registers */
+ popl %ebx
+
+ popl %esi
+ popl %edi
+
+ ret
+
+ /* We know there is a NUL byte in the word. But we have to test
+ whether there is an C byte before it in the word. */
+L4: subl $4, %eax /* adjust pointer */
+ cmpb %dl, %cl /* first byte == C? */
+
+ je L2 /* yes => return pointer */
+
+ cmpb $0, %cl /* first byte == NUL? */
+ je L3 /* yes => return NULL */
+
+ incl %eax /* increment pointer */
+
+ cmpb %dl, %ch /* second byte == C? */
+ je L2 /* yes => return pointer */
+
+ cmpb $0, %ch /* second byte == NUL? */
+ je L3 /* yes => return NULL */
+
+ shrl $16, %ecx /* make upper bytes accessible */
+ incl %eax /* increment pointer */
+
+ cmpb %dl, %cl /* third byte == C? */
+ je L2 /* yes => return pointer */
+
+ cmpb $0, %cl /* third byte == NUL? */
+ je L3 /* yes => return NULL */
+
+ incl %eax /* increment pointer */
+
+ /* The test four the fourth byte is necessary! */
+ cmpb %dl, %ch /* fourth byte == C? */
+ je L2 /* yes => return pointer */
+
+L3: xorl %eax, %eax /* set return value = NULL */
+
+ popl %ebp /* restore saved registers */
+ popl %ebx
+
+ popl %esi
+ popl %edi
+
+ ret
+
+#undef index
+weak_alias (strchr, index)
diff --git a/sysdeps/i386/i586/strlen.S b/sysdeps/i386/i586/strlen.S
new file mode 100644
index 0000000000..b807ed4b4f
--- /dev/null
+++ b/sysdeps/i386/i586/strlen.S
@@ -0,0 +1,185 @@
+/* strlen -- Compute length og NUL terminated string.
+Highly optimized version for ix86, x>=5.
+Copyright (C) 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <sysdep.h>
+
+/* This version is especially optimized for the i586 (and following?)
+ processors. This is mainly done by using the two pipelines. The
+ version optimized for i486 is weak in this aspect because to get
+ as much parallelism we have to executs some *more* instructions.
+
+ The code below is structured to reflect the pairing of the instructions
+ as *I think* it is. I have no processor data book to verify this.
+ If you find something you think is incorrect let me know. */
+
+
+/* The magic value which is used throughout in the whole code. */
+#define magic 0xfefefeff
+
+/*
+ INPUT PARAMETERS:
+ str (sp + 4)
+*/
+
+ .text
+ENTRY(strlen)
+ movl 4(%esp), %eax /* get string pointer */
+
+ movl %eax, %ecx /* duplicate it */
+ andl $3, %ecx /* mask alignment bits */
+
+ jz L11 /* aligned => start loop */
+
+ cmpb %ch, (%eax) /* is byte NUL? */
+ je L2 /* yes => return */
+
+ incl %eax /* increment pointer */
+ cmpl $3, %ecx /* was alignment = 3? */
+
+ je L11 /* yes => now it is aligned and start loop */
+
+ cmpb %ch, (%eax) /* is byte NUL? */
+ je L2 /* yes => return */
+
+ incl %eax /* increment pointer */
+ cmpl $2, %ecx /* was alignment = 2? */
+
+ je L11 /* yes => now it is aligned and start loop */
+
+ cmpb %ch, (%eax) /* is byte NUL? */
+ je L2 /* yes => return */
+
+ incl %eax /* increment pointer */
+
+ /* 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 LONGWORD 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. If one of bits 24-31 is set, there will be a carry
+ into bit 32 (=carry flag), so all of the hole bits will
+ be changed. */
+L11: xorl %edx, %edx /* We need %edx == 0 for later */
+
+L1:
+ movl (%eax), %ecx /* get word (= 4 bytes) in question */
+ addl $4, %eax /* adjust pointer for *next* word */
+
+ subl %ecx, %edx /* first step to negate word */
+ addl $magic, %ecx /* add magic word */
+
+ decl %edx /* complete negation of word */
+ jnc L3 /* previous addl caused overflow? */
+
+ xorl %ecx, %edx /* (word+magic)^word */
+ subl $magic, %ecx /* undo previous addl to restore word */
+
+ andl $~magic, %edx /* any of the carry flags set? */
+
+ jne L3 /* yes => determine byte */
+
+
+ movl (%eax), %ecx /* get word (= 4 bytes) in question */
+ addl $4, %eax /* adjust pointer for *next* word */
+
+ subl %ecx, %edx /* first step to negate word */
+ addl $magic, %ecx /* add magic word */
+
+ decl %edx /* complete negation of word */
+ jnc L3 /* previous addl caused overflow? */
+
+ xorl %ecx, %edx /* (word+magic)^word */
+ subl $magic, %ecx /* undo previous addl to restore word */
+
+ andl $~magic, %edx /* any of the carry flags set? */
+
+ jne L3 /* yes => determine byte */
+
+
+ movl (%eax), %ecx /* get word (= 4 bytes) in question */
+ addl $4, %eax /* adjust pointer for *next* word */
+
+ subl %ecx, %edx /* first step to negate word */
+ addl $magic, %ecx /* add magic word */
+
+ decl %edx /* complete negation of word */
+ jnc L3 /* previous addl caused overflow? */
+
+ xorl %ecx, %edx /* (word+magic)^word */
+ subl $magic, %ecx /* undo previous addl to restore word */
+
+ andl $~magic, %edx /* any of the carry flags set? */
+
+ jne L3 /* yes => determine byte */
+
+
+ movl (%eax), %ecx /* get word (= 4 bytes) in question */
+ addl $4, %eax /* adjust pointer for *next* word */
+
+ subl %ecx, %edx /* first step to negate word */
+ addl $magic, %ecx /* add magic word */
+
+ decl %edx /* wcomplete negation of ord */
+ jnc L3 /* previous addl caused overflow? */
+
+ xorl %ecx, %edx /* (word+magic)^word */
+ subl $magic, %ecx /* undo previous addl to restore word */
+
+ andl $~magic, %edx /* any of the carry flags set? */
+
+ je L1 /* no => start loop again */
+
+
+L3: subl $4, %eax /* correct too early pointer increment */
+ testb %cl, %cl /* lowest byte NUL? */
+
+ jz L2 /* yes => return */
+
+ inc %eax /* increment pointer */
+ testb %ch, %ch /* second byte NUL? */
+
+ jz L2 /* yes => return */
+
+ shrl $16, %ecx /* make upper bytes accessible */
+ incl %eax /* increment pointer */
+
+ cmpb $0, %cl /* is third byte NUL? */
+ jz L2 /* yes => return */
+
+ incl %eax /* increment pointer */
+
+L2: subl 4(%esp), %eax /* now compute the length as difference
+ between start and terminating NUL
+ character */
+
+ ret
diff --git a/sysdeps/i386/i586/sub_n.S b/sysdeps/i386/i586/sub_n.S
new file mode 100644
index 0000000000..1382e665f6
--- /dev/null
+++ b/sysdeps/i386/i586/sub_n.S
@@ -0,0 +1,136 @@
+/* Pentium __mpn_sub_n -- Subtract two limb vectors of the same length > 0
+ and store difference in a third limb vector.
+
+Copyright (C) 1992, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Library General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+The GNU MP 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 Library General Public
+License for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ INPUT PARAMETERS
+ res_ptr (sp + 4)
+ s1_ptr (sp + 8)
+ s2_ptr (sp + 12)
+ size (sp + 16)
+*/
+
+#define r1 %eax
+#define r2 %edx
+#define src1 %esi
+#define src2 %ebp
+#define dst %edi
+#define x %ebx
+
+#include "sysdep.h"
+#include "asm-syntax.h"
+
+.text
+ ALIGN (3)
+ .globl C_SYMBOL_NAME(__mpn_sub_n)
+C_SYMBOL_NAME(__mpn_sub_n:)
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+ pushl %ebp
+
+ movl 20(%esp),dst /* res_ptr */
+ movl 24(%esp),src1 /* s1_ptr */
+ movl 28(%esp),src2 /* s2_ptr */
+ movl 32(%esp),%ecx /* size */
+
+ movl (src2),x
+
+ decl %ecx
+ movl %ecx,r2
+ shrl $3,%ecx
+ andl $7,r2
+ testl %ecx,%ecx /* zero carry flag */
+ jz Lend
+ pushl r2
+
+ ALIGN (3)
+Loop: movl 28(dst),%eax /* fetch destination cache line */
+ leal 32(dst),dst
+
+L1: movl (src1),r1
+ movl 4(src1),r2
+ sbbl x,r1
+ movl 4(src2),x
+ sbbl x,r2
+ movl 8(src2),x
+ movl r1,-32(dst)
+ movl r2,-28(dst)
+
+L2: movl 8(src1),r1
+ movl 12(src1),r2
+ sbbl x,r1
+ movl 12(src2),x
+ sbbl x,r2
+ movl 16(src2),x
+ movl r1,-24(dst)
+ movl r2,-20(dst)
+
+L3: movl 16(src1),r1
+ movl 20(src1),r2
+ sbbl x,r1
+ movl 20(src2),x
+ sbbl x,r2
+ movl 24(src2),x
+ movl r1,-16(dst)
+ movl r2,-12(dst)
+
+L4: movl 24(src1),r1
+ movl 28(src1),r2
+ sbbl x,r1
+ movl 28(src2),x
+ sbbl x,r2
+ movl 32(src2),x
+ movl r1,-8(dst)
+ movl r2,-4(dst)
+
+ leal 32(src1),src1
+ leal 32(src2),src2
+ decl %ecx
+ jnz Loop
+
+ popl r2
+Lend:
+ decl r2 /* test r2 w/o clobbering carry */
+ js Lend2
+ incl r2
+Loop2:
+ leal 4(dst),dst
+ movl (src1),r1
+ sbbl x,r1
+ movl 4(src2),x
+ movl r1,-4(dst)
+ leal 4(src1),src1
+ leal 4(src2),src2
+ decl r2
+ jnz Loop2
+Lend2:
+ movl (src1),r1
+ sbbl x,r1
+ movl r1,(dst)
+
+ sbbl %eax,%eax
+ negl %eax
+
+ popl %ebp
+ popl %ebx
+ popl %esi
+ popl %edi
+ ret
diff --git a/sysdeps/i386/i586/submul_1.S b/sysdeps/i386/i586/submul_1.S
new file mode 100644
index 0000000000..14bfe54e24
--- /dev/null
+++ b/sysdeps/i386/i586/submul_1.S
@@ -0,0 +1,82 @@
+/* Pentium __mpn_submul_1 -- Multiply a limb vector with a limb and subtract
+ the result from a second limb vector.
+
+Copyright (C) 1992, 1994 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Library General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+The GNU MP 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 Library General Public
+License for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with the GNU MP Library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ INPUT PARAMETERS
+ res_ptr (sp + 4)
+ s1_ptr (sp + 8)
+ size (sp + 12)
+ s2_limb (sp + 16)
+*/
+
+#include "sysdep.h"
+#include "asm-syntax.h"
+
+#define res_ptr edi
+#define s1_ptr esi
+#define size ecx
+#define s2_limb ebp
+
+ TEXT
+ ALIGN (3)
+ GLOBL C_SYMBOL_NAME(__mpn_submul_1)
+C_SYMBOL_NAME(__mpn_submul_1:)
+
+ INSN1(push,l ,R(edi))
+ INSN1(push,l ,R(esi))
+ INSN1(push,l ,R(ebx))
+ INSN1(push,l ,R(ebp))
+
+ INSN2(mov,l ,R(res_ptr),MEM_DISP(esp,20))
+ INSN2(mov,l ,R(s1_ptr),MEM_DISP(esp,24))
+ INSN2(mov,l ,R(size),MEM_DISP(esp,28))
+ INSN2(mov,l ,R(s2_limb),MEM_DISP(esp,32))
+
+ INSN2(lea,l ,R(res_ptr),MEM_INDEX(res_ptr,size,4))
+ INSN2(lea,l ,R(s1_ptr),MEM_INDEX(s1_ptr,size,4))
+ INSN1(neg,l ,R(size))
+ INSN2(xor,l ,R(edx),R(edx))
+ ALIGN (3)
+Loop:
+ INSN2(mov,l ,R(ebx),R(edx))
+ INSN2(mov,l ,R(eax),MEM_INDEX(s1_ptr,size,4))
+
+ INSN1(mul,l ,R(s2_limb))
+
+ INSN2(add,l ,R(eax),R(ebx))
+ INSN2(mov,l ,R(ebx),MEM_INDEX(res_ptr,size,4))
+
+ INSN2(adc,l ,R(edx),$0)
+ INSN2(sub,l ,R(ebx),R(eax))
+
+ INSN2(adc,l ,R(edx),$0)
+ INSN2(mov,l ,MEM_INDEX(res_ptr,size,4),R(ebx))
+
+ INSN1(inc,l ,R(size))
+ INSN1(jnz, ,Loop)
+
+
+ INSN2(mov,l ,R(eax),R(edx))
+ INSN1(pop,l ,R(ebp))
+ INSN1(pop,l ,R(ebx))
+ INSN1(pop,l ,R(esi))
+ INSN1(pop,l ,R(edi))
+ ret
diff --git a/sysdeps/i386/memchr.S b/sysdeps/i386/memchr.S
new file mode 100644
index 0000000000..9931f97241
--- /dev/null
+++ b/sysdeps/i386/memchr.S
@@ -0,0 +1,315 @@
+/* memchr (str, ch, n) -- Return pointer to first occurrence of CH in STR less
+ than N.
+For Intel 80x86, x>=3.
+Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>
+Optimised a little by Alan Modra <Alan@SPRI.Levels.UniSA.Edu.Au>
+This file is part of the GNU C Library.
+
+This version is developed using the same algorithm as the fast C
+version which carries the following introduction:
+
+Based on strlen implemention by Torbjorn Granlund (tege@sics.se),
+with help from Dan Sahlin (dan@sics.se) and
+commentary by Jim Blandy (jimb@ai.mit.edu);
+adaptation to memchr suggested by Dick Karpinski (dick@cca.ucsf.edu),
+and implemented by Roland McGrath (roland@ai.mit.edu).
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. 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"
+
+/*
+ INPUT PARAMETERS:
+ str (sp + 4)
+ c (sp + 8)
+ len (sp + 12)
+*/
+
+ .text
+ENTRY (memchr)
+ /* Save callee-safe registers used in this function. */
+ pushl %esi
+ pushl %edi
+
+ /* Load parameters into registers. */
+ movl 12(%esp), %eax /* str: pointer to memory block. */
+ movl 16(%esp), %edx /* c: byte we are looking for. */
+ movl 20(%esp), %esi /* len: length of memory block. */
+
+ /* If my must not test more than three characters test
+ them one by one. This is especially true for 0. */
+ cmpl $4, %esi
+ jb L3
+
+ /* At the moment %edx contains C. What we need for the
+ algorithm is C in all bytes of the dword. Avoid
+ operations on 16 bit words because these require an
+ prefix byte (and one more cycle). */
+ movb %dl, %dh /* Now it is 0|0|c|c */
+ movl %edx, %ecx
+ shll $16, %edx /* Now c|c|0|0 */
+ movw %cx, %dx /* And finally c|c|c|c */
+
+ /* Better performance can be achieved if the word (32
+ bit) memory access is aligned on a four-byte-boundary.
+ So process first bytes one by one until boundary is
+ reached. Don't use a loop for better performance. */
+
+ testb $3, %eax /* correctly aligned ? */
+ je L2 /* yes => begin loop */
+ cmpb %dl, (%eax) /* compare byte */
+ je L9 /* target found => return */
+ incl %eax /* increment source pointer */
+ decl %esi /* decrement length counter */
+ je L4 /* len==0 => return NULL */
+
+ testb $3, %eax /* correctly aligned ? */
+ je L2 /* yes => begin loop */
+ cmpb %dl, (%eax) /* compare byte */
+ je L9 /* target found => return */
+ incl %eax /* increment source pointer */
+ decl %esi /* decrement length counter */
+ je L4 /* len==0 => return NULL */
+
+ testb $3, %eax /* correctly aligned ? */
+ je L2 /* yes => begin loop */
+ cmpb %dl, (%eax) /* compare byte */
+ je L9 /* target found => return */
+ incl %eax /* increment source pointer */
+ decl %esi /* decrement length counter */
+ /* no test for len==0 here, because this is done in the
+ loop head */
+ jmp L2
+
+ /* 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 LONGWORD 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. If one of bits 24-31 is set, there will be a carry
+ into bit 32 (=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. */
+
+
+ /* Each round the main loop processes 16 bytes. */
+
+ ALIGN (4)
+
+L1: movl (%eax), %ecx /* get word (= 4 bytes) in question */
+ movl $0xfefefeff, %edi /* magic value */
+ xorl %edx, %ecx /* XOR with word c|c|c|c => bytes of str == c
+ are now 0 */
+ addl %ecx, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+
+ /* According to the algorithm we had to reverse the effect of the
+ XOR first and then test the overflow bits. But because the
+ following XOR would destroy the carry flag and it would (in a
+ representation with more than 32 bits) not alter then last
+ overflow, we can now test this condition. If no carry is signaled
+ no overflow must have occured in the last byte => it was 0. */
+ jnc L8
+
+ /* We are only interested in carry bits that change due to the
+ previous add, so remove original bits */
+ xorl %ecx, %edi /* ((word^charmask)+magic)^(word^charmask) */
+
+ /* Now test for the other three overflow bits. */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+
+ /* If at least one byte of the word is C we don't get 0 in %edi. */
+ jnz L8 /* found it => return pointer */
+
+ /* This process is unfolded four times for better performance.
+ we don't increment the source pointer each time. Instead we
+ use offsets and increment by 16 in each run of the loop. But
+ before probing for the matching byte we need some extra code
+ (following LL(13) below). Even the len can be compared with
+ constants instead of decrementing each time. */
+
+ movl 4(%eax), %ecx /* get word (= 4 bytes) in question */
+ movl $0xfefefeff, %edi /* magic value */
+ xorl %edx, %ecx /* XOR with word c|c|c|c => bytes of str == c
+ are now 0 */
+ addl %ecx, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L7 /* highest byte is C => return pointer */
+ xorl %ecx, %edi /* ((word^charmask)+magic)^(word^charmask) */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jnz L7 /* found it => return pointer */
+
+ movl 8(%eax), %ecx /* get word (= 4 bytes) in question */
+ movl $0xfefefeff, %edi /* magic value */
+ xorl %edx, %ecx /* XOR with word c|c|c|c => bytes of str == c
+ are now 0 */
+ addl %ecx, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L6 /* highest byte is C => return pointer */
+ xorl %ecx, %edi /* ((word^charmask)+magic)^(word^charmask) */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jnz L6 /* found it => return pointer */
+
+ movl 12(%eax), %ecx /* get word (= 4 bytes) in question */
+ movl $0xfefefeff, %edi /* magic value */
+ xorl %edx, %ecx /* XOR with word c|c|c|c => bytes of str == c
+ are now 0 */
+ addl %ecx, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L5 /* highest byte is C => return pointer */
+ xorl %ecx, %edi /* ((word^charmask)+magic)^(word^charmask) */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jnz L5 /* found it => return pointer */
+
+ /* Adjust both counters for a full round, i.e. 16 bytes. */
+ addl $16, %eax
+L2: subl $16, %esi
+ jae L1 /* Still more than 16 bytes remaining */
+
+ /* Process remaining bytes separately. */
+ cmpl $4-16, %esi /* rest < 4 bytes? */
+ jb L3 /* yes, than test byte by byte */
+
+ movl (%eax), %ecx /* get word (= 4 bytes) in question */
+ movl $0xfefefeff, %edi /* magic value */
+ xorl %edx, %ecx /* XOR with word c|c|c|c => bytes of str == c
+ are now 0 */
+ addl %ecx, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L8 /* highest byte is C => return pointer */
+ xorl %ecx, %edi /* ((word^charmask)+magic)^(word^charmask) */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jne L8 /* found it => return pointer */
+ addl $4, %eax /* adjust source pointer */
+
+ cmpl $8-16, %esi /* rest < 8 bytes? */
+ jb L3 /* yes, than test byte by byte */
+
+ movl (%eax), %ecx /* get word (= 4 bytes) in question */
+ movl $0xfefefeff, %edi /* magic value */
+ xorl %edx, %ecx /* XOR with word c|c|c|c => bytes of str == c
+ are now 0 */
+ addl %ecx, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L8 /* highest byte is C => return pointer */
+ xorl %ecx, %edi /* ((word^charmask)+magic)^(word^charmask) */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jne L8 /* found it => return pointer */
+ addl $4, %eax /* adjust source pointer */
+
+ cmpl $12-16, %esi /* rest < 12 bytes? */
+ jb L3 /* yes, than test byte by byte */
+
+ movl (%eax), %ecx /* get word (= 4 bytes) in question */
+ movl $0xfefefeff, %edi /* magic value */
+ xorl %edx, %ecx /* XOR with word c|c|c|c => bytes of str == c
+ are now 0 */
+ addl %ecx, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L8 /* highest byte is C => return pointer */
+ xorl %ecx, %edi /* ((word^charmask)+magic)^(word^charmask) */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jne L8 /* found it => return pointer */
+ addl $4, %eax /* adjust source pointer */
+
+ /* Check the remaining bytes one by one. */
+L3: andl $3, %esi /* mask out uninteresting bytes */
+ jz L4 /* no remaining bytes => return NULL */
+
+ cmpb %dl, (%eax) /* compare byte with C */
+ je L9 /* equal, than return pointer */
+ incl %eax /* increment source pointer */
+ decl %esi /* decrement length */
+ jz L4 /* no remaining bytes => return NULL */
+
+ cmpb %dl, (%eax) /* compare byte with C */
+ je L9 /* equal, than return pointer */
+ incl %eax /* increment source pointer */
+ decl %esi /* decrement length */
+ jz L4 /* no remaining bytes => return NULL */
+
+ cmpb %dl, (%eax) /* compare byte with C */
+ je L9 /* equal, than return pointer */
+
+L4: /* no byte found => return NULL */
+ xorl %eax, %eax
+ jmp L9
+
+ /* add missing source pointer increments */
+L5: addl $4, %eax
+L6: addl $4, %eax
+L7: addl $4, %eax
+
+ /* Test for the matching byte in the word. %ecx contains a NUL
+ char in the byte which originally was the byte we are looking
+ at. */
+L8: testb %cl, %cl /* test first byte in dword */
+ jz L9 /* if zero => return pointer */
+ incl %eax /* increment source pointer */
+
+ testb %ch, %ch /* test second byte in dword */
+ jz L9 /* if zero => return pointer */
+ incl %eax /* increment source pointer */
+
+ testl $0xff0000, %ecx /* test third byte in dword */
+ jz L9 /* if zero => return pointer */
+ incl %eax /* increment source pointer */
+
+ /* No further test needed we we known it is one of the four byytes. */
+
+L9: popl %edi /* pop saved registers */
+ popl %esi
+
+ ret
diff --git a/sysdeps/i386/memchr.c b/sysdeps/i386/memchr.c
deleted file mode 100644
index ff0f8d9044..0000000000
--- a/sysdeps/i386/memchr.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/* memchr (str, ch, n) -- Return pointer to first occurrence of CH in STR less
- than N.
- For Intel 80x86, x>=3.
- Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
- Contributed by Torbjorn Granlund (tege@sics.se).
-
-The GNU C Library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Library General Public License as
-published by the Free Software Foundation; either version 2 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
-Library General Public License for more details.
-
-You should have received a copy of the GNU Library General Public
-License along with the GNU C Library; see the file COPYING.LIB. If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA. */
-
-#include <ansidecl.h>
-#include <string.h>
-
-#ifdef __GNUC__
-
-PTR
-DEFUN(memchr, (str, c, len),
- CONST PTR str AND int c AND size_t len)
-{
- PTR retval;
- asm("cld\n" /* Search forward. */
- "testl %1,%1\n" /* Clear Z flag, to handle LEN == 0. */
- /* Some old versions of gas need `repne' instead of `repnz'. */
- "repnz\n" /* Search for C in al. */
- "scasb\n"
- "movl %2,%0\n" /* Set %0 to 0 (without affecting Z flag). */
- "jnz done\n" /* Jump if we found nothing equal to C. */
- "leal -1(%1),%0\n" /* edi has been incremented. Return edi-1. */
- "done:" :
- "=a" (retval), "=D" (str), "=c" (len) :
- "0" (c), "1" (str), "2" (len));
- return retval;
-}
-
-#else
-#include <sysdeps/generic/memchr.c>
-#endif
diff --git a/sysdeps/i386/memcmp.S b/sysdeps/i386/memcmp.S
new file mode 100644
index 0000000000..f16b44a1b4
--- /dev/null
+++ b/sysdeps/i386/memcmp.S
@@ -0,0 +1,68 @@
+/* memcmp -- compare two memory blocks for differences in the first COUNT
+ bytes.
+Copyright (C) 1995 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. 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"
+
+/*
+ INPUT PARAMETERS:
+ block1 (sp + 4)
+ block2 (sp + 8)
+ len (sp + 12)
+*/
+
+ .text
+ENTRY (memcmp)
+ pushl %esi /* Save callee-safe registers. */
+ movl %edi, %edx /* Note that %edx is not used and can
+ so be used to save %edi. It's faster. */
+
+ movl 12(%esp), %esi /* Load address of block #1. */
+ movl 16(%esp), %edi /* Load address of block #2. */
+ movl 20(%esp), %ecx /* Load maximal length of compare area. */
+
+ cld /* Set direction of comparison. */
+
+ xorl %eax, %eax /* Default result. */
+
+ repe /* Compare at most %ecx bytes. */
+ cmpsb
+ jz L1 /* If even last byte was equal we return 0. */
+
+ /* The memory blocks are not equal. So result of the last
+ subtraction is present in the carry flag. It is set when
+ the byte in block #2 is bigger. In this case we have to
+ return -1 (=0xffffffff), else 1. */
+ sbbl %eax, %eax /* This is tricky. %eax == 0 and carry is set
+ or not depending on last subtraction. */
+
+ /* At this point %eax == 0, if the byte of block #1 was bigger, and
+ 0xffffffff if the last byte of block #2 was bigger. The later
+ case is already correct but the former needs a little adjustment.
+ Note that the following operation does not change 0xffffffff. */
+ orb $1, %al /* Change 0 to 1. */
+
+L1: popl %esi /* Restore registers. */
+ movl %edx, %edi
+
+ ret
+
+#undef bcmp
+weak_alias (memcmp, bcmp)
diff --git a/sysdeps/i386/stpcpy.S b/sysdeps/i386/stpcpy.S
new file mode 100644
index 0000000000..f38a9089bc
--- /dev/null
+++ b/sysdeps/i386/stpcpy.S
@@ -0,0 +1,87 @@
+/* stpcpy -- copy SRC to DEST returning the address of the terminating '\0'
+ in DEST.
+For Intel 80x86, x>=3.
+Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+Contributed by Ulrich Drepper (drepper@gnu.ai.mit.edu).
+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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* This function is defined neither in ANSI nor POSIX standards but is
+ also not invented here. */
+
+#include <sysdep.h>
+#include "asm-syntax.h"
+
+/*
+ INPUT PARAMETERS:
+ dest (sp + 4)
+ src (sp + 8)
+*/
+
+ .text
+ENTRY (__stpcpy)
+ movl 4(%esp), %eax /* load destination pointer */
+ movl 8(%esp), %ecx /* load source pointer */
+
+ subl %eax, %ecx /* magic: reduce number of loop variants
+ to one using addressing mode */
+
+ /* Here we would like to write
+
+ subl $4, %eax
+ ALIGN (4)
+
+ but the assembler is too smart and optimizes for the shortest
+ form where the number only needs one byte. But if we could
+ have the long form we would not need the alignment. */
+
+ .byte 0x81, 0xe8 /* This is `subl $0x00000004, %eax' */
+ .long 0x00000004
+
+ /* Four times unfolded loop with only one loop counter. This
+ is achieved by the use of index+base adressing mode. As the
+ loop counter we use the destination address because this is
+ also the result. */
+L1: addl $4, %eax /* increment loop counter */
+
+ movb (%eax,%ecx), %dl /* load current char */
+ movb %dl, (%eax) /* and store it */
+ testb %dl, %dl /* was it NUL? */
+ jz L2 /* yes, then exit */
+
+ movb 1(%eax,%ecx), %dl /* load current char */
+ movb %dl, 1(%eax) /* and store it */
+ testb %dl, %dl /* was it NUL? */
+ jz L3 /* yes, then exit */
+
+ movb 2(%eax,%ecx), %dl /* load current char */
+ movb %dl, 2(%eax) /* and store it */
+ testb %dl, %dl /* was it NUL? */
+ jz L4 /* yes, then exit */
+
+ movb 3(%eax,%ecx), %dl /* load current char */
+ movb %dl, 3(%eax) /* and store it */
+ testb %dl, %dl /* was it NUL? */
+ jnz L1 /* no, then continue loop */
+
+ incl %eax /* correct loop counter */
+L4: incl %eax
+L3: incl %eax
+L2:
+ ret
+
+weak_alias (__stpcpy, stpcpy)
diff --git a/sysdeps/i386/stpncpy.S b/sysdeps/i386/stpncpy.S
new file mode 100644
index 0000000000..59192e66c9
--- /dev/null
+++ b/sysdeps/i386/stpncpy.S
@@ -0,0 +1,143 @@
+/* stpncpy -- copy no more then N bytes from SRC to DEST, returning the
+ address of the terminating '\0' in DEST.
+For Intel 80x86, x>=3.
+Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>
+Some bug fixes by Alan Modra <Alan@SPRI.Levels.UniSA.Edu.Au>
+ - original wrote n+1 chars in some cases.
+ - stpncpy() ought to behave like strncpy() ie. not null-terminate
+ if limited by n. glibc-1.09 stpncpy() does this.
+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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. 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"
+
+/*
+ INPUT PARAMETERS:
+ dest (sp + 4)
+ src (sp + 8)
+ maxlen (sp + 12)
+*/
+
+ .text
+ENTRY (__stpncpy)
+
+ pushl %esi
+
+ movl 8(%esp), %eax /* load destination pointer */
+ movl 12(%esp), %esi /* load source pointer */
+ movl 16(%esp), %ecx /* load maximal length */
+
+ subl %eax, %esi /* magic: reduce number of loop variants
+ to one using addressing mode */
+ jmp L1 /* jump to loop "head" */
+
+ ALIGN(4)
+
+ /* Four times unfolded loop with two loop counters. We get the
+ the third value (the source address) by using the index+base
+ adressing mode. */
+L2: movb (%eax,%esi), %dl /* load current char */
+ movb %dl, (%eax) /* and store it */
+ testb %dl, %dl /* was it NUL? */
+ jz L7 /* yes, then exit */
+
+ movb 1(%eax,%esi), %dl /* load current char */
+ movb %dl, 1(%eax) /* and store it */
+ testb %dl, %dl /* was it NUL? */
+ jz L6 /* yes, then exit */
+
+ movb 2(%eax,%esi), %dl /* load current char */
+ movb %dl, 2(%eax) /* and store it */
+ testb %dl, %dl /* was it NUL? */
+ jz L5 /* yes, then exit */
+
+ movb 3(%eax,%esi), %dl /* load current char */
+ movb %dl, 3(%eax) /* and store it */
+ testb %dl, %dl /* was it NUL? */
+ jz L4 /* yes, then exit */
+
+ addl $4, %eax /* increment loop counter for full round */
+
+L1: subl $4, %ecx /* still more than 4 bytes allowed? */
+ jae L2 /* yes, then go to start of loop */
+
+ /* The maximal remaining 15 bytes are not processed in a loop. */
+
+ addl $4, %ecx /* correct above subtraction */
+ jz L9 /* maximal allowed char reached => go to end */
+
+ movb (%eax,%esi), %dl /* load current char */
+ movb %dl, (%eax) /* and store it */
+ testb %dl, %dl /* was it NUL? */
+ jz L3 /* yes, then exit */
+
+ incl %eax /* increment pointer */
+ decl %ecx /* decrement length counter */
+ jz L9 /* no more allowed => exit */
+
+ movb (%eax,%esi), %dl /* load current char */
+ movb %dl, (%eax) /* and store it */
+ testb %dl, %dl /* was it NUL? */
+ jz L3 /* yes, then exit */
+
+ incl %eax /* increment pointer */
+ decl %ecx /* decrement length counter */
+ jz L9 /* no more allowed => exit */
+
+ movb (%eax,%esi), %dl /* load current char */
+ movb %dl, (%eax) /* and store it */
+ testb %dl, %dl /* was it NUL? */
+ jz L3 /* yes, then exit */
+
+ incl %eax /* increment pointer */
+ jmp L9 /* we don't have to test for counter underflow
+ because we know we had a most 3 bytes
+ remaining => exit */
+
+ /* When coming from the main loop we have to adjust the pointer. */
+L4: decl %ecx /* decrement counter */
+ incl %eax /* increment pointer */
+
+L5: decl %ecx /* increment pointer */
+ incl %eax /* increment pointer */
+
+L6: decl %ecx /* increment pointer */
+ incl %eax /* increment pointer */
+L7:
+
+ addl $3, %ecx /* correct pre-decrementation of counter
+ at the beginning of the loop; but why 3
+ and not 4? Very simple, we have to count
+ the NUL char we already wrote. */
+ jz L9 /* counter is also 0 => exit */
+
+ /* We now have to fill the rest of the buffer with NUL. This
+ is done in a tricky way. Please note that the adressing mode
+ used below is not the same we used above. Here we use the
+ %ecx register. */
+L8:
+ movb $0, (%ecx,%eax) /* store NUL char */
+L3: decl %ecx /* all bytes written? */
+ jnz L8 /* no, then again */
+
+L9: popl %esi /* restore saved register content */
+
+ ret
+
+weak_alias (__stpncpy, stpncpy)
diff --git a/sysdeps/i386/strchr.S b/sysdeps/i386/strchr.S
new file mode 100644
index 0000000000..de947cd252
--- /dev/null
+++ b/sysdeps/i386/strchr.S
@@ -0,0 +1,278 @@
+/* strchr (str, ch) -- Return pointer to first occurrence of CH in STR.
+For Intel 80x86, x>=3.
+Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>
+Some optimisations by Alan Modra <Alan@SPRI.Levels.UniSA.Edu.Au>
+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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. 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"
+
+/*
+ INPUT PARAMETERS:
+ str (sp + 4)
+ ch (sp + 8)
+*/
+
+ .text
+ENTRY (strchr)
+ pushl %edi /* Save callee-safe registers used here. */
+
+ movl 8(%esp), %eax /* get string pointer */
+ movl 12(%esp), %edx /* get character we are looking for */
+
+ /* At the moment %edx contains C. What we need for the
+ algorithm is C in all bytes of the dword. Avoid
+ operations on 16 bit words because these require an
+ prefix byte (and one more cycle). */
+ movb %dl, %dh /* now it is 0|0|c|c */
+ movl %edx, %ecx
+ shll $16, %edx /* now it is c|c|0|0 */
+ movw %cx, %dx /* and finally c|c|c|c */
+
+ /* Before we start with the main loop we process single bytes
+ until the source pointer is aligned. This has two reasons:
+ 1. aligned 32-bit memory access is faster
+ and (more important)
+ 2. we process in the main loop 32 bit in one step although
+ we don't know the end of the string. But accessing at
+ 4-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 inherant
+ boundaries are multiples of 4. */
+
+ testb $3, %eax /* correctly aligned ? */
+ jz L11 /* yes => begin loop */
+ movb (%eax), %cl /* load byte in question (we need it twice) */
+ cmpb %cl, %dl /* compare byte */
+ je L6 /* target found => return */
+ testb %cl, %cl /* is NUL? */
+ jz L2 /* yes => return NULL */
+ incl %eax /* increment pointer */
+
+ testb $3, %eax /* correctly aligned ? */
+ jz L11 /* yes => begin loop */
+ movb (%eax), %cl /* load byte in question (we need it twice) */
+ cmpb %cl, %dl /* compare byte */
+ je L6 /* target found => return */
+ testb %cl, %cl /* is NUL? */
+ jz L2 /* yes => return NULL */
+ incl %eax /* increment pointer */
+
+ testb $3, %eax /* correctly aligned ? */
+ jz L11 /* yes => begin loop */
+ movb (%eax), %cl /* load byte in question (we need it twice) */
+ cmpb %cl, %dl /* compare byte */
+ je L6 /* target found => return */
+ testb %cl, %cl /* is NUL? */
+ jz L2 /* yes => return NULL */
+ incl %eax /* increment pointer */
+
+ /* No we have reached alignment. */
+ jmp L11 /* begin loop */
+
+ /* 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 LONGWORD 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. If one of bits 24-31 is set, there will be a carry
+ into bit 32 (=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. */
+
+ /* Each round the main loop processes 16 bytes. */
+
+ ALIGN(4)
+
+L1: addl $16, %eax /* adjust pointer for whole round */
+
+L11: movl (%eax), %ecx /* get word (= 4 bytes) in question */
+ xorl %edx, %ecx /* XOR with word c|c|c|c => bytes of str == c
+ are now 0 */
+ movl $0xfefefeff, %edi /* magic value */
+ addl %ecx, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* C */
+
+ /* According to the algorithm we had to reverse the effect of the
+ XOR first and then test the overflow bits. But because the
+ following XOR would destroy the carry flag and it would (in a
+ representation with more than 32 bits) not alter then last
+ overflow, we can now test this condition. If no carry is signaled
+ no overflow must have occured in the last byte => it was 0. */
+ jnc L7
+
+ /* We are only interested in carry bits that change due to the
+ previous add, so remove original bits */
+ xorl %ecx, %edi /* ((word^charmask)+magic)^(word^charmask) */
+
+ /* Now test for the other three overflow bits. */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+
+ /* If at least one byte of the word is C we don't get 0 in %edi. */
+ jnz L7 /* found it => return pointer */
+
+ /* Now we made sure the dword does not contain the character we are
+ looking for. But because we deal with strings we have to check
+ for the end of string before testing the next dword. */
+
+ xorl %edx, %ecx /* restore original dword without reload */
+ movl $0xfefefeff, %edi /* magic value */
+ addl %ecx, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L2 /* highest byte is NUL => return NULL */
+ xorl %ecx, %edi /* (word+magic)^word */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jnz L2 /* found NUL => return NULL */
+
+ movl 4(%eax), %ecx /* get word (= 4 bytes) in question */
+ xorl %edx, %ecx /* XOR with word c|c|c|c => bytes of str == c
+ are now 0 */
+ movl $0xfefefeff, %edi /* magic value */
+ addl %ecx, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* C */
+ jnc L71 /* highest byte is C => return pointer */
+ xorl %ecx, %edi /* ((word^charmask)+magic)^(word^charmask) */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jnz L71 /* found it => return pointer */
+ xorl %edx, %ecx /* restore original dword without reload */
+ movl $0xfefefeff, %edi /* magic value */
+ addl %ecx, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L2 /* highest byte is NUL => return NULL */
+ xorl %ecx, %edi /* (word+magic)^word */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jnz L2 /* found NUL => return NULL */
+
+ movl 8(%eax), %ecx /* get word (= 4 bytes) in question */
+ xorl %edx, %ecx /* XOR with word c|c|c|c => bytes of str == c
+ are now 0 */
+ movl $0xfefefeff, %edi /* magic value */
+ addl %ecx, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* C */
+ jnc L72 /* highest byte is C => return pointer */
+ xorl %ecx, %edi /* ((word^charmask)+magic)^(word^charmask) */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jnz L72 /* found it => return pointer */
+ xorl %edx, %ecx /* restore original dword without reload */
+ movl $0xfefefeff, %edi /* magic value */
+ addl %ecx, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L2 /* highest byte is NUL => return NULL */
+ xorl %ecx, %edi /* (word+magic)^word */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jnz L2 /* found NUL => return NULL */
+
+ movl 12(%eax), %ecx /* get word (= 4 bytes) in question */
+ xorl %edx, %ecx /* XOR with word c|c|c|c => bytes of str == c
+ are now 0 */
+ movl $0xfefefeff, %edi /* magic value */
+ addl %ecx, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* C */
+ jnc L73 /* highest byte is C => return pointer */
+ xorl %ecx, %edi /* ((word^charmask)+magic)^(word^charmask) */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jnz L73 /* found it => return pointer */
+ xorl %edx, %ecx /* restore original dword without reload */
+ movl $0xfefefeff, %edi /* magic value */
+ addl %ecx, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L2 /* highest byte is NUL => return NULL */
+ xorl %ecx, %edi /* (word+magic)^word */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jz L1 /* no NUL found => restart loop */
+
+L2: /* Return NULL. */
+ xorl %eax, %eax /* load NULL in return value register */
+ popl %edi /* restore saved register content */
+ ret
+
+L73: addl $4, %eax /* adjust pointer */
+L72: addl $4, %eax
+L71: addl $4, %eax
+
+ /* 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. */
+
+L7: testb %cl, %cl /* is first byte C? */
+ jz L6 /* yes => return pointer */
+ cmpb %dl, %cl /* is first byte NUL? */
+ je L2 /* yes => return NULL */
+ incl %eax /* it's not in the first byte */
+
+ testb %ch, %ch /* is second byte C? */
+ jz L6 /* yes => return pointer */
+ cmpb %dl, %ch /* is second byte NUL? */
+ je L2 /* yes => return NULL? */
+ incl %eax /* it's not in the second byte */
+
+ shrl $16, %ecx /* make upper byte accessible */
+ testb %cl, %cl /* is third byte C? */
+ jz L6 /* yes => return pointer */
+ cmpb %dl, %cl /* is third byte NUL? */
+ je L2 /* yes => return NULL */
+
+ /* It must be in the fourth byte and it cannot be NUL. */
+ incl %eax
+
+L6: popl %edi /* restore saved register content */
+
+ ret
+
+weak_alias (strchr, index)
diff --git a/sysdeps/i386/strcspn.S b/sysdeps/i386/strcspn.S
new file mode 100644
index 0000000000..b0e789b490
--- /dev/null
+++ b/sysdeps/i386/strcspn.S
@@ -0,0 +1,176 @@
+/* strcspn (str, ss) -- Return the length of the initial segement of STR
+ which contains no characters from SS.
+For Intel 80x86, x>=3.
+Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>
+Bug fixes by Alan Modra <Alan@SPRI.Levels.UniSA.Edu.Au>
+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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. 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"
+
+/*
+ INPUT PARAMETERS:
+ str (sp + 4)
+ stopset (sp + 8)
+*/
+
+ .text
+ENTRY (strcspn)
+ movl 4(%esp), %edx /* get string pointer */
+ movl 8(%esp), %eax /* get stopset pointer */
+
+ /* 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. The unrolled form is much faster than a loop. */
+ xorl %ecx, %ecx /* %ecx = 0 !!! */
+
+ pushl %ecx /* make a 256 bytes long block filled with 0 */
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl $0 /* These immediate values make the label 2 */
+ pushl $0 /* to be aligned on a 16 byte boundary to */
+ pushl $0 /* get a better performance of the loop. */
+ pushl $0
+ pushl $0
+ pushl $0
+
+/* For understanding the following code remember that %ecx == 0 now.
+ Although all the following instruction only modify %cl we always
+ have a correct zero-extended 32-bit value in %ecx. */
+
+/* Don't change the "testb $0xff,%%cl" to "testb %%cl,%%cl". We want
+ longer instructions so that the next loop aligns without adding nops. */
+
+L2: movb (%eax), %cl /* get byte from stopset */
+ testb %cl, %cl /* is NUL char? */
+ jz L1 /* yes => start compare loop */
+ movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */
+
+ movb 1(%eax), %cl /* get byte from stopset */
+ testb $0xff, %cl /* is NUL char? */
+ jz L1 /* yes => start compare loop */
+ movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */
+
+ movb 2(%eax), %cl /* get byte from stopset */
+ testb $0xff, %cl /* is NUL char? */
+ jz L1 /* yes => start compare loop */
+ movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */
+
+ movb 3(%eax), %cl /* get byte from stopset */
+ addl $4, %eax /* increment stopset pointer */
+ movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */
+ testb $0xff, %cl /* is NUL char? */
+ jnz L2 /* no => process next dword from stopset */
+
+L1: leal -4(%edx), %eax /* 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 chracter 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. */
+
+L3: addl $4, %eax /* adjust pointer for full loop round */
+
+ movb (%eax), %cl /* get byte from string */
+ cmpb %cl, (%esp,%ecx) /* is it contained in stopset? */
+ je L4 /* yes => return */
+
+ movb 1(%eax), %cl /* get byte from string */
+ cmpb %cl, (%esp,%ecx) /* is it contained in stopset? */
+ je L5 /* yes => return */
+
+ movb 2(%eax), %cl /* get byte from string */
+ cmpb %cl, (%esp,%ecx) /* is it contained in stopset? */
+ je L6 /* yes => return */
+
+ movb 3(%eax), %cl /* get byte from string */
+ cmpb %cl, (%esp,%ecx) /* is it contained in stopset? */
+ jne L3 /* yes => return */
+
+ incl %eax /* adjust pointer */
+L6: incl %eax
+L5: incl %eax
+
+L4: subl %edx, %eax /* we have to return the number of valid
+ characters, so compute distance to first
+ non-valid character */
+ addl $256, %esp /* remove stopset */
+
+ ret
diff --git a/sysdeps/i386/strpbrk.S b/sysdeps/i386/strpbrk.S
new file mode 100644
index 0000000000..245bf1a935
--- /dev/null
+++ b/sysdeps/i386/strpbrk.S
@@ -0,0 +1,177 @@
+/* strcspn (str, ss) -- Return the length of the initial segement of STR
+ which contains no characters from SS.
+For Intel 80x86, x>=3.
+Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>
+Bug fixes by Alan Modra <Alan@SPRI.Levels.UniSA.Edu.Au>
+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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. 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"
+
+/*
+ INPUT PARAMETERS:
+ str (sp + 4)
+ stopset (sp + 8)
+*/
+
+ .text
+ENTRY (strpbrk)
+ movl 4(%esp), %edx /* get string pointer */
+ movl 8(%esp), %eax /* get stopset pointer */
+
+ /* 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. The unrolled form is much faster than a loop. */
+ xorl %ecx, %ecx /* %ecx = 0 !!! */
+
+ pushl %ecx /* make a 256 bytes long block filled with 0 */
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl $0 /* These immediate values make the label 2 */
+ pushl $0 /* to be aligned on a 16 byte boundary to */
+ pushl $0 /* get a better performance of the loop. */
+ pushl $0
+ pushl $0
+ pushl $0
+
+/* For understanding the following code remember that %ecx == 0 now.
+ Although all the following instruction only modify %cl we always
+ have a correct zero-extended 32-bit value in %ecx. */
+
+/* Don't change the "testb $0xff,%%cl" to "testb %%cl,%%cl". We want
+ longer instructions so that the next loop aligns without adding nops. */
+
+L2: movb (%eax), %cl /* get byte from stopset */
+ testb %cl, %cl /* is NUL char? */
+ jz L1 /* yes => start compare loop */
+ movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */
+
+ movb 1(%eax), %cl /* get byte from stopset */
+ testb $0xff, %cl /* is NUL char? */
+ jz L1 /* yes => start compare loop */
+ movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */
+
+ movb 2(%eax), %cl /* get byte from stopset */
+ testb $0xff, %cl /* is NUL char? */
+ jz L1 /* yes => start compare loop */
+ movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */
+
+ movb 3(%eax), %cl /* get byte from stopset */
+ addl $4, %eax /* increment stopset pointer */
+ movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */
+ testb $0xff, %cl /* is NUL char? */
+ jnz L2 /* no => process next dword from stopset */
+
+L1: leal -4(%edx), %eax /* 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 chracter 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. */
+
+L3: addl $4, %eax /* adjust pointer for full loop round */
+
+ movb (%eax), %cl /* get byte from string */
+ cmpb %cl, (%esp,%ecx) /* is it contained in stopset? */
+ je L4 /* yes => return */
+
+ movb 1(%eax), %cl /* get byte from string */
+ cmpb %cl, (%esp,%ecx) /* is it contained in stopset? */
+ je L5 /* yes => return */
+
+ movb 2(%eax), %cl /* get byte from string */
+ cmpb %cl, (%esp,%ecx) /* is it contained in stopset? */
+ je L6 /* yes => return */
+
+ movb 3(%eax), %cl /* get byte from string */
+ cmpb %cl, (%esp,%ecx) /* is it contained in stopset? */
+ jne L3 /* yes => return */
+
+ incl %eax /* adjust pointer */
+L6: incl %eax
+L5: incl %eax
+
+L4: addl $256, %esp /* remove stopset */
+
+ orb %cl, %cl /* was last character NUL? */
+ jnz L7 /* no => return pointer */
+ xorl %eax, %eax /* return NULL */
+
+L7: ret
diff --git a/sysdeps/i386/strrchr.S b/sysdeps/i386/strrchr.S
new file mode 100644
index 0000000000..468a940d74
--- /dev/null
+++ b/sysdeps/i386/strrchr.S
@@ -0,0 +1,321 @@
+/* strchr (str, ch) -- Return pointer to last occurrence of CH in STR.
+For Intel 80x86, x>=3.
+Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>
+Some optimisations by Alan Modra <Alan@SPRI.Levels.UniSA.Edu.Au>
+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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. 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"
+
+/*
+ INPUT PARAMETERS:
+ str (sp + 4)
+ ch (sp + 8)
+*/
+
+ .text
+ENTRY (strrchr)
+ pushl %edi /* Save callee-safe registers used here. */
+ pushl %esi
+
+ xorl %eax, %eax
+ movl 12(%esp), %esi /* get string pointer */
+ movl 16(%esp), %ecx /* get character we are looking for */
+
+ /* At the moment %ecx contains C. What we need for the
+ algorithm is C in all bytes of the dword. Avoid
+ operations on 16 bit words because these require an
+ prefix byte (and one more cycle). */
+ movb %cl, %ch /* now it is 0|0|c|c */
+ movl %ecx, %edx
+ shll $16, %ecx /* now it is c|c|0|0 */
+ movw %dx, %cx /* and finally c|c|c|c */
+
+ /* Before we start with the main loop we process single bytes
+ until the source pointer is aligned. This has two reasons:
+ 1. aligned 32-bit memory access is faster
+ and (more important)
+ 2. we process in the main loop 32 bit in one step although
+ we don't know the end of the string. But accessing at
+ 4-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 inherant
+ boundaries are multiples of 4. */
+
+ testb $3, %esi /* correctly aligned ? */
+ jz L19 /* yes => begin loop */
+ movb (%esi), %dl /* load byte in question (we need it twice) */
+ cmpb %dl, %cl /* compare byte */
+ jne L11 /* target found => return */
+ movl %esi, %eax /* remember pointer as possible result */
+L11: orb %dl, %dl /* is NUL? */
+ jz L2 /* yes => return NULL */
+ incl %esi /* increment pointer */
+
+ testb $3, %esi /* correctly aligned ? */
+ jz L19 /* yes => begin loop */
+ movb (%esi), %dl /* load byte in question (we need it twice) */
+ cmpb %dl, %cl /* compare byte */
+ jne L12 /* target found => return */
+ movl %esi, %eax /* remember pointer as result */
+L12: orb %dl, %dl /* is NUL? */
+ jz L2 /* yes => return NULL */
+ incl %esi /* increment pointer */
+
+ testb $3, %esi /* correctly aligned ? */
+ jz L19 /* yes => begin loop */
+ movb (%esi), %dl /* load byte in question (we need it twice) */
+ cmpb %dl, %cl /* compare byte */
+ jne L13 /* target found => return */
+ movl %esi, %eax /* remember pointer as result */
+L13: orb %cl, %cl /* is NUL? */
+ jz L2 /* yes => return NULL */
+ incl %esi /* increment pointer */
+
+ /* No we have reached alignment. */
+ jmp L19 /* begin loop */
+
+ /* 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 LONGWORD 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. If one of bits 24-31 is set, there will be a carry
+ into bit 32 (=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. */
+
+ /* Each round the main loop processes 16 bytes. */
+
+ /* Jump to here when the character is detected. We chose this
+ way around because the character one is looking for is not
+ as frequent as the rest and taking a conditional jump is more
+ expensive than ignoring it.
+
+ Some more words to the code below: it might not be obvious why
+ we decrement the source pointer here. In the loop the pointer
+ is not pre-incremented and so it still points before the word
+ we are looking at. But you should take a look at the instruction
+ which gets executed before we get into the loop: `addl $16, %esi'.
+ This makes the following subs into adds. */
+
+ /* These fill bytes make the main loop be correctly aligned.
+ We cannot use align because it is not the following instruction
+ which should be aligned. */
+ .byte 0, 0, 0, 0, 0, 0, 0, 0
+
+L4: subl $4, %esi /* adjust pointer */
+L41: subl $4, %esi
+L42: subl $4, %esi
+L43: testl $0xff000000, %edx /* is highest byte == C? */
+ jnz L33 /* no => try other bytes */
+ leal 15(%esi), %eax /* store address as result */
+ jmp L1 /* and start loop again */
+
+L3: subl $4, %esi /* adjust pointer */
+L31: subl $4, %esi
+L32: subl $4, %esi
+L33: testl $0xff0000, %edx /* is C in third byte? */
+ jnz L51 /* no => try other bytes */
+ leal 14(%esi), %eax /* store address as result */
+ jmp L1 /* and start loop again */
+
+L51:
+ /* At this point we know that the byte is in one of the lower bytes.
+ We make a guess and correct it if necessary. This reduces the
+ number of necessary jumps. */
+ leal 12(%esi), %eax /* guess address of lowest byte as result */
+ testb %dh, %dh /* is guess correct? */
+ jnz L1 /* yes => start loop */
+ leal 13(%esi), %eax /* correct guess to second byte */
+
+L1: addl $16, %esi /* increment pointer for full round */
+
+L19: movl (%esi), %edx /* get word (= 4 bytes) in question */
+ movl $0xfefefeff, %edi /* magic value */
+ addl %edx, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+
+ /* According to the algorithm we had to reverse the effect of the
+ XOR first and then test the overflow bits. But because the
+ following XOR would destroy the carry flag and it would (in a
+ representation with more than 32 bits) not alter then last
+ overflow, we can now test this condition. If no carry is signaled
+ no overflow must have occured in the last byte => it was 0. */
+
+ jnc L20 /* found NUL => check last word */
+
+ /* We are only interested in carry bits that change due to the
+ previous add, so remove original bits */
+ xorl %edx, %edi /* (word+magic)^word */
+
+ /* Now test for the other three overflow bits. */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+
+ /* If at least one byte of the word is C we don't get 0 in %edi. */
+ jnz L20 /* found NUL => check last word */
+
+ /* Now we made sure the dword does not contain the character we are
+ looking for. But because we deal with strings we have to check
+ for the end of string before testing the next dword. */
+
+ xorl %ecx, %edx /* XOR with word c|c|c|c => bytes of str == c
+ are now 0 */
+ movl $0xfefefeff, %edi /* magic value */
+ addl %edx, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L4 /* highest byte is C => examine dword */
+ xorl %edx, %edi /* ((word^charmask)+magic)^(word^charmask) */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jnz L3 /* C is detected in the word => examine it */
+
+ movl 4(%esi), %edx /* get word (= 4 bytes) in question */
+ movl $0xfefefeff, %edi /* magic value */
+ addl %edx, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L21 /* found NUL => check last word */
+ xorl %edx, %edi /* (word+magic)^word */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jnz L21 /* found NUL => check last word */
+ xorl %ecx, %edx /* XOR with word c|c|c|c => bytes of str == c
+ are now 0 */
+ movl $0xfefefeff, %edi /* magic value */
+ addl %edx, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L41 /* highest byte is C => examine dword */
+ xorl %edx, %edi /* ((word^charmask)+magic)^(word^charmask) */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jnz L31 /* C is detected in the word => examine it */
+
+ movl 8(%esi), %edx /* get word (= 4 bytes) in question */
+ movl $0xfefefeff, %edi /* magic value */
+ addl %edx, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L22 /* found NUL => check last word */
+ xorl %edx, %edi /* (word+magic)^word */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jnz L22 /* found NUL => check last word */
+ xorl %ecx, %edx /* XOR with word c|c|c|c => bytes of str == c
+ are now 0 */
+ movl $0xfefefeff, %edi /* magic value */
+ addl %edx, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L42 /* highest byte is C => examine dword */
+ xorl %edx, %edi /* ((word^charmask)+magic)^(word^charmask) */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jnz L32 /* C is detected in the word => examine it */
+
+ movl 12(%esi), %edx /* get word (= 4 bytes) in question */
+ movl $0xfefefeff, %edi /* magic value */
+ addl %edx, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L23 /* found NUL => check last word */
+ xorl %edx, %edi /* (word+magic)^word */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jnz L23 /* found NUL => check last word */
+ xorl %ecx, %edx /* XOR with word c|c|c|c => bytes of str == c
+ are now 0 */
+ movl $0xfefefeff, %edi /* magic value */
+ addl %edx, %edi /* add the magic value to the word. We get
+ carry bits reported for each byte which
+ is *not* 0 */
+ jnc L43 /* highest byte is C => examine dword */
+ xorl %edx, %edi /* ((word^charmask)+magic)^(word^charmask) */
+ orl $0xfefefeff, %edi /* set all non-carry bits */
+ incl %edi /* add 1: if one carry bit was *not* set
+ the addition will not result in 0. */
+ jz L1 /* C is not detected => restart loop */
+ jmp L33 /* examine word */
+
+L23: addl $4, %esi /* adjust pointer */
+L22: addl $4, %esi
+L21: addl $4, %esi
+
+ /* What remains to do is to test which byte the NUL char is and
+ whether the searched character appears in one of the bytes
+ before. A special case is that the searched byte maybe NUL.
+ In this case a pointer to the terminating NUL char has to be
+ returned. */
+
+L20: cmpb %cl, %dl /* is first byte == C? */
+ jne L24 /* no => skip */
+ movl %esi, %eax /* store address as result */
+L24: testb %dl, %dl /* is first byte == NUL? */
+ jz L2 /* yes => return */
+
+ cmpb %cl, %dh /* is second byte == C? */
+ jne L25 /* no => skip */
+ leal 1(%esi), %eax /* store address as result */
+L25: testb %dh, %dh /* is second byte == NUL? */
+ jz L2 /* yes => return */
+
+ shrl $16,%edx /* make upper bytes accessible */
+ cmpb %cl, %dl /* is third byte == C */
+ jne L26 /* no => skip */
+ leal 2(%esi), %eax /* store address as result */
+L26: testb %dl, %dl /* is third byte == NUL */
+ jz L2 /* yes => return */
+
+ cmpb %cl, %dh /* is fourth byte == C */
+ jne L2 /* no => skip */
+ leal 3(%esi), %eax /* store address as result */
+
+L2: popl %esi /* restore saved register content */
+ popl %edi
+
+ ret
+
+weak_alias (strrchr, rindex)
diff --git a/sysdeps/i386/strspn.S b/sysdeps/i386/strspn.S
new file mode 100644
index 0000000000..1a02026285
--- /dev/null
+++ b/sysdeps/i386/strspn.S
@@ -0,0 +1,176 @@
+/* strcspn (str, ss) -- Return the length of the initial segement of STR
+ which contains only characters from SS.
+For Intel 80x86, x>=3.
+Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>
+Bug fixes by Alan Modra <Alan@SPRI.Levels.UniSA.Edu.Au>
+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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. 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"
+
+/*
+ INPUT PARAMETERS:
+ str (sp + 4)
+ skipset (sp + 8)
+*/
+
+ .text
+ENTRY (strspn)
+ movl 4(%esp), %edx /* get string pointer */
+ movl 8(%esp), %eax /* get skipset pointer */
+
+ /* 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. The unrolled form is much faster than a loop. */
+ xorl %ecx, %ecx /* %ecx = 0 !!! */
+
+ pushl %ecx /* make a 256 bytes long block filled with 0 */
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl %ecx
+ pushl $0 /* These immediate values make the label 2 */
+ pushl $0 /* to be aligned on a 16 byte boundary to */
+ pushl $0 /* get a better performance of the loop. */
+ pushl $0
+ pushl $0
+ pushl $0
+
+/* For understanding the following code remember that %ecx == 0 now.
+ Although all the following instruction only modify %cl we always
+ have a correct zero-extended 32-bit value in %ecx. */
+
+/* Don't change the "testb $0xff,%%cl" to "testb %%cl,%%cl". We want
+ longer instructions so that the next loop aligns without adding nops. */
+
+L2: movb (%eax), %cl /* get byte from stopset */
+ testb %cl, %cl /* is NUL char? */
+ jz L1 /* yes => start compare loop */
+ movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */
+
+ movb 1(%eax), %cl /* get byte from stopset */
+ testb $0xff, %cl /* is NUL char? */
+ jz L1 /* yes => start compare loop */
+ movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */
+
+ movb 2(%eax), %cl /* get byte from stopset */
+ testb $0xff, %cl /* is NUL char? */
+ jz L1 /* yes => start compare loop */
+ movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */
+
+ movb 3(%eax), %cl /* get byte from stopset */
+ addl $4, %eax /* increment stopset pointer */
+ movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */
+ testb $0xff, %cl /* is NUL char? */
+ jnz L2 /* no => process next dword from stopset */
+
+L1: leal -4(%edx), %eax /* 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 chracter 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. */
+
+L3: addl $4, %eax /* adjust pointer for full loop round */
+
+ movb (%eax), %cl /* get byte from string */
+ testb %cl, (%esp,%ecx) /* is it contained in skipset? */
+ jz L4 /* no => return */
+
+ movb 1(%eax), %cl /* get byte from string */
+ testb %cl, (%esp,%ecx) /* is it contained in skipset? */
+ jz L5 /* no => return */
+
+ movb 2(%eax), %cl /* get byte from string */
+ testb %cl, (%esp,%ecx) /* is it contained in skipset? */
+ jz L6 /* no => return */
+
+ movb 3(%eax), %cl /* get byte from string */
+ testb %cl, (%esp,%ecx) /* is it contained in skipset? */
+ jnz L3 /* yes => start loop again */
+
+ incl %eax /* adjust pointer */
+L6: incl %eax
+L5: incl %eax
+
+L4: subl %edx, %eax /* we have to return the number of valid
+ characters, so compute distance to first
+ non-valid character */
+ addl $256, %esp /* remove stopset */
+
+ ret
diff --git a/sysdeps/i386/sub_n.S b/sysdeps/i386/sub_n.S
index 64d2c25293..e18a70885b 100644
--- a/sysdeps/i386/sub_n.S
+++ b/sysdeps/i386/sub_n.S
@@ -1,7 +1,7 @@
/* i80386 __mpn_sub_n -- Add two limb vectors of the same length > 0 and store
sum in a third limb vector.
-Copyright (C) 1992, 1994 Free Software Foundation, Inc.
+Copyright (C) 1992, 1994, 1995 Free Software Foundation, Inc.
This file is part of the GNU MP Library.
@@ -37,10 +37,10 @@ C_SYMBOL_NAME(__mpn_sub_n:)
pushl %edi
pushl %esi
- movl 12(%esp),%edi /* res_ptr */
- movl 16(%esp),%esi /* s1_ptr */
- movl 20(%esp),%edx /* s2_ptr */
- movl 24(%esp),%ecx /* size */
+ movl 12(%esp),%edi /* res_ptr */
+ movl 16(%esp),%esi /* s1_ptr */
+ movl 20(%esp),%edx /* s2_ptr */
+ movl 24(%esp),%ecx /* size */
movl %ecx,%eax
shrl $3,%ecx /* compute count for unrolled loop */
@@ -54,14 +54,18 @@ C_SYMBOL_NAME(__mpn_sub_n:)
subl %eax,%edx /* ... enter the loop */
shrl $2,%eax /* restore previous value */
#ifdef PIC
- call here
-here: leal (Loop - 3 - here)(%eax,%eax,8),%eax
- addl %eax,(%esp)
- ret
+/* Calculate start address in loop for PIC. Due to limitations in some
+ assemblers, Loop-L0-3 cannot be put into the leal */
+ call L0
+L0: leal (%eax,%eax,8),%eax
+ addl (%esp),%eax
+ addl $(Loop-L0-3),%eax
+ addl $4,%esp
#else
- leal (Loop - 3)(%eax,%eax,8),%eax /* calc start addr in loop */
- jmp *%eax /* jump into loop */
+/* Calculate start address in loop for non-PIC. */
+ leal (Loop - 3)(%eax,%eax,8),%eax
#endif
+ jmp *%eax /* jump into loop */
ALIGN (3)
Loop: movl (%esi),%eax
sbbl (%edx),%eax