Разрешено ли компилятору постоянно сворачивать локальную переменную?

Рассмотрим этот простой код:

void g();

void foo()
{
    volatile bool x = false;
    if (x)
        g();
}

https://godbolt.org/z/I2kBY7

Вы можете видеть, что ни gcc, ни clang не оптимизируют потенциальный вызов g. В моем понимании это правильно: абстрактная машина предполагает, что переменные volatile могут изменяться в любой момент (например, из-за аппаратного отображения), поэтому постоянное свертывание инициализации false в проверку if будет неправильно.

Но MSVC полностью исключает обращение к g (хотя чтение и запись в volatile сохраняются!). Это стандартное поведение?


Background: I occasionally use this kind of construct to be able to turn on/off debugging output on-the-fly: The compiler has to always read the value from memory, so changing that variable/memory during debugging should modify the control flow accordingly. The MSVC output does re-read the value but ignores it (presumably due to constant folding and/or dead code elimination), which of course defeats my intentions here.


Редактирование:

  • Здесь обсуждается исключение операций чтения и записи в volatile: Разрешено ли компилятору оптимизировать локальную изменчивую переменную? (спасибо Натану!). Я думаю, что стандарт совершенно ясен, что эти чтения и записи должны произойти. Но это обсуждение не охватывает вопрос о том, является ли законным компилятор принимать результаты этих чтений как должное и оптимизировать их на этом основании. Я предполагаю, что это under-/не указано в стандарте, но я был бы счастлив, если бы кто-то доказал, что я неправ.

  • Конечно, я могу сделать x нелокальной переменной, чтобы обойти проблему. Этот вопрос больше из любопытства.

Ответы

Ответ 1

Я думаю, что [intro.execution] (номер параграфа может отличаться) можно использовать для объяснения поведения MSVC:

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

Стандарт не разрешает исключение чтения через изменчивое значение, но параграф выше может быть интерпретирован как позволяющий предсказать значение false.


Кстати, стандарт C (N1570 6.2.4/2) гласит, что

Объект существует, имеет постоянный адрес и сохраняет свое последнее сохраненное значение в течение всего срока его жизни. 34


34) В случае изменчивого объекта последнее хранилище не обязательно должно быть явным в программе.

Неясно, может ли быть неявное хранилище в объекте с автоматической продолжительностью хранения в памяти C/объектной модели.