2012-05-23

今でも乗除算をビット演算に展開する意義はあるんだろうか

昔は、乗除算のオペランドの片方が定数であれば、たとえCPUに乗除算の命令があったとしても、ビット演算に展開したものである。これは、乗除算命令は、ビット演算に展開するよりも遅かったからだ。

深いパイプラインやマイクロコードへの変換が一般化した今はどうなっているのだろう。2の累乗のような綺麗な例はともかくとして、そういう二進数的に綺麗な数ではない場合、複数のビット演算を組み合わせなければならない。その分コードサイズが膨れ上がり、コードがキャッシュに乗らなくなり、また命令をマイクロコードに変換するデコーダーが一度に読み取る命令数からも溢るような気がするのだが。

まあ、一番重要なことは、もはや一介のプログラマーが、そんな些細なビット魔術を知らなくてもよくなったということだ。実際、この2012年では、もはやコンパイラーの吐き出すアセンブリを確かめる気にもならない。

6 comments:

やねうらお said...

除算に関して言えば、割る数が定数だとわかっていれば掛け算(mul)に変形できます。
除算命令(div)はすこぶるlatencyの長い命令なので、掛け算に変形する効果は絶大です。

ゆえに任意の変数で割るのと、定数で割るのとでは全く速度が異なります。
C++でコードを書いてコンパイルして比較してみてください。

あと、乗算のほうも掛ける数によっては任意の変数を掛けるのと定数とでは全く速度が変わってきます。例えば、大きな画像に対してエフェクトをかけたい場合、全ピクセルに対して乗算が必要になることがありますが、乗ずる数は実行時に決まる定数であることが多いので、JITを自作して定数の掛け算を最適化して生成するコードを自分で生成してそれを実行するのが常道です。

現実的なプロダクトを作るならば、このへんは当然おさえておくべきであって、もうちょっとそういうプロダクトのことも考えてあげてください…。

Anonymous said...

JITを自作するのが常道なのかはさておき、

ほとんどのコンパイラは、最適化OFFの場合であっても、定数による除算を乗算+シフトに変形するようです。

江添亮 said...

まあ、大規模な画像処理とか、DirectXやOpenGLをソフトウェア実装するなら動的なコード生成は役に立つのでしょうが、

やねうらお said...

> まあ、大規模な画像処理とか、DirectXやOpenGLをソフトウェア実装するなら動的なコード生成は役に立つのでしょうが、

大規模とおっしゃいますが、スクリーン全体の輝度を下げるだけ(こんな機能、いまどきどのペイントソフトにもついてますよね)でも、こういうテクニックは必要になりますよ。スライダーで輝度を変更した瞬間にリアルタイムにプレビューが見せるような場合、この部分の速度が数倍違ってきますから、ユーザビリティは雲泥の差です。

大規模だなんてとんでもないです。こじんまりしたペイントソフトですらこういう部分の高速化は必要になります。

Anonymous said...

もしかして、
 もはやマイコンや低性能CPUは過去のもので全く使われていない
などと考えてはいないでしょうか。

性能はトレードオフのたかだか一要因に過ぎないので、必要なら手でパフォーマンスチューニングするのは当然です。
そもそも、高級言語を使って開発するとすら限りません。

また、コンパイラが高性能化したと言いますが、すべてのCPUやマイコンがその恩恵にあずかれるわけではありません。

「世の中には自分の知らないハードやソフト、開発環境が山のようにある」
という視点を持ってみてはいかがでしょうか。

Anonymous said...

わかりました。広い視野(かっこわらい)を持ちます!