[〜#〜] gccの[〜#〜] 最適化レベルはどのように多くのがありますか?
私が試したのgcc -O1、-O2のgcc、gccの-O3、とgcc -O4
本当に大きな数を使用すると、機能しません。
しかし、私は試しました
gcc -O100
コンパイルしました。
最適化レベルはいくつありますか?
教訓的にするには、gccに指定できる8つの有効な-Oオプションがありますが、同じことを意味するものもあります。
この回答の元のバージョンには、7つの選択肢があると述べられていました。 GCCはその後-Og
合計を8にする
manページ: から
-O
(と同じ -O1
)-O0
(最適化を行わない、最適化レベルが指定されていない場合のデフォルト)-O1
(最小限の最適化)-O2
(さらに最適化)-O3
(さらに最適化)-Ofast
(標準準拠を破る点まで積極的に最適化する)-Og
(デバッグエクスペリエンスを最適化します。-Ogは、デバッグに干渉しない最適化を有効にします。標準のedit-compile-debugサイクルに最適な最適化レベルである必要があります。経験。)-Os
(サイズの最適化。-Os
はすべてを有効にします-O2
コードサイズを通常増加させない最適化。また、コードサイズを削減するために設計されたさらなる最適化も実行します。 -Os
は、次の最適化フラグを無効にします:-falign-functions -falign-jumps -falign-loops -falign-labels -freorder-blocks -freorder-blocks-and-partition -fprefetch-loop-arrays -ftree-vect-loop-version
)@pauldooが指摘しているように、OS Xには-Oz
GCC 5.1のソースコードを解釈するでは、-O100
で何が起こるかを確認します。これは、manページでは明確ではありません。
次のように結論付けます。
-O3
以上INT_MAX
までは-O3
と同じですが、将来的には簡単に変更される可能性があるため、それに依存しないでください。INT_MAX
より大きい整数を入力すると、GCC 5.1は未定義の動作を実行します。-O-1
のような負の整数を除外しますサブプログラムに焦点を当てる
最初に、GCCはcpp
、as
、cc1
、collect2
の単なるフロントエンドであることを忘れないでください。簡単な./XXX --help
は、collect2
とcc1
だけが-O
を取ると言うので、それらに注目しましょう。
そして:
gcc -v -O100 main.c |& grep 100
与える:
COLLECT_GCC_OPTIONS='-O100' '-v' '-mtune=generic' '-march=x86-64'
/usr/local/libexec/gcc/x86_64-unknown-linux-gnu/5.1.0/cc1 [[noise]] hello_world.c -O100 -o /tmp/ccetECB5.
-O
はcc1
とcollect2
の両方に転送されました。
common.optのO
common.opt は 内部ドキュメント で説明されているGCC固有のCLIオプション記述形式であり、 opth-gen.awk および-によってCに変換されます optc-gen.awk 。
次の興味深い行が含まれています。
O
Common JoinedOrMissing Optimization
-O<number> Set optimization level to <number>
Os
Common Optimization
Optimize for space rather than speed
Ofast
Common Optimization
Optimize for speed disregarding exact standards compliance
Og
Common Optimization
Optimize for debugging experience rather than speed or size
すべてのO
オプションを指定します。 -O<n>
が他のOs
、Ofast
およびOg
とは別のファミリーにあることに注意してください。
ビルドするとき、これは以下を含むoptions.h
ファイルを生成します:
OPT_O = 139, /* -O */
OPT_Ofast = 140, /* -Ofast */
OPT_Og = 141, /* -Og */
OPT_Os = 142, /* -Os */
ボーナスとして、\bO\n
の内部でcommon.opt
をgreppingしている間に、次の行に気付きます。
-optimize
Common Alias(O)
--optimize
(ダッシュが-optimize
ファイルのダッシュ.opt
で始まるため二重ダッシュ)は、-O
の文書化されていないエイリアスであり、--optimize=3
] _!
OPT_Oが使用される場所
ここでgrep:
git grep -E '\bOPT_O\b'
次の2つのファイルを示します。
最初にopts.c
を追跡しましょう
opts.c:default_options_optimization
opts.c
の使用はすべて、default_options_optimization
の内部で発生します。
この関数を呼び出す人を確認するためにバックトラックをgrepしますが、唯一のコードパスは次のとおりです。
main.c:main
toplev.c:toplev::main
opts-global.c:decode_opts
opts.c:default_options_optimization
main.c
はcc1
のエントリポイントです。良い!
この関数の最初の部分:
integral_argument
は、OPT_O
に対応する文字列でatoi
を呼び出して入力引数を解析しますopts
がopts->x_optimize
であるstruct gcc_opts
内に値を保存します。struct gcc_opts
無駄にグレップした後、このstruct
もoptions.h
で生成されることに気付きます。
struct gcc_options {
int x_optimize;
[...]
}
x_optimize
は次の行に由来します。
Variable
int optimize
common.opt
に存在し、そのoptions.c
:
struct gcc_options global_options;
したがって、これは設定全体のグローバル状態を含むものであり、int x_optimize
は最適化値であると推測します。
255は内部の最大値
opts.c:integral_argument
では、atoi
が入力引数に適用されるため、INT_MAX
は上限です。そして、もっと大きなものを置くと、GCCはCの未定義の動作を実行しているように見えます。痛い?
integral_argument
は、atoi
も薄くラップし、文字が数字でない場合は引数を拒否します。したがって、負の値は正常に失敗します。
opts.c:default_options_optimization
に戻ると、次の行が表示されます。
if ((unsigned int) opts->x_optimize > 255)
opts->x_optimize = 255;
最適化レベルは255
に切り捨てられます。 opth-gen.awk
を読みながら、私は出会ったことがあります:
# All of the optimization switches gathered together so they can be saved and restored.
# This will allow attribute((cold)) to turn on space optimization.
生成されたoptions.h
:
struct GTY(()) cl_optimization
{
unsigned char x_optimize;
これは、切り捨ての理由を説明しています。オプションは、char
を使用してスペースを節約するcl_optimization
にも転送する必要があります。したがって、255は実際には内部の最大値です。
opts.c:maybe_default_options
opts.c:default_options_optimization
に戻ると、maybe_default_options
に出くわします。それを入力し、maybe_default_option
で大きなスイッチに到達します:
switch (default_opt->levels)
{
[...]
case OPT_LEVELS_1_PLUS:
enabled = (level >= 1);
break;
[...]
case OPT_LEVELS_3_PLUS:
enabled = (level >= 3);
break;
>= 4
チェックはありません。これは、3
が可能な限り大きいことを示しています。
次に、OPT_LEVELS_3_PLUS
でcommon-target.h
の定義を検索します。
enum opt_levels
{
OPT_LEVELS_NONE, /* No levels (mark end of array). */
OPT_LEVELS_ALL, /* All levels (used by targets to disable options
enabled in target-independent code). */
OPT_LEVELS_0_ONLY, /* -O0 only. */
OPT_LEVELS_1_PLUS, /* -O1 and above, including -Os and -Og. */
OPT_LEVELS_1_PLUS_SPEED_ONLY, /* -O1 and above, but not -Os or -Og. */
OPT_LEVELS_1_PLUS_NOT_DEBUG, /* -O1 and above, but not -Og. */
OPT_LEVELS_2_PLUS, /* -O2 and above, including -Os. */
OPT_LEVELS_2_PLUS_SPEED_ONLY, /* -O2 and above, but not -Os or -Og. */
OPT_LEVELS_3_PLUS, /* -O3 and above. */
OPT_LEVELS_3_PLUS_AND_SIZE, /* -O3 and above and -Os. */
OPT_LEVELS_SIZE, /* -Os only. */
OPT_LEVELS_FAST /* -Ofast only. */
};
ハ!これは、レベルが3つしかないことを示す強力な指標です。
opts.c:default_options_table
opt_levels
は非常に興味深いので、OPT_LEVELS_3_PLUS
をgrepし、opts.c:default_options_table
を見つけます。
static const struct default_options default_options_table[] = {
/* -O1 optimizations. */
{ OPT_LEVELS_1_PLUS, OPT_fdefer_pop, NULL, 1 },
[...]
/* -O3 optimizations. */
{ OPT_LEVELS_3_PLUS, OPT_ftree_loop_distribute_patterns, NULL, 1 },
[...]
}
そのため、ドキュメントで言及されている-On
から特定の最適化へのマッピングがエンコードされます。いいね!
x_optimizeの使用がもうないことを確認
x_optimize
の主な使用法は、マニュアルページに記載されている-fdefer_pop
などの他の特定の最適化オプションを設定することでした。もうありますか?
grep
、そしてさらにいくつか見つけます。数は少なく、手動で検査した結果、すべての使用法がせいぜいx_optimize >= 3
しかないため、結論が保持されます。
lto-wrapper.c
次に、OPT_O
にあったlto-wrapper.c
の2番目のオカレンスに進みます。
LTOはリンク名の最適化を意味します。名前が示すとおり、-O
オプションが必要になり、collec2
(基本的にリンカー)にリンクされます。
実際、lto-wrapper.c
の最初の行は次のとおりです。
/* Wrapper to call lto. Used by collect2 and the linker plugin.
このファイルでは、OPT_O
の出現はO
の値を正規化して転送するだけなので、問題ないはずです。
7つの異なるレベル:
-O0
(デフォルト):最適化なし。
-O
または-O1
(同じ):最適化するが、あまり時間をかけないでください。
-O2
:より積極的に最適化する
-O3
:最も積極的に最適化する
-Ofast
: に相当 -O3 -ffast-math
。 -ffast-math
は、非標準準拠の浮動小数点最適化をトリガーします。これにより、コンパイラーは、浮動小数点数が無限に正確であり、それらの代数が実数代数の標準規則に従うように見せかけることができます。また、少なくともx86やx86-64を含む一部のプロセッサでは、非正規化をゼロにフラッシュし、非正規化をゼロとして扱うようにハードウェアに指示するようコンパイラーに指示します。非正規化は多くのFPUでスローパスをトリガーするため、ゼロとして処理する(スローパスをトリガーしない)ことは、パフォーマンスを大幅に向上させることができます。
-Os
:コードサイズを最適化します。これにより、Iキャッシュの動作が改善されるため、実際には速度が向上する場合があります。
-Og
:最適化を行いますが、デバッグには干渉しません。これにより、デバッグビルドの恥ずかしくないパフォーマンスが可能になり、-O0
デバッグビルド用。
これらのいずれによっても有効にされない他のオプションもあり、個別に有効にする必要があります。最適化オプションを使用することもできますが、この最適化によって有効にされた特定のフラグを無効にします。
詳細については、GCC Webサイトを参照してください。
4(0-3):GCC 4.4.2 manual を参照してください。それ以上は-O3だけですが、ある時点で可変サイズの制限をオーバーフローします。