34

でコンパイルするとgcc -O3、次のループが (自動的に) ベクトル化されないのはなぜですか?

#define SIZE (65536)

int a[SIZE], b[SIZE], c[SIZE];

int foo () {
  int i, j;

  for (i=0; i<SIZE; i++){
    for (j=i; j<SIZE; j++) {
      a[i] = b[i] > c[j] ? b[i] : c[j];
    }
  }
  return a[0];
}

次のものはいつですか?

#define SIZE (65536)

int a[SIZE], b[SIZE], c[SIZE];

int foov () {
  int i, j;

  for (i=0; i<SIZE; i++){
    for (j=i; j<SIZE; j++) {
      a[i] += b[i] > c[j] ? b[i] : c[j];
    }
  }
  return a[0];
}

唯一の違いは、内側のループの式の結果がa[i] に割り当てられるか、a[i] に追加されるかです。

参考-ftree-vectorizer-verbose=6までに、最初の (ベクトル化されていない) ループの次の出力を示します。

v.c:8: note: not vectorized: inner-loop count not invariant.
v.c:9: note: Unknown alignment for access: c
v.c:9: note: Alignment of access forced using peeling.
v.c:9: note: not vectorized: live stmt not supported: D.2700_5 = c[j_20];

v.c:5: note: vectorized 0 loops in function.

ベクトル化するループの同じ出力は次のとおりです。

v.c:8: note: not vectorized: inner-loop count not invariant.
v.c:9: note: Unknown alignment for access: c
v.c:9: note: Alignment of access forced using peeling.
v.c:9: note: vect_model_load_cost: aligned.
v.c:9: note: vect_model_load_cost: inside_cost = 1, outside_cost = 0 .
v.c:9: note: vect_model_simple_cost: inside_cost = 1, outside_cost = 1 .
v.c:9: note: vect_model_reduction_cost: inside_cost = 1, outside_cost = 6 .
v.c:9: note: cost model: prologue peel iters set to vf/2.
v.c:9: note: cost model: epilogue peel iters set to vf/2 because peeling for alignment is unknown .
v.c:9: note: Cost model analysis:
  Vector inside of loop cost: 3
  Vector outside of loop cost: 27
  Scalar iteration cost: 3
  Scalar outside cost: 7
  prologue iterations: 2
  epilogue iterations: 2
  Calculated minimum iters for profitability: 8

v.c:9: note:   Profitability threshold = 7

v.c:9: note: Profitability threshold is 7 loop iterations.
v.c:9: note: LOOP VECTORIZED.
v.c:5: note: vectorized 1 loops in function.
4

4 に答える 4

31

最初のケースa[i]: コードは各反復で同じメモリ位置を上書きします。ループの反復は独立していないため、これは本質的にループを順次化します。
(実際には、最後の反復のみが実際に必要です。そのため、内側のループ全体を取り出すことができます。)

2 番目のケース: GCC はループをリダクション操作として認識します。これには、ベクトル化する特別なケースの処理があります。

コンパイラのベクトル化は、多くの場合、ある種の「パターン マッチング」として実装されます。つまり、コンパイラーはコードを分析して、ベクトル化できる特定のパターンに適合するかどうかを確認します。その場合、ベクトル化されます。そうでない場合は、そうではありません。

これは、最初のループが、GCC が処理できる事前にコード化されたパターンのいずれにも適合しない、まれなケースのようです。しかし、2 番目のケースは「ベクトル化可能なリダクション」パターンに適合します。


"not vectorized: live stmt not supported: "そのメッセージを吐き出すGCCのソースコードの関連部分は次のとおりです。

http://svn.open64.net/svnroot/open64/trunk/osprey-gcc-4.2.0/gcc/tree-vect-analyze.c

if (STMT_VINFO_LIVE_P (stmt_info))
{
    ok = vectorizable_reduction (stmt, NULL, NULL);

    if (ok)
        need_to_vectorize = true;
    else
        ok = vectorizable_live_operation (stmt, NULL, NULL);

    if (!ok)
    {
        if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
        {
            fprintf (vect_dump, 
                "not vectorized: live stmt not supported: ");
            print_generic_expr (vect_dump, stmt, TDF_SLIM);
        }
        return false;
    }
}

ちょうど行から:

vectorizable_reduction (stmt, NULL, NULL);

GCC が「ベクトル化可能なリダクション」パターンに一致するかどうかを確認していることは明らかです。

于 2012-08-23T17:42:37.477 に答える
4

GCCベクトライザーは、おそらく最初のループをベクトル化するほど賢くはありません。加算の場合は、ベクトル化が容易ですa + 0 == a。考えてみてくださいSIZE==4

  0 1 2 3 i
0 X
1 X X
2 X X X
3 X X X X
j

Xとの組み合わせが割り当てられるかijいつ増加するかを示します。加算の場合、たとえばa、の結果を計算し、それをベクトルに入れることができます。次に、ゼロにして結果のベクトルをに追加するだけです。割り当ての場合、もう少し注意が必要です。ゼロだけでなく、ゼロにして、結果を組み合わせる必要があります。これがベクトライザーが失敗しているところだと思います。b[i] > c[j] ? b[i] : c[j]j==1i==0..4DD[2..3]a[0..3]D[2..3]A[0..1]

于 2012-08-23T17:29:24.327 に答える
4

最初のループは

#define SIZE (65536)

int a[SIZE], b[SIZE], c[SIZE];

int foo () {
  int i, j;

  for (i=0; i<SIZE; i++){
    a[i] = b[i] > c[SIZE - 1] ? b[i] : c[SIZE - 1];
  }
  return a[0];
}

元の式の問題は、実際にはそれほど意味がないことです。したがって、gccがそれをベクトル化できないことはそれほど驚くことではありません。

于 2012-08-23T18:24:57.153 に答える
1

最初の 1 つは、[] を何度も (一時的に) 単純に変更するだけです。2 つ目は、毎回 a[] の最後の値を使用します (一時的ではありません)。

パッチのバージョンまでは、「volatile」変数を使用してベクトル化できました。

使用する

int * c=malloc(sizeof(int));

それを揃えるために;

v.c:9: note: Unknown alignment for access: c

b および a とは異なるストレージ領域を持つ "c" を示します。

「ベクトル化」されるための「movaps」のような命令を想定しています (SSE-AVX 命令リストから)

ここ: http://gcc.gnu.org/projects/tree-ssa/vectorization.html#using

6 番目と 7 番目の例は、同様の問題を示しています。

于 2012-08-23T17:12:17.423 に答える