Here is a short program to count the number of divisors of an integer. The program does work correctly. The problem is, however, that under the -O3
optimization flag of the current trunk of the Clang C++ compiler (version 3.3, trunk 180686) the behavior of the program changes and the result is no longer correct.
Here's the code:
#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;
}
Here's the compile command used, and the correct and expected output, which the program exhibits under normal circumstances:
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
This is the command line used that produces the binary that gives incorrect output. Notice that the only change is the optimization flag (-O2
to -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
I've updated to tip of trunk, clang version 3.4 (trunk 183073). The behavior does not reproduce anymore, it should have been fixed somehow already. Anyone who knows what issue was it, if there was one actually verified and fixed, please feel free to provide an answer. If there was none verified, a regression may happen.
Looks like you got bitten by this bug in llvm. You can work around it by disabling the loop vectorizer, or (as you've already found), by updating to an llvm builit at a revision newer than r181286.
If you check out the diffs, you'll see a test case has been added as part of the fix. That should keep this problem from cropping up again in the future.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With