ベクトル化の例

このセクションでは、ベクトル・プログラミングの一般的な問題を簡単な例を用いていくつか紹介します。

引数のエイリアシング: ベクトルコピー

ベクトルコピーを行う次のループの例では、コンパイラーは dest[i]src[i] の相違を証明できるため、ベクトル化されます。

例: 相違を証明できるためにベクトル化可能なコピー

void vec_copy_multi_version(float *dest, float *src, int len)

{

  for (int i=0; i<len; i++)

    dest[i] = src[i];

}

次の例に示した restrict キーワードは、各ポインターが別々のオブジェクトを参照していることを示します。したがって、マルチバージョン・コードを生成しなくてもベクトル化できます。

例: ベクトル化できるだけの違いがあることを証明するための restrict の使用

void vec_copy(float *restrict dest, float *restrict src, int len)

{

  for (int i=0; i<len; i++)

    dest[i] = src[i];

}

データのアライメント

16 バイト (Linux* および Mac OS*) または 64 バイト (Windows*) 以上のデータ構造体または配列は、ベースアドレスが 16 (Linux および Mac OS) または 32 (Windows) の倍数になるように、各構造体要素または配列要素の先頭をアライメントしなければなりません。

下の図は、間違ってアライメントされたデータが原因でデータ・キャッシュ・ユニット (DCU) が分割した場合の影響を示したものです。アライメントの合っていないデータをロードすると 16 バイト境界にまたがるため、メモリーアクセスが 1 回余分に発生し、その結果、6 〜 12 サイクルのストールが発生します。データがアライメントされていることがわかっており、このアライメントを使用するよう指定すれば、このストールを回避できます。

16 バイト境界にまたがる間違ってアライメントされたデータ

例えば、要素 a[0]b[0] が 16 バイト境界にアライメントされているのがわかっている場合は、アライメント・オプション (#pragma vector aligned) をオンにすると、次のループはベクトル化できます。

例: ポインターのアライメントが確認済みの場合

void aligned(float *a, float *b, int len)

{

  for (int i=0; i<len; i++)

    a[i] = b[i];

}

ベクトル化の実行後、下の図に示すように、ループが実行されます。

ベクトルおよびスカラーのクリーンアップ反復処理

ベクトル反復処理である a[0:3] = b[0:3]a[4:7] = b[4:7] は、要素 a[0]b[0] (同様に a[4]b[4]) が 16 バイトでアライメントされている場合には、アライメントの合った移動命令を使用して両方とも実装できます。

警告

不正なアライメント・オプションでベクトライザーを使用すると、コンパイラーの動作は予測がつかなくなります。特に、アライメントの合っていないデータを、アライメントの合っている移動命令で処理すると、不正命令例外が発生します。

データのアライメント例

下の例は、アライメントの合っていないメモリー命令でしかベクトル化しないループを示したものです。コンパイラーはこのローカル配列をアライメントできますが、コンパイル時には lb の値がわからないため、アライメントが正しいかどうかの判断はできません。

例: コンパイル時に変数の値がわからないためにアライメントされないループ

void unaligned(int lb, float *a, float x, float *y, int len)

{

  for (int i=lb; i<len; i++)

    a[i] = a[i] * x + y[i];

}

lb が 4 の倍数であることがわかっているときは、下の例に示したように #pragma vector aligned を使用してループをアライメントできます。

例: 変数の値が 4 の倍数であるという前提でアライメントを行う

#include <assert.h>

void assert_aligned(int lb, float *a, float x, float *y, int len)

{

  assert(lb%4 == 0);

  #pragma vector aligned

  for (int i=lb; i<len; i++)

    a[i] = a[i] * x + y[i];

}