Home > Archives > 2013年02月17日

2013年02月17日

コンパイラとの戦い再び

意味的に下のループと等価な2種類のプログラムをコンパイルして,出てきたバイナリの実行時間に差が出て泣いた.

for(int i = 0; i < n; i++) r += (x[i]&1) ? x[i] : x[i] + x[i];

Expression templates 使いまくってるのでコンパイラのコントロールが難しいのだけど,とりあえずアセンブリ眺めて原因調査してどうにかした.

アセンブリを比べて最初に気づいた実行時間の差の原因は,内側の条件分岐をジャンプ命令で処理するか条件代入命令(cmov)で処理するかの違いだった.どのタイミングで cmov になってくれるのかはよくわからないが,この式のもとになる関数オブジェクト(この中では if を使っている)をゴニョゴニョ書き換えたら cmov になってくれた.

んで,これで速度おなじになるだろうとか思ったら,未だ微妙に違いが残ってて…… よく見比べてみたら,一方では r をメモリに書き戻しているのに対し,もう一方ではメモリに書き戻してないとかいう罠が発生してた.この差は,上記のループの外側に単純な if 文をひとつ置くだけで生じる.ということで,きっと if 文が何かの解析の邪魔になるんだろうなぁとか思って,その条件式を静的に判定できるときには if文を無くすように書き換えてみたら差がなくなってくれた.

とかいう戦いをしたら1日終わった.はぁ.

Home > Archives > 2013年02月17日

Search
Feeds

Page Top