[PATCH 6/6] newlib: introduce HAVE_HW_UNALIGNED_ACCESS option
Alexey Lapshin <[email protected]>
| Newsgroups | gmane.comp.lib.newlib |
|---|---|
| Message-ID | <[email protected]> |
Some hardware may perform better when copying unaligned
word-sized memory compared to byte-by-byte copying.
---
newlib/configure.host | 6 ++++++
newlib/libc/machine/riscv/memcpy.c | 4 ++++
newlib/libc/machine/riscv/strcmp.S | 5 ++++-
newlib/libc/machine/riscv/strcpy.c | 2 ++
newlib/libc/string/local.h | 11 ++++++++++-
5 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/newlib/configure.host b/newlib/configure.host
index ff2e51275..0adb1aced 100644
--- a/newlib/configure.host
+++ b/newlib/configure.host
@@ -454,6 +454,12 @@ case "${host}" in
newlib_cflags="${newlib_cflags} -D_NO_GETPASS -D_NO_SIGSET -D_NO_WORDEXP -D_NO_POPEN -D_NO_POSIX_SPAWN"
newlib_cflags="${newlib_cflags} -DHAVE_FCNTL -DHAVE_BLKSIZE -DHAVE_OPENDIR -DHAVE_RENAME"
newlib_cflags="${newlib_cflags} -DGETREENT_PROVIDED -DSIGNAL_PROVIDED"
+ newlib_cflags="${newlib_cflags} -D__ESP__"
+ case "${host_cpu}" in
+ riscv*)
+ newlib_cflags="${newlib_cflags} -DHAVE_HW_UNALIGNED_ACCESS"
+ ;;
+ esac
;;
a29k-*-*)
sys_dir=a29khif
diff --git a/newlib/libc/machine/riscv/memcpy.c b/newlib/libc/machine/riscv/memcpy.c
index 4098f3ab1..f2d335b33 100644
--- a/newlib/libc/machine/riscv/memcpy.c
+++ b/newlib/libc/machine/riscv/memcpy.c
@@ -33,8 +33,12 @@ memcpy(void *__restrict aa, const void *__restrict bb, size_t n)
const char *b = (const char *)bb;
char *end = a + n;
uintptr_t msk = sizeof (long) - 1;
+#ifdef HAVE_HW_UNALIGNED_ACCESS
+ if (n < sizeof (long))
+#else
if (unlikely ((((uintptr_t)a & msk) != ((uintptr_t)b & msk))
|| n < sizeof (long)))
+#endif // HAVE_HW_UNALIGNED_ACCESS
{
small:
if (__builtin_expect (a < end, 1))
diff --git a/newlib/libc/machine/riscv/strcmp.S b/newlib/libc/machine/riscv/strcmp.S
index 9af9ca1f3..bb0be9afd 100644
--- a/newlib/libc/machine/riscv/strcmp.S
+++ b/newlib/libc/machine/riscv/strcmp.S
@@ -30,10 +30,13 @@ strcmp:
.size strcmp, .-strcmp
#else
- or a4, a0, a1
li t2, -1
+
+#ifndef HAVE_HW_UNALIGNED_ACCESS
+ or a4, a0, a1
and a4, a4, SZREG-1
bnez a4, .Lmisaligned
+#endif
#if SZREG == 4
li a5, 0x7f7f7f7f
diff --git a/newlib/libc/machine/riscv/strcpy.c b/newlib/libc/machine/riscv/strcpy.c
index 6d802fa8e..7d7554615 100644
--- a/newlib/libc/machine/riscv/strcpy.c
+++ b/newlib/libc/machine/riscv/strcpy.c
@@ -17,8 +17,10 @@ char *strcpy(char *dst, const char *src)
char *dst0 = dst;
#if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__)
+#ifndef HAVE_HW_UNALIGNED_ACCESS
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;
diff --git a/newlib/libc/string/local.h b/newlib/libc/string/local.h
index fb8e6c65c..5eb34319a 100644
--- a/newlib/libc/string/local.h
+++ b/newlib/libc/string/local.h
@@ -17,12 +17,21 @@ int __wcwidth (wint_t);
# define __inhibit_loop_to_libcall
#endif
-/* Nonzero if X is not aligned on a "long" boundary. */
+/* Nonzero if X is not aligned on a "long" boundary.
+ * This macro is used to skip a few bytes to find an aligned pointer.
+ * It's better to keep it as is even if HAVE_HW_UNALIGNED_ACCESS is enabled,
+ * to avoid small performance penalties (if they are not zero). */
#define UNALIGNED_X(X) ((long)X & (sizeof (long) - 1))
+#ifdef HAVE_HW_UNALIGNED_ACCESS
+/* Hardware performs unaligned operations with little
+ * to no penalty compared to byte-to-byte copy. */
+#define UNALIGNED_X_Y(X, Y) (0)
+#else // HAVE_HW_UNALIGNED_ACCESS
/* Nonzero if either X or Y is not aligned on a "long" boundary. */
#define UNALIGNED_X_Y(X, Y) \
(((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1)))
+#endif // HAVE_HW_UNALIGNED_ACCESS
/* How many bytes are copied each iteration of the word copy loop. */
#define LITTLE_BLOCK_SIZE (sizeof (long))
--
2.43.0