简单的ADD / ADC ARM组装失败

时间:2013-01-01 05:41:10

标签: c gcc assembly arm

我有(假设)相同代码的以下C和ASM版本。它做的是加载2个128位整数,每个由2个64位整数表示寄存器(前4 *低32位,然后4 *高32位)和ADD / ADC给它们。它足够简单,而ARM / ST手册实际上给出了96bit(3 ADD / ADC s)的相同示例。

对于简单调用,两个版本都有效(重复添加(1 << x++)或1..x)。但是对于较长的测试套件,ARM组件会出现故障(电路板挂起)。 ATM我无法捕获/调试它,也无法使用任何printf()或类似物来查找测试失败,这无论如何都是无关紧要的,因为在ASM版本中必定存在一些基本错误,因为C版本可以工作如预期的那样。

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

我真的只是寻找最快的添加方式,而不是专门修复代码。遗憾的是,您必须使用常量寄存器名称,因为没有约束来指定rXrX+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                                                                                      

1 个答案:

答案 0 :(得分: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

注意拇指2指令的数量较少,除非你在拥有thumb2支持的皮质-A上,那些闪光(cortex-m)的提取(可能)很慢。我看到你正在尝试保存另外两个寄存器的推送和弹出,但是你花费了更多的时间。您可以采用上述方法并仍然重新安排加载和存储并保存这两个寄存器。

到目前为止,最低限度的测试。 printfs显示上面的单词添加,我没有看到你的代码。我仍然试图解开调用约定(请为我们更多地记录您的代码),看起来r0由调用者准备放置结果,rest在堆栈上。我正在使用stellaris启动板(cortex-m4)。