В 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
или даже хуже, чем clang с -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, с двумя предикатными инструкциями.
Кодогенерация режима 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