免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 10551 | 回复: 11
打印 上一主题 下一主题

[C] gcc 嵌入汇编使用sse指令 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-07-03 12:45 |只看该作者 |倒序浏览
如下指令有什么问题?
      float   root = 0.f;
      float   x = 0;

        __asm__ __volatile__(
                "sqrtss %X1, %%xmm0\n\t"
                "movss %%xmm0, %X0\n\t"
                : "=X" (root)
                : "X" (x)
                : "%xmm0"
                );
我编译的时候爆出“error: unknown register name '%xmm0' in 'asm'”
是不是xmm0寄存器不能用在嵌入汇编的“修改”部分,即第2各冒号的右边 ?

论坛徽章:
0
2 [报告]
发表于 2009-07-03 15:16 |只看该作者
用intrinsics吧

论坛徽章:
0
3 [报告]
发表于 2009-07-04 14:50 |只看该作者

回复 #1 UnixStudier 的帖子

好像这个问题很普遍,应该是xmm0寄存器不能用在嵌入汇编的“修改”部分

论坛徽章:
0
4 [报告]
发表于 2009-07-04 18:34 |只看该作者
gcc默认的CPU是什么?也许是386

论坛徽章:
0
5 [报告]
发表于 2009-07-04 19:39 |只看该作者
memcpy.c
  1. /*
  2.     memcpy.c  copy from directfb
  3. */
  4. /*
  5. * memcpy.c
  6. * Copyright (C) 1999-2001 Aaron Holtzman <[email]aholtzma@ess.engr.uvic.ca[/email]>
  7. *
  8. * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
  9. *
  10. * mpeg2dec is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * mpeg2dec is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  23. */

  24. #include <sys/time.h>
  25. #include <time.h>

  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>

  29. #include "memcpy.h"
  30. #include "cpu_accel.h"

  31. #if defined (ARCH_X86) || defined (ARCH_X86_64) || defined (ARCH_PPC) || (SIZEOF_LONG == 8)
  32. # define RUN_BENCHMARK  1
  33. #else
  34. # define RUN_BENCHMARK  0
  35. #endif

  36. #if defined (ARCH_X86) || defined (ARCH_X86_64)

  37. /* for small memory blocks (<256 bytes) this version is faster */
  38. #define small_memcpy(to,from,n)\
  39. {\
  40. register unsigned long int dummy;\
  41. __asm__ __volatile__(\
  42.   "rep; movsb"\
  43.   :"=&D"(to), "=&S"(from), "=&c"(dummy)\
  44.   :"0" (to), "1" (from),"2" (n)\
  45.   : "memory");\
  46. }

  47. /* linux kernel __memcpy (from: /include/asm/string.h) */
  48. static inline void * __memcpy(void * to, const void * from, size_t n)
  49. {
  50.      int d0, d1, d2;

  51.      if ( n < 4 ) {
  52.           small_memcpy(to,from,n);
  53.      }
  54.      else
  55.           __asm__ __volatile__(
  56.                               "rep ; movsl\n\t"
  57.                               "testb $2,%b4\n\t"
  58.                               "je 1f\n\t"
  59.                               "movsw\n"
  60.                               "1:\ttestb $1,%b4\n\t"
  61.                               "je 2f\n\t"
  62.                               "movsb\n"
  63.                               "2:"
  64.                               : "=&c" (d0), "=&D" (d1), "=&S" (d2)
  65.                               :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
  66.                               : "memory");

  67.      return(to);
  68. }

  69. #ifdef USE_MMX

  70. #define MMX_MMREG_SIZE 8

  71. #define MMX1_MIN_LEN 0x800  /* 2K blocks */
  72. #define MIN_LEN 0x40  /* 64-byte blocks */

  73. static void * mmx_memcpy(void * to, const void * from, size_t len)
  74. {
  75.      void *retval;
  76.      size_t i;
  77.      retval = to;

  78.      if (len >= MMX1_MIN_LEN) {
  79.           register unsigned long int delta;
  80.           /* Align destinition to MMREG_SIZE -boundary */
  81.           delta = ((unsigned long int)to)&(MMX_MMREG_SIZE-1);
  82.           if (delta) {
  83.                delta=MMX_MMREG_SIZE-delta;
  84.                len -= delta;
  85.                small_memcpy(to, from, delta);
  86.           }
  87.           i = len >> 6; /* len/64 */
  88.           len&=63;
  89.           for (; i>0; i--) {
  90.                __asm__ __volatile__ (
  91.                                     "movq (%0), %%mm0\n"
  92.                                     "movq 8(%0), %%mm1\n"
  93.                                     "movq 16(%0), %%mm2\n"
  94.                                     "movq 24(%0), %%mm3\n"
  95.                                     "movq 32(%0), %%mm4\n"
  96.                                     "movq 40(%0), %%mm5\n"
  97.                                     "movq 48(%0), %%mm6\n"
  98.                                     "movq 56(%0), %%mm7\n"
  99.                                     "movq %%mm0, (%1)\n"
  100.                                     "movq %%mm1, 8(%1)\n"
  101.                                     "movq %%mm2, 16(%1)\n"
  102.                                     "movq %%mm3, 24(%1)\n"
  103.                                     "movq %%mm4, 32(%1)\n"
  104.                                     "movq %%mm5, 40(%1)\n"
  105.                                     "movq %%mm6, 48(%1)\n"
  106.                                     "movq %%mm7, 56(%1)\n"
  107.                                     :: "r" (from), "r" (to) : "memory");
  108.                from +=64;
  109.                to   +=64;
  110.           }
  111.           __asm__ __volatile__ ("emms":::"memory");
  112.      }
  113.      /*
  114.       * Now do the tail of the block
  115.       */
  116.      if (len) __memcpy(to, from, len);
  117.      return retval;
  118. }

  119. #ifdef USE_SSE

  120. #define SSE_MMREG_SIZE 16

  121. static void * mmx2_memcpy(void * to, const void * from, size_t len)
  122. {
  123.      void *retval;
  124.      size_t i;
  125.      retval = to;

  126.      /* PREFETCH has effect even for MOVSB instruction ;) */
  127.      __asm__ __volatile__ (
  128.                           "   prefetchnta (%0)\n"
  129.                           "   prefetchnta 64(%0)\n"
  130.                           "   prefetchnta 128(%0)\n"
  131.                           "   prefetchnta 192(%0)\n"
  132.                           "   prefetchnta 256(%0)\n"
  133.                           : : "r" (from) );

  134.      if (len >= MIN_LEN) {
  135.           register unsigned long int delta;
  136.           /* Align destinition to MMREG_SIZE -boundary */
  137.           delta = ((unsigned long int)to)&(MMX_MMREG_SIZE-1);
  138.           if (delta) {
  139.                delta=MMX_MMREG_SIZE-delta;
  140.                len -= delta;
  141.                small_memcpy(to, from, delta);
  142.           }
  143.           i = len >> 6; /* len/64 */
  144.           len&=63;
  145.           for (; i>0; i--) {
  146.                __asm__ __volatile__ (
  147.                                     "prefetchnta 320(%0)\n"
  148.                                     "movq (%0), %%mm0\n"
  149.                                     "movq 8(%0), %%mm1\n"
  150.                                     "movq 16(%0), %%mm2\n"
  151.                                     "movq 24(%0), %%mm3\n"
  152.                                     "movq 32(%0), %%mm4\n"
  153.                                     "movq 40(%0), %%mm5\n"
  154.                                     "movq 48(%0), %%mm6\n"
  155.                                     "movq 56(%0), %%mm7\n"
  156.                                     "movntq %%mm0, (%1)\n"
  157.                                     "movntq %%mm1, 8(%1)\n"
  158.                                     "movntq %%mm2, 16(%1)\n"
  159.                                     "movntq %%mm3, 24(%1)\n"
  160.                                     "movntq %%mm4, 32(%1)\n"
  161.                                     "movntq %%mm5, 40(%1)\n"
  162.                                     "movntq %%mm6, 48(%1)\n"
  163.                                     "movntq %%mm7, 56(%1)\n"
  164.                                     :: "r" (from), "r" (to) : "memory");
  165.                from += 64;
  166.                to   += 64;
  167.           }
  168.           /* since movntq is weakly-ordered, a "sfence"
  169.           * is needed to become ordered again. */
  170.           __asm__ __volatile__ ("sfence":::"memory");
  171.           __asm__ __volatile__ ("emms":::"memory");
  172.      }
  173.      /*
  174.       * Now do the tail of the block
  175.       */
  176.      if (len) __memcpy(to, from, len);
  177.      return retval;
  178. }

  179. /* SSE note: i tried to move 128 bytes a time instead of 64 but it
  180. didn't make any measureable difference. i'm using 64 for the sake of
  181. simplicity. [MF] */
  182. static void * sse_memcpy(void * to, const void * from, size_t len)
  183. {
  184.      void *retval;
  185.      size_t i;
  186.      retval = to;

  187.      /* PREFETCH has effect even for MOVSB instruction ;) */
  188.      __asm__ __volatile__ (
  189.                           "   prefetchnta (%0)\n"
  190.                           "   prefetchnta 64(%0)\n"
  191.                           "   prefetchnta 128(%0)\n"
  192.                           "   prefetchnta 192(%0)\n"
  193.                           "   prefetchnta 256(%0)\n"
  194.                           : : "r" (from) );

  195.      if (len >= MIN_LEN) {
  196.           register unsigned long int delta;
  197.           /* Align destinition to MMREG_SIZE -boundary */
  198.           delta = ((unsigned long int)to)&(SSE_MMREG_SIZE-1);
  199.           if (delta) {
  200.                delta=SSE_MMREG_SIZE-delta;
  201.                len -= delta;
  202.                small_memcpy(to, from, delta);
  203.           }
  204.           i = len >> 6; /* len/64 */
  205.           len&=63;
  206.           if (((unsigned long)from) & 15)
  207.                /* if SRC is misaligned */
  208.                for (; i>0; i--) {
  209.                     __asm__ __volatile__ (
  210.                                          "prefetchnta 320(%0)\n"
  211.                                          "movups (%0), %%xmm0\n"
  212.                                          "movups 16(%0), %%xmm1\n"
  213.                                          "movups 32(%0), %%xmm2\n"
  214.                                          "movups 48(%0), %%xmm3\n"
  215.                                          "movntps %%xmm0, (%1)\n"
  216.                                          "movntps %%xmm1, 16(%1)\n"
  217.                                          "movntps %%xmm2, 32(%1)\n"
  218.                                          "movntps %%xmm3, 48(%1)\n"
  219.                                          :: "r" (from), "r" (to) : "memory");
  220.                     from += 64;
  221.                     to   += 64;
  222.                }
  223.           else
  224.                /*
  225.                   Only if SRC is aligned on 16-byte boundary.
  226.                   It allows to use movaps instead of movups, which required
  227.                   data to be aligned or a general-protection exception (#GP)
  228.                   is generated.
  229.                */
  230.                for (; i>0; i--) {
  231.                     __asm__ __volatile__ (
  232.                                          "prefetchnta 320(%0)\n"
  233.                                          "movaps (%0), %%xmm0\n"
  234.                                          "movaps 16(%0), %%xmm1\n"
  235.                                          "movaps 32(%0), %%xmm2\n"
  236.                                          "movaps 48(%0), %%xmm3\n"
  237.                                          "movntps %%xmm0, (%1)\n"
  238.                                          "movntps %%xmm1, 16(%1)\n"
  239.                                          "movntps %%xmm2, 32(%1)\n"
  240.                                          "movntps %%xmm3, 48(%1)\n"
  241.                                          :: "r" (from), "r" (to) : "memory");
  242.                     from += 64;
  243.                     to   += 64;
  244.                }
  245.           /* since movntq is weakly-ordered, a "sfence"
  246.            * is needed to become ordered again. */
  247.           __asm__ __volatile__ ("sfence":::"memory");
  248.           /* enables to use FPU */
  249.           __asm__ __volatile__ ("emms":::"memory");
  250.      }
  251.      /*
  252.       * Now do the tail of the block
  253.       */
  254.      if (len) __memcpy(to, from, len);
  255.      return retval;
  256. }

  257. #endif /* USE_SSE */
  258. #endif /* USE_MMX */


  259. static void *linux_kernel_memcpy(void *to, const void *from, size_t len) {
  260.      return __memcpy(to,from,len);
  261. }

  262. #endif /* ARCH_X86 */


  263. #if SIZEOF_LONG == 8

  264. static void * generic64_memcpy( void * to, const void * from, size_t len )
  265. {
  266.      register u8   *d = (u8*)to;
  267.      register u8   *s = (u8*)from;
  268.      size_t         n;

  269.      if (len >= 128) {
  270.           unsigned long delta;

  271.           /* Align destination to 8-byte boundary */
  272.           delta = (unsigned long)d & 7;
  273.           if (delta) {
  274.                len -= 8 - delta;                 

  275.                if ((unsigned long)d & 1) {
  276.                     *d++ = *s++;
  277.                }
  278.                if ((unsigned long)d & 2) {
  279.                     *((u16*)d) = *((u16*)s);
  280.                     d += 2; s += 2;
  281.                }
  282.                if ((unsigned long)d & 4) {
  283.                     *((unsigned int*)d) = *((unsigned int*)s);
  284.                     d += 4; s += 4;
  285.                }
  286.           }
  287.          
  288.           n    = len >> 6;
  289.           len &= 63;
  290.          
  291.           for (; n; n--) {
  292.                ((u64*)d)[0] = ((u64*)s)[0];
  293.                ((u64*)d)[1] = ((u64*)s)[1];
  294.                ((u64*)d)[2] = ((u64*)s)[2];
  295.                ((u64*)d)[3] = ((u64*)s)[3];
  296.                ((u64*)d)[4] = ((u64*)s)[4];
  297.                ((u64*)d)[5] = ((u64*)s)[5];
  298.                ((u64*)d)[6] = ((u64*)s)[6];
  299.                ((u64*)d)[7] = ((u64*)s)[7];
  300.                d += 64; s += 64;
  301.           }
  302.      }
  303.      /*
  304.       * Now do the tail of the block
  305.       */
  306.      if (len) {
  307.           n = len >> 3;
  308.          
  309.           for (; n; n--) {
  310.                *((u64*)d) = *((u64*)s);
  311.                d += 8; s += 8;
  312.           }
  313.           if (len & 4) {
  314.                *((unsigned int*)d) = *((unsigned int*)s);
  315.                d += 4; s += 4;
  316.           }
  317.           if (len & 2)  {
  318.                *((u16*)d) = *((u16*)s);
  319.                d += 2; s += 2;
  320.           }
  321.           if (len & 1)
  322.                *d = *s;
  323.      }
  324.      
  325.      return to;
  326. }

  327. #endif /* SIZEOF_LONG == 8 */



  328. static struct {
  329.      char                 *name;
  330.      char                 *desc;
  331.      memcpy_func           function;
  332.      unsigned long long    time;
  333.      unsigned int          cpu_require;
  334.      int                   best_count;
  335. } memcpy_method[] =
  336. {
  337.      { NULL, NULL, NULL, 0, 0},
  338.      { "libc",     "libc memcpy()",             (memcpy_func) memcpy, 0, 0, 0 },
  339. #if SIZEOF_LONG == 8
  340.      { "generic64","Generic 64bit memcpy()",    generic64_memcpy, 0, 0, 0},
  341. #endif /* SIZEOF_LONG == 8 */
  342. #if defined (ARCH_X86) || defined (ARCH_X86_64)
  343.      { "linux",    "linux kernel memcpy()",     linux_kernel_memcpy, 0, 0, 0},
  344. #ifdef USE_MMX
  345.      { "mmx",      "MMX optimized memcpy()",    mmx_memcpy, 0, MM_MMX, 0},
  346. #ifdef USE_SSE
  347.      { "mmxext",   "MMXEXT optimized memcpy()", mmx2_memcpy, 0, MM_MMXEXT, 0},
  348.      { "sse",      "SSE optimized memcpy()",    sse_memcpy, 0, MM_MMXEXT|MM_SSE, 0},
  349. #endif /* USE_SSE  */
  350. #endif /* USE_MMX  */
  351. #endif /* ARCH_X86 */
  352.      { NULL, NULL, NULL, 0, 0}
  353. };


  354. #ifdef ARCH_X86
  355. static inline unsigned long long int rdtsc()
  356. {
  357.      unsigned long long int x;
  358.      __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
  359.      return x;
  360. }
  361. #else
  362. static inline unsigned long long int rdtsc()
  363. {
  364.      struct timeval tv;

  365.      gettimeofday (&tv, NULL);
  366.      return (tv.tv_sec * 1000000 + tv.tv_usec);
  367. }
  368. #endif


  369. memcpy_func seye_memcpy = (memcpy_func) memcpy;

  370. void seye_find_best_memcpy( int buf_size)
  371. {
  372.      unsigned long long t;
  373.      char *buf1, *buf2;
  374.      int i, j, best = 0;
  375.      int count=0x3FFFFFF/buf_size;
  376.      unsigned int config_flags = seye_mm_accel();
  377.    
  378.      if ( buf_size>1024000 )
  379.          buf_size=102400;
  380.      if (buf_size>128000 || count>0xFFFFFF)
  381.         count=1000;
  382.      if (!(buf1 = (char *)malloc( buf_size*8 )))
  383.           return;

  384.      if (!(buf2 = (char *)malloc( buf_size*8 ))) {
  385.           free( buf1 );
  386.           return;
  387.      }

  388.      /* make sure buffers are present on physical memory */
  389.      memcpy( buf1, buf2, buf_size*8 );
  390.      memcpy( buf2, buf1, buf_size*8 );

  391.      for (i=1; memcpy_method[i].name; i++) {
  392.           if (memcpy_method[i].cpu_require & ~config_flags)
  393.                continue;

  394.           t = rdtsc();

  395.           for (j=0; j<count; j++)
  396.                memcpy_method[i].function( buf1 + (j%8)*buf_size, buf2 + (j%8)*buf_size, buf_size );

  397.           t = rdtsc() - t;
  398.           memcpy_method[i].time = t;

  399.           //fprintf(stderr, "\t%-10s  %20lld\n", memcpy_method[i].name, t );

  400.           if (best == 0 || t < memcpy_method[best].time)
  401.                best = i;
  402.      }

  403.      if (best) {
  404.           seye_memcpy = memcpy_method[best].function;
  405.      

  406.           fprintf(stderr,"Memcpy: buf_size=%d count=%d Using %s\n", buf_size,count, memcpy_method[best].desc );
  407.           memcpy_method[best].best_count++;
  408.      }

  409.      free( buf1 );
  410.      free( buf2 );
  411.      return;
  412. }

  413. void m_seye_find_best_memcpy( int try_count )
  414. {
  415.     int i, best_index;
  416.     int best_count=0;
  417.     if (try_count<5)
  418.         try_count=5;
  419.     for (i=1; i<=try_count; i++)
  420.     {
  421.         seye_find_best_memcpy( i*10240 );
  422.     }
  423.     for (i=1; memcpy_method[i].name; i++)
  424.     {
  425.         fprintf(stderr,"Memcpy: %s best=%d\n", memcpy_method[i].desc,memcpy_method[i].best_count );
  426.         if (best_count<memcpy_method[i].best_count)
  427.         {
  428.             best_index = i;
  429.             best_count=memcpy_method[i].best_count;
  430.         }
  431.     }
  432.     seye_memcpy = memcpy_method[best_index].function;
  433.     fprintf(stderr,"Memcpy: try %d times, best_count=%d Using %s\n",
  434.                 try_count, best_count, memcpy_method[best_index].desc );
  435.     return;
  436. }


  437. void seye_print_memcpy_routines()
  438. {
  439.      int   i;
  440.      unsigned int unsupported;
  441.      unsigned int config_flags = seye_mm_accel();

  442.      fprintf( stderr, "\nPossible values for memcpy option are:\n\n" );

  443.      for (i=1; memcpy_method[i].name; i++) {
  444.           unsupported = (memcpy_method[i].cpu_require & ~config_flags);

  445.           fprintf( stderr, "  %-10s  %-27s  %s\n", memcpy_method[i].name,
  446.                    memcpy_method[i].desc, unsupported ? "" : "supported" );
  447.      }

  448.      fprintf( stderr, "\n" );
  449. }

