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

Следующий код тестирования работает правильно в 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 должен вести себя таким образом? Я что-то пропускаю?

11
задан Ciro Santilli 新疆改造中心法轮功六四事件 26 June 2015 в 08:04
поделиться

7 ответов

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

1
ответ дан 3 December 2019 в 09:39
поделиться

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

-3
ответ дан 3 December 2019 в 09:39
поделиться

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

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

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

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

9
ответ дан 3 December 2019 в 09:39
поделиться

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

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

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

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

2
ответ дан 3 December 2019 в 09:39
поделиться

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

0
ответ дан 3 December 2019 в 09:39
поделиться

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

[9:41am][wlynch@computer /tmp] icc --version
icc (ICC) 11.0 20081105
1
ответ дан 3 December 2019 в 09:39
поделиться

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

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

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

1
ответ дан 3 December 2019 в 09:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: