programing

GCC: 유사한 두 루프 사이의 벡터화 차이

stoneblock 2023. 9. 21. 20:02

GCC: 유사한 두 루프 사이의 벡터화 차이

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는 첫 번째(비 vector라이징) 루프에 대해 다음과 같은 출력을 제공합니다.

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.

번째 경우: 코드가 동일한 메모리 위치를 덮어씁니다.a[i]한번씩 반복해서 않기 에 본질적으로 합니다.이는 루프 반복이 독립적이지 않기 때문에 본질적으로 루프를 순차화합니다.
(실제로는 최종 반복만 필요합니다.따라서 내부 루프 전체를 제거할 수 있습니다.)

두 번째 경우: GCC는 루프를 축소 연산으로 인식합니다. 이를 위해 벡터화할 수 있는 특수한 경우 처리가 있습니다.

컴파일러 벡터화는 종종 일종의 "패턴 매칭"으로 구현됩니다.컴파일러는 코드가 벡터화할 수 있는 특정 패턴에 맞는지 확인하기 위해 코드를 분석합니다.만약 그렇게 된다면, 벡터화 됩니다.그렇지 않으면 그렇지 않습니다.

이것은 첫 번째 루프가 GCC가 처리할 수 있는 미리 코딩된 패턴에 맞지 않는 코너 케이스인 것 같습니다.그러나 두 번째 경우는 "벡터화 가능한 감소" 패턴에 적합합니다.


은 의입니다 GCC "not vectorized: live stmt not supported: "메시지:

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가 "벡터화 가능한 감소" 패턴과 일치하는지 확인 중인 것은 분명합니다.

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는다의 .i그리고.ja에 할당되거나 증가됩니다.우,다의 결과를 할 수 .b[i] > c[j] ? b[i] : c[j]예를 면 j==1그리고.i==0..4 겁니다.D 0. 0 만 됩니다.D[2..3]합니다.a[0..3] 과제의 경우에는 조금 더 까다롭습니다.다 0는 안 됩니다.D[2..3] 0, 0A[0..1]그 다음에야 결과를 합칠 수 있습니다.여기서 벡터라이저가 고장난 것 같습니다.

첫번째 루프는 다음과 같습니다.

#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가 벡터화하지 못하는 것이 그리 놀랍지 않습니다.

첫번째 것은 그저 a[]를 여러번 바꾸는 것입니다.두 번째 값은 매번 a[]의 마지막 값을 사용합니다(일시적이 아님).

패치 버전까지 "volatile" 변수를 사용하여 벡터화할 수 있습니다.

사용하다

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

정렬되도록 하기 위해,

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

band a와는 다른 저장 영역을 가진 "c"를 보여줍니다.

나는 "벡터화"된 "모브랩스"와 같은 명령을 가정합니다 (SSE-AVX 명령 목록에서).

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

6번째와 7번째 예시는 비슷한 어려움을 보여줍니다.

언급URL : https://stackoverflow.com/questions/12096599/gcc-vectorization-difference-between-two-similar-loops