string_32.h 7.3 KB
Newer Older
V
Vegard Nossum 已提交
1 2
#ifndef ASM_X86__STRING_32_H
#define ASM_X86__STRING_32_H
L
Linus Torvalds 已提交
3 4 5

#ifdef __KERNEL__

6
/* Let gcc decide whether to inline or use the out of line functions */
L
Linus Torvalds 已提交
7 8

#define __HAVE_ARCH_STRCPY
9
extern char *strcpy(char *dest, const char *src);
L
Linus Torvalds 已提交
10 11

#define __HAVE_ARCH_STRNCPY
12
extern char *strncpy(char *dest, const char *src, size_t count);
L
Linus Torvalds 已提交
13 14

#define __HAVE_ARCH_STRCAT
15
extern char *strcat(char *dest, const char *src);
L
Linus Torvalds 已提交
16 17

#define __HAVE_ARCH_STRNCAT
18
extern char *strncat(char *dest, const char *src, size_t count);
L
Linus Torvalds 已提交
19 20

#define __HAVE_ARCH_STRCMP
21
extern int strcmp(const char *cs, const char *ct);
L
Linus Torvalds 已提交
22 23

#define __HAVE_ARCH_STRNCMP
24
extern int strncmp(const char *cs, const char *ct, size_t count);
L
Linus Torvalds 已提交
25 26

#define __HAVE_ARCH_STRCHR
27
extern char *strchr(const char *s, int c);
L
Linus Torvalds 已提交
28 29

#define __HAVE_ARCH_STRLEN
30
extern size_t strlen(const char *s);
L
Linus Torvalds 已提交
31

32
static __always_inline void *__memcpy(void *to, const void *from, size_t n)
L
Linus Torvalds 已提交
33
{
34 35 36 37 38 39 40 41 42 43 44
	int d0, d1, d2;
	asm volatile("rep ; movsl\n\t"
		     "movl %4,%%ecx\n\t"
		     "andl $3,%%ecx\n\t"
		     "jz 1f\n\t"
		     "rep ; movsb\n\t"
		     "1:"
		     : "=&c" (d0), "=&D" (d1), "=&S" (d2)
		     : "0" (n / 4), "g" (n), "1" ((long)to), "2" ((long)from)
		     : "memory");
	return to;
L
Linus Torvalds 已提交
45 46 47
}

/*
D
Denis Vlasenko 已提交
48
 * This looks ugly, but the compiler can optimize it totally,
L
Linus Torvalds 已提交
49 50
 * as the count is constant.
 */
51 52
static __always_inline void *__constant_memcpy(void *to, const void *from,
					       size_t n)
L
Linus Torvalds 已提交
53
{
D
Denis Vlasenko 已提交
54
	long esi, edi;
55 56 57
	if (!n)
		return to;

D
Denis Vlasenko 已提交
58
	switch (n) {
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
	case 1:
		*(char *)to = *(char *)from;
		return to;
	case 2:
		*(short *)to = *(short *)from;
		return to;
	case 4:
		*(int *)to = *(int *)from;
		return to;

	case 3:
		*(short *)to = *(short *)from;
		*((char *)to + 2) = *((char *)from + 2);
		return to;
	case 5:
		*(int *)to = *(int *)from;
		*((char *)to + 4) = *((char *)from + 4);
		return to;
	case 6:
		*(int *)to = *(int *)from;
		*((short *)to + 2) = *((short *)from + 2);
		return to;
	case 8:
		*(int *)to = *(int *)from;
		*((int *)to + 1) = *((int *)from + 1);
		return to;
D
Denis Vlasenko 已提交
85
	}
86 87 88 89

	esi = (long)from;
	edi = (long)to;
	if (n >= 5 * 4) {
D
Denis Vlasenko 已提交
90 91
		/* large block: use rep prefix */
		int ecx;
92 93 94 95
		asm volatile("rep ; movsl"
			     : "=&c" (ecx), "=&D" (edi), "=&S" (esi)
			     : "0" (n / 4), "1" (edi), "2" (esi)
			     : "memory"
D
Denis Vlasenko 已提交
96 97 98
		);
	} else {
		/* small block: don't clobber ecx + smaller code */
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
		if (n >= 4 * 4)
			asm volatile("movsl"
				     : "=&D"(edi), "=&S"(esi)
				     : "0"(edi), "1"(esi)
				     : "memory");
		if (n >= 3 * 4)
			asm volatile("movsl"
				     : "=&D"(edi), "=&S"(esi)
				     : "0"(edi), "1"(esi)
				     : "memory");
		if (n >= 2 * 4)
			asm volatile("movsl"
				     : "=&D"(edi), "=&S"(esi)
				     : "0"(edi), "1"(esi)
				     : "memory");
		if (n >= 1 * 4)
			asm volatile("movsl"
				     : "=&D"(edi), "=&S"(esi)
				     : "0"(edi), "1"(esi)
				     : "memory");
D
Denis Vlasenko 已提交
119
	}
L
Linus Torvalds 已提交
120
	switch (n % 4) {
D
Denis Vlasenko 已提交
121
		/* tail */
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
	case 0:
		return to;
	case 1:
		asm volatile("movsb"
			     : "=&D"(edi), "=&S"(esi)
			     : "0"(edi), "1"(esi)
			     : "memory");
		return to;
	case 2:
		asm volatile("movsw"
			     : "=&D"(edi), "=&S"(esi)
			     : "0"(edi), "1"(esi)
			     : "memory");
		return to;
	default:
		asm volatile("movsw\n\tmovsb"
			     : "=&D"(edi), "=&S"(esi)
			     : "0"(edi), "1"(esi)
			     : "memory");
		return to;
L
Linus Torvalds 已提交
142 143 144 145 146 147 148 149 150 151 152 153 154
	}
}

