gcc拡張で手軽にベクタ命令

int v __attribute__((vector_size(16)));

とすると、v はサイズが16byteで各要素がint型であるベクタである。
int が 4byte だとすると、結果的に v は4つの要素を持つことになる。
このようにして定義されたベクタは

  • + (add)
  • - (sub)
  • * (mul)
  • / (div)
  • unary minus
  • ^ (xor)
  • | (or)
  • & (and)
  • ~ (not)

の演算が可能。


実際に使うときには union を用いると使いやすそうだ。

#include <stdio.h>
typedef union {
  int v __attribute__((vector_size(16)));
  int i[4];
} v4si;

int main(void)
{
  v4si a = {.i = {0, 1, 2, 3}}, b = {.i = {3, 2, 1, 0}}, c;
  int i;
  c.v = a.v + b.v;
  for (i = 0; i < 4; i++) {
    printf("%d ", c.i[i]);
  }
  putchar('\n');
  return 0;
}
% ./a.out
3 3 3 3

gcc -S してアセンブリコードを見てみると、movdqa や paddd といった命令が使われているのが分かる。


移植性の観点から言えば

  • mmintrin.h (MMX)
  • xmmintrin.h (SSE)
  • emmintrin.h (SSE2)
  • pmmintrin.h (SSE3)
  • tmmintrin.h (SSSE3)

などにある intrinsic functions を使うほうが良いのだけど、どうしても読みにくくなってしまう。*1
移植性を考えなくていい俺々コードを書くときにはこっちの方法も使うことがあるかもしれない。

*1:上記の方法でもベクタ演算の度に .v、ストアやロードのときには .i がつきまとって、それはそれで少し見づらくなるのだけど