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

#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;
}




    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值