【问题标题】:GCC optimization of while loop with expression带有表达式的while循环的GCC优化
【发布时间】:2011-11-18 11:16:48
【问题描述】:
我有以下情况:
while (node != NULL && has_all_except)
{
...
}
如果node和has_all_except在循环中都没有被修改,gcc会优化循环只计算一次表达式吗?
我研究了关于编译器优化的维基百科文章 (http://en.wikipedia.org/wiki/Compiler_optimization),但无法得到明确的答案。我的胆量说它会被优化。
【问题讨论】:
标签:
gcc
while-loop
compiler-optimization
【解决方案1】:
这取决于循环中的任何代码是否可以直接或间接修改node 或has_all_except。例如。如果node 是一个全局变量并且您在循环中进行了函数调用,那么编译器不能假定node 不会被修改为函数调用的副作用。
【解决方案2】:
&& 运算符是惰性求值的。
如果node != NULL 为假,则甚至不会考虑has_all_except。这是语言规则,也不是优化。
如果两者都没有被更改,则无条件循环在理论上是可能的,这取决于它们可以从哪里修改以及发现它的难易程度。我怀疑对于现代 CPU 而言,它可能更糟糕,而不仅仅是应用测试。 (它会引入更多的总分支、更多的代码和更大的内存需求——另一方面,分支预测应该在循环控制方面做得很好)。
您可以使用goto 自己实现这种“优化”来测试它(注意:我不提倡使用goto,但它确实可移植地“模拟”正在讨论的建议优化的效果)。我认为看一个例子会使我讨论的问题更清楚,例如:
#include <stdlib.h>
int do_stuff(); // returns true/false if things were changed
int other_stuff(); // returns true/false if changed
int main() {
int has_all_except = 1;
void *node = &has_all_except;
while (node != NULL && has_all_except) {
int changed = 0; // flag to watch for changes
nochanges: // Place to jump to to unconditionally
changed |= do_stuff();
changed |= other_stuff();
if (!changed)
goto nochanges; // Unconditional jump
}
}
问题在于我们成功地引入了无条件跳转,但是无条件跳转本身是有条件应用的并且该条件并不比第一个简单&& 本身的一部分。
这样做意味着:
- 一个额外的
int 作为“标志”,看看是否有任何问题
-
do_stuff() 和 other_stuff() 的合作 - 如果 任何事情 不合作,那么这是不可能的(您的编译器不太可能跨翻译单元为您解决这个问题)
- 更多代码,因此处理器拥有的任何缓存中的空间都更少
- 更多分支,因此管道停顿、预测和较差预测的可能性更大
如果它值得做并且安全,那么我相当有信心它会由适当的现代编译器完成。如果没有完成,那么我怀疑它不值得(没有更好的性能),或者应用不安全。无论哪种方式,编译器都比绝大多数程序员更能理解在特定平台上为您的代码优化循环的复杂性!