SSE2命令(movdqu)を使用した128ビット単位のメモリ間転送プログラム

SSE2では、128ビット整数演算のSIMD命令の拡張が行われており、演算だけでなく、movdqa・movdquという命令を使うことで128ビット単位でメモリ間のデータコピーを高速に行うことができます。movdqaは転送対象のメモリのアドレスが16バイトの境界(アライメン ト)に揃ってる必要があります(アドレス値が16で割り切れる)。これに対して、movdquでは16バイトのアライメント制約はなく、どのアドレス値からでも読み書きできます。ただ、アライメントが揃っている分、CPUが処理しやすいため、movdqa命令の方が実行速度が速いです。速さを追求するならば、mallocや配列の確保時に16バイトのアライメントを意識する必要があります。各命令の基本的な実行速度はIntelから以下の資料が出ていますが、この資料上ではmovdqa・ movdquのスループットとレイテンシは同じになってますね・・・。ちょっとこのあたりは不明です。

・Intel技術資料 「IA-32命令のレイテンシとスループット」 (PDF)

この資料にはMMXやSSEの拡張命令も載っています。ちなみにざっくり分けると、MMXは64ビットのSIMD命令の拡張で、SSEは128ビットの浮動小数点演算のSIMD命令拡張だったと思います。

とりあえず、movdquを使ってメモリ間のデータ転送を行うサンプルは以下のようになります。 Linux+gccの環境で動きます。srcとdstにポインタを渡し、転送サイズをsizeで指定するだけです。SSE2非対応の場合を考えて、normalcalcの部分を追加してます。

ソースコード


// SSE2のmovdqu命令を用いてメモリ間転送
void memcpy_sse2(void *src, void *dst, size_t size)
{
  asm ("\n"
    "    mov      %0, %%eax\n"
    "    lea      (%%esi, %0), %%ebx\n"
    "  ssecalc:\n"
    "    movdqu   (%%esi),%%xmm0\n"
    "    lea      16(%%esi), %%esi \n"
    "    movdqu   %%xmm0,(%%edi)\n"
    "    lea      16(%%edi), %%edi\n"
    "    sub      $16, %%eax\n"
    "    cmp      $16, %%eax\n"
    "    jge      ssecalc\n"
    "    cmp      %%ebx, %%esi\n"
    "    je       end\n"
    " normalcalc:\n"
    "    mov      (%%esi), %%al\n"
    "    lea      1(%%esi), %%esi\n"
    "    mov      %%al, (%%edi)\n"
    "    lea      1(%%edi), %%edi\n"
    "    cmp      %%ebx, %%esi\n"
    "    jne      normalcalc\n"
    " end:\n"
    "    emms" :: "r" (size), "S" (src), "D" (dst));
}


(ファイル)
memcpy_SSE2.h
memcpy_SSE2.c

(参考URL)
Programming Lab
Advanced Optimization

トラックバック(0)

トラックバックURL: http://kirihari.net/mt/mt-tb.cgi/5

コメント(2)

Programming Lab は移転しました。
移転先: http://krypton.pv.land.to/

ご連絡ありがとうございます! リンク修正しました。

コメントする