为什么使用clang -O3会出现这种行为?

7

这里是一个简短的程序,用于计算整数的因子数量。该程序确实可以正确运行。然而,问题在于在当前Clang C++编译器(版本3.3,trunk 180686)的-O3优化标志下,程序的行为会发生变化,结果不再正确。

代码

以下是代码:

#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

不正确的行为

使用以下命令行生成二进制文件会产生不正确的输出。请注意,唯一的更改是优化标志(-O2 更改为 -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)。行为不再重现,应该已经被修复了。如果有人知道问题是什么,如果确实已经验证并解决了问题,请随时提供答案。如果没有验证,可能会发生回归。

1个回答

6

看起来你遇到了llvm中的这个bug。你可以通过禁用循环向量化器或更新到比r181286新的llvm构建版本来解决它(就像你已经找到的那样)。

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


你进行了二分法吗?这个过程很繁琐吗?因为我无法及时在我的机器上实现二分法。 - oblitum
我试过了,感觉还不错。你是在用git还是svn? - Carl Norum
目前我正在使用 LLVM 的 SVN 存储库,但是如果有机会的话,我会选择 Git。即便使用 Git,我也更担心构建时间和二分查找之后的效率问题。 - oblitum
llvm+clang(这是我测试的全部内容)在我的机器上(17英寸MacBook Pro)甚至不到十分钟就可以从头开始构建。也许会稍微长一点?但总的来说还不错。二分步骤也不总是需要完全重建,因此通常比那快。总体而言,这并不太糟糕-今天我在家里做其他事情的同时,顺便完成了它。 - Carl Norum
好的,我从未尝试过处理这种繁重的东西,但我想为了体验一下我会试一试。 - oblitum
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接