ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / include / asm-i386 / string.h
1 #ifndef _I386_STRING_H_
2 #define _I386_STRING_H_
3
4 #ifdef __KERNEL__
5 #include <linux/config.h>
6 /*
7  * On a 486 or Pentium, we are better off not using the
8  * byte string operations. But on a 386 or a PPro the
9  * byte string ops are faster than doing it by hand
10  * (MUCH faster on a Pentium).
11  */
12
13 /*
14  * This string-include defines all string functions as inline
15  * functions. Use gcc. It also assumes ds=es=data space, this should be
16  * normal. Most of the string-functions are rather heavily hand-optimized,
17  * see especially strsep,strstr,str[c]spn. They should work, but are not
18  * very easy to understand. Everything is done entirely within the register
19  * set, making the functions fast and clean. String instructions have been
20  * used through-out, making for "slightly" unclear code :-)
21  *
22  *              NO Copyright (C) 1991, 1992 Linus Torvalds,
23  *              consider these trivial functions to be PD.
24  */
25
26 /* AK: in fact I bet it would be better to move this stuff all out of line.
27  */
28 #if !defined(IN_STRING_C)
29
30 static inline char * strcpy(char * dest,const char *src)
31 {
32 int d0, d1, d2;
33 __asm__ __volatile__(
34         "1:\tlodsb\n\t"
35         "stosb\n\t"
36         "testb %%al,%%al\n\t"
37         "jne 1b"
38         : "=&S" (d0), "=&D" (d1), "=&a" (d2)
39         :"0" (src),"1" (dest) : "memory");
40 return dest;
41 }
42
43 static inline char * strncpy(char * dest,const char *src,size_t count)
44 {
45 int d0, d1, d2, d3;
46 __asm__ __volatile__(
47         "1:\tdecl %2\n\t"
48         "js 2f\n\t"
49         "lodsb\n\t"
50         "stosb\n\t"
51         "testb %%al,%%al\n\t"
52         "jne 1b\n\t"
53         "rep\n\t"
54         "stosb\n"
55         "2:"
56         : "=&S" (d0), "=&D" (d1), "=&c" (d2), "=&a" (d3)
57         :"0" (src),"1" (dest),"2" (count) : "memory");
58 return dest;
59 }
60
61 static inline char * strcat(char * dest,const char * src)
62 {
63 int d0, d1, d2, d3;
64 __asm__ __volatile__(
65         "repne\n\t"
66         "scasb\n\t"
67         "decl %1\n"
68         "1:\tlodsb\n\t"
69         "stosb\n\t"
70         "testb %%al,%%al\n\t"
71         "jne 1b"
72         : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
73         : "0" (src), "1" (dest), "2" (0), "3" (0xffffffffu):"memory");
74 return dest;
75 }
76
77 static inline char * strncat(char * dest,const char * src,size_t count)
78 {
79 int d0, d1, d2, d3;
80 __asm__ __volatile__(
81         "repne\n\t"
82         "scasb\n\t"
83         "decl %1\n\t"
84         "movl %8,%3\n"
85         "1:\tdecl %3\n\t"
86         "js 2f\n\t"
87         "lodsb\n\t"
88         "stosb\n\t"
89         "testb %%al,%%al\n\t"
90         "jne 1b\n"
91         "2:\txorl %2,%2\n\t"
92         "stosb"
93         : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
94         : "0" (src),"1" (dest),"2" (0),"3" (0xffffffffu), "g" (count)
95         : "memory");
96 return dest;
97 }
98
99 static inline int strcmp(const char * cs,const char * ct)
100 {
101 int d0, d1;
102 register int __res;
103 __asm__ __volatile__(
104         "1:\tlodsb\n\t"
105         "scasb\n\t"
106         "jne 2f\n\t"
107         "testb %%al,%%al\n\t"
108         "jne 1b\n\t"
109         "xorl %%eax,%%eax\n\t"
110         "jmp 3f\n"
111         "2:\tsbbl %%eax,%%eax\n\t"
112         "orb $1,%%al\n"
113         "3:"
114         :"=a" (__res), "=&S" (d0), "=&D" (d1)
115                      :"1" (cs),"2" (ct));
116 return __res;
117 }
118
119 static inline int strncmp(const char * cs,const char * ct,size_t count)
120 {
121 register int __res;
122 int d0, d1, d2;
123 __asm__ __volatile__(
124         "1:\tdecl %3\n\t"
125         "js 2f\n\t"
126         "lodsb\n\t"
127         "scasb\n\t"
128         "jne 3f\n\t"
129         "testb %%al,%%al\n\t"
130         "jne 1b\n"
131         "2:\txorl %%eax,%%eax\n\t"
132         "jmp 4f\n"
133         "3:\tsbbl %%eax,%%eax\n\t"
134         "orb $1,%%al\n"
135         "4:"
136                      :"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
137                      :"1" (cs),"2" (ct),"3" (count));
138 return __res;
139 }
140
141 static inline char * strchr(const char * s, int c)
142 {
143 int d0;
144 register char * __res;
145 __asm__ __volatile__(
146         "movb %%al,%%ah\n"
147         "1:\tlodsb\n\t"
148         "cmpb %%ah,%%al\n\t"
149         "je 2f\n\t"
150         "testb %%al,%%al\n\t"
151         "jne 1b\n\t"
152         "movl $1,%1\n"
153         "2:\tmovl %1,%0\n\t"
154         "decl %0"
155         :"=a" (__res), "=&S" (d0) : "1" (s),"0" (c));
156 return __res;
157 }
158
159 static inline char * strrchr(const char * s, int c)
160 {
161 int d0, d1;
162 register char * __res;
163 __asm__ __volatile__(
164         "movb %%al,%%ah\n"
165         "1:\tlodsb\n\t"
166         "cmpb %%ah,%%al\n\t"
167         "jne 2f\n\t"
168         "leal -1(%%esi),%0\n"
169         "2:\ttestb %%al,%%al\n\t"
170         "jne 1b"
171         :"=g" (__res), "=&S" (d0), "=&a" (d1) :"0" (0),"1" (s),"2" (c));
172 return __res;
173 }
174
175 #endif
176
177 #define __HAVE_ARCH_STRLEN
178 static inline size_t strlen(const char * s)
179 {
180 int d0;
181 register int __res;
182 __asm__ __volatile__(
183         "repne\n\t"
184         "scasb\n\t"
185         "notl %0\n\t"
186         "decl %0"
187         :"=c" (__res), "=&D" (d0) :"1" (s),"a" (0), "0" (0xffffffffu));
188 return __res;
189 }
190
191 static inline void * __memcpy(void * to, const void * from, size_t n)
192 {
193 int d0, d1, d2;
194 __asm__ __volatile__(
195         "rep ; movsl\n\t"
196         "testb $2,%b4\n\t"
197         "je 1f\n\t"
198         "movsw\n"
199         "1:\ttestb $1,%b4\n\t"
200         "je 2f\n\t"
201         "movsb\n"
202         "2:"
203         : "=&c" (d0), "=&D" (d1), "=&S" (d2)
204         :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
205         : "memory");
206 return (to);
207 }
208
209 /*
210  * This looks horribly ugly, but the compiler can optimize it totally,
211  * as the count is constant.
212  */
213 static inline void * __constant_memcpy(void * to, const void * from, size_t n)
214 {
215         if (n <= 128)
216                 return __builtin_memcpy(to, from, n);
217
218 #define COMMON(x) \
219 __asm__ __volatile__( \
220         "rep ; movsl" \
221         x \
222         : "=&c" (d0), "=&D" (d1), "=&S" (d2) \
223         : "0" (n/4),"1" ((long) to),"2" ((long) from) \
224         : "memory");
225 {
226         int d0, d1, d2;
227         switch (n % 4) {
228                 case 0: COMMON(""); return to;
229                 case 1: COMMON("\n\tmovsb"); return to;
230                 case 2: COMMON("\n\tmovsw"); return to;
231                 default: COMMON("\n\tmovsw\n\tmovsb"); return to;
232         }
233 }
234   
235 #undef COMMON
236 }
237
238 #define __HAVE_ARCH_MEMCPY
239
240 #ifdef CONFIG_X86_USE_3DNOW
241
242 #include <asm/mmx.h>
243
244 /*
245  *      This CPU favours 3DNow strongly (eg AMD Athlon)
246  */
247
248 static inline void * __constant_memcpy3d(void * to, const void * from, size_t len)
249 {
250         if (len < 512)
251                 return __constant_memcpy(to, from, len);
252         return _mmx_memcpy(to, from, len);
253 }
254
255 static __inline__ void *__memcpy3d(void *to, const void *from, size_t len)
256 {
257         if (len < 512)
258                 return __memcpy(to, from, len);
259         return _mmx_memcpy(to, from, len);
260 }
261
262 #define memcpy(t, f, n) \
263 (__builtin_constant_p(n) ? \
264  __constant_memcpy3d((t),(f),(n)) : \
265  __memcpy3d((t),(f),(n)))
266
267 #else
268
269 /*
270  *      No 3D Now!
271  */
272  
273 #define memcpy(t, f, n) \
274 (__builtin_constant_p(n) ? \
275  __constant_memcpy((t),(f),(n)) : \
276  __memcpy((t),(f),(n)))
277
278 #endif
279
280 /*
281  * struct_cpy(x,y), copy structure *x into (matching structure) *y.
282  *
283  * We get link-time errors if the structure sizes do not match.
284  * There is no runtime overhead, it's all optimized away at
285  * compile time.
286  */
287 extern void __struct_cpy_bug (void);
288
289 #define struct_cpy(x,y)                         \
290 ({                                              \
291         if (sizeof(*(x)) != sizeof(*(y)))       \
292                 __struct_cpy_bug();             \
293         memcpy(x, y, sizeof(*(x)));             \
294 })
295
296 #define __HAVE_ARCH_MEMMOVE
297 static inline void * memmove(void * dest,const void * src, size_t n)
298 {
299 int d0, d1, d2;
300 if (dest<src) {
301         memcpy(dest,src,n);
302 } else
303 __asm__ __volatile__(
304         "std\n\t"
305         "rep\n\t"
306         "movsb\n\t"
307         "cld"
308         : "=&c" (d0), "=&S" (d1), "=&D" (d2)
309         :"0" (n),
310          "1" (n-1+(const char *)src),
311          "2" (n-1+(char *)dest)
312         :"memory");
313 return dest;
314 }
315
316 #define memcmp __builtin_memcmp
317
318 #define __HAVE_ARCH_MEMCHR
319 static inline void * memchr(const void * cs,int c,size_t count)
320 {
321 int d0;
322 register void * __res;
323 if (!count)
324         return NULL;
325 __asm__ __volatile__(
326         "repne\n\t"
327         "scasb\n\t"
328         "je 1f\n\t"
329         "movl $1,%0\n"
330         "1:\tdecl %0"
331         :"=D" (__res), "=&c" (d0) : "a" (c),"0" (cs),"1" (count));
332 return __res;
333 }
334
335 static inline void * __memset_generic(void * s, char c,size_t count)
336 {
337 int d0, d1;
338 __asm__ __volatile__(
339         "rep\n\t"
340         "stosb"
341         : "=&c" (d0), "=&D" (d1)
342         :"a" (c),"1" (s),"0" (count)
343         :"memory");
344 return s;
345 }
346
347 /* we might want to write optimized versions of these later */
348 #define __constant_count_memset(s,c,count) __memset_generic((s),(c),(count))
349
350 /*
351  * memset(x,0,y) is a reasonably common thing to do, so we want to fill
352  * things 32 bits at a time even when we don't know the size of the
353  * area at compile-time..
354  */
355 static inline void * __constant_c_memset(void * s, unsigned long c, size_t count)
356 {
357 int d0, d1;
358 __asm__ __volatile__(
359         "rep ; stosl\n\t"
360         "testb $2,%b3\n\t"
361         "je 1f\n\t"
362         "stosw\n"
363         "1:\ttestb $1,%b3\n\t"
364         "je 2f\n\t"
365         "stosb\n"
366         "2:"
367         : "=&c" (d0), "=&D" (d1)
368         :"a" (c), "q" (count), "0" (count/4), "1" ((long) s)
369         :"memory");
370 return (s);     
371 }
372
373 /* Added by Gertjan van Wingerde to make minix and sysv module work */
374 #define __HAVE_ARCH_STRNLEN
375 static inline size_t strnlen(const char * s, size_t count)
376 {
377 int d0;
378 register int __res;
379 __asm__ __volatile__(
380         "movl %2,%0\n\t"
381         "jmp 2f\n"
382         "1:\tcmpb $0,(%0)\n\t"
383         "je 3f\n\t"
384         "incl %0\n"
385         "2:\tdecl %1\n\t"
386         "cmpl $-1,%1\n\t"
387         "jne 1b\n"
388         "3:\tsubl %2,%0"
389         :"=a" (__res), "=&d" (d0)
390         :"c" (s),"1" (count));
391 return __res;
392 }
393 /* end of additional stuff */
394
395 #define __HAVE_ARCH_STRSTR
396
397 extern char *strstr(const char *cs, const char *ct);
398
399 /*
400  * This looks horribly ugly, but the compiler can optimize it totally,
401  * as we by now know that both pattern and count is constant..
402  */
403 static inline void * __constant_c_and_count_memset(void * s, unsigned long pattern, size_t count)
404 {
405         switch (count) {
406                 case 0:
407                         return s;
408                 case 1:
409                         *(unsigned char *)s = pattern;
410                         return s;
411                 case 2:
412                         *(unsigned short *)s = pattern;
413                         return s;
414                 case 3:
415                         *(unsigned short *)s = pattern;
416                         *(2+(unsigned char *)s) = pattern;
417                         return s;
418                 case 4:
419                         *(unsigned long *)s = pattern;
420                         return s;
421         }
422 #define COMMON(x) \
423 __asm__  __volatile__( \
424         "rep ; stosl" \
425         x \
426         : "=&c" (d0), "=&D" (d1) \
427         : "a" (pattern),"0" (count/4),"1" ((long) s) \
428         : "memory")
429 {
430         int d0, d1;
431         switch (count % 4) {
432                 case 0: COMMON(""); return s;
433                 case 1: COMMON("\n\tstosb"); return s;
434                 case 2: COMMON("\n\tstosw"); return s;
435                 default: COMMON("\n\tstosw\n\tstosb"); return s;
436         }
437 }
438   
439 #undef COMMON
440 }
441
442 #define __constant_c_x_memset(s, c, count) \
443 (__builtin_constant_p(count) ? \
444  __constant_c_and_count_memset((s),(c),(count)) : \
445  __constant_c_memset((s),(c),(count)))
446
447 #define __memset(s, c, count) \
448 (__builtin_constant_p(count) ? \
449  __constant_count_memset((s),(c),(count)) : \
450  __memset_generic((s),(c),(count)))
451
452 #define __HAVE_ARCH_MEMSET
453 #define memset(s, c, count) \
454 (__builtin_constant_p(c) ? \
455  __constant_c_x_memset((s),(0x01010101UL*(unsigned char)(c)),(count)) : \
456  __memset((s),(c),(count)))
457
458 /*
459  * find the first occurrence of byte 'c', or 1 past the area if none
460  */
461 #define __HAVE_ARCH_MEMSCAN
462 static inline void * memscan(void * addr, int c, size_t size)
463 {
464         if (!size)
465                 return addr;
466         __asm__("repnz; scasb\n\t"
467                 "jnz 1f\n\t"
468                 "dec %%edi\n"
469                 "1:"
470                 : "=D" (addr), "=c" (size)
471                 : "0" (addr), "1" (size), "a" (c));
472         return addr;
473 }
474
475 #endif /* __KERNEL__ */
476
477 #endif