g++ 最適化オプション

g++ の最適化オプションで "-O2" と "-O3" のどちらが良いのか分からなかったので調べました.結局,確信を持つことは出来ませんでしたが "-O2" をデフォルトで使用して,高速化をしたいときに両方を試すことにします.

環境

参考

 g++ の最適化オプションの説明が書かれています.

 最適化オプションの違いなどがまとめられています.リンク先には,『浮動小数点演算を多く使用するループや大きなデータセットを処理するループを含むアプリケーションに推奨します』と書かれています.

 2005年の記事なので古いのですが最適化オプションの利用について有益な情報が書かれています.O2は空間と速度のトレードオフを考えた最適化で,O3は速度重視の最適化と書かれています.

 江添さんのブログです.2013年の記事なのですがO2とO3の違いが実感できないと書かれています.

 「g++でO3を使用すると危ないって本当?」という質問に関する答えです.O2で使用される最適化はO3でも使用されているので,追加されたものにバグが含まれる場合はその通りです.

使用場所の例

"-O2" オプション

 競技プログラミングサイトの1つである Codeforces の andreyv さんのブログに書かれているオプションなのですが,"-O2" が使用されています.

 国際大学対抗プログラミングコンテストの2018年世界大会の環境ですが,"-O2" が使用されています.

使用されている最適化の違い

Using the GNU Compiler Collection (GCC): Optimize Options には,"-O2" で使用されずに "-O3" で追加された最適化として次があります.

  • finline-functions
  • funswitch-loops
  • fpredictive-commoning
  • fgcse-after-reload
  • ftree-loop-vectorize
  • ftree-loop-distribution
  • ftree-loop-distribute-patterns
  • floop-interchange
  • fsplit-paths
  • ftree-slp-vectorize
  • fvect-cost-model
  • ftree-partial-pre
  • fpeel-loops
  • fipa-cp-clone

ただし,自分のマシンで調べた所 "-floop-interchange" などは "-O3" でも使用されていなく,次の最適化が "-O2" から "-O3" へ追加されていました.ただし,コンパイラのバージョンなどによってもどれを enabled にするかは違うと思うので参考程度にします.
調べ方は syohex さんのブログ を参考にしました.

  • fgcse-after-reload
  • finline-functions
  • fipa-cp-clone
  • fpredictive-commoning
  • ftree-loop-distribute-patterns
  • ftree-loop-vectorize
  • ftree-partial-pre
  • ftree-slp-vectorize
  • funswitch-loops
  • fvect-cost-model=dynamic # O2では cheap

まとめ

O2にいくつかの最適化を加えたものがO3になり,高速になるかは実際に確かめないと分からないようです.例えば,"-finline-functions"はすべての関数をインライン化できるかを試すのですが,一般的にコードサイズが増え速度が低下する可能性もあります.
また,追加された最適化にバグを生成する可能性がある場合はバグに悩まされる可能性もありますが,時と場合によるものなのでどちらが良いのかを決めるのは難しそうです.
まとめると,通常はO2を使用して,より高速化したい場合にO3を試すということになりそうです.