]> sourceware.org Git - newlib-cygwin.git/commitdiff
Optimize the generic strchr.
authorEric Blake <eblake@redhat.com>
Thu, 22 May 2008 02:31:46 +0000 (02:31 +0000)
committerEric Blake <eblake@redhat.com>
Thu, 22 May 2008 02:31:46 +0000 (02:31 +0000)
* libc/string/strchr.c (strchr) [!__OPTIMIZE_SIZE__]: Pre-align
data so unaligned searches aren't penalized.  Special-case
searching for 0.

newlib/ChangeLog
newlib/libc/string/strchr.c

index 35a80e2662dd9ffb2dbefb93d80d3fc48580f883..5876f26325a95ce13f6381035a1c4416661b50d7 100644 (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>
 
index 60b0fde8e6461e0eea6c21afb7b49366a239771e..e921b5db7179c5f01f6be15190aec9779ec9bb92 100644 (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)
+#if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__)
+  unsigned long mask,j;
+  unsigned long *aligned_addr;
+
+  /* Special case for finding 0.  */
+  if (!c)
     {
-      s++;
+      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++;
+      /* Found the end of string.  */
+      s = (const unsigned char *) aligned_addr;
+      while (*s)
+        s++;
+      return (char *) s;
     }
 
-  if (*s != c)
+  /* All other bytes.  Align the pointer, then search a long at a time.  */
+  while (UNALIGNED (s))
     {
-      s = NULL;
+      if (!*s)
+        return NULL;
+      if (*s == c)
+        return (char *) s;
+      s++;
     }
 
-  return (char *) s;
-#else
-  unsigned char c = (unsigned char)i;
-  unsigned long mask,j;
-  unsigned long *aligned_addr;
+  mask = c;
+  for (j = 8; j < LBLOCKSIZE * 8; j <<= 1)
+    mask = (mask << j) | mask;
 
-  if (!UNALIGNED (s))
-    {
-      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))
+    aligned_addr++;
 
-      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.  */
 
-      /* 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;
 
-      s = (unsigned char*)aligned_addr;
-    }
+#endif /* not PREFER_SIZE_OVER_SPEED */
 
   while (*s && *s != c)
-      s++;
+    s++;
   if (*s == c)
     return (char *)s;
   return NULL;
-#endif /* not PREFER_SIZE_OVER_SPEED */
 }
This page took 0.049138 seconds and 5 git commands to generate.