ARM EABIでの浮動小数点演算

EABIとOABIのページでは、EABIでは浮動小数点演算がとても速くなると紹介しました。本ページでは、EABIにおける浮動小数点演算の取扱いを詳しくみていきます。

なお、ツールチェインやライブラリは、emdebianのものを使用します。emdebianツールチェインのインストール方法は、ARMクロス開発環境構築を参照してください。

1. デフォルトの浮動小数点演算の取扱い 〜 soft-float 〜

まずは、デフォルトで浮動小数点演算がどのように処理されるのか、見ていきます。

サンプルプログラムとして、以下のコードを使用します。

sample.c

#include <stdio.h>

double __attribute__((noinline)) float_mult(double a, double b)
{
    return a * b;
}

int main(int argc, char *argv[])
{
    double d;

    d = float_mult(12.3, 98.7);

    printf("%lf\n", d);

    return 0;
}



これを、デフォルトの設定でコンパイルしてみます。emdebianのEABI用ツールチェインでは、デフォルトで"-mfloat-abi=soft"がついたものと同じ、すなわち、ソフトフロートのコードを生成します。
$ arm-linux-gnueabi-gcc -Wall -g -O1 sample.c -o default
$ arm-linux-gnueabi-objdump -S default > default.dump



浮動小数点演算は、__aeabi_dmul()という関数に置き換えられました。__aeabi_dmul()は、実行ファイルにスタティックリンクされており、FPAやVFPなどの浮動小数点演算命令を含まない関数です。
double __attribute__((noinline)) float_mult(double a, double b)
{
    845c:       e52de004        push    {lr}            ; (str lr, [sp, #-4]!)
    8460:       e24dd004        sub     sp, sp, #4      ; 0x4
    8464:       eb000016        bl      84c4 <__aeabi_dmul>
        return a * b;
}
    8468:       e28dd004        add     sp, sp, #4      ; 0x4
    846c:       e49de004        pop     {lr}            ; (ldr lr, [sp], #4)
    8470:       e12fff1e        bx      lr


浮動小数点演算が浮動小数点演算命令を含まない関数に置き換えられたことで、(浮動小数点演算ユニットを持たないハードで)浮動小数点演算をおこなったときにFPEによるコンテキストスイッチが発生せず、浮動小数点演算が速くなります。

OABIでは、浮動小数点演算はFPA用の浮動小数点演算命令で処理していました。しかし、現在のARMプロセッサでFPAを搭載しているものは(おそらく)存在しません。そのため、ほぼ全てのハードで、OABIからEABIへユーザランドを変更することで浮動小数点演算高速化の恩恵を受けることができます。("ほぼ全て"としたのは、OABIでもアプリとライブラリすべてがhard-floatでビルドされている場合、EABIのsoft-floatよりも、浮動小数点演算は高速に処理できるからです。)

2. 浮動小数点演算ユニットを使う 〜 softfp 〜

EABIのsoft-floatにした場合、VFPなどの浮動小数点演算ユニットを持っているハードでもそれらを使用しないことになります。せっかくVFPがついているのであれば、できればその能力を活かしたいところです。

EABIで浮動小数点演算命令を含むバイナリを生成するためのコンパイルオプションとして、"softfp"というものがあります。("hard-float"は、EABIでは使用することはできません。)

softfpは、gcc-4.3のmanページによると以下のような意味を持つオプションです。

man gcc-4.3より

`softfp' allows the generation of floating point instructions, but still uses the soft-float calling conventions. 


"softfp"でコンパイルするとどうなるか、実際に見てみましょう。
$ arm-linux-gnueabi-gcc -Wall -g -O1 -mfloat-abi=softfp -mfpu=vfp sample.c -o soft-fp-vfp
$ arm-linux-gnueabi-objdump -S soft-fp-vfp > soft-fp-vfp.dump


浮動小数点演算は、"fmuld"という命令に置き換えられました。"fmuld"は、VFP用の浮動小数点演算命令です。
double __attribute__((noinline)) float_mult(double a, double b)
{
        return a * b;
}
    845c:       ec410b16        vmov    d6, r0, r1
    8460:       ec432b17        vmov    d7, r2, r3
    8464:       ee265b07        fmuld   d5, d6, d7
    8468:       ec510b15        vmov    r0, r1, d5
    846c:       e12fff1e        bx      lr


"softfp"でコンパイルされたバイナリは、浮動小数点演算命令を含みます。一方で、コーリングコンベンションは"soft-float"(デフォルト)と同じです。このため、"softfp"でコンパイルされたバイナリと"soft-float"でコンパイルされたバイナリは混ぜることができます。

このため、浮動小数点演算がボトルネックになっていて、それを改善したい場合、もしアプリ側にボトルネックがあるのならばアプリだけを"softfp"でビルドしなおしたり、ライブラリの一つが問題であればそのライブラリだけを"softfp"でビルドしなおして使用するといったことが可能です。

Debianのarmelパッケージで提供されるライブラリは"soft-float"なので、速度が問題となっているところだけ"softfp"に置き換えることができるというのは、とても便利だったりします。


Comments