ARM EABI と浮動小数点演算

前回のベンチマークで,EABI 環境では浮動小数点演算が改善されたことがわかったので,今回はそこらへんを見ていきましょう.

プログラム

こんなプログラムを書いて

#include <stdio.h>

int main ( void )
{
	double a = 1.0, b = 2.0;

	printf ( "%f\n", a + b );

	return 0;
}

こんなふうにコンパイルします.

$ gcc -mfpu=fpa -O0 floattest.c 

浮動小数点演算が最適化されてしまっては意味が無いので,-O0 オプションで最適化を阻止.

OABI 環境

生成された a.out をディスアセンブルしてみます.

$ objdump -d a.out

a.out:     file format elf32-littlearm

…(略)…
000083c0 <main>:
    83c0:      e1a0c00d        mov     ip, sp
    83c4:      e92dd810        stmdb   sp!, {r4, fp, ip, lr, pc}
    83c8:      e24cb004        sub     fp, ip, #4      ; 0x4
    83cc:      e24dd010        sub     sp, sp, #16     ; 0x10
    83d0:      e28f3044        add     r3, pc, #68     ; 0x44
    83d4:      e8930018        ldmia   r3, {r3, r4}
    83d8:      e50b3020        str     r3, [fp, #-32]
    83dc:      e50b401c        str     r4, [fp, #-28]
    83e0:      e28f303c        add     r3, pc, #60     ; 0x3c
    83e4:      e8930018        ldmia   r3, {r3, r4}
    83e8:      e50b3018        str     r3, [fp, #-24]
    83ec:      e50b4014        str     r4, [fp, #-20]
    83f0:      ed1b9108        ldfd    f1, [fp, #-32]
    83f4:      ed1b8106        ldfd    f0, [fp, #-24]
    83f8:      ee010180        adfd    f0, f1, f0
    83fc:      e59f0028        ldr     r0, [pc, #40]   ; 842c <.text+0x178>
    8400:      ed2d8102        stfd    f0, [sp, #-8]!
    8404:      e8bd0006        ldmia   sp!, {r1, r2}
    8408:      ebffffa3        bl      829c <.text-0x18>
    840c:      e3a03000        mov     r3, #0  ; 0x0
    8410:      e1a00003        mov     r0, r3
    8414:      e24bd010        sub     sp, fp, #16     ; 0x10
    8418:      e89da810        ldmia   sp, {r4, fp, sp, pc}
    841c:      3ff00000        svccc   0x00f00000      ; IMB
    8420:      00000000        andeq   r0, r0, r0
    8424:      40000000        andmi   r0, r0, r0
    8428:      00000000        andeq   r0, r0, r0
    842c:      00008524        andeq   r8, r0, r4, lsr #10

    …(略)…

ldfd とか adfd なんていうニーモニックが見えますね.

浮動小数点演算ユニットの無い CPU の場合,

  1. 浮動小数点演算を実行しようとする
  2. 未定義命令なので例外が発生
  3. カーネルの例外処理に飛ぶ
  4. 実行しようとした命令が浮動小数点演算である
  5. カーネル側の浮動小数点演算エミュレーションコードを実行
  6. ユーザプログラムに復帰

なんて処理を行います. いちいちカーネルモードとユーザモードを行き来するので,オーバヘッドは大きいわけです.

EABI 環境の場合

同様にコンパイルした実行ファイルを同様にディスアセンブルしてみます.

$ objdump -d a.out 

a.out:     file format elf32-littlearm

…(略)…

00008398 <main>:
    8398:      e1a0c00d        mov     ip, sp
    839c:      e92dd810        push    {r4, fp, ip, lr, pc}
    83a0:      e24cb004        sub     fp, ip, #4      ; 0x4
    83a4:      e24dd014        sub     sp, sp, #20     ; 0x14
    83a8:      e3a03000        mov     r3, #0  ; 0x0
    83ac:      e3a045ff        mov     r4, #1069547520 ; 0x3fc00000
    83b0:      e2844603        add     r4, r4, #3145728        ; 0x300000
    83b4:      e50b3024        str     r3, [fp, #-36]
    83b8:      e50b4020        str     r4, [fp, #-32]
    83bc:      e3a03000        mov     r3, #0  ; 0x0
    83c0:      e3a04101        mov     r4, #1073741824 ; 0x40000000
    83c4:      e50b301c        str     r3, [fp, #-28]
    83c8:      e50b4018        str     r4, [fp, #-24]
    83cc:      e24b0024        sub     r0, fp, #36     ; 0x24
    83d0:      e8900003        ldm     r0, {r0, r1}
    83d4:      e24b201c        sub     r2, fp, #28     ; 0x1c
    83d8:      e892000c        ldm     r2, {r2, r3}
    83dc:      eb00000e        bl      841c <__adddf3>
    83e0:      e1a03000        mov     r3, r0
    83e4:      e1a04001        mov     r4, r1
    83e8:      e59f001c        ldr     r0, [pc, #28]   ; 840c <main+0x74>
    83ec:      e1a02003        mov     r2, r3
    83f0:      e1a03004        mov     r3, r4
    83f4:      ebffffb3        bl      82c8 <_init+0x50>
    83f8:      e3a03000        mov     r3, #0  ; 0x0
    83fc:      e1a00003        mov     r0, r3
    8400:      e24bd010        sub     sp, fp, #16     ; 0x10
    8404:      e89d6810        ldm     sp, {r4, fp, sp, lr}
    8408:      e12fff1e        bx      lr
    840c:      000088c4        .word   0x000088c4

    …(略)…

浮動小数点の足し算は,__adddf3 というルーチンをコールして実行しているようです. で,この __adddf3 は

0000841c <__adddf3>:
    841c:      e92d4030        push    {r4, r5, lr}
    8420:      e1a04081        lsl     r4, r1, #1
    8424:      e1a05083        lsl     r5, r3, #1
    8428:      e1340005        teq     r4, r5
    842c:      01300002        teqeq   r0, r2
    8430:      1194c000        orrsne  ip, r4, r0
    8434:      1195c002        orrsne  ip, r5, r2
    8438:      11f0cac4        mvnsne  ip, r4, asr #21
    843c:      11f0cac5        mvnsne  ip, r5, asr #21
    8440:      0a00008c        beq     8678 <__adddf3+0x25c>
    8444:      e1a04aa4        lsr     r4, r4, #21
    8448:      e0745aa5        rsbs    r5, r4, r5, lsr #21
    844c:      b2655000        rsblt   r5, r5, #0      ; 0x0
    8450:      da000006        ble     8470 <__adddf3+0x54>
    …(略)…

と,実行プログラムにスタティックリンクされてたりします. つまり,EABI 環境での浮動小数点演算は,ユーザスペースのプログラム内のみで完結しており,カーネルへのスイッチは発生しないことになります.

というわけで

先日のベンチマークの結果も納得できましたね.


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2009-01-18 (日) 01:39:02 (5600d)