Оптимизация компилятора Visual Studio C ++, нарушающая код? - PullRequest
2 голосов
/ 16 сентября 2010

У меня есть особая проблема, которая возникает как в VS2005, так и в 2010 году. У меня есть цикл for, в котором вызывается встроенная функция, в сущности что-то вроде этого (C ++, только для иллюстративных целей):

inline double f(int a)
{
  if (a > 100)
  {
    // This is an error condition that shouldn't happen..
  }

  // Do something with a and return a double
}

И затем цикл в другой функции:

for (int i = 0; i < 11; ++i)
{
  double b = f(i * 10);
}

Теперь происходит то, что в отладочной сборке все работает нормально.В сборке релиза со всеми включенными оптимизациями это, согласно разборке, скомпилировано так, что i используется напрямую без * 10, а сравнение a > 100 превращается в a > 9, в то время как я предполагаю, что это должно быть a > 10.Есть ли у вас какие-либо сведения о том, что может заставить компилятор думать, что a > 9 - правильный путь?Интересно, что даже незначительное изменение (например, распечатка отладки) в окружающем коде заставляет компилятор использовать i * 10 и сравнивать его с буквальным значением 100.

Я знаю, что это несколько расплывчато, но я 'Буду благодарен за любую старую идею.

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

Вот, мы надеемся, воспроизводимый случай.Я не считаю его слишком большим, чтобы его можно было вставить здесь, так что вот так:

__forceinline int get(int i)
{
  if (i > 600)
    __asm int 3;

  return i * 2;
}

int main()
{
  for (int i = 0; i < 38; ++i)
  {
    int j = (i < 4) ? 0 : get(i * 16);
  }

  return 0;
}

Я проверил это с VS2010 на своей машине, и, похоже, он ведет себя так же плохо, как и исходный код, который у меня естьпроблемы с.Я скомпилировал и запустил это с пустым шаблоном проекта C ++ IDE по умолчанию в конфигурации выпуска.Как видите, разрыв никогда не должен быть достигнут (37 * 16 = 592).Обратите внимание, что удаление i < 4 делает эту работу, как и в оригинальном коде.

Ответы [ 4 ]

6 голосов
/ 01 марта 2013

Для всех, кто заинтересовался, это оказалось ошибкой в ​​компиляторе VS. Подтверждено Microsoft и исправлено в пакете обновления после отчета.

2 голосов
/ 16 сентября 2010

Во-первых, было бы полезно, если бы вы опубликовали достаточно кода, чтобы мы могли воспроизвести проблему.В противном случае вы просто запрашиваете психическую отладку.

Во-вторых, иногда случается, что компилятору не удается сгенерировать корректный код на самых высоких уровнях оптимизации, но, скорее всего, у вас просто есть ошибка где-то в вашем коде.Если где-то в вашем коде есть неопределенное поведение, это означает, что предположения, сделанные оптимизатором, могут не сохраниться, и тогда компилятор может в итоге генерировать плохой код.

Но, не увидев ваш реальный код, я не могудействительно получить более конкретную информацию.

0 голосов
/ 16 сентября 2010

Во-первых, встроенная сборка предотвращает определенные оптимизации, вы должны использовать встроенную функцию __debugbreak () для точки прерывания int3. Компилятор видит, что встроенная функция не имеет никакого эффекта, кроме точки останова, поэтому он делит 600 на 16 (примечание: на это влияет целочисленное усечение), таким образом он оптимизирует отладку для запуска с 38> i> = 37. Так что, кажется, работать над этим

0 голосов
/ 16 сентября 2010

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

Как уже говорилось, трудно иметь точную идею без дополнительного кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...