GCCを使用してCプログラムをコンパイルするためのデフォルトの最適化レベルは-O0です。これにより、GCCドキュメントに従ってすべての最適化がオフになります。例えば:
gcc -O0 test.c
ただし、-O0が実際にすべての最適化をオフにするであるかどうかを確認するには。私はこのコマンドを実行しました:
gcc -Q -O0 --help=optimizers
そしてここで、私は少し驚いた。約50のオプションを有効にしました。次に、これを使用してgccに渡されるデフォルトの引数を確認しました。
gcc -v
私はこれを得た:
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.8/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.8.4-
2ubuntu1~14.04' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --
enable-languages=c,c++,Java,go,d,fortran,objc,obj-c++ --prefix=/usr --
program-suffix=-4.8 --enable-shared --enable-linker-build-id --
libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-
gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-
sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-
time=yes --enable-gnu-unique-object --disable-libmudflap --enable-plugin --
with-system-zlib --disable-browser-plugin --enable-Java-awt=gtk --enable-gtk-
cairo --with-Java-home=/usr/lib/jvm/Java-1.5.0-gcj-4.8-AMD64/jre --enable-
Java-home --with-jvm-root-dir=/usr/lib/jvm/Java-1.5.0-gcj-4.8-AMD64 --with-
jvm-jar-dir=/usr/lib/jvm-exports/Java-1.5.0-gcj-4.8-AMD64 --with-Arch-
directory=AMD64 --with-ecj-jar=/usr/share/Java/Eclipse-ecj.jar --enable-objc-
gc --enable-multiarch --disable-werror --with-Arch-32=i686 --with-abi=m64 --
with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release
--build=x86_64-linux-gnu --Host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04)
したがって、私の結論は、プログラムに提供した-O0
フラグは他の何かによってオーバーライドされなかったということです。
実際、私は、最適化オプションのランダムシーケンスを生成し、生成されたシーケンスをデフォルトレベル0〜3と比較するツールを最初から実装しようとしています。 「acovea」のように。そのため、生成されたシーケンスを最適化ゼロレベル(-O0
である必要があります)と比較したいと思います。
-O0
で50個のオプションがデフォルトで有効になっている理由を説明してください。
私が考えているアイデアの1つは、-O0
でコンパイルし、-O0
を50回使用して-fno-OPTIMIZATION_NAME
のデフォルトの最適化をオフにすることです。どう思いますか?
厳密に言えば、GCCコンパイラのミドルエンドは最適化パスのシーケンス(実際にはネストされたツリーであり、コンパイル中に動的に変化します)で構成されているため、GCCが最適化を行わなかった場合、コードを出力できません。
別の言い方をすると、GCCへの入力言語は非常に豊富です(プレーンCの場合でも、while
、for
、....があります)が、中間のGimple言語ははるかに豊富です貧弱な(特にGimple/SSA)ので、いくつかの変換を適用する必要があります )ソースASTからGimpleに移動します。これらの変換は最適化パスであり、ほぼ定義上です。
その answer および this one(SVG画像)の写真も参照し、言及されている参照を読んでください here 。
-O0
は、追加の最適化(たとえば、-O1
などによって提供される)を無効にすることとして理解する必要があります。実行可能。
上手
gcc -O0 `gcc -Q -O0 --help=optimizers 2>&1 | Perl -ane 'if ($F[1] =~/enabled/) {$F[0] =~ s/^\s*-f/-fno-/g;Push @o,$F[0];}} END {print join(" ", @o)'` your args here
すべてのオプションがオフになります(うん)。
さらに深刻なことに、すべての最適化状態をカバーしている場合は、最適化フラグのリストを作成し(とにかく行う必要があります)、-fmyflag
または-fno-myflag
を使用してそれぞれを明示的にオンまたはオフにします。これは本質的にあなたの2番目の質問に答えます。
ただし、すべての-O
レベルでオンになっている最適化をオフにして遊んでいる間は価値がないと考えるかもしれません。
whyについては、「広すぎる」(つまり、誰に書いたかを尋ねる必要がある)との間のどこかにあります。 https://github.com/gcc-mirror/gcc/blob/master/gcc/toplev.c します '。
ドキュメントには、-O0
が最適化を無効にすることは記載されていないことに注意してください。それは言う( manページ から):
-O0
コンパイル時間を短縮し、デバッグで期待される結果が得られるようにします。これがデフォルトです。
含意によって、コンパイル時間を増加させず、デバッグに影響を与えない最適化が存在する可能性があり、これらはオンのままになります。
私の質問に答えるために、私はいくつかの結論と仮定をしました:
したがって、O0でコンパイルしても、最適化が適用されないという意味ではありません。 @ablighが上で述べたように、コンパイル時間を短縮し、デバッグを改善するオプションがオンになります。
言い換えれば、O0はコンパイルのレベルで最適化されています。生成されたバイナリは、デバッグプロセスを容易にするために最適化されていません。
例を挙げます:このオプションはO0レベルで有効になっています
-faggressive-loop-optimizations
GCCドキュメント:
このオプションは、言語制約を使用してループの反復回数の範囲を導出するようにループオプティマイザーに指示します。これは、ループコードが、たとえば符号付き整数オーバーフローや範囲外の配列アクセスを引き起こすなど、未定義の動作を引き起こさないことを前提としています。ループの反復回数の境界は、ループの展開とピーリング、およびループ終了テストの最適化をガイドするために使用されます。 このオプションはデフォルトで有効になっています。
したがって、GCC 4.8.xの場合、デフォルトでほぼ50のオプションがオンになっています。