diff --git a/LICENSE b/LICENSE index c51bac1eedb..0ea7752a492 100644 --- a/LICENSE +++ b/LICENSE @@ -8664,3 +8664,34 @@ drivers/i3c/internals.h Author: Boris Brezillon SPDX-License-Identifier: Apache-2.0 + +libs/libc/string/lib_memccpy.c +libs/libc/string/lib_memchr.c +libs/libc/string/lib_memcmp.c +libs/libc/string/lib_memcpy.c +libs/libc/string/lib_memrchr.c +libs/libc/string/lib_stpcpy.c +libs/libc/string/lib_stpncpy.c +libs/libc/string/lib_strcat.c +libs/libc/string/lib_strchr.c +libs/libc/string/lib_strchrnul.c +libs/libc/string/lib_strcmp.c +libs/libc/string/lib_strcpy.c +libs/libc/string/lib_strlen.c +libs/libc/string/lib_strncmp.c +libs/libc/string/lib_strncpy.c +libs/libc/string/lib_strrchr.c +====================== + +Copyright (c) 1994-2009 Red Hat, Inc. All rights reserved. + +This copyrighted material is made available to anyone wishing to use, +modify, copy, or redistribute it subject to the terms and conditions +of the BSD License. This program is distributed in the hope that +it will be useful, but WITHOUT ANY WARRANTY expressed or implied, +including the implied warranties of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. A copy of this license is available at +http://www.opensource.org/licenses. Any Red Hat trademarks that are +incorporated in the source code or documentation are not subject to +the BSD License and may only be used or replicated with the express +permission of Red Hat, Inc. diff --git a/libs/libc/string/Kconfig b/libs/libc/string/Kconfig index e7180cddffc..c8e0630e596 100644 --- a/libs/libc/string/Kconfig +++ b/libs/libc/string/Kconfig @@ -36,6 +36,13 @@ config LIBC_STRERROR_ERRNUM for unknown errors like "Unknown error 101". Default enabled when LIBC_STRERROR is not selected. +config LIBC_STRING_OPTIMIZE + bool "optimized string function" + depends on ALLOW_BSD_COMPONENTS + default y + --help-- + Use optimized string function implementation based on newlib. + config LIBC_PERROR_STDOUT bool "perror() to stdout" default n diff --git a/libs/libc/string/lib_memccpy.c b/libs/libc/string/lib_memccpy.c index 283e5650cf2..3cb34c0d2d9 100644 --- a/libs/libc/string/lib_memccpy.c +++ b/libs/libc/string/lib_memccpy.c @@ -28,6 +28,36 @@ #include #include +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_LIBC_STRING_OPTIMIZE +/* Nonzero if either x or y is not aligned on a "long" boundary. */ + +#define UNALIGNED(x, y) \ + (((long)(uintptr_t)(x) & (sizeof(long) - 1)) | ((long)(uintptr_t)(y) & (sizeof(long) - 1))) + +/* How many bytes are copied each iteration of the word copy loop. */ + +#define LITTLEBLOCKSIZE (sizeof(long)) + +/* Threshhold for punting to the byte copier. */ + +#define TOO_SMALL(len) ((len) < LITTLEBLOCKSIZE) + +/* Macros for detecting endchar */ + +#if LONG_MAX == 2147483647 +# define DETECTNULL(x) (((x) - 0x01010101) & ~(x) & 0x80808080) +#elif LONG_MAX == 9223372036854775807 +/* Nonzero if x (a long int) contains a NULL byte. */ + +# define DETECTNULL(x) (((x) - 0x0101010101010101) & ~(x) & 0x8080808080808080) +#endif + +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -51,6 +81,71 @@ #undef memccpy /* See mm/README.txt */ FAR void *memccpy(FAR void *s1, FAR const void *s2, int c, size_t n) { +#ifdef CONFIG_LIBC_STRING_OPTIMIZE + FAR void *ptr = NULL; + FAR unsigned char *pout = (FAR unsigned char *)s1; + FAR const unsigned char *pin = (FAR const unsigned char *)s2; + FAR long *paligned_out; + FAR const long *paligned_in; + unsigned char endchar = c & 0xff; + + /* If the size is small, or either pin or pout is unaligned, + * then punt into the byte copy loop. This should be rare. + */ + + if (!TOO_SMALL(n) && !UNALIGNED(pin, pout)) + { + unsigned int i; + unsigned long mask = 0; + + paligned_out = (FAR long *)pout; + paligned_in = (FAR long *)pin; + + /* The fast code reads the ASCII one word at a time and only + * performs the bytewise search on word-sized segments if they + * contain the search character, which is detected by XORing + * the word-sized segment with a word-sized block of the search + * character and then detecting for the presence of NULL in the + * result. + */ + + for (i = 0; i < LITTLEBLOCKSIZE; i++) + { + mask = (mask << 8) + endchar; + } + + /* Copy one long word at a time if possible. */ + + while (n >= LITTLEBLOCKSIZE) + { + unsigned long buffer = (unsigned long)(*paligned_in); + buffer ^= mask; + if (DETECTNULL(buffer)) + { + break; /* endchar is found, go byte by byte from here */ + } + + *paligned_out++ = *paligned_in++; + n -= LITTLEBLOCKSIZE; + } + + /* Pick up any residual with a byte copier. */ + + pout = (FAR unsigned char *)paligned_out; + pin = (FAR unsigned char *)paligned_in; + } + + while (n--) + { + if ((*pout++ = *pin++) == endchar) + { + ptr = pout; + break; + } + } + + return ptr; +#else FAR unsigned char *pout = (FAR unsigned char *)s1; FAR unsigned char *pin = (FAR unsigned char *)s2; @@ -75,4 +170,5 @@ FAR void *memccpy(FAR void *s1, FAR const void *s2, int c, size_t n) /* C was not found in the first n bytes of s2 */ return NULL; +#endif } diff --git a/libs/libc/string/lib_memchr.c b/libs/libc/string/lib_memchr.c index 2c24e3256f9..e651f21b673 100644 --- a/libs/libc/string/lib_memchr.c +++ b/libs/libc/string/lib_memchr.c @@ -30,6 +30,38 @@ #include "libc.h" +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_LIBC_STRING_OPTIMIZE + +#define UNALIGNED(x) ((long)(uintptr_t)(x) & (sizeof(long) - 1)) + +/* How many bytes are loaded each iteration of the word copy loop. */ + +#define LBLOCKSIZE (sizeof(long)) + +/* Threshhold for punting to the bytewise iterator. */ + +#define TOO_SMALL(len) ((len) < LBLOCKSIZE) + +#if LONG_MAX == 2147483647 +# define DETECTNULL(x) (((x) - 0x01010101) & ~(x) & 0x80808080) +#elif LONG_MAX == 9223372036854775807 +/* Nonzero if x (a long int) contains a NULL byte. */ + +# define DETECTNULL(x) (((x) - 0x0101010101010101) & ~(x) & 0x8080808080808080) +#endif + +/* DETECTCHAR returns nonzero if (long)x contains the byte used + * to fill (long)mask. + */ + +#define DETECTCHAR(x, mask) (DETECTNULL((x) ^ (mask))) + +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -52,6 +84,76 @@ #undef memchr /* See mm/README.txt */ FAR void *memchr(FAR const void *s, int c, size_t n) { +#ifdef CONFIG_LIBC_STRING_OPTIMIZE + FAR const unsigned char *p = (FAR const unsigned char *)s; + FAR unsigned long *asrc; + unsigned char d = c; + unsigned long mask; + unsigned int i; + + while (UNALIGNED(p)) + { + if (!n--) + { + return NULL; + } + + if (*p == d) + { + return (FAR void *)p; + } + + p++; + } + + if (!TOO_SMALL(n)) + { + /* If we get this far, we know that n is large and p is + * word-aligned. + * The fast code reads the source one word at a time and only + * performs the bytewise search on word-sized segments if they + * contain the search character, which is detected by XORing + * the word-sized segment with a word-sized block of the search + * character and then detecting for the presence of NUL in the + * result. + */ + + asrc = (FAR unsigned long *)p; + mask = d << 8 | d; + mask = mask << 16 | mask; + for (i = 32; i < LBLOCKSIZE * 8; i <<= 1) + { + mask = (mask << i) | mask; + } + + while (n >= LBLOCKSIZE) + { + if (DETECTCHAR(*asrc, mask)) + { + break; + } + + n -= LBLOCKSIZE; + asrc++; + } + + /* If there are fewer than LBLOCKSIZE characters left, + * then we resort to the bytewise loop. + */ + + p = (FAR unsigned char *)asrc; + } + + while (n--) + { + if (*p == d) + { + return (FAR void *)p; + } + + p++; + } +#else FAR const unsigned char *p = (FAR const unsigned char *)s; while (n--) @@ -63,6 +165,7 @@ FAR void *memchr(FAR const void *s, int c, size_t n) p++; } +#endif return NULL; } diff --git a/libs/libc/string/lib_memcmp.c b/libs/libc/string/lib_memcmp.c index 251cbf7bbad..4960a810fb5 100644 --- a/libs/libc/string/lib_memcmp.c +++ b/libs/libc/string/lib_memcmp.c @@ -30,6 +30,26 @@ #include "libc.h" +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_LIBC_STRING_OPTIMIZE +/* Nonzero if either x or y is not aligned on a "long" boundary. */ + +#define UNALIGNED(x, y) \ + (((long)(uintptr_t)(x) & (sizeof(long) - 1)) | ((long)(uintptr_t)(y) & (sizeof(long) - 1))) + +/* How many bytes are copied each iteration of the word copy loop. */ + +#define LBLOCKSIZE (sizeof(long)) + +/* Threshhold for punting to the byte copier. */ + +#define TOO_SMALL(len) ((len) < LBLOCKSIZE) + +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -39,6 +59,54 @@ no_builtin("memcmp") int memcmp(FAR const void *s1, FAR const void *s2, size_t n) { +#ifdef CONFIG_LIBC_STRING_OPTIMIZE + FAR unsigned char *p1 = (FAR unsigned char *)s1; + FAR unsigned char *p2 = (FAR unsigned char *)s2; + FAR unsigned long *a1; + FAR unsigned long *a2; + + /* If the size is too small, or either pointer is unaligned, + * then we punt to the byte compare loop. Hopefully this will + * not turn up in inner loops. + */ + + if (!TOO_SMALL(n) && !UNALIGNED(p1, p2)) + { + /* Otherwise, load and compare the blocks of memory one + * word at a time. + */ + + a1 = (FAR unsigned long *)p1; + a2 = (FAR unsigned long *)p2; + while (n >= LBLOCKSIZE) + { + if (*a1 != *a2) + { + break; + } + + a1++; + a2++; + n -= LBLOCKSIZE; + } + + /* check s mod LBLOCKSIZE remaining characters */ + + p1 = (FAR unsigned char *)a1; + p2 = (FAR unsigned char *)a2; + } + + while (n--) + { + if (*p1 != *p2) + { + return *p1 - *p2; + } + + p1++; + p2++; + } +#else FAR unsigned char *p1 = (FAR unsigned char *)s1; FAR unsigned char *p2 = (FAR unsigned char *)s2; @@ -56,6 +124,7 @@ int memcmp(FAR const void *s1, FAR const void *s2, size_t n) p1++; p2++; } +#endif return 0; } diff --git a/libs/libc/string/lib_memcpy.c b/libs/libc/string/lib_memcpy.c index c1ff6ae1e85..66367cb2f24 100644 --- a/libs/libc/string/lib_memcpy.c +++ b/libs/libc/string/lib_memcpy.c @@ -30,6 +30,30 @@ #include "libc.h" +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_LIBC_STRING_OPTIMIZE +/* Nonzero if either x or y is not aligned on a "long" boundary. */ + +#define UNALIGNED(x, y) \ + (((long)(uintptr_t)(x) & (sizeof(long) - 1)) | ((long)(uintptr_t)(y) & (sizeof(long) - 1))) + +/* How many bytes are copied each iteration of the 4X unrolled loop. */ + +#define BIGBLOCKSIZE (sizeof(long) << 2) + +/* How many bytes are copied each iteration of the word copy loop. */ + +#define LITTLEBLOCKSIZE (sizeof(long)) + +/* Threshhold for punting to the byte copier. */ + +#define TOO_SMALL(len) ((len) < BIGBLOCKSIZE) + +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -43,12 +67,58 @@ no_builtin("memcpy") FAR void *memcpy(FAR void *dest, FAR const void *src, size_t n) { +#ifdef CONFIG_LIBC_STRING_OPTIMIZE + FAR char *pout = dest; + FAR const char *pin = src; + FAR long *paligned_out; + FAR const long *paligned_in; + + /* If the size is small, or either pin or pout is unaligned, + * then punt into the byte copy loop. This should be rare. + */ + + if (!TOO_SMALL(n) && !UNALIGNED(pin, pout)) + { + paligned_out = (FAR long *)pout; + paligned_in = (FAR long *)pin; + + /* Copy 4X long words at a time if possible. */ + + while (n >= BIGBLOCKSIZE) + { + *paligned_out++ = *paligned_in++; + *paligned_out++ = *paligned_in++; + *paligned_out++ = *paligned_in++; + *paligned_out++ = *paligned_in++; + n -= BIGBLOCKSIZE; + } + + /* Copy one long word at a time if possible. */ + + while (n >= LITTLEBLOCKSIZE) + { + *paligned_out++ = *paligned_in++; + n -= LITTLEBLOCKSIZE; + } + + /* Pick up any residual with a byte copier. */ + + pout = (FAR char *)paligned_out; + pin = (FAR char *)paligned_in; + } + + while (n--) + { + *pout++ = *pin++; + } +#else FAR unsigned char *pout = (FAR unsigned char *)dest; FAR unsigned char *pin = (FAR unsigned char *)src; while (n-- > 0) { *pout++ = *pin++; } +#endif return dest; } diff --git a/libs/libc/string/lib_memmove.c b/libs/libc/string/lib_memmove.c index fd6d43383a6..7864902f024 100644 --- a/libs/libc/string/lib_memmove.c +++ b/libs/libc/string/lib_memmove.c @@ -44,13 +44,7 @@ FAR void *memmove(FAR void *dest, FAR const void *src, size_t count) if (dest <= src) { - tmp = (FAR char *) dest; - s = (FAR char *) src; - - while (count--) - { - *tmp++ = *s++; - } + memcpy(dest, src, count); } else { diff --git a/libs/libc/string/lib_memrchr.c b/libs/libc/string/lib_memrchr.c index 9a8f4a69d68..e8a07e7565a 100644 --- a/libs/libc/string/lib_memrchr.c +++ b/libs/libc/string/lib_memrchr.c @@ -28,6 +28,37 @@ #include +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_LIBC_STRING_OPTIMIZE +/* Nonzero if x is not aligned on a "long" boundary. */ + +#define UNALIGNED(x) ((long)(uintptr_t)((x) + 1) & (sizeof(long) - 1)) + +/* How many bytes are loaded each iteration of the word copy loop. */ + +#define LBLOCKSIZE (sizeof(long)) + +/* Threshhold for punting to the bytewise iterator. */ + +#define TOO_SMALL(len) ((len) < LBLOCKSIZE) + +/* Macros for detecting endchar */ + +#if LONG_MAX == 2147483647 +# define DETECTNULL(x) (((x) - 0x01010101) & ~(x) & 0x80808080) +#elif LONG_MAX == 9223372036854775807 +/* Nonzero if x (a long int) contains a NULL byte. */ + +# define DETECTNULL(x) (((x) - 0x0101010101010101) & ~(x) & 0x8080808080808080) +#endif + +#define DETECTCHAR(x, mask) (DETECTNULL((x) ^ (mask))) + +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -49,6 +80,77 @@ #undef memrchr /* See mm/README.txt */ FAR void *memrchr(FAR const void *s, int c, size_t n) { +#ifdef CONFIG_LIBC_STRING_OPTIMIZE + FAR const unsigned char *src0 = + (FAR const unsigned char *)s + n - 1; + FAR unsigned long *asrc; + unsigned char d = c; + unsigned long mask; + unsigned int i; + + while (UNALIGNED(src0)) + { + if (!n--) + { + return NULL; + } + + if (*src0 == d) + { + return (FAR void *)src0; + } + + src0--; + } + + if (!TOO_SMALL(n)) + { + /* If we get this far, we know that n is large and src0 is + * word-aligned. + * The fast code reads the source one word at a time and only + * performs the bytewise search on word-sized segments if they + * contain the search character, which is detected by XORing + * the word-sized segment with a word-sized block of the search + * character and then detecting for the presence of NUL in the + * result. + */ + + asrc = (FAR unsigned long *)(src0 - LBLOCKSIZE + 1); + mask = d << 8 | d; + mask = mask << 16 | mask; + for (i = 32; i < LBLOCKSIZE * 8; i <<= 1) + { + mask = (mask << i) | mask; + } + + while (n >= LBLOCKSIZE) + { + if (DETECTCHAR(*asrc, mask)) + { + break; + } + + n -= LBLOCKSIZE; + asrc--; + } + + /* If there are fewer than LBLOCKSIZE characters left, + * then we resort to the bytewise loop. + */ + + src0 = (FAR unsigned char *)asrc + LBLOCKSIZE - 1; + } + + while (n--) + { + if (*src0 == d) + { + return (FAR void *)src0; + } + + src0--; + } +#else FAR const unsigned char *p = (FAR const unsigned char *)s + n; while (n--) @@ -58,6 +160,7 @@ FAR void *memrchr(FAR const void *s, int c, size_t n) return (FAR void *)p; } } +#endif return NULL; } diff --git a/libs/libc/string/lib_stpcpy.c b/libs/libc/string/lib_stpcpy.c index ae1a9cbfb91..c9eff7ad14b 100644 --- a/libs/libc/string/lib_stpcpy.c +++ b/libs/libc/string/lib_stpcpy.c @@ -28,6 +28,28 @@ #include +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_LIBC_STRING_OPTIMIZE +/* Nonzero if either x or y is not aligned on a "long" boundary. */ + +#define UNALIGNED(x, y) \ + (((long)(uintptr_t)(x) & (sizeof(long) - 1)) | ((long)(uintptr_t)(y) & (sizeof(long) - 1))) + +/* Macros for detecting endchar */ + +#if LONG_MAX == 2147483647 +# define DETECTNULL(x) (((x) - 0x01010101) & ~(x) & 0x80808080) +#elif LONG_MAX == 9223372036854775807 +/* Nonzero if x (a long int) contains a NULL byte. */ + +# define DETECTNULL(x) (((x) - 0x0101010101010101) & ~(x) & 0x8080808080808080) +#endif + +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -49,7 +71,33 @@ #undef stpcpy /* See mm/README.txt */ FAR char *stpcpy(FAR char *dest, FAR const char *src) { +#ifdef CONFIG_LIBC_STRING_OPTIMIZE + FAR long *aligned_dst; + FAR const long *aligned_src; + + /* If src or dest is unaligned, then copy bytes. */ + + if (!UNALIGNED(src, dest)) + { + aligned_dst = (FAR long *)dest; + aligned_src = (FAR long *)src; + + /* src and dest are both "long int" aligned, try to do "long int" + * sized copies. + */ + + while (!DETECTNULL(*aligned_src)) + { + *aligned_dst++ = *aligned_src++; + } + + dest = (FAR char *)aligned_dst; + src = (FAR char *)aligned_src; + } +#endif + while ((*dest++ = *src++) != '\0'); + return --dest; } #endif diff --git a/libs/libc/string/lib_stpncpy.c b/libs/libc/string/lib_stpncpy.c index acbc1f3a459..b33c0b77d45 100644 --- a/libs/libc/string/lib_stpncpy.c +++ b/libs/libc/string/lib_stpncpy.c @@ -28,6 +28,34 @@ #include #include +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_LIBC_STRING_OPTIMIZE +/* Nonzero if either x or y is not aligned on a "long" boundary. */ + +#define UNALIGNED(x, y) \ + (((long)(uintptr_t)(x) & (sizeof(long) - 1)) | ((long)(uintptr_t)(y) & (sizeof(long) - 1))) + +/* How many bytes are loaded each iteration of the word copy loop. */ + +#define LBLOCKSIZE (sizeof(long)) + +/* Macros for detecting endchar */ + +#if LONG_MAX == 2147483647 +#define DETECTNULL(x) (((x) - 0x01010101) & ~(x) & 0x80808080) +#elif LONG_MAX == 9223372036854775807 +/* Nonzero if x (a long int) contains a NULL byte. */ + +#define DETECTNULL(x) (((x) - 0x0101010101010101) & ~(x) & 0x8080808080808080) +#endif + +#define TOO_SMALL(len) ((len) < sizeof(long)) + +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -59,6 +87,49 @@ #undef stpncpy /* See mm/README.txt */ FAR char *stpncpy(FAR char *dest, FAR const char *src, size_t n) { +#ifdef CONFIG_LIBC_STRING_OPTIMIZE + FAR char *ret = NULL; + FAR long *aligned_dst; + FAR const long *aligned_src; + + /* If src and dest is aligned and n large enough, then copy words. */ + + if (!UNALIGNED(src, dest) && !TOO_SMALL(n)) + { + aligned_dst = (FAR long *)dest; + aligned_src = (FAR long *)src; + + /* src and dest are both "long int" aligned, try to do "long int" + * sized copies. + */ + + while (n >= LBLOCKSIZE && !DETECTNULL(*aligned_src)) + { + n -= LBLOCKSIZE; + *aligned_dst++ = *aligned_src++; + } + + dest = (FAR char *)aligned_dst; + src = (FAR char *)aligned_src; + } + + while (n > 0) + { + --n; + if ((*dest++ = *src++) == '\0') + { + ret = dest - 1; + break; + } + } + + while (n-- > 0) + { + *dest++ = '\0'; + } + + return ret ? ret : dest; +#else FAR char *end = dest + n; /* End of dest buffer + 1 byte */ FAR char *ret; /* Value to be returned */ @@ -91,5 +162,6 @@ FAR char *stpncpy(FAR char *dest, FAR const char *src, size_t n) } return ret; +#endif } #endif diff --git a/libs/libc/string/lib_strcat.c b/libs/libc/string/lib_strcat.c index 7dcc5e4ee8c..5d7dc8dcb09 100644 --- a/libs/libc/string/lib_strcat.c +++ b/libs/libc/string/lib_strcat.c @@ -30,6 +30,27 @@ #include "libc.h" +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_LIBC_STRING_OPTIMIZE + +#define ALIGNED(x) \ + (((long)(uintptr_t)(x) & (sizeof(long) - 1)) == 0) + +/* Macros for detecting endchar */ + +#if LONG_MAX == 2147483647 +# define DETECTNULL(x) (((x) - 0x01010101) & ~(x) & 0x80808080) +#elif LONG_MAX == 9223372036854775807 +/* Nonzero if x (a long int) contains a NULL byte. */ + +# define DETECTNULL(x) (((x) - 0x0101010101010101) & ~(x) & 0x8080808080808080) +#endif + +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -38,6 +59,37 @@ #undef strcat /* See mm/README.txt */ FAR char *strcat(FAR char *dest, FAR const char *src) { +#ifdef CONFIG_LIBC_STRING_OPTIMIZE + FAR char *ret = dest; + + /* Skip over the data in dest as quickly as possible. */ + + if (ALIGNED(dest)) + { + FAR unsigned long *aligned_s1 = (FAR unsigned long *)dest; + while (!DETECTNULL(*aligned_s1)) + { + aligned_s1++; + } + + dest = (FAR char *)aligned_s1; + } + + while (*dest) + { + dest++; + } + + /* dest now points to the its trailing null character, we can + * just use strcpy to do the work for us now. + * ?!? We might want to just include strcpy here. + * Also, this will cause many more unaligned string copies because + * dest is much less likely to be aligned. I don't know if its worth + * tweaking strcpy to handle this better. + */ + + strcpy(dest, src); +#else FAR char *ret = dest; dest += strlen(dest); @@ -47,6 +99,7 @@ FAR char *strcat(FAR char *dest, FAR const char *src) } *dest = '\0'; +#endif return ret; } diff --git a/libs/libc/string/lib_strchr.c b/libs/libc/string/lib_strchr.c index 98538abbb50..463b485001d 100644 --- a/libs/libc/string/lib_strchr.c +++ b/libs/libc/string/lib_strchr.c @@ -30,6 +30,32 @@ #include "libc.h" +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_LIBC_STRING_OPTIMIZE + +#define UNALIGNED(x) ((long)(uintptr_t)(x) & (sizeof(long) - 1)) + +/* How many bytes are loaded each iteration of the word copy loop. */ + +#define LBLOCKSIZE (sizeof(long)) + +/* Macros for detecting endchar */ + +#if LONG_MAX == 2147483647 +# define DETECTNULL(x) (((x) - 0x01010101) & ~(x) & 0x80808080) +#elif LONG_MAX == 9223372036854775807 +/* Nonzero if x (a long int) contains a NULL byte. */ + +# define DETECTNULL(x) (((x) - 0x0101010101010101) & ~(x) & 0x8080808080808080) +#endif + +#define DETECTCHAR(x, mask) (DETECTNULL((x) ^ (mask))) + +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -52,6 +78,92 @@ #undef strchr /* See mm/README.txt */ FAR char *strchr(FAR const char *s, int c) { +#ifdef CONFIG_LIBC_STRING_OPTIMIZE + FAR const unsigned char *s1 = (FAR const unsigned char *)s; + FAR unsigned long *aligned_addr; + unsigned char i = c; + unsigned long mask; + unsigned long j; + + /* Special case for finding 0. */ + + if (!i) + { + while (UNALIGNED(s1)) + { + if (!*s1) + { + return (FAR char *)s1; + } + + s1++; + } + + /* Operate a word at a time. */ + + aligned_addr = (FAR unsigned long *)s1; + while (!DETECTNULL(*aligned_addr)) + { + aligned_addr++; + } + + /* Found the end of string. */ + + s1 = (FAR const unsigned char *)aligned_addr; + while (*s1) + { + s1++; + } + + return (FAR char *)s1; + } + + /* All other bytes. Align the pointer, then search a long at a time. */ + + while (UNALIGNED(s1)) + { + if (!*s1) + { + return NULL; + } + + if (*s1 == i) + { + return (FAR char *)s1; + } + + s1++; + } + + mask = i; + for (j = 8; j < LBLOCKSIZE * 8; j <<= 1) + { + mask = (mask << j) | mask; + } + + aligned_addr = (FAR unsigned long *)s1; + 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. + */ + + s1 = (FAR unsigned char *)aligned_addr; + + while (*s1 && *s1 != i) + { + s1++; + } + + if (*s1 == i) + { + return (FAR char *)s1; + } +#else for (; ; s++) { if (*s == c) @@ -64,6 +176,7 @@ FAR char *strchr(FAR const char *s, int c) break; } } +#endif return NULL; } diff --git a/libs/libc/string/lib_strchrnul.c b/libs/libc/string/lib_strchrnul.c index d8433b695c7..9cccb44ce9d 100644 --- a/libs/libc/string/lib_strchrnul.c +++ b/libs/libc/string/lib_strchrnul.c @@ -52,6 +52,11 @@ #undef strchrnul /* See mm/README.txt */ FAR char *strchrnul(FAR const char *s, int c) { +#ifdef CONFIG_LIBC_STRING_OPTIMIZE + FAR char *s1 = strchr(s, c); + + return s1 ? s1 : (FAR char *)s + strlen(s); +#else if (s) { while (*s != '\0' && *s != c) @@ -61,5 +66,6 @@ FAR char *strchrnul(FAR const char *s, int c) } return (FAR char *)s; +#endif } #endif diff --git a/libs/libc/string/lib_strcmp.c b/libs/libc/string/lib_strcmp.c index f445d5f99a2..1a99f8109c1 100644 --- a/libs/libc/string/lib_strcmp.c +++ b/libs/libc/string/lib_strcmp.c @@ -30,6 +30,28 @@ #include "libc.h" +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_LIBC_STRING_OPTIMIZE +/* Nonzero if either x or y is not aligned on a "long" boundary. */ + +#define UNALIGNED(x, y) \ + (((long)(uintptr_t)(x) & (sizeof(long) - 1)) | ((long)(uintptr_t)(y) & (sizeof(long) - 1))) + +/* Macros for detecting endchar */ + +#if LONG_MAX == 2147483647 +# define DETECTNULL(x) (((x) - 0x01010101) & ~(x) & 0x80808080) +#elif LONG_MAX == 9223372036854775807 +/* Nonzero if x (a long int) contains a NULL byte. */ + +# define DETECTNULL(x) (((x) - 0x0101010101010101) & ~(x) & 0x8080808080808080) +#endif + +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -38,6 +60,49 @@ #undef strcmp /* See mm/README.txt */ int strcmp(FAR const char *cs, FAR const char *ct) { +#ifdef CONFIG_LIBC_STRING_OPTIMIZE + FAR unsigned long *a1; + FAR unsigned long *a2; + + /* If cs or ct are unaligned, then compare bytes. */ + + if (!UNALIGNED(cs, ct)) + { + /* If cs and ct are word-aligned, compare them a word at a time. */ + + a1 = (FAR unsigned long *)cs; + a2 = (FAR unsigned long *)ct; + while (*a1 == *a2) + { + /* To get here, *a1 == *a2, thus if we find a null in *a1, + * then the strings must be equal, so return zero. + */ + + if (DETECTNULL(*a1)) + { + return 0; + } + + a1++; + a2++; + } + + /* A difference was detected in last few bytes of cs, + * so search bytewise. + */ + + cs = (FAR char *)a1; + ct = (FAR char *)a2; + } + + while (*cs != '\0' && *cs == *ct) + { + cs++; + ct++; + } + + return (*(FAR unsigned char *)cs) - (*(FAR unsigned char *)ct); +#else register int result; for (; ; ) { @@ -49,5 +114,6 @@ int strcmp(FAR const char *cs, FAR const char *ct) } return result; +#endif } #endif diff --git a/libs/libc/string/lib_strcoll.c b/libs/libc/string/lib_strcoll.c index 31d49db4733..1c592aaf3ab 100644 --- a/libs/libc/string/lib_strcoll.c +++ b/libs/libc/string/lib_strcoll.c @@ -52,7 +52,7 @@ * ****************************************************************************/ -int strcoll(const char *a, const char *b) +int strcoll(FAR const char *a, FAR const char *b) { return strcmp(a, b); } diff --git a/libs/libc/string/lib_strcpy.c b/libs/libc/string/lib_strcpy.c index 38c73c3a481..27cddca36f5 100644 --- a/libs/libc/string/lib_strcpy.c +++ b/libs/libc/string/lib_strcpy.c @@ -30,6 +30,28 @@ #include "libc.h" +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_LIBC_STRING_OPTIMIZE +/* Nonzero if either x or y is not aligned on a "long" boundary. */ + +#define UNALIGNED(x, y) \ + (((long)(uintptr_t)(x) & (sizeof(long) - 1)) | ((long)(uintptr_t)(y) & (sizeof(long) - 1))) + +/* Macros for detecting endchar */ + +#if LONG_MAX == 2147483647 +# define DETECTNULL(x) (((x) - 0x01010101) & ~(x) & 0x80808080) +#elif LONG_MAX == 9223372036854775807 +/* Nonzero if x (a long int) contains a NULL byte. */ + +# define DETECTNULL(x) (((x) - 0x0101010101010101) & ~(x) & 0x8080808080808080) +#endif + +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -50,8 +72,39 @@ #undef strcpy /* See mm/README.txt */ FAR char *strcpy(FAR char *dest, FAR const char *src) { +#ifdef CONFIG_LIBC_STRING_OPTIMIZE + FAR char *dst0 = dest; + FAR const char *src0 = src; + FAR long *aligned_dst; + FAR const long *aligned_src; + + /* If SRC or DEST is unaligned, then copy bytes. */ + + if (!UNALIGNED(src0, dst0)) + { + aligned_dst = (FAR long *)dst0; + aligned_src = (FAR long *)src0; + + /* SRC and DEST are both "long int" aligned, try to do "long int" + * sized copies. + */ + + while (!DETECTNULL(*aligned_src)) + { + *aligned_dst++ = *aligned_src++; + } + + dst0 = (FAR char *)aligned_dst; + src0 = (FAR char *)aligned_src; + } + + while ((*dst0++ = *src0++) != '\0'); + + return dest; +#else FAR char *tmp = dest; while ((*dest++ = *src++) != '\0'); return tmp; +#endif } #endif diff --git a/libs/libc/string/lib_strdup.c b/libs/libc/string/lib_strdup.c index f876d0b2404..40e7fef4b17 100644 --- a/libs/libc/string/lib_strdup.c +++ b/libs/libc/string/lib_strdup.c @@ -42,7 +42,7 @@ FAR char *strdup(FAR const char *s) if (news) { - strlcpy(news, s, size); + memcpy(news, s, size); } return news; diff --git a/libs/libc/string/lib_strlen.c b/libs/libc/string/lib_strlen.c index 594f01a4812..d13968c26d2 100644 --- a/libs/libc/string/lib_strlen.c +++ b/libs/libc/string/lib_strlen.c @@ -30,6 +30,27 @@ #include "libc.h" +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_LIBC_STRING_OPTIMIZE + +#define LBLOCKSIZE (sizeof(long)) +#define UNALIGNED(x) ((long)(uintptr_t)(x) & (LBLOCKSIZE - 1)) + +/* Macros for detecting endchar */ + +#if LONG_MAX == 2147483647 +# define DETECTNULL(x) (((x) - 0x01010101) & ~(x) & 0x80808080) +#elif LONG_MAX == 9223372036854775807 +/* Nonzero if x (a long int) contains a NULL byte. */ + +# define DETECTNULL(x) (((x) - 0x0101010101010101) & ~(x) & 0x8080808080808080) +#endif + +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -38,8 +59,47 @@ #undef strlen /* See mm/README.txt */ size_t strlen(FAR const char *s) { +#ifdef CONFIG_LIBC_STRING_OPTIMIZE + FAR const char *start = s; + FAR unsigned long *aligned_addr; + + /* Align the pointer, so we can search a word at a time. */ + + while (UNALIGNED(s)) + { + if (!*s) + { + return s - start; + } + + s++; + } + + /* If the string is word-aligned, we can check for the presence of + * a null in each word-sized block. + */ + + aligned_addr = (FAR unsigned long *)s; + while (!DETECTNULL(*aligned_addr)) + { + aligned_addr++; + } + + /* Once a null is detected, we check each byte in that block for a + * precise position of the null. + */ + + s = (FAR char *)aligned_addr; + while (*s) + { + s++; + } + + return s - start; +#else FAR const char *sc; for (sc = s; *sc != '\0'; ++sc); return sc - s; +#endif } #endif diff --git a/libs/libc/string/lib_strncmp.c b/libs/libc/string/lib_strncmp.c index e46c7abbcea..8000c17be38 100644 --- a/libs/libc/string/lib_strncmp.c +++ b/libs/libc/string/lib_strncmp.c @@ -30,6 +30,31 @@ #include "libc.h" +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_LIBC_STRING_OPTIMIZE + +#define LBLOCKSIZE (sizeof(long)) + +/* Nonzero if either x or y is not aligned on a "long" boundary. */ + +#define UNALIGNED(x, y) \ + (((long)(uintptr_t)(x) & (sizeof(long) - 1)) | ((long)(uintptr_t)(y) & (sizeof(long) - 1))) + +/* Macros for detecting endchar */ + +#if LONG_MAX == 2147483647 +# define DETECTNULL(x) (((x) - 0x01010101) & ~(x) & 0x80808080) +#elif LONG_MAX == 9223372036854775807 +/* Nonzero if x (a long int) contains a NULL byte. */ + +# define DETECTNULL(x) (((x) - 0x0101010101010101) & ~(x) & 0x8080808080808080) +#endif + +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -38,6 +63,65 @@ #undef strncmp /* See mm/README.txt */ int strncmp(FAR const char *cs, FAR const char *ct, size_t nb) { +#ifdef CONFIG_LIBC_STRING_OPTIMIZE + FAR unsigned long *a1; + FAR unsigned long *a2; + + if (nb == 0) + { + return 0; + } + + /* If cs or ct are unaligned, then compare bytes. */ + + if (!UNALIGNED(cs, ct)) + { + /* If cs and ct are word-aligned, compare them a word at a time. */ + + a1 = (FAR unsigned long *)cs; + a2 = (FAR unsigned long *)ct; + while (nb >= LBLOCKSIZE && *a1 == *a2) + { + nb -= LBLOCKSIZE; + + /* If we've run out of bytes or hit a null, return zero + * since we already know *a1 == *a2. + */ + + if (nb == 0 || DETECTNULL(*a1)) + { + return 0; + } + + a1++; + a2++; + } + + /* A difference was detected in last few bytes of cs, so search + * bytewise. + */ + + cs = (FAR char *)a1; + ct = (FAR char *)a2; + } + + while (nb-- > 0 && *cs == *ct) + { + /* If we've run out of bytes or hit a null, return zero + * since we already know *cs == *ct. + */ + + if (nb == 0 || *cs == '\0') + { + return 0; + } + + cs++; + ct++; + } + + return *cs - *ct; +#else register int result = 0; for (; nb > 0; nb--) { @@ -49,5 +133,6 @@ int strncmp(FAR const char *cs, FAR const char *ct, size_t nb) } return result; +#endif } #endif diff --git a/libs/libc/string/lib_strncpy.c b/libs/libc/string/lib_strncpy.c index 3e36df4ff53..ccceb5d87ba 100644 --- a/libs/libc/string/lib_strncpy.c +++ b/libs/libc/string/lib_strncpy.c @@ -30,6 +30,33 @@ #include "libc.h" +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_LIBC_STRING_OPTIMIZE + +#define LBLOCKSIZE (sizeof(long)) + +/* Nonzero if either x or y is not aligned on a "long" boundary. */ + +#define UNALIGNED(x, y) \ + (((long)(uintptr_t)(x) & (sizeof(long) - 1)) | ((long)(uintptr_t)(y) & (sizeof(long) - 1))) + +/* Macros for detecting endchar */ + +#if LONG_MAX == 2147483647 +# define DETECTNULL(x) (((x) - 0x01010101) & ~(x) & 0x80808080) +#elif LONG_MAX == 9223372036854775807 +/* Nonzero if x (a long int) contains a NULL byte. */ + +# define DETECTNULL(x) (((x) - 0x0101010101010101) & ~(x) & 0x8080808080808080) +#endif + +#define TOO_SMALL(len) ((len) < sizeof(long)) + +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -59,6 +86,49 @@ #undef strncpy /* See mm/README.txt */ FAR char *strncpy(FAR char *dest, FAR const char *src, size_t n) { +#ifdef CONFIG_LIBC_STRING_OPTIMIZE + FAR char *dst0 = dest; + FAR const char *src0 = src; + FAR long *aligned_dst; + FAR const long *aligned_src; + + /* If src and dest is aligned and n large enough, then copy words. */ + + if (!UNALIGNED(src0, dst0) && !TOO_SMALL(n)) + { + aligned_dst = (FAR long *)dst0; + aligned_src = (FAR long *)src0; + + /* src and dest are both "long int" aligned, try to do "long int" + * sized copies. + */ + + while (n >= LBLOCKSIZE && !DETECTNULL(*aligned_src)) + { + n -= LBLOCKSIZE; + *aligned_dst++ = *aligned_src++; + } + + dst0 = (FAR char *)aligned_dst; + src0 = (FAR char *)aligned_src; + } + + while (n > 0) + { + --n; + if ((*dst0++ = *src0++) == '\0') + { + break; + } + } + + while (n-- > 0) + { + *dst0++ = '\0'; + } + + return dest; +#else FAR char *ret = dest; /* Value to be returned */ FAR char *end = dest + n; /* End of dest buffer + 1 byte */ @@ -80,5 +150,6 @@ FAR char *strncpy(FAR char *dest, FAR const char *src, size_t n) } return ret; +#endif } #endif diff --git a/libs/libc/string/lib_strrchr.c b/libs/libc/string/lib_strrchr.c index d19afc743bc..a448f277575 100644 --- a/libs/libc/string/lib_strrchr.c +++ b/libs/libc/string/lib_strrchr.c @@ -42,6 +42,24 @@ #undef strrchr /* See mm/README.txt */ FAR char *strrchr(FAR const char *s, int c) { +#ifdef CONFIG_LIBC_STRING_OPTIMIZE + FAR const char *last = NULL; + + if (c) + { + while ((s = strchr(s, c))) + { + last = s; + s++; + } + } + else + { + last = strchr(s, c); + } + + return (FAR char *)last; +#else FAR const char *r = NULL; do @@ -54,5 +72,6 @@ FAR char *strrchr(FAR const char *s, int c) while (*s++ != '\0'); return (FAR char *)r; +#endif } #endif