home *** CD-ROM | disk | FTP | other *** search
-
- /* strrchr (str, ch) -- Return pointer to last occurrence of CH in STR.
- For Intel 80x86, x>=3.
- Copyright (C) 1994 Free Software Foundation, Inc.
- Contributed by Ulrich Drepper <drepper@ira.uka.de>
-
- 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 <string.h>
-
- #include "asm-ops.h"
-
- char *
- strrchr(const char * str, int ch)
- {
- register char * __res;
-
- __asm__(
- /*
- * On entry the last found position (stored in %eax) is set
- * to NULL.
- */
-
- "movb %%cl,%%ch\n\t" /* now %cx is c|c */
- "movw %%cx,%%dx\n\t"
- "shll $16,%%ecx\n\t" /* %ecx is c|c|0|0 */
- "movw %%dx,%%cx\n\t" /* %ecx is c|c|c|c */
-
- "testl $3,%2\n\t"
- "jz " LF(19) "\n\t"
- "movb (%2),%%dl\n\t"
- "cmpb %%cl,%%dl\n\t"
- "jne " LF(11) "\n\t"
- "movl %2,%0\n"
- LL(11) "\torb %%dl,%%dl\n\t"
- "jz " LF(2) "\n\t"
- "incl %2\n\t"
-
- "testl $3,%2\n\t"
- "jz " LF(19) "\n\t"
- "movb (%2),%%dl\n\t"
- "cmpb %%cl,%%dl\n\t"
- "jne " LF(12) "\n\t"
- "movl %2,%0\n"
- LL(12) "\torb %%dl,%%dl\n\t"
- "jz " LF(2) "\n\t"
- "incl %2\n\t"
-
- "testl $3,%2\n\t"
- "jz " LF(19) "\n\t"
- "movb (%2),%%dl\n\t"
- "cmpb %%cl,%%dl\n\t"
- "jne " LF(13) "\n\t"
- "movl %2,%0\n"
- LL(13) "\torb %%dl,%%dl\n\t"
- "jz " LF(2) "\n\t"
- "incl %2\n\t"
-
- "jmp " LF(19) "\n\t"
-
- ALIGN "\n"
-
- LL(43) "\taddl $4,%2\n" /* correct missing pointer increments */
- LL(42) "\taddl $4,%2\n"
- LL(41) "\taddl $4,%2\n"
- LL(4) "\ttestl $0xff000000,%%edx\n\t"
- "jnz " LF(3) "\n\t"
- "leal 3(%2),%0\n\t"
- "jmp " LF(6) "\n\t"
-
- ALIGN "\n"
-
- LL(33) "\taddl $4,%2\n" /* correct missing pointer increments */
- LL(32) "\taddl $4,%2\n"
- LL(31) "\taddl $4,%2\n"
-
- LL(3) "\ttestl $0xff0000,%%edx\n\t"
- "jnz " LF(51) "\n\t"
- "leal 2(%2),%0\n\t"
- "jmp " LF(6) "\n\t"
-
- ALIGN "\n"
-
- LL(51) "\ttestb $0xff,%%dh\n\t"
- "jnz " LF(52) "\n\t"
- "leal 1(%2),%0\n\t"
- "jmp " LF(6) "\n"
-
- /* If you cannot guess what this is for look through the resulting
- * code. The dumb version has an .align at the end of the first
- * conditional region. This would cause a delay which is not
- * necessary if we could move the instructions behind the NOPS.
- * Exactly this is done here. The problem is that the number of
- * NOPs depends on the prepending instructions. If anything
- * changes there the number of may have to change, too. */
-
- #if defined(I_DONT_KNOW_WHAT_THIS_MEANS)
- LL(52) "\tmovl %2,%0\n"
-
- LL(6) "\tsubl $12,%2\n\t" /* together with the following +16 = +4 */
-
- ALIGN "\n"
-
- #else
- #if !defined(__i486__) && !defined(__i586__)
- /* Alignment on i386 is on 4-byte boundary. */
- "\tnop\n"
- #else
- "\tnop; nop; nop; nop; nop\n"
- #endif
-
- LL(52) "\tmovl %2,%0\n"
-
- LL(6) "\tsubl $12,%2\n" /* together with the following +16 = +4 */
-
- #endif
-
- /*
- * Some optimizations:
- * 1. four times unfolded loop
- * 2. loop pointer increment only at the end of the loop
- * 3. don't use register used for register variables (i.e. which
- * must be saved)
- * 4. optimize main flow path; the assumption is that the searched
- * character does not appear as often as other ones. So the
- * more expensive jump after the comparison if done for matched
- * characters.
- */
-
- LL(1) "\taddl $16,%2\n"
-
- LL(19) "\tmovl (%2),%%edx\n\t"
- "movl %%edx,%%edi\n\t"
- "addl $0xfefefeff,%%edx\n\t"
- "jnc " LF(20) "\n\t"
- "xorl %%edi,%%edx\n\t"
- "notl %%edx\n\t"
- "andl $0x01010100,%%edx\n\t"
- "jnz " LF(20) "\n\t"
- "xorl %%ecx,%%edi\n\t"
- "movl %%edi,%%edx\n\t"
- "addl $0xfefefeff,%%edi\n\t"
- "jnc " LB(4) "\n\t"
- "xorl %%edx,%%edi\n\t"
- "notl %%edi\n\t"
- "andl $0x01010100,%%edi\n\t"
- "jnz " LB(3) "\n\t"
-
- "movl 4(%2),%%edx\n\t"
- "movl %%edx,%%edi\n\t"
- "addl $0xfefefeff,%%edx\n\t"
- "jnc " LF(21) "\n\t"
- "xorl %%edi,%%edx\n\t"
- "notl %%edx\n\t"
- "andl $0x01010100,%%edx\n\t"
- "jnz " LF(21) "\n\t"
- "xorl %%ecx,%%edi\n\t"
- "movl %%edi,%%edx\n\t"
- "addl $0xfefefeff,%%edi\n\t"
- "jnc " LB(41) "\n\t"
- "xorl %%edx,%%edi\n\t"
- "notl %%edi\n\t"
- "andl $0x01010100,%%edi\n\t"
- "jnz " LB(31) "\n\t"
-
- "movl 8(%2),%%edx\n\t"
- "movl %%edx,%%edi\n\t"
- "addl $0xfefefeff,%%edx\n\t"
- "jnc " LF(22) "\n\t"
- "xorl %%edi,%%edx\n\t"
- "notl %%edx\n\t"
- "andl $0x01010100,%%edx\n\t"
- "jnz " LF(22) "\n\t"
- "xorl %%ecx,%%edi\n\t"
- "movl %%edi,%%edx\n\t"
- "addl $0xfefefeff,%%edi\n\t"
- "jnc " LB(42) "\n\t"
- "xorl %%edx,%%edi\n\t"
- "notl %%edi\n\t"
- "andl $0x01010100,%%edi\n\t"
- "jnz " LB(32) "\n\t"
-
- "movl 12(%2),%%edx\n\t"
- "movl %%edx,%%edi\n\t"
- "addl $0xfefefeff,%%edx\n\t"
- "jnc " LF(23) "\n\t"
- "xorl %%edi,%%edx\n\t"
- "notl %%edx\n\t"
- "andl $0x01010100,%%edx\n\t"
- "jnz " LF(23) "\n\t"
- "xorl %%ecx,%%edi\n\t"
- "movl %%edi,%%edx\n\t"
- "addl $0xfefefeff,%%edi\n\t"
- "jnc " LB(43) "\n\t"
- "xorl %%edx,%%edi\n\t"
- "notl %%edi\n\t"
- "andl $0x01010100,%%edi\n\t"
- "jz " LB(1) "\n\t"
- "jmp " LB(33) "\n"
-
- LL(23) "\taddl $4,%2\n\t" /* correct pointer increments */
- LL(22) "\taddl $4,%2\n\t"
- LL(21) "\taddl $4,%2\n\t"
-
- /* What remains to do is to test which byte the NULL char is and
- * whether the searched character appears in one of the bytes
- * before. A special case is that the searched byte maybe NULL.
- * In this case a pointer to the terminating NULL char has to be
- * returned. */
-
- LL(20) "\tmovl %%edi,%%edx\n\t"/* last dword to %edx */
-
- "cmpb %%cl,%%dl\n\t" /* is first byte the searched one ? */
- "jne " LF(24) "\n\t" /* no, branch */
- "movl %2,%0\n" /* remember position */
- LL(24) "\ttestb $0xff,%%dl\n\t"/* is NULL char ? */
- "jz " LF(2) "\n\t" /* yes, than end */
- "cmpb %%cl,%%dh\n\t"
- "jne " LF(25) "\n\t"
- "leal 1(%2),%0\n"
- LL(25) "\ttestb $0xff,%%dh\n\t"
- "jz " LF(2) "\n\t"
- "shrl $16,%%edx\n\t"
- "cmpb %%cl,%%dl\n\t"
- "jne " LF(26) "\n\t"
- "leal 2(%2),%0\n"
- LL(26) "\ttestb $0xff,%%dl\n\t"
- "jz " LF(2) "\n\t"
- "cmpb %%cl,%%dh\n\t"
- "jne " LF(2) "\n\t"
- "leal 3(%2),%0\n"
-
- LL(2)
- :"=a" (__res):"0" (0),"S" (str),"c" (ch):"cx","dx","di");
- return __res;
- }
-
- #include <gnu-stabs.h>
- #ifdef elf_alias
- elf_alias (strrchr, rindex);
- #endif
-