程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> VC 對 memcpy 的優化

VC 對 memcpy 的優化

編輯:關於C語言
 

在很多編譯器中,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<strong>
rep movsd</strong>
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<strong>
movsw
movsb</strong>
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

非常簡潔,不是嗎?
 

 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved