どんな最適化やねん(4)
VC++の最適化ってどないやねん(2)
再びabs関数の速度比較に戻ります.前回(http://d.hatena.ne.jp/Ozy/20071111#p1)のコメント欄に書いたことのまとめですが,if文で分岐させたabs1とビット演算を使ったabs2は最適化によってかなりの速度差になることがわかりました.で,その時ふと思ったわけです.「標準関数のabsってどんなもんかな」と.
そんなわけで、abs1とabs2の速い方、つまりabs2と標準関数のabsを比較してみました.
テストコードは以下のような感じです.
- test.c(の一部)
for(i=0;i<ARRAY_SIZE;++i) { K=abs(a[i]); // or K=abs2(a[i]); }
Kはグローバル変数で,このように書いておいて最適化時にコードが丸々消されるのを防ぎます.コイツを/O2オプションでコンパイルしてやります.
- abs2
; 52 : K=abs2(a[i]); 00070 8b 0a mov ecx, DWORD PTR [edx] 00072 8b c1 mov eax, ecx 00074 c1 f8 1f sar eax, 31 ; 0000001fH 00077 8b e8 mov ebp, eax 00079 33 e9 xor ebp, ecx 0007b 2b e8 sub ebp, eax 0007d 83 c2 14 add edx, 20 ; 00000014H 00080 83 ee 01 sub esi, 1 00083 89 2d 00 00 00 00 mov DWORD PTR _K, ebp 00089 75 e5 jne SHORT $LL3@main
- abs
; 52 : K=abs(a[i]); 00077 8b 01 mov eax, DWORD PTR [ecx] 00079 99 cdq 0007a 33 c2 xor eax, edx 0007c 2b c2 sub eax, edx 0007e 83 c1 14 add ecx, 20 ; 00000014H 00081 83 ee 01 sub esi, 1 00084 a3 00 00 00 00 mov DWORD PTR _K, eax 00089 75 ec jne SHORT $LL3@main
標準関数を使った場合,abs2を最適化したものに良く似ていますが,シフトは行わずにcdq命令を使ってedxレジスタを正→0,負→-1みたいなかんじでセットするわけですね.
へるみさんによれば,
μOPレベルでは同じものになりますが,cdqの方がコード長が短いので速くなることがあります(CPU依存).
私の手元にあるCPUだとすべて速くなったので,CPU依存とはいえ結構いろんなCPUで速くなりそうですね.それから,GCC 4.xではどないかなーと思ってたところ,(これもへるみさんのコメント)
ちなみにgcc4.2.2ではabs(), abs1(), abs2()どれを使っても同一のコードが生成されました.
addl $1, %ecx
sarl $31, %edx
xorl %edx, %eax
subl %edx, %eax
だそうです(゜□゜)
私もMinGWに付いてたgcc4.1.2で試したのですが,ちょっと違うコードでした.早いトコcygwinの標準gccが4.xになってくれれば楽に試せるのですが…(自前ビルドは相変わらず失敗しています^^;)
何気なく調べたら,結構奥深いですね.こういう話題はちょっと避け気味でやったきたのですが,ショートコーディングでもバイナリ埋め込みとか出てきましたし,ちゃんと追求しないといけませんね….