インテル® C++ コンパイラー 15.0 ユーザー・リファレンス・ガイド
このトピックは、インテル® メニー・インテグレーテッド・コア (インテル® MIC) アーキテクチャーにのみ適用されます。
オフロードコードには次の制約があります。
CPU で実行するコード内およびコプロセッサーで実行するコード内で例外処理が行われた場合、CPU の例外を CPU で扱い、コプロセッサーの例外をコプロセッサーで扱うことは可能ですが、コプロセッサーの例外を CPU で扱うことはできません。
#pragma offload 文に続く文の内部で __MIC__ マクロを使用しないでください。 ただし、プラグマから呼び出されるサブプログラムでこのマクロを使用することはできます。
コンパイラーは、offload プラグマに続く文の中にある関数に対してインライン展開を行いません (forceinline プラグマが指定された関数も含む)。 ただし、コンパイラーの判断で、offload プラグマが指定された文から呼び出されたサブプログラムで関数のインライン展開を行う可能性があります。
ホスト CPU スレッドは同時に複数実行できますが、コードのセクションをオフロードするのは 1 つのホスト CPU スレッドです。この場合、ロック、アトミック、ミューテックス、OpenMP* atomic 操作、OpenMP* critical、OpenMP* taskwait、OpenMP* barrier などの同期メカニズムは、ホスト CPU コードとターゲットにオフロードされたコードとの間では動作しません。ただし、ホスト CPU のコードが OpenMP* を使用して並列化されている場合、OpenMP* 並列領域の一部がターゲットにオフロードされても、OpenMP* 並列領域の最後の同期は保証されます。
変数をターゲットで使用できるようにするには、オフロードコード内から呼び出される関数で参照されるグローバル変数が、一致するターゲット属性で宣言されている必要があります。オフロードコードはホスト CPU のグローバル変数にアクセスできません。これはコンパイラーによる制約です。
デフォルトでは、ポインター変数は対応する型の単一要素を指すと仮定されます。オフロードコードはポインターを逆参照して単一要素にアクセスできます。ポインターが指すデータ要素はターゲットメモリーおよび調整されたポインター値に自動的にコピーされます。element-count-expr 式と in / out / inout パラメーターを使用して、可変長データをコピーできます。
非ポインター型へのポインターのみサポートされます。 ポインター変数へのポインターはサポートされていません。これはコンパイラーによる制約です。
配列は、配列要素がスカラー型か、ビット単位でコピーできる構造体またはクラスの場合のみサポートされるため、 ポインターの配列はサポートされていません。
ポインターはホストとターゲット間のインターフェイスでコピーされず、代わりにポインターが指すデータがコピーされるため、別々の変数を指すポインター間の相対距離はホストとターゲットでは異なります。同じデータ構造内のポインター間の距離は、オフロードの後でも同じです。このため、ホスト CPU 上では有効であったポインター比較と算術演算は、ターゲット上では信頼性がなく、適切に使用できません。
同様に、ポインターで指されていたデータはオフロード後も利用できますが、プログラムは同じユーザー変数がオフロード後に指されることを仮定できません。例えば、次のようなコード行を考えてみます。
{int a = 55; int *p = &a; #pragma offload { q = p; ... }ターゲットの q は値 55 を指していますが、q の値はターゲットの &a になりません。
ポインターメンバーと非ポインターメンバーの組み合わせを含む共用体は、非ポインター値型を保持していると見なされます。このため、ポインターに対して特別な解釈は行われず、指されていたデータはターゲットにコピーされません。
すべてがポインターメンバーの共用体は、ホストとターゲット間でコピーできません。
オフロード文が別のファイルで定義された関数を呼び出して、その関数がグローバル変数を参照する場合、その参照はコンパイラーには不可視であるため、グローバル変数はコピーできません。オフロードされた文でも参照される場合、グローバル変数はコピーされます。
これらのグローバル変数は、オフロードの in および out 節で明示的に指定する必要があります。 これらのグローバル変数がファイルスコープのスタティック変数の場合、in または out 節で指定することはできません。 次のいずれかの方法を使用して値にアクセスする必要があります。
外部変数にしてオフロードの in または out 節に追加します。
専用の関数を使用して変数値をローカル変数にフェッチし、ローカル変数を in または out 節に追加します。
#pragma offload 領域内で ostream オブジェクト std::cout のようなビット単位でコピーできないオブジェクトを使用することはできません。 使用すると、コンパイラーは「変数 "std::cout" はビット単位でコピーできません」のようなエラーを出力します。
インテル® Cilk™ Plus キーワードは 3 つ (_Cilk_spawn、_Cilk_sync、_Cilk_for) あります。 #pragma offload 構造内の関数ではすべてのキーワードを使用できますが、オフロード構造内では _Cilk_for のみ使用できます。 インテル® Cilk™ Plus スポーンルーチンの一部のみをオフロードすることは不正であるため、#pragma offload 構造内で _Cilk_spawn および _Cilk_sync を使用することはできません。 スポーンルーチン全体をオフロードする必要があります。
例えば、次のコードは不正です。
#pragma offload target(mic) { _Cilk_spawn f(); // _Cilk_spawn をオフロード構造内で使用 }
次のコードは有効です。
#pragma offload target(mic) { g(); } ... void g() { _Cilk_spawn f(); // _Cilk_spawn をオフロード関数内で使用 }
次のコードは無効です。
Void foo() { #pragma offload target(mic) { _Cilk_spawn test() // オフロード内では使用できません test(); _Cilk_sync; // オフロード内では使用できません } }
次のコードは有効です。
__declspec(target(mic)) void foo() { #pragma offload target(mic) { _Cilk_spawn test() test(); _Cilk_sync; } } void bar() { #pragma offload target(mic) { foo(); } }
次のコードは有効です。
void foo() { #pragma offload target(mic) { _Cilk_for (int i = 0; i < 10; i++) { // オフロード領域内で直接使用できます // ... } } }