复制代码

论坛徽章:
0
6 [报告]
发表于 2009-07-04 19:40 |只看该作者
#ifndef __MEM__CPY_H
#define __MEM__CPY_H


#ifdef __cplusplus
extern "C" {
#endif

typedef void* (*memcpy_func)(void *to, const void *from, size_t len);

extern memcpy_func seye_memcpy;
extern void seye_find_best_memcpy( int buf_size );
extern void m_seye_find_best_memcpy( int try_count );
extern void seye_print_memcpy_routines();


#ifdef __cplusplus
}
#endif


#endif

论坛徽章:
0
7 [报告]
发表于 2009-07-04 19:41 |只看该作者
#include <stdio.h>

#include "memcpy.h"

int main(int argc, char **argv)
{
&nbsp;&nbsp;&nbsp;&nbsp;seye_find_best_memcpy(1024);
&nbsp;&nbsp;&nbsp;&nbsp;m_seye_find_best_memcpy( 8 );
&nbsp;&nbsp;&nbsp;&nbsp;return 0;
}

论坛徽章:
0
8 [报告]
发表于 2009-07-04 19:45 |只看该作者
mpeg2dec 中取的代码, 还有 cpu_accel 检测cpu 类型的。

论坛徽章:
0
9 [报告]
发表于 2009-07-04 22:32 |只看该作者
原帖由 aaaaa5aa 于 2009-7-4 14:50 发表
好像这个问题很普遍,应该是xmm0寄存器不能用在嵌入汇编的“修改”部分


这个,我在别的文章也看到了.不过我觉得我举的那个例子,xmm0寄存器应该放在嵌入汇编的“修改”部分的,表明我的潜入汇编里面会改写这个寄存器的内容.

论坛徽章:
0
10 [报告]
发表于 2009-07-04 22:37 |只看该作者
必须嵌汇编吗?intrinsics不行
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP