在GCC中禁用所有优化选项

23

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


    gcc -O0 test.c 

然而,为了检查是否真的关闭了所有优化,我执行了该命令:

然而,为了检查是否真正关闭了所有优化,我执行了这个命令:

    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进行比较。就像“acovea”一样。因此,我想将我生成的序列与零优化级别(应该是-O0)进行比较

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

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


3
大多数使用 -O0 的选项不是优化选项(但是确实有一些)。 - Konrad Rudolph
2
@KonradRudolph 这种行为让我非常恼火。当调试某些晦涩的行为时,我希望关闭所有优化。该死的编译器,拒绝听取我的要求.. :) - Martin James
1
@KonradRudolph 我不同意你的观点。例如,-fdce:在O0中激活可以执行死代码消除。 - staticx
1
@staticx 这与我的评论有何矛盾之处? - Konrad Rudolph
默认的优化级别是-O0,而不是-O1。 - interjay
显示剩余4条评论
3个回答

19

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

从另一个角度考虑:GCC的输入语言相当丰富(即使是纯C语言,您也有whilefor等),但是中间的Gimple语言要简单得多(特别是Gimple/SSA),因此您需要应用一些“转换”以从源AST到Gimple。这些“转换”实质上就是优化通道。

参见该答案图片(一个SVG图像),并阅读此处所提到的引用。

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


11

好的

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所做的”之间。

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

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

由此可以推断出,可能存在不增加编译时间也不影响调试的优化,这些优化将被保留。


是的,但我需要了解为什么在O0级别内某些选项被激活。 - staticx
我不确定对于那个问题是否有比“因为这就是 https://github.com/gcc-mirror/gcc/blob/master/gcc/toplev.c 所做的事情”更好的答案。 - abligh
谢谢指点。如果编译程序时默认启用了某些优化选项,那么为什么GCC的人会说O0根本没有优化呢?这有点奇怪。 - staticx
@staticx 那些人是错的 - 我已经在手册页面中包含了该段落。 - abligh
这在当前的GCC上失败了-- gcc: error: unrecognized command line option ‘-fno-no-threadsafe-statics’; did you mean ‘-fno-threadsafe-statics’? - S.S. Anne
使用AWK重新编写:gcc -Q -O0 --help=optimizers | awk -v ORS=" " '($1 ~ /^-f/) && ($2 ~ /enabled/) {print "-fno-" substr($1,3)}' - undefined

5
为了回答我的问题,我得出了一些结论和假设:
因此,用O0编译并不意味着不会应用任何优化。像@abligh上面说的那样,将打开减少编译时间和使调试更好的选项。
换句话说,O0在编译级别进行优化。生成的二进制文件没有优化以便于调试过程。
我举个例子:这个选项在O0级别是启用的
-faggressive-loop-optimizations
在GCC文档中:
此选项告诉循环优化器使用语言约束来推导循环的迭代次数的界限。这假定循环代码不通过例如引起有符号整数溢出或越界数组访问来调用未定义行为。循环迭代次数的边界用于指导循环展开、剥离和循环退出测试优化。此选项默认启用。 因此,对于GCC 4.8.x,几乎有50个选项默认打开。

你确定它在 -O0 下启用了吗?我理解 "enabled by default" 的意思是 "默认情况下未被禁用",但这并不意味着它在所有优化级别下都被使用。我只期望在启用时才会在 -O2-O3 下使用它。 - M.M
你可以使用 "gcc -Q -O0 --help=optimizers" 查看它。 - staticx
这让我很感兴趣。我不知道问题是来自那个命令还是O0默认激活了一些选项。 - staticx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接