aboutsummaryrefslogtreecommitdiff
path: root/libc/arch-mips/string/memmove.c
diff options
context:
space:
mode:
Diffstat (limited to 'libc/arch-mips/string/memmove.c')
-rw-r--r--libc/arch-mips/string/memmove.c468
1 files changed, 0 insertions, 468 deletions
diff --git a/libc/arch-mips/string/memmove.c b/libc/arch-mips/string/memmove.c
deleted file mode 100644
index 74d4cd0bf..000000000
--- a/libc/arch-mips/string/memmove.c
+++ /dev/null
@@ -1,468 +0,0 @@
-/*
- * Copyright (c) 2017 Imagination Technologies.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with
- * the distribution.
- * * Neither the name of Imagination Technologies nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <string.h>
-
-#if !defined(UNALIGNED_INSTR_SUPPORT)
-/* does target have unaligned lw/ld/ualw/uald instructions? */
-#define UNALIGNED_INSTR_SUPPORT 0
-#if __mips_isa_rev < 6 && !__mips1
-#undef UNALIGNED_INSTR_SUPPORT
-#define UNALIGNED_INSTR_SUPPORT 1
-#endif
-#endif
-
-#if !defined(HW_UNALIGNED_SUPPORT)
-/* Does target have hardware support for unaligned accesses? */
-#define HW_UNALIGNED_SUPPORT 0
-#if __mips_isa_rev >= 6
-#undef HW_UNALIGNED_SUPPORT
-#define HW_UNALIGNED_SUPPORT 1
-#endif
-#endif
-
-#define ENABLE_PREFETCH 1
-
-#if ENABLE_PREFETCH
-#define PREFETCH(addr) __builtin_prefetch (addr, 0, 1);
-#else
-#define PREFETCH(addr)
-#endif
-
-#if _MIPS_SIM == _ABIO32
-typedef unsigned long reg_t;
-typedef struct
-{
- reg_t B0:8, B1:8, B2:8, B3:8;
-} bits_t;
-#else
-typedef unsigned long long reg_t;
-typedef struct
-{
- reg_t B0:8, B1:8, B2:8, B3:8, B4:8, B5:8, B6:8, B7:8;
-} bits_t;
-#endif
-
-typedef union
-{
- reg_t v;
- bits_t b;
-} bitfields_t;
-
-#define DO_BYTE(a, i) \
- a[i] = bw.b.B##i; \
- len--; \
- if(!len) return ret; \
-
-/* This code is called when aligning a pointer, there are remaining bytes
- after doing word compares, or architecture does not have some form
- of unaligned support. */
-static inline void * __attribute__ ((always_inline))
-do_bytes (void *a, const void *b, unsigned long len, void *ret)
-{
- unsigned char *x = (unsigned char *) a;
- unsigned char *y = (unsigned char *) b;
- unsigned long i;
-
- /* 'len' might be zero here, so preloading the first two values
- before the loop may access unallocated memory. */
- for (i = 0; i < len; i++)
- {
- *x = *y;
- x++;
- y++;
- }
- return ret;
-}
-
-static inline void * __attribute__ ((always_inline))
-do_bytes_backward (void *a, const void *b, unsigned long len, void *ret)
-{
- unsigned char *x = (unsigned char *) a;
- unsigned char *y = (unsigned char *) b;
- unsigned long i;
-
- /* 'len' might be zero here, so preloading the first two values
- before the loop may access unallocated memory. */
- for (i = 0; i < len; i++) {
- *--x = *--y;
- }
- return ret;
-}
-
-static inline void * __attribute__ ((always_inline))
-do_bytes_aligned (void *a, const void *b, unsigned long len, void *ret)
-{
- unsigned char *x = (unsigned char *) a;
-
- if(len > 0) {
- bitfields_t bw;
- bw.v = *((reg_t*) b);
-
-#if __mips64
- DO_BYTE(x, 0);
- DO_BYTE(x, 1);
- DO_BYTE(x, 2);
- DO_BYTE(x, 3);
- DO_BYTE(x, 4);
- DO_BYTE(x, 5);
- DO_BYTE(x, 6);
- DO_BYTE(x, 7);
-#else
- DO_BYTE(x, 0);
- DO_BYTE(x, 1);
- DO_BYTE(x, 2);
- DO_BYTE(x, 3);
-#endif
- }
-
- return ret;
-}
-
-#if !HW_UNALIGNED_SUPPORT
-#if UNALIGNED_INSTR_SUPPORT
-/* for MIPS GCC, there are no unaligned builtins - so this struct forces
- the compiler to treat the pointer access as unaligned. */
-struct ulw
-{
- reg_t uli;
-} __attribute__ ((packed));
-
-#define STORE_UNALIGNED_8(a, b) \
-{ \
- reg_t y0 = b[0], y1 = b[1], y2 = b[2], y3 = b[3]; \
- reg_t y4 = b[4], y5 = b[5], y6 = b[6], y7 = b[7]; \
- a[0].uli = y0; \
- a[1].uli = y1; \
- a[2].uli = y2; \
- a[3].uli = y3; \
- a[4].uli = y4; \
- a[5].uli = y5; \
- a[6].uli = y6; \
- a[7].uli = y7; \
-}
-
-#define STORE_UNALIGNED_4(a, b) \
-{ \
- reg_t y0 = b[0], y1 = b[1], y2 = b[2], y3 = b[3]; \
- a[0].uli = y0; \
- a[1].uli = y1; \
- a[2].uli = y2; \
- a[3].uli = y3; \
-}
-
-/* first pointer is not aligned while second pointer is. */
-static void *
-unaligned_words_forward (struct ulw *a, const reg_t * b,
- unsigned long words, unsigned long bytes, void *ret)
-{
-#if ((_MIPS_SIM == _ABIO32) || _MIPS_TUNE_I6400)
- unsigned long i, words_by_8, words_by_1;
- words_by_1 = words % 8;
- words_by_8 = words >> 3;
- for (; words_by_8 > 0; words_by_8--) {
- if(words_by_8 != 1)
- PREFETCH (b + 8);
- STORE_UNALIGNED_8(a, b);
- a += 8;
- b += 8;
- }
-#else
- unsigned long i, words_by_4, words_by_1;
- words_by_1 = words % 4;
- words_by_4 = words >> 2;
- for (; words_by_4 > 0; words_by_4--) {
- if(words_by_4 != 1)
- PREFETCH (b + 4);
- STORE_UNALIGNED_4(a, b);
- a += 4;
- b += 4;
- }
-#endif
-
- /* do remaining words. */
- for (i = 0; i < words_by_1; i++) {
- a->uli = *b;
- a += 1;
- b += 1;
- }
-
- /* mop up any remaining bytes. */
- return do_bytes_aligned (a, b, bytes, ret);
-}
-
-static void *
-unaligned_words_backward (struct ulw *a, const reg_t * b,
- unsigned long words, unsigned long bytes, void *ret)
-{
-#if ((_MIPS_SIM == _ABIO32) || _MIPS_TUNE_I6400)
- unsigned long i, words_by_8, words_by_1;
- words_by_1 = words % 8;
- words_by_8 = words >> 3;
- for (; words_by_8 > 0; words_by_8--) {
- if(words_by_8 != 1)
- PREFETCH (b - 16);
- a -= 8;
- b -= 8;
- STORE_UNALIGNED_8(a, b);
- }
-#else
- unsigned long i, words_by_4, words_by_1;
- words_by_1 = words % 4;
- words_by_4 = words >> 2;
- for (; words_by_4 > 0; words_by_4--) {
- if(words_by_4 != 1)
- PREFETCH (b - 8);
- a -= 4;
- b -= 4;
- STORE_UNALIGNED_4(a, b);
- }
-#endif
-
- /* do remaining words. */
- for (i = 0; i < words_by_1; i++) {
- a -= 1;
- b -= 1;
- a->uli = *b;
- }
-
- /* mop up any remaining bytes. */
- return do_bytes_backward (a, b, bytes, ret);
-}
-
-#else
-/* no HW support or unaligned lw/ld/ualw/uald instructions. */
-static void *
-unaligned_words_forward (reg_t * a, const reg_t * b,
- unsigned long words, unsigned long bytes, void *ret)
-{
- return do_bytes_aligned (a, b, (sizeof (reg_t) * words) + bytes, ret);
-}
-
-static void *
-unaligned_words_backward (reg_t * a, const reg_t * b,
- unsigned long words, unsigned long bytes, void *ret)
-{
- return do_bytes_backward (a, b, (sizeof (reg_t) * words) + bytes, ret);
-}
-
-#endif /* UNALIGNED_INSTR_SUPPORT */
-#endif /* HW_UNALIGNED_SUPPORT */
-
-/* both pointers are aligned, or first isn't and HW support for unaligned. */
-
-#define STORE_ALIGNED_8(a, b) \
-{ \
- reg_t x0 = b[0], x1 = b[1], x2 = b[2], x3 = b[3]; \
- reg_t x4 = b[4], x5 = b[5], x6 = b[6], x7 = b[7]; \
- a[0] = x0; \
- a[1] = x1; \
- a[2] = x2; \
- a[3] = x3; \
- a[4] = x4; \
- a[5] = x5; \
- a[6] = x6; \
- a[7] = x7; \
-}
-
-#define STORE_ALIGNED_4(a, b) \
-{ \
- reg_t x0 = b[0], x1 = b[1], x2 = b[2], x3 = b[3]; \
- a[0] = x0; \
- a[1] = x1; \
- a[2] = x2; \
- a[3] = x3; \
-}
-
-static void *
-aligned_words_forward (reg_t * a, const reg_t * b,
- unsigned long words, unsigned long bytes, void *ret)
-{
-#if ((_MIPS_SIM == _ABIO32) || _MIPS_TUNE_I6400)
- unsigned long i, words_by_8, words_by_1;
- words_by_1 = words % 8;
- words_by_8 = words >> 3;
- for (; words_by_8 > 0; words_by_8--) {
- if(words_by_8 != 1)
- PREFETCH (b + 8);
- STORE_ALIGNED_8(a, b);
- a += 8;
- b += 8;
- }
-#else
- unsigned long i, words_by_4, words_by_1;
- words_by_1 = words % 4;
- words_by_4 = words >> 2;
- for (; words_by_4 > 0; words_by_4--) {
- if(words_by_4 != 1)
- PREFETCH (b + 4);
- STORE_ALIGNED_4(a, b);
- a += 4;
- b += 4;
- }
-#endif
-
- /* do remaining words. */
- for (i = 0; i < words_by_1; i++) {
- *a = *b;
- a += 1;
- b += 1;
- }
-
- /* mop up any remaining bytes. */
- return do_bytes_aligned (a, b, bytes, ret);
-}
-
-
-static void *
-aligned_words_backward (reg_t * a, const reg_t * b,
- unsigned long words, unsigned long bytes, void *ret)
-{
-#if ((_MIPS_SIM == _ABIO32) || _MIPS_TUNE_I6400)
- unsigned long i, words_by_8, words_by_1;
- words_by_1 = words % 8;
- words_by_8 = words >> 3;
- for (; words_by_8 > 0; words_by_8--) {
- if(words_by_8 != 1)
- PREFETCH (b - 16);
- a -= 8;
- b -= 8;
- STORE_ALIGNED_8(a, b);
- }
-#else
- unsigned long i, words_by_4, words_by_1;
- words_by_1 = words % 4;
- words_by_4 = words >> 2;
- for (; words_by_4 > 0; words_by_4--) {
- if(words_by_4 != 1)
- PREFETCH (b - 8);
- a -= 4;
- b -= 4;
- STORE_ALIGNED_4(a, b);
- }
-#endif
-
- /* do remaining words. */
- for (i = 0; i < words_by_1; i++) {
- a -= 1;
- b -= 1;
- *a = *b;
- }
-
- /* mop up any remaining bytes. */
- return do_bytes_backward (a, b, bytes, ret);
-}
-
-void *
-memmove (void *dst0, const void *src0, size_t length)
-{
- unsigned long bytes, words;
- void *ret = dst0;
-
- if (length == 0 || dst0 == src0) /* nothing to do */
- return dst0;
-
- if ((unsigned long)dst0 < (unsigned long)src0) {
- /* Copy forwards. */
- /* This shouldn't hit that often. */
- if (length < sizeof (reg_t) * 4) {
- return do_bytes (dst0, src0, length, ret);
- }
-
- /* Align the second pointer to word/dword alignment.
- Note that the pointer is only 32-bits for o32/n32 ABIs. For
- n32, loads are done as 64-bit while address remains 32-bit. */
- bytes = ((unsigned long) src0) % sizeof (reg_t);
- if (bytes) {
- bytes = sizeof (reg_t) - bytes;
- if (bytes > length)
- bytes = length;
- do_bytes (dst0, src0, bytes, ret);
- if (length == bytes)
- return ret;
- length -= bytes;
- dst0 = (void *) (((unsigned char *) dst0) + bytes);
- src0 = (const void *) (((unsigned char *) src0) + bytes);
- }
-
- /* Second pointer now aligned. */
- words = length / sizeof (reg_t);
- bytes = length % sizeof (reg_t);
-#if HW_UNALIGNED_SUPPORT
- /* treat possible unaligned first pointer as aligned. */
- return aligned_words_forward (dst0, src0, words, bytes, ret);
-#else
- if (((unsigned long) dst0) % sizeof (reg_t) == 0) {
- return aligned_words_forward (dst0, src0, words, bytes, ret);
- }
- /* need to use unaligned instructions on first pointer. */
- return unaligned_words_forward (dst0, src0, words, bytes, ret);
-#endif
- } else {
- /* Copy backwards. */
- dst0 = (void *) (((unsigned char *) dst0) + length);
- src0 = (const void *) (((unsigned char *) src0) + length);
-
- /* This shouldn't hit that often. */
- if (length < sizeof (reg_t) * 4) {
- return do_bytes_backward (dst0, src0, length, ret);
- }
-
- /* Align the second pointer to word/dword alignment.
- Note that the pointer is only 32-bits for o32/n32 ABIs. For
- n32, loads are done as 64-bit while address remains 32-bit. */
- bytes = ((unsigned long) src0) % sizeof (reg_t);
- if (bytes) {
- if (bytes > length)
- bytes = length;
- do_bytes_backward (dst0, src0, bytes, ret);
- if (length == bytes)
- return ret;
- length -= bytes;
- dst0 = (void *) (((unsigned char *) dst0) - bytes);
- src0 = (const void *) (((unsigned char *) src0) - bytes);
- }
-
- words = length / sizeof (reg_t);
- bytes = length % sizeof (reg_t);
-#if HW_UNALIGNED_SUPPORT
- /* treat possible unaligned first pointer as aligned. */
- return aligned_words_backward ((void *)dst0, (void *)src0, words, bytes, ret);
-#else
- if (((unsigned long) dst0) % sizeof (reg_t) == 0) {
- return aligned_words_backward (dst0, src0, words, bytes, ret);
- }
- /* need to use unaligned instructions on first pointer. */
- return unaligned_words_backward (dst0, src0, words, bytes, ret);
-#endif
- }
-}