部分GNU代码片 19、快速的memcpy

原创 2008年04月23日 15:32:00
#include <stdio.h>
#include 
<stdlib.h>


/* for small memory blocks (<256 bytes) this version is faster */
#define small_memcpy(to,from,n)
{
register unsigned 
long int dummy;
__asm__ __volatile__(
  
"rep; movsb"
  :
"=&D"(to), "=&S"(from), "=&c"(dummy)
  :
"0" (to), "1" (from),"2" (n)
  : 
"memory");
}



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

     
if ( n < 4 ) {
          small_memcpy(to,from,n);
     }

     
else
          __asm__ __volatile__(
                              
"rep ; movsl "
                              
"testb $2,%b4 "
                              
"je 1f "
                              
"movsw "
                              
"1: testb $1,%b4 "
                              
"je 2f "
                              
"movsb "
                              
"2:"
                              : 
"=&c" (d0), "=&D" (d1), "=&S" (d2)
                              :
"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
                              : 
"memory");

     
return(to);
}


#ifdef HAVE_3DNOW
#define EMMS     "femms"
#else
#define EMMS     "emms"
#endif

#ifdef HAVE_MMX2
#define PREFETCH "prefetchnta"
#elif defined ( HAVE_3DNOW )
#define PREFETCH  "prefetch"
#else
#define PREFETCH "/nop"
#endif


#undef MOVNTQ
#ifdef HAVE_MMX2
#define MOVNTQ "movntq"
#else
#define MOVNTQ "movq"
#endif

#undef MIN_LEN
#ifdef HAVE_MMX1
#define MIN_LEN 0x800  /* 2K blocks */
#else
#define MIN_LEN 0x40  /* 64-byte blocks */
#endif


static void * big_memcpy(void *to, const void *from , size_t len) {
    
void *retval;
    size_t i;
    retval 
= to;
       
if(len >= MIN_LEN)
    
{
      register unsigned 
long int delta;
          
/* Align destinition to MMREG_SIZE -boundary */
          delta 
= ((unsigned long int)to)&7;
          
if(delta)
      
{
        delta
=8-delta;
        len 
-= delta;
        small_memcpy(to, from, delta);
      }

      i 
= len >> 6/* len/64 */
      len 
&= 63;
        
/*
           This algorithm is top effective when the code consequently
           reads and writes blocks which have size of cache line.
           Size of cache line is processor-dependent.
           It will, however, be a minimum of 32 bytes on any processors.
           It would be better to have a number of instructions which
           perform reading and writing to be multiple to a number of
           processor's decoders, but it's not always possible.
        
*/

    
for(; i>0; i--)
    
{
        __asm__ __volatile__ (
            PREFETCH
" 320(%0) "
        
"movq (%0), %%mm0 "
        
"movq 8(%0), %%mm1 "
        
"movq 16(%0), %%mm2 "
        
"movq 24(%0), %%mm3 "
        
"movq 32(%0), %%mm4 "
        
"movq 40(%0), %%mm5 "
        
"movq 48(%0), %%mm6 "
        
"movq 56(%0), %%mm7 "
        MOVNTQ
" %%mm0, (%1) "
        MOVNTQ
" %%mm1, 8(%1) "
        MOVNTQ
" %%mm2, 16(%1) "
        MOVNTQ
" %%mm3, 24(%1) "
        MOVNTQ
" %%mm4, 32(%1) "
        MOVNTQ
" %%mm5, 40(%1) "
        MOVNTQ
" %%mm6, 48(%1) "
        MOVNTQ
" %%mm7, 56(%1) "
        :: 
"r" (from), "r" (to) : "memory");
        ((
const unsigned char *)from)+=64;
        ((unsigned 
char *)to)+=64;
    }

#ifdef HAVE_MMX2
                
/* since movntq is weakly-ordered, a "sfence"
         * is needed to become ordered again. 
*/

        __asm__ __volatile__ (
"sfence":::"memory");
#endif
        
/* enables to use FPU */
        __asm__ __volatile__ (EMMS:::
"memory");
    }

    
/*
     *  Now do the tail of the block
     
*/

    
if(len) small_memcpy(to, from, len);
    
return retval;
}


char src[1270];
char dest[1270];

void init_src()
{
    
int i;
    
for(i = 0; i < 1260; i++)
        src[i] 
= i+1;
}


void output(int beg, int end)
{
    
int i;
    
for(i = beg-1; i < end; i++)
        printf(
" %d, ", dest[i]);
    printf(
" ");
}


void test_last16()
{
//    __memcpy(dest, src, 15);
    big_memcpy(dest, src, 1100);
    output(
11100);
}


int main()
{
    init_src();

    test_last16();

    
return 0;
}




    

相关文章推荐

汇编总结-第三部分_2_GNU下优化代码

通常汇编写的代码具有非常好的速度。但是难懂,所以人们就选择先编译高级语言,然后再修改汇编代码来达到优化目的。但实际上想要写的比编译器好是需要很多的练习的。对于我们这些普通的汇编使用者,就了解点简单的技...
  • meiboyu
  • meiboyu
  • 2014年01月10日 14:19
  • 569

memcpy函数的实现代码

  • 2012年05月12日 13:03
  • 77KB
  • 下载

Linux-05-Linux操作系统发展史及GNU-GPL-自用软件介绍1(L002-19)

多任务:听歌、玩游戏、聊qq同时进行; 多用户:张三在A地玩,李四在B地玩,同时连接服务器   【总结】 以下三个人: 第一个人Andrew S. Tanenbaum开发了...
  • wy_0928
  • wy_0928
  • 2016年05月05日 08:55
  • 160

部分字符串库函数的重写(源码) toupper,memcpy,memmove,memset,memchr,strlen,strcpy,strcat,strcmp,strchr

#include #include #include //////////////////////////////////////////////////// //Convert cha...

strcpy strlen memcpy strcat strcmp strstr strrev函数的实现代码

/* //strcpy函数的实现,注意命名要与原来的库函数有区别 #include #include #include using namespace std; char *mystrcp...
  • yzl_rex
  • yzl_rex
  • 2012年07月24日 10:53
  • 1094

memcpy内存复制代码的安全版本

C代码关于memcpy复制内存函数的安全版本#include #include #include void *Memcpy(void *dst, const void *src, size_t s...
  • JQ_AK47
  • JQ_AK47
  • 2016年10月15日 23:19
  • 1185

strcpy函数和memcpy函数的实现代码

***********************/   char *strcpy(char *strDestination, const char *strSource)   {   assert(st...

一步一步学Streams:第三部分(19)高级配置之单源单向复制环境

这里单源复制环境不是是说数据都从一处来,而是指单个对象的仅来源于一处,但可能有多个数据库同时捕获数据。在启动capture 进程和配置传播前,确认已经配置了propagation和apply进程处理相...
  • xyz846
  • xyz846
  • 2012年03月31日 22:43
  • 750

19. 如何使用GameCenter制作一个简单的多人游戏教程:第二部分

免责申明(必读!):本博客提供的所有教程的翻译原稿均来自于互联网,仅供学习交流之用,切勿进行商业传播。同时,转载时不要移除本申明。如产生任何纠纷,均与本博客所有人、发表该翻译稿之人无任何关系。谢谢合作...

Linux江湖08:使用GCC和GNU Binutils编写能在x86实模式运行的16位代码

Linux江湖08:使用GCC和GNU Binutils编写能在x86实模式运行的16位代码 http://www.cnblogs.com/youxia/p/linux008.html ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:部分GNU代码片 19、快速的memcpy
举报原因:
原因补充:

(最多只允许输入30个字)