Ответ 1
Во-первых, C-стандарт запрещает принимать адрес переменной, объявленной register
, так же, как и для битных полей в struct
s.
Для нерегистрационных ( "авто" ) переменных короткий ответ - да. Простейшей стратегией оптимизатора является немедленное разлитие переменных, адреса которых приняты.
"Проливание" - это всего лишь термин из литературы распределения регистров, означающий "решить разместить в памяти, а не в регистре".
Усовершенствованный оптимизатор может выполнить анализ псевдонимов и по-прежнему хранить значение в регистре, хотя его адрес был взят. Это возможно везде, где можно доказать, что результирующий указатель не может быть использован для изменения значения.
Другая соответствующая оптимизация - это разделение живого диапазона. Это позволяет хранить переменную в регистре для части диапазона инструкций, где она содержит полезное значение (его "диапазон действия" ) и разливается в других частях. В этом случае разлитые части будут соответствовать местам, где указатель может использоваться для изменения значения переменной. Например:
x = 3;
... lots of computations involving x
if T {
// SPILL HERE, so store register holding x to memory
int *p = &x;
... lots of computations, perhaps using p to change x
*p = 2;
// DONE SPILL HERE, so reload register
... more code here not using p to change x.
}
else {
... lots of computations involving x.
}
Агрессивный оптимизатор этого кода может выделять позицию стека для x, но загружать его в регистр вверху кода, поддерживая его там, кроме региона, отмеченного как SPILL. Эта область будет окружена хранилищем регистра в память и соответствующей загрузкой регистра.