Встроенная сборка GCC: пусть компилятор решает, какой регистр использовать для временного значения - PullRequest
3 голосов
/ 04 августа 2011

Мне нужно загрузить 18h и вывести его на порт 60h, следуя работам (внутри asm ("")).

ldi r1, 0x18 ; 0x18 -> r1
sts 0x60, r1 ; output r1 -> 0x60

Мне все равно, используется ли для этого регистр r1 или любой другой. Есть ли простой способ позволить компилятору решать, какой регистр использовать?

Я мог бы использовать внешнюю переменную r / w, но это создает некоторые ненужные издержки:

register uint8_t tmp;
asm volatile (
    "ldi %[tmp], 0x18 \n\t"
    "sts 0x60, %[tmp]"
    : [tmp] "=r"(tmp) :);

это для 8-битного процессора AVR atmega. Использование GCC 4.3.2

Ответы [ 2 ]

1 голос
/ 17 августа 2011

Я не знаю, почему я видел издержки раньше, но использование внешней переменной register temp работает без издержек даже с -O0 (без оптимизации). Поэтому я использую:

register uint8_t tmp;
asm volatile (
    "ldi %[tmp], 0x18 \n\t"
    "sts 0x60, %[tmp]"
    : [tmp] "=r"(tmp) :);

Для этого по-прежнему требуется объявить переменную, чем это описано в выходном блоке оператора asm, но он создает нужный код сборки (без издержек).

0 голосов
/ 31 октября 2016

Я думаю, вы должны использовать ограничение "= &" для выходного операнда.

Механика выглядит так:

  • Для любого из входных операндов компилятор предоставит несколько регистров и загрузит их со значением их операндов до того, как начнется ваша встроенная сборка. Входные операнды только для чтения , что означает, что компилятор будет ожидать, что вы оставите регистры нетронутыми в вашей сборке. То есть компилятор ожидает, что регистры будут иметь те же значения после вашей сборки, что и он может впоследствии решить использовать эти значения.

  • Для выходных операндов компилятор также назначает вам ряд регистров. В конце вашей встроенной сборки вы должны были загрузить эти регистры с вашими результатами, так как компилятор ожидает найти их прямо там. Предупреждение: Регистры, которые вы задаете для выходных операндов, могут совпадать с регистрами, которые вы предоставляете для входных операндов! Тем не менее, это прекрасно имеет смысл: компилятор предоставляет вам входные данные в некотором регистре до вашей сборки и собирает ваш результат в тот же регистр после вашей сборки, например.

  • Вы можете использовать модификатор только для вывода ('&'), чтобы предотвратить именно это. Компилятор гарантирует, что регистр только для вывода никогда не удваивается как регистр ввода.

  • Вы можете использовать модификатор input-output ('+'), чтобы явно попросить компилятор использовать тот же регистр для ввода и вывода операнда. Это фактически дает вам прозрачный доступ к операнду. Напомним, что обратное не имеет места: Не использование этого модификатора делает не предотвращение двойного компилятора с использованием того же регистра - используйте модификатор только для вывода что.

Так что в основном ваш выбор прост:

  • Не запрашивать входной операнд для временной переменной из-за ее природы только для чтения и предположений компилятора. Например, если вы создаете временную переменную и инициализируете ее с некоторым значением (возможно, нулевым), компилятор может повторно использовать регистр, который он предоставляет вам всякий раз, когда ему снова понадобится ее значение (ноль).
  • Не запрашивать выходной операнд, так как он может совпадать с некоторым входным операндом. Вы можете случайно столкнуть свои входные операнды при использовании предполагаемого временного.
  • Использовать вывод с модификатором only-output . Таким образом, компилятор назначит вам несколько регистров, которые вы можете безопасно поцарапать (так как он ожидает некоторого вывода от вас).

Использование ввода-вывода также предоставляет вам безопасный регистр. Однако операнд нуждается в инициализации (так как компилятор предполагает, что вы читаете его как ввод), и если вы используете один и тот же операнд в нескольких фрагментах встроенной сборки, он нуждается в восстановлении (по той же причине). Напротив, при использовании модификатора только для вывода компилятор может легко выяснить, что переменная никогда не читается.

...