4

我有(据说)相同代码的以下 C 和 ASM 版本。它所做的是将由 2 个 64 位整数表示的 2 个 128 位整数加载到寄存器(首先是 4* 低 32 位,然后是 4* 高 32 位)和ADD/ADC到它们。这是足够简单的代码,ARM/ST 手册实际上给出了与 96 位(3 ADD/ ADCs)相同的示例。

对于简单的调用,两个版本都可以工作(重复添加(1 << x++)或 1..x)。但是对于更长的测试套件,ARM 组装失败(板挂起)。ATM 我没有能力捕获/调试它,也不能使用任何printf()或类似的方法来发现测试失败,这无论如何都无关紧要,因为 ASM 版本中必须存在一些基本错误,因为 C 版本按预期工作。

我不明白,它很简单,并且非常接近 C 汇编输出(无分支)。我尝试了“内存”约束(不需要),我尝试将低位和高位 64 位之间的进位保存在寄存器中,然后使用ADD(C).W、对齐、使用两个LDR/STR而不是LDRD/STRD等添加它。我假设电路板故障,因为某些加法出错并导致除以 0 或类似的东西。GCC ASM 在下面并使用类似的基本技术,所以我没有看到问题。

我真的只是在寻找进行添加的最快方法,而不是专门修复该代码。rX很遗憾您必须使用常量寄存器名称,因为指定and没有约束rX+1。此外,不可能使用 GCC 一样多的寄存器,因为它会在编译期间用完它们。

typedef struct I128 {
    int64_t high;
    uint64_t low;
} I128;

I128 I128add(I128 a, const I128 b) {
#if defined(USEASM) && defined(ARMx)
    __asm(
            "LDRD %%r2, %%r3, %[alo]\n"
            "LDRD %%r4, %%r5, %[blo]\n"
            "ADDS %%r2, %%r2, %%r4\n"
            "ADCS %%r3, %%r3, %%r5\n"
            "STRD %%r2, %%r3, %[alo]\n"

            "LDRD %%r2, %%r3, %[ahi]\n"
            "LDRD %%r4, %%r5, %[bhi]\n"
            "ADCS %%r2, %%r2, %%r4\n"
            "ADC %%r3, %%r3, %%r5\n"
            "STRD %%r2, %%r3, %[ahi]\n"
            : [alo] "+m" (a.low), [ahi] "+m" (a.high)
            : [blo] "m" (b.low), [bhi] "m" (b.high)
            : "r2", "r3", "r4", "r5", "cc"
            );
    return a;
#else
    // faster to use temp than saving low and adding to a directly
    I128 r = {a.high + b.high, a.low + b.low};
    // check for overflow of low 64 bits, add carry to high
    // avoid conditionals
    //r.high += r.low < a.low || r.low < b.low;
    // actually gcc produces faster code with conditionals
    if(r.low < a.low || r.low < b.low) ++r.high;
    return r;
}

GCC C 版本使用“armv7m-none-eabi-gcc-4.7.2 -O3 -ggdb -fomit-frame-pointer -falign-functions=16 -std=gnu99 -march=armv7e-m”:

