【发布时间】:2013-08-03 07:21:52
【问题描述】:
现代编译器的优化越来越好,基本优化如常量折叠到利用 SIMD 指令。但是,我想知道这些优化应该走多远,以及现在的编译器是如何做出这种决定的。
我们来看一个例子:
#include <stdio.h>
static double naive_sin(double n) {
return n - n*n*n / 6.0 + n*n*n*n*n / 120.0 + n*n*n*n*n*n*n / 5040.0;
}
int main() {
printf("%f\n", naive_sin(1.0));
return 0;
}
当使用带有-O3 的GCC 编译它时,可以观察到生成的浮点数由编译器计算并存储在源代码中。显然不可能进一步优化。
现在,让我们看第二个例子:
#include <stdio.h>
int main() {
double start = 0.0;
for (int i = 0; i < 100; i++) {
start += 1.0;
}
printf("%f\n", start);
return 0;
}
考虑到第一个示例的结果,可以预期编译器会应用类似的优化并在生成的机器代码中生成常量100.0。但是,当查看输出时,发现循环仍然存在!
显然这种优化并不总是可行的。假设您正在编写一个将 pi 计算到一百万个位置的程序。这样的程序不需要用户输入,因此理论上结果可以由编译器硬编码为机器代码。当然这不是一个好主意,因为编译器会花费更长的时间来内部评估这样的程序,而不是只运行优化程度较低的版本。
在这种情况下,是什么让编译器决定不优化循环?是否有优化这种代码的语言/编译器,或者有什么东西阻止了这种情况?是否可能与无法预测程序是否会结束的概念有关?
【问题讨论】:
-
“提前编译器如何确定优化的距离?” - 它查看命令行标志:))
-
“无法预测程序是否会结束”(仅供参考)称为halting problem。请注意,编译器可以并且确实展开某些循环,因此编译器可以在 一些 情况下证明循环将终止。
-
这不是问题。 AOT 处理代码的图形,它实际上并不执行 代码。程序员不会编写无限嵌套的函数。
标签: c optimization compiler-construction