有多less个GCC优化级别?

有多less个GCC优化级别?

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

如果我使用一个非常大的数字,它将不起作用。

不过,我已经尝试过了

gcc -O100 

并编译。

有多less优化级别?

要迂腐,有8个不同的有效的-O选项,你可以给海湾合作委员会,但也有一些意思是相同的事情。

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

从手册页:

  • -O (与-O1相同)
  • -O0 (不进行优化,如果没有指定优化级别,则默认为默认值)
  • -O1 (最小优化)
  • -O2 (优化更多)
  • -O3 (优化更多)
  • -Ofast (非常积极地进行优化以达到违反标准的要求)
  • -Og (优化debugging体验-Og使优化不会影响debugging,它应该是标准编辑 – 编译 – debugging周期的优化级别,提供合理的优化级别,同时保持快速编译和良好的debugging经验。)
  • -Os (优化大小 – -Os使所有-O2优化不会增加代码大小,还可以执行进一步的优化来减less代码大小。- -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

七个不同的层次:

  • -O0 (默认):没有优化。

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

  • -O2 :优化更积极

  • -O3 :最积极地进行优化

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

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

  • -Og :优化,但不妨碍debugging。 这为debugging版本提供了非令人尴尬的性能,并且用于replacedebugging版本的-O0

还有其他选项不能被任何这些选项启用,并且必须单独启用。 也可以使用优化选项,但禁用通过此优化启用的特定标志。

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

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

我们将得出结论:

  • 任何超过-O3 INT_MAX都与-O3相同,但在未来很容易改变,所以不要依赖它。
  • 如果input大于INT_MAX整数,GCC 5.1会运行未定义的行为。
  • 该参数只能有数字,否则会优雅地失败。 尤其是,这排除了像-O-1这样的负整数

专注于子程序

首先记住GCC只是cpp的前端, ascc1collect2 。 一个快速的./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共同

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是分开的。

当我们构build时,这将生成一个options.h文件,其中包含:

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

作为奖励,当我们在common.opt里面\bO\n ,我们注意到这些行:

 -optimize Common Alias(O) 

它告诉我们--optimize (双破折号,因为它开始于对.opt文件进行破折号-optimize )是一个未logging的别名,可以用作--optimize=3

在哪里使用OPT_O

现在我们grep:

 git grep -E '\bOPT_O\b' 

这指向了两个文件:

  • opts.c
  • LTO-wrapper.c

我们先来opts.c

opts.c:default_options_optimization

所有的opts.c用法都在里面: default_options_optimization

我们grep回溯看看谁调用这个函数,我们看到唯一的代码path是:

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

main.ccc1的入口点。 好!

这个函数的第一部分:

  • 那么调用与OPT_O相对应的string上的atoi来parsinginput参数的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; 

所以我们猜测这是包含整个configuration全局状态的东西,而int x_optimize是优化值。

255是内部最大值

opts.c:integral_argumentatoi应用于input参数,所以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这听起来很有趣。 我们input它,然后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是最大的可能。

然后我们在common-target.hsearchOPT_LEVELS_3_PLUS的定义:

 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 }, [...] } 

所以这是在文档中提到的特定优化映射的编码。 太好了!

确保x_optimize没有更多的用途

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

我们grep ,并find更多。 这个数字很小,经过人工检查,我们发现每一个用法最多只有一个x_optimize >= 3 ,所以我们的结论是成立的。

LTO-wrapper.c

现在我们来OPT_O第二次出现的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的值来传递它,所以我们应该没问题。

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