SIMD 演算用の C++ クラスは、配列 (ベクトルデータ) を並列処理するときに使用するのが基本です。例として、2 つのベクトル A と B の加算を考えてみます。各ベクトルは 4 つの要素で構成されているとします。整数ベクトル (Ivec) クラスを使用して、各配列から取り出した要素 A[i] と B[i] を下の例のように加算します。
short a[4], b[4], c[4];
for (i=0; i<4; i++) /* needs four iterations */
c[i] = a[i] + b[i]; /* returns c[0], c[1], c[2], c[3] *
次の例を見ると、Ivec クラスを使用すれば 1 回の演算で同じ結果が得られることがわかります。
sIs16vec4 ivecA, ivecB, ivec C; /*needs one iteration */
ivecC = ivecA + ivecB; /*returns ivecC0, ivecC1, ivecC2, ivecC3 */
並列処理は、C++ では通常それほど簡単には実装できませんが、インテル(R) C++ SIMD クラスを使用すればそれが可能です。次の表は、インテル C++ SIMD クラスでクラスとライブラリーがどのように使用されるかを列挙したものです。
命令セット | クラス | 符号の有無 | データ型 | サイズ | 要素の数 | ヘッダーファイル |
---|---|---|---|---|---|---|
MMX(R) テクノロジー | 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 | |
ストリーミング SIMD 拡張命令 | F32vec4 | 符号付き | float | 32 | 4 | fvec.h |
F32vec1 | 符号付き | float | 32 | 1 | fvec.h | |
ストリーミング SIMD 拡張命令 2 | F64vec2 | 符号付き | double | 64 | 2 | dvec.h |
I128vec1 | 不定 | __m128i | 128 | 1 | dvec.h | |
I64vec2 | 不定 | long int | 64 | 4 | dvec.h | |
Is64vec2 | 符号付き | long int | 64 | 4 | dvec.h | |
Iu64vec2 | 符号なし | long int | 32 | 4 | 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 |
ほとんどのクラスは、どのデータ型についても同じような機能を持っていて、利用できるすべての組み込み関数で表現されています。ただし一部の機能については、データ型が変わるときにその機能を維持しようとするとパフォーマンスが下がる場合があるため、個々のクラスからは除外しています。
注
即値をとるためにクラスの中に簡単に表現できない組み込み関数は実装していません。
(例えば、_mm_shuffle_ps、_mm_shuffle_pi16、_mm_extract_pi16、_mm_insert_pi16)
必要なクラス・ヘッダー・ファイルは、インテル(R) C++ コンパイラーと一緒にインクルード・ディレクトリーにインストールされます。各クラスを有効にするときは、次の表に示すように、プログラムファイルの中で #include 宣言子を使用してください。
拡張命令セット | インクルード宣言子 |
---|---|
MMX テクノロジー | #include <ivec.h> |
ストリーミング SIMD 拡張命令 | #include <fvec.h> |
ストリーミング SIMD 拡張命令 2 | #include <dvec.h> |
上の表で、dvec.h は fvec.h の内容を含みます。同様に fvec.h は ivec.h の内容を含みます。Ivec クラスと Fvec クラスの両方を使用する場合は、fvec.h をインクルードするだけで済みます。同様に、ストリーミング SIMD 拡張命令 2 を利用する場合に、その 3 つとも含むすべてのクラスを使用するときは、dvec.h ファイルをインクルードするだけで済みます。
C++ クラスの使用方法については、一般的なガイドラインがいくつかあります。クラスごとの使用規則については、「整数ベクトルクラス」および「浮動小数点ベクトルクラス」を参照してください。
Ivec クラスと Fvec クラスを同時に使用している場合は、Ivec クラスから呼び出される MMX 命令と、Fvec クラスから呼び出されるインテル(R) x87 アーキテクチャー浮動小数点命令がプログラムの中で混在していることがあります。次の Fvec 関数の中には浮動小数点命令が含まれています。
注
MMX テクノロジー・レジスターは浮動小数点レジスター上にエイリアス化されています。したがって、x87 浮動小数点命令を発行する前には、EMMS 命令の組み込み関数を使用して MMX テクノロジー・ステートを消去する必要があります。次に例を示します。
ivecA = ivecA & ivecB; | MMX 命令を使用する Ivec 論理演算 |
empty (); | ステートを消去 |
cout << f32vec4a; | x87 浮動小数点命令を使用する F32vec4 演算 |
警告
MMX テクノロジー・レジスターを消去しないとレジスターステートが不正な状態になります。そのため、処理が不正確になったり、パフォーマンスが低下したりすることがあります。
「EMMS 命令を使用する際のガイドライン」に従うことを強くお勧めします。Ivec クラスを使用してコーディングを行う前に、このトピックを参照してください。