ゆき社長

シーゲンガーのお勉強 ゲームプログラマ、ゲーマー、色々!

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バイトアラインしておけば

良いよ。