Add string inlines to string-inlines.c

Message ID AM3PR08MB00882AF1EBD6C5F53B829CE583F40@AM3PR08MB0088.eurprd08.prod.outlook.com
State Superseded
Headers

Commit Message

Wilco Dijkstra Jan. 6, 2016, 4:33 p.m. UTC
  This patch adds all remaining string/bits/string2.h inlines to string-inlines.c. Modify string2.h to no longer support being included into string-inlines.c. This enables further patches to remove inlines from string2.h without worrying about ABI implications. My plan is to improve the underlying generic string functions first and remove any inlines that are beaten by the non-inline version. Calling the non-inlined version also enables further improvements for special cases in future GLIBCs rather than hard coding a slow byte loop in lots of binaries. I have patches in progress for strcspn, strpbrk and strcpn which show it is easy to beat the inlines for all but really small inputs. 

Built and tested on AArch64. OK for GLIBC 2.23? (note this depends on https://sourceware.org/ml/libc-alpha/2015-12/msg00386.html)

ChangeLog:
2016-01-06  Wilco Dijkstra  <wdijkstr@arm.com>

	* string/string-inlines.c: Don't inline <bits/string2.h>
	(__strcspn_c1): Add function from <bits/string2.h>.
	(__strcspn_c2): Likewise.
	(__strcspn_c3): Likewise.
	(__strspn_c1): Likewise.
	(__strspn_c2): Likewise.
	(__strspn_c3): Likewise.
	(__strpbrk_c2): Likewise.
	(__strpbrk_c3): Likewise.
	(__strtok_r_1c): Likewise.
	(__strpbrk_c1): Likewise.
	(__strsep_1c): Likewise.
	(__strsep_2c): Likewise.
	(__strsep_3c): Likewise.
	* string/bits/string2.h: Remove _FORCE_INLINES support.
	(strchr): Remove pre-GCC3.2 support.
	(__strcmp_cc): Remove unused define.
  

Patch

diff --git a/string/bits/string2.h b/string/bits/string2.h
index cff529728b7d31f207c6c43aedae4a1b0df4b4b4..e18c67530ec78338c9591015f3d95c785de54726 100644
--- a/string/bits/string2.h
+++ b/string/bits/string2.h
@@ -21,6 +21,10 @@ 
 # error "Never use <bits/string2.h> directly; include <string.h> instead."
 #endif
 
+#ifdef _FORCE_INLINES
+# error "This header no longer supports _FORCE_INLINES."
+#endif
+
 #ifndef __NO_STRING_INLINES
 
 /* Unlike the definitions in the header <bits/string.h> the
@@ -67,7 +71,7 @@ 
 /* Copy N bytes from SRC to DEST, returning pointer to byte following the
    last copied.  */
 #ifdef __USE_GNU
-# if !defined _HAVE_STRING_ARCH_mempcpy || defined _FORCE_INLINES
+# if !defined _HAVE_STRING_ARCH_mempcpy
 #  ifndef _HAVE_STRING_ARCH_mempcpy
 #   if __GNUC_PREREQ (3, 4)
 #    define __mempcpy(dest, src, n) __builtin_mempcpy (dest, src, n)
@@ -88,18 +92,13 @@  extern void *__rawmemchr (const void *__s, int __c);
 		  && (c) == '\0'					      \
 		  ? (char *) __rawmemchr (s, c)				      \
 		  : __builtin_strchr (s, c)))
-# else
-#  define strchr(s, c) \
-  (__extension__ (__builtin_constant_p (c) && (c) == '\0'		      \
-		  ? (char *) __rawmemchr (s, c)				      \
-		  : strchr (s, c)))
 # endif
 #endif
 
 
 /* Copy SRC to DEST, returning pointer to final NUL byte.  */
 #ifdef __USE_GNU
-# if !defined _HAVE_STRING_ARCH_stpcpy || defined _FORCE_INLINES
+# if !defined _HAVE_STRING_ARCH_stpcpy
 #  ifndef _HAVE_STRING_ARCH_stpcpy
 #   if __GNUC_PREREQ (3, 4)
 #    define __stpcpy(dest, src) __builtin_stpcpy (dest, src)
@@ -157,37 +156,10 @@  extern void *__rawmemchr (const void *__s, int __c);
 	    && (__s2_len = strlen (s2), __s2_len < 4)			      \
 	    ? (__builtin_constant_p (s1) && __string2_1bptr_p (s1)	      \
 	       ? __builtin_strcmp (s1, s2)				      \
-	       : __strcmp_gc (s1, s2, __s2_len))			      \
+	       : (- __strcmp_cg (s2, s1, __s2_len)))			      \
 	    : __builtin_strcmp (s1, s2)))); })
 # endif
 
