インテル® C++ コンパイラー 17.0 デベロッパー・ガイドおよびリファレンス
オリジナルの C/C++ スカラー関数に対応するベクトル関数を指定します。 このベクトル関数は、ベクトル・コンテキストで呼び出すことができます。
Windows®: __declspec(vector_variant(clauses)) |
Linux*: __attribute__((vector_variant(clauses))) |
clauses |
設定可能な値は以下のとおりです。 implements 節。implements (<function declarator>) [, <simd-clauses>]) 形式で指定します。function declarator はオリジナルのスカラー関数、simd-clauses は vector 属性で許可されている 1 つ以上の節です。 simd-clauses はオプションです。 |
この属性により、プログラマーはベクトル関数と対応するスカラー関数を表現できます。 コンパイラーは、ベクトル化されたループでスカラー関数の呼び出しをベクトル関数に置き換えます。
この属性に関する制限は以下のとおりです。
ベクトル関数には、1 つの vector_variant アノテーションのみ指定できます。
ベクトル関数のアノテーションでは、1 つの implements 節のみ指定できます。
ベクトル関数のアノテーションは、1 つのベクトル関数にのみ適用され、mask 節と nomask 節を一緒に指定することはできません。 mask 節または nomask 節のいずれかを指定することは可能です。デフォルトは nomask です。
ユーザー定義のベクトル関数で mask 節を指定する場合、mask 引数は最後の引数にします。
以下に、ベクトル関数の例を示します。
#include<immintrin.h>
__declspec(noinline)
float MyAdd(float* a, int b) { return *a + b; }
__declspec(vector_variant(implements(MyAdd(float *a, int b)),
linear(a), vectorlength(8),
nomask, processor(core_2nd_gen_avx)))
__m256 __regcall MyAddVec(float* v_a, __m128i v_b, __m128i v_b2) {
__m256i t96 = _mm256_castsi128_si256(v_b);
__m256i tmp = _mm256_insertf128_si256(t96, v_b2, 1);
__m256 t95 = _mm256_cvtepi32_ps(tmp);
return _mm256_add_ps(*((__m256*)v_a), t95);
}
float x[2000], y[2000];
float foo(float y[]) {
#pragma omp simd
for (int k=0; k< 2000; k++) {
x[k] = MyAdd(&y[k], k);
}
return x[0] + x[1999];
戻り値に 2 つ以上のレジスターが含まれる場合、次の方法で関数を正しく定義できます。
#include<immintrin.h>
typedef struct {
__m256d r1;
__m256d r2;
} __m256dx2;
__declspec(noinline)
double MyAdd(double* a, int b) { return *a + b; }
__declspec(vector_variant(implements(MyAdd(double *a, int b)),
linear(a), vectorlength(8),
nomask, processor(core_2nd_gen_avx)))
__m256dx2 __regcall MyAddVec(double* v_a, __m128i v_b, __m128i v_b2) {
__m256d t1 = _mm256_cvtepi32_pd(v_b);
__m256d t2 = _mm256_cvtepi32_pd(v_b2);
__m256dx2 ret;
ret.r1 = _mm256_mul_pd(t1,*((__m256d*)v_a));
ret.r2 = _mm256_mul_pd(t2,*(((__m256d*)v_a)+1));
return ret;
}
__declspec(align(32)) double x[2000], y[2000];
double foo(double* y) {
#pragma omp simd
for (int k=0; k< 2000; k++) {
x[k] = MyAdd(y, k);
y++;
}
return x[0] + x[1999];
}