7

这是一个计算整数除数的简短程序。该程序运行正常。然而,问题是,-O3在 Clang C++ 编译器(版本 3.3,主干 180686)的当前主干的优化标志下,程序的行为发生了变化,结果不再正确。

代码

这是代码:

#include <iostream>

constexpr unsigned long divisors(unsigned long n, unsigned long c)
{
    // This is supposed to sum 1 anytime a divisor shows up
    // in the recursion
    return !c ? 0 : !(n % c) + divisors(n, c - 1);
}

int main()
{
    // Here I print the number of divisors of 9 numbers! (from 1 to 9)
    for (unsigned long i = 1; i < 10; ++i)
        std::cout << i << " has " << divisors(i, i) << " divisors" << std::endl;
}

正确的行为

这是使用的编译命令,以及程序在正常情况下显示的正确和预期的输出:

clang++ -O2 -std=c++11 -stdlib=libc++ -lcxxrt -ldl sample.cpp -o sample
./sample 
1 has 1 divisors
2 has 2 divisors
3 has 2 divisors
4 has 3 divisors
5 has 2 divisors
6 has 4 divisors
7 has 2 divisors
8 has 4 divisors
9 has 3 divisors

不正确的行为

这是用于生成提供不正确输出的二进制文件的命令行。请注意,唯一的变化是优化标志 ( -O2to -O3.)

clang++ -O3 -std=c++11 -stdlib=libc++ -lcxxrt -ldl sample.cpp -o sample
./sample 
1 has 1 divisors
2 has 2 divisors
3 has 2 divisors
4 has 1 divisors
5 has 2 divisors
6 has 3 divisors
7 has 2 divisors
8 has 2 divisors
9 has 2 divisors

编辑

我已经更新到树干尖端,clang 版本 3.4(树干 183073)。该行为不再重现,它应该已经以某种方式修复。任何知道它是什么问题的人,如果有一个实际验证和修复,请随时提供答案。如果没有经过验证,则可能会发生回归。

4

1 回答 1

6

看起来你被llvm 中的这个 bug咬了。您可以通过禁用循环矢量化器来解决它,或者(正如您已经发现的那样)通过更新到比 r181286 更新的版本的 llvm 构建。

如果您检查差异,您会看到已添加测试用例作为修复的一部分。这应该可以防止这个问题在未来再次出现。

于 2013-06-02T04:48:01.893 回答