Home | History | Annotate | Download | only in asm-x86
      1 #ifndef _I386_STRING_H_
      2 #define _I386_STRING_H_
      3 
      4 #ifdef __KERNEL__
      5 
      6 /* Let gcc decide wether to inline or use the out of line functions */
      7 
      8 #define __HAVE_ARCH_STRCPY
      9 extern char *strcpy(char *dest, const char *src);
     10 
     11 #define __HAVE_ARCH_STRNCPY
     12 extern char *strncpy(char *dest, const char *src, size_t count);
     13 
     14 #define __HAVE_ARCH_STRCAT
     15 extern char *strcat(char *dest, const char *src);
     16 
     17 #define __HAVE_ARCH_STRNCAT
     18 extern char *strncat(char *dest, const char *src, size_t count);
     19 
     20 #define __HAVE_ARCH_STRCMP
     21 extern int strcmp(const char *cs, const char *ct);
     22 
     23 #define __HAVE_ARCH_STRNCMP
     24 extern int strncmp(const char *cs, const char *ct, size_t count);
     25 
     26 #define __HAVE_ARCH_STRCHR
     27 extern char *strchr(const char *s, int c);
     28 
     29 #define __HAVE_ARCH_STRLEN
     30 extern size_t strlen(const char *s);
     31 
     32 static __always_inline void * __memcpy(void * to, const void * from, size_t n)
     33 {
     34 int d0, d1, d2;
     35 __asm__ __volatile__(
     36 	"rep ; movsl\n\t"
     37 	"movl %4,%%ecx\n\t"
     38 	"andl $3,%%ecx\n\t"
     39 	"jz 1f\n\t"
     40 	"rep ; movsb\n\t"
     41 	"1:"
     42 	: "=&c" (d0), "=&D" (d1), "=&S" (d2)
     43 	: "0" (n/4), "g" (n), "1" ((long) to), "2" ((long) from)
     44 	: "memory");
     45 return (to);
     46 }
     47 
     48 /*
     49  * This looks ugly, but the compiler can optimize it totally,
     50  * as the count is constant.
     51  */
     52 static __always_inline void * __constant_memcpy(void * to, const void * from, size_t n)
     53 {
     54 	long esi, edi;
     55 	if (!n) return to;
     56 #if 1	/* want to do small copies with non-string ops? */
     57 	switch (n) {
     58 		case 1: *(char*)to = *(char*)from; return to;
     59 		case 2: *(short*)to = *(short*)from; return to;
     60 		case 4: *(int*)to = *(int*)from; return to;
     61 #if 1	/* including those doable with two moves? */
     62 		case 3: *(short*)to = *(short*)from;
     63 			*((char*)to+2) = *((char*)from+2); return to;
     64 		case 5: *(int*)to = *(int*)from;
     65 			*((char*)to+4) = *((char*)from+4); return to;
     66 		case 6: *(int*)to = *(int*)from;
     67 			*((short*)to+2) = *((short*)from+2); return to;
     68 		case 8: *(int*)to = *(int*)from;
     69 			*((int*)to+1) = *((int*)from+1); return to;
     70 #endif
     71 	}
     72 #endif
     73 	esi = (long) from;
     74 	edi = (long) to;
     75 	if (n >= 5*4) {
     76 		/* large block: use rep prefix */
     77 		int ecx;
     78 		__asm__ __volatile__(
     79 			"rep ; movsl"
     80 			: "=&c" (ecx), "=&D" (edi), "=&S" (esi)
     81 			: "0" (n/4), "1" (edi),"2" (esi)
     82 			: "memory"
     83 		);
     84 	} else {
     85 		/* small block: don't clobber ecx + smaller code */
     86 		if (n >= 4*4) __asm__ __volatile__("movsl"
     87 			:"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory");
     88 		if (n >= 3*4) __asm__ __volatile__("movsl"
     89 			:"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory");
     90 		if (n >= 2*4) __asm__ __volatile__("movsl"
     91 			:"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory");
     92 		if (n >= 1*4) __asm__ __volatile__("movsl"
     93 			:"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory");
     94 	}
     95 	switch (n % 4) {
     96 		/* tail */
     97 		case 0: return to;
     98 		case 1: __asm__ __volatile__("movsb"
     99 			:"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory");
    100 			return to;
    101 		case 2: __asm__ __volatile__("movsw"
    102 			:"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory");
    103 			return to;
    104 		default: __asm__ __volatile__("movsw\n\tmovsb"
    105 			:"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory");
    106 			return to;
    107 	}
    108 }
    109 
    110 #define __HAVE_ARCH_MEMCPY
    111 
    112 #ifdef CONFIG_X86_USE_3DNOW
    113 
    114 #include <asm/mmx.h>
    115 
    116 /*
    117  *	This CPU favours 3DNow strongly (eg AMD Athlon)
    118  */
    119 
    120 static inline void * __constant_memcpy3d(void * to, const void * from, size_t len)
    121 {
    122 	if (len < 512)
    123 		return __constant_memcpy(to, from, len);
    124 	return _mmx_memcpy(to, from, len);
    125 }
    126 
    127 static __inline__ void *__memcpy3d(void *to, const void *from, size_t len)
    128 {
    129 	if (len < 512)
    130 		return __memcpy(to, from, len);
    131 	return _mmx_memcpy(to, from, len);
    132 }
    133 
    134 #define memcpy(t, f, n) \
    135 (__builtin_constant_p(n) ? \
    136  __constant_memcpy3d((t),(f),(n)) : \
    137  __memcpy3d((t),(f),(n)))
    138 
    139 #else
    140 
    141 /*
    142  *	No 3D Now!
    143  */
    144 
    145 #define memcpy(t, f, n) \
    146 (__builtin_constant_p(n) ? \
    147  __constant_memcpy((t),(f),(n)) : \
    148  __memcpy((t),(f),(n)))
    149 
    150 #endif
    151 
    152 #define __HAVE_ARCH_MEMMOVE
    153 void *memmove(void * dest,const void * src, size_t n);
    154 
    155 #define memcmp __builtin_memcmp
    156 
    157 #define __HAVE_ARCH_MEMCHR
    158 extern void *memchr(const void * cs,int c,size_t count);
    159 
    160 static inline void * __memset_generic(void * s, char c,size_t count)
    161 {
    162 int d0, d1;
    163 __asm__ __volatile__(
    164 	"rep\n\t"
    165 	"stosb"
    166 	: "=&c" (d0), "=&D" (d1)
    167 	:"a" (c),"1" (s),"0" (count)
    168 	:"memory");
    169 return s;
    170 }
    171 
    172 /* we might want to write optimized versions of these later */
    173 #define __constant_count_memset(s,c,count) __memset_generic((s),(c),(count))
    174 
    175 /*
    176  * memset(x,0,y) is a reasonably common thing to do, so we want to fill
    177  * things 32 bits at a time even when we don't know the size of the
    178  * area at compile-time..
    179  */
    180 static __always_inline void * __constant_c_memset(void * s, unsigned long c, size_t count)
    181 {
    182 int d0, d1;
    183 __asm__ __volatile__(
    184 	"rep ; stosl\n\t"
    185 	"testb $2,%b3\n\t"
    186 	"je 1f\n\t"
    187 	"stosw\n"
    188 	"1:\ttestb $1,%b3\n\t"
    189 	"je 2f\n\t"
    190 	"stosb\n"
    191 	"2:"
    192 	:"=&c" (d0), "=&D" (d1)
    193 	:"a" (c), "q" (count), "0" (count/4), "1" ((long) s)
    194 	:"memory");
    195 return (s);
    196 }
    197 
    198 /* Added by Gertjan van Wingerde to make minix and sysv module work */
    199 #define __HAVE_ARCH_STRNLEN
    200 extern size_t strnlen(const char * s, size_t count);
    201 /* end of additional stuff */
    202 
    203 #define __HAVE_ARCH_STRSTR
    204 extern char *strstr(const char *cs, const char *ct);
    205 
    206 /*
    207  * This looks horribly ugly, but the compiler can optimize it totally,
    208  * as we by now know that both pattern and count is constant..
    209  */
    210 static __always_inline void * __constant_c_and_count_memset(void * s, unsigned long pattern, size_t count)
    211 {
    212 	switch (count) {
    213 		case 0:
    214 			return s;
    215 		case 1:
    216 			*(unsigned char *)s = pattern;
    217 			return s;
    218 		case 2:
    219 			*(unsigned short *)s = pattern;
    220 			return s;
    221 		case 3:
    222 			*(unsigned short *)s = pattern;
    223 			*(2+(unsigned char *)s) = pattern;
    224 			return s;
    225 		case 4:
    226 			*(unsigned long *)s = pattern;
    227 			return s;
    228 	}
    229 #define COMMON(x) \
    230 __asm__  __volatile__( \
    231 	"rep ; stosl" \
    232 	x \
    233 	: "=&c" (d0), "=&D" (d1) \
    234 	: "a" (pattern),"0" (count/4),"1" ((long) s) \
    235 	: "memory")
    236 {
    237 	int d0, d1;
    238 	switch (count % 4) {
    239 		case 0: COMMON(""); return s;
    240 		case 1: COMMON("\n\tstosb"); return s;
    241 		case 2: COMMON("\n\tstosw"); return s;
    242 		default: COMMON("\n\tstosw\n\tstosb"); return s;
    243 	}
    244 }
    245 
    246 #undef COMMON
    247 }
    248 
    249 #define __constant_c_x_memset(s, c, count) \
    250 (__builtin_constant_p(count) ? \
    251  __constant_c_and_count_memset((s),(c),(count)) : \
    252  __constant_c_memset((s),(c),(count)))
    253 
    254 #define __memset(s, c, count) \
    255 (__builtin_constant_p(count) ? \
    256  __constant_count_memset((s),(c),(count)) : \
    257  __memset_generic((s),(c),(count)))
    258 
    259 #define __HAVE_ARCH_MEMSET
    260 #define memset(s, c, count) \
    261 (__builtin_constant_p(c) ? \
    262  __constant_c_x_memset((s),(0x01010101UL*(unsigned char)(c)),(count)) : \
    263  __memset((s),(c),(count)))
    264 
    265 /*
    266  * find the first occurrence of byte 'c', or 1 past the area if none
    267  */
    268 #define __HAVE_ARCH_MEMSCAN
    269 extern void *memscan(void * addr, int c, size_t size);
    270 
    271 #endif /* __KERNEL__ */
    272 
    273 #endif
    274