連載1 高速なメモリーコピー その6
コピー元:0x11111115
コピー先:0x22222229
の場合はとりあえずパターン2と同様に最初の11バイトをmemcpy()で処理して次のアドレスからメインの処理を開始します。
コピー元:0x11111120
コピー先:0x22222234
最初のmemcpy()でコピー元のアライメントが揃うので、読み込みは何も考えずにmovdqaで16バイトずつガンガン読込んでいきます。
問題は書き込みです。このままではアライメントが揃っていないのでmovntdqが使えません。そこで、読込んだ16バイトの内、12バイトだけを汎用命令のmovdquで書き込んで、残り4バイトはレジスターに残しておきます。こうすると、次の書き込みアドレスが0x22222240になるので、残りの4バイトと新しく読み込んだ16バイトの内の前方12バイトをレジスター上で合成してからmovntdqで書き込むことができます。
レジスターで合成する処理がちょっと面倒ですが、読み書き共にアライメントが揃うこの方法が私の知る限り最も効率良くメモリーコピーを行えます。
movdqa xmm0, [esi+ 0]; movdqu [esi+eax+ 0], xmm0; add eax, _SHIFT; psrldq xmm0, _SHIFT; LB_SHIFT( MAIN ): movdqa xmm1, [esi+16]; movdqa xmm3, [esi+32]; movdqa xmm2, xmm1; movdqa xmm4, xmm3; pslldq xmm1, 16-_SHIFT; psrldq xmm2, _SHIFT; pslldq xmm3, 16-_SHIFT; psrldq xmm4, _SHIFT; por xmm1, xmm0; por xmm3, xmm2; MOVNTDQ [esi+eax+ 0], xmm1; MOVNTDQ [esi+eax+16], xmm3; movdqa xmm1, [esi+48]; movdqa xmm3, [esi+64]; movdqa xmm2, xmm1; movdqa xmm0, xmm3; pslldq xmm1, 16-_SHIFT; psrldq xmm2, _SHIFT; pslldq xmm3, 16-_SHIFT; psrldq xmm0, _SHIFT; por xmm1, xmm4; por xmm3, xmm2; MOVNTDQ [esi+eax+32], xmm1; MOVNTDQ [esi+eax+48], xmm3; add esi, 64; loop LB_SHIFT( MAIN ); |
- 関連記事
trackback
コメントの投稿