ARM Linux ディストリビューションでの浮動小数点のサポートは簡単ではありません。そのため、オペレーティング システムとハードウェアであるシステムに一致するツールチェーンを使用し、適切なコンパイル スイッチを使用する必要があります。
まず、「関数を呼び出すときに引数を渡す方法」に関する ARM の呼び出し規則を理解する必要があります。. ARM は RISC アーキテクチャであるため、レジスタでのみ動作します。メモリを直接操作する命令はありません。メモリ内の値を変更する必要がある場合は、最初にそれをレジスタにロードし、変更してからメモリに保存する必要があります。
関数を呼び出すときに引数を渡す必要がある場合は、引数をスタック (メモリ) に置くことができますが、ARM はレジスタでしか動作しないため、関数が最初に行うことはおそらくそれらをレジスタにロードすることです。この無駄を避けるために、ARM 呼び出し規約はレジスタを使用して引数を渡します。ただし、ARM には限られた数のレジスタがあるため、呼び出し規約では、最初の 4 つの引数に最初の 4 つ (r0-r3) のレジスタのみを使用するように指示されており、残りは渡されるためにスタックを使用する必要があります。
2 つ目は、初期の ARM コアには浮動小数点がサポートされておらず、操作がソフトウェアで実装されていたことです。(これは、gcc の を介してまだサポートされているものです-mfloat-abi=soft
。)
次のスニペットを使用して、これが何を意味するかを簡単に示すことができます。
float pi2(float a) {
return a * 3.14f;
}
-c -O3 -mfloat-abi=soft
これを viaとobdump
ingでコンパイルすると、
00000000 <pi2>:
0: f24f 51c3 movw r1, #62915 ; 0xf5c3
4: b508 push {r3, lr}
6: f2c4 0148 movt r1, #16456 ; 0x4048
a: f7ff fffe bl 0 <__aeabi_fmul>
e: bd08 pop {r3, pc}
ご覧のとおり (実際には表示されません:))pi2
でパラメータを取得しr0
、入力pi constant
しr1
て使用__aeabi_fmul
し、それらを乗算して結果を で返しr0
ます。も同じ呼び出し規約を使用しているため__aeabi_fmul
、詳細r0
は表示されません。すべての関数は、データを入力r1
して に委譲するために行い__aeabi_fmul
ます。
フローティング ハードウェア サポートが ARM に追加されたとき (これもアーキテクチャ スタイルのため)、独自のレジスタ セット(s0、s1、...)が付属していました。
同じスニペットをコンパイルし-c -O3 -mfloat-abi=softfp
てダンプすると、
00000000 <pi2>:
0: eddf 7a04 vldr s15, [pc, #16] ; 14 <pi2+0x14>
4: ee07 0a10 vmov s14, r0
8: ee27 7a27 vmul.f32 s14, s14, s15
c: ee17 0a10 vmov r0, s14
10: 4770 bx lr
12: bf00 nop
14: 4048f5c3 .word 0x4048f5c3
ご覧のとおり、コンパイラは への呼び出しを作成しません__aeabi_fmul
が、代わりに、 にvmul.f32
ある引数を に移動しr0
てs14
に入力3.14
した後に命令を作成しs15
ます。乗算命令の後、呼び出し規約により、この関数の呼び出し元はそれを期待するため、s14
利用可能な結果を元に戻します。r0
サードパーティから提供されたライブラリと考えるpi2
と、soft 実装と softfp 実装の両方が同じことを行い、それらを交換可能に使用できることが理解できます。システムがそれらを提供する場合、アプリがハードウェア浮動小数点をサポートするシステムで実行されるかどうかは気にしません。これは、古いソフトウェアを新しいハードウェアで実行し続けるのに非常に役立ちました。
ただし、互換性を維持しながら、このアプローチでは、ARM レジスタと FP レジスタ間で値を移動するオーバーヘッドが発生します。これは明らかにパフォーマンスに影響し、 によって呼び出される新しい呼び出し規約によって対処さhard
れgcc
ます。この新しい規則は、関数に浮動小数点引数がある場合、通常の浮動小数点レジスタとインターリーブされた浮動小数点レジスタを利用できること、および浮動小数点レジスタで浮動小数点値を返すことができることを示していますs0
。
スニペットをコンパイルし-c -O3 -mfloat-abi=hard
てダンプすると、次のようになります。
00000000 <pi2>:
0: eddf 7a02 vldr s15, [pc, #8] ; c <pi2+0xc>
4: ee20 0a27 vmul.f32 s0, s0, s15
8: 4770 bx lr
a: bf00 nop
c: 4048f5c3 .word 0x4048f5c3
レジスタが移動していないことがわかります。への引数pi2
が渡されs0
、コンパイラが作成したコードを入力3.14
し、必要な結果を取得するためにs15
使用します。vmul.f32 s0, s0, s15
s0
この新しい規則の大きな問題は、コンパイラによって生成されたコードを改善すると、互換性が完全に失われてしまうことです。hard
規則soft/softfp
に従って構築されたアプリケーションが、ハード向けに構築されたライブラリで動作することを期待することはできません。
呼び出し規則の詳細については、ARM の Web サイトを確認してください。