Разрешено ли компиляторам удалять бесконечные циклы, как это делает компилятор Intel C ++ с параметром -O2? - PullRequest
11 голосов
/ 20 августа 2010

Следующий код тестирования работает правильно в VS с отладкой или выпуском, а также в GCC. Это также верно для ICC с отладкой, но не при включенной оптимизации (-O2).

#include <cstdio>

class tClassA{
public:
  int m_first, m_last;

  tClassA() : m_first(0), m_last(0) {}
  ~tClassA() {}

  bool isEmpty() const {return (m_first == m_last);}
  void updateFirst() {m_first = m_first + 1;}
  void updateLast() {m_last = m_last + 1;}
  void doSomething() {printf("should not reach here\r\n");}
};

int main() {
  tClassA q;
  while(true) {
    while(q.isEmpty()) ;
    q.doSomething();
  }
  return 1;
}

Предполагается остановиться на while(q.isEmpty()). Однако, когда -O2 включен в ICC (выпуск), он начинает бесконечно "делать что-то".

Поскольку это однопоточная программа и isEmpty() следует оценивать как true, я не могу найти причину, по которой ICC должен вести себя таким образом? Я что-то пропустил?

Ответы [ 7 ]

10 голосов
/ 20 августа 2010

Поскольку цикл while (q.isEmpty()) ; не содержит операторов, которые могли бы когда-либо вызывать видимый извне побочный эффект, весь цикл оптимизируется из-за отсутствия. По той же причине:

for (int i = 0; i < 10; i++)
    ;

можно было бы оптимизировать из-за отсутствия, если i не было volatile (сохранение в volatile объектов является частью "внешне видимых" эффектов программы).

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

2 голосов
/ 20 августа 2010

Это звучит как ошибка.Вот (довольно дикое) предположение о том, к чему могли привести рассуждения ...

После встраивания он видит:

while (q.m_first == q.m_last) /* do nothing */ ;
do_something();

и любая последовательность do nothing repeatedly ; do something может быть переведена впросто "сделай что-нибудь".Это падает, если повторяемая часть бесконечна (как в этом случае).Но, возможно, они не проверяют свою компиляцию на примерах, которые намеренно имеют бесконечный цикл; -).

1 голос
/ 21 августа 2010

Стандарт C ++ позволяет удалять петли без побочных эффектов, даже если они не заканчиваются:

Обычно считается, что важно разрешить преобразование потенциально не заканчивающихсяциклы (например, путем слияния двух циклов, которые повторяются по одному и тому же потенциально бесконечному набору, или путем исключения цикла без побочных эффектов), даже если это не может быть оправдано иным образом в случае, когда первый цикл никогда не заканчивается.http://www.open -std.org / jtc1 / sc22 / wg21 / docs /apers / 2007 / n2429.htm

Смотрите обсуждение здесь: http://blog.regehr.org/archives/161

1 голос
/ 20 августа 2010

Немного в стороне, эта версия icc делает то, что вы хотите.То есть он никогда не вызывает doSomething().

[9:41am][wlynch@computer /tmp] icc --version
icc (ICC) 11.0 20081105
1 голос
/ 20 августа 2010

Есть ли шанс, что фактический код, который вы создали и выполнили, пропустил точку с запятой после while(q.isEmpty())?Это, безусловно, привело бы к бесконечному вызову следующей строки.

0 голосов
/ 20 августа 2010

Я думаю, что это могла быть ваша версия gcc. Я скомпилировал вашу прогу под 4.4.2 и она работала точно так, как и должна.

0 голосов
/ 20 августа 2010

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

...