ひとつ改善点を思いついたのとベンチマークです。

改善点

浮動小数点数に変換して処理する場合でビットがたくさん立っている場合のケアですが、一番上の 1 のビットから連続して 25 ビットが立っている時にのみ丸めで繰り上がるので、一番上 1 の次のビットを 0 にしてしまえばそれで解決です。結局以下のようなコードが使えます。

    movdqa      xmm2, xmm0
    psrld       xmm0, 1
    pandn       xmm2, xmm0

    cvtdq2ps    xmm1, xmm2
    psrld       xmm1, 23
    psubd       xmm1, 0000007f0000007f0000007f0000007fh

この方法なら SSE2 の範囲で書けます。

ベンチマーク

Core i7-2600K 3.4GHz、EIST 無効、TB 無効、32bit プロセス でレイテンシを計測した結果です。(一部出力を省略してあります)

ベンチマークプログラムはこちら(Windows + Visual C++ + NASM)

E:\pbsrd>asmbench.exe
algorithm                         cycles
----------------------------------------
gpr_nothing                        1.000
gpr_bsr                            4.000
----------------------------------------
sse_nothing                        1.000
sse_cvtdq2ps_only                  6.000
sse_cvtdq2pd_only                  6.049
sse_insext_pbsrd                  12.053
sse_cvtdq2ps_pbsrd_nocare          8.000
sse_cvtdq2ps_pbsrd_msbcare_sse2   10.000
sse_cvtdq2ps_pbsrd_msbcare_sse41   9.000
sse_cvtdq2ps_pbsrd_roundcare      11.000
sse_cvtdq2ps_pbsrd_bothcare_sse41 12.000
sse_cvtdq2pd_pbsrd_nocare         11.969

分かりやすくすると以下の表のようになります。

手法 サイクル数
生の BSR 命令 3
生の CVTDQ2PS 命令 5
生の CVTDQ2PD 命令 5
スカラーにして処理 11
CVTDQ2PS を使う (別段のケア無し) 7
CVTDQ2PS を使う (最上位ビットのケア SSE2 版) 9
CVTDQ2PS を使う (最上位ビットのケア SSE4.1 版) 8
CVTDQ2PS を使う (丸めのケア SSE2 版) 10
CVTDQ2PS を使う (最上位ビット SSE4.1 + 丸め SSE2) 11
CVSDQ2PD を使う (別段のケア無し) 11

これを見る限り、スカラーにして処理するか CVTDQ2PS を使うのがよさそうですね。また、将来 ymm レジスタに対して処理する場合は CVTDQ2PS を使うのが最適になりそうです。

しかし、上の丸めのケアが 3 サイクルもかかることになっているのが意外です。SandyBridge 以降ではレジスタ間 mov は命令デコード段階で消滅すると聞いたので 2 サイクルになると思っていたのですが… うまく対処できないケースなのかしら。

結論

{V,}PBS{F,R}{D,Q} 命令追加してくれよ Intel さん。

Trackback

no comment untill now

Add your comment now