6.47.5.2 Указание регистров для локальных переменных
Вы можете определить локальную переменную регистра и связать ее со специфическим регистром следующим образом:
register int *foo asm ("r12");
Здесь r12 — имя регистра, который должен быть использован. Обратите внимание, что этот синтаксис аналогичен синтаксису для определения глобальных переменных регистра, но для локальной переменной объявление появляется внутри функции. Ключевое слово register обязательно и не может быть объединено с static. Имя регистра должно быть допустимым именем регистра для целевой платформы.
Не используйте квалификаторы типа, такие как const и volatile, так как результат может быть непредсказуемым. В частности, когда используется квалификатор const, компилятор может заменить переменную её инициализатором в инструкциях asm, что может привести к появлению соответствующего операнда в другом регистре.
Как и в случае с глобальными переменными регистра, рекомендуется выбрать регистр, который обычно сохраняется и восстанавливается вызовами функций на вашей машине, чтобы вызовы библиотечных процедур не перезаписывали его.
Единственное поддерживаемое применение этой функции — указание регистров для операндов входных и выходных данных при вызове Расширенного asm (см. Расширенное Asm). Это может быть необходимо, если ограничения для конкретной машины не предоставляют достаточного контроля для выбора желаемого регистра. Чтобы принудительно поместить операнд в регистр, создайте локальную переменную и укажите имя регистра после объявления переменной. Затем используйте локальную переменную для операнда asm и укажите любой символ ограничения, соответствующий регистру:
register int *p1 asm ("r0") = …;
register int *p2 asm ("r1") = …;
register int *result asm ("r0");
asm ("sysint" : "=r" (result) : "0" (p1), "r" (p2));
Предупреждение: В приведенном выше примере имейте в виду, что регистр (например, r0) может быть перезаписан последующим кодом, включая вызовы функций и вызовы библиотек для арифметических операций с другими переменными (например, инициализации p2). В этом случае используйте временные переменные для выражений между присваиваниями регистров:
int t1 = …;
register int *p1 asm ("r0") = …;
register int *p2 asm ("r1") = t1;
register int *result asm ("r0");
asm ("sysint" : "=r" (result) : "0" (p1), "r" (p2));
Определение переменной регистра не резервирует регистр. За исключением вызова Расширенного asm, содержимое указанного регистра не гарантируется. По этой причине следующие варианты использования не поддерживаются. Если они кажутся рабочими, это просто случайность, и они могут перестать работать должным образом из-за (казалось бы) не связанных изменений в окружающем коде или даже незначительных изменений в оптимизации будущей версии gcc:
- Передача параметров в или из Базовых
asm - Передача параметров в или из Расширенного
asmбез использования операндов входных или выходных данных. - Передача параметров в или из процедур, написанных на языке ассемблера (или других языках) с использованием нестандартных соглашений о вызовах.
Некоторые разработчики используют локальные переменные регистра, чтобы попытаться улучшить распределение регистров gcc, особенно в больших функциях. В этом случае имя регистра в основном является подсказкой для распределителя регистров. Хотя в некоторых случаях это может генерировать лучший код, улучшения зависят от желаний распределителя/оптимизаторов. Поскольку нет гарантии, что ваши улучшения не будут утеряны, этот способ использования локальных переменных регистра не рекомендуется.
На платформе MIPS существует связанное применение локальных переменных регистра с немного другими характеристиками (см. Определение специфики сопроцессоров для целей MIPS в GNU Compiler Collection (GCC) Internals).
Предыдущая: Глобальные переменные регистра, Следующая: Явные переменные регистра [Оглавление][Индекс]
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-9.5.0/gcc/Local-Register-Variables.html