インテル® C++ コンパイラー 18.0 デベロッパー・ガイドおよびリファレンス
このトピックは、インテル® メニー・インテグレーテッド・コア (インテル® MIC) アーキテクチャーをターゲットとする場合にのみ適用されます。
オフロードコードには次の制約があります。
CPU で実行するコード内およびコプロセッサーで実行するコード内で例外処理が行われた場合、CPU の例外を CPU で扱い、コプロセッサーの例外をコプロセッサーで扱うことは可能ですが、コプロセッサーの例外を CPU で扱うことはできません。
#pragma offload 文に続く文の内部でマクロを使用しないでください。ただし、プラグマから呼び出されるサブプログラムではマクロを使用することができます。
コンパイラーは、offload プラグマに続く文の中にある関数に対してインライン展開を行いません (forceinline プラグマが指定された関数も含む)。ただし、コンパイラーの判断で、offload プラグマが指定された文から呼び出されたサブプログラムで関数のインライン展開を行う可能性があります。
ホスト CPU スレッドは同時に複数実行できますが、コードのセクションをオフロードするのは 1 つのホスト CPU スレッドです。この場合、ロック、アトミック、ミューテックス、OpenMP* atomic 操作、OpenMP* critical、OpenMP* taskwait、OpenMP* barrier などの同期メカニズムは、ホスト CPU コードとターゲットにオフロードされたコードとの間では動作しません。ただし、ホスト CPU のコードが OpenMP* を使用して並列化されている場合、OpenMP* 並列領域の一部がターゲットにオフロードされても、OpenMP* 並列領域の最後の同期は保証されます。
変数をターゲットで使用できるようにするには、オフロードコード内から呼び出される関数で参照されるグローバル変数が、一致するターゲット属性で宣言されている必要があります。また、ホストとターゲット間でこれらの変数の値を同期するため、in/out/inout 節を指定して明示的に値を送信/受信する必要があります。オフロードプラグマの語彙スコープ内でアクセス可能なグローバル変数は、一致するターゲット属性で宣言されている必要はありません。また、関連する値はデフォルトで送信/受信されます。オフロードプラグマの語彙スコープで使用されるグローバルポインター変数は、in/out/inout 節内で指定する必要があります。これはコンパイラーによる制約です。
デフォルトでは、ポインター変数は対応する型の単一要素を指すと仮定されます。オフロードコードはポインターを逆参照して単一要素にアクセスできます。ポインターが指すデータ要素はターゲットメモリーおよび調整されたポインター値に自動的にコピーされます。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 節に追加します。
#pragma offload 領域内でostream オブジェクト std::cout のようなビット単位でコピーできないオブジェクトを使用することはできません。使用すると、コンパイラーは「変数 "std::cout" はビット単位でコピーできません」のようなエラーを出力します。
インテル® Cilk™ Plus キーワードは 3 つ (_Cilk_spawn、_Cilk_sync、_Cilk_for) あります (インテル® Cilk™ Plus は古い機能 (非推奨) です)。#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++) { // オフロード領域内で直接使用可能
// ...
}
}
}