Почему этот энергозависимый доступ можно изменить в отношении энергонезависимого доступа?

Приведенный ниже пример кода взят из китайского блога, который представляет эффект volatile, Левая сторона - это код C; другой - сгенерированный ассемблерный код.

// cordering.c                                gcc -O2 -S -masm=intel cordering.c

int A;
volatile int B;
void foo()                                    mov   eax, DWORD PTR B[rip]
{                                             mov   DWORD PTR B[rip], 0
    A = B + 1;                                add   eax, 1
    B = 0;                                    mov   DWORD PTR A[rip], eax
}                                             ret

Как мы можем видеть в коде сборки, побочный эффект A помещается после побочного эффекта B, даже если B является volatile Квалифицированный. Тем не менее, cppreference.com говорит:

[W] В одном потоке выполнения изменчивые обращения не могут быть оптимизированы или переупорядочены с другим видимым побочным эффектом, который последовательно перед последовательным доступом или после него.

Здесь побочный эффект A последовательность перед B, так что я думаю, что это запрещено для компилятора. Я прав?


В качестве дополнения, блог сказал, если мы хотим гарантировать последовательность между volatile а также non-volatile типа, нам нужно сделать оба volatile:

// cordering.c                                gcc -O2 -S -masm=intel cordering.c

volatile int A;
volatile int B;
void foo()                                    mov   eax, DWORD PTR B[rip]
{                                             add   eax, 1
    A = B + 1;                                mov   DWORD PTR A[rip], eax
    B = 0;                                    mov   DWORD PTR B[rip], 0
}                                             ret

1 ответ

Решение

На странице, на которую вы ссылаетесь, написано:

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

Таким образом, если A не является volatile, доступ к A не рассматриваются как видимые побочные эффекты, и второе утверждение не применяется (так как оно ничего не говорит о переупорядочении видимого и невидимого доступа).

РЕДАКТИРОВАТЬ: Обратите внимание, что cppreference не официальная документация для C++, а усилия сообщества. Я полагаю, что цель заявления, выделенного жирным шрифтом, состояла в том, чтобы определить, что является видимым побочным эффектом, но оно не написано четко.

Окончательной ссылкой является стандарт C++ ( вот несколько вариантов его получения). Черновик стандарта N4659 определяет побочные эффекты в [intro.execution], параграф 14, и видимые побочные эффекты через цепочку определений из 2 страниц в [intro.races]. Я не эксперт по стандарту C++, поэтому я не могу расшифровать, что именно говорит стандарт без значительных усилий, но вы можете попробовать.

Однако для неформального объяснения того, какие оптимизации разрешено выполнять компилятору, вы можете взглянуть на правило " как будто" в cppreference.

РЕДАКТИРОВАТЬ 2: стандарт также формально определяет правило " как будто" в [intro.execution], параграф 7:

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

Короче говоря, любая оптимизация допустима, если программа выдает одинаковые выходные данные, а чтение и запись в энергозависимые объекты происходят в правильном порядке, что справедливо для вашего исходного примера.

Другие вопросы по тегам