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


101

どのように多くのGCCの最適化のレベルがありますか?

gcc -O1、gcc -O2、gcc -O3、gcc -O4を試しました

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

しかし、私は試しました

gcc -O100

そしてそれはコンパイルされました。

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


13
@minitechどのFMを見ていますか?さえでman gccのCygwin(12000本の奇数ライン)上のあなたがのために検索することができます-Oと答え状態下のすべてを見つけるし、その後いくつかの。
イェンス

1
ソースを読んだ後の@minmaxavg、私はあなたに同意しません。それ以上のもの33intオーバーフローしない限り)と同じです。私の答えをください。
Ciro Santilli郝海东冠状病六四事件法轮功

1
実際、GCCには最適化を微調整するための他の多くのフラグがあります。-fomit-stack-pointer 生成されたコードを変更します。
バジルStarynkevitch

回答:


141

わかりやすくするために、gccに指定できる有効な-Oオプションは8つありますが、同じことを意味するものもあります。

この回答の元のバージョンでは、7つのオプションがあると述べていました。その後、GCCは-Og合計を8にするために追加しました

manページから

  • -O (と同じ-O1
  • -O0 (最適化を行わない、最適化レベルが指定されていない場合のデフォルト)
  • -O1 (最小限に最適化)
  • -O2 (さらに最適化)
  • -O3 (さらに最適化)
  • -Ofast (非常に積極的に最適化して、標準準拠に違反するまで)
  • -Og (デバッグエクスペリエンスを最適化します。-Ogは、デバッグを妨げない最適化を有効にします。これは、標準の編集、コンパイル、デバッグサイクルに最適な最適化レベルである必要があり、高速コンパイルと優れたデバッグエクスペリエンスを維持しながら、妥当なレベルの最適化を提供します。 )
  • -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


23
あなたは、Mac OS X上で開発している場合、追加があります-Oz「よりも、より積極的に大きさのために最適化され、設定-Os:」developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/...
pauldoo

6
注:名前が示唆する場合でも、O3は必ずしもO2よりも優れているとは限りません。両方試してください。
johan d '09

1
@pauldoo 404ページ、archive.orgで置き換える
noɥʇʎԀʎzɐɹƆ

また-Og、これはデバッグに干渉しないすべての最適化オプションです
einpoklum

47

マニュアルページでは明確ではないので、GCC 5.1のソースコードを解釈して何が起こるか見てみましょう-O100

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

  • 上記のもの-O3まではINT_MAX同じである-O3が、それは簡単に、将来的に変更される可能性がそれに依存しないでください。
  • より大きい整数を入力すると、GCC 5.1は未定義の動作を実行しますINT_MAX
  • 引数は数字しか持てないか、正常に失敗します。特に、これは次のような負の整数を除外します-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.

その-O両方に転送されたcc1collect2

common.optのO

common.optはGCC固有のCLIオプションの説明形式で、内部のドキュメントに記載されており、opth-gen.awkおよびoptc-gen.awkによってCに変換されます。

次の興味深い行が含まれています。

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>、他のとは別の家族の中でOsOfastOg

ビルドすると、以下options.hを含むファイルが生成されます。

OPT_O = 139,                               /* -O */
OPT_Ofast = 140,                           /* -Ofast */
OPT_Og = 141,                              /* -Og */
OPT_Os = 142,                              /* -Os */

我々はgrepをしている間、ボーナスとして、\bO\n内部のcommon.opt私たちは、行に気づきます:

-optimize
Common Alias(O)

そのことを私たちに教えて--optimize(ダブルダッシュ、それはダッシュで始まるので、-optimize上の.optファイル)のために文書化されていないエイリアスである-Oとして使用することができます--optimize=3

OPT_Oが使用される場所

今私たちはグレップ:

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を呼び出して入力引数を解析しますatoiOPT_O
  • 内部記憶値 opts->x_optimizeところoptsですstruct gcc_opts

構造体gcc_opts

無駄にgreppingした後、これ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は内部最大値です

in 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;

切り捨ての理由を説明します。オプションはにも転送する必要がcl_optimizationあります。charスペースを節約するためにに。つまり、255は実際には内部最大値です。

opts.c:maybe_default_options

に戻るとopts.c:default_options_optimizationmaybe_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_PLUSin の定義を検索します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我々はgrepすることを、とても興味深いですOPT_LEVELS_3_PLUS、とに遭遇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をこれ以上使用しないようにします

の主な用途は、manページに記載されているx_optimizeような他の特定の最適化オプションを設定することでした-fdefer_pop。これ以上ありますか?

私たちはgrep、さらにいくつかを見つけます。数は少なく、手動で調べると、すべての使用法が最大でaしか行わないことがわかりx_optimize >= 3ます。そのため、結論は成り立ちます。

lto-wrapper.c

今、私たちは第二の発生のために行くOPT_Oにありました、lto-wrapper.c

LTOは、リンクタイムの最適化を意味します。これは、名前が示すように、-Oオプションが必要であり、リンクされますcollec2(基本的にはリンカーです)。

実際には、の最初の行はlto-wrapper.c言う:

/* Wrapper to call lto.  Used by collect2 and the linker plugin.

このファイルでは、OPT_OオカレンスはOそれを転送するためにの値を正規化するだけのようですので、問題ありません。


38

7つの異なるレベル:

  • -O0 (デフォルト):最適化なし。

  • -Oまたは-O1(同じこと):最適化しますが、あまり時間をかけないでください。

  • -O2:より積極的に最適化する

  • -O3:最も積極的に最適化する

  • -Ofast:に相当し-O3 -ffast-mathます。 -ffast-math非標準に準拠した浮動小数点最適化をトリガーします。これにより、コンパイラーは、浮動小数点数が無限に正確であり、それらの代数が実数代数の標準規則に従っているように見せかけることができます。また、少なくともx86とx86-64を含む一部のプロセッサでは、ハードウェアにデノー​​マルをゼロにフラッシュし、デノーマルをゼロとして扱うように指示します。デノーマルは多くのFPUで低速パスをトリガーするため、それらをゼロとして処理すると(低速パスをトリガーしません)、パフォーマンスが大幅に向上します。

  • -Os:コードサイズを最適化します。これにより、Iキャッシュの動作が改善されるため、実際には速度が向上する場合があります。

  • -Og:最適化しますが、デバッグを妨げません。これにより、デバッグビルドで非の打ちどころのないパフォーマンスが可能になり、デバッグビルドに置き換わるもの-O0です。

これらのいずれによっても有効にされていないオプションが他にもあり、個別に有効にする必要があります。最適化オプションを使用することもできますが、この最適化によって有効にされた特定のフラグを無効にします。

詳細については、GCC Webサイトを参照してください。


確かに、他の回答に公平であるとはいえ、それらの回答が書かれたときには-Ofastも-Ogも存在しませんでした。
janneb 2013年

では、なぜ-O100コンパイルするのでしょうか?
einpoklum 2016

3
@einpoklumは、GCCが-O3以上のすべてを-O3と同等に扱うためです。
デミ

残念ながら、デバッガで-Ogを使用すると、まだ大量の<optimized out>が表示されます。ステッピングは依然としてランダムにジャンプします。それは役に立たない私見です。
doug65536 2017年

3

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


ソースコードを調べました 私の回答であなたに同意します。より具体的には、GCCはatoi未定義の動作に依存しているようであり、その後に255内部制限が続きます。
Ciro Santilli郝海东冠状病六四事件法轮功

4
(少なくとも最近では)正しくないため、回答の削除を検討してください。
einpoklum 2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.