はじめに
コンパイラがvalignq
という見慣れない命令を吐いたのでその機能について覚書。
使い方
valignq
は、二つの512bitレジスタと整数を引数にとって、二つのレジスタをくっつけて、その「間」を取ってくるような働きをします。AVX-512Fに属しているので、AVX-512に対応している石全てで使えます。
組み込み関数としてはこんな感じの使い方になります。
__m512i c = _mm512_alignr_epi64(a, b, count);
図解するとこんな感じです。
つまり、第一引数a
を上位512bit、第二引数b
を下位512bitとする1024bitのデータを考え、その下位のcount*64
bitから512bitのデータを取ってくる命令です。
ただし、count
は即値である必要があります。
サンプルコード
以下がサンプルです。
#include <immintrin.h>
#include <stdio.h>
#include <stdint.h>
void
put8(__m512i a){
int64_t *v = (int64_t*)(&a);
for(int i=0;i<8;i++){
printf("%ld ",v[7-i]);
}
printf("\n");
}
int
main(void){
__m512i a = _mm512_set_epi64(15,14,13,12,11,10,9,8);
__m512i b = _mm512_set_epi64(7,6,5,4,3,2,1,0);
printf("a = ");
put8(a);
printf("b = ");
put8(b);
printf("c = ");
__m512i c = _mm512_alignr_epi64(a, b, 3);
put8(c);
}
実行結果はこうなります。
$ ./a.out
a = 15 14 13 12 11 10 9 8
b = 7 6 5 4 3 2 1 0
c = 10 9 8 7 6 5 4 3
マスク版(_mm512_mask_alignr_epi64
や_mm512_maskz_alignr_epi64
)もありますが、その動作はすぐにわかると思うので省略します。
まとめ
コンパイラが吐いたんだから使える命令なんだと思いますが、いまいち使いみちが思いつきません。特にシフトする数が即値じゃないといけない、ということが使いみちを狭めている気がします。この命令を使うときれいに書けるような処理があったら是非教えてください。