valignq

はじめに

コンパイラがvalignqという見慣れない命令を吐いたのでその機能について覚書。

使い方

valignqは、二つの512bitレジスタと整数を引数にとって、二つのレジスタをくっつけて、その「間」を取ってくるような働きをします。AVX-512Fに属しているので、AVX-512に対応している石全てで使えます。

組み込み関数としてはこんな感じの使い方になります。

__m512i c = _mm512_alignr_epi64(a, b, count);

図解するとこんな感じです。

image0.png

つまり、第一引数aを上位512bit、第二引数bを下位512bitとする1024bitのデータを考え、その下位のcount*64bitから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)もありますが、その動作はすぐにわかると思うので省略します。

まとめ

コンパイラが吐いたんだから使える命令なんだと思いますが、いまいち使いみちが思いつきません。特にシフトする数が即値じゃないといけない、ということが使いみちを狭めている気がします。この命令を使うときれいに書けるような処理があったら是非教えてください。