b082        sub sp, #8
e92d 0ff0   stmdb   sp!, {r4, r5, r6, r7, r8, r9, sl, fp}
a908        add r1, sp, #32
e881 000c   stmia.w r1, {r2, r3}
e9dd 890e   ldrd    r8, r9, [sp, #56]   ; 0x38
e9dd 670a   ldrd    r6, r7, [sp, #40]   ; 0x28
e9dd 2308   ldrd    r2, r3, [sp, #32]
e9dd 450c   ldrd    r4, r5, [sp, #48]   ; 0x30
eb16 0a08   adds.w  sl, r6, r8
eb47 0b09   adc.w   fp, r7, r9
1912        adds    r2, r2, r4
eb43 0305   adc.w   r3, r3, r5
45bb        cmp fp, r7
bf08        it  eq
45b2        cmpeq   sl, r6
d303        bcc.n   8012c9a <I128add+0x3a>
45cb        cmp fp, r9
bf08        it  eq
45c2        cmpeq   sl, r8
d204        bcs.n   8012ca4 <I128add+0x44>
2401        movs    r4, #1
2500        movs    r5, #0
1912        adds    r2, r2, r4
eb43 0305   adc.w   r3, r3, r5
e9c0 2300   strd    r2, r3, [r0]
e9c0 ab02   strd    sl, fp, [r0, #8]
e8bd 0ff0   ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp}
b002        add sp, #8
4770        bx  lr

我的 ASM 版本失败:

b082        sub sp, #8                                                                                  
b430        push    {r4, r5}                                                                            
a902        add r1, sp, #8                                                                              
e881 000c   stmia.w r1, {r2, r3}                                                                        
e9dd 2304   ldrd    r2, r3, [sp, #16]                                                                   
e9dd 4508   ldrd    r4, r5, [sp, #32]                                                                   
1912        adds    r2, r2, r4                                                                          
416b        adcs    r3, r5                                                                              
e9cd 2304   strd    r2, r3, [sp, #16]                                                                   
e9dd 2302   ldrd    r2, r3, [sp, #8]                                                                    
e9dd 4506   ldrd    r4, r5, [sp, #24]                                                                   
4162        adcs    r2, r4                                                                              
eb43 0305   adc.w   r3, r3, r5                                                                          
e9cd 2302   strd    r2, r3, [sp, #8]                                                                    
4604        mov r4, r0                                                                                  
c90f        ldmia   r1, {r0, r1, r2, r3}                                                                
e884 000f   stmia.w r4, {r0, r1, r2, r3}                                                                
4620        mov r0, r4                                                                                  
bc30        pop {r4, r5}                                                                                
b002        add sp, #8                                                                                  
4770        bx  lr                                                                                      
4

1 回答 1

1

我没有从你的代码中得到一个挂起,但它也不起作用,不知道为什么。但是很容易修补编译器生成的代码来处理进位:

I128 I128add(I128 a, const I128 b) {

    I128 r = {a.high + b.high, a.low + b.low};
    return r;
}

变成

000001e4 <I128add>:
 1e4:   b082        sub sp, #8
 1e6:   b4f0        push    {r4, r5, r6, r7}
 1e8:   e9dd 4506   ldrd    r4, r5, [sp, #24]
 1ec:   a904        add r1, sp, #16
 1ee:   e881 000c   stmia.w r1, {r2, r3}
 1f2:   e9dd 230a   ldrd    r2, r3, [sp, #40]   ; 0x28
 1f6:   1912        adds    r2, r2, r4
 1f8:   eb43 0305   adc.w   r3, r3, r5
 1fc:   e9dd 6704   ldrd    r6, r7, [sp, #16]
 200:   e9dd 4508   ldrd    r4, r5, [sp, #32]
 204:   1936        adds    r6, r6, r4
 206:   eb47 0705   adc.w   r7, r7, r5
 20a:   e9c0 6700   strd    r6, r7, [r0]
 20e:   e9c0 2302   strd    r2, r3, [r0, #8]
 212:   bcf0        pop {r4, r5, r6, r7}
 214:   b002        add sp, #8
 216:   4770        bx  lr

修复了添加

.thumb_func
.globl test2
test2:
    sub sp, #8
    push    {r4, r5, r6, r7}
    ldrd    r4, r5, [sp, #24]
    add r1, sp, #16
    stmia r1, {r2, r3}
    ldrd    r2, r3, [sp, #40]
    add r2, r4
    adc r3, r5
    ldrd    r6, r7, [sp, #16]
    ldrd    r4, r5, [sp, #32]
    adc r6, r4
    adc r7, r5
    strd    r6, r7, [r0]
    strd    r2, r3, [r0, #8]
    pop {r4, r5, r6, r7}
    add sp, #8
    bx  lr

最后结果

00000024 <test2>:
  24:   b082        sub sp, #8
  26:   b4f0        push    {r4, r5, r6, r7}
  28:   e9dd 4506   ldrd    r4, r5, [sp, #24]
  2c:   a904        add r1, sp, #16
  2e:   c10c        stmia   r1!, {r2, r3}
  30:   e9dd 230a   ldrd    r2, r3, [sp, #40]   ; 0x28
  34:   1912        adds    r2, r2, r4
  36:   416b        adcs    r3, r5
  38:   e9dd 6704   ldrd    r6, r7, [sp, #16]
  3c:   e9dd 4508   ldrd    r4, r5, [sp, #32]
  40:   4166        adcs    r6, r4
  42:   416f        adcs    r7, r5
  44:   e9c0 6700   strd    r6, r7, [r0]
  48:   e9c0 2302   strd    r2, r3, [r0, #8]
  4c:   bcf0        pop {r4, r5, r6, r7}
  4e:   b002        add sp, #8
  50:   4770        bx  lr

请注意,thumb2 指令的数量较少,除非您使用的是支持 thumb2 的 cortex-A,否则从 flash (cortex-m) 中获取的那些指令(可能)很慢。我看到您正在尝试保存另外两个寄存器的推送和弹出,但您花费了更多的获取。您可以采用上述方法,仍然重新安排加载和存储并保存这两个寄存器。

到目前为止最小的测试。printfs 显示上面的单词添加,我没有看到你的代码。我仍在尝试解除调用约定(请为我们记录更多代码),看起来 r0 已由调用者准备好放置结果,其余部分在堆栈上。我正在使用 Stellaris 发射台(cortex-m4)。

于 2013-01-01T17:29:56.557 回答