neu*_*cer 91 c compiler-construction optimization gcc
有多少GCC优化级别?
我尝试了gcc -O1,gcc -O2,gcc -O3和gcc -O4
如果我使用一个非常大的数字,它将无法正常工作.
但是,我试过了
gcc -O100
Run Code Online (Sandbox Code Playgroud)
并编译.
有多少优化级别?
Gle*_*len 126
要迂腐,你可以给gcc提供8种不同的有效-O选项,尽管有一些意思相同.
这个答案的原始版本说明有7个选项.此后海湾合作委员会增加-Og了总数达到8个
从手册页:
-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
Cir*_*四事件 44
让我们解释一下GCC 5.1的源代码,看看会发生什么,-O100因为在手册页上不清楚.
我们将得出结论:
-O3最多INT_MAX是一样的-O3,但可以很容易地改变未来,所以不要依赖它.INT_MAX.-O-1专注于子程序
首先要记住,GCC只是一个前端为cpp,as,cc1,collect2.快速./XXX --help说只有collect2并且cc1采取-O,所以让我们专注于他们.
和:
gcc -v -O100 main.c |& grep 100
Run Code Online (Sandbox Code Playgroud)
得到:
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.
Run Code Online (Sandbox Code Playgroud)
所以-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
Run Code Online (Sandbox Code Playgroud)
它指定了所有O选项.注意如何-O<n>在另一个家庭中Os,Ofast和Og.
构建时,会生成一个options.h包含以下内容的文件:
OPT_O = 139, /* -O */
OPT_Ofast = 140, /* -Ofast */
OPT_Og = 141, /* -Og */
OPT_Os = 142, /* -Os */
Run Code Online (Sandbox Code Playgroud)
作为奖励,当我们在\bO\n内部时,common.opt我们会注意到这些线条:
-optimize
Common Alias(O)
Run Code Online (Sandbox Code Playgroud)
它告诉我们--optimize(双击,因为它以文件-optimize上的破折号.opt开头)是一个未记录的别名-O,可以用作--optimize=3!
使用OPT_O的地方
现在我们grep:
git grep -E '\bOPT_O\b'
Run Code Online (Sandbox Code Playgroud)
这指向我们两个文件:
让我们先跟踪 opts.c
opts.c:default_options_optimization
所有opts.c用法都发生在:default_options_optimization.
我们回溯看看谁调用了这个函数,我们看到唯一的代码路径是:
main.c:maintoplev.c:toplev::mainopts-global.c:decode_optsopts.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;
[...]
}
Run Code Online (Sandbox Code Playgroud)
x_optimize线条来自哪里:
Variable
int optimize
Run Code Online (Sandbox Code Playgroud)
介绍common.opt,并且options.c:
struct gcc_options global_options;
Run Code Online (Sandbox Code Playgroud)
所以我们猜测这是包含整个配置全局状态的,并且int x_optimize是优化值.
255是内部最大值
in opts.c:integral_argument,atoi应用于输入参数,因此INT_MAX是上限.如果你把任何更大的东西,似乎GCC运行C未定义的行为.哎哟?
integral_argumentatoi如果任何字符不是数字,也会精简包装并拒绝参数.所以负值优雅地失败了.
回到opts.c:default_options_optimization,我们看到了这条线:
if ((unsigned int) opts->x_optimize > 255)
opts->x_optimize = 255;
Run Code Online (Sandbox Code Playgroud)
以便优化级别被截断为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.
Run Code Online (Sandbox Code Playgroud)
并在生成的options.h:
struct GTY(()) cl_optimization
{
unsigned char x_optimize;
Run Code Online (Sandbox Code Playgroud)
这解释了为什么截断:选项也必须转发到cl_optimization,它使用a 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;
Run Code Online (Sandbox Code Playgroud)
没有>= 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. */
};
Run Code Online (Sandbox Code Playgroud)
哈!这是一个强有力的指标,只有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 },
[...]
}
Run Code Online (Sandbox Code Playgroud)
所以这是-On对docs中提到的特定优化映射进行编码的地方.太好了!
确保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.
Run Code Online (Sandbox Code Playgroud)
在这个文件中,OPT_O出现似乎只是规范化值O以传递它,所以我们应该没问题.
Dem*_*emi 38
七个不同的级别:
-O0 (默认值):无优化.
-O或-O1(同样的事情):优化,但不要花太多时间.
-O2:更积极地优化
-O3:最积极地优化
-Ofast:相当于-O3 -ffast-math. -ffast-math触发非标准兼容的浮点优化.这允许编译器假装浮点数是无限精确的,并且它们上的代数遵循实数代数的标准规则.它还告诉编译器告诉硬件将非正规数刷新为零并将非正规数视为零,至少在某些处理器上,包括x86和x86-64.非正规在许多FPU上触发慢速路径,因此将它们视为零(不会触发慢速路径)可能是一个很大的性能胜利.
-Os:优化代码大小.在某些情况下,由于更好的I-cache行为,这实际上可以提高速度.
-Og:优化,但不干扰调试.这为调试版本提供了非令人尴尬的性能,旨在取代-O0调试版本.
还有其他选项未被其中任何一个启用,必须单独启用.也可以使用优化选项,但禁用此优化启用的特定标志.
有关更多信息,请参阅GCC网站.