diff options
Diffstat (limited to 'lib/libc/string/memcpy.c')
| -rw-r--r-- | lib/libc/string/memcpy.c | 98 |
1 files changed, 94 insertions, 4 deletions
diff --git a/lib/libc/string/memcpy.c b/lib/libc/string/memcpy.c index f87d95cd..83a29170 100644 --- a/lib/libc/string/memcpy.c +++ b/lib/libc/string/memcpy.c @@ -1,5 +1,6 @@ #include <errno.h> // for EINVAL, ERANGE #include <stddef.h> // for NULL, errno_t +#include <stdint.h> #include <string.h> // for rsize_t, memcpy, size_t, memcpy_s #include <sys/cdefs.h> @@ -7,12 +8,101 @@ __weak void *memcpy(void *restrict s1, const void *restrict s2, size_t n); void *memcpy(void *restrict s1, const void *restrict s2, size_t n) { - unsigned char *dest = (unsigned char *)s1; - const unsigned char *src = (const unsigned char *)s2; + unsigned char *d = (unsigned char *)s1; + const unsigned char *s = (const unsigned char *)s2; - while (n--) { - *dest++ = *src++; + if (n == 0) + return s1; + + if (n < 16) { + if (n >= 8) { + *(uint64_t *)d = *(const uint64_t *)s; + d += 8; + s += 8; + n -= 8; + } + if (n >= 4) { + *(uint32_t *)d = *(const uint32_t *)s; + d += 4; + s += 4; + n -= 4; + } + if (n >= 2) { + *(uint16_t *)d = *(const uint16_t *)s; + d += 2; + s += 2; + n -= 2; + } + if (n) + *d = *s; + return s1; + } + + uintptr_t align_mask = 15; + size_t misalign = (uintptr_t)d & align_mask; + if (misalign) { + size_t to_align = 16 - misalign; + if (to_align > n) + to_align = n; + for (size_t i = 0; i < to_align; ++i) + *d++ = *s++; + n -= to_align; + } + + while (n >= 128) { +#pragma unroll + for (int i = 0; i < 8; ++i) { + ((i128 *)d)[i] = ((const i128 *)s)[i]; + } + d += 128; + s += 128; + n -= 128; + } + while (n >= 64) { +#pragma unroll + for (int i = 0; i < 4; ++i) { + ((i128 *)d)[i] = ((const i128 *)s)[i]; + } + d += 64; + s += 64; + n -= 64; + } + while (n >= 32) { +#pragma unroll + for (int i = 0; i < 2; ++i) { + ((i128 *)d)[i] = ((const i128 *)s)[i]; + } + d += 32; + s += 32; + n -= 32; + } + while (n >= 16) { + *(i128 *)d = *(const i128 *)s; + d += 16; + s += 16; + n -= 16; + } + + if (n >= 8) { + *(uint64_t *)d = *(const uint64_t *)s; + d += 8; + s += 8; + n -= 8; + } + if (n >= 4) { + *(uint32_t *)d = *(const uint32_t *)s; + d += 4; + s += 4; + n -= 4; + } + if (n >= 2) { + *(uint16_t *)d = *(const uint16_t *)s; + d += 2; + s += 2; + n -= 2; } + if (n) + *d = *s; return s1; } |
