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