次のような疑似コードがあるとします。
main() {
BOOL b = get_bool_from_environment(); //get it from a file, network, registry, whatever
while(true) {
do_stuff(b);
}
}
do_stuff(BOOL b) {
if(b)
path_a();
else
path_b();
}
ここで、外部環境が影響get_bool_from_environment()
を与えて真または偽の結果を生成する可能性if(b)
があることがわかっているので、 の真と偽の両方のブランチのコードをバイナリに含める必要があることがわかります。path_a();
コードから単に省略したり、コードから除外したりすることはできませんpath_b();
。
BUT -- 設定BOOL b
は 1 回だけで、プログラムの初期化後は常に同じ値を再利用します。
この有効な C コードを作成し、 を使用してコンパイルするとgcc -O0
、が呼び出されるif(b)
たびにプロセッサ上で繰り返し評価され、do_stuff(b)
基本的に静的なブランチのパイプラインに不要な命令が挿入されると考えられます。初期化後。
と同じくらい愚かなコンパイラを実際に持っていると仮定すると、gcc -O0
このコードを書き直して、関数ポインタと、テストを実行しない2 つの別個の関数do_stuff_a()
とを含めることになりますが、単に先に進んで、 2 つのパスのいずれかを実行します。次に、の値に基づいて関数ポインタを割り当て、ループ内でその関数を呼び出します。これにより分岐がなくなりますが、確かに関数ポインターの逆参照のためのメモリアクセスが追加されます (アーキテクチャの実装により、私は本当にそれについて心配する必要はないと思います)。do_stuff_b()
if(b)
main()
b
原則として、コンパイラが元の疑似コード サンプルと同じスタイルのコードを取得し、 の値がb
に一度割り当てられると、テストが不要であることに気付くことは可能main()
ですか? もしそうなら、このコンパイラー最適化の理論上の名前は何ですか? また、これを行う実際のコンパイラー実装 (オープンソースまたはそれ以外) の例を教えてください。
コンパイラは実行時に動的コードを生成できず、原則としてそれを実行できるシステムは、バイトコード仮想マシンまたはインタープリター (Java、.NET、Ruby など) だけであることを認識しています。これを静的に実行して、path_a();
ブランチとブランチのpath_b()
両方を含むコードを生成できるかどうか。 if(b)
do_stuff(b);