ぐだぐだ低レベルプログラミング(104)ARM64(AArach64)FABS、FSQRT他

Joseph Halfmoon

今回は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種です。

    1. FABS、絶対値
    2. FNEG、符合反転
    3. 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は正を負にしてくれるだけでなく、負は正になるっと。fabsnegsqrtResults

2の平方根はありがち。倍精度じゃ足らんというお人はこちらへ(アセンブラじゃなくなるケド。)

ぐだぐだ低レベルプログラミング(103)ARM64(AArach64)FSUB、FMUL他 へ戻る

ぐだぐだ低レベルプログラミング(105)ARM64(AArach64)FMOV へ進む