インテル® C++ コンパイラー 18.0 デベロッパー・ガイドおよびリファレンス
このトピックは、インテル® グラフィックス・テクノロジーをターゲットとする場合にのみ適用されます。
インテル® Cilk™ Plus は、インテル® C++ コンパイラー 18.0 では非推奨の古い機能です。プロセッサー・グラフィックスへオフロードする代替手段は、将来のリリースで提供される予定です。詳細は、「インテル® Cilk™ Plus の代わりに OpenMP* またはインテル® TBB を使用するためのアプリケーションの移行」を参照してください。
__declspec(gfx_kernel) 属性で宣言された関数の並列ループが、第 1 レベルの並列ループの入れ子 (_Thread_group が付きます) になることがあります。
第 1 レベルの並列ループの入れ子内では、次の構造のみ許可されます。
SLM (共有ローカルメモリー) データ宣言 (オプションで初期化子を含めることも可能)
__thread_group_local データへの代入
第 2 レベルの並列ループの入れ子
スレッドバリア組込み関数の呼び出し
シリアルコード (シリアルコードの定義と関連する制約事項については「シリアルコード」を参照してください)
チャンクサイズはすべての次元で 1 になることが保証されています。そのため、各スレッドグループは、第 1 レベルのループの入れ子の 1 つの反復だけを実行します。
シリアルコードとは、第 2 レベルの並列ループの入れ子の構文に含まれない、第 1 レベルの並列ループの入れ子内のコードを指します。例えば、次のサンプルの行 4 ~ 5 です。
01 __declspec(target(gfx_kernel)) void slm_enabled_kernel(int *data, int param) {
02 _Cilk_for _Thread_group (...){
03 ...
04 int lo = param/2; // シリアルコード
05 int up = param*2; // シリアルコード
06
07 _Cilk_for (int j = lo; j < up; j++) {
08 ...
09 }
10 }
11 }
前述のシリアルコードは、各スレッドグループのマスタースレッドによって実行されます。上記のサンプルの行 7 にある入れ子構造の _Cilk_for ループのような並列構造に到達すると、マスタースレッドはグループ内のスレッド間で実行を分割します。
以下は、SLM を使用する行列乗算プログラムの一部です。この例からシリアルコードの制約事項が分かります。
01 _Cilk_for _Thread_group (int tg_y = 0; tg_y < Y; tg_y += SLM_TILE_Y) {
02 _Cilk_for _Thread_group (int tg_x = 0; tg_x < X; tg_x += SLM_TILE_X) {
03 // SLM に割り当てられる各行列の "スーパータイル" を宣言します
04 __thread_group_local float slm_atile[SLM_TILE_Y][SLM_TILE_K];
05 __thread_group_local float slm_btile[SLM_TILE_K][SLM_TILE_X];
06 __thread_group_local float slm_ctile[SLM_TILE_Y][SLM_TILE_X];
07
08 // スーパータイルを (並列に) 初期化します
09 _Cilk_for (int i = 0; i < SLM_TILE_Y; i++)
10 _Cilk_for (int j = 0; j < SLM_TILE_X; j++)
11 slm_ctile[i][j] = 0.0;
12
13 // 現在の A のスーパータイル行と B のスーパータイル列の
14 // ドット積を計算します
15 for (int super_k = 0; super_k < K; super_k += SLM_TILE_K) {
16 // 並列実行
17 // A と B の "スーパータイル" を SLM に (並列に) キャッシュします
18 slm_atile[:][:] = A[tg_y:SLM_TILE_Y][super_k:SLM_TILE_K];
19 slm_btile[:][:] = B[super_k:SLM_TILE_Y][tg_x:SLM_TILE_X];
20
21 // コピーが完了するまですべてのスレッドが待機します
22 _gfx_gpgpu_thread_barrier();
23
24 // 並列実行
25 // タイル化された行列乗算アルゴリズムを使用して
26 // 通常の行列のようにスーパータイルの乗算を (並列に) 実行します
27 _Cilk_for (int t_y = 0; t_y < SLM_TILE_Y; t_y += TILE_Y) {
28 _Cilk_for (int t_x = 0; t_x < SLM_TILE_X; t_x += TILE_X) {
行 1 ~ 2 は第 1 レベルの並列ループの入れ子、行 15 はシリアルコード、行 18 ~ 19 と行 27 ~ 28 は第 2 レベルの並列ループの入れ子です。シリアルコードは、スーパータイルのドット積を計算するループです。この計算は各スレッドグループによって実行され、このサイクルはスレッドグループ内のスレッド間で並列化されません。
グループ内のスレッドはすべて同じシリアルコードを実行します。同じスレッドグループ内の異なるスレッドが異なる結果になることはありません。また、現在のスレッド以外にアクセスできます。シリアルコードには次の制約事項があります。
ローカル変数と仮引数 (async カーネル)、または #pragma offload parameters (オフロードブロック) のみアクセスできます。例えば、静的変数やスレッド・グループ・ローカル変数へのアクセスは許可されません。
完全入れ子ループのみプロセッサー・グラフィックスへオフロードできます。2 レベルの並列処理では、第 1 レベルの入れ子が完全でなければなりません。これは、前述のローカル変数が第 1 レベルの入れ子内で宣言されなければならないことを意味します。
関数呼び出しは許可されません。
ポインターの逆参照などによるメモリーの更新は許可されません。
第 2 レベルの並列ループの入れ子外で宣言され、第 2 レベルの並列ループの入れ子内で使用されるローカル変数は、firstprivate として扱われます。ループの入れ子の後にこのような変数が有効な場合 (つまり、その値が使用される場合)、ループの入れ子内でこの変数を更新することはできません。
_Cilk_for ループとして明記された完全入れ子ループを第 2 レベルの並列ループの入れ子にできます。
入れ子内のループは、完全入れ子ループでなければなりません。
第 2 レベルの並列ループの入れ子は、第 1 レベルの入れ子に含める必要があります。第 1 レベルの入れ子から呼び出される関数内に配置することはできません。
少なくとも 1 つの第 2 レベルの並列ループの入れ子がなければなりません。
スレッド・グループ・ローカル・データには、次の構文の制約事項とセマンティクスが適用されます。
変数は、ローカルとして宣言し、直ちに第 1 レベルの並列ループの入れ子に含める必要があります。
__thread_group_local は常に SLM に割り当てられるため、データの合計サイズが利用可能な SLM を超えることはできません。
存続期間:
__thread_group_local データは、スレッドグループの開始時 (グループ内のスレッドが実行を開始する直前に) に割り当てられ、スレッドグループの終了時 (最後のスレッドが実行を完了した直後に) に解放されます。
初期化子は許可されており、SLM データに割り当てられます。
初期化子は、マスタースレッドにより実行されます。
初期化を行わない場合、初期値は定義されません。
__thread_group_local で定義可能な変数は、スカラー、スカラー配列、PODS のみです。
種類 |
例 |
制約事項 |
---|---|---|
変数宣言 |
|
問題なし。有効な SLM データ宣言。 |
変数宣言 |
|
無効な SLM データ宣言。_Cilk_for 入れ子構造のスレッドグループ内に入れ子されなければなりません。 |
ポインター宣言 |
|
問題なし。SLM に割り当てられるポインターの宣言。 |
ポインター宣言 |
|
問題なし。SLM に割り当てられたデータへのポインターの宣言。 |
クラス・オブジェクト |
|
無効。将来、言語拡張によりサポートされる可能性があります。 |
戻り値の型 |
|
問題なし。戻り値はポインター型。 |
戻り値の型 |
|
問題なし。rval の型修飾子が不適切ですが、許可されます/無視されます。 |
構造体フィールド |
|
宣言は問題なし。一部のコンテキストでは利用できません。 |
構造体フィールド |
|
許可されません。変数全体を __thread_local_group にする必要があります。 |
構造体 |
|
問題なし。一般に SLM データは配列であることが想定されますが、任意のデータが許可されます。 |
並列ループ |
|
foo がインライン展開されていない場合、このようなプラグマの定義はエラーと診断されます。ただし、言語上は問題ありません。 |