4

(おそらく) 同じコードの次の C および ASM バージョンがあります。それが行うことは、それぞれ 2 つの 64 ビット整数で表される 2 つの 128 ビット整数をレジスタ (最初に 4*下位 32 ビット、次に 4*上位 32 ビット) およびADD/ADCにロードすることです。ADDこれは十分に単純なコードであり、ARM/ST のマニュアルでは実際に 96 ビット (3 / ADCs)で同じ例を示しています。

単純な呼び出しの場合、両方のバージョンが機能します (繰り返し追加(1 << x++)または 1..x)。しかし、より長いテストスイートでは、ARM アセンブリが失敗します (ボードがハングします)。ATM 私はそれをトラップ/デバッグする能力がなくprintf()、テストの失敗を見つけるために何も使用できません。これはとにかく無関係です.C バージョンは期待どおりに動作するため、ASM バージョンにはいくつかの基本的な障害があるはずです。

わかりません。これは十分に単純で、C アセンブリの出力に非常に近いものです (sans branching)。「メモリ」制約を試しました(必要ないはずです)。下位64ビットと上位64ビットの間のキャリーをレジスタに保存し、後で追加してADD(C).W、 、アライメント、LDR/STRの代わりに2つのLDRD/STRDなどを使用してみました。一部の加算がうまくいかず、0 による除算などの結果になるため、ボード フォールトが発生します。GCC ASM は以下にあり、同様の基本的な手法を使用しているため、問題は見られません。

私は本当にそのコードを具体的に修正するのではなく、追加を行うための最速の方法を探しています。rXとを指定するための制約がないため、定数レジスタ名を使用する必要があるのは残念です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;
}

「armv7m-none-eabi-gcc-4.7.2 -O3 -ggdb -fomit-frame-pointer -falign-functions=16 -std=gnu99 -march=armv7e-m」を使用する GCC C バージョン:

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をサポートするcortex-Aを使用していない限り、thumb2命令の数が少ないことに注意してください。フラッシュ(cortex-m)からのフェッチは(遅くなる可能性があります)遅くなります。さらに2つのレジスタのプッシュとポップを節約しようとしているようですが、フェッチのコストが高くなっています。上記を実行しても、ロードとストアを再配置して、これら2つのレジスタを保存できます。

これまでのところ最小限のテスト。printfsは、あなたのコードでは見られなかった、追加する上位の単語を示しています。私はまだ呼び出し規約を解こうとしています(私たちのためにあなたのコードをもっと文書化してください)、r0は結果を置くために呼び出し元によって準備されているようです、残りはスタックにあります。stellarisランチパッド(cortex-m4)を使用しています。

于 2013-01-01T17:29:56.557 に答える