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));
}
Другие вопросы по тегам