This is the mail archive of the libc-alpha@sources.redhat.com mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] improving the performance of isdigit, isdigit_l in usercode


Ulrich Drepper <drepper@redhat.com> writes:

> isdigit must only match the ASCII digits, nothing else.

With that in mind, here's a proposed performance improvement to
isdigit and isdigit_l for user programs, so that they have the same
optimization that libc itself does.  On x86 with GCC 3.4.0 -O2, this
shortened my isdigit test case by 2 bytes and 1 memory reference.

This uses a different way to express the same optimization, one that
works with any conforming C compiler.  The only tricky bit is the
"/ 1", which ensures that bogus calls like isdigit("") are properly
rejected by the compiler.

2004-06-29  Paul Eggert  <eggert@cs.ucla.edu>

	* ctype/ctype.h (isdigit, __isdigit_l): Avoid a memory access
	by subtracting '0' and then using unsigned int comparison against 9.
        * include/ctype.h (isdigit, isdigit_l, __isdigit_l): Remove;
	no longer needed due to the above change.

diff -pru libc/ctype/ctype.h libc-ctype/ctype/ctype.h
--- libc/ctype/ctype.h	2002-09-02 00:08:54 -0700
+++ libc-ctype/ctype/ctype.h	2004-06-29 13:30:02 -0700
@@ -173,7 +173,6 @@ __exctype (_tolower);
 # define isalnum(c)	__isctype((c), _ISalnum)
 # define isalpha(c)	__isctype((c), _ISalpha)
 # define iscntrl(c)	__isctype((c), _IScntrl)
-# define isdigit(c)	__isctype((c), _ISdigit)
 # define islower(c)	__isctype((c), _ISlower)
 # define isgraph(c)	__isctype((c), _ISgraph)
 # define isprint(c)	__isctype((c), _ISprint)
@@ -182,6 +181,12 @@ __exctype (_tolower);
 # define isupper(c)	__isctype((c), _ISupper)
 # define isxdigit(c)	__isctype((c), _ISxdigit)
 
+/* The C Standard says that isdigit must match only the decimal digits.
+   Hence isdigit must match only '0' through '9', and nothing else.
+   Check this without a memory access.
+   The '/ 1' generates a diagnostic whenever the C Standard requires one.  */
+# define isdigit(c)	(((unsigned int) ((c) / 1) - '0') <= 9)
+
 # ifdef __USE_ISOC99
 #  define isblank(c)	__isctype((c), _ISblank)
 # endif
@@ -281,7 +286,6 @@ extern int toupper_l (int __c, __locale_
 #  define __isalnum_l(c,l)	__isctype_l((c), _ISalnum, (l))
 #  define __isalpha_l(c,l)	__isctype_l((c), _ISalpha, (l))
 #  define __iscntrl_l(c,l)	__isctype_l((c), _IScntrl, (l))
-#  define __isdigit_l(c,l)	__isctype_l((c), _ISdigit, (l))
 #  define __islower_l(c,l)	__isctype_l((c), _ISlower, (l))
 #  define __isgraph_l(c,l)	__isctype_l((c), _ISgraph, (l))
 #  define __isprint_l(c,l)	__isctype_l((c), _ISprint, (l))
@@ -290,6 +294,9 @@ extern int toupper_l (int __c, __locale_
 #  define __isupper_l(c,l)	__isctype_l((c), _ISupper, (l))
 #  define __isxdigit_l(c,l)	__isctype_l((c), _ISxdigit, (l))
 
+/* See isdigit above.  */
+#  define __isdigit_l(c,l)	(((unsigned int) ((c) / 1) - '0') <= 9)
+
 #  define __isblank_l(c,l)	__isctype_l((c), _ISblank, (l))
 
 #  if defined __USE_SVID || defined __USE_MISC || defined __USE_XOPEN
diff -pru libc/include/ctype.h libc-ctype/include/ctype.h
--- libc/include/ctype.h	2004-03-18 16:39:03 -0800
+++ libc-ctype/include/ctype.h	2004-06-29 13:18:38 -0700
@@ -68,15 +68,4 @@ __ctype_tolower_loc (void)
 
 # include <ctype/ctype.h>
 
-# if !defined __NO_CTYPE && !defined NOT_IN_libc
-/* The spec says that isdigit must only match the decimal digits.  We
-   can check this without a memory access.  */
-#  undef isdigit
-#  define isdigit(c) ({ int __c = (c); __c >= '0' && __c <= '9'; })
-#  undef isdigit_l
-#  define isdigit_l(c, l) ({ int __c = (c); __c >= '0' && __c <= '9'; })
-#  undef __isdigit_l
-#  define __isdigit_l(c, l) ({ int __c = (c); __c >= '0' && __c <= '9'; })
-# endif
-
 #endif /* ctype.h */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]