This commit was manufactured by cvs2svn to create tag
[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 /*
62  * This is a more generic variant of strncpy_count() suitable for
63  * implementing string-access routines with all sorts of return
64  * code semantics. It's used by mm/usercopy.c.
65  */
66 static inline size_t strncpy_count(char * dest,const char *src,size_t count)
67 {
68         __asm__ __volatile__(
69
70         "1:\tdecl %0\n\t"
71         "js 2f\n\t"
72         "lodsb\n\t"
73         "stosb\n\t"
74         "testb %%al,%%al\n\t"
75         "jne 1b\n\t"
76         "2:"
77         "incl %0"
78         : "=c" (count)
79         :"S" (src),"D" (dest),"0" (count) : "memory");
80
81         return count;
82 }
83
84 static inline char * strcat(char * dest,const char * src)
85 {
86 int d0, d1, d2, d3;
87 __asm__ __volatile__(
88         "repne\n\t"
89         "scasb\n\t"
90         "decl %1\n"
91         "1:\tlodsb\n\t"
92         "stosb\n\t"
93         "testb %%al,%%al\n\t"
94         "jne 1b"
95         : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
96         : "0" (src), "1" (dest), "2" (0), "3" (0xffffffffu):"memory");
97 return dest;
98 }
99
100 static inline char * strncat(char * dest,const char * src,size_t count)
101 {
102 int d0, d1, d2, d3;
103 __asm__ __volatile__(
104         "repne\n\t"
105         "scasb\n\t"
106         "decl %1\n\t"
107         "movl %8,%3\n"
108         "1:\tdecl %3\n\t"
109         "js 2f\n\t"
110         "lodsb\n\t"
111         "stosb\n\t"
112         "testb %%al,%%al\n\t"
113         "jne 1b\n"
114         "2:\txorl %2,%2\n\t"
115         "stosb"
116         : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
117         : "0" (src),"1" (dest),"2" (0),"3" (0xffffffffu), "g" (count)
118         : "memory");
119 return dest;
120 }
121
122 static inline int strcmp(const char * cs,const char * ct)
123 {
124 int d0, d1;
125 register int __res;
126 __asm__ __volatile__(
127         "1:\tlodsb\n\t"
128         "scasb\n\t"
129         "jne 2f\n\t"
130         "testb %%al,%%al\n\t"
131         "jne 1b\n\t"
132         "xorl %%eax,%%eax\n\t"
133         "jmp 3f\n"
134         "2:\tsbbl %%eax,%%eax\n\t"
135         "orb $1,%%al\n"
136         "3:"
137         :"=a" (__res), "=&S" (d0), "=&D" (d1)
138                      :"1" (cs),"2" (ct));
139 return __res;
140 }
141
142 static inline int strncmp(const char * cs,const char * ct,size_t count)
143 {
144 register int __res;
145 int d0, d1, d2;
146 __asm__ __volatile__(
147         "1:\tdecl %3\n\t"
148         "js 2f\n\t"
149         "lodsb\n\t"
150         "scasb\n\t"
151         "jne 3f\n\t"
152         "testb %%al,%%al\n\t"
153         "jne 1b\n"
154         "2:\txorl %%eax,%%eax\n\t"
155         "jmp 4f\n"
156         "3:\tsbbl %%eax,%%eax\n\t"
157         "orb $1,%%al\n"
158         "4:"
159                      :"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
160                      :"1" (cs),"2" (ct),"3" (count));
161 return __res;
162 }
163
164 static inline char * strchr(const char * s, int c)
165 {
166 int d0;
167 register char * __res;
168 __asm__ __volatile__(
169         "movb %%al,%%ah\n"
170         "1:\tlodsb\n\t"
171         "cmpb %%ah,%%al\n\t"
172         "je 2f\n\t"
173         "testb %%al,%%al\n\t"
174         "jne 1b\n\t"
175         "movl $1,%1\n"
176         "2:\tmovl %1,%0\n\t"
177         "decl %0"
178         :"=a" (__res), "=&S" (d0) : "1" (s),"0" (c));
179 return __res;
180 }
181
182 static inline char * strrchr(const char * s, int c)
183 {
184 int d0, d1;
185 register char * __res;
186 __asm__ __volatile__(
187         "movb %%al,%%ah\n"
188         "1:\tlodsb\n\t"
189         "cmpb %%ah,%%al\n\t"
190         "jne 2f\n\t"
191         "leal -1(%%esi),%0\n"
192         "2:\ttestb %%al,%%al\n\t"
193         "jne 1b"
194         :"=g" (__res), "=&S" (d0), "=&a" (d1) :"0" (0),"1" (s),"2" (c));
195 return __res;
196 }
197
198 #endif
199
200 #define __HAVE_ARCH_STRLEN
201 static inline size_t strlen(const char * s)
202 {
203 int d0;
204 register int __res;
205 __asm__ __volatile__(
206         "repne\n\t"
207         "scasb\n\t"
208         "notl %0\n\t"
209         "decl %0"
210         :"=c" (__res), "=&D" (d0) :"1" (s),"a" (0), "0" (0xffffffffu));
211 return __res;
212 }
213
214 static inline void * __memcpy(void * to, const void * from, size_t n)
215 {
216 int d0, d1, d2;
217 __asm__ __volatile__(
218         "rep ; movsl\n\t"
219         "testb $2,%b4\n\t"
220         "je 1f\n\t"
221         "movsw\n"
222         "1:\ttestb $1,%b4\n\t"
223         "je 2f\n\t"
224         "movsb\n"
225         "2:"
226         : "=&c" (d0), "=&D" (d1), "=&S" (d2)
227         :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
228         : "memory");
229 return (to);
230 }
231
232 /*
233  * This looks horribly ugly, but the compiler can optimize it totally,
234  * as the count is constant.
235  */
236 static inline void * __constant_memcpy(void * to, const void * from, size_t n)
237 {
238         if (n <= 128)
239                 return __builtin_memcpy(to, from, n);
240
241 #define COMMON(x) \
242 __asm__ __volatile__( \
243         "rep ; movsl" \
244         x \
245         : "=&c" (d0), "=&D" (d1), "=&S" (d2) \
246         : "0" (n/4),"1" ((long) to),"2" ((long) from) \
247         : "memory");
248 {
249         int d0, d1, d2;
250         switch (n % 4) {
251                 case 0: COMMON(""); return to;
252                 case 1: COMMON("\n\tmovsb"); return to;
253                 case 2: COMMON("\n\tmovsw"); return to;
254                 default: COMMON("\n\tmovsw\n\tmovsb"); return to;
255         }
256 }
257   
258 #undef COMMON
259 }
260
261 #define __HAVE_ARCH_MEMCPY
262
263 #ifdef CONFIG_X86_USE_3DNOW
264
265 #include <asm/mmx.h>
266
267 /*
268  *      This CPU favours 3DNow strongly (eg AMD Athlon)
269  */
270
271 static inline void * __constant_memcpy3d(void * to, const void * from, size_t len)
272 {
273         if (len < 512)
274                 return __constant_memcpy(to, from, len);
275         return _mmx_memcpy(to, from, len);
276 }
277
278 static __inline__ void *__memcpy3d(void *to, const void *from, size_t len)
279 {
280         if (len < 512)
281                 return __memcpy(to, from, len);
282         return _mmx_memcpy(to, from, len);
283 }
284
285 #define memcpy(t, f, n) \
286 (__builtin_constant_p(n) ? \
287  __constant_memcpy3d((t),(f),(n)) : \
288  __memcpy3d((t),(f),(n)))
289
290 #else
291
292 /*
293  *      No 3D Now!
294  */
295  
296 #define memcpy(t, f, n) \
297 (__builtin_constant_p(n) ? \
298  __constant_memcpy((t),(f),(n)) : \
299  __memcpy((t),(f),(n)))
300
301 #endif
302
303 #define __HAVE_ARCH_MEMMOVE
304 void *memmove(void * dest,const void * src, size_t n);
305
306 #define memcmp __builtin_memcmp
307
308 #define __HAVE_ARCH_MEMCHR
309 static inline void * memchr(const void * cs,int c,size_t count)
310 {
311 int d0;
312 register void * __res;
313 if (!count)
314         return NULL;
315 __asm__ __volatile__(
316         "repne\n\t"
317         "scasb\n\t"
318         "je 1f\n\t"
319         "movl $1,%0\n"
320         "1:\tdecl %0"
321         :"=D" (__res), "=&c" (d0) : "a" (c),"0" (cs),"1" (count));
322 return __res;
323 }
324
325 static inline void * __memset_generic(void * s, char c,size_t count)
326 {
327 int d0, d1;
328 __asm__ __volatile__(
329         "rep\n\t"
330         "stosb"
331         : "=&c" (d0), "=&D" (d1)
332         :"a" (c),"1" (s),"0" (count)
333         :"memory");
334 return s;
335 }
336
337 /* we might want to write optimized versions of these later */
338 #define __constant_count_memset(s,c,count) __memset_generic((s),(c),(count))
339
340 /*
341  * memset(x,0,y) is a reasonably common thing to do, so we want to fill
342  * things 32 bits at a time even when we don't know the size of the
343  * area at compile-time..
344  */
345 static inline void * __constant_c_memset(void * s, unsigned long c, size_t count)
346 {
347 int d0, d1;
348 __asm__ __volatile__(
349         "rep ; stosl\n\t"
350         "testb $2,%b3\n\t"
351         "je 1f\n\t"
352         "stosw\n"
353         "1:\ttestb $1,%b3\n\t"
354         "je 2f\n\t"
355         "stosb\n"
356         "2:"
357         : "=&c" (d0), "=&D" (d1)
358         :"a" (c), "q" (count), "0" (count/4), "1" ((long) s)
359         :"memory");
360 return (s);     
361 }
362
363 /* Added by Gertjan van Wingerde to make minix and sysv module work */
364 #define __HAVE_ARCH_STRNLEN
365 static inline size_t strnlen(const char * s, size_t count)
366 {
367 int d0;
368 register int __res;
369 __asm__ __volatile__(
370         "movl %2,%0\n\t"
371         "jmp 2f\n"
372         "1:\tcmpb $0,(%0)\n\t"
373         "je 3f\n\t"
374         "incl %0\n"
375         "2:\tdecl %1\n\t"
376         "cmpl $-1,%1\n\t"
377         "jne 1b\n"
378         "3:\tsubl %2,%0"
379         :"=a" (__res), "=&d" (d0)
380         :"c" (s),"1" (count));
381 return __res;
382 }
383 /* end of additional stuff */
384
385 #define __HAVE_ARCH_STRSTR
386
387 extern char *strstr(const char *cs, const char *ct);
388
389 /*
390  * This looks horribly ugly, but the compiler can optimize it totally,
391  * as we by now know that both pattern and count is constant..
392  */
393 static inline void * __constant_c_and_count_memset(void * s, unsigned long pattern, size_t count)
394 {
395         switch (count) {
396                 case 0:
397                         return s;
398                 case 1:
399                         *(unsigned char *)s = pattern;
400                         return s;
401                 case 2:
402                         *(unsigned short *)s = pattern;
403                         return s;
404                 case 3:
405                         *(unsigned short *)s = pattern;
406                         *(2+(unsigned char *)s) = pattern;
407                         return s;
408                 case 4:
409                         *(unsigned long *)s = pattern;
410                         return s;
411         }
412 #define COMMON(x) \
413 __asm__  __volatile__( \
414         "rep ; stosl" \
415         x \
416         : "=&c" (d0), "=&D" (d1) \
417         : "a" (pattern),"0" (count/4),"1" ((long) s) \
418         : "memory")
419 {
420         int d0, d1;
421         switch (count % 4) {
422                 case 0: COMMON(""); return s;
423                 case 1: COMMON("\n\tstosb"); return s;
424                 case 2: COMMON("\n\tstosw"); return s;
425                 default: COMMON("\n\tstosw\n\tstosb"); return s;
426         }
427 }
428   
429 #undef COMMON
430 }
431
432 #define __constant_c_x_memset(s, c, count) \
433 (__builtin_constant_p(count) ? \
434  __constant_c_and_count_memset((s),(c),(count)) : \
435  __constant_c_memset((s),(c),(count)))
436
437 #define __memset(s, c, count) \
438 (__builtin_constant_p(count) ? \
439  __constant_count_memset((s),(c),(count)) : \
440  __memset_generic((s),(c),(count)))
441
442 #define __HAVE_ARCH_MEMSET
443 #define memset(s, c, count) \
444 (__builtin_constant_p(c) ? \
445  __constant_c_x_memset((s),(0x01010101UL*(unsigned char)(c)),(count)) : \
446  __memset((s),(c),(count)))
447
448 /*
449  * find the first occurrence of byte 'c', or 1 past the area if none
450  */
451 #define __HAVE_ARCH_MEMSCAN
452 static inline void * memscan(void * addr, int c, size_t size)
453 {
454         if (!size)
455                 return addr;
456         __asm__("repnz; scasb\n\t"
457                 "jnz 1f\n\t"
458                 "dec %%edi\n"
459                 "1:"
460                 : "=D" (addr), "=c" (size)
461                 : "0" (addr), "1" (size), "a" (c));
462         return addr;
463 }
464
465 #endif /* __KERNEL__ */
466
467 #endif