diff options
Diffstat (limited to 'libc/arch-mips/string/memmove.c')
-rw-r--r-- | libc/arch-mips/string/memmove.c | 468 |
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 - } -} |