今回はFloating-point arithmetic(one source)のカテゴリを一気にやります。といっても3命令、FABS、FNEG、FSQRTです。例外とか「コマケー話」を避けていれば浮動小数点の演算そのものは素直で分かりやすい?です。そのうちメンドイ話もやらんといかんですが、今回は無し。平穏無事。。
※「ぐだぐだ低レベルプログラミング」投稿順indexはこちら
※実機確認には以下を使用しております。
-
- Raspberry Pi 4 model B、Cortex-A72コア(ARMv8-A)
- Raspberry Pi OS (64bit) bullseye
- gcc (Debian 10.2.1-6) 10.2.1 20210110
ARMv8もいろいろレベルがあり、Arm Cortex-A72はARMv8の中でもベーシックな(命令数の少ない)ARMv8p0です。
※A64の最新のマニュアルは以下でダウンロード可能です。
Arm Architecture Reference Manual for A-profile architecture
Floating-point arithmetic (one sources)
前回はソースレジスタ2つの間で演算してその結果をデスティネーションに書き込む two sources命令でした。今回はソースレジスタ1個を引数として何か関数に通してその結果をデスティネーションに書き込む one sources 命令群です。
ARMv8.2以降であれば、半精度が使えますが、残念ながらARMv8.0上で練習しているので、倍精度、単精度のみとなります。命令は以下の3種です。
-
- FABS、絶対値
- FNEG、符合反転
- FSQRT、平方根
動作そのものは実行結果などご覧いただければ分かるかと。
今回実験に使用したアセンブリ言語ソース
いつものように、関数プロローグもエピローグもない、手抜きな「ほぼ」1命令1関数スタイルの被テスト関数群が以下に。
.globl fabsd, fabss, fnegd, fnegs, fsqrtd, fsqrts .text .balign 4 fabsd: fabs d0, d1 ret fabss: fabs s0, s1 ret fnegd: fneg d0, d1 ret fnegs: fneg s0, s1 ret fsqrtd: fsqrt d0, d1 ret fsqrts: fsqrt s0, s1 ret
C言語記述のmain関数
上記の関数群を呼び出して、ざっとテストするだけのmain()関数です。これまた平穏無事?
#include <stdio.h> #include <stdint.h> extern double fabsd(double, double); extern float fabss(float, float); extern double fnegd(double, double); extern float fnegs(float, float); extern double fsqrtd(double, double); extern float fsqrts(float, float); int main(void) { double resultD; float resultS; resultD = fabsd(0.0, -1.234567890123456); printf ("fabsd(0.0, -1.234567890123456): %.16e\n", resultD); resultS = fabss(0.0f, -1.234567f); printf ("fabss(0.0f, -1.234567f): %f\n", resultS); resultD = fabsd(0.0, 1.234567890123456); printf ("fabsd(0.0, 1.234567890123456): %.16e\n", resultD); resultS = fabss(0.0f, 1.234567f); printf ("fabss(0.0f, 1.234567f): %f\n", resultS); resultD = fnegd(0.0, 1.234567890123456); printf ("fnegd(0.0, 1.234567890123456): %.16e\n", resultD); resultS = fnegs(0.0f, 1.234567f); printf ("fnegs(0.0f, 1.234567f): %f\n", resultS); resultD = fnegd(0.0, -1.234567890123456); printf ("fnegd(0.0, -1.234567890123456): %.16e\n", resultD); resultS = fnegs(0.0f, -1.234567f); printf ("fnegs(0.0f, -1.234567f): %f\n", resultS); resultD = fsqrtd(0.0, 2.0); printf ("fsqrtd(0.0, 2.0): %.16e\n", resultD); resultS = fsqrts(0.0f, 2.0f); printf ("fsqrts(0.0f, 2.0f): %f\n", resultS); return 0; }
ビルドして実行
冒頭に掲げたものを再掲します。FABSは負の数を正にするけれども、正は正のまま、FNEGは正を負にしてくれるだけでなく、負は正になるっと。
2の平方根はありがち。倍精度じゃ足らんというお人はこちらへ(アセンブラじゃなくなるケド。)