1/*
2 * Taken from Linux /usr/include/asm/string.h
3 * All except memcpy, memmove, memset and memcmp removed.
4 */
5
6#ifndef	_I386_STRING_H_
7#define _I386_STRING_H_
8
9/*
10 * This string-include defines all string functions as inline
11 * functions. Use gcc. It also assumes ds=es=data space, this should be
12 * normal. Most of the string-functions are rather heavily hand-optimized,
13 * see especially strtok,strstr,str[c]spn. They should work, but are not
14 * very easy to understand. Everything is done entirely within the register
15 * set, making the functions fast and clean. String instructions have been
16 * used through-out, making for "slightly" unclear code :-)
17 *
18 *		NO Copyright (C) 1991, 1992 Linus Torvalds,
19 *		consider these trivial functions to be PD.
20 */
21
22typedef int	size_t;
23
24extern void *__memcpy(void * to, const void * from, size_t n);
25extern void *__constant_memcpy(void * to, const void * from, size_t n);
26extern void *memmove(void * dest,const void * src, size_t n);
27extern void *__memset_generic(void * s, char c,size_t count);
28extern void *__constant_c_memset(void * s, unsigned long c, size_t count);
29extern void *__constant_c_and_count_memset(void * s, unsigned long pattern, size_t count);
30
31
32extern inline void * __memcpy(void * to, const void * from, size_t n)
33{
34int d0, d1, d2;
35__asm__ __volatile__(
36	"cld\n\t"
37	"rep ; movsl\n\t"
38	"testb $2,%b4\n\t"
39	"je 1f\n\t"
40	"movsw\n"
41	"1:\ttestb $1,%b4\n\t"
42	"je 2f\n\t"
43	"movsb\n"
44	"2:"
45	: "=&c" (d0), "=&D" (d1), "=&S" (d2)
46	:"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
47	: "memory");
48return (to);
49}
50
51/*
52 * This looks horribly ugly, but the compiler can optimize it totally,
53 * as the count is constant.
54 */
55extern inline void * __constant_memcpy(void * to, const void * from, size_t n)
56{
57	switch (n) {
58		case 0:
59			return to;
60		case 1:
61			*(unsigned char *)to = *(const unsigned char *)from;
62			return to;
63		case 2:
64			*(unsigned short *)to = *(const unsigned short *)from;
65			return to;
66		case 3:
67			*(unsigned short *)to = *(const unsigned short *)from;
68			*(2+(unsigned char *)to) = *(2+(const unsigned char *)from);
69			return to;
70		case 4:
71			*(unsigned long *)to = *(const unsigned long *)from;
72			return to;
73		case 6:	/* for Ethernet addresses */
74			*(unsigned long *)to = *(const unsigned long *)from;
75			*(2+(unsigned short *)to) = *(2+(const unsigned short *)from);
76			return to;
77		case 8:
78			*(unsigned long *)to = *(const unsigned long *)from;
79			*(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
80			return to;
81		case 12:
82			*(unsigned long *)to = *(const unsigned long *)from;
83			*(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
84			*(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
85			return to;
86		case 16:
87			*(unsigned long *)to = *(const unsigned long *)from;
88			*(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
89			*(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
90			*(3+(unsigned long *)to) = *(3+(const unsigned long *)from);
91			return to;
92		case 20:
93			*(unsigned long *)to = *(const unsigned long *)from;
94			*(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
95			*(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
96			*(3+(unsigned long *)to) = *(3+(const unsigned long *)from);
97			*(4+(unsigned long *)to) = *(4+(const unsigned long *)from);
98			return to;
99	}
100#define COMMON(x) \
101__asm__ __volatile__( \
102	"cld\n\t" \
103	"rep ; movsl" \
104	x \
105	: "=&c" (d0), "=&D" (d1), "=&S" (d2) \
106	: "0" (n/4),"1" ((long) to),"2" ((long) from) \
107	: "memory");
108{
109	int d0, d1, d2;
110	switch (n % 4) {
111		case 0: COMMON(""); return to;
112		case 1: COMMON("\n\tmovsb"); return to;
113		case 2: COMMON("\n\tmovsw"); return to;
114		default: COMMON("\n\tmovsw\n\tmovsb"); return to;
115	}
116}
117
118#undef COMMON
119}
120
121#define __HAVE_ARCH_MEMCPY
122#define memcpy(t, f, n) \
123(__builtin_constant_p(n) ? \
124 __constant_memcpy((t),(f),(n)) : \
125 __memcpy((t),(f),(n)))
126
127#define __HAVE_ARCH_MEMMOVE
128extern inline void * memmove(void * dest,const void * src, size_t n)
129{
130int d0, d1, d2;
131if (dest<src)
132__asm__ __volatile__(
133	"cld\n\t"
134	"rep\n\t"
135	"movsb"
136	: "=&c" (d0), "=&S" (d1), "=&D" (d2)
137	:"0" (n),"1" (src),"2" (dest)
138	: "memory");
139else
140__asm__ __volatile__(
141	"std\n\t"
142	"rep\n\t"
143	"movsb\n\t"
144	"cld"
145	: "=&c" (d0), "=&S" (d1), "=&D" (d2)
146	:"0" (n),
147	 "1" (n-1+(const char *)src),
148	 "2" (n-1+(char *)dest)
149	:"memory");
150return dest;
151}
152
153#define memcmp __builtin_memcmp
154
155extern inline void * __memset_generic(void * s, char c,size_t count)
156{
157int d0, d1;
158__asm__ __volatile__(
159	"cld\n\t"
160	"rep\n\t"
161	"stosb"
162	: "=&c" (d0), "=&D" (d1)
163	:"a" (c),"1" (s),"0" (count)
164	:"memory");
165return s;
166}
167
168/* we might want to write optimized versions of these later */
169#define __constant_count_memset(s,c,count) __memset_generic((s),(c),(count))
170
171/*
172 * memset(x,0,y) is a reasonably common thing to do, so we want to fill
173 * things 32 bits at a time even when we don't know the size of the
174 * area at compile-time..
175 */
176extern inline void * __constant_c_memset(void * s, unsigned long c, size_t count)
177{
178int d0, d1;
179__asm__ __volatile__(
180	"cld\n\t"
181	"rep ; stosl\n\t"
182	"testb $2,%b3\n\t"
183	"je 1f\n\t"
184	"stosw\n"
185	"1:\ttestb $1,%b3\n\t"
186	"je 2f\n\t"
187	"stosb\n"
188	"2:"
189	: "=&c" (d0), "=&D" (d1)
190	:"a" (c), "q" (count), "0" (count/4), "1" ((long) s)
191	:"memory");
192return (s);
193}
194
195/*
196 * This looks horribly ugly, but the compiler can optimize it totally,
197 * as we by now know that both pattern and count is constant..
198 */
199extern inline void * __constant_c_and_count_memset(void * s, unsigned long pattern, size_t count)
200{
201	switch (count) {
202		case 0:
203			return s;
204		case 1:
205			*(unsigned char *)s = pattern;
206			return s;
207		case 2:
208			*(unsigned short *)s = pattern;
209			return s;
210		case 3:
211			*(unsigned short *)s = pattern;
212			*(2+(unsigned char *)s) = pattern;
213			return s;
214		case 4:
215			*(unsigned long *)s = pattern;
216			return s;
217	}
218#define COMMON(x) \
219__asm__  __volatile__("cld\n\t" \
220	"rep ; stosl" \
221	x \
222	: "=&c" (d0), "=&D" (d1) \
223	: "a" (pattern),"0" (count/4),"1" ((long) s) \
224	: "memory")
225{
226	int d0, d1;
227	switch (count % 4) {
228		case 0: COMMON(""); return s;
229		case 1: COMMON("\n\tstosb"); return s;
230		case 2: COMMON("\n\tstosw"); return s;
231		default: COMMON("\n\tstosw\n\tstosb"); return s;
232	}
233}
234
235#undef COMMON
236}
237
238#define __constant_c_x_memset(s, c, count) \
239(__builtin_constant_p(count) ? \
240 __constant_c_and_count_memset((s),(c),(count)) : \
241 __constant_c_memset((s),(c),(count)))
242
243#define __memset(s, c, count) \
244(__builtin_constant_p(count) ? \
245 __constant_count_memset((s),(c),(count)) : \
246 __memset_generic((s),(c),(count)))
247
248#define __HAVE_ARCH_MEMSET
249#define memset(s, c, count) \
250(__builtin_constant_p(c) ? \
251 __constant_c_x_memset((s),(c),(count)) : \
252 __memset((s),(c),(count)))
253
254#define __HAVE_ARCH_STRNCMP
255static inline int strncmp(const char * cs,const char * ct,size_t count)
256{
257register int __res;
258int d0, d1, d2;
259__asm__ __volatile__(
260	"1:\tdecl %3\n\t"
261	"js 2f\n\t"
262	"lodsb\n\t"
263	"scasb\n\t"
264	"jne 3f\n\t"
265	"testb %%al,%%al\n\t"
266	"jne 1b\n"
267	"2:\txorl %%eax,%%eax\n\t"
268	"jmp 4f\n"
269	"3:\tsbbl %%eax,%%eax\n\t"
270	"orb $1,%%al\n"
271	"4:"
272		     :"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
273		     :"1" (cs),"2" (ct),"3" (count));
274return __res;
275}
276
277#define __HAVE_ARCH_STRLEN
278static inline size_t strlen(const char * s)
279{
280int d0;
281register int __res;
282__asm__ __volatile__(
283	"repne\n\t"
284	"scasb\n\t"
285	"notl %0\n\t"
286	"decl %0"
287	:"=c" (__res), "=&D" (d0) :"1" (s),"a" (0), "0" (0xffffffff));
288return __res;
289}
290
291#endif
292