1. ホーム
  2. c++

[解決済み] 末尾再帰最適化を行うC++コンパイラがあるとすれば、どのコンパイラですか?

2022-04-26 17:19:27

質問

CとC++の両方で末尾再帰の最適化を行うことは完全にうまくいくように思えますが、デバッグ中にこの最適化を示すフレームスタックを見ることはないようです。スタックを見れば、再帰の深さがわかるので、それはいいことだと思います。しかし、この最適化も同様に素晴らしいものです。

この最適化を行うC++コンパイラはありますか?なぜですか?なぜしないのですか?

どのようにコンパイラに指示すればよいのでしょうか?

  • MSVCの場合。 /O2 または /Ox
  • GCCの場合。 -O2 または -O3

コンパイラがあるケースでこうなっているかどうかをチェックするのはどうでしょうか。

  • MSVCの場合、PDB出力を有効にしてコードをトレースできるようにし、コードを検査します。
  • GCCの場合は...?

ある関数がコンパイラによってこのように最適化されているかどうかを判断する方法について、提案を受けたいと思います(Konradがそれを想定するように言ってくれるのは心強いですが)。

コンパイラがこのようなことを全くしないかどうかは、無限再帰を行い、無限ループやスタックオーバーフローになるかどうかをチェックすることで常に可能です(私はGCCでこれを行い、以下のことを発見しました。 -O2 で十分なのですが)、どうせ終了することが分かっている特定の関数をチェックできるようにしたいのです。これを簡単にチェックする方法があればいいのですが :)


いくつかのテストの後、私はデストラクタがこの最適化を行う可能性を台無しにすることを発見しました。特定の変数やテンポラリのスコープを変更して、returnステートメントが始まる前にスコープ外になるようにすることは、時として価値があることなのです。

テールコールの後にデストラクタを実行する必要がある場合、テールコールの最適化はできません。

解決方法は?

現在主流のコンパイラはすべてテールコール最適化を行っています。 は、かなりよくできています(10年以上前からできています)。 相互に再帰的な呼び出しであっても のようなものです。

int bar(int, int);

int foo(int n, int acc) {
    return (n == 0) ? acc : bar(n - 1, acc + 2);
}

int bar(int n, int acc) {
    return (n == 0) ? acc : foo(n - 1, acc + 1);
}

コンパイラに最適化をさせるのは簡単です。高速化のための最適化をオンにするだけです。

  • MSVCの場合は /O2 または /Ox .
  • GCC、Clang、ICCの場合は、以下のようになります。 -O3

コンパイラが最適化を行ったかどうかを確認する簡単な方法は、スタックオーバーフローになるような呼び出しを行うこと、またはアセンブリ出力を見ることです。

興味深い歴史的なメモとして、C言語のテールコール最適化がGCCに追加されたのは 卒業論文 マーク・プロブスト氏によるものです。この論文には、実装上の興味深い注意点がいくつか書かれています。一読の価値ありです。