glibc/sysdeps/i386/i586/strlen.S
Ulrich Drepper 6ed0492f8e update from main archvie 961022
Tue Oct 22 21:38:21 1996  Ulrich Drepper  <drepper@cygnus.com>

	* version.h: Bump version number to 1.97.

	* features.h: Undo change of Sun Oct 20 22:19:58 1996.
	Include libc-version.h.
	* features.h.in: Removed.
	* Makefile: Change rules to generate libc-version.h instead of
	features.h.

	* malloc/free.c: Add cast to prevent warning.
	* malloc/malloc-walk.c: Likewise.
	* malloc/ralloc.c: Likewise.
	* malloc/realloc.c: Likewise.

	* grp/fgetgrent_r.c: Accept empty numeric field if name start with +
	or -.
	* pwd/fgetpwent_r.c: Likewise.
	* nss/nss_files/files-grp.c: Don't accept entries with names starting
	with + or - in lookup functions.
	* nss/nss_files/files-pwd.c: Likewise.

	* Makerules: Call autolock.sh using $(SHELL).

Mon Oct 21 22:52:16 1996  NIIBE Yutaka  <gniibe@mri.co.jp>

	* elf/dl-minimal.c: Don't define `dgettext' replacement but
	`dcgettext'.  When optimizing the macros in <libintl.h> define
	`dgettext' as a macro and so this function will never be called.

Mon Oct 21 15:41:59 1996  Ulrich Drepper  <drepper@cygnus.com>

	* sysdeps/i386/sysdep.h: Define END to use .size when available.
	(PSEUDO_END): Use END.
	* sysdeps/unix/sysv/linux/i386/sysdep.h: Define PSEUDO_END to
	define SYSCALL_ERROR_HANDLER before using END.
	(SYSCALL_ERROR_HANDLER): Don't use .size directive.
	* sysdeps/unix/sysv/linux/clone.S: Don't use SYSCALL_ERROR_HANDLER
	and .size directive but PSEUDO_END.
	* sysdeps/unix/sysv/linux/mmap.S: Likewise.
	* sysdeps/unix/sysv/linux/socket.S: Likewise.
	* sysdeps/unix/sysv/linux/syscall.S: Likewise.
	* sysdeps/unix/sysv/linux/sysdep.S (__errno_location): Use END.
	* sysdeps/unix/i386/sysdep.S (__syscall_error): Likewise.
	* sysdeps/i386/__longjmp.S: Use END instead of PSEUDO_END.
	* sysdeps/i386/bsd-_setjmp.S: Likewise.
	* sysdeps/i386/bsd-setjmp.S: Likewise.
	* sysdeps/i386/memchr.S: Likewise.
	* sysdeps/i386/memcmp.S: Likewise.
	* sysdeps/i386/setjmp.S: Likewise.
	* sysdeps/i386/stpcpy.S: Likewise.
	* sysdeps/i386/stpncpy.S: Likewise.
	* sysdeps/i386/strchr.S: Likewise.
	* sysdeps/i386/strcspn.S: Likewise.
	* sysdeps/i386/strpbrk.S: Likewise.
	* sysdeps/i386/strrchr.S: Likewise.
	* sysdeps/i386/strspn.S: Likewise.
	* sysdeps/i386/strtok.S: Likewise.
	* sysdeps/i386/i486/strcat.S: Likewise.
	* sysdeps/i386/i486/strlen.S: Likewise.
	* sysdeps/i386/i586/memset.S: Likewise.
	* sysdeps/i386/i586/strchr.S: Likewise.
	* sysdeps/i386/i586/strlen.S: Likewise.

	* sysdeps/i386/strlen.c: De-ANSI-fy.

	* sysdeps/generic/_strerror.c: Undo change of Mon Oct 21 01:32:36 1996.
	Define dgettext if not defined to use dcgettext.
	* sysdeps/mach/_strerror.c: Likewise.

	* sysdeps/unix/sysv/i386/time.S: Add PSEUDO_END to get
 	__syscall_error defined..

Sat Oct 19 12:27:50 1996  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* sysdeps/unix/sysv/linux/m68k/mmap.S: Fix braino: CALL_MCOUNT is
	already included in the ENTRY macro.  Remove SYSCALL_ERROR_HANDLER
	now provided by PSEUDO_END.
	* sysdeps/unix/sysv/linux/m68k/sigreturn.S: Likewise.
	* sysdeps/unix/sysv/linux/m68k/socket.S: Likewise.
	* sysdeps/unix/sysv/linux/m68k/syscall.S: Likewise.
	* sysdeps/unix/sysv/linux/m68k/sysdep.S: Likewise.
	* sysdeps/unix/sysv/linux/m68k/clone.S: Likewise.  Use JUMPTARGET.

	* sysdeps/generic/sysdep.h (END): Provide default empty
	definition.
	* sysdeps/unix/sysv/linux/m68k/sysdep.h (END): Redefine to use
	size directive.
	(PSEUDO): Don't include SYSCALL_ERROR_HANDLER.
	(PSEUDO_END): Include it here instead.
	(SYSCALL_ERROR_HANDLER): Remove type directive.
	* sysdeps/m68k/bsd-_setjmp.S: Use END, not PSEUDO_END.
	* sysdeps/m68k/bsd-setjmp.S: Likewise.
	* sysdeps/unix/sysv/linux/m68k/sigreturn.S: Likewise.
	* sysdeps/unix/sysv/linux/m68k/sysdep.S: Likewise.
	(__syscall_error): Can't use ENTRY macro.

Sat Oct 19 12:13:24 1996  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* sysdeps/unix/sysv/linux/syscalls.list (getresuid, setresuid):
	Set caller to EXTRA.

	O_SHLOCK.

Tue Oct 15 14:37:40 1996  Thomas Bushnell, n/BSG  <thomas@gnu.ai.mit.edu>

	* sysdeps/mach/hurd/fcntlbits.h (O_HURD): Add O_EXLOCK and
1996-10-22 23:29:26 +00:00

184 lines
5.5 KiB
ArmAsm

/* strlen -- Compute length og NUL terminated string.
Highly optimized version for ix86, x>=5.
Copyright (C) 1995, 1996 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 $3, %edx /* load mask (= 3) */
andl %eax, %edx /* separate last two bits of address */
jz L1 /* aligned => start loop */
jp L0 /* exactly two bits set */
cmpb %dh, (%eax) /* is byte NUL? */
je L2 /* yes => return */
incl %eax /* increment pointer */
cmpb %dh, (%eax) /* is byte NUL? */
je L2 /* yes => return */
incl %eax /* increment pointer */
xorl $2, %edx
jz L1
L0: cmpb %dh, (%eax) /* is byte NUL? */
je L2 /* yes => return */
incl %eax /* increment pointer */
xorl %edx, %edx /* We need %edx == 0 for later */
/* 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.
Note: %edx == 0 in any case here. */
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 */
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 */
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 */
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 */
andl $~magic, %edx /* any of the carry flags set? */
je L1 /* no => start loop again */
L3: subl $4, %eax /* correct too early pointer increment */
subl $magic, %ecx
cmpb $0, %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
END (strlen)