有多少个GCC优化级别?


101

有多少个GCC优化级别?

我尝试了gcc -O1,gcc -O2,gcc -O3和gcc -O4

如果我使用非常大的数字,它将无法正常工作。

但是,我尝试了

gcc -O100

然后编译。

有多少个优化级别?


13
@minitech您在看哪个FM?即使使用man gccCygwin(12000个奇数行),您也可以搜索-O并找到下面状态的所有答案,然后找到一些答案。
詹斯2012年

1
@minmaxavg在阅读源代码之后,我不同意您的看法:任何大于等于的3内容3(只要它不会int溢出)。看我的回答
西罗Santilli郝海东冠状病六四事件法轮功

1
实际上,GCC还有许多其他标志可以微调优化。-fomit-stack-pointer 将更改生成的代码。
Basile Starynkevitch

Answers:


141

值得一提的是,您可以为gcc提供8个有效的-O选项,尽管有些选项具有相同的含义。

该答案的原始版本指出有7个选项。此后,GCC已将-Og总数增加到8

手册页:

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


23
如果你在Mac OS X开发有一个额外-Oz的设置,这是“为大小优化更积极比-Os:” developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/...
pauldoo

6
注意:O3不一定比O2好,即使名称暗示如此。尝试两者。
johan d 2013年

1
@pauldoo 404页面,替换为archive.org
2013年

还有-Og,这是所有不干扰调试的优化选项
einpoklum

47

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

我们将得出以下结论:

  • 上面的东西-O3最多INT_MAX是一样的-O3,但可以很容易地改变未来,所以不要依赖它。
  • 如果您输入大于的整数,则GCC 5.1将运行未定义的行为INT_MAX
  • 该参数只能包含数字,否则会正常失败。特别是,这排除了负整数,例如-O-1

专注于子程序

首先要记住,GCC只是一个前端为cppascc1collect2。快速的./XXX --help说,只有collect2and cc1take -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 common.opt

common.opt是在描述的具体GCC CLI选项描述格式内部文档通过并翻译到C opth-gen.awkOPTC-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>是从另外一个单独的家庭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

我们回溯一下grep,看看谁调用了此函数,并且我们看到唯一的代码路径是:

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

main.c是的切入点cc1。好!

此功能的第一部分:

  • 经营实体integral_argument这就要求atoi相应的字符串OPT_O来解析输入参数
  • 存储的值内 opts->x_optimize,其中opts是一个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_argumentatoi被施加到所述输入参数,因此INT_MAX是一个上限。而且,如果您放大一些,似乎GCC会运行C未定义的行为。哎哟?

integral_argumentatoi如果任何字符都不是数字,还可以自动包装并拒绝该参数。因此,负值会正常失败。

返回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_optimizationchar以节省空间。因此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_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没有更多用途

的主要用途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它的值以将其向前传递,因此我们应该没事。


38

七个不同的级别:

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

  • -O-O1(相同):优化,但不要花费太多时间。

  • -O2:更积极地优化

  • -O3:最积极地优化

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

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

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

还有一些其他选项均未启用,必须分别启用。也可以使用优化选项,但是禁用此优化启用的特定标志。

有关更多信息,请参见GCC网站。


的确,尽管与其他答案公平,但写这些答案时-Ofast和-Og都不存在。
janneb 2013年

那么为什么要-O100编译呢?
einpoklum

3
@einpoklum,因为GCC将-O3之上的所有内容都等同于-O3。
黛咪

不幸的是,使用-Og在调试器中仍然可以得到大量的<optimized out>。步进仍然随机跳来跳去。恕我直言,这没用。
doug65536 '17

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.