restrict 修飾子 - 2023.2 日本語

AI エンジン カーネルおよびグラフ プログラミング ガイド (UG1079)

Document ID
UG1079
Release Date
2023-12-04
Version
2023.2 日本語

C 標準では、ポインター修飾子 __restrict を利用できます。これは、ポインターが参照するものと、その他すべての変数との間のデータ独立性を明示することで、より積極的なコンパイラ最適化を可能にします。次に例を示します。

int a; // global variable
void foo(int* __restrict p, int* q)
{
  for (...) { ... *p += a + *q; ...}
}

foo の解析は、*p*q および a と同じオブジェクトを指していないという事実に基づいて進めることができます。そのため、a*q はループの前に一度に読み込むことができます。

現在のところ、コンパイラのフロント エンドでは、同じ配列への異なるアクセスは明確に区別されません。そのため、配列の 1 つの要素をアップデートすると、配列全体の値が変更されたと想定されます。__restrict 修飾子を使用すると、この想定を無効にできます。これは、同じ配列への複数の独立したポインターを取得する場合に便利です。

void foo(int A[])
{
  int* __restrict rA = A; // force independent access
  for (int i = ...)
  rA[i] = ... A[i];
}

この例では、__restrict 修飾子により、ループのソフトウェア パイプライン処理が可能となり、前の要素を保存しながら次の要素を読み込むことができます。__restrict 修飾子の影響を最大限にするため、コンパイラのフロント エンドにより、デフォルトで初期化に chess_copy 演算が挿入されます。

int* __restrict rA = chess_copy(A);

これは、最適化で両方のポインターを異なるものに保持するために必要です (たとえば、共通部分式除去なし)。この動作は、オプション -mllvm -chess-implicit-chess_copy=false を使用して、aiecompiler フロントエンドで無効にできます。そのため、chess_copy により 2 つのポインターが作成され、__restrict によりこれらのポインターを使用したストア/ロード間の相互依存はコンパイラにより考慮されません。ローカル スコープを持つ __restrict ポインターでは、__restrict ポインターが有効である間のみ相互に独立していると想定されます。

__restrict ポインターから派生したポインター (rA+1 やポインター組み込み関数など) も restrict ポインターとなり、同じ制限されたメモリ領域をポイントします。

注記: chess_copy の詳細は、AI エンジン ラウンジにある『ASIP Programmer Chess コンパイラ ユーザー マニュアル』を参照してください。