9

考虑以下简单的程序(改编自这个问题):

#include <cstdlib>

int main(int argc, char** argv) {
    int mul1[10] = { 4, 1, 8, 6, 3, 2, 5, 8, 6, 7 }; // sum = 50
    int mul2[10] = { 4, 1, 8, 6, 7, 9, 5, 1, 2, 3 }; // sum = 46

    int x1 = std::atoi(argv[1]);
    int x2 = std::atoi(argv[2]);

    int result = 0;

    // For each element in mul1/mul2, accumulate the product with x1/x2 in result
    for (int i = 0; i < 10; ++i) {
        result += x1 * mul1[i] + x2 * mul2[i];
    }

    return result;
}

我相信它在功能上等同于以下一个:

#include <cstdlib>

int main(int argc, char** argv) {
    int x1 = std::atoi(argv[1]);
    int x2 = std::atoi(argv[2]);

    return x1 * 50 + x2 * 46;
}

然而clang 3.7.1gcc 5.3icc 13.0.1似乎无法进行这样的优化,即使使用-Ofast. (注意生成的程序集在编译器之间是如何大不相同的!)。但是,当从等式中删除mul2和时, clang能够执行类似的优化,即使是.x2-O2

是什么阻止了两个编译器将第一个程序优化为第二个程序?

4

2 回答 2

4

完整的表达方式对于 clang 来说也太复杂了。如果你拆分它,那么一切都会再次优化:

int result1 = 0;
int result2 = 0;

for (int i = 0; i < 10; ++i) {
    result1 += x1 * mul1[i];
    result2 += x2 * mul2[i];
}

std::cout << (result1 + result2);
于 2015-06-10T08:55:37.783 回答
2

我不是编译器程序员,所以这只能是猜测。恕我直言,答案是@dlask 的答案的一部分,也是当您从表达式中删除x2mul2从表达式中进行优化时clang 进行优化的评论的一部分。

编译器可能会优化掉它所能做的所有事情。但我也认为优化编译器已经是庞大而复杂的程序,其中的错误可能会产生严重的后果,因为它们几乎是其他所有东西的基础(Python 最新的解释器是用 ... C 编写的)

所以必须在优化器的效率和它的复杂性之间取得平衡,我认为这个示例程序对于 gcc 来说已经超出了它,而对于 clang 来说就差不多了。没有什么能阻止他们进行这种优化,只是对于这些编译器的当前版本来说太复杂了。

于 2015-06-10T09:40:04.107 回答