1 /*
2 * Copyright (c) 2017 Imagination Technologies.
3 *
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with
15 * the distribution.
16 * * Neither the name of Imagination Technologies nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <string.h>
34
35 #define op_t unsigned long int
36
37 #if !defined(UNALIGNED_INSTR_SUPPORT)
38 /* does target have unaligned lw/ld/ualw/uald instructions? */
39 #define UNALIGNED_INSTR_SUPPORT 0
40 #if __mips_isa_rev < 6 && !__mips1
41 #undef UNALIGNED_INSTR_SUPPORT
42 #define UNALIGNED_INSTR_SUPPORT 1
43 #endif
44 #endif
45
46 #if !defined(HW_UNALIGNED_SUPPORT)
47 /* Does target have hardware support for unaligned accesses? */
48 #define HW_UNALIGNED_SUPPORT 0
49 #if __mips_isa_rev >= 6
50 #undef HW_UNALIGNED_SUPPORT
51 #define HW_UNALIGNED_SUPPORT 1
52 #endif
53 #endif
54
55 #if __mips64
56 typedef struct
57 {
58 op_t B0:8, B1:8, B2:8, B3:8, B4:8, B5:8, B6:8, B7:8;
59 } bits_t;
60 #else
61 typedef struct
62 {
63 op_t B0:8, B1:8, B2:8, B3:8;
64 } bits_t;
65 #endif
66
67 typedef union
68 {
69 op_t v;
70 bits_t b;
71 } bitfields_t;
72
73 #if !HW_UNALIGNED_SUPPORT && UNALIGNED_INSTR_SUPPORT
74 /* for MIPS GCC, there are no unaligned builtins - so this struct forces
75 the compiler to treat the pointer access as unaligned. */
76 struct ulw
77 {
78 op_t uli;
79 } __attribute__ ((packed));
80 #endif /* !HW_UNALIGNED_SUPPORT && UNALIGNED_INSTR_SUPPORT */
81
82 #define DO_BYTE(i, ptdst) { \
83 *(ptdst+i) = a.b.B##i; \
84 if(a.b.B##i == '\0') \
85 return ret; \
86 }
87
88 #if __mips64
89 #define DO_BYTES(val, dst) { \
90 bitfields_t a; \
91 char *tdst = (char *)(dst); \
92 a.v = val; \
93 DO_BYTE(0, tdst) \
94 DO_BYTE(1, tdst) \
95 DO_BYTE(2, tdst) \
96 DO_BYTE(3, tdst) \
97 DO_BYTE(4, tdst) \
98 DO_BYTE(5, tdst) \
99 DO_BYTE(6, tdst) \
100 DO_BYTE(7, tdst) \
101 }
102 #else
103 #define DO_BYTES(val, dst) { \
104 bitfields_t a; \
105 char *tdst = (char *)(dst); \
106 a.v = val; \
107 DO_BYTE(0, tdst) \
108 DO_BYTE(1, tdst) \
109 DO_BYTE(2, tdst) \
110 DO_BYTE(3, tdst) \
111 }
112 #endif
113
114 #define DO_WORD_ALIGNED(dst, src) { \
115 op_t val = *(src); \
116 if ((((val - mask_1) & ~val) & mask_128) != 0) { \
117 DO_BYTES(val, dst); \
118 } else *(dst) = val; \
119 }
120
121 #if !HW_UNALIGNED_SUPPORT
122 #if UNALIGNED_INSTR_SUPPORT
123 #define DO_WORD_UNALIGNED(dst, src) { \
124 op_t val = *(src); \
125 if ((((val - mask_1) & ~val) & mask_128) != 0) { \
126 DO_BYTES(val, dst); \
127 } else { \
128 struct ulw *a = (struct ulw *)(dst); \
129 a->uli = val; \
130 } \
131 }
132 #else
133 #define DO_WORD_UNALIGNED(dst, src) { \
134 op_t val = *(src); \
135 if ((((val - mask_1) & ~val) & mask_128) != 0) { \
136 DO_BYTES(val, dst); \
137 } else { \
138 char *pdst = (char *) dst; \
139 const char *psrc = (const char *) src; \
140 for (; (*pdst = *psrc) != '\0'; ++psrc, ++pdst); \
141 return ret; \
142 } \
143 }
144 #endif /* UNALIGNED_INSTR_SUPPORT */
145
146 #define PROCESS_UNALIGNED_WORDS(a, b) { \
147 while (1) { \
148 DO_WORD_UNALIGNED(a, b); \
149 DO_WORD_UNALIGNED(a + 1, b + 1); \
150 DO_WORD_UNALIGNED(a + 2, b + 2); \
151 DO_WORD_UNALIGNED(a + 3, b + 3); \
152 a += 4; \
153 b += 4; \
154 } \
155 }
156 #endif /* HW_UNALIGNED_SUPPORT */
157
158 #define PROCESS_ALIGNED_WORDS(a, b) { \
159 while (1) { \
160 DO_WORD_ALIGNED(a, b); \
161 DO_WORD_ALIGNED(a + 1, b + 1); \
162 DO_WORD_ALIGNED(a + 2, b + 2); \
163 DO_WORD_ALIGNED(a + 3, b + 3); \
164 a += 4; \
165 b += 4; \
166 } \
167 }
168
169 char *
strcpy(char * to,const char * from)170 strcpy (char *to, const char *from) __overloadable
171 {
172 char *ret = to;
173 op_t mask_1, mask_128;
174 const op_t *src;
175 op_t *dst;
176
177 for (; (*to = *from) != '\0' && ((size_t) from % sizeof (op_t)) != 0; ++from, ++to);
178
179 if(*to != '\0') {
180 __asm__ volatile (
181 "li %0, 0x01010101 \n\t"
182 : "=r" (mask_1)
183 );
184 #if __mips64
185 mask_1 |= mask_1 << 32;
186 #endif
187 mask_128 = mask_1 << 7;
188
189 src = (const op_t *) from;
190 dst = (op_t *) to;
191
192 #if HW_UNALIGNED_SUPPORT
193 PROCESS_ALIGNED_WORDS(dst, src);
194 #else
195 if (((unsigned long) dst) % sizeof (op_t) == 0) {
196 PROCESS_ALIGNED_WORDS(dst, src);
197 } else {
198 PROCESS_UNALIGNED_WORDS(dst, src);
199 }
200 #endif
201 }
202
203 return ret;
204 }
205