#define __HAVE_ARCH_MEMCPY

#ifdef CONFIG_X86_USE_3DNOW

#include <asm/mmx.h>

/*
 *	This CPU favours 3DNow strongly (eg AMD Athlon)
 */

155
static inline void *__constant_memcpy3d(void *to, const void *from, size_t len)
L
Linus Torvalds 已提交
156 157 158 159 160 161
{
	if (len < 512)
		return __constant_memcpy(to, from, len);
	return _mmx_memcpy(to, from, len);
}

162
static inline void *__memcpy3d(void *to, const void *from, size_t len)
L
Linus Torvalds 已提交
163 164 165 166 167 168
{
	if (len < 512)
		return __memcpy(to, from, len);
	return _mmx_memcpy(to, from, len);
}

169 170 171 172
#define memcpy(t, f, n)				\
	(__builtin_constant_p((n))		\
	 ? __constant_memcpy3d((t), (f), (n))	\
	 : __memcpy3d((t), (f), (n)))
L
Linus Torvalds 已提交
173 174 175 176 177 178

#else

/*
 *	No 3D Now!
 */
179 180 181 182 183

#define memcpy(t, f, n)				\
	(__builtin_constant_p((n))		\
	 ? __constant_memcpy((t), (f), (n))	\
	 : __memcpy((t), (f), (n)))
L
Linus Torvalds 已提交
184 185 186 187

#endif

#define __HAVE_ARCH_MEMMOVE
188
void *memmove(void *dest, const void *src, size_t n);
L
Linus Torvalds 已提交
189 190 191 192

#define memcmp __builtin_memcmp

#define __HAVE_ARCH_MEMCHR
193
extern void *memchr(const void *cs, int c, size_t count);
L
Linus Torvalds 已提交
194

195
static inline void *__memset_generic(void *s, char c, size_t count)
L
Linus Torvalds 已提交
196
{
197 198 199 200 201 202 203
	int d0, d1;
	asm volatile("rep\n\t"
		     "stosb"
		     : "=&c" (d0), "=&D" (d1)
		     : "a" (c), "1" (s), "0" (count)
		     : "memory");
	return s;
L
Linus Torvalds 已提交
204 205 206
}

/* we might want to write optimized versions of these later */
207
#define __constant_count_memset(s, c, count) __memset_generic((s), (c), (count))
L
Linus Torvalds 已提交
208 209

/*
210
 * memset(x, 0, y) is a reasonably common thing to do, so we want to fill
L
Linus Torvalds 已提交
211 212 213
 * things 32 bits at a time even when we don't know the size of the
 * area at compile-time..
 */
214 215
static __always_inline
void *__constant_c_memset(void *s, unsigned long c, size_t count)
L
Linus Torvalds 已提交
216
{
217 218 219 220 221 222 223 224 225 226 227 228 229
	int d0, d1;
	asm volatile("rep ; stosl\n\t"
		     "testb $2,%b3\n\t"
		     "je 1f\n\t"
		     "stosw\n"
		     "1:\ttestb $1,%b3\n\t"
		     "je 2f\n\t"
		     "stosb\n"
		     "2:"
		     : "=&c" (d0), "=&D" (d1)
		     : "a" (c), "q" (count), "0" (count/4), "1" ((long)s)
		     : "memory");
	return s;
L
Linus Torvalds 已提交
230 231 232 233
}

/* Added by Gertjan van Wingerde to make minix and sysv module work */
#define __HAVE_ARCH_STRNLEN
234
extern size_t strnlen(const char *s, size_t count);
L
Linus Torvalds 已提交
235 236 237 238 239 240 241 242 243
/* end of additional stuff */

#define __HAVE_ARCH_STRSTR
extern char *strstr(const char *cs, const char *ct);

/*
 * This looks horribly ugly, but the compiler can optimize it totally,
 * as we by now know that both pattern and count is constant..
 */
244 245 246
static __always_inline
void *__constant_c_and_count_memset(void *s, unsigned long pattern,
				    size_t count)
L
Linus Torvalds 已提交
247 248
{
	switch (count) {
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
	case 0:
		return s;
	case 1:
		*(unsigned char *)s = pattern & 0xff;
		return s;
	case 2:
		*(unsigned short *)s = pattern & 0xffff;
		return s;
	case 3:
		*(unsigned short *)s = pattern & 0xffff;
		*((unsigned char *)s + 2) = pattern & 0xff;
		return s;
	case 4:
		*(unsigned long *)s = pattern;
		return s;
	}

#define COMMON(x)							\
	asm volatile("rep ; stosl"					\
		     x							\
		     : "=&c" (d0), "=&D" (d1)				\
270
		     : "a" (eax), "0" (count/4), "1" ((long)s)	\
271 272 273 274
		     : "memory")

	{
		int d0, d1;
275 276 277 278 279 280 281
#if __GNUC__ == 4 && __GNUC_MINOR__ == 0
		/* Workaround for broken gcc 4.0 */
		register unsigned long eax asm("%eax") = pattern;
#else
		unsigned long eax = pattern;
#endif

282
		switch (count % 4) {
L
Linus Torvalds 已提交
283
		case 0:
284
			COMMON("");
L
Linus Torvalds 已提交
285 286
			return s;
		case 1:
287
			COMMON("\n\tstosb");
L
Linus Torvalds 已提交
288 289
			return s;
		case 2:
290
			COMMON("\n\tstosw");
L
Linus Torvalds 已提交
291
			return s;
292 293
		default:
			COMMON("\n\tstosw\n\tstosb");
L
Linus Torvalds 已提交
294
			return s;
295
		}
L
Linus Torvalds 已提交
296
	}
297

L
Linus Torvalds 已提交
298 299 300
#undef COMMON
}

301 302 303 304
#define __constant_c_x_memset(s, c, count)			\
	(__builtin_constant_p(count)				\
	 ? __constant_c_and_count_memset((s), (c), (count))	\
	 : __constant_c_memset((s), (c), (count)))
L
Linus Torvalds 已提交
305

306 307 308 309
#define __memset(s, c, count)				\
	(__builtin_constant_p(count)			\
	 ? __constant_count_memset((s), (c), (count))	\
	 : __memset_generic((s), (c), (count)))
L
Linus Torvalds 已提交
310 311

#define __HAVE_ARCH_MEMSET
312 313 314 315 316
#define memset(s, c, count)						\
	(__builtin_constant_p(c)					\
	 ? __constant_c_x_memset((s), (0x01010101UL * (unsigned char)(c)), \
				 (count))				\
	 : __memset((s), (c), (count)))
L
Linus Torvalds 已提交
317 318 319 320 321

/*
 * find the first occurrence of byte 'c', or 1 past the area if none
 */
#define __HAVE_ARCH_MEMSCAN
322
extern void *memscan(void *addr, int c, size_t size);
L
Linus Torvalds 已提交
323 324 325

#endif /* __KERNEL__ */

V
Vegard Nossum 已提交
326
#endif /* ASM_X86__STRING_32_H */