7

これは、整数の約数を数える短いプログラムです。プログラムは正しく動作します。ただし、問題は、-O3Clang 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 のこのバグに噛まれたようです。ループ ベクトライザーを無効にするか、(すでにわかっているように) r181286 よりも新しいリビジョンの llvm ビルドに更新することで回避できます。

差分を確認すると、修正の一部としてテスト ケースが追加されていることがわかります。これにより、この問題が将来再び発生するのを防ぐことができます。

于 2013-06-02T04:48:01.893 に答える