GCC расширенный ассемблер дифференцирующий литерал против регистра
Я активно использую встроенный ассемблер и очень часто хочу иметь возможность использовать регистр или литерал в заданном битовом ассемблере, однако я не понимаю, как это сделать с помощью пакета Microchip XC16.
Насколько я могу судить, нужно вручную кодировать буквенный символ #
и это несовместимо с префиксом. Это означает, что следующий код не компилируется:
asm("MOV %1, %0" : "=r" (res) : "i" (1));
Invalid operands specified ('mov 1,w0').
Но следующее делает:
asm("MOV #%1, %0" : "=r" (res) : "i" (1));
Что, конечно, несовместимо с регистрами:
asm("MOV #%1, %0" : "=r" (res) : "ri" (x));
Invalid operands specified ('mov #w0,w0').
Поэтому мне кажется, что Microchip не следует соглашениям GCC, где я считаю, что буквенный символ должен был быть встроен в операнд, и это делает его особенно трудным для работы.
Мне было интересно на случайность.. есть ли у кого-нибудь яркие идеи о том, как обойти эту проблему?
Сейчас я прохожу __builtin_constant_p
в качестве дополнительного параметра, который я тогда .if
в asm следующим образом, но сказать, что это становится громоздким быстро, было бы преуменьшением.
asm(".if %[isk] \n"
"MOV #%1, %0 \n"
".elseif \n"
"MOV %1, %0 \n"
".endif \n"
: "=r" (res)
: "ri" (x), [isk] "i" (__builtin_constant_p(x));
И я даже не верю, что GCC гарантирует, что %1
будет буквальным, если isk
Это правда, что означает необходимость блокировать все, что есть, на стороне C... вздох.
Уточнить MOV
это просто пример инструкции. Эти процессоры (dsPIC33E) имеют нулевые накладные расходы и одиночные циклы с несколькими инструкциями, которые требуют использования asm, синтаксис которого выглядит следующим образом:
/* this code demonstrates compilation failure if cnt is a constant
* as there is no # prefix before the %[cnt] */
asm("REPEAT %[cnt] \n"
" MOV [%0++], [%1++] \n"
: "+r" (src), "+r" (dst), "=m" (*dst)
: "m" (*src), [cnt] "ri" (cnt));
Этот цикл memcpy занимает cnt+1
выполнение циклов, что благодаря конвейерной обработке в два раза быстрее, чем если бы вы полностью развернули цикл, и в 6 раз быстрее, чем ветвление каждой итерации. Наряду с их многоканальным вариантом цикла DO, они очень важны, чтобы получить максимальную отдачу от этих процессоров.
1 ответ
Я нашел способ обнаружить в asm, является ли данный параметр литералом или нет, он далек от идеала, но, похоже, работает.
Сначала в заголовочном файле asm отметьте символ для каждого регистра:
.irp r,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
.set _IS_REG_w&r&, 1 ; mark all registers as "REGs"
.set _IS_REG_W&r&, 1
.endr
А потом использовать:
.ifdecl _IS_REG_%0
REPEAT %0
.else
REPEAT #%0
.endif
Который может быть заключен в макрос asm:
.macro REPEATN cnt
.ifdecl _IS_REG_&cnt&
REPEAT \cnt
.else
REPEAT #\cnt
.endif
.endm
Для легкого встраивания в inline asm:
void DelayCycles(int count)
{
asm("REPEATN %[cnt] \n"
" NOP \n"
:
: [cnt] "ri" (count));
}