禁用 GCC 中的所有优化选项

Posted

技术标签:

【中文标题】禁用 GCC 中的所有优化选项【英文标题】:Disable all optimization options in GCC 【发布时间】:2016-01-21 14:21:09 【问题描述】:

使用 GCC 编译 C 程序的默认优化级别是 -O0。 根据 GCC 文档关闭所有优化。 例如:

    gcc -O0 test.c 

但是,要检查 -O0 是否真的关闭所有优化。我执行了这个命令:

    gcc -Q -O0 --help=optimizers 

在这里,我有点惊讶。我启用了大约 50 个选项。 然后,我使用以下命令检查了传递给 gcc 的默认参数:

    gcc -v 

我知道了:

Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.8/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.8.4-       
2ubuntu1~14.04' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --      
enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --
program-suffix=-4.8 --enable-shared --enable-linker-build-id --
libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-
gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-
sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-
time=yes --enable-gnu-unique-object --disable-libmudflap --enable-plugin --
with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-
cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-
java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 --with-
jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-amd64 --with-arch-
directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-
gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --
with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release 
--build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu

Thread model: posix

gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04) 

所以我的结论是我提供给程序的-O0 标志没有被其他东西覆盖。

事实上,我正在寻求从头开始实现一个生成随机优化选项序列并将生成的序列与默认级别 0-3 进行比较的工具。就像“凹凸”一样。因此,我想将我生成的序列与零优化级别(应该是-O0)进行比较

你能解释一下为什么-O0默认启用50个选项吗?

我想到的一个想法是使用-O0 编译并使用-fno-OPTIMIZATION_NAME 关闭-O0 中的默认优化50 次。你怎么看?

【问题讨论】:

-O0 启用的大多数选项都不是优化选项(但是是的,有一些)。 @KonradRudolph 这种行为让我非常恼火。在调试一些晦涩的行为时,我希望关闭所有优化。 Soddin'编译器,拒绝听.. :) @MartinJames 您可以通过编写 -fno 而不是 -f 手动禁用所有 -f 标志(对于 GCC)。这可行,但耗时且不实用 @KonradRudolph 我不同意你的看法。例如 -fdce: 在 O0 中激活执行死代码消除 @staticx 这与我的评论有何矛盾? 【参考方案1】:

严格来说,GCC 编译器中端是由一系列优化通道组成的(实际上是一个嵌套树,在编译过程中动态变化),因此如果 GCC 不进行优化,它将无法发出任何代码。

换一种方式想一想:GCC 的输入语言非常丰富(即使对于纯 C,你有 whilefor,....)但是中间的 Gimple 语言要差得多(在特定的 Gimple/SSA),因此您需要应用一些转换以从源 AST 转到 Gimple。这些转换优化通道,几乎按照定义。

另请参阅 answer 和 this 的图片(SVG 图像)并阅读提到的参考资料 here。

您应该将-O0 理解为禁用任何不需要生成某些可执行文件的附加优化(例如,由-O1 等提供)。

【讨论】:

【参考方案2】:

gcc -O0 `gcc -Q -O0 --help=optimizers 2>&1 | perl -ane 'if ($F[1] =~/enabled/) $F[0] =~ s/^\s*-f/-fno-/g;push @o,$F[0]; END print join(" ", @o)'` your args here

将关闭所有选项(糟糕)。

更严重的是,如果您要涵盖所有优化状态,请列出优化标志(无论如何您都需要这样做),并使用-fmyflag-fno-myflag 明确打开或关闭每个优化标志。这实质上回答了您的第二个问题。

但是,您可能会认为关闭所有-O 级别的优化是不值得的。

至于为什么是这样的,介于“太宽泛”(即你必须问是谁写的)和“因为这就是https://github.com/gcc-mirror/gcc/blob/master/gcc/toplev.c 所做的”之间的某个地方 em>。

请注意,文档并没有说 -O0 禁用优化。它说(来自man page):

-O0 减少编译时间,让调试产生预期的结果。这是默认设置。

暗示可能存在不增加编译时间且不影响调试的优化,这些将被保留。

【讨论】:

是的,但我需要了解为什么在 O0 级别中激活了某些选项 我不确定这个问题是否有比 更好的答案,因为这就是 github.com/gcc-mirror/gcc/blob/master/gcc/toplev.c 所做的' 是的,感谢您的指点。如果在编译程序时默认激活了一些优化选项,那么为什么 GCC 人说 O0 根本没有优化。这有点奇怪 @staticx 那些人会错的 - 我已经包含了手册页中的部分。 这在当前的 GCC 上失败 -- gcc: error: unrecognized command line option ‘-fno-no-threadsafe-statics’; did you mean ‘-fno-threadsafe-statics’?【参考方案3】:

为了回答我的问题,我做了一些结论和假设:

所以我说使用 O0 编译并不意味着不会应用任何优化。正如上面@abligh 所说,减少编译时间并使调试更好的选项将被打开。

也就是说,O0 是在编译层面进行优化。生成的二进制文件未进行优化以简化调试过程。

我举个例子:这个选项在O0级别启用

-faggressive-loop-optimizations

在 GCC 文档中:

此选项告诉循环优化器使用语言约束来导出循环迭代次数的界限。这假设循环代码不会通过例如导致有符号整数溢出或越界数组访问来调用未定义的行为。循环迭代次数的界限用于指导循环展开和剥离以及循环退出测试优化。 此选项默认启用。

所以对于 GCC 4.8.x,默认开启了将近 50 个选项。

【讨论】:

你确定在-O0启用了吗?我会将“默认启用”解释为“默认未禁用”,但这并不意味着它在所有优化级别都使用。我希望它仅在启用时用于-O2-O3 您可以使用 gcc -Q -O0 --help=optimizers 进行检查 这让我很感兴趣。我不知道问题是来自那个命令还是 O0 默认只是激活了一些选项

以上是关于禁用 GCC 中的所有优化选项的主要内容,如果未能解决你的问题,请参考以下文章

gcc的调试调研——gdb

GCC编译选项 -OX[转]

如何在 GCC 中通过优化构建发布模式?

GCC 优化选项

如何查看 gcc 优化选项?

GCC:程序不适用于编译选项 -O3