Скажите компилятору gcc, чтобы он рассматривал переменную не как константу при оптимизации

Есть ли способ сообщить компилятору (здесь gcc), что он не должен оптимизировать переменные, которые он считает константами, в константные выражения? В общем, с помощью флага компилятора или, что еще лучше, с помощью атрибута для конкретной переменной?

Я хочу, чтобы (локальная) переменная действительно существовала, каждое чтение этой переменной действительно выполнялось, а также каждая запись, даже если я снова запишу одно и то же значение.

Он всегда будет загружать/сохранять переменную из/в ОЗУ, если я не оптимизирую. То же самое, если я объявлю его изменчивым. Однако я хочу, чтобы ее можно было хранить в регистре, как обычную переменную, которая не является ни постоянной, ни изменчивой. Полностью отключить оптимизацию тоже не вариант.

Пример кода (r(a) и r(b) — любой регистр):
int a, b;
a = 2;
a = 2;
b = a;
Результат (при условии, что b понадобится позже, a не больше):
Игнорируемая строка
Игнорируемая строка
Перемещает 2 в r(b)
a заменяется константным выражением 2

volatile int a;  
int b;  
a = 2;  
a = 2;  
b = a;  

Результат (b понадобится позже, a не имеет значения):
Перемещает 2 в r2, помещает адрес a в r3, записывает r2 в RAM(r3)
Записывает r2 снова в RAM(r3)
Считывает RAM(r3) в r4
Помещает адрес b в r5, записывает r4 в RAM(r5)

Как видите, это очень неэффективно. Что я хочу:
Переместить 2 в r(a)
Переместить 2 снова в r(a)
Записать r(a) в r(b)
Если регистры нужны для чего-то еще, сохранить a и b в оперативной памяти
Именно это и произошло бы, если бы a была реальной переменной, а не просто 2.


person Apache00    schedule 20.12.2016    source источник
comment
-O0 удалит все оптимизации. Обратите внимание, что, возможно, эта оптимизация является стандартной, поэтому GCC сделает это, когда бы то ни было. Предоставьте минимально воспроизводимый пример.   -  person Stargateur    schedule 20.12.2016
comment
Зачем тебе это? Эффект даже не должен быть заметен (если var находится в регистре)?   -  person alain    schedule 20.12.2016
comment
Поскольку тогда переменная никогда не будет храниться в регистре, ее придется каждый раз загружать из ОЗУ.   -  person Apache00    schedule 20.12.2016
comment
volatile не обязательно означает, что переменная не может быть помещена в регистр. С точки зрения стандарта C, он ничего не говорит ничего о том, где он может храниться. Вы даже можете указать переменную как register volatile, если хотите   -  person tofro    schedule 20.12.2016
comment
Не означает ли это, что переменная может измениться в ОЗУ в любое время и, следовательно, должна каждый раз перезагружаться? По крайней мере, в моем коде это так   -  person Apache00    schedule 20.12.2016
comment
Разместите свой код, если хотите что-то продемонстрировать. Но я думаю, что это очень преждевременная оптимизация.   -  person Eugene Sh.    schedule 20.12.2016
comment
@ Apache00, если в вашем коде переменные, используемые в C, могут изменяться во время работы вашей программы на C, у вас серьезная проблема с параллелизмом. Это должно происходить только для памяти, сопоставленной с каким-либо устройством, или в многопроцессорной системе. В последнем случае: Прочтите книгу по параллельному программированию.   -  person Marcus Müller    schedule 20.12.2016
comment
register volatile на самом деле не означает, что он должен храниться в оперативной памяти, не так ли? Однако вы не можете принудительно поместить переменную в регистр. registerэто только намек.   -  person tofro    schedule 20.12.2016
comment
Возможно, вы могли бы помочь нам ответить на ваш вопрос, указав, чего вы хотите достичь. В данный момент я не вижу причин, по которым вы хотели бы делать то, что пытаетесь сделать.   -  person tofro    schedule 20.12.2016
comment
На самом деле это не так просто. Я ввожу случайные ошибки в процессор. Вот почему это должна быть переменная, которой я могу манипулировать (в оборудовании), я не могу манипулировать ПЗУ, где хранится код и, следовательно, постоянное выражение. Затем я тестирую контрмеру, которая автоматически перезагружает переменные (используя постоянное выражение), если обнаруживается ошибка. Можно было бы сделать со значением RAM, но это было бы слишком неэффективно, так как это не просто одна переменная.   -  person Apache00    schedule 20.12.2016
comment
@tofro Я имел в виду без регистра, он все равно не влияет на мой код, как вы говорите.   -  person Apache00    schedule 20.12.2016
comment
Добавлен пример кода, чтобы вы могли понять, что я имею в виду (не знаю, почему он не форматируется правильно)   -  person Apache00    schedule 20.12.2016
comment
Мне было бы интересно, как вы хотите ввести значение ошибки в регистр ЦП - это было бы почти так же сложно, как сделать это в ПЗУ...   -  person tofro    schedule 20.12.2016


Ответы (3)


Для такого требования вы не могли бы использовать C для этого. Невозможно указать физическое расположение переменных (ОЗУ или реестр). Весь смысл GCC в том, чтобы позаботиться об этом за вас.

Вам придется написать свой собственный ассемблерный код для работы с использованием операций загрузки.

person Dellowar    schedule 20.12.2016
comment
Я не хочу диктовать, но если я использую volatile, я диктую ему использовать RAM. То, что он делает, это оптимизация, поэтому его можно отключить, я просто не знаю, как это сделать? - person Apache00; 20.12.2016
comment
@ Apache00 нет, ты этого не диктуешь; это не так просто. См. ответ Джона Боллинджера. - person Marcus Müller; 20.12.2016
comment
Но можно ли как-то отключить эту конкретную оптимизацию (заменить vars константными выражениями)? Он отключен, когда я отключаю всю оптимизацию, поэтому я должен каким-то образом отключить только эту. Я посмотрел здесь gcc.gnu.org/onlinedocs/gcc/Optimize-Options. html, но это сотни вариантов, и я едва в них разбираюсь. Один из них может нести за это ответственность. - person Apache00; 20.12.2016

Ни C, ни GCC не имеют механизма для того, что вы описываете. Ближе всего объявить переменную volatile, которая имеет следующий эффект:

[...] любое выражение, относящееся к объекту [a volatile], должно вычисляться строго в соответствии с правилами абстрактной машины, как описано в 5.1.2.3. Кроме того, в каждой точке последовательности значение, сохраненное последним в объекте, должно совпадать со значением, предписанным абстрактной машиной, за исключением случаев, когда оно изменяется под действием неизвестных факторов, упомянутых ранее.

(C2011, 6.7.3/7; курсив добавлен)

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

person John Bollinger    schedule 20.12.2016
comment
@ Apache00, задумывались ли вы о том, что компилятор может подумать, что доступные регистры можно использовать более эффективно, чем выделить вашу переменную одному из них? Вы могли бы также рассмотреть возможность объявления переменной с классом хранения register, если вы никогда не берете ее адрес, но это всего лишь подсказка — компилятор не обязан обрабатывать ее иначе, чем auto. - person John Bollinger; 20.12.2016
comment
Я понимаю, но в моем коде он всегда компилируется в нагрузку ОЗУ, даже с O3 и переменной, написанной непосредственно перед. Как я могу отключить, что он вынужден это делать? Ассемблерный код имеет вид 5a24: d4 01 28 00 l.sw 0(r1),r5 5a28: a8 c6 42 40 l.ori r6,r6,0x4240 (еще что-то) 5a2c: c0 14 30 00 l.mtspr r20,r6, 0x0 (что-то еще) 5a30: 84 61 00 00 l.lwz r3,0(r1) Очевидно, что значение уже находится в r5 (r1 — это указатель стека) - person Apache00; 20.12.2016
comment
@ Apache00, если компилятор действительно выделяет переменную в ОЗУ, то значение volatile означает, что она должна считываться/записываться в ОЗУ при каждом доступе. Если он размещен в регистре, то нет. Как я уже ответил, в C или расширении GCC для C нет способа указать именно то, о чем вы, кажется, просите. Как заметили другие комментаторы, непонятно, зачем вам это. - person John Bollinger; 20.12.2016
comment
register ничего не изменил, если я правильно использовал: register volatile float* volatile pointer = (float*) addr; - person Apache00; 20.12.2016
comment
Ах, я понимаю, тогда это заняло бы регистр все время выполнения - person Apache00; 20.12.2016

Он всегда будет загружать/сохранять переменную из/в ОЗУ, если я не оптимизирую.

нет, это не то, как работают процессоры или компиляторы.

В то время как C, по крайней мере, для внешне видимых объектов, гарантирует, что невременный объект имеет сравнимый адрес необходима цитата, компилятору абсолютно нет причин генерировать из следующего кода C:

int a,b;
a = 0;
b = a + 2; 
a = 3;

любой ассемблер, который каждый раз, когда вы касаетесь a, загружает из ОЗУ и сохраняет его обратно в ОЗУ. На самом деле задача компилятора как раз и состоит в том, чтобы точно знать, какие переменные находятся в каком регистре в момент выполнения, и обрабатывать операции над переменными, таким образом, на основе этих регистров.

person Marcus Müller    schedule 20.12.2016