インテル® C++ コンパイラー 18.0 デベロッパー・ガイドおよびリファレンス

C++ クラスと SIMD 演算

SIMD 演算用の C++ クラスを使用することで、単一の操作で複数の配列/ベクトルデータを処理できます。例として、2 つのベクトル AB の加算を考えてみます。各ベクトルは 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 回の演算で同じ結果が得られることが分かります。

Ivec クラスを使用して複数の要素を加算する SIMD 手法

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

ほとんどのクラスは、どのデータ型についても同じような機能を持っていて、利用できるすべての組込み関数で表現されています。ただし一部の機能については、データ型が変わるときにその機能を維持しようとするとパフォーマンスが下がる場合があるため、個々のクラスからは除外しています。

即値をとるためにクラスの中に簡単に表現できない組込み関数は実装していません。次に例を示します。

  • _mm_shuffle_ps
  • _mm_shuffle_pi16
  • _mm_shuffle_ps
  • _mm_extract_pi16
  • _mm_insert_pi16

ヘッダーファイルを使用したクラスへのアクセス

必要なクラス・ヘッダー・ファイルは、インテル® 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 の浮動小数点命令が含まれています。

MMX レジスターは浮動小数点レジスター上にエイリアス化されています。したがって、x87 浮動小数点命令を発行する前には、EMMS 命令の組込み関数を使用して MMX ステートを消去する必要があります。次に例を示します。

ivecA = ivecA & ivecB;

インテル® MMX® 命令を使用する Ivec 論理演算

empty ();

ステートを消去

cout << f32vec4a;

x87 浮動小数点命令を使用する F32vec4 演算

注意

MMX レジスターを消去しないとレジスターステートが不正な状態になります。そのため、処理が不正確になったり、パフォーマンスが低下したりすることがあります。