有多少GCC优化级别?

时间:2009-11-22 12:13:05

标签: c optimization gcc compiler-construction

有多少GCC个优化级别?

我试过gcc -O1,gcc -O2,gcc -O3和gcc -O4

如果我使用非常大的数字,它将无效。

但是,我试过了

gcc -O100

并编译。

有多少优化级别?

4 个答案:

答案 0 :(得分:115)

要迂腐,你可以给gcc提供8种不同的有效-O选项,尽管有一些意思相同。

这个答案的原始版本说明有7个选项。此后,海湾合作委员会增加-Og使总数达到8

来自man page:

  • -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

答案 1 :(得分:37)

七个不同的级别:

  • -O0(默认):无优化。

  • -O-O1(同样的事情):优化,但不要花太多时间。

  • -O2:更积极地优化

  • -O3:最积极地优化

  • -Ofast:相当于-O3 -ffast-math-ffast-math触发符合非标准的浮点优化。这允许编译器假装浮点数是无限精确的,并且它们上的代数遵循实数代数的标准规则。它还告诉编译器告诉硬件将非正规数刷新为零并将非正规数视为零,至少在某些处理器上,包括x86和x86-64。非正规在许多FPU上触发慢速路径,因此将它们视为零(不会触发慢速路径)可能是一个很大的性能胜利。

  • -Os:优化代码大小。在某些情况下,由于更好的I-cache行为,这实际上可以提高速度。

  • -Og:优化,但不要干扰调试。这为调试版本提供了非令人尴尬的性能,旨在替换调试版本的-O0

还有其他任何选项未启用,必须单独启用。也可以使用优化选项,但禁用此优化启用的特定标志。

有关详细信息,请参阅GCC网站。

答案 2 :(得分:37)

让我们解释GCC 5.1的源代码,看看-O100上发生了什么,因为在手册页上不清楚。

我们将得出结论:

  • -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.

因此-O已转发给cc1collect2

O in common.opt

common.optinternals documentation中描述的GCC特定的CLI选项说明格式,并由opth-gen.awkoptc-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 */

作为奖励,当我们在\bO\n内点击common.opt时,我们会注意到以下几行:

-optimize
Common Alias(O)

告诉我们--optimize(双击,因为它以-optimize文件上的短划线.opt开头)是-O的未记录别名,可用作--optimize=3

使用OPT_O的地方

现在我们grep:

git grep -E '\bOPT_O\b'

指向我们两个文件:

让我们先跟踪opts.c

<强> opts.c:default_options_optimization

所有opts.c次使用都发生在default_options_optimization内。

我们回头看看是谁调用了这个函数,我们看到唯一的代码路径是:

  • main.c:main
  • toplev.c:toplev::main
  • opts-global.c:decode_opts
  • opts.c:default_options_optimization

main.ccc1的切入点。好!

这个功能的第一部分:

  • 执行integral_argumentatoi对应的字符串调用OPT_O来解析输入参数
  • 将值opts->x_optimize存储在optsstruct gcc_opts的位置。

struct gcc_opts

徒劳无功后,我们注意到此struct也是在options.h生成的:

struct gcc_options {
    int x_optimize;
    [...]
}

其中x_optimize来自以下行:

Variable
int optimize

出现在common.optoptions.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;

解释了截断的原因:选项也必须转发到cl_optimization,后者使用char来节省空间。所以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非常有趣,我们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

x_optimize的主要用途是设置其他特定的优化选项,如手册页中记录的-fdefer_pop。还有吗?

我们grep,还可以找到更多。这个数字很小,经过人工检查,我们发现每次使用最多只有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的值标准化以将其向前传递,因此我们应该没问题。

答案 3 :(得分:3)

四(0-3):见GCC 4.4.2 manual。任何更高的东西只是-O3,但在某些时候你会溢出可变大小限制。