
前回、ロング化一族(勝手命名)を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です。予定通りの動作ね。

