5
for (int i = 0; i < 10000; i++)
  a[i] = b[i] + c[i]

この高級言語のARMアセンブリはどのように見えますか?

編集:AのベースアドレスはR8にあり、BのベースアドレスはR9にあり、CのベースアドレスはR10にあり、A、B、Cはすべてint配列であると仮定しています。

とても有難い

私は試した:

MOV  R0, #0  ; Init r0 (i = 0)

Loop:

        a[i] = b[i] + c[i]   //How to fix this? 

        ADD  R0, R0, #1 ;Increment it

        CMP  R0, #1000 ;Check the limit

        BLE  Loop  ;Loop if not finished
4

4 に答える 4

7

この高級言語にCと競合するものがないと仮定すると、armCコンパイラを使用してスニペットからアセンブリコードを作成できます。たとえば、test.cに次のようなものがある場合、

void test() {
        register int i asm("r0");
        register int *a asm("r8");
        register int *b asm("r9");
        register int *c asm("r10");

        for (i = 0; i < 10000; i++) {
                a[i] = b[i] + c[i];
        }
}

あなたが実行することができます

arm-linux-androideabi-gcc -O0 -S test.c

test.sファイルを作成します。このファイルには、テスト関数のアセンブリコードといくつかの追加情報が含まれています。ループがどのようにアセンブリにコンパイルされたかを以下で確認できます。

<snipped>
.L3:
        mov     r2, r8
        mov     r3, r0
        mov     r3, r3, asl #2
        add     r3, r2, r3
        mov     r1, r9
        mov     r2, r0
        mov     r2, r2, asl #2
        add     r2, r1, r2
        ldr     r1, [r2, #0]
        mov     ip, sl
        mov     r2, r0
        mov     r2, r2, asl #2
        add     r2, ip, r2
        ldr     r2, [r2, #0]
        add     r2, r1, r2
        str     r2, [r3, #0]
        mov     r3, r0
        add     r3, r3, #1
        mov     r0, r3
.L2:
        mov     r2, r0
        ldr     r3, .L5
        cmp     r2, r3
        ble     .L3
        sub     sp, fp, #12
        ldmfd   sp!, {r8, r9, sl, fp}
        bx      lr
<snipped>

このアプローチの問題は、コンパイラが研究に最適なコードを生成することを信頼することです。これは常に当てはまるとは限りませんが、人々を待つのではなく、上記のような質問にすばやく答えることができます:)

- 追加 -

GCCを使用すると、変数を特定のレジスタに入れることができます。関連ドキュメントを参照してください。

ここで腕の指示に関するチートシートを入手できます。

新しいバージョンのGCCは、予想どおり、より優れたアームコードを作成します。上記の切り取りはバージョン4.4.3で生成されており、Linaroの4.7.1が私の主張を証明していることを確認できます。したがって、私のアプローチを採用する場合は、入手できる最新のツールチェーンを使用してください。

于 2012-08-16T06:50:38.820 に答える
4

http://www.peter-cockerell.net/aalp/html/ch-5.html

;Print characters 32..126 using a FOR loop-type construct

;R0 holds the character
MOV  R0, #32  ;Init the character
.loop
SWI  WriteC  ;Print it
ADD  R0, R0, #1 ;Increment it
CMP  R0, #126 ;Check the limit
BLE  loop  ;Loop if not finished
;
于 2012-08-16T02:18:35.107 に答える
1
for (int i = 0; i < 10000; i++)
  a[i] = b[i] + c[i]



mov r0,#0x2700
orr r0,#0x0010
top:
ldr r1,[r9],#4
ldr r2,[r10],#4
add r1,r1,r2
str r1,[r8],#4
subs r0,#1
bne top
于 2012-08-16T03:48:58.823 に答える
1

@alperaの答えに基づいて構築するには、ループを展開して一度に4つの操作を実行することもできますが、パフォーマンス上の利点が得られるかどうかは、メモリアクセスまたはブランチ周辺のパイプラインストールのどちらがより大きな効果であるかによって異なります。

mov r11,#0x2700
orr r11,#0x0010
top:
ldmia r9!, {r0-r3}
ldmia r10!, {r4-r7}
add r0,r0,r4
add r1,r1,r5
add r2,r2,r6
add r3,r3,r7
stmia r8!, {r0-r3}
subs r11,#4
bne top

NEONユニットが手元にある場合は、その方法でも実行できます。この場合、ロード、保存、追加が並列化され、ループの2回の反復を同時に実行する5つの命令に問題が軽減されます。

ACコンパイラは、読み取りと書き込みに使用されるバッファ(r8、r10、r11)が重複する可能性があると想定する必要があるため、デフォルトではこれほどタイトなコードを生成しません(または、NEONの場合は並列化します)。したがって、r8を介した書き込みはすぐに読み込まれる可能性があります。 r9またはr10を通るループの次の反復。restrict( C ++の場合)修飾子を使用し__restrictて、これが当てはまらないことをコンパイラーに通知できます。

于 2012-08-16T09:15:57.583 に答える