-# define __strcmp_cc(s1, s2, l) \
-  (__extension__ ({ int __result =					      \
-		      (((const unsigned char *) (const char *) (s1))[0]	      \
-		       - ((const unsigned char *) (const char *)(s2))[0]);    \
-		    if (l > 0 && __result == 0)				      \
-		      {							      \
-			__result = (((const unsigned char *)		      \
-				     (const char *) (s1))[1]		      \
-				    - ((const unsigned char *)		      \
-				       (const char *) (s2))[1]);	      \
-			if (l > 1 && __result == 0)			      \
-			  {						      \
-			    __result =					      \
-			      (((const unsigned char *)			      \
-				(const char *) (s1))[2]			      \
-			       - ((const unsigned char *)		      \
-				  (const char *) (s2))[2]);		      \
-			    if (l > 2 && __result == 0)			      \
-			      __result =				      \
-				(((const unsigned char *)		      \
-				  (const char *) (s1))[3]		      \
-				 - ((const unsigned char *)		      \
-				    (const char *) (s2))[3]);		      \
-			  }						      \
-		      }							      \
-		    __result; }))
-
 # define __strcmp_cg(s1, s2, l1) \
   (__extension__ ({ const unsigned char *__s2 =				      \
 		      (const unsigned char *) (const char *) (s2);	      \
@@ -210,7 +182,6 @@  extern void *__rawmemchr (const void *__s, int __c);
 		      }							      \
 		    __result; }))
 
-# define __strcmp_gc(s1, s2, l2) (- __strcmp_cg (s2, s1, l2))
 #endif
 
 
@@ -228,7 +199,7 @@  extern void *__rawmemchr (const void *__s, int __c);
 
 /* Return the length of the initial segment of S which
    consists entirely of characters not in REJECT.  */
-#if !defined _HAVE_STRING_ARCH_strcspn || defined _FORCE_INLINES
+#if !defined _HAVE_STRING_ARCH_strcspn
 # ifndef _HAVE_STRING_ARCH_strcspn
 #  if __GNUC_PREREQ (3, 2)
 #   define strcspn(s, reject) \
@@ -289,7 +260,7 @@  __strcspn_c3 (const char *__s, int __reject1, int __reject2,
 
 /* Return the length of the initial segment of S which
    consists entirely of characters in ACCEPT.  */
-#if !defined _HAVE_STRING_ARCH_strspn || defined _FORCE_INLINES
+#if !defined _HAVE_STRING_ARCH_strspn
 # ifndef _HAVE_STRING_ARCH_strspn
 #  if __GNUC_PREREQ (3, 2)
 #   define strspn(s, accept) \
@@ -350,7 +321,7 @@  __strspn_c3 (const char *__s, int __accept1, int __accept2, int __accept3)
 
 
 /* Find the first occurrence in S of any character in ACCEPT.  */
-#if !defined _HAVE_STRING_ARCH_strpbrk || defined _FORCE_INLINES
+#if !defined _HAVE_STRING_ARCH_strpbrk
 # ifndef _HAVE_STRING_ARCH_strpbrk
 #  if __GNUC_PREREQ (3, 2)
 #   define strpbrk(s, accept) \
@@ -397,7 +368,7 @@  __strpbrk_c3 (const char *__s, int __accept1, int __accept2, int __accept3)
 #endif
 
 
-#if !defined _HAVE_STRING_ARCH_strtok_r || defined _FORCE_INLINES
+#if !defined _HAVE_STRING_ARCH_strtok_r
 # ifndef _HAVE_STRING_ARCH_strtok_r
 #  define __strtok_r(s, sep, nextp) \
   (__extension__ (__builtin_constant_p (sep) && __string2_1bptr_p (sep)	      \
@@ -436,7 +407,7 @@  __strtok_r_1c (char *__s, char __sep, char **__nextp)
 #endif
 
 
-#if !defined _HAVE_STRING_ARCH_strsep || defined _FORCE_INLINES
+#if !defined _HAVE_STRING_ARCH_strsep
 # ifndef _HAVE_STRING_ARCH_strsep
 
 extern char *__strsep_g (char **__stringp, const char *__delim);
@@ -585,8 +556,6 @@  extern char *__strndup (const char *__string, size_t __n)
 
 #endif /* Use misc. or use GNU.  */
 
-#ifndef _FORCE_INLINES
-# undef __STRING_INLINE
-#endif
+#undef __STRING_INLINE
 
 #endif /* No string inlines.  */
diff --git a/string/string-inlines.c b/string/string-inlines.c
index 4e91329df22b9c604fff1e833212a8b778c36390..a3c1d27f91d025c8bc4b3d9b8ed5f496562e024e 100644
--- a/string/string-inlines.c
+++ b/string/string-inlines.c
@@ -15,9 +15,10 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-/*  <bits/string.h> and <bits/string2.h> declare some extern inline
-    functions.  These functions are declared additionally here if
-    inlining is not possible.  */
+/*  <bits/string.h> and <bits/string2.h> declare various extern inline
+    functions.  These functions are defined here as an external ABI in
+    case they are not inlined.  Even if these functions are removed
+    from the string headers, they must still be defined here.  */
 
 #undef __USE_STRING_INLINES
 #define __USE_STRING_INLINES
@@ -31,7 +32,14 @@ 
 
 #undef __NO_INLINE__
 #include <bits/string.h>
-#include <bits/string2.h>
+
+#ifndef __STRING_INLINE
+# ifdef __cplusplus
+#  define __STRING_INLINE inline
+# else
+#  define __STRING_INLINE __extern_inline
+# endif
+#endif
 
 /* These are a few types we need for the optimizations if we cannot
    use unaligned memory accesses.  */
@@ -378,3 +386,167 @@  __stpcpy_small (char *__dest,
   return __dest + __srclen - 1;
 }
 #endif
+
+__STRING_INLINE size_t
+__strcspn_c1 (const char *__s, int __reject)
+{
+  size_t __result = 0;
+  while (__s[__result] != '\0' && __s[__result] != __reject)
+    ++__result;
+  return __result;
+}
+
+__STRING_INLINE size_t
+__strcspn_c2 (const char *__s, int __reject1, int __reject2)
+{
+  size_t __result = 0;
+  while (__s[__result] != '\0' && __s[__result] != __reject1
+	 && __s[__result] != __reject2)
+    ++__result;
+  return __result;
+}
+
+__STRING_INLINE size_t
+__strcspn_c3 (const char *__s, int __reject1, int __reject2,
+	      int __reject3)
+{
+  size_t __result = 0;
+  while (__s[__result] != '\0' && __s[__result] != __reject1
+	 && __s[__result] != __reject2 && __s[__result] != __reject3)
+    ++__result;
+  return __result;
+}
+
+__STRING_INLINE size_t
+__strspn_c1 (const char *__s, int __accept)
+{
+  size_t __result = 0;
+  /* Please note that __accept never can be '\0'.  */
+  while (__s[__result] == __accept)
+    ++__result;
+  return __result;
+}
+
+__STRING_INLINE size_t
+__strspn_c2 (const char *__s, int __accept1, int __accept2)
+{
+  size_t __result = 0;
+  /* Please note that __accept1 and __accept2 never can be '\0'.  */
+  while (__s[__result] == __accept1 || __s[__result] == __accept2)
+    ++__result;
+  return __result;
+}
+
+__STRING_INLINE size_t
+__strspn_c3 (const char *__s, int __accept1, int __accept2, int __accept3)
+{
+  size_t __result = 0;
+  /* Please note that __accept1 to __accept3 never can be '\0'.  */
+  while (__s[__result] == __accept1 || __s[__result] == __accept2
+	 || __s[__result] == __accept3)
+    ++__result;
+  return __result;
+}
+
+__STRING_INLINE char *
+__strpbrk_c2 (const char *__s, int __accept1, int __accept2)
+{
+  /* Please note that __accept1 and __accept2 never can be '\0'.  */
+  while (*__s != '\0' && *__s != __accept1 && *__s != __accept2)
+    ++__s;
+  return *__s == '\0' ? NULL : (char *) (size_t) __s;
+}
+
+__STRING_INLINE char *
+__strpbrk_c3 (const char *__s, int __accept1, int __accept2, int __accept3)
+{
+  /* Please note that __accept1 to __accept3 never can be '\0'.  */
+  while (*__s != '\0' && *__s != __accept1 && *__s != __accept2
+	 && *__s != __accept3)
+    ++__s;
+  return *__s == '\0' ? NULL : (char *) (size_t) __s;
+}
+
+__STRING_INLINE char *
+__strtok_r_1c (char *__s, char __sep, char **__nextp)
+{
+  char *__result;
+  if (__s == NULL)
+    __s = *__nextp;
+  while (*__s == __sep)
+    ++__s;
+  __result = NULL;
+  if (*__s != '\0')
+    {
+      __result = __s++;
+      while (*__s != '\0')
+	if (*__s++ == __sep)
+	  {
+	    __s[-1] = '\0';
+	    break;
+	  }
+    }
+  *__nextp = __s;
+  return __result;
+}
+
+__STRING_INLINE char *
+__strsep_1c (char **__s, char __reject)
+{
+  char *__retval = *__s;
+  if (__retval != NULL && (*__s = strchr (__retval, __reject)) != NULL)
+    *(*__s)++ = '\0';
+  return __retval;
+}
+
+__STRING_INLINE char *
+__strsep_2c (char **__s, char __reject1, char __reject2)
+{
+  char *__retval = *__s;
+  if (__retval != NULL)
+    {
+      char *__cp = __retval;
+      while (1)
+	{
+	  if (*__cp == '\0')
+	    {
+	      __cp = NULL;
+	  break;
+	    }
+	  if (*__cp == __reject1 || *__cp == __reject2)
+	    {
+	      *__cp++ = '\0';
+	      break;
+	    }
+	  ++__cp;
+	}
+      *__s = __cp;
+    }
+  return __retval;
+}
+
+__STRING_INLINE char *
+__strsep_3c (char **__s, char __reject1, char __reject2, char __reject3)
+{
+  char *__retval = *__s;
+  if (__retval != NULL)
+    {
+      char *__cp = __retval;
+      while (1)
+	{
+	  if (*__cp == '\0')
+	    {
+	      __cp = NULL;
+	  break;
+	    }
+	  if (*__cp == __reject1 || *__cp == __reject2 || *__cp == __reject3)
+	    {
+	      *__cp++ = '\0';
+	      break;
+	    }
+	  ++__cp;
+	}
+      *__s = __cp;
+    }
+  return __retval;
+}