
前回はLD1命令を練習。1ストラクチャが1要素の一番「シンプル」なベクトルロード命令です。今回はLD1と対になるST1命令をつかってベクトルストアを練習してみます。ベクトルロードしたものを即ストア。折角なので前回未使用だったポスト・インデックス・アドレシングも使用。「シンプル」といいながら1命令の動作がデッカイドー。
※「ぐだぐだ低レベルプログラミング」投稿順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
ベクトル・ストア命令と今回実験の関数
ベクトル・レジスタをオペランドにとるベクトル・ストア命令は、前回のベクトル・ロード命令同様、各要素、バイトからクワッドワードまでのビット幅に対応しています。全部練習するのはメンドイので前回同様に単精度浮動小数(ワード幅、32ビット)だけを練習してお茶を濁します。てへ。
LD1命令でメモリからロードしたベクトルをST1命令でメモリにストアするのですが、同じメモリアドレスに書き戻したのではなんだか分からないので、LD1命令のアドレシングモードにポスト・インデックスを採用し、ロード後のアドレス・レジスタの内容をロードしたベクトルの長さ分ずらしてみます。なお、ポストインデックス処理のアドレス確認のため fld1R4S4p という関数を設けてます。
また、LD1もST1もターゲットとなるレジスタは4本までとれるので、今回はフルに4本ロードして4本ストアすることにしてみます。
結果、「いつものように手抜きな」関数プロローグ無、エピローグ無の被テスト関数ですが、64バイト(単精度浮動小数16個)を一気にロード、および一気にロードしてストアするものが以下に。
.globl fld1R4S4p, fst1R4S4
.text
.balign 4
fld1R4S4p:
ld1 {v0.4S, v1.4S, v2.4S, v3.4S}, [x0], #64
ret
fst1R4S4:
ld1 {v0.4S, v1.4S, v2.4S, v3.4S}, [x0], #64
st1 {v0.4S, v1.4S, v2.4S, v3.4S}, [x0]
ret
C言語記述のmain関数
前回、ベクトルレジスタの内容を直接 gdb で観察したのが、老眼の目に辛かったので、今回はメモリにストアしてprintfで表示してます。この方がお楽(かといって一致比較までソフトで完結してしまうと楽しくないし。)
最初に、ベクトルロード命令のポスト・インデックス・アドレシングでx0が更新されることを確認、つづいて「ロードしたものを即ストア」してみます。
#include <stdio.h>
#include <stdint.h>
#define MAXMEM (32)
float TargetMEM[MAXMEM];
extern float * fld1R4S4p(float *);
extern void fst1R4S4(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) {
float * adr = NULL;
initTGT(1.001f);
printf("TargetMEM ADR=0x%016lx\n", TargetMEM);
adr = fld1R4S4p(TargetMEM);
printf("POST-INDEX ADR=0x%016lx\n", adr);
dumpTGT("Before STORE");
fst1R4S4(TargetMEM);
dumpTGT("After STORE");
return 0;
}
ビルドして実行
コンパイルと実行の最初の部分が以下に。与えたメモリアドレスがPOST-INDEXで0x40バイト(64バイト)分ズレたのが分かりますかね。
つづいて以下はロード、ストアのメモリ領域の初期値です。このうち先頭側の16個のデータをベクトルレジスタに1命令でロードし、その後、後ろの16個のデータに上書きする予定っす。まずは初期値を覚えて?おいてくだされ。
ロードして即ストアの結果が以下に。後半の16個のデータが書き換わっているのがわかりますか。
ロードしたものを即ストアしただけ、一気に64バイトだけれども。
