3.15 ポインタを含むループのベクトル化

配列にアクセスする際、多くの場合は、メモリアクセスがオーバーラップしないことをコンパイラ側で検証できます。しかし、ポインタを使用すると、この可能性は低下し、ランタイムテストを実行するか、 restrict キーワードを使用する必要が生じます。

コンパイラは、ループが安全であると判断できる場合はポインタを含んでいるループをベクトル化できます。ループ内の配列参照およびポインタ参照は、メモリへのベクタアクセスがあるかどうかを判断するために解析されます。場合によっては、コンパイラはランタイムテストを作成し、テストの結果によってループのベクタバージョンかスカラバージョンを実行します。
関数の引数はポインタとして渡される場合があります。複数のポインタ変数を関数に渡す場合は、メモリのオーバーラップしているセクションをポイントすることが可能です。実行時にこのようになることはほとんどありませんが、コンパイラは常に安全な方法に従い、代入演算子の左辺および右辺にポインタがあるループの最適化は回避します。例えば、以下の関数を考えてみます。
void func (int *pa, int *pb, int x)
{
    int i;
    for (i = 0; i < 100; i++)
    {
       *(pa + i) = *(pb + i) + x;
    }
};
この例では、1 つのループパスの結果によって次のループパスにフィードバックされるようにメモリ内で papb がオーバーラップしていると、ループのベクトル化によって不正な結果が得られることがあります。以下の引数で関数が呼び出された場合は、ベクトル化はあいまいなものになります。
int *a;
        
func (a, a-1);
コンパイラはランタイムテストを実行して、ポインタのエイリアスの生成が行われるかどうかを調べます。ポインタのエイリアス生成が発生しない場合は、コードのベクトル化バージョンを実行します。ポインタのエイリアス生成が発生する場合は、元のベクトル化されていないコードが代わりに実行されます。これによって、ランタイムの効率が良くなりコードサイズが小さくなります。
実際には、関数の引数によってデータの依存関係が生じることはほとんどありません。ベクトル化の問題は別にして、オーバーラップしたポインタを渡すプログラムは理解とデバッグが困難です。
上述の例では、 restrict pa に追加するだけで、ランタイムテストを回避できます。
関連する概念
3.17 条件付き終了の非ベクトル化
3.16 ポインタおよび間接アドレス指定を含むループの非ベクトル化
3.14 ベクタのスカラへの縮退
3.13 キャリーアラウンドスカラ変数とベクトル化
3.12 コードをベクトル化するときのデータの依存関係による競合
3.9 NEON ベクトル化によるパフォーマンスに影響を与える要因
関連する参考文書
3.11 ベクトル化のために推奨されるループ構造
3.10 NEON ベクトル化によるパフォーマンスの目標
8.192 --vectorize、--no_vectorize
8.164 --restrict、--no_restrict
9.13 restrict
非機密扱いPDF file icon PDF 版ARM DUI0472LJ
Copyright © 2010-2015 ARM.All rights reserved.