(SPARC) ポインタ型の値をとる関数の引数を制限付きポインタとして扱います。f には次の値のいずれかを指定します。
表 A–46 -xrestrict の値
値 |
意味 |
---|---|
%all |
ファイル全体のすべてのポインタ型引数を制限付きとして扱います。 |
%none |
ファイル内のどのポインタ型引数も制限付きとして扱いません。 |
%source |
メインソースファイル内に定義されている関数のみ制限付きにします。インクルードファイル内に定義されている関数は制限付きにしません。 |
fn[,fn...] |
1 つ以上の関数名のコンマ区切りのリスト。関数リストが指定された場合は、指定された関数内のポインタ型引数を制限付きとして扱います。詳細については、次の「A.2.175.1 制限付きポインタ」を参照してください。 |
このコマンド行オプションは独立して使用できますが、最適化時に使用するのがもっとも適しています。たとえば、次のようなコマンドを使用します。
%CC -xO3 -xrestrict=%all prog.cc |
このコマンドでは、ファイル prog.c 内のすべてのポインタ引数を制限付きポインタとして扱います。次のようなコマンド行があるとします。
%CC -xO3 -xrestrict=agc prog.cc |
このコマンドでは、ファイル prog.c 内の関数 agc のすべてのポインタ引数を制限付きポインタとして扱います。
デフォルトは %none で、-xrestrict と指定すると -xrestrict=%sourcel と指定した場合と同様の結果が得られます。
コンパイラが効率よくループを並列化できるようにするには、左辺値が記憶領域の特定の領域を示している必要があります。別名とは、記憶領域の決まった位置を示していない左辺値のことです。オブジェクトへの 2 個のポインタが別名であるかどうかを判断することは困難です。これを判断するにはプログラム全体を解析することが必要であるため、非常に時間がかかります。次の関数 vsq() を考えてみましょう。
extern "C" void vsq(int n, double *a, double *b) { int i; for (i=0; i<n; i++) { b[i] = a[i] * a[i]; } } |
ポインタ a および b が異なるオブジェクトをアクセスすることをコンパイラが知っている場合には、ループ内の異なる繰り返しを並列に実行することができます。しかし、ポインタ a および b でアクセスされるオブジェクトが重なりあっていれば、ループを安全に並列実行できなくなります。
コンパイル時に関数 vsq() を単純に解析するだけでは、a および b によるオブジェクトのアクセスが重なりあっているかどうかを知ることはできません。この情報を得るには、プログラム全体を解析することが必要になります。次のコマンド行オプションを使用することにより、ポインタ値の関数パラメータを制限付きポインタとして扱うよう指定できます。-xrestrict[ =func1,…,funcn] 関数リストを指定する場合は、指定した関数内のポインタパラメータは制限付きとして扱われます。それ以外の場合は、ソースファイル全体の中にあるすべてのポインタパラメータが制限つきとして扱われます (推奨しない)。たとえば、-xrestrict=vsq を使用すると、関数 vsq() についての例では、ポインタ a および b が修飾されます。
ポインタ引数を制限付きとして宣言する場合は、ポインタが個別のオブジェクトを指定すると明示することになります。コンパイラは、a および b が個別の記憶領域を指していると想定します。この別名情報によって、コンパイラはループの並列化を実行することができます。
-xrestrict を正しく使用することはとても重要です。区別できないオブジェクトを指しているポインタを制限付きポインタにしてしまうと、ループを正しく並列化できなくなり、不定な動作をすることになります。たとえば、関数 vsq() のポインタ a および b が重なりあっているオブジェクトを指している場合には、b[i] と a[i+1] などが同じオブジェクトである可能性があります。このとき a および b が制限付きポインタとして宣言されていなければ、ループは順次実行されます。a および b が間違って制限付きであると宣言されていれば、コンパイラはループを並列実行するようになりますが、この場合 b[i+1] の結果は b[i] を計算したあとでなければ得られないので、安全に実行することはできません。