【问题标题】:How does an ahead-of-time compiler determine how far to go with optimization?提前编译器如何确定优化的距离?
【发布时间】: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


【解决方案1】:

这实际上只是启用了哪些优化以及编译器中实际可用的优化的问题。一些优化,比如函数内联和常量传播,基本上是普遍可用的并且相对容易实现。因此,大多数编译器会优化第一个具有最多优化设置的程序。

第二个程序需要循环分析和循环消除来优化,这要复杂得多。编译器可能可以优化第二个程序,但您的编译器很可能没有优化此类循环的机制(证明浮点优化的正确性通常比证明整数的正确性要复杂得多优化)。请注意,如果 start 被声明为 int,我的 GCC 版本会优化循环。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-14
    • 2016-04-06
    • 1970-01-01
    • 2011-11-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多