LoginSignup
1
2

More than 5 years have passed since last update.

vpermt2b

Posted at

みなさんは、SSE/AVXプログラミング中に、こう思ったことはありませんか…?

「なんでこんなにシャッフル命令使い分けないといけないんだ…」

もう、そんなことで悩む時代は終わりました!これからは vpermt2b(_mm512_permutex2var_epi8) を使いましょう!

vpermt2b は zmm を2個くっつけた、128byte のデータを、バイト単位で、完全に任意に、実行時に作ったテーブルで並びかえられます!

脅威の128byte!インデックスの値が8bitしか持てないのが不安に感じられる大きさです!

#include <immintrin.h>
#include <stdio.h>

unsigned char in0[128];
unsigned char out[64];
unsigned char table[64];

static void
test(void)
{
    register __m512i dest __asm__("zmm0") = _mm512_loadu_si512(in0);
    register __m512i src1 __asm__("zmm1") = _mm512_loadu_si512(table);
    register __m512i src2 __asm__("zmm2") = _mm512_loadu_si512(in0+64);

    __asm__ __volatile__ (".byte 0x62, 0xf2, 0x75, 0x48, 0x7d, 0xc2 # vpermt2b %%zmm2 %%zmm1, %%zmm0\n\t"
                          :[dest]"+v"(dest)
                          :[src1]"v"(src1),
                           [src2]"v"(src2));

    _mm512_storeu_si512(out, dest);

    int i,j;
    for (i=0; i<4; i++) {
        printf("%3d: ", i*16);

        for (j=0; j<16; j++) {
            printf("%3d ", out[i*16+j]);
        }

        puts("");
    }
}

int
main()
{
    int i;
    for (i=0; i<128; i++) {
        in0[i] = i + 10;
    }

    for (i=0; i<32; i++) {
        table[i*2+0] = i*2;
        table[i*2+1] = 110-i;
    }

    test();

    puts("--");

    for (i=0; i<64; i++) {
        table[i] = i*2;
    }

    test();

    puts("--");

    for (i=0; i<64; i++) {
        table[i] = i;
    }

    test();

}
 $ ./sde -cnl -- ./a.out
  0:  10 120  12 119  14 118  16 117  18 116  20 115  22 114  24 113
 16:  26 112  28 111  30 110  32 109  34 108  36 107  38 106  40 105
 32:  42 104  44 103  46 102  48 101  50 100  52  99  54  98  56  97
 48:  58  96  60  95  62  94  64  93  66  92  68  91  70  90  72  89
--
  0:  10  12  14  16  18  20  22  24  26  28  30  32  34  36  38  40
 16:  42  44  46  48  50  52  54  56  58  60  62  64  66  68  70  72
 32:  74  76  78  80  82  84  86  88  90  92  94  96  98 100 102 104
 48: 106 108 110 112 114 116 118 120 122 124 126 128 130 132 134 136
--
  0:  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25
 16:  26  27  28  29  30  31  32  33  34  35  36  37  38  39  40  41
 32:  42  43  44  45  46  47  48  49  50  51  52  53  54  55  56  57
 48:  58  59  60  61  62  63  64  65  66  67  68  69  70  71  72  73

やったね!

    register __m512i dest __asm__("zmm0") = _mm512_loadu_si512(in0);
    register __m512i src1 __asm__("zmm1") = _mm512_loadu_si512(table);
    register __m512i src2 __asm__("zmm2") = _mm512_loadu_si512(in0+64);

    __asm__ __volatile__ (".byte 0x62, 0xf2, 0x75, 0x48, 0x7d, 0xc2 # vpermt2b %%zmm2 %%zmm1, %%zmm0\n\t"
                          :[dest]"+v"(dest)
                          :[src1]"v"(src1),
                           [src2]"v"(src2));

なんだこの不穏なコードは…?

vpermt2b は、AVX512VBMI というまた別の拡張になっていて、binutils も2.24では対応してませんでした。仕方なく git の binutils を取ってきて、それで出たバイト列を埋めてます。

このハイパー便利そうな vpermt2b ですが、一個だけ欠点があって、

 $ ./sde -knl -- ./a.out  
TID 0 SDE-ERROR: Executed instruction not valid for specified chip (KNL): 0x400688: vpermt2b zmm0, zmm1, zmm2
Image: /home/w0/test/avx512/a.out+0x688
Function: test
Instruction bytes are: 62 f2 75 48 7d c2 

 $ ./sde -skx -- ./a.out  
TID 0 SDE-ERROR: Executed instruction not valid for specified chip (SKYLAKE_SERVER): 0x400688: vpermt2b zmm0, zmm1, zmm2
Image: /home/w0/test/avx512/a.out+0x688
Function: test
Instruction bytes are: 62 f2 75 48 7d c2

Skylake でも KNL でも使えないのだった。(つまり使えない)

明日は、@tanakmura の推しイン(イチ推しインストラクション)、vpconflictd について書きます。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2