有多少个GCC优化级别?
我尝试了gcc -O1,gcc -O2,gcc -O3和gcc -O4
如果我使用非常大的数字,它将无法正常工作。
但是,我尝试了
gcc -O100
然后编译。
有多少个优化级别?
-fomit-stack-pointer
将更改生成的代码。
有多少个GCC优化级别?
我尝试了gcc -O1,gcc -O2,gcc -O3和gcc -O4
如果我使用非常大的数字,它将无法正常工作。
但是,我尝试了
gcc -O100
然后编译。
有多少个优化级别?
-fomit-stack-pointer
将更改生成的代码。
Answers:
值得一提的是,您可以为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
-Oz
的设置,这是“为大小优化更积极比-Os
:” developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/...
-Og
,这是所有不干扰调试的优化选项
让我们解释一下GCC 5.1的源代码,以了解发生了什么,-O100
因为手册页上尚不清楚。
我们将得出以下结论:
-O3
最多INT_MAX
是一样的-O3
,但可以很容易地改变未来,所以不要依赖它。INT_MAX
。-O-1
专注于子程序
首先要记住,GCC只是一个前端为cpp
,as
,cc1
,collect2
。快速的./XXX --help
说,只有collect2
and cc1
take -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
common.opt是在描述的具体GCC CLI选项描述格式内部文档通过并翻译到C opth-gen.awk和OPTC-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>
是从另外一个单独的家庭Os
,Ofast
和Og
。
构建时,这将生成一个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_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
in 的定义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
它的值以将其向前传递,因此我们应该没事。
七个不同的级别:
-O0
(默认):无优化。
-O
或-O1
(相同):优化,但不要花费太多时间。
-O2
:更积极地优化
-O3
:最积极地优化
-Ofast
:等同于-O3 -ffast-math
。 -ffast-math
触发不符合标准的浮点优化。这使编译器可以假装浮点数是无限精确的,并且它们上的代数遵循实数代数的标准规则。它还告诉编译器告诉硬件至少在某些处理器(包括x86和x86-64)上,将异常值刷新为零并将异常值视为零。异常会在许多FPU上触发一条缓慢的路径,因此将它们视为零(不会触发缓慢的路径)可以赢得很大的性能。
-Os
:优化代码大小。由于具有更好的I缓存行为,在某些情况下,这实际上可以提高速度。
-Og
:优化,但不干扰调试。这为调试版本提供了非令人尴尬的性能,并旨在代替-O0
调试版本。
还有一些其他选项均未启用,必须分别启用。也可以使用优化选项,但是禁用此优化启用的特定标志。
有关更多信息,请参见GCC网站。
-O100
编译呢?
man gcc
Cygwin(12000个奇数行),您也可以搜索-O
并找到下面状态的所有答案,然后找到一些答案。