ぐだぐだ低レベルプログラミング(129)ARM64(AArach64)FSQRT(ベクトル)

Joseph Halfmoon

前回前々回とA64のSIMD命令のうちソースオペランドを2つ取る演算命令の2タイプを練習しました。今回はソースオペランドを一つだけとる演算命令の代表選手?FSQRTです。前にもそんなこと書いた気がするな。デジャヴか記憶の混濁か?SIMD命令はとっても数が多いので「各パターン」せめて一種類くらいは練習しておこうと。

※「ぐだぐだ低レベルプログラミング」投稿順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

FSQRT(ベクトル)命令

今回練習してみるFSQRT命令の図が以下に。単精度浮動小数4個をベクトルレジスタv1 にロードして、それぞれの平方根をとって結果をベクトルレジスタv0に書き込みます。その後、v0をストア。fsqrtvDiagram

前回はデスティネーションオペランドもアキュムレータとして計算にとりこまれるパターンでしたが、今回はそのようなこともなく平和です。

勿論、FSQRT命令は以下の3種類のデータを計算できることになっているのですが、例によってARMv8p0は半精度には対応していないのでこれは練習できず。また、メンドイので単精度のみ実習してお茶を濁すと、いつものとおり。

    1. 半精度浮動小数
    2. 単精度浮動小数
    3. 倍精度浮動小数
実験につかったアセンブリ言語記述の被テスト関数

例によって手抜きの関数プロローグ、エピローグ無の被テスト関数です。今回簡単だからパスしても、と思ったですけど、異なる演算(転送)パターン毎に1種類は練習すべしとの最低限のお約束。

.globl	fsqrtv
.text
.balign	4

fsqrtv:
    ld1  {v1.4S}, [x0], #16
    fsqrt v0.4S, v1.4S
    st1  {v0.4S}, [x0]
    ret
C言語記述のmain関数

上記のアセンブリ言語関数を呼び出すmain関数が以下に。FSQRTをやる前のメモリ初期値をダンプ、平方根とった後で再びダンプというお手軽コードです。そして平方根とった結果には、中学生でも暗記しているやつ(今はしないか?)「ひとよひとよにひとみごろ」と「ひとなみにおごれや」が微妙に(単精度浮動小数を10進表記しているので最後の方があやしい)含まれとります。

#include <stdio.h>
#include <stdint.h>

#define MAXMEM	(8)
float TargetMEM[MAXMEM];

extern void fsqrtv(float *);

void initTGT(float c) {
    for (int i=0; i < MAXMEM; i++) {
        TargetMEM[i] = c * (i+1);
    }
}

void dumpTGT(const char *arg) {
    printf("%s\n", arg);
    for (int i=0; i < MAXMEM; i++) {
        printf("%d: %f\n", i, TargetMEM[i]);
    }
}

int main(void) {
    initTGT(1.000f);

    dumpTGT("Before FSQRTv");
    fsqrtv(TargetMEM);
    dumpTGT("After  FSQRTv");

    return 0;
}
実験結果

以下のようにしてビルドして実行しています。

$ gcc -g -O0 fsqrtv.c fsqrt.s
$ ./a.out

標準出力に現れた結果が以下に。

fsqrtvResults

平方根とれてるみたい。当たり前か。

ぐだぐだ低レベルプログラミング(128)ARM64(AArach64)FMLA、ベクトル積和 に戻る

ぐだぐだ低レベルプログラミング(130)ARM64(AArach64)MOV(ベクトル)へ進む