これらのプラグマは、プログラム中の後に続くループのベクトル化を制御しますが、コンパイラーは入れ子されたループには適用しません。入れ子されたそれぞれのループの前に、プラグマ文が必要です。loop 文の前にプラグマを配置してください。
構文 |
---|
#pragma vector always |
vector always プラグマは、ベクトル化するかどうかを決定する際、効率ヒューリスティックを無効にするようコンパイラーに指示します。そして 1 以外のストライドまたはほとんどアライメントの合っていないメモリーアクセスをベクトル化します。
例: vector always 宣言子 |
---|
void vec_always(int *a, int *b, int m) { #pragma vector always for(int i = 0; i <= m; i++) a[32*i] = b[99*i]; } |
構文 |
---|
#pragma ivdep |
ivdep プラグマは、ベクトル依存性が存在していると推定されてもそれを無視するようコンパイラーに指示します。正しいコードにするため、コンパイラーは、想定される依存性を証明された依存性として扱い、ベクトル化を行わないようにします。このプラグマは、その決定を無視します。推定されたループの依存性が安全で、無視できる場合にのみ使用してください。
この例のループは、k の値が不明なため、ivdep プラグマなしではベクトル化を行いません (ベクトル化は k < 0 の場合、不正です)。
例 |
---|
void ignore_vec_dep(int *a, int k, int c, int m) { #pragma ivdep for (int i = 0; i < m; i++) a[i] = a[i + k] * c; } |
プラグマは、現在の関数に含まれている for ループだけをバインドします。これには、現在の関数によって呼び出されるサブ関数に含まれる for ループも含まれます。
構文 |
---|
#pragma vector {aligned | unaligned} |
プラグマは、ループのベクトル化が可能である限り、ベクトル化によるメリットの有無についての通常のヒューリスティックな判断を無視してベクトル化を行うことを示します。aligned または unaligned 指示子が使用されると、ループは、aligned または unaligned 演算を使用して、ベクトル化されます。aligned または unaligned のいずれか 1 つを指定します。
引数として aligned を指定する場合、ループはこの命令を使用してベクトル化可能であることが確実でなければなりません。それ以外の場合、コンパイラーは誤ったコードを生成します。
次の例に示すループは、コンパイラーは通常それが安全であると証明できないように配列が宣言されているため、aligned 指示子を使用して、aligned 命令でループがベクトル化されるように要求を出します。
例 |
---|
void vec_aligned(float *a, int m, int c) { int i; // Instruct compiler to ignore assumed vector dependencies. #pragma vector aligned for (i = 0; i < m; i++) a[i] = a[i] * c; // Alignment unknown but compiler can still align. for (i = 0; i < 100; i++) a[i] = a[i] + 1.0f; } |
コンパイラーは、コンパイル時にデータ構造のアライメントが不明な場合に備えて、いくつかのアライメント手法を用意しています。簡単な例を次に示します (ただし、他の方法もサポートされています)。ループにおいて、アライメントが不明な場合、コンパイラーはプレリュードのループを生成し、ほとんどの場合に発生する配列参照がアライメントされたアドレスにヒットするまでループを反復します。
例: アライメント手法 |
---|
float *a; // Alignment unknown for (i = 0; i < 100; i++) { a[i] = a[i] + 1.0f; } // Dynamic loop peeling p = a & 0x0f; if (p != 0) { p = (16 - p) / 4; for (i = 0; i < p; i++) { a[i] = a[i] + 1.0f; } } // Loop with a aligned (will be vectorized accordingly) for (i = p; i < 100; i++) { a[i] = a[i] + 1.0f; } |
構文 |
---|
#pragma novector |
プラグマは、ループのベクトル化が有効な場合でもループをベクトル化しないことを示します。この例では、反復回数 (ub - lb) が低すぎて、ベクトル化が無駄になるとわかっています。novector を使用して、ループがベクトル化可能であると認識されても、コンパイラーにベクトル化しないように指示できます。
例: novector 宣言子 |
---|
void foo(int lb, int ub) { #pragma novector for(j=lb; j<ub; j++) { a[j]=a[j]+b[j]; } } |
構文 |
---|
#pragma vector nontemporal |
IA-32 アーキテクチャー・ベースのシステムでストリーミング・ストアをもたらします。生成されたアセンブリーとのループ (float 型) の例は、次のとおりです。N が大きくなると、インテル(R) Pentium(R) 4 プロセッサー・システムでの非ストリーミング組み込み関数のパフォーマンスが大幅に向上します。
例 |
---|
#pragma vector nontemporal for (i = 0; i < N; i++) a[i] = 1; .B1.2: movntps XMMWORD PTR _a[eax], xmm0 movntps XMMWORD PTR _a[eax+16], xmm0 add eax, 32 cmp eax, 4096 jl .B1.2 |
例: 動的依存性のテスト例 |
---|
float *p, *q; for (i = L; I <= U; i++) { p[i] = q[i]; } ... pL = p * 4*L; pH = p + 4*U; qL = q + 4*L; qH = q + 4*U; if (pH < qL || pL > qH) { // loop without data dependence for (i = L; i <= U; i++) { p[i] = q[i]; } else { for (i = L; i <= U; i++) { p[i] = q[i]; } } |