Разрешено ли компилятору постоянно сворачивать локальную переменную? - PullRequest
25 голосов
/ 16 октября 2019

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

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 сохраняются!). Это стандартно-совместимое поведение?


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


Правка:

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

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

Ответы [ 3 ]

2 голосов
/ 23 октября 2019

TL; DR Компилятор может делать все, что ему захочется, при каждом энергозависимом доступе. Но документация должна вам сказать .-- «Семантика доступа через volatile glvalue определяется реализацией.»


Стандарт определяет для программы разрешенные последовательности «volatile access» и других«наблюдаемое поведение» (достигается с помощью «побочных эффектов»), которое реализация должна соблюдать в соответствии с «правилом« как будто »».

Но стандарт гласит (выделение жирным шрифтом):

Рабочий проект, стандарт для языка программирования C ++
Номер документа: N4659
Дата: 2017-03-21

§ 10.1. 7.1 Спецификаторы cv

5 Семантика доступа через энергозависимое glvalue определяется реализацией. […]

Аналогично для интерактивных устройств (мойвыделение жирным шрифтом):

§ 4.6 Выполнение программы

5 Соответствующая реализация, выполняющая правильно сформированную программу, должна производить то же наблюдаемое поведение, что и одно из возможных исполнений соответствующегоэкземпляр абстрактной машины с той же программой и тем же входом. [...]

7 Минимальные требования к соответствующей реализации:

(7.1) - Доступ через изменчивые значения вычисляется строго в соответствии с правилами абстрактной машины.
(7.2) - При завершении программы все данные, записанные в файлы, должны быть идентичны одному из возможных результатов, которые могло бы дать выполнение программы в соответствии с абстрактной семантикой.
(7.3) - Динамика ввода и вывода в интерактивном режимеУстройства должны работать таким образом, чтобы вывод на самом деле доставлялся до того, как программа ожидает ввода. То, что составляет интерактивное устройство, определяется реализацией.

Все вместе они называются наблюдаемым поведением программы. [...]

(В любом случае какой конкретный код генерируется для программы не указан стандартом.)

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

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

Хронически люди ошибочно полагают, что для изменчивых обращений оценка / чтение абстрактной машины вызывает реализованное чтение, а назначение / запись абстрактной машины вызывает реализованную запись. Нет никаких оснований для этого убеждения в отсутствие документации о реализации, говорящей об этом. Когда / iff реализация говорит, что на самом деле делает что-то при "изменчивом доступе", люди оправдывают ожидание того, что что-то--maybe, генерация определенного объектного кода.

2 голосов
/ 21 октября 2019

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

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

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


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

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


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

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

0 голосов
/ 24 октября 2019

Полагаю, что чек - это законноявное указание в программе

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

Сказав это, я думаю, что поведение MSVC является ошибкой. Нет реальной причины оптимизировать вызов. Такая оптимизация может быть послушной, но она излишне злая.

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