禁用GCC中的所有优化选项
使用GCC编译C程序的默认优化级别是-O0。 根据GCC文档closures所有优化。 例如:
gcc -O0 test.c
但是,要检查-O0是否真的closures了所有的优化 。 我执行了这个命令:
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
标志没有被别的东西覆盖。
事实上,我正试图从头开始实施一种工具,可以生成随机优化选项序列,并将生成的序列与默认级别O0-3进行比较。 就像“acovea”一样。 所以,我想比较我生成的序列到零优化级别(应该是O0)
你能解释一下为什么-O0
默认启用了50个选项吗?
我想到的一个想法是用O0
编译+使用-fno-OPTIMIZATION_NAME
50次closuresO0
默认优化。 你怎么看?
GCC编译器中端是由一个序列(实际上是一个嵌套树,在编译过程中dynamic改变)的优化过程组成的,所以如果GCC没有进行优化,它将不能发出任何代码。
换个angular度来看,GCC的input语言是相当丰富的(即使对于普通的C语言,你也可以while
for
…),但是中级Gimple语言要差得多(特别是Gimple / SSA),所以你需要应用一些转换从源AST到Gimple。 这些转换几乎是按照定义进行的。
另请参阅这个答案和这个 (SVG图像)的图片,并阅读这里提到的参考。
您应该将-O0
理解为禁用任何额外的优化(例如-O1
等提供的)来生成一些可执行文件。
好
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
将把所有的选项closures(yuck)。
更严重的是,如果你正在覆盖所有的优化状态,做一个优化标志列表(你需要做的),并明确地打开或closures每一个与-fmyflag
或-fno-myflag
。 这实质上是回答你的第二个问题。
但是,您可能会认为在closures所有-O
级别的优化时玩起来不值得。
至于为什么会这样呢,那就是“太广泛”(也就是说你不得不问谁写的), 因为这就是https://github.com/gcc-mirror/gcc/blob/master/gcc/ toplev.c做' 。
注意文档没有说-O0
禁用了优化。 它说(从手册页 ):
-O0
减less编译时间并使debugging产生预期的结果。 这是默认的。
暗示可能会有优化,不会增加编译时间,也不会影响debugging,这些都会留下来。
为了回答我的问题,我做了一些结论和假设:
那么让我说,编译O0并不意味着不会优化。 减less编译时间和debugging更好的选项将打开,如上面所说的@abligh。
换句话说,O0在编译的层次上是最优化的。 生产的二进制文件没有被优化,以便于debugging过程。
我举一个例子:这个选项在O0级别启用
-faggressive循环的优化
在GCC文档中:
该选项告诉循环优化器使用语言约束来获得循环迭代次数的界限。 这假设循环代码不会调用未定义的行为,例如导致有符号整数溢出或出界数组访问。 循环迭代次数的界限用于指导循环展开和剥离以及循环退出testing优化。 该选项默认启用。
所以对于GCC 4.8.x,默认情况下几乎有50个选项打开。