VC 对 memcpy 的优化

来自:http://blog.codingnow.com/2005/10/vc_memcpy.html


在很多编译器中,memcpy 是一个 intrinsic 函数,也就是说,这个函数是由编译器实现的。它比 inline 函数更容易被编译时优化。编译器可以根据 memcpy 的参数是常量还是变量做出多种版本,达到最佳的性能。这一点,用 inline 或者 template 的技巧都无法办到。

我们看看 VC 对 memcpy 的优化。(所用版本 VC6)

void foo(void *d,const void *s)
{
     memcpy(d,s,1);
}

选性能最优化,生成汇编代码可以看到。代码被优化成:

mov eax, DWORD PTR _s$[esp-4]
mov edx, DWORD PTR _d$[esp-4]
mov cl, BYTE PTR [eax]
mov BYTE PTR [edx], cl

只是一个字节拷贝,用 cl 寄存器 mov 完成的。


把 1 改成 4 后:

mov eax, DWORD PTR _s$[esp-4]
mov edx, DWORD PTR _d$[esp-4]
mov ecx, DWORD PTR [eax]
mov DWORD PTR [edx], ecx

就变成了一条最普通的 mov 指令。


如果是 8 个字节:

mov eax, DWORD PTR _s$[esp-4]
mov ecx, DWORD PTR _d$[esp-4]
mov edx, DWORD PTR [eax]
mov DWORD PTR [ecx], edx
mov eax, DWORD PTR [eax+4]
mov DWORD PTR [ecx+4], eax

就是两条 mov 指令。


直到长度是常量 19 还是用 mov 完成的:

mov eax, DWORD PTR _s$[esp-4]
mov ecx, DWORD PTR _d$[esp-4]
mov edx, DWORD PTR [eax]
mov DWORD PTR [ecx], edx
mov edx, DWORD PTR [eax+4]
mov DWORD PTR [ecx+4], edx
mov edx, DWORD PTR [eax+8]
mov DWORD PTR [ecx+8], edx
mov edx, DWORD PTR [eax+12]
mov DWORD PTR [ecx+12], edx
mov dx, WORD PTR [eax+16]
mov WORD PTR [ecx+16], dx
mov al, BYTE PTR [eax+18]
mov BYTE PTR [ecx+18], al


长度达到 20 后,就转变成了使用 rep movsd

push esi
mov esi, DWORD PTR _s$[esp]
push edi
mov edi, DWORD PTR _d$[esp+4]
mov ecx, 5
rep movsd
pop edi
pop esi

如果长度并非 4 的整数倍的话,比如复制 23 个字节:

push esi
mov esi, DWORD PTR _s$[esp]
push edi
mov edi, DWORD PTR _d$[esp+4]
mov ecx, 5
rep movsd
movsw
movsb
pop edi
pop esi

编译器会在后面插入 movsw 和 movsb 。

现在我们来看看,memcpy 的长度是变量的情况:

void foo(void *d,const void *s,size_t size)
{
    memcpy(d,s,size);
}

这次编译器直接调用了 rep movsd

mov ecx, DWORD PTR _size$[esp-4]
push esi
mov esi, DWORD PTR _s$[esp]
mov eax, ecx
push edi
mov edi, DWORD PTR _d$[esp+4]
shr ecx, 2
rep movsd
mov ecx, eax
and ecx, 3
rep movsb
pop edi
pop esi

因为我们并不知道 size 是否是 4 的整数倍,所以尾巴上用 and ecx,3 / repmovsb 来处理了一下。

那么我们能否通知编译器,需要 memcpy 的数据块长度是 4 的倍数呢?答案是可以的。看看编译器怎么编译 memcpy(d,s,size*4);

mov ecx, DWORD PTR _size$[esp-4]
push esi
mov esi, DWORD PTR _s$[esp]
push edi
mov edi, DWORD PTR _d$[esp+4]
rep movsd
pop edi
pop esi

非常简洁,不是吗?


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值