如何读取 ARMv7 Thumb-2 程序集中的条件标志?

How to read a condition flag in ARMv7 Thumb-2 assembly?

我正在使用带有 Thumb-2 指令的 ARMv7 处理器。

我执行了 ADDSUBCMP。现在我想将条件标志 LE 移动到 r2。此后,r2 应包含 01.

我一直在查看 Thumb-2 手册,但我没有找到条件 MOV 指令或读取标志的特殊指令。

最有效的方法是什么?提前致谢!

您需要使用 ite (if-then-else) 指令开始一个条件块,然后只使用条件赋值:

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

一般来说,如果您在 Thumb-2 中使用适当的 IT 指令作为前缀,则可以在 Thumb-2 中使用任意条件指令。详细阅读手册。

I've been looking through the Thumb-2 manual, but I haven't found a conditional MOV instruction or a special instruction to read the flags.

您可以使用 MRS,以便将条件标志复制到寄存器(即 r2)。

What's the most efficient way to do this?

到目前为止,您还没有包含 conditional execution code 不够的要求,因此这是最有效的方法。

在 ARM 中,(几乎)任何指令都可以断言。在拇指模式下,这需要一个 it 指令来为接下来的几条指令编码谓词和否定模式。

但我认为,在统一语法中,汇编器可以为您做到这一点,而无需显式 it

例如如果标志中的 LE 条件为真,movle r0, #1 设置 r0 = 1,否则保持不变。所以你首先需要一个mov r0, #0

ARM32 没有像 x86 的 setcc.

那样的条件设置指令

AArch64 做到了:将标志条件转换为整数只需要一条 cset 指令。

此 C 源代码:

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

使用 clang -O3 (on the Godbolt compiler explorer) 为 ARM32 thumb 编译,揭示了一些愚蠢的遗漏优化。 gcc 类似,使分支代码没有 -mcpu 甚至比带有 -mcpu=cortex-a53 的 clang 更糟糕。 Branchy 在简单的微控制器上可能并非完全不合理。

@@ 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

这绝对比@fuz 的回答中的 ite le / movle / movgt 差很多,有 2 个谓词指令。

ARM 模式代码生成或多或少很好,其中每个 32 位指令字在编码中都有 4 位用于谓词条件。 (asm源码中没有后缀的默认是al = always.)

@ 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