|
|
1.1 root 1: #ifndef _I386_STRING_H_
2: #define _I386_STRING_H_
3:
4: /*
5: * On a 486 or Pentium, we are better off not using the
6: * byte string operations. But on a 386 or a PPro the
7: * byte string ops are faster than doing it by hand
8: * (MUCH faster on a Pentium).
9: *
10: * Also, the byte strings actually work correctly. Forget
11: * the i486 routines for now as they may be broken..
12: */
13: #if FIXED_486_STRING && (CPU == 486 || CPU == 586)
14: #include <asm/string-486.h>
15: #else
16:
17: /*
18: * This string-include defines all string functions as inline
19: * functions. Use gcc. It also assumes ds=es=data space, this should be
20: * normal. Most of the string-functions are rather heavily hand-optimized,
21: * see especially strtok,strstr,str[c]spn. They should work, but are not
22: * very easy to understand. Everything is done entirely within the register
23: * set, making the functions fast and clean. String instructions have been
24: * used through-out, making for "slightly" unclear code :-)
25: *
26: * Copyright (C) 1991, 1992 Linus Torvalds
27: */
28:
29: #define __HAVE_ARCH_STRCPY
30: extern inline char * strcpy(char * dest,const char *src)
31: {
32: __asm__ __volatile__(
33: "cld\n"
34: "1:\tlodsb\n\t"
35: "stosb\n\t"
36: "testb %%al,%%al\n\t"
37: "jne 1b"
38: : /* no output */
39: :"S" (src),"D" (dest):"si","di","ax","memory");
40: return dest;
41: }
42:
43: #define __HAVE_ARCH_STRNCPY
44: extern inline char * strncpy(char * dest,const char *src,size_t count)
45: {
46: __asm__ __volatile__(
47: "cld\n"
48: "1:\tdecl %2\n\t"
49: "js 2f\n\t"
50: "lodsb\n\t"
51: "stosb\n\t"
52: "testb %%al,%%al\n\t"
53: "jne 1b\n\t"
54: "rep\n\t"
55: "stosb\n"
56: "2:"
57: : /* no output */
58: :"S" (src),"D" (dest),"c" (count):"si","di","ax","cx","memory");
59: return dest;
60: }
61:
62: #define __HAVE_ARCH_STRCAT
63: extern inline char * strcat(char * dest,const char * src)
64: {
65: __asm__ __volatile__(
66: "cld\n\t"
67: "repne\n\t"
68: "scasb\n\t"
69: "decl %1\n"
70: "1:\tlodsb\n\t"
71: "stosb\n\t"
72: "testb %%al,%%al\n\t"
73: "jne 1b"
74: : /* no output */
75: :"S" (src),"D" (dest),"a" (0),"c" (0xffffffff):"si","di","ax","cx");
76: return dest;
77: }
78:
79: #define __HAVE_ARCH_STRNCAT
80: extern inline char * strncat(char * dest,const char * src,size_t count)
81: {
82: __asm__ __volatile__(
83: "cld\n\t"
84: "repne\n\t"
85: "scasb\n\t"
86: "decl %1\n\t"
87: "movl %4,%3\n"
88: "1:\tdecl %3\n\t"
89: "js 2f\n\t"
90: "lodsb\n\t"
91: "stosb\n\t"
92: "testb %%al,%%al\n\t"
93: "jne 1b\n"
94: "2:\txorl %2,%2\n\t"
95: "stosb"
96: : /* no output */
97: :"S" (src),"D" (dest),"a" (0),"c" (0xffffffff),"g" (count)
98: :"si","di","ax","cx","memory");
99: return dest;
100: }
101:
102: #define __HAVE_ARCH_STRCMP
103: extern inline int strcmp(const char * cs,const char * ct)
104: {
105: register int __res;
106: __asm__ __volatile__(
107: "cld\n"
108: "1:\tlodsb\n\t"
109: "scasb\n\t"
110: "jne 2f\n\t"
111: "testb %%al,%%al\n\t"
112: "jne 1b\n\t"
113: "xorl %%eax,%%eax\n\t"
114: "jmp 3f\n"
115: "2:\tsbbl %%eax,%%eax\n\t"
116: "orb $1,%%eax\n"
117: "3:"
118: :"=a" (__res):"S" (cs),"D" (ct):"si","di");
119: return __res;
120: }
121:
122: #define __HAVE_ARCH_STRNCMP
123: extern inline int strncmp(const char * cs,const char * ct,size_t count)
124: {
125: register int __res;
126: __asm__ __volatile__(
127: "cld\n"
128: "1:\tdecl %3\n\t"
129: "js 2f\n\t"
130: "lodsb\n\t"
131: "scasb\n\t"
132: "jne 3f\n\t"
133: "testb %%al,%%al\n\t"
134: "jne 1b\n"
135: "2:\txorl %%eax,%%eax\n\t"
136: "jmp 4f\n"
137: "3:\tsbbl %%eax,%%eax\n\t"
138: "orb $1,%%al\n"
139: "4:"
140: :"=a" (__res):"S" (cs),"D" (ct),"c" (count):"si","di","cx");
141: return __res;
142: }
143:
144: #define __HAVE_ARCH_STRCHR
145: extern inline char * strchr(const char * s, int c)
146: {
147: register char * __res;
148: __asm__ __volatile__(
149: "cld\n\t"
150: "movb %%al,%%ah\n"
151: "1:\tlodsb\n\t"
152: "cmpb %%ah,%%al\n\t"
153: "je 2f\n\t"
154: "testb %%al,%%al\n\t"
155: "jne 1b\n\t"
156: "movl $1,%1\n"
157: "2:\tmovl %1,%0\n\t"
158: "decl %0"
159: :"=a" (__res):"S" (s),"0" (c):"si");
160: return __res;
161: }
162:
163: #define __HAVE_ARCH_STRRCHR
164: extern inline char * strrchr(const char * s, int c)
165: {
166: register char * __res;
167: __asm__ __volatile__(
168: "cld\n\t"
169: "movb %%al,%%ah\n"
170: "1:\tlodsb\n\t"
171: "cmpb %%ah,%%al\n\t"
172: "jne 2f\n\t"
173: "leal -1(%%esi),%0\n"
174: "2:\ttestb %%al,%%al\n\t"
175: "jne 1b"
176: :"=d" (__res):"0" (0),"S" (s),"a" (c):"ax","si");
177: return __res;
178: }
179:
180: #define __HAVE_ARCH_STRSPN
181: extern inline size_t strspn(const char * cs, const char * ct)
182: {
183: register char * __res;
184: __asm__ __volatile__(
185: "cld\n\t"
186: "movl %4,%%edi\n\t"
187: "repne\n\t"
188: "scasb\n\t"
189: "notl %%ecx\n\t"
190: "decl %%ecx\n\t"
191: "movl %%ecx,%%edx\n"
192: "1:\tlodsb\n\t"
193: "testb %%al,%%al\n\t"
194: "je 2f\n\t"
195: "movl %4,%%edi\n\t"
196: "movl %%edx,%%ecx\n\t"
197: "repne\n\t"
198: "scasb\n\t"
199: "je 1b\n"
200: "2:\tdecl %0"
201: :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
202: :"ax","cx","dx","di");
203: return __res-cs;
204: }
205:
206: #define __HAVE_ARCH_STRCSPN
207: extern inline size_t strcspn(const char * cs, const char * ct)
208: {
209: register char * __res;
210: __asm__ __volatile__(
211: "cld\n\t"
212: "movl %4,%%edi\n\t"
213: "repne\n\t"
214: "scasb\n\t"
215: "notl %%ecx\n\t"
216: "decl %%ecx\n\t"
217: "movl %%ecx,%%edx\n"
218: "1:\tlodsb\n\t"
219: "testb %%al,%%al\n\t"
220: "je 2f\n\t"
221: "movl %4,%%edi\n\t"
222: "movl %%edx,%%ecx\n\t"
223: "repne\n\t"
224: "scasb\n\t"
225: "jne 1b\n"
226: "2:\tdecl %0"
227: :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
228: :"ax","cx","dx","di");
229: return __res-cs;
230: }
231:
232: #define __HAVE_ARCH_STRPBRK
233: extern inline char * strpbrk(const char * cs,const char * ct)
234: {
235: register char * __res;
236: __asm__ __volatile__(
237: "cld\n\t"
238: "movl %4,%%edi\n\t"
239: "repne\n\t"
240: "scasb\n\t"
241: "notl %%ecx\n\t"
242: "decl %%ecx\n\t"
243: "movl %%ecx,%%edx\n"
244: "1:\tlodsb\n\t"
245: "testb %%al,%%al\n\t"
246: "je 2f\n\t"
247: "movl %4,%%edi\n\t"
248: "movl %%edx,%%ecx\n\t"
249: "repne\n\t"
250: "scasb\n\t"
251: "jne 1b\n\t"
252: "decl %0\n\t"
253: "jmp 3f\n"
254: "2:\txorl %0,%0\n"
255: "3:"
256: :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
257: :"ax","cx","dx","di");
258: return __res;
259: }
260:
261: #define __HAVE_ARCH_STRSTR
262: extern inline char * strstr(const char * cs,const char * ct)
263: {
264: register char * __res;
265: __asm__ __volatile__(
266: "cld\n\t" \
267: "repne\n\t"
268: "scasb\n\t"
269: "notl %%ecx\n\t"
270: "decl %%ecx\n\t" /* NOTE! This also sets Z if searchstring='' */
271: "movl %%ecx,%%edx\n"
272: "1:\tmovl %4,%%edi\n\t"
273: "movl %%esi,%%eax\n\t"
274: "movl %%edx,%%ecx\n\t"
275: "repe\n\t"
276: "cmpsb\n\t"
277: "je 2f\n\t" /* also works for empty string, see above */
278: "xchgl %%eax,%%esi\n\t"
279: "incl %%esi\n\t"
280: "cmpb $0,-1(%%eax)\n\t"
281: "jne 1b\n\t"
282: "xorl %%eax,%%eax\n\t"
283: "2:"
284: :"=a" (__res):"0" (0),"c" (0xffffffff),"S" (cs),"D" (ct),
285: "g" (*cs), "g" (*ct)
286: :"cx","dx","di","si");
287: return __res;
288: }
289:
290: #define __HAVE_ARCH_STRLEN
291: extern inline size_t strlen(const char * s)
292: {
293: register int __res;
294: __asm__ __volatile__(
295: "cld\n\t"
296: "repne\n\t"
297: "scasb\n\t"
298: "notl %0\n\t"
299: "decl %0"
300: :"=c" (__res):"D" (s),"a" (0),"0" (0xffffffff):"di");
301: return __res;
302: }
303:
304: #define __HAVE_ARCH_STRTOK
305: extern inline char * strtok(char * s,const char * ct)
306: {
307: register char * __res;
308: __asm__ __volatile__(
309: "testl %1,%1\n\t"
310: "jne 1f\n\t"
311: "testl %0,%0\n\t"
312: "je 8f\n\t"
313: "movl %0,%1\n"
314: "1:\txorl %0,%0\n\t"
315: "movl $-1,%%ecx\n\t"
316: "xorl %%eax,%%eax\n\t"
317: "cld\n\t"
318: "movl %4,%%edi\n\t"
319: "repne\n\t"
320: "scasb\n\t"
321: "notl %%ecx\n\t"
322: "decl %%ecx\n\t"
323: "je 7f\n\t" /* empty delimiter-string */
324: "movl %%ecx,%%edx\n"
325: "2:\tlodsb\n\t"
326: "testb %%al,%%al\n\t"
327: "je 7f\n\t"
328: "movl %4,%%edi\n\t"
329: "movl %%edx,%%ecx\n\t"
330: "repne\n\t"
331: "scasb\n\t"
332: "je 2b\n\t"
333: "decl %1\n\t"
334: "cmpb $0,(%1)\n\t"
335: "je 7f\n\t"
336: "movl %1,%0\n"
337: "3:\tlodsb\n\t"
338: "testb %%al,%%al\n\t"
339: "je 5f\n\t"
340: "movl %4,%%edi\n\t"
341: "movl %%edx,%%ecx\n\t"
342: "repne\n\t"
343: "scasb\n\t"
344: "jne 3b\n\t"
345: "decl %1\n\t"
346: "cmpb $0,(%1)\n\t"
347: "je 5f\n\t"
348: "movb $0,(%1)\n\t"
349: "incl %1\n\t"
350: "jmp 6f\n"
351: "5:\txorl %1,%1\n"
352: "6:\tcmpb $0,(%0)\n\t"
353: "jne 7f\n\t"
354: "xorl %0,%0\n"
355: "7:\ttestl %0,%0\n\t"
356: "jne 8f\n\t"
357: "movl %0,%1\n"
358: "8:"
359: :"=b" (__res),"=S" (___strtok)
360: :"0" (___strtok),"1" (s),"g" (ct)
361: :"ax","cx","dx","di","memory");
362: return __res;
363: }
364:
365: extern inline void * __memcpy(void * to, const void * from, size_t n)
366: {
367: __asm__ __volatile__(
368: "cld\n\t"
369: "rep ; movsl\n\t"
370: "testb $2,%b1\n\t"
371: "je 1f\n\t"
372: "movsw\n"
373: "1:\ttestb $1,%b1\n\t"
374: "je 2f\n\t"
375: "movsb\n"
376: "2:"
377: : /* no output */
378: :"c" (n/4), "q" (n),"D" ((long) to),"S" ((long) from)
379: : "cx","di","si","memory");
380: return (to);
381: }
382:
383: /*
384: * This looks horribly ugly, but the compiler can optimize it totally,
385: * as the count is constant.
386: */
387: extern inline void * __constant_memcpy(void * to, const void * from, size_t n)
388: {
389: switch (n) {
390: case 0:
391: return to;
392: case 1:
393: *(unsigned char *)to = *(const unsigned char *)from;
394: return to;
395: case 2:
396: *(unsigned short *)to = *(const unsigned short *)from;
397: return to;
398: case 3:
399: *(unsigned short *)to = *(const unsigned short *)from;
400: *(2+(unsigned char *)to) = *(2+(const unsigned char *)from);
401: return to;
402: case 4:
403: *(unsigned long *)to = *(const unsigned long *)from;
404: return to;
405: case 8:
406: *(unsigned long *)to = *(const unsigned long *)from;
407: *(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
408: return to;
409: case 12:
410: *(unsigned long *)to = *(const unsigned long *)from;
411: *(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
412: *(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
413: return to;
414: case 16:
415: *(unsigned long *)to = *(const unsigned long *)from;
416: *(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
417: *(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
418: *(3+(unsigned long *)to) = *(3+(const unsigned long *)from);
419: return to;
420: case 20:
421: *(unsigned long *)to = *(const unsigned long *)from;
422: *(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
423: *(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
424: *(3+(unsigned long *)to) = *(3+(const unsigned long *)from);
425: *(4+(unsigned long *)to) = *(4+(const unsigned long *)from);
426: return to;
427: }
428: #define COMMON(x) \
429: __asm__("cld\n\t" \
430: "rep ; movsl" \
431: x \
432: : /* no outputs */ \
433: : "c" (n/4),"D" ((long) to),"S" ((long) from) \
434: : "cx","di","si","memory");
435:
436: switch (n % 4) {
437: case 0: COMMON(""); return to;
438: case 1: COMMON("\n\tmovsb"); return to;
439: case 2: COMMON("\n\tmovsw"); return to;
440: default: COMMON("\n\tmovsw\n\tmovsb"); return to;
441: }
442: #undef COMMON
443: }
444:
445: #define __HAVE_ARCH_MEMCPY
446: #define memcpy(t, f, n) \
447: (__builtin_constant_p(n) ? \
448: __constant_memcpy((t),(f),(n)) : \
449: __memcpy((t),(f),(n)))
450:
451: #define __HAVE_ARCH_MEMMOVE
452: extern inline void * memmove(void * dest,const void * src, size_t n)
453: {
454: if (dest<src)
455: __asm__ __volatile__(
456: "cld\n\t"
457: "rep\n\t"
458: "movsb"
459: : /* no output */
460: :"c" (n),"S" (src),"D" (dest)
461: :"cx","si","di");
462: else
463: __asm__ __volatile__(
464: "std\n\t"
465: "rep\n\t"
466: "movsb\n\t"
467: "cld"
468: : /* no output */
469: :"c" (n),
470: "S" (n-1+(const char *)src),
471: "D" (n-1+(char *)dest)
472: :"cx","si","di","memory");
473: return dest;
474: }
475:
476: #define memcmp __builtin_memcmp
477:
478: #define __HAVE_ARCH_MEMCHR
479: extern inline void * memchr(const void * cs,int c,size_t count)
480: {
481: register void * __res;
482: if (!count)
483: return NULL;
484: __asm__ __volatile__(
485: "cld\n\t"
486: "repne\n\t"
487: "scasb\n\t"
488: "je 1f\n\t"
489: "movl $1,%0\n"
490: "1:\tdecl %0"
491: :"=D" (__res):"a" (c),"D" (cs),"c" (count)
492: :"cx");
493: return __res;
494: }
495:
496: extern inline void * __memset_generic(void * s, char c,size_t count)
497: {
498: __asm__ __volatile__(
499: "cld\n\t"
500: "rep\n\t"
501: "stosb"
502: : /* no output */
503: :"a" (c),"D" (s),"c" (count)
504: :"cx","di","memory");
505: return s;
506: }
507:
508: /* we might want to write optimized versions of these later */
509: #define __constant_count_memset(s,c,count) __memset_generic((s),(c),(count))
510:
511: /*
512: * memset(x,0,y) is a reasonably common thing to do, so we want to fill
513: * things 32 bits at a time even when we don't know the size of the
514: * area at compile-time..
515: */
516: extern inline void * __constant_c_memset(void * s, unsigned long c, size_t count)
517: {
518: __asm__ __volatile__(
519: "cld\n\t"
520: "rep ; stosl\n\t"
521: "testb $2,%b1\n\t"
522: "je 1f\n\t"
523: "stosw\n"
524: "1:\ttestb $1,%b1\n\t"
525: "je 2f\n\t"
526: "stosb\n"
527: "2:"
528: : /* no output */
529: :"a" (c), "q" (count), "c" (count/4), "D" ((long) s)
530: :"cx","di","memory");
531: return (s);
532: }
533:
534: /* Added by Gertjan van Wingerde to make minix and sysv module work */
535: #define __HAVE_ARCH_STRNLEN
536: extern inline size_t strnlen(const char * s, size_t count)
537: {
538: register int __res;
539: __asm__ __volatile__(
540: "movl %1,%0\n\t"
541: "jmp 2f\n"
542: "1:\tcmpb $0,(%0)\n\t"
543: "je 3f\n\t"
544: "incl %0\n"
545: "2:\tdecl %2\n\t"
546: "cmpl $-1,%2\n\t"
547: "jne 1b\n"
548: "3:\tsubl %1,%0"
549: :"=a" (__res)
550: :"c" (s),"d" (count)
551: :"dx");
552: return __res;
553: }
554: /* end of additional stuff */
555:
556: /*
557: * This looks horribly ugly, but the compiler can optimize it totally,
558: * as we by now know that both pattern and count is constant..
559: */
560: extern inline void * __constant_c_and_count_memset(void * s, unsigned long pattern, size_t count)
561: {
562: switch (count) {
563: case 0:
564: return s;
565: case 1:
566: *(unsigned char *)s = pattern;
567: return s;
568: case 2:
569: *(unsigned short *)s = pattern;
570: return s;
571: case 3:
572: *(unsigned short *)s = pattern;
573: *(2+(unsigned char *)s) = pattern;
574: return s;
575: case 4:
576: *(unsigned long *)s = pattern;
577: return s;
578: }
579: #define COMMON(x) \
580: __asm__("cld\n\t" \
581: "rep ; stosl" \
582: x \
583: : /* no outputs */ \
584: : "a" (pattern),"c" (count/4),"D" ((long) s) \
585: : "cx","di","memory")
586:
587: switch (count % 4) {
588: case 0: COMMON(""); return s;
589: case 1: COMMON("\n\tstosb"); return s;
590: case 2: COMMON("\n\tstosw"); return s;
591: default: COMMON("\n\tstosw\n\tstosb"); return s;
592: }
593: #undef COMMON
594: }
595:
596: #define __constant_c_x_memset(s, c, count) \
597: (__builtin_constant_p(count) ? \
598: __constant_c_and_count_memset((s),(c),(count)) : \
599: __constant_c_memset((s),(c),(count)))
600:
601: #define __memset(s, c, count) \
602: (__builtin_constant_p(count) ? \
603: __constant_count_memset((s),(c),(count)) : \
604: __memset_generic((s),(c),(count)))
605:
606: #define __HAVE_ARCH_MEMSET
607: #define memset(s, c, count) \
608: (__builtin_constant_p(c) ? \
609: __constant_c_x_memset((s),(0x01010101UL*(unsigned char)c),(count)) : \
610: __memset((s),(c),(count)))
611:
612: /*
613: * find the first occurrence of byte 'c', or 1 past the area if none
614: */
615: #define __HAVE_ARCH_MEMSCAN
616: extern inline void * memscan(void * addr, int c, size_t size)
617: {
618: if (!size)
619: return addr;
620: __asm__("cld
621: repnz; scasb
622: jnz 1f
623: dec %%edi
624: 1: "
625: : "=D" (addr), "=c" (size)
626: : "0" (addr), "1" (size), "a" (c));
627: return addr;
628: }
629:
630: #endif
631: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.