Почему это поведение на Clang -O3?

Вот короткая программа для подсчета количества делителей целого числа. Программа работает правильно. Проблема, однако, в том, что под -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

Неверное поведение

Это используемая командная строка, которая производит двоичный файл, который дает некорректный выход. Обратите внимание, что единственным изменением является флаг оптимизации (-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

РЕДАКТИРОВАТЬ

Я обновился до кончика багажника, лязг версии 3.4 (багажник 183073). Поведение больше не воспроизводится, должно быть уже как-то исправлено. Любой, кто знает, что это была за проблема, если она была действительно проверена и исправлена, пожалуйста, не стесняйтесь дать ответ. Если ничего не подтверждено, может произойти регрессия.

7

Решение

Похоже, тебя укусила эта ошибка в llvm. Вы можете обойти это, отключив векторизатор цикла или (как вы уже нашли), обновив до сборки llvm с ревизией, более новой, чем r181286.

Если вы посмотрите различия, вы увидите, что тестовый пример был добавлен как часть исправления. Это должно предотвратить появление этой проблемы в будущем.

6

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]