コードを書いていると、特定の関数呼び出しの値を複数回使用していることに気付くことがよくあります。明らかな最適化は、これらの繰り返し使用される値を変数に取り込むことであることに気付きました。これ(疑似コード):
function add1(foo){ foo + 1; }
...
do_something(foo(1));
do_something_else(foo(1));
なる:
function add1(foo){ foo + 1; }
...
bar = foo(1);
do_something(bar);
do_something_else(bar);
ただし、これを明示的に行うと、私の経験ではコードが読みにくくなります。選択した言語が関数に副作用を与えることを許可している場合、コンパイラはこの種の最適化を実行できないと思いました。
最近私はこれを調べました、そして私が正しく理解していれば、この最適化は関数が純粋でなければならない言語に対して行う/行うことができます. それは私を驚かせませんが、おそらくこれは不純な関数に対しても行うことができます。いくつかの簡単な Google 検索で、次のスニペットを見つけました: GCC 4.7 Fortran の改善
フロントエンドの最適化を実行する場合、 -faggressive-function-elimination オプションを使用すると、純粋でない関数であっても重複する関数呼び出しを削除できます。
たとえば、一部の言語では、関数に副作用を持たせることが許可されていません。したがって、プログラムが同じ関数を同じ引数で複数回呼び出した場合、コンパイラは、関数の結果を 1 回だけ計算する必要があると即座に推測できます。関数が副作用を持つことを許可されている言語では、別の戦略が可能です。オプティマイザは、どの関数に副作用がないかを判断し、そのような最適化を副作用のない関数に制限できます。この最適化は、オプティマイザーが呼び出された関数にアクセスできる場合にのみ可能です。
私の理解では、これはオプティマイザーが関数が純粋かどうかを判断し、関数が純粋であるときにこの最適化を実行できることを意味します。これは、同じ入力が与えられたときに関数が常に同じ出力を生成し、副作用がない場合、純粋と見なされる両方の条件を満たしているためです。
これらの 2 つのスニペットから、2 つの疑問が生じます。
- 関数が純粋でない場合、コンパイラはどのようにしてこの最適化を安全に行うことができますか? (-faggressive-function-eliminationのように)
- コンパイラは、関数が純粋かどうかをどのように判断できますか? (ウィキペディアの記事で提案されている戦略のように)
そして最後に:
- この種の最適化はどの言語にも適用できますか、それとも特定の条件が満たされた場合にのみ適用できますか?
- この最適化は、非常に単純な関数でも価値のあるものですか?
- スタックからの値の保存と取得で発生するオーバーヘッドはどれくらいですか?
これらがばかげた、または非論理的な質問である場合は、お詫び申し上げます。それらは、私が最近気になっていることのほんの一部です。:)