Spec-Zone.ru › GCC 13

6.47.5.2 Определение регистров для локальных переменных

Вы можете определить локальную переменную-регистр и связать ее с указанным регистром так:

register int *foo asm ("r12");

Здесь r12 — это имя регистра, который должен использоваться. Обратите внимание, что этот синтаксис аналогичен синтаксису определения глобальных переменных-регистров, но для локальной переменной объявление находится внутри функции. Ключевое слово register обязательно и не может быть комбинировано с static. Имя регистра должно быть допустимым именем регистра для целевой платформы.

Не используйте квалификаторы типа, такие как const и volatile, так как результат может быть не таким, как ожидалось. В частности, когда используется квалификатор const, компилятор может заменить переменную её инициализатором в выражениях asm, что может привести к появлению соответствующего операнда в другом регистре.

Как и в случае с глобальными переменными-регистрами, рекомендуется выбирать регистр, который обычно сохраняется и восстанавливается вызовами функций на вашей машине, чтобы вызовы библиотечных процедур не перезаписывали его.

Единственное поддерживаемое использование этой функции — указание регистров для операндов ввода и вывода при вызове Расширенной asm (см. Расширенная ассемблерная инструкция с операндами выражений C). Это может быть необходимо, если ограничения для определенной машины не обеспечивают достаточного управления для выбора желаемого регистра. Чтобы принудительно поместить операнд в регистр, создайте локальную переменную и укажите имя регистра после объявления переменной. Затем используйте локальную переменную для операнда 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-13.3.0/gcc/Local-Register-Variables.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API