Как прочитать флаг условия в сборке ARMv7 Thumb-2?

Я использую процессор ARMv7 с инструкциями Thumb-2.

Я выполнил ADD, SUB или CMP, Теперь я хочу переместить флаг условия LE в r2, После этого, r2 должен содержать либо 0 или же 1,

Я просматривал руководство по Thumb-2, но не нашел условной инструкции MOV или специальной инструкции для чтения флагов.

Какой самый эффективный способ сделать это? Заранее спасибо!

3 ответа

Решение

Вы должны начать условный блок с ite (если-то-еще), а затем просто использовать условные присваивания:

ite le        @ if-then-else (le)
movle r2, #1  @ if (le) then r2 = #1
movgt r2, #0  @         else r2 = #0

В общем, вы можете использовать произвольные условные инструкции в Thumb-2, если вы добавите к ним соответствующие IT-инструкции. Прочитайте руководство для деталей.

В ARM (почти) любая инструкция может быть предиката. В режиме большого пальца это требует it Инструкция для кодирования предиката и шаблона отрицается или нет для следующих нескольких инструкций.

Но в унифицированном синтаксисе ассемблер может сделать это за вас без объяснения причин. it, Я думаю.

например movle r0, #1 наборы r0 = 1 если условие LE верно для флагов, в противном случае оно остается неизменным. Так что вам нужно mov r0, #0 первый.

ARM32 не имеет инструкции set-from-condition, как в x86 setcc,

AArch64 делает: превращение состояния флага в целое число занимает всего один cset инструкция.

Этот источник C:

int booleanize(int x, int y) { return x<y; }
int booleanize_u(unsigned a, unsigned b) { return a<b; }

компилирует для большого пальца ARM32 с помощью clang -O3 ( в проводнике компилятора Godbolt), выявляя некоторые глупые пропущенные оптимизации. gcc похож, делает ветвистый код без -mcpu или даже хуже, чем лязг с -mcpu=cortex-a53, Ветвление, возможно, не совсем необоснованно на простом микроконтроллере.

@@ BAD EXAMPLE, compiler missed optimizations

@ clang7.0 -target arm -mthumb -mcpu=cortex-a53
booleanize(int, int):
    movs    r2, #0         @ movs is 16-bit, mov is a 32-bit instruction, I think.
    cmp     r0, r1
    it      lt
    movlt   r2, #1
    mov     r0, r2         @ wasted instruction because the compiler wanted to mov #0 before cmp
    bx      lr

booleanize_u(unsigned int, unsigned int):
    movs    r2, #0
    cmp     r0, r1
    it      lo
    movlo   r2, #1
    mov     r0, r2
    bx      lr

Это определенно хуже, чем ite le / movle / movgt из ответа @ fuz, с двумя предикатными инструкциями.

Code-gen режима ARM более или менее точен, когда каждое 32-битное слово инструкции имеет 4 бита в кодировании для условия предиката. (По умолчанию без суффикса в исходном коде asm al = всегда.)

@ gcc8.2 -O3 -mcpu=cortex-a53
booleanize(int, int):
    cmp     r0, r1
    movge   r0, #0     @ a simple mov without predication or flag-setting would work
    movlt   r0, #1
    bx      lr

booleanize_u(unsigned int, unsigned int):
    cmp     r0, r1
    movcs   r0, #0
    movcc   r0, #1
    bx      lr

AArch64 имеет cset, буленизация в банке.

@ clang and gcc make the same efficient code
booleanize(int, int):
    cmp     w0, w1
    cset    w0, lt            @ signed less-than
    ret
booleanize_u(unsigned int, unsigned int):
    cmp     w0, w1
    cset    w0, lo            @ unsigned lower
    ret

Я просматривал руководство по Thumb-2, но не нашел условной инструкции MOV или специальной инструкции для чтения флагов.

Ты можешь использовать MRS, чтобы скопировать условные флаги в регистр (т.е. r2).

Какой самый эффективный способ сделать это?

До сих пор вы не включили требование, в котором недостаточно кода условного выполнения, так что это наиболее эффективный способ.

Другие вопросы по тегам