linux-old/include/asm-i386/string.h
<<
>>
Prefs
   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 * Also, the byte strings actually work correctly. Forget
  13 * the i486 routines for now as they may be broken..
  14 */
  15#if FIXED_486_STRING && defined(CONFIG_X86_USE_STRING_486)
  16#include <asm/string-486.h>
  17#else
  18
  19/*
  20 * This string-include defines all string functions as inline
  21 * functions. Use gcc. It also assumes ds=es=data space, this should be
  22 * normal. Most of the string-functions are rather heavily hand-optimized,
  23 * see especially strtok,strstr,str[c]spn. They should work, but are not
  24 * very easy to understand. Everything is done entirely within the register
  25 * set, making the functions fast and clean. String instructions have been
  26 * used through-out, making for "slightly" unclear code :-)
  27 *
  28 *              NO Copyright (C) 1991, 1992 Linus Torvalds,
  29 *              consider these trivial functions to be PD.
  30 */
  31
  32#define __HAVE_ARCH_STRCPY
  33static inline char * strcpy(char * dest,const char *src)
  34{
  35int d0, d1, d2;
  36__asm__ __volatile__(
  37        "1:\tlodsb\n\t"
  38        "stosb\n\t"
  39        "testb %%al,%%al\n\t"
  40        "jne 1b"
  41        : "=&S" (d0), "=&D" (d1), "=&a" (d2)
  42        :"0" (src),"1" (dest) : "memory");
  43return dest;
  44}
  45
  46#define __HAVE_ARCH_STRNCPY
  47static inline char * strncpy(char * dest,const char *src,size_t count)
  48{
  49int d0, d1, d2, d3;
  50__asm__ __volatile__(
  51        "1:\tdecl %2\n\t"
  52        "js 2f\n\t"
  53        "lodsb\n\t"
  54        "stosb\n\t"
  55        "testb %%al,%%al\n\t"
  56        "jne 1b\n\t"
  57        "rep\n\t"
  58        "stosb\n"
  59        "2:"
  60        : "=&S" (d0), "=&D" (d1), "=&c" (d2), "=&a" (d3)
  61        :"0" (src),"1" (dest),"2" (count) : "memory");
  62return dest;
  63}
  64
  65#define __HAVE_ARCH_STRCAT
  66static inline char * strcat(char * dest,const char * src)
  67{
  68int d0, d1, d2, d3;
  69__asm__ __volatile__(
  70        "repne\n\t"
  71        "scasb\n\t"
  72        "decl %1\n"
  73        "1:\tlodsb\n\t"
  74        "stosb\n\t"
  75        "testb %%al,%%al\n\t"
  76        "jne 1b"
  77        : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
  78        : "0" (src), "1" (dest), "2" (0), "3" (0xffffffff):"memory");
  79return dest;
  80}
  81
  82#define __HAVE_ARCH_STRNCAT
  83static inline char * strncat(char * dest,const char * src,size_t count)
  84{
  85int d0, d1, d2, d3;
  86__asm__ __volatile__(
  87        "repne\n\t"
  88        "scasb\n\t"
  89        "decl %1\n\t"
  90        "movl %8,%3\n"
  91        "1:\tdecl %3\n\t"
  92        "js 2f\n\t"
  93        "lodsb\n\t"
  94        "stosb\n\t"
  95        "testb %%al,%%al\n\t"
  96        "jne 1b\n"
  97        "2:\txorl %2,%2\n\t"
  98        "stosb"
  99        : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
 100        : "0" (src),"1" (dest),"2" (0),"3" (0xffffffff), "g" (count)
 101        : "memory");
 102return dest;
 103}
 104
 105#define __HAVE_ARCH_STRCMP
 106static inline int strcmp(const char * cs,const char * ct)
 107{
 108int d0, d1;
 109register int __res;
 110__asm__ __volatile__(
 111        "1:\tlodsb\n\t"
 112        "scasb\n\t"
 113        "jne 2f\n\t"
 114        "testb %%al,%%al\n\t"
 115        "jne 1b\n\t"
 116        "xorl %%eax,%%eax\n\t"
 117        "jmp 3f\n"
 118        "2:\tsbbl %%eax,%%eax\n\t"
 119        "orb $1,%%al\n"
 120        "3:"
 121        :"=a" (__res), "=&S" (d0), "=&D" (d1)
 122                     :"1" (cs),"2" (ct));
 123return __res;
 124}
 125
 126#define __HAVE_ARCH_STRNCMP
 127static inline int strncmp(const char * cs,const char * ct,size_t count)
 128{
 129register int __res;
 130int d0, d1, d2;
 131__asm__ __volatile__(
 132        "1:\tdecl %3\n\t"
 133        "js 2f\n\t"
 134        "lodsb\n\t"
 135        "scasb\n\t"
 136        "jne 3f\n\t"
 137        "testb %%al,%%al\n\t"
 138        "jne 1b\n"
 139        "2:\txorl %%eax,%%eax\n\t"
 140        "jmp 4f\n"
 141        "3:\tsbbl %%eax,%%eax\n\t"
 142        "orb $1,%%al\n"
 143        "4:"
 144                     :"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
 145                     :"1" (cs),"2" (ct),"3" (count));
 146return __res;
 147}
 148
 149#define __HAVE_ARCH_STRCHR
 150static inline char * strchr(const char * s, int c)
 151{
 152int d0;
 153register char * __res;
 154__asm__ __volatile__(
 155        "movb %%al,%%ah\n"
 156        "1:\tlodsb\n\t"
 157        "cmpb %%ah,%%al\n\t"
 158        "je 2f\n\t"
 159        "testb %%al,%%al\n\t"
 160        "jne 1b\n\t"
 161        "movl $1,%1\n"
 162        "2:\tmovl %1,%0\n\t"
 163        "decl %0"
 164        :"=a" (__res), "=&S" (d0) : "1" (s),"0" (c));
 165return __res;
 166}
 167
 168#define __HAVE_ARCH_STRRCHR
 169static inline char * strrchr(const char * s, int c)
 170{
 171int d0, d1;
 172register char * __res;
 173__asm__ __volatile__(
 174        "movb %%al,%%ah\n"
 175        "1:\tlodsb\n\t"
 176        "cmpb %%ah,%%al\n\t"
 177        "jne 2f\n\t"
 178        "leal -1(%%esi),%0\n"
 179        "2:\ttestb %%al,%%al\n\t"
 180        "jne 1b"
 181        :"=g" (__res), "=&S" (d0), "=&a" (d1) :"0" (0),"1" (s),"2" (c));
 182return __res;
 183}
 184
 185#define __HAVE_ARCH_STRLEN
 186static inline size_t strlen(const char * s)
 187{
 188int d0;
 189register int __res;
 190__asm__ __volatile__(
 191        "repne\n\t"
 192        "scasb\n\t"
 193        "notl %0\n\t"
 194        "decl %0"
 195        :"=c" (__res), "=&D" (d0) :"1" (s),"a" (0), "0" (0xffffffff));
 196return __res;
 197}
 198
 199static inline void * __memcpy(void * to, const void * from, size_t n)
 200{
 201int d0, d1, d2;
 202__asm__ __volatile__(
 203        "rep ; movsl\n\t"
 204        "testb $2,%b4\n\t"
 205        "je 1f\n\t"
 206        "movsw\n"
 207        "1:\ttestb $1,%b4\n\t"
 208        "je 2f\n\t"
 209        "movsb\n"
 210        "2:"
 211        : "=&c" (d0), "=&D" (d1), "=&S" (d2)
 212        :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
 213        : "memory");
 214return (to);
 215}
 216
 217/*
 218 * This looks horribly ugly, but the compiler can optimize it totally,
 219 * as the count is constant.
 220 */
 221static inline void * __constant_memcpy(void * to, const void * from, size_t n)
 222{
 223        switch (n) {
 224                case 0:
 225                        return to;
 226                case 1:
 227                        *(unsigned char *)to = *(const unsigned char *)from;
 228                        return to;
 229                case 2:
 230                        *(unsigned short *)to = *(const unsigned short *)from;
 231                        return to;
 232                case 3:
 233                        *(unsigned short *)to = *(const unsigned short *)from;
 234                        *(2+(unsigned char *)to) = *(2+(const unsigned char *)from);
 235                        return to;
 236                case 4:
 237                        *(unsigned long *)to = *(const unsigned long *)from;
 238                        return to;
 239                case 6: /* for Ethernet addresses */
 240                        *(unsigned long *)to = *(const unsigned long *)from;
 241                        *(2+(unsigned short *)to) = *(2+(const unsigned short *)from);
 242                        return to;
 243                case 8:
 244                        *(unsigned long *)to = *(const unsigned long *)from;
 245                        *(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
 246                        return to;
 247                case 12:
 248                        *(unsigned long *)to = *(const unsigned long *)from;
 249                        *(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
 250                        *(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
 251                        return to;
 252                case 16:
 253                        *(unsigned long *)to = *(const unsigned long *)from;
 254                        *(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
 255                        *(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
 256                        *(3+(unsigned long *)to) = *(3+(const unsigned long *)from);
 257                        return to;
 258                case 20:
 259                        *(unsigned long *)to = *(const unsigned long *)from;
 260                        *(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
 261                        *(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
 262                        *(3+(unsigned long *)to) = *(3+(const unsigned long *)from);
 263                        *(4+(unsigned long *)to) = *(4+(const unsigned long *)from);
 264                        return to;
 265        }
 266#define COMMON(x) \
 267__asm__ __volatile__( \
 268        "rep ; movsl" \
 269        x \
 270        : "=&c" (d0), "=&D" (d1), "=&S" (d2) \
 271        : "0" (n/4),"1" ((long) to),"2" ((long) from) \
 272        : "memory");
 273{
 274        int d0, d1, d2;
 275        switch (n % 4) {
 276                case 0: COMMON(""); return to;
 277                case 1: COMMON("\n\tmovsb"); return to;
 278                case 2: COMMON("\n\tmovsw"); return to;
 279                default: COMMON("\n\tmovsw\n\tmovsb"); return to;
 280        }
 281}
 282  
 283#undef COMMON
 284}
 285
 286#define __HAVE_ARCH_MEMCPY
 287
 288#ifdef CONFIG_X86_USE_3DNOW
 289
 290#include <asm/mmx.h>
 291
 292/*
 293 *      This CPU favours 3DNow strongly (eg AMD Athlon)
 294 */
 295
 296static inline void * __constant_memcpy3d(void * to, const void * from, size_t len)
 297{
 298        if (len < 512)
 299                return __constant_memcpy(to, from, len);
 300        return _mmx_memcpy(to, from, len);
 301}
 302
 303static __inline__ void *__memcpy3d(void *to, const void *from, size_t len)
 304{
 305        if (len < 512)
 306                return __memcpy(to, from, len);
 307        return _mmx_memcpy(to, from, len);
 308}
 309
 310#define memcpy(t, f, n) \
 311(__builtin_constant_p(n) ? \
 312 __constant_memcpy3d((t),(f),(n)) : \
 313 __memcpy3d((t),(f),(n)))
 314
 315#else
 316
 317/*
 318 *      No 3D Now!
 319 */
 320 
 321#define memcpy(t, f, n) \
 322(__builtin_constant_p(n) ? \
 323 __constant_memcpy((t),(f),(n)) : \
 324 __memcpy((t),(f),(n)))
 325
 326#endif
 327
 328/*
 329 * struct_cpy(x,y), copy structure *x into (matching structure) *y.
 330 *
 331 * We get link-time errors if the structure sizes do not match.
 332 * There is no runtime overhead, it's all optimized away at
 333 * compile time.
 334 */
 335extern void __struct_cpy_bug (void);
 336
 337#define struct_cpy(x,y)                         \
 338({                                              \
 339        if (sizeof(*(x)) != sizeof(*(y)))       \
 340                __struct_cpy_bug;               \
 341        memcpy(x, y, sizeof(*(x)));             \
 342})
 343
 344#define __HAVE_ARCH_MEMMOVE
 345static inline void * memmove(void * dest,const void * src, size_t n)
 346{
 347int d0, d1, d2;
 348if (dest<src)
 349__asm__ __volatile__(
 350        "rep\n\t"
 351        "movsb"
 352        : "=&c" (d0), "=&S" (d1), "=&D" (d2)
 353        :"0" (n),"1" (src),"2" (dest)
 354        : "memory");
 355else
 356__asm__ __volatile__(
 357        "std\n\t"
 358        "rep\n\t"
 359        "movsb\n\t"
 360        "cld"
 361        : "=&c" (d0), "=&S" (d1), "=&D" (d2)
 362        :"0" (n),
 363         "1" (n-1+(const char *)src),
 364         "2" (n-1+(char *)dest)
 365        :"memory");
 366return dest;
 367}
 368
 369#define memcmp __builtin_memcmp
 370
 371#define __HAVE_ARCH_MEMCHR
 372static inline void * memchr(const void * cs,int c,size_t count)
 373{
 374int d0;
 375register void * __res;
 376if (!count)
 377        return NULL;
 378__asm__ __volatile__(
 379        "repne\n\t"
 380        "scasb\n\t"
 381        "je 1f\n\t"
 382        "movl $1,%0\n"
 383        "1:\tdecl %0"
 384        :"=D" (__res), "=&c" (d0) : "a" (c),"0" (cs),"1" (count));
 385return __res;
 386}
 387
 388static inline void * __memset_generic(void * s, char c,size_t count)
 389{
 390int d0, d1;
 391__asm__ __volatile__(
 392        "rep\n\t"
 393        "stosb"
 394        : "=&c" (d0), "=&D" (d1)
 395        :"a" (c),"1" (s),"0" (count)
 396        :"memory");
 397return s;
 398}
 399
 400/* we might want to write optimized versions of these later */
 401#define __constant_count_memset(s,c,count) __memset_generic((s),(c),(count))
 402
 403/*
 404 * memset(x,0,y) is a reasonably common thing to do, so we want to fill
 405 * things 32 bits at a time even when we don't know the size of the
 406 * area at compile-time..
 407 */
 408static inline void * __constant_c_memset(void * s, unsigned long c, size_t count)
 409{
 410int d0, d1;
 411__asm__ __volatile__(
 412        "rep ; stosl\n\t"
 413        "testb $2,%b3\n\t"
 414        "je 1f\n\t"
 415        "stosw\n"
 416        "1:\ttestb $1,%b3\n\t"
 417        "je 2f\n\t"
 418        "stosb\n"
 419        "2:"
 420        : "=&c" (d0), "=&D" (d1)
 421        :"a" (c), "q" (count), "0" (count/4), "1" ((long) s)
 422        :"memory");
 423return (s);     
 424}
 425
 426/* Added by Gertjan van Wingerde to make minix and sysv module work */
 427#define __HAVE_ARCH_STRNLEN
 428static inline size_t strnlen(const char * s, size_t count)
 429{
 430int d0;
 431register int __res;
 432__asm__ __volatile__(
 433        "movl %2,%0\n\t"
 434        "jmp 2f\n"
 435        "1:\tcmpb $0,(%0)\n\t"
 436        "je 3f\n\t"
 437        "incl %0\n"
 438        "2:\tdecl %1\n\t"
 439        "cmpl $-1,%1\n\t"
 440        "jne 1b\n"
 441        "3:\tsubl %2,%0"
 442        :"=a" (__res), "=&d" (d0)
 443        :"c" (s),"1" (count));
 444return __res;
 445}
 446/* end of additional stuff */
 447
 448#define __HAVE_ARCH_STRSTR
 449
 450extern char *strstr(const char *cs, const char *ct);
 451
 452/*
 453 * This looks horribly ugly, but the compiler can optimize it totally,
 454 * as we by now know that both pattern and count is constant..
 455 */
 456static inline void * __constant_c_and_count_memset(void * s, unsigned long pattern, size_t count)
 457{
 458        switch (count) {
 459                case 0:
 460                        return s;
 461                case 1:
 462                        *(unsigned char *)s = pattern;
 463                        return s;
 464                case 2:
 465                        *(unsigned short *)s = pattern;
 466                        return s;
 467                case 3:
 468                        *(unsigned short *)s = pattern;
 469                        *(2+(unsigned char *)s) = pattern;
 470                        return s;
 471                case 4:
 472                        *(unsigned long *)s = pattern;
 473                        return s;
 474        }
 475#define COMMON(x) \
 476__asm__  __volatile__( \
 477        "rep ; stosl" \
 478        x \
 479        : "=&c" (d0), "=&D" (d1) \
 480        : "a" (pattern),"0" (count/4),"1" ((long) s) \
 481        : "memory")
 482{
 483        int d0, d1;
 484        switch (count % 4) {
 485                case 0: COMMON(""); return s;
 486                case 1: COMMON("\n\tstosb"); return s;
 487                case 2: COMMON("\n\tstosw"); return s;
 488                default: COMMON("\n\tstosw\n\tstosb"); return s;
 489        }
 490}
 491  
 492#undef COMMON
 493}
 494
 495#define __constant_c_x_memset(s, c, count) \
 496(__builtin_constant_p(count) ? \
 497 __constant_c_and_count_memset((s),(c),(count)) : \
 498 __constant_c_memset((s),(c),(count)))
 499
 500#define __memset(s, c, count) \
 501(__builtin_constant_p(count) ? \
 502 __constant_count_memset((s),(c),(count)) : \
 503 __memset_generic((s),(c),(count)))
 504
 505#define __HAVE_ARCH_MEMSET
 506#define memset(s, c, count) \
 507(__builtin_constant_p(c) ? \
 508 __constant_c_x_memset((s),(0x01010101UL*(unsigned char)(c)),(count)) : \
 509 __memset((s),(c),(count)))
 510
 511/*
 512 * find the first occurrence of byte 'c', or 1 past the area if none
 513 */
 514#define __HAVE_ARCH_MEMSCAN
 515static inline void * memscan(void * addr, int c, size_t size)
 516{
 517        if (!size)
 518                return addr;
 519        __asm__("repnz; scasb\n\t"
 520                "jnz 1f\n\t"
 521                "dec %%edi\n"
 522                "1:"
 523                : "=D" (addr), "=c" (size)
 524                : "0" (addr), "1" (size), "a" (c));
 525        return addr;
 526}
 527
 528#endif /* CONFIG_X86_USE_STRING_486 */
 529#endif /* __KERNEL__ */
 530
 531#endif
 532
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.