Различная оптимизация в VS2015 и VS2013 вызывает исключение с плавающей запятой

У меня есть небольшой пример проблемы, которая возникла при переходе с VS2013 на VS2015. В VS2015 далее упомянутый пример кода вызывает недопустимую операцию с плавающей точкой.

введите описание изображения здесь

int main()
{
unsigned int enableBits = _EM_OVERFLOW | _EM_ZERODIVIDE | _EM_INVALID;

_clearfp();
_controlfp_s(0, ~enableBits, enableBits);

int count = 100;
float array[100];

for (int i = 0; i < count; ++i)
{
array[i] = (float)pow((float)(count - 1 - i) / count, 4); //this causes exception in VS2015
}

return 0;
}

Это происходит только в режиме релиза, поэтому, вероятно, это вызвано другой оптимизацией. Что-то не так с этим кодом или это ошибка в VS 2015?

Трудно найти подобные проблемы по всей базе кода, поэтому я ищу какое-то систематическое исправление, а не обходной путь (например, используйте другую переменную вместо я который работает)

Я также проверил сгенерированный код ассемблера, и кажется, что в VS2013 он использует весь 128-битный реестр для выполнения 4 операций с плавающей запятой в одном подразделении. В VS2015 кажется, что он выполняет только 2 операции с плавающей запятой, а остальная часть реестра равна нулю (или некоторому мусору), что, вероятно, вводит это исключение.

Инструкция, которая вызывает исключение, отмечена на рисунке.

VS2013
VS2013

и VS2015
введите описание изображения здесь

Любая помощь будет оценена.
Благодарю.

4

Решение

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

Код выполняет 2 итерации одновременно (развертывание цикла), но использует divps, который делает 4 деления одновременно (из 4 операций с плавающей запятой в регистре XMM). Верхние 2 числа в регистре XMM не используются и равны нулю. В результате деления значений в этих слотах не используются, это обычно не имеет значения. Однако, когда вы устанавливаете обработку пользовательских исключений, это вызывает недопустимое операционное исключение, которое вы видите, даже если его генерирующие значения не будут использоваться.

На мой взгляд, вы можете выбрать / fp: strict, что отключит оптимизацию, поэтому сделайте это (но, очевидно, замедлит код) или удалите вызов controlfp.

1

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

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

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