Optimize the generic strchr.

* libc/string/strchr.c (strchr) [!__OPTIMIZE_SIZE__]: Pre-align
data so unaligned searches aren't penalized.  Special-case
searching for 0.
This commit is contained in:
Eric Blake 2008-05-22 02:31:46 +00:00
parent 0b99028af4
commit ae47b14a12
2 changed files with 54 additions and 33 deletions

View File

@ -1,8 +1,14 @@
2008-05-21 Eric Blake <ebb9@byu.net>
Optimize the generic strchr.
* libc/string/strchr.c (strchr) [!__OPTIMIZE_SIZE__]: Pre-align
data so unaligned searches aren't penalized. Special-case
searching for 0.
Optimize strchr for x86.
* libc/machine/i386/strchr.S (strchr): Pre-align data so unaligned
searches aren't penalized. Special-case searching for 0.
* libc/machine/i386/strchr.S (strchr) [!__OPTIMIZE_SIZE__]:
Pre-align data so unaligned searches aren't penalized.
Special-case searching for 0.
2008-05-20 Nick Clifton <nickc@redhat.com>

View File

@ -53,7 +53,7 @@ QUICKREF
#endif
#endif
/* DETECTCHAR returns nonzero if (long)X contains the byte used
/* DETECTCHAR returns nonzero if (long)X contains the byte used
to fill (long)MASK. */
#define DETECTCHAR(X,MASK) (DETECTNULL(X ^ MASK))
@ -63,46 +63,61 @@ _DEFUN (strchr, (s1, i),
int i)
{
_CONST unsigned char *s = (_CONST unsigned char *)s1;
#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
unsigned char c = (unsigned int)i;
unsigned char c = i;
while (*s && *s != c)
{
s++;
}
if (*s != c)
{
s = NULL;
}
return (char *) s;
#else
unsigned char c = (unsigned char)i;
#if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__)
unsigned long mask,j;
unsigned long *aligned_addr;
if (!UNALIGNED (s))
/* Special case for finding 0. */
if (!c)
{
mask = 0;
for (j = 0; j < LBLOCKSIZE; j++)
mask = (mask << 8) | c;
aligned_addr = (unsigned long*)s;
while (!DETECTNULL (*aligned_addr) && !DETECTCHAR (*aligned_addr, mask))
while (UNALIGNED (s))
{
if (!*s)
return (char *) s;
s++;
}
/* Operate a word at a time. */
aligned_addr = (unsigned long *) s;
while (!DETECTNULL (*aligned_addr))
aligned_addr++;
/* The block of bytes currently pointed to by aligned_addr
contains either a null or the target char, or both. We
catch it using the bytewise search. */
s = (unsigned char*)aligned_addr;
/* Found the end of string. */
s = (const unsigned char *) aligned_addr;
while (*s)
s++;
return (char *) s;
}
while (*s && *s != c)
/* All other bytes. Align the pointer, then search a long at a time. */
while (UNALIGNED (s))
{
if (!*s)
return NULL;
if (*s == c)
return (char *) s;
s++;
}
mask = c;
for (j = 8; j < LBLOCKSIZE * 8; j <<= 1)
mask = (mask << j) | mask;
aligned_addr = (unsigned long *) s;
while (!DETECTNULL (*aligned_addr) && !DETECTCHAR (*aligned_addr, mask))
aligned_addr++;
/* The block of bytes currently pointed to by aligned_addr
contains either a null or the target char, or both. We
catch it using the bytewise search. */
s = (unsigned char *) aligned_addr;
#endif /* not PREFER_SIZE_OVER_SPEED */
while (*s && *s != c)
s++;
if (*s == c)
return (char *)s;
return NULL;
#endif /* not PREFER_SIZE_OVER_SPEED */
}