Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  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
  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("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.  */
  51. static __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.  
  154. static 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.  
  161. static 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.  
  181. #if (__GNUC__ >= 4)
  182. #define memcpy(t, f, n) __builtin_memcpy(t, f, n)
  183. #else
  184. #define memcpy(t, f, n)                         \
  185.         (__builtin_constant_p((n))              \
  186.          ? __constant_memcpy((t), (f), (n))     \
  187.          : __memcpy((t), (f), (n)))
  188. #endif
  189. #else
  190. /*
  191.  * kmemcheck becomes very happy if we use the REP instructions unconditionally,
  192.  * because it means that we know both memory operands in advance.
  193.  */
  194. #define memcpy(t, f, n) __memcpy((t), (f), (n))
  195. #endif
  196.  
  197. #endif
  198.  
  199. #define __HAVE_ARCH_MEMMOVE
  200. void *memmove(void *dest, const void *src, size_t n);
  201.  
  202. #define memcmp __builtin_memcmp
  203.  
  204. #define __HAVE_ARCH_MEMCHR
  205. extern void *memchr(const void *cs, int c, size_t count);
  206.  
  207. static inline void *__memset_generic(void *s, char c, size_t count)
  208. {
  209.         int d0, d1;
  210.         asm volatile("rep\n\t"
  211.                      "stosb"
  212.                      : "=&c" (d0), "=&D" (d1)
  213.                      : "a" (c), "1" (s), "0" (count)
  214.                      : "memory");
  215.         return s;
  216. }
  217.  
  218. /* we might want to write optimized versions of these later */
  219. #define __constant_count_memset(s, c, count) __memset_generic((s), (c), (count))
  220.  
  221. /*
  222.  * memset(x, 0, y) is a reasonably common thing to do, so we want to fill
  223.  * things 32 bits at a time even when we don't know the size of the
  224.  * area at compile-time..
  225.  */
  226. static __always_inline
  227. void *__constant_c_memset(void *s, unsigned long c, size_t count)
  228. {
  229.         int d0, d1;
  230.         asm volatile("rep ; stosl\n\t"
  231.                      "testb $2,%b3\n\t"
  232.                      "je 1f\n\t"
  233.                      "stosw\n"
  234.                      "1:\ttestb $1,%b3\n\t"
  235.                      "je 2f\n\t"
  236.                      "stosb\n"
  237.                      "2:"
  238.                      : "=&c" (d0), "=&D" (d1)
  239.                      : "a" (c), "q" (count), "0" (count/4), "1" ((long)s)
  240.                      : "memory");
  241.         return s;
  242. }
  243.  
  244. /* Added by Gertjan van Wingerde to make minix and sysv module work */
  245. #define __HAVE_ARCH_STRNLEN
  246. extern size_t strnlen(const char *s, size_t count);
  247. /* end of additional stuff */
  248.  
  249. #define __HAVE_ARCH_STRSTR
  250. extern char *strstr(const char *cs, const char *ct);
  251.  
  252. /*
  253.  * This looks horribly ugly, but the compiler can optimize it totally,
  254.  * as we by now know that both pattern and count is constant..
  255.  */
  256. static __always_inline
  257. void *__constant_c_and_count_memset(void *s, unsigned long pattern,
  258.                                     size_t count)
  259. {
  260.         switch (count) {
  261.         case 0:
  262.                 return s;
  263.         case 1:
  264.                 *(unsigned char *)s = pattern & 0xff;
  265.                 return s;
  266.         case 2:
  267.                 *(unsigned short *)s = pattern & 0xffff;
  268.                 return s;
  269.         case 3:
  270.                 *(unsigned short *)s = pattern & 0xffff;
  271.                 *((unsigned char *)s + 2) = pattern & 0xff;
  272.                 return s;
  273.         case 4:
  274.                 *(unsigned long *)s = pattern;
  275.                 return s;
  276.         }
  277.  
  278. #define COMMON(x)                                                       \
  279.         asm volatile("rep ; stosl"                                      \
  280.                      x                                                  \
  281.                      : "=&c" (d0), "=&D" (d1)                           \
  282.                      : "a" (eax), "0" (count/4), "1" ((long)s)  \
  283.                      : "memory")
  284.  
  285.         {
  286.                 int d0, d1;
  287. #if __GNUC__ == 4 && __GNUC_MINOR__ == 0
  288.                 /* Workaround for broken gcc 4.0 */
  289.                 register unsigned long eax asm("%eax") = pattern;
  290. #else
  291.                 unsigned long eax = pattern;
  292. #endif
  293.  
  294.                 switch (count % 4) {
  295.                 case 0:
  296.                         COMMON("");
  297.                         return s;
  298.                 case 1:
  299.                         COMMON("\n\tstosb");
  300.                         return s;
  301.                 case 2:
  302.                         COMMON("\n\tstosw");
  303.                         return s;
  304.                 default:
  305.                         COMMON("\n\tstosw\n\tstosb");
  306.                         return s;
  307.                 }
  308.         }
  309.  
  310. #undef COMMON
  311. }
  312.  
  313. #define __constant_c_x_memset(s, c, count)                      \
  314.         (__builtin_constant_p(count)                            \
  315.          ? __constant_c_and_count_memset((s), (c), (count))     \
  316.          : __constant_c_memset((s), (c), (count)))
  317.  
  318. #define __memset(s, c, count)                           \
  319.         (__builtin_constant_p(count)                    \
  320.          ? __constant_count_memset((s), (c), (count))   \
  321.          : __memset_generic((s), (c), (count)))
  322.  
  323. #define __HAVE_ARCH_MEMSET
  324. #if (__GNUC__ >= 4)
  325. #define memset(s, c, count) __builtin_memset(s, c, count)
  326. #else
  327. #define memset(s, c, count)                                             \
  328.         (__builtin_constant_p(c)                                        \
  329.          ? __constant_c_x_memset((s), (0x01010101UL * (unsigned char)(c)), \
  330.                                  (count))                               \
  331.          : __memset((s), (c), (count)))
  332. #endif
  333.  
  334. /*
  335.  * find the first occurrence of byte 'c', or 1 past the area if none
  336.  */
  337. #define __HAVE_ARCH_MEMSCAN
  338. extern void *memscan(void *addr, int c, size_t size);
  339.  
  340. #endif /* __KERNEL__ */
  341.  
  342. #endif /* _ASM_X86_STRING_32_H */
  343.