web-dev-qa-db-ja.com

GCC最適化レベルはいくつありますか?

[〜#〜] gccの[〜#〜] 最適化レベルはどのように多くのがありますか?

私が試したのgcc -O1、-O2のgcc、gccの-O3、とgcc -O4

本当に大きな数を使用すると、機能しません。

しかし、私は試しました

gcc -O100

コンパイルしました。

最適化レベルはいくつありますか?

86
neuromancer

教訓的にするには、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

120
Glen

GCC 5.1のソースコードを解釈するでは、-O100で何が起こるかを確認します。これは、manページでは明確ではありません。

次のように結論付けます。

  • -O3以上INT_MAXまでは-O3と同じですが、将来的には簡単に変更される可能性があるため、それに依存しないでください。
  • INT_MAXより大きい整数を入力すると、GCC 5.1は未定義の動作を実行します。
  • 引数には数字しか使用できないか、正常に失敗します。特に、これは-O-1のような負の整数を除外します

サブプログラムに焦点を当てる

最初に、GCCはcppascc1collect2の単なるフロントエンドであることを忘れないでください。簡単な./XXX --helpは、collect2cc1だけが-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.

-Occ1collect2の両方に転送されました。

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>が他のOsOfastおよび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.ccc1のエントリポイントです。良い!

この関数の最初の部分:

  • integral_argumentは、OPT_Oに対応する文字列でatoiを呼び出して入力引数を解析します
  • optsopts->x_optimizeであるstruct gcc_opts内に値を保存します。

struct gcc_opts

無駄にグレップした後、このstructoptions.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_PLUScommon-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サイトを参照してください。

38
Demi

4(0-3):GCC 4.4.2 manual を参照してください。それ以上は-O3だけですが、ある時点で可変サイズの制限をオーバーフローします。

3
Tom