何时在 ARM 汇编中使用 CMP 和 TEQ 指令?

Rak*_*esh 5 arm instruction-set

为什么是两条单独的指令而不是一条指令?实际上在什么样的情况下我们需要使用CMP和TEQ指令。

我知道这两条指令是如何运作的。

Jak*_*LEE 7

简而言之:两者都有不同的目的,cmp没有subs目的地,而teq没有eors目的地。

cmp非常简单:比较两个
有符号的数字 A 和 B:
gt: A > B
ge: A >= B
eq: A == B
le: A <= B
lt: A < B

无符号:
hi: A > B
hs: A >= B
eq: A == B
ls: A <= B
lo: A < B

让我们假设下面的问题:

int32_t foo(int32_t A)
{
    if (((A < 0) && ((A & 1) == 1)) || ((A >= 0) && ((A & 1) == 0)))
    {
        A += 1;
    }
    else
    {
        A -= 1;
    }

    return A;
}
Run Code Online (Sandbox Code Playgroud)

在人类语言中,如果 A 是(奇数负数)或(偶数正数),则 if 语句为真,并且Linaro GCC 7.4.1 @ O3会产生以下混乱:

foo
        0x00000000:    CMP      r0,#0
        0x00000004:    AND      r3,r0,#1
        0x00000008:    BLT      {pc}+0x14 ; 0x1c
        0x0000000C:    CMP      r3,#0
        0x00000010:    BEQ      {pc}+0x14 ; 0x24
        0x00000014:    SUB      r0,r0,#1
        0x00000018:    BX       lr
        0x0000001C:    CMP      r3,#0
        0x00000020:    BEQ      {pc}-0xc ; 0x14
        0x00000024:    ADD      r0,r0,#1
        0x00000028:    BX       lr
Run Code Online (Sandbox Code Playgroud)

精通比特黑客领域的人会更改 if 语句,如下所示:

int32_t bar(int32_t A)
{
    if ((A ^ (A<<31)) >= 0)
    {
        A += 1;
    }
    else
    {
        A -= 1;
    }

    return A;
}
Run Code Online (Sandbox Code Playgroud)

结果是:

bar
        0x0000002C:    EORS     r3,r0,r0,LSL #31
        0x00000030:    ADDPL    r0,r0,#1
        0x00000034:    SUBMI    r0,r0,#1
        0x00000038:    BX       lr
Run Code Online (Sandbox Code Playgroud)

最后,汇编程序员将替换EORSteq r0, r0, lsl #31.

它不会使代码更快,但它不需要R3作为暂存寄存器。

请注意,上面的代码只是一个演示案例,它是一个单独的函数,其中有多余的可用寄存器。

然而,在现实生活中,寄存器是迄今为止最稀缺的资源,尤其是在循环内,甚至编译器也会在类似情况下使用该teq指令。

总而言之,在纠错、解密/加密等领域需要xor进行大量操作,处理这些问题的人们只知道欣赏诸如teq以及何时使用它们之类的指令。

永远记住:永远不要相信编译器