4月
02
ひとつ改善点を思いついたのとベンチマークです。
改善点
浮動小数点数に変換して処理する場合でビットがたくさん立っている場合のケアですが、一番上の 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 さん。
no comment untill now