前回より浮動小数点レジスタおよびSIMDレジスタのスカラーに関するメモリからのロード命令の練習を始めました。何度も書いているようにA64の命令も多すぎなら、アドレシング・モードも多すぎ(個人の感想です。)下手をするとオペランドのビット幅のバリエーションが多い分、整数ロード命令より組み合わせ多いんでないの。
※「ぐだぐだ低レベルプログラミング」投稿順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
A64のアドレシング・モードについて
整数ロード/ストア命令で使えるアドレシング・モードは皆使えるみたいです。アドレシングモードについては以下の回で「図を描きながら」一通りおさらいしてみています。
ぐだぐだ低レベルプログラミング(90)ARM64(AArach64)、ロードストア命令その1
整数ロード/ストア命令はオペランドのビット幅と符号拡張を指示するのにやたらニーモニックが増えていたことにくらべると、浮動小数点/SIMDのロード/ストア命令はニーモニックの種類が少ないのでありがたいデス。しかし整数型よりも、扱えるオペランドのビット幅のバリエーションが増えとります。ビット幅によりアドレシングモードのオフセット計算も影響受けるので組み合わせが増えている気がしないでもないです。
今回実験のアセンブリ言語関数
「いつものように手抜きな」関数プロローグもエピローグもない被テスト関数が以下に。今回は以下の5つのアドレシングモードを練習してみます。組み合わせがメンドイので例によってfloat型(単精度浮動小数)のみです。
-
- ベースレジスタ+64ビット幅インデックスレジスタ(シフト無)
- ベースレジスタ+64ビット幅インデックスレジスタ(シフト有)
- ベースレジスタ+32ビット幅インデックスレジスタ(符合なし拡張)
- ベースレジスタ+32ビット幅インデックスレジスタ(符合なし拡張、シフト有)
- PC相対
.globl fldrSRegLSL0, fldrSRegLSL2, fldrSRegUXTW0, fldrSRegUXTW2, fldrSPC .text .balign 4 fldrSRegLSL0: ldr s0, [x0, x1] ret fldrSRegLSL2: ldr s0, [x0, x1, LSL #2] ret fldrSRegUXTW0: ldr s0, [x0, w1, UXTW] ret fldrSRegUXTW2: ldr s0, [x0, w1, UXTW #2] ret fldrSPC: ldr s0, datalabel ret .balign 4 datalabel: .single 1.2345e3
C言語記述のmain関数
いつも通りの「通り一遍さわるだけの手抜きな」C言語記述のテスト駆動部です。float型を構造体メモリからロードしてます。インデックスレジスタを使う4種関数では全て同じメモリを指してそこからロードしています。今回「割愛」してますが実はインデックスの符合付拡張もありなので、とても全部やりきれないっと。
#include <stdio.h> #include <stdint.h> typedef struct { float s0; float s1; float s2; } TargetMEM; TargetMEM tgt; extern float fldrSRegLSL0(TargetMEM *, uint64_t); extern float fldrSRegLSL2(TargetMEM *, uint64_t); extern float fldrSRegUXTW0(TargetMEM *, uint32_t); extern float fldrSRegUXTW2(TargetMEM *, uint32_t); extern float fldrSPC(); void initTGT() { tgt.s0 = 1.2345f; tgt.s1 = 2.0001f; tgt.s2 = 3.1415f; } int main(void) { float resultS; initTGT(); resultS =fldrSRegLSL0(&tgt, 4); printf ("fldrSRegLSL0: %f\n", resultS); resultS =fldrSRegLSL2(&tgt, 1); printf ("fldrSRegLSL2: %f\n", resultS); resultS =fldrSRegUXTW0(&tgt, 4); printf ("fldrSRegUXTW0: %f\n", resultS); resultS =fldrSRegUXTW2(&tgt, 1); printf ("fldrSRegUXTW2: %f\n", resultS); resultS =fldrSPC(); printf ("fldrSPC: %e\n", resultS); return 0; }
ビルドして実行
ベース・レジスタ+インデックス・レジスタの4種は、いろいろアドレシングモード使って、結局同じデータを読んでますな。予定通り。PC相対の方はアセンブラソース中のデータをロードできてます。