ぐだぐだ低レベルプログラミング(170)ARM64(AArach64)SIMD即値シフト6

Joseph Halfmoon

前回、ロング化一族(勝手命名)を2回に分けて練習すると書きました。しかし既視感。実は今回練習にとってあった4命令、練習済でした。実体がない上に、二股かけてる?奴らだったからです。気を取り直して今回は挿入系一族(勝手命名)といっても2命令だけですがを練習していきたいと思います。ぐだぐだな成り行きだな。

※「ぐだぐだ低レベルプログラミング」投稿順indexはこちら

※実機動作確認には以下を使用しております。

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命令

さて気を取り直して練習したのは以下です。simdSFTimm6_tableB

 

大量な即値シフト命令群の中で独特な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

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

「下地」のデスティネーションにはオール1が詰めてあります。24ビット(3バイト)左シフトが上のSLI、24ビット(3バイト)右シフトが下のSRIです。予定通りの動作ね。

ぐだぐだ低レベルプログラミング(169)ARM64(AArach64)SIMD即値シフト5 へ戻る

ぐだぐだ低レベルプログラミング(171)ARM64(AArach64)SIMD即値シフト7 へ進む