GCC: różnica wektoryzacji między dwiema podobnymi pętlami

Podczas kompilacji z gcc -O3, Dlaczego następująca pętla nie wektoryzuje się (automatycznie):

#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];
}

Kiedy następny zrobi?

#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];
}

Jedyną różnicą jest to, czy wynik wyrażenia w pętli wewnętrznej jest przypisany do [i], czy dodany do [i] .

Dla odniesienia -ftree-vectorizer-verbose=6 daje następujące wyjście dla pierwszej (Nie-wektoryzującej) pętli.

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.

I to samo wyjście dla wektoryzowanej pętli to:

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.
Author: Mysticial, 2012-08-23

4 answers

W pierwszym przypadku: kod nadpisuje tę samą lokalizację pamięci a[i] w każdej iteracji. To z natury sekwencjalizuje pętlę, ponieważ iteracje pętli nie są niezależne.
(W rzeczywistości potrzebna jest tylko ostateczna iteracja. Więc cała wewnętrzna pętla może zostać wyjęta.)

W drugim przypadku: GCC rozpoznaje pętlę jako operację redukcji - dla której ma specjalną obsługę przypadków do wektoryzowania.

Wektoryzacja kompilatora jest często implementowana jako jakiś rodzaj "dopasowania wzorców". Oznacza to, że kompilator analizuje kod, aby sprawdzić, czy pasuje do określonego wzorca, który jest w stanie wektoryzować. Jeśli tak, to zostanie wektoryzowany. Jeśli nie, to nie.

To wygląda na przypadek narożny, w którym pierwsza pętla nie pasuje do żadnego z wstępnie zakodowanych wzorców, które GCC może obsłużyć. Ale drugi przypadek pasuje do wzoru "redukcji wektorowej".


Oto odpowiednia część kodu źródłowego GCC, która wypluwa to "not vectorized: live stmt not supported: " wiadomość:

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;
    }
}

From just the line:

vectorizable_reduction (stmt, NULL, NULL);

Jest jasne, że GCC sprawdza, czy pasuje do wzoru redukcji wektorowej.

 30
Author: Mysticial,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-23 18:11:27

Wektoryzator GCC prawdopodobnie nie jest wystarczająco inteligentny, aby wektoryzować pierwszą pętlę. Przypadek dodawania jest łatwiejszy do wektoryzacji, ponieważ a + 0 == a. Rozważmy SIZE==4:

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

X oznacza kombinacje i i j, Gdy a zostanie przypisana lub zwiększona. W przypadku dodawania możemy obliczyć wyniki b[i] > c[j] ? b[i] : c[j] dla, powiedzmy, j==1 i i==0..4 i umieścić je w wektorze D. Następnie wystarczy zerować D[2..3] i dodać wektor wynikowy do a[0..3]. W przypadku zadania jest to trochę trudniejsze. Musimy nie tylko zero D[2..3], ale także zero A[0..1] i dopiero wtedy połączyć wyniki. Chyba tutaj zawodzi wektoryzator.

 3
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-23 17:39:18

Pierwsza pętla jest równoważna

#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];
}

Problem z oryginalnym wyrażeniem jest taki, że naprawdę nie ma to większego sensu, więc nie jest to zbyt zaskakujące, że gcc nie jest w stanie go wektoryzować.

 3
Author: ecatmur,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-23 18:24:57

Pierwszy po prostu trywialnie zmienia a [] wiele razy (tymczasowe). Drugi używa za każdym razem ostatniej wartości [] (nie tymczasowej).

Do wersji patcha można było użyć zmiennej "volatile" do wektoryzacji.

Użyj

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

To make it aligned;

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

Pokazuje "c" O innym obszarze przechowywania niż b I a.

W przeciwieństwie do SSE-AVX-a, w przypadku SSE-AVX-a, w przypadku SSE-AVX-a, SSE-AVX-a, SSE-AVX-a, SSE-AVX-a, SSE-AVX-a, SSE-AVX-a]}

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

6. i 7. przykłady pokazują podobne trudności.
 1
Author: huseyin tugrul buyukisik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-23 18:15:37