6.47.5.2 Указание регистров для локальных переменных
Вы можете определить локальную переменную-регистр и связать её со специфическим регистром следующим образом:
register int *foo asm ("r12");
Здесь r12 — имя регистра, которое должно быть использовано. Обратите внимание, что это тот же синтаксис, что используется для определения глобальных переменных-регистров, но для локальной переменной объявление находится внутри функции. Ключевое слово register обязательно и не может быть объединено с static. Имя регистра должно быть допустимым именем регистра для целевой платформы.
Не используйте квалификаторы типа, такие как const и volatile, так как результат может быть не таким, как ожидается. В частности, когда используется квалификатор const, компилятор может заменить переменную её инициализатором в 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-12.2.0/gcc/Local-Register-Variables.html