有多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
的前端, as
, cc1
, collect2
。 一个快速的./XXX --help
说只有collect2
和cc1
带-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
被转发给cc1
和collect2
。
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>
与另一个Os
, Ofast
和Og
是分开的。
当我们构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.c
是cc1
的入口点。 好!
这个函数的第一部分:
- 那么调用与
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_argument
, atoi
应用于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.h
searchOPT_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,但在某些时候你会溢出可变的大小限制。