memcpy 速くするには・・
memcpyは良く使うだけに、SIMD命令を使い速くならないか
と思って ソースを見てみる
VisualStudio2010 での話だけど
memcpy.asm
にソースが書いてあるので読んでみる
まずプロローグでレジスタの退避や引数処理
memcpyではフレームポインタは作ってない
mov eax,ecx ;V - eax = byte count...
mov edx,ecx ;U - edx = byte count...
add eax,esi ;V - eax = point past source end
cmp edi,esi ;U - dst <= src ?
jbe short CopyUp ;V - yes, copy toward higher addresses
cmp edi,eax ;U - dst < (src + count) ?
jb CopyDown ;V - yes, copy toward lower addresses
領域のオーバーラップを見ている。コピー領域がオーバーラップし かつ、dest>src アドレスの場合
コピー領域が重なるので 後ろからmemcpyする
つまり memmoveと同じ動きをする。memmoveのソースはmemcpyを呼ぶようになっていた
VCではmemcpy=memmove で、オーバーラップもOKのようだ
CopyUp:
;
; First, see if we can use a "fast" copy SSE2 routine
; block size greater than min threshold?
cmp ecx,080h
jb Dword_align
; SSE2 supported?
cmp DWORD PTR __sse2_available,0
je Dword_align
; alignments equal?
push edi
push esi
and edi,15
and esi,15
cmp edi,esi
pop esi
pop edi
jne Dword_align
; do fast SSE2 copy, params already set
jmp _VEC_memcpy
SSE2に対応かつメモリアライメントが16バイト の場合は _VEC_memcpy へ行け
それ以外は Dword_align へ
なんと・・・メモリアラインを16バイトにしていれば _VEC_memcpy
名前からして目的の SIMDによる高速memcpyされるっぽい・・・
アライメントがあってない場合は以下
Dword_align:
test edi,11b ;U - destination dword aligned?
jnz short CopyLeadUp ;V - if we are not dword aligned already, align
shr ecx,2 ;U - shift down to dword count
and edx,11b ;V - trailing byte count
cmp ecx,8 ;U - test if small enough for unwind copy
jb short CopyUnwindUp ;V - if so, then jump
rep movsd ;N - move all of our dwords
jmp dword ptr TrailUpVec[edx*4] ;N - process trailing bytes
このように、アライメントを合わせて DWORDなどでmemcpy行うと。
memcpy 頑張ってるじゃん! 高速化するには
オーバーラップしない前提にし チェック外す
16バイトアライン前提にし アライメントチェック外す
SSE命令で16バイト単位の高速コピーを行う
つまり、edi、esi、ecx に、dest、src、length
設定して _VEC_memcpy 呼べばいい。以上!
(_VEC_memcpyにあたる アセンブラも書いたが速度変わらなかったので・・)
とりあえず、memcpyをよく行うだろう変数は 16バイトアラインしておけば
良いよ。