Можно ли оптимизировать следующие строки кода? - PullRequest
0 голосов
/ 25 апреля 2018

Можно ли оптимизировать эти строки кода?

int *ptr = (int *)0x1234;
*ptr = 2;
/* no further code in the scope uses ptr */

Могу ли я быть уверен, что для любого достойного компилятора и с любым уровнем оптимизации этот код будет выполнен?

Проверка его с флагом -S на двух разных компиляторах (gcc и gcc-arm-none-eabi) показывает, что этот код не оптимизирован. Но я ищу определенные гарантии или рекомендации относительно этого конкретного кода.

Решено (Я полагаю): Принято решение, данное Джонатаном Ми из Википедия - Анализ псевдонимов

... если неизвестно, есть ли псевдоним p и q или нет, тогда никакие оптимизации не могут быть выполнены, и весь код должен быть выполнен

Насколько я понимаю, p в этом примере можно отнести к моему ptr, который указывает на 0x1234, а q можно рассматривать как ссылку на этот адрес в программе любого типа.

Ответы [ 2 ]

0 голосов
/ 25 апреля 2018

Нет, их нельзя оптимизировать.

int* ptr = (int*)0x12345 устанавливает указатель на байт, адресуемый 0x12345, который вы предположительно выделяете в другом месте? Однако такой адрес, будучи нечетным, не выровнен по байту, что в лучшем случае неоптимизировано.

*ptr = 2 назначает 2 этому адресу. Явная оптимизация этих строк приведет к другому состоянию памяти. Таким образом, они не могут быть оптимизированы.


Оптимизация без ссылок допускается с помощью анализа псевдонимов , с помощью которого можно определить, можно ли "получить доступ к хранилищу несколькими способами"

участвует в анализе псевдонимов на основе типов :

  1. Две переменные разных типов не могут быть в одном и том же классе псевдонимов, поскольку это свойство строго типизированных языков без ссылок на память (т. Е. Ссылки на области памяти не могут быть изменены напрямую) языков, которые две переменные разных типов не могут совместно использовать. в одной и той же ячейке памяти одновременно.
  2. Выделения, локальные для текущего фрейма стека, не могут быть в том же классе псевдонимов, что и любое предыдущее распределение из другого фрейма стека. Это так, потому что новые выделения памяти должны быть непересекающимися со всеми другими выделениями памяти.
  3. В общем, каждое поле записи каждого типа записи имеет свой собственный класс псевдонимов, поскольку дисциплина ввода обычно допускает только записи одного типа с псевдонимом. Поскольку все записи типа будут храниться в памяти в одинаковом формате, поле может иметь псевдоним только для себя.
  4. Аналогично, каждый массив данного типа имеет свой собственный класс псевдонимов.

2 - настоящий кикер здесь, потому что он не выделяется локально для текущего фрейма стека, ptr может быть связан с любым другим int в программе, таким образом, компилятор не может оптимизировать это прочь.

0 голосов
/ 25 апреля 2018

Если вы хотите быть уверены, что компилятор запишет значение 2 по адресу 0x12345, вас заинтересует квалификатор volatile.

volatile int *ptr = (int*) 0x12345; // hardware special address
*ptr = 2;

Это означает, что каждое чтениеили запись в *ptr должна рассматриваться компилятором как имеющая побочные эффекты и не может быть оптимизирована 1 .

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


1) Из последней версии C ++ (этот вопросбыл помечен C ++ в его первой версии), [dcl.type.cv]/6 приведено ниже.
2) Кредит пользователю StoryTeller.


[dcl.type.cv]/6

[Примечание: volatile - это подсказка для реализации, чтобы избежать агрессивной оптимизации с использованием объекта, поскольку значение объекта может быть изменено средствами, которые не могут быть обнаружены реализацией.Кроме того, для некоторых реализаций volatile может указывать, что для доступа к объекту требуются специальные аппаратные инструкции.Смотрите [intro.execution] для подробной семантики.Как правило, семантика volatile должна быть такой же в C ++, как и в C. - примечание к концу]

...