[PATCH v2] Add __pure2 to __locale_ctype_ptr(_l)
Craig Howland
howland@LGSInnovations.com
Wed Nov 1 04:53:00 GMT 2017
On 10/31/2017 09:34 AM, Wilco Dijkstra wrote:
> The newlib ctype functons are extremely inefficient due to repeatedly
> calling __locale_ctype_ptr for every single use of a ctype macro, even
> in a tight loop. Improve this by adding the missing __pure2 attribute so
> the pointer can be cached just like in GLIBC, resulting in > 2x speedup
> in loops.
>
> I haven't looked in detail at the implementation, but in general you don't
> need a function call - a variable, thread-local if required, would be simpler,
> even faster and cache automatically.
>
> ChangeLog:
> 2017-10-31 Wilco Dijkstra <wdijkstr@arm.com>
>
> * newlib/libc/include/ctype.h (__locale_ctype_ptr): Add __pure2.
> (__locale_ctype_ptr_l): Likewise.
> --
> diff --git a/newlib/libc/include/ctype.h b/newlib/libc/include/ctype.h
> index 06458cbda47abe1294ebe226a16981fc9f38254d..a85e157a9019132fd7f9eceba690dcde07be2f3c 100644
> --- a/newlib/libc/include/ctype.h
> +++ b/newlib/libc/include/ctype.h
> @@ -66,7 +66,7 @@ extern int toascii_l (int __c, locale_t __l);
> #define _X 0100
> #define _B 0200
>
> -const char *__locale_ctype_ptr (void);
> +const char *__locale_ctype_ptr (void) __pure2;
> # define __CTYPE_PTR (__locale_ctype_ptr ())
>
> #ifndef __cplusplus
> @@ -100,7 +100,7 @@ const char *__locale_ctype_ptr (void);
> #endif
>
> #if __POSIX_VISIBLE >= 200809
> -const char *__locale_ctype_ptr_l (locale_t);
> +const char *__locale_ctype_ptr_l (locale_t) __pure2;
> #define __ctype_lookup_l(__c,__l) ((__locale_ctype_ptr_l(__l)+sizeof(""[__c]))[(int)(__c)])
>
> #define isalpha_l(__c,__l) (__ctype_lookup_l(__c,__l)&(_U|_L))
    The __pure2 attribute really is (maps to) the "const" attribute. The GCC
"const" attribute appears to not be allowed in this case. Quoting from the GCC
4.7.2 manual,
"Many functions do not examine any values except their arguments, and have
no effects except the return value. Basically this is just slightly more strict
class than the pure attribute below, since function is not allowed to read global
memory.
Note that a function that has pointer arguments and examines the data pointed
to must not be declared const."
    __locale_ctype_ptr() reads global memory. __locale_ctype_ptr_l() has a
pointer argument and does examine the data pointed to (in that it returns a
member from the given structure pointer).
    The GCC "pure" attribute is less strict, but even that does not appear to
be appropriate/safe. "Many functions have no effects except the return value
and their return value
depends only on the parameters and/or global variables. Such a function can
be subject to common subexpression elimination and loop optimization just as
an arithmetic operator would be."Â The problem is that a pointer is being used,
not a plain variable. So
for(i=0; i<strlen(str); i++)Â { if(isalpha(str[i])) putchar(str[i]); }
could be safe, but
for(i=0; i<strlen(str); i++)Â {
   if(isalpha(str[i])) putchar(str[i]);
   else setlocale(...); }
would probably not be. This is a contrived example, but there is no way for the
compiler to know the the locale has been changed since the pointer is still the
same, being the underlying member which gets edited by the set.
    I think it would be safe when if !defined(_MB_CAPABLE), since the locale
cannot be changed then, but not in the general case which is being changed by
the proposed ctype.h edit. That is, I think the patch can probably be OK if it
is enhanced to be conditional for _MB_CAPABLE. (It would be "dangerous" in the
sense that it requires linkage between the header and the specific
implementation of _setlocale_r() in a different file, but some comments can help
with that.)
            Craig
More information about the Newlib
mailing list