インテル® C++ コンパイラー 18.0 デベロッパー・ガイドおよびリファレンス
SIMD 演算用の C++ クラスを使用することで、単一の操作で複数の配列/ベクトルデータを処理できます。例として、2 つのベクトル A と B の加算を考えてみます。各ベクトルは 4 つの要素で構成されているとします。整数ベクトルクラスを使用して、各配列から取り出した要素 A[i] と B[i] を下の例のように加算します。
int a[4], b[4], c[4]; for (i=0; i<4; i++) /* 4 回反復が必要 */ c[i] = a[i] + b[i]; /* c[0]、c[1]、c[2]、c[3] を計算する */
次の例を見ると、整数クラスを使用すれば 1 回の演算で同じ結果が得られることが分かります。
Is16vec4 ivecA, ivecB, ivec C; /* 1 回反復が必要 */ ivecC = ivecA + ivecB; /* ivecC0、ivecC1、ivecC2、ivecC3 を計算する */
並列処理は、C++ では通常それほど簡単には実装できませんが、インテル® C++ SIMD クラスを使用すればそれが可能です。次の表は、インテル® C++ SIMD クラスで SIMD クラスとライブラリーがどのように使用されるかを列挙したものです。
SIMD ベクトルクラス
命令セット |
クラス |
符号の有無 |
データ型 |
サイズ |
要素の数 |
ヘッダーファイル |
---|---|---|---|---|---|---|
インテル® MMX® テクノロジー |
I64vec1 |
不定 |
__m64 |
64 |
1 |
ivec.h |
|
I32vec2 |
不定 |
int |
32 |
2 |
ivec.h |
|
Is32vec2 |
符号付き |
int |
32 |
2 |
ivec.h |
|
Iu32vec2 |
符号なし |
int |
32 |
2 |
ivec.h |
|
I16vec4 |
不定 |
short |
16 |
4 |
ivec.h |
|
Is16vec4 |
符号付き |
short |
16 |
4 |
ivec.h |
|
Iu16vec4 |
符号なし |
short |
16 |
4 |
ivec.h |
|
I8vec8 |
不定 |
char |
8 |
8 |
ivec.h |
|
Is8vec8 |
符号付き |
char |
8 |
8 |
ivec.h |
|
Iu8vec8 |
符号なし |
char |
8 |
8 |
ivec.h |
インテル® SSE |
F32vec4 |
不定 |
float |
32 |
4 |
fvec.h |
|
F32vec1 |
不定 |
float |
32 |
1 |
fvec.h |
インテル® SSE2 |
F64vec2 |
不定 |
double |
64 |
2 |
dvec.h |
|
I128vec1 |
不定 |
__m128i |
128 |
1 |
dvec.h |
|
I64vec2 |
不定 |
long int |
64 |
2 |
dvec.h |
|
I32vec4 |
不定 |
int |
32 |
4 |
dvec.h |
|
Is32vec4 |
符号付き |
int |
32 |
4 |
dvec.h |
|
Iu32vec4 |
符号なし |
int |
32 |
4 |
dvec.h |
|
I16vec8 |
不定 |
int |
16 |
8 |
dvec.h |
|
Is16vec8 |
符号付き |
int |
16 |
8 |
dvec.h |
|
Iu16vec8 |
符号なし |
int |
16 |
8 |
dvec.h |
|
I8vec16 |
不定 |
char |
8 |
16 |
dvec.h |
|
Is8vec16 |
符号付き |
char |
8 |
16 |
dvec.h |
|
Iu8vec16 |
符号なし |
char |
8 |
16 |
dvec.h |
インテル® AVX |
F32vec8 |
不定 |
float |
32 |
8 |
dvec.h |
F64vec4 |
不定 |
double |
64 |
4 |
dvec.h |
ほとんどのクラスは、どのデータ型についても同じような機能を持っていて、利用できるすべての組込み関数で表現されています。ただし一部の機能については、データ型が変わるときにその機能を維持しようとするとパフォーマンスが下がる場合があるため、個々のクラスからは除外しています。
即値をとるためにクラスの中に簡単に表現できない組込み関数は実装していません。次に例を示します。
必要なクラス・ヘッダー・ファイルは、インテル® C++ コンパイラーと一緒にインクルード・ディレクトリーにインストールされます。各クラスを有効にするときは、次の表に示すように、プログラムファイルの中で #include ディレクティブを使用してください。
クラスを有効にするためのインクルード・ディレクティブ
拡張命令セット |
インクルード・ディレクティブ |
---|---|
インテル® MMX® テクノロジー |
#include <ivec.h> |
インテル® SSE |
#include <fvec.h> |
インテル® SSE2 |
#include <dvec.h> |
インテル® SSE3 |
#include <dvec.h> |
インテル® SSE4 |
#include <dvec.h> |
インテル® AVX |
#include <dvec.h> |
上の表で、dvec.h は fvec.h の内容を含みます。同様に fvec.h は ivec.h の内容を含みます。Ivec クラスと Fvec クラスの両方を使用する場合は、fvec.h をインクルードするだけで済みます。同様に、インテル® ストリーミング SIMD 拡張命令 2 を利用する場合に、その 3 つとも含むすべてのクラスを使用するときは、dvec.h ファイルをインクルードするだけで済みます。
C++ クラスの使用方法については、一般的なガイドラインがいくつかあります。クラスごとの使用規則については、「整数ベクトルクラス」および「浮動小数点ベクトルクラス」を参照してください。
MMX レジスターの消去
Ivec クラスと Fvec クラスを同時に使用している場合は、Ivec クラスから呼び出されるインテル® MMX® 命令と、Fvec クラスから呼び出されるインテル® アーキテクチャー浮動小数点命令がプログラムの中で混在していることがあります。次の Fvec 関数の中には x87 の浮動小数点命令が含まれています。
fvec コンストラクター
デバッグ関数 (cout および要素アクセス)
rsqrt_nr
MMX レジスターは浮動小数点レジスター上にエイリアス化されています。したがって、x87 浮動小数点命令を発行する前には、EMMS 命令の組込み関数を使用して MMX ステートを消去する必要があります。次に例を示します。
ivecA = ivecA & ivecB; |
インテル® MMX® 命令を使用する Ivec 論理演算 |
empty (); |
ステートを消去 |
cout << f32vec4a; |
x87 浮動小数点命令を使用する F32vec4 演算 |
MMX レジスターを消去しないとレジスターステートが不正な状態になります。そのため、処理が不正確になったり、パフォーマンスが低下したりすることがあります。