Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why this behavior on clang -O3?

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.

Code

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;
}

Correct Behavior

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

Incorrect Behavior

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

EDIT

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.

like image 651
pepper_chico Avatar asked Jun 01 '13 04:06

pepper_chico


1 Answers

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.

like image 59
Carl Norum Avatar answered Sep 27 '22 17:09

Carl Norum