Vector Type Extension¶
概要¶
NEC C/C++コンパイラでは、GCC、clang のVector Type Extensionと互換のあるベクトル型を利用できます。 さらに、NEC C/C++ Compilerの独自拡張であるVector builtin関数、それらでマスク処理を使用するためのベクトルマスク型を利用できます。
#include <_vector.h>
// Vector builtin関数を使用するときインクルードする
typedef double vf256 __attribute__((ext_vector_type(256)));
// double型の要素、その個数が256個のベクトル型の型定義
vf256 a; // 変数の宣言
vf256 func(vf256 b, vf256 c) // ベクトル型の関数の定義
{
return a + b * c; // ベクトル型の積和計算
}
ベクトル型の型定義¶
ベクトル型は、vector_size、ext_vector_type のどちらかのattribute指定で型定義できます。
vector_size¶
形式¶
typedef <element-type> <type-name> __attribute__((vector_size(<size>)));
説明¶
- element-type:
ベクトル型の要素の型
- type-name:
ベクトル型の名前
- size:
ベクトル型のサイズ。単位はバイト。element-typeのサイズ×要素数に等しい値を指定する。2のべき乗数のみ指定できる。
ext_vector_type 属性¶
形式:¶
typedef <element-type> <type-name> __attribute__((ext_vector_type(<num>)));
説明:¶
- element-type:
ベクトル型の要素の型
- type-name:
ベクトル型の名前
- num:
ベクトル型の要素数。2のべき乗数以外の値も指定できる。element-typeのサイズ×numの値がベクトル型のサイズとなる。
注意事項¶
- ベクトル型の要素として指定できる型は以下です。
int、long、long long、および、それらのunsigned型
float、double
ベクトル型の最大サイズは、要素のサイズが8バイトのとき2048バイト、サイズが4バイトのとき1024バイトです。
ベクトル型は、そのサイズ以上の2のべき乗数の最小値でアラインされます。
V.xyzwによる定義、引用は利用できません。
ベクトル型の配列は利用できません。
利用例¶
typedef double v1 __attribute__((vector_size(sizeof(double)*256))); // OK
typedef double v2 __attribute__((ext_vector_type(256))); // OK
// v1とv2は同一のベクトル型
typedef float v3 __attribute__((vector_size(sizeof(float)*15))); // Error
// サイズが2のべき乗数でない
typedef float v4 __attribute__((ext_vector_type(15))); // OK
typedef float v5 __attribute__((vector_size(sizeof(float)*512)));// Error
// サイズが1024バイトより大きい
typedef float v6 __attribute__((ext_vector_type(512))); // Error
// サイズが1024バイトより大きい
typedef short v7 __attribute__((vector_size(sizeof(short)*16))); // Error
// 要素の型が不適切
typedef long double v8 __attribute__((ext_vector_type(16))); // Error
// 要素の型が不適切
ベクトル型の定数¶
ベクトル型の定数は、各要素の値を中括弧で囲って指定します。
typedef double vf4 __attribute__((vector_size(sizeof(double)*4)));
vf4 a = { 1.0, 2.0, 3.0, 4.0 }; // 右辺がベクトル型の定数
vf4 b = { 2.0, 3.0 }; // 3、4番目の要素の値は不定
演算子¶
次の演算子のオペランドとしてベクトル型が指定できます。
演算子 |
説明 |
---|---|
[n] |
n番目の要素にアクセス |
+、- |
単項演算 |
+、-、*、/、% |
加減乗除演算、剰余演算 |
&、|、^、~ |
ビット演算 |
>>、<< |
シフト演算 |
!、&&、|| |
否定、論理演算 |
==、!=、>、<、>=、<= |
等価演算、比較演算 |
= |
代入演算 |
? : |
条件演算 (C++でのみ利用可) |
sizeof |
sizeof演算 |
&v[i] |
ベクトル型の要素のアドレス取得 |
Builtin関数¶
clang で使用できる次のbuiltin関数が利用できます。
__builtin_shufflevector(vec1, vec2, index1, index2, ...)
__builtin_convertvector(src_vec, dest_vec_type)
vreg指示行¶
vreg指示行でベクトル型の変数に優先してベクトルレジスタを割り当てることができます。これにより、当該変数のベクトルロード、ベクトルストアを削減でき、高速化が期待できます。
形式¶
#pragma _NEC vreg(<name>)
説明¶
オブジェクト<name>にメモリの代わりにベクトルレジスタを割り当てる。 <name>がベクトル型であるとき、次の条件を満たさなければならない。
ローカル変数、または、関数の仮引数である
ベクトル型の配列ではない
クラス、構造体、共用体のメンバでない
ベクトル型の要素のアドレスを取得する演算のオペランドでない (&v[i]のvでない)
ベクトル型を処理するときのベクトル長は常にベクトル型の要素数に等しい
注意事項¶
ベクトル型の論理演算の真の値はall 1です。
サイズが異なるベクトル型の間では型変換できません。
ベクトル型のサイズは同じだが、その要素のサイズが異なるベクトル型の型変換は、 ベクトル型全体のコピーとして処理されます。
ベクトル型の変数はOpenMP指示句で指定できません。
プログラミング例¶
以下でベクトル型を使用したプログラミング例を示します。 ベクトル型の定数を記述するのは大変であるため、一般的には共用体(union)を 利用して初期化します。
#include <iostream>
// C++のエリアステンプレートを使ったベクトル型の型定義
template <typename T, int N>
using vector_type = T __attribute__((ext_vector_type(N)));
// 初期値設定、要素の設定、取り出しを容易にするためのunionの宣言
template <typename T, int N>
union Vec {
vector_type<T, N> v;
T e[N];
};
// ベクトルマスクのためのunionの宣言
typedef union {
__vm v;
unsigned int m[8];
} vmask;
template <typename T, int N>
T vector_sum(Vec<T, N> &a, Vec<T, N> &b, vmask &vm)
{
vector_type<T, N> c;
c = a.v * b.v;
__builtin_ve_vfsum(c, c, vm.v); // Vector builtin関数により総和を計算
return c[0]; // 計算結果は0番目の要素に設定される
}
int main()
{
double sum;
vmask vm;
Vec<double, 64> a, b;
// ベクトル型の初期値設定
for (int i = 0; i < 64; i++) {
a.e[i] = i;
b.e[i] = 64 - i;
}
// ベクトルマスク値の設定
for (int i = 0; i < 8; i++) {
vm.m[i] = 0xAAAAAAAAU; // 0b10101010101010....
}
sum = vector_sum<double,64>(a, b, vm);
std::cout << sum << " (Result must be 21824)" << std::endl;
}