GCC、MSVC、LLVM、およびおそらく他のツールチェーンは、コンパイル時の呼び出しの最適化を可能にするリンク時(プログラム全体)最適化をサポートしています。
実動ソフトウェアのコンパイル時にこのオプションを有効にしない理由はありますか?
"プロダクションソフトウェア"とは、顧客に出荷する/プロダクションに入るソフトウェアを意味すると想定しています。 なぜコンパイラ最適化を常に使用しないのか? ( Mankarse によって指摘される)の答えは、コードをデバッグしたい状況にほとんど当てはまります(したがって、ソフトウェアはまだ開発段階-本番ではありません)。
私が考えることができる唯一の良い、正当な理由は、リンク時間の最適化mayが微妙なバグを導入することです。 リンク時間のカーネルの最適化を参照) 。出荷しようとしているソフトウェアの正確性をチェックする適切なテストがあると仮定すると、デフォルトでLTOを使用しない理由はわかりません。 (LTOは時間とともに成熟しているため、これらの微妙なバグがますます少なくなることを期待しましょう。)
この最近の質問 は、LTOが望ましくない効果をもたらす可能性のある別の可能性のある(しかしかなり具体的な)ケースを発生させます:問題のコードがタイミングのために装備されており、相対的なインストルメントされたステートメントとインストルメントステートメントの順序付けを行うと、LTOは必要な順序付けを破棄する可能性が高くなります。
具体的だと言った。
よく書かれたコードを持っている場合、それは有利なだけです。コンパイラ/リンカーのバグに遭遇する可能性がありますが、これはあらゆるタイプの最適化に当てはまりますが、これはまれです。
最大の欠点は、リンク時間が大幅に増加することです。
リンク時最適化が間違ったコードに対して予期しない動作を引き起こす可能性がある1つのシナリオは次のとおりです。
別々のオブジェクトファイルにコンパイルする2つのソースファイルread.c
とclient.c
があるとします。ファイルread.c
には、特定のメモリアドレスからの読み取り以外は何もしないread
関数があります。ただし、このアドレスのコンテンツはvolatile
とマークする必要がありますが、残念ながら忘れていました。 client.c
から関数read
が同じ関数から数回呼び出されます。 read
はアドレスから1回の読み取りのみを実行し、read
関数の境界を超えた最適化は行われないため、read
は呼び出されると常にそれぞれのメモリ位置にアクセスします。したがって、read
がclient.c
から呼び出されるたびに、client.c
のコードは、まるでvolatile
が使用されたかのように、アドレスから新たに読み取られた値を取得します。
現在、リンク時最適化では、read.c
から呼び出された場合に、client.c
からの小さな関数read
がインライン化される可能性があります。 volatile
がないため、コンパイラはコードが同じアドレスから数回読み取ることを認識し、メモリアクセスを最適化することができます。その結果、コードは異なる動作を開始します。
To this とは別に、
組み込みシステムの典型的な例を考えてみましょう。
void function1(void) { /*Do something*/} //located at address 0x1000
void function2(void) { /*Do something*/} //located at address 0x1100
void function3(void) { /*Do something*/} //located at address 0x1200
定義済みのアドレス指定関数を使用すると、以下のような相対アドレスを介して呼び出すことができます。
void (*ptr)(void) = function1;
(ptr + 0x100)(); //expected to call function2
(ptr + 0x200)(); //expected to call function3
LOTは予期しない動作を引き起こす可能性があります。