aboutsummaryrefslogtreecommitdiff
path: root/newlib/libc
diff options
context:
space:
mode:
Diffstat (limited to 'newlib/libc')
-rw-r--r--newlib/libc/machine/riscv/Makefile.inc2
-rw-r--r--newlib/libc/machine/riscv/stpcpy.c7
-rw-r--r--newlib/libc/machine/riscv/strcpy.c52
-rw-r--r--newlib/libc/machine/riscv/strlen.c48
-rw-r--r--newlib/libc/machine/riscv/sys/asm.h4
-rw-r--r--newlib/libc/machine/riscv/sys/string.h107
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