This is the mail archive of the
libc-alpha@sources.redhat.com
mailing list for the glibc project.
[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 */