1/*
2 * @TAG(OTHER_MIT)
3 */
4/*
5 * Copyright �� 2005-2014 Rich Felker, et al.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27#include "util.h"
28
29void *__sel4runtime_memcpy(void *restrict dest, const void *restrict src, sel4runtime_size_t n)
30{
31    unsigned char *d = dest;
32    const unsigned char *s = src;
33
34#ifdef __GNUC__
35
36#if __BYTE_ORDER == __LITTLE_ENDIAN
37#define LS >>
38#define RS <<
39#else
40#define LS <<
41#define RS >>
42#endif
43
44    typedef sel4runtime_uint32_t __attribute__((__may_alias__)) u32;
45    sel4runtime_uint32_t w, x;
46
47    for (; (sel4runtime_uintptr_t)s % 4 && n; n--) {
48        *d++ = *s++;
49    }
50
51    if ((sel4runtime_uintptr_t)d % 4 == 0) {
52        for (; n >= 16; s += 16, d += 16, n -= 16) {
53            *(u32 *)(d + 0) = *(u32 *)(s + 0);
54            *(u32 *)(d + 4) = *(u32 *)(s + 4);
55            *(u32 *)(d + 8) = *(u32 *)(s + 8);
56            *(u32 *)(d + 12) = *(u32 *)(s + 12);
57        }
58        if (n & 8) {
59            *(u32 *)(d + 0) = *(u32 *)(s + 0);
60            *(u32 *)(d + 4) = *(u32 *)(s + 4);
61            d += 8;
62            s += 8;
63        }
64        if (n & 4) {
65            *(u32 *)(d + 0) = *(u32 *)(s + 0);
66            d += 4;
67            s += 4;
68        }
69        if (n & 2) {
70            *d++ = *s++;
71            *d++ = *s++;
72        }
73        if (n & 1) {
74            *d = *s;
75        }
76        return dest;
77    }
78
79    if (n >= 32) switch ((sel4runtime_uintptr_t)d % 4) {
80        case 1:
81            w = *(u32 *)s;
82            *d++ = *s++;
83            *d++ = *s++;
84            *d++ = *s++;
85            n -= 3;
86            for (; n >= 17; s += 16, d += 16, n -= 16) {
87                x = *(u32 *)(s + 1);
88                *(u32 *)(d + 0) = (w LS 24) | (x RS 8);
89                w = *(u32 *)(s + 5);
90                *(u32 *)(d + 4) = (x LS 24) | (w RS 8);
91                x = *(u32 *)(s + 9);
92                *(u32 *)(d + 8) = (w LS 24) | (x RS 8);
93                w = *(u32 *)(s + 13);
94                *(u32 *)(d + 12) = (x LS 24) | (w RS 8);
95            }
96            break;
97        case 2:
98            w = *(u32 *)s;
99            *d++ = *s++;
100            *d++ = *s++;
101            n -= 2;
102            for (; n >= 18; s += 16, d += 16, n -= 16) {
103                x = *(u32 *)(s + 2);
104                *(u32 *)(d + 0) = (w LS 16) | (x RS 16);
105                w = *(u32 *)(s + 6);
106                *(u32 *)(d + 4) = (x LS 16) | (w RS 16);
107                x = *(u32 *)(s + 10);
108                *(u32 *)(d + 8) = (w LS 16) | (x RS 16);
109                w = *(u32 *)(s + 14);
110                *(u32 *)(d + 12) = (x LS 16) | (w RS 16);
111            }
112            break;
113        case 3:
114            w = *(u32 *)s;
115            *d++ = *s++;
116            n -= 1;
117            for (; n >= 19; s += 16, d += 16, n -= 16) {
118                x = *(u32 *)(s + 3);
119                *(u32 *)(d + 0) = (w LS 8) | (x RS 24);
120                w = *(u32 *)(s + 7);
121                *(u32 *)(d + 4) = (x LS 8) | (w RS 24);
122                x = *(u32 *)(s + 11);
123                *(u32 *)(d + 8) = (w LS 8) | (x RS 24);
124                w = *(u32 *)(s + 15);
125                *(u32 *)(d + 12) = (x LS 8) | (w RS 24);
126            }
127            break;
128        }
129    if (n & 16) {
130        *d++ = *s++;
131        *d++ = *s++;
132        *d++ = *s++;
133        *d++ = *s++;
134        *d++ = *s++;
135        *d++ = *s++;
136        *d++ = *s++;
137        *d++ = *s++;
138        *d++ = *s++;
139        *d++ = *s++;
140        *d++ = *s++;
141        *d++ = *s++;
142        *d++ = *s++;
143        *d++ = *s++;
144        *d++ = *s++;
145        *d++ = *s++;
146    }
147    if (n & 8) {
148        *d++ = *s++;
149        *d++ = *s++;
150        *d++ = *s++;
151        *d++ = *s++;
152        *d++ = *s++;
153        *d++ = *s++;
154        *d++ = *s++;
155        *d++ = *s++;
156    }
157    if (n & 4) {
158        *d++ = *s++;
159        *d++ = *s++;
160        *d++ = *s++;
161        *d++ = *s++;
162    }
163    if (n & 2) {
164        *d++ = *s++;
165        *d++ = *s++;
166    }
167    if (n & 1) {
168        *d = *s;
169    }
170    return dest;
171#endif
172
173    for (; n; n--) {
174        *d++ = *s++;
175    }
176    return dest;
177}
178