前回、ロング化一族(勝手命名)を2回に分けて練習すると書きました。しかし既視感。実は今回練習にとってあった4命令、練習済でした。実体がない上に、二股かけてる?奴らだったからです。気を取り直して今回は挿入系一族(勝手命名)といっても2命令だけですがを練習していきたいと思います。ぐだぐだな成り行きだな。
※「ぐだぐだ低レベルプログラミング」投稿順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
既に練習済、SXTL一族
上記Arm様のマニュアルでは、参照する人の利便性を考えてのことでしょう。同じ命令が異なるカテゴリの表に登場することがあります。命令実体の解説ページは同一なので表のエントリだけですが。当方、表を手がかりに「端から」練習しているので、時々「これは練習したな」と思う命令に行き当たってスキップしてます。まあ、今回の SXTL、SXTL2、UXTL、UXTL2もそのような例なのです。フェイントなのは、
-
- SXTL、SXTL2、UXTL、UXTL2という実命令はない(エイリアス)
- 実体はSSHLL、SSHLL2、USHLL、USHLL2(前回演習)
- しかし符合拡張命令のカテゴリでエイリアスを練習済だった(第150回)
まあ、前回練習のエイリアスであったので、それらしく引数をあつらえ直して演習しようと思ったら、実は別カテゴリでやっていたというお粗末。忘却力であります。
即値シフト「挿入系」の2命令
大量な即値シフト命令群の中で独特なInsert属性の2命令、SLIとSRIです。「ほんわか」した動作を書くと以下のごとし。
-
- ソースをシフトする
- 実際にシフトした「ビット」だけをデスティネーションに送る
- シフトの際に「ゼロ詰め」された部分はデスティネーションの元の値を維持
実験につかったアセンブリ言語記述の被テスト関数
例によって手抜きの関数プロローグ、エピローグ無の被テスト関数のソースが以下に。さらに手抜きで要素のビット幅はワードのみ、SIMDレジスタは128ビット幅のみ限定です。
.globl sli4V, sri4V .text .balign 4 sli4V: ld1 {v0.4S, v1.4S}, [x0] sli v0.4S, v1.4S, #24 st1 {v0.4S}, [x0] ret sri4V: ld1 {v0.4S, v1.4S}, [x0] sri v0.4S, v1.4S, #24 st1 {v0.4S}, [x0] ret
C言語記述のmain関数
上記のアセンブリ言語関数を呼び出すmain関数が以下に。今回はめずらしく符号の有無関係ないので全てuint32_t型にしてあります。スッキリ?
#include <stdio.h> #include <stdint.h> #include <math.h> #define MAXMEM (8) uint32_t TargetMEM[MAXMEM]; extern void sli4V(uint32_t *); extern void sri4V(uint32_t *); void initTGT() { TargetMEM[0] = 0x11111111; TargetMEM[1] = 0x11111111; TargetMEM[2] = 0x11111111; TargetMEM[3] = 0x11111111; TargetMEM[4] = 0x12345678; TargetMEM[5] = 0x9ABCDEF0; TargetMEM[6] = 0xCC0000DD; TargetMEM[7] = 0xFF0000EE; } void dumpTGT(const char *arg) { printf("%s\n", arg); for (int i=0; i<4; i++) { printf("%02d: %08x\n", i, TargetMEM[i]); } } int main(void) { initTGT(); sli4V(TargetMEM); dumpTGT("sli v0.4S, V1.4S, #24"); initTGT(); sri4V(TargetMEM); dumpTGT("sri v0.4S, V1.4S, #24"); return 0; }
実機実行結果の確認
以下のようにしてビルドして実行しています。
$ gcc -g -O0 simdSFTImm6.c simdSFTImm6.s $ ./a.out
「下地」のデスティネーションにはオール1が詰めてあります。24ビット(3バイト)左シフトが上のSLI、24ビット(3バイト)右シフトが下のSRIです。予定通りの動作ね。