diff options
Diffstat (limited to 'newlib/libc')
-rw-r--r-- | newlib/libc/machine/riscv/Makefile.inc | 2 | ||||
-rw-r--r-- | newlib/libc/machine/riscv/stpcpy.c | 7 | ||||
-rw-r--r-- | newlib/libc/machine/riscv/strcpy.c | 52 | ||||
-rw-r--r-- | newlib/libc/machine/riscv/strlen.c | 48 | ||||
-rw-r--r-- | newlib/libc/machine/riscv/sys/asm.h | 4 | ||||
-rw-r--r-- | newlib/libc/machine/riscv/sys/string.h | 107 |
6 files changed, 148 insertions, 72 deletions
diff --git a/newlib/libc/machine/riscv/Makefile.inc b/newlib/libc/machine/riscv/Makefile.inc index 47bbce0..4d6c046 100644 --- a/newlib/libc/machine/riscv/Makefile.inc +++ b/newlib/libc/machine/riscv/Makefile.inc @@ -1,3 +1,3 @@ libc_a_SOURCES += \ %D%/memmove.S %D%/memmove-stub.c %D%/memset.S %D%/memcpy-asm.S %D%/memcpy.c %D%/strlen.c \ - %D%/strcpy.c %D%/strcmp.S %D%/setjmp.S %D%/ieeefp.c %D%/ffs.c + %D%/strcpy.c %D%/stpcpy.c %D%/strcmp.S %D%/setjmp.S %D%/ieeefp.c %D%/ffs.c diff --git a/newlib/libc/machine/riscv/stpcpy.c b/newlib/libc/machine/riscv/stpcpy.c new file mode 100644 index 0000000..9243457 --- /dev/null +++ b/newlib/libc/machine/riscv/stpcpy.c @@ -0,0 +1,7 @@ +#include <string.h> +#include <stdbool.h> + +char *stpcpy(char *dst, const char *src) +{ + return __libc_strcpy(dst, src, false); +} diff --git a/newlib/libc/machine/riscv/strcpy.c b/newlib/libc/machine/riscv/strcpy.c index 08aef64..f770493 100644 --- a/newlib/libc/machine/riscv/strcpy.c +++ b/newlib/libc/machine/riscv/strcpy.c @@ -10,57 +10,9 @@ */ #include <string.h> -#include <stdint.h> +#include <stdbool.h> char *strcpy(char *dst, const char *src) { - char *dst0 = dst; - -#if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) -#if !(__riscv_misaligned_slow || __riscv_misaligned_fast) - int misaligned = ((uintptr_t)dst | (uintptr_t)src) & (sizeof (long) - 1); - if (__builtin_expect(!misaligned, 1)) -#endif - { - long *ldst = (long *)dst; - const long *lsrc = (const long *)src; - - while (!__libc_detect_null(*lsrc)) - *ldst++ = *lsrc++; - - dst = (char *)ldst; - src = (const char *)lsrc; - - char c0 = src[0]; - char c1 = src[1]; - char c2 = src[2]; - if (!(*dst++ = c0)) return dst0; - if (!(*dst++ = c1)) return dst0; - char c3 = src[3]; - if (!(*dst++ = c2)) return dst0; - if (sizeof (long) == 4) goto out; - char c4 = src[4]; - if (!(*dst++ = c3)) return dst0; - char c5 = src[5]; - if (!(*dst++ = c4)) return dst0; - char c6 = src[6]; - if (!(*dst++ = c5)) return dst0; - if (!(*dst++ = c6)) return dst0; - -out: - *dst++ = 0; - return dst0; - } -#endif /* not PREFER_SIZE_OVER_SPEED */ - - char ch; - do - { - ch = *src; - src++; - dst++; - *(dst - 1) = ch; - } while (ch); - - return dst0; + return __libc_strcpy(dst, src, true); } diff --git a/newlib/libc/machine/riscv/strlen.c b/newlib/libc/machine/riscv/strlen.c index 3b04066..7e5d416 100644 --- a/newlib/libc/machine/riscv/strlen.c +++ b/newlib/libc/machine/riscv/strlen.c @@ -11,6 +11,7 @@ #include <string.h> #include <stdint.h> +#include "sys/asm.h" size_t strlen(const char *str) { @@ -21,33 +22,44 @@ size_t strlen(const char *str) ; return str - start - 1; #else - if (__builtin_expect ((uintptr_t)str & (sizeof (long) - 1), 0)) do + if (__builtin_expect ((uintxlen_t)str & (sizeof (uintxlen_t) - 1), 0)) do { char ch = *str; str++; if (!ch) - return str - start - 1; - } while ((uintptr_t)str & (sizeof (long) - 1)); + return str - start - 1; + } while ((uintxlen_t)str & (sizeof (uintxlen_t) - 1)); - unsigned long *ls = (unsigned long *)str; - while (!__libc_detect_null (*ls++)) + uintxlen_t *ps = (uintxlen_t *)str; + uintxlen_t psval; + + while (!__libc_detect_null ((psval = *ps++))) ; - asm volatile ("" : "+r"(ls)); /* prevent "optimization" */ + asm volatile ("" : "+r"(ps)); /* prevent "optimization" */ + + str = (const char *)ps; + size_t ret = str - start, sp = sizeof (*ps); - str = (const char *)ls; - size_t ret = str - start, sl = sizeof (long); + #if __riscv_zbb + psval = ~__LIBC_RISCV_ZBB_ORC_B(psval); + psval = __LIBC_RISCV_ZBB_CNT_Z(psval); - char c0 = str[0 - sl], c1 = str[1 - sl], c2 = str[2 - sl], c3 = str[3 - sl]; - if (c0 == 0) return ret + 0 - sl; - if (c1 == 0) return ret + 1 - sl; - if (c2 == 0) return ret + 2 - sl; - if (sl == 4 || c3 == 0) return ret + 3 - sl; + return ret + (psval >> 3) - sp; + #else + char c0 = str[0 - sp], c1 = str[1 - sp], c2 = str[2 - sp], c3 = str[3 - sp]; + if (c0 == 0) return ret + 0 - sp; + if (c1 == 0) return ret + 1 - sp; + if (c2 == 0) return ret + 2 - sp; + if (c3 == 0) return ret + 3 - sp; - c0 = str[4 - sl], c1 = str[5 - sl], c2 = str[6 - sl], c3 = str[7 - sl]; - if (c0 == 0) return ret + 4 - sl; - if (c1 == 0) return ret + 5 - sl; - if (c2 == 0) return ret + 6 - sl; + #if __riscv_xlen == 64 + c0 = str[4 - sp], c1 = str[5 - sp], c2 = str[6 - sp]; + if (c0 == 0) return ret + 4 - sp; + if (c1 == 0) return ret + 5 - sp; + if (c2 == 0) return ret + 6 - sp; + #endif - return ret + 7 - sl; + return ret + 7 - sp; + #endif #endif /* not PREFER_SIZE_OVER_SPEED */ } diff --git a/newlib/libc/machine/riscv/sys/asm.h b/newlib/libc/machine/riscv/sys/asm.h index 8c8aeb3..0a354b2 100644 --- a/newlib/libc/machine/riscv/sys/asm.h +++ b/newlib/libc/machine/riscv/sys/asm.h @@ -12,6 +12,8 @@ #ifndef _SYS_ASM_H #define _SYS_ASM_H +#include <stdint.h> + /* * Macros to handle different pointer/register sizes for 32/64-bit code */ @@ -20,11 +22,13 @@ # define SZREG 8 # define REG_S sd # define REG_L ld +typedef uint64_t uintxlen_t; #elif __riscv_xlen == 32 # define PTRLOG 2 # define SZREG 4 # define REG_S sw # define REG_L lw +typedef uint32_t uintxlen_t; #else # error __riscv_xlen must equal 32 or 64 #endif diff --git a/newlib/libc/machine/riscv/sys/string.h b/newlib/libc/machine/riscv/sys/string.h index beebe31..b65635c 100644 --- a/newlib/libc/machine/riscv/sys/string.h +++ b/newlib/libc/machine/riscv/sys/string.h @@ -12,12 +12,113 @@ #ifndef _SYS_STRING_H #define _SYS_STRING_H -static __inline unsigned long __libc_detect_null(unsigned long w) +#include <stdbool.h> +#include "asm.h" + +#if __riscv_zbb + #include <riscv_bitmanip.h> + + // Determine which intrinsics to use based on XLEN and endianness + #if __riscv_xlen == 64 + #define __LIBC_RISCV_ZBB_ORC_B(x) __riscv_orc_b_64(x) + + #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + #define __LIBC_RISCV_ZBB_CNT_Z(x) __riscv_ctz_64(x) + #else + #define __LIBC_RISCV_ZBB_CNT_Z(x) __riscv_clz_64(x) + #endif + #else + #define __LIBC_RISCV_ZBB_ORC_B(x) __riscv_orc_b_32(x) + + #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + #define __LIBC_RISCV_ZBB_CNT_Z(x) __riscv_ctz_32(x) + #else + #define __LIBC_RISCV_ZBB_CNT_Z(x) __riscv_clz_32(x) + #endif + #endif +#endif + + +static __inline uintxlen_t __libc_detect_null(uintxlen_t w) { - unsigned long mask = 0x7f7f7f7f; - if (sizeof (long) == 8) +#if __riscv_zbb + /* + If there are any zeros in each byte of the register, all bits will + be unset for that byte value, otherwise, all bits will be set. + If the value is -1, all bits are set, meaning no null byte was found. + */ + return __LIBC_RISCV_ZBB_ORC_B(w) != -1; +#else + uintxlen_t mask = 0x7f7f7f7f; + #if __riscv_xlen == 64 mask = ((mask << 16) << 16) | mask; + #endif return ~(((w & mask) + mask) | w | mask); +#endif } + +static __inline char *__libc_strcpy(char *dst, const char *src, bool ret_start) +{ + char *dst0 = dst; + +#if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) +#if !(__riscv_misaligned_slow || __riscv_misaligned_fast) + int misaligned = ((uintxlen_t)dst | (uintxlen_t)src) & (sizeof (uintxlen_t) - 1); + if (__builtin_expect(!misaligned, 1)) +#endif + { + uintxlen_t *pdst = (uintxlen_t *)dst; + const uintxlen_t *psrc = (const uintxlen_t *)src; + + while (!__libc_detect_null(*psrc)) + *pdst++ = *psrc++; + + dst = (char *)pdst; + src = (const char *)psrc; + + if (ret_start) + { + if (!(*dst++ = src[0])) return dst0; + if (!(*dst++ = src[1])) return dst0; + if (!(*dst++ = src[2])) return dst0; + if (!(*dst++ = src[3])) return dst0; + #if __riscv_xlen == 64 + if (!(*dst++ = src[4])) return dst0; + if (!(*dst++ = src[5])) return dst0; + if (!(*dst++ = src[6])) return dst0; + #endif + } + else + { + if (!(*dst++ = src[0])) return dst - 1; + if (!(*dst++ = src[1])) return dst - 1; + if (!(*dst++ = src[2])) return dst - 1; + if (!(*dst++ = src[3])) return dst - 1; + #if __riscv_xlen == 64 + if (!(*dst++ = src[4])) return dst - 1; + if (!(*dst++ = src[5])) return dst - 1; + if (!(*dst++ = src[6])) return dst - 1; + dst0 = dst; + #endif + } + + *dst = 0; + return dst0; + } +#endif /* not PREFER_SIZE_OVER_SPEED */ + + char ch; + do + { + ch = *src; + src++; + dst++; + *(dst - 1) = ch; + } while (ch); + + return ret_start ? dst0 : dst - 1; +} + + #endif |