ベクトルレジスタでの位置合わせ (_mm256_shuffle_ps)

2014年9月6日土曜日

SIMD

t f B! P L
続けて、ベクトルレジスタ同士を結合してシフトの方法、AVX編。

AVXの場合は256ビット長のベクトルレジスタ2つに入ったデータを、
合わせてシフトする命令はありません。

そこでshuffle命令を使います。_mm256_shuffle_psです。

shuffle命令を使うと、2つの256ビット長レジスタから、
1つ目の上位128ビット長のどこか2か所の32ビット2つと、
2つ目の上位128ビット長のどこか2か所の32ビット2つ、
続けて1つ目の下位128ビット長の先程と同じ相対位置の32ビット2つ、
最後に2つ目の下位128ビット長のやはり先程と同じ相対位置の32ビット2つ、
これをまとめて計256ビット長の値を合成できます。
はっきりいって訳わかりません。

分かりやすく書くと、以下の処理でシフトできるわけです。
__m256 x02x03x04x05x06x07x08x09 =
    _mm256_shuffle_ps(
        x04x05x06x07x08x09x10x11,
        x00x01x02x03x04x05x06x07,
        _MM_SHUFFLE(1, 0, 3, 2) /* = 0x4E */);
これを文章で書くと、
まず第2引数の下位128ビットの2番目(8~11バイト)と3番目(12~15バイト)を取り出し、
次に第1引数の下位128ビットの0番目(0~3バイト)と1番目(4~7バイト)を取り、
続けて第2引数の上位128ビットの2番目(24~27バイト)と3番目(28~31バイト)を、
最後に第1引数の上位128ビットの0番目(16~19バイト)と1番目(20~23バイト)を取って、
それを結果の256ビットにまとめる。という処理になります。
Little-endianなので下位ビットが最初のバイトになります。

同様に、今度は1番目(4バイト目)からの256ビット長の値が欲しい場合は、
__m256 x01x02x03x04x05x06x07x08 =
    _mm256_shuffle_ps(
        x02x03x04x05x06x07x08x09,
        x00x01x02x03x04x05x06x07,
        _MM_SHUFFLE(2, 1, 2, 1) /* = 0x99 */);
となります。

最後に、4番目(16バイト目)からの256ビット長の値が欲しい場合は、
__m256 x04x05x06x07x08x09x10x11 =
    _mm256_permute2f128_ps(
        x08x09x10x11x12x13x14x15,
        x00x01x02x03x04x05x06x07,
        3);
となります。_mm256_permute2f128_psを使います。

ここら辺は、面倒臭いので呪文のように覚えるのが吉ですね。

ラベル

AndroidTV (1) chromebook (2) DIY (4) docker (1) git (4) Ingress (4) llvm (3) MacBook (1) MVNO (1) narou (1) PS4 (2) QNAPNAS (9) SIMD (9) SmartBand (8) Ubuntu (9) VAIO (1) Windows (2) wsl (2) wsl2 (1) Xperia (20) トルネ (3) プログラム (26) ルーター (18) 音楽 (6) 家事 (2) 自炊 (2) 電子書籍 (2) 洋食 (4)

フォロワー

QooQ