2011-11-27 26 views
7

Moja początkowa próba wyglądało to (niby chcemy mnożyć)Jak wykonać operację macierzy 8 x 8 przy użyciu SSE?

__m128 mat[n]; /* rows */ 
    __m128 vec[n] = {1,1,1,1}; 
    float outvector[n]; 
    for (int row=0;row<n;row++) { 
     for(int k =3; k < 8; k = k+ 4) 
     { 
      __m128 mrow = mat[k]; 
      __m128 v = vec[row]; 
      __m128 sum = _mm_mul_ps(mrow,v); 
      sum= _mm_hadd_ps(sum,sum); /* adds adjacent-two floats */ 
     } 
      _mm_store_ss(&outvector[row],_mm_hadd_ps(sum,sum)); 
} 

Ale to wyraźnie nie działa. Jak mam się do tego podejść?

mam obciążenia 4 na raz ....

Inne pytanie brzmi: jeśli tablica jest bardzo duża (powiedzmy n = 1000), w jaki sposób mogę to zrobić 16 bajtów wyrównane? Czy to w ogóle jest możliwe?

+0

Jakiego wyniku oczekujesz? Nie widzę żadnej matrycy, tylko mnożenie wektorowe. Poza tym skąd pochodzą 3, 8 i 4? – pezcode

+0

@ user963889, wymiary nie mają żadnego sensu. Co próbujesz zrobić? Pomnożyć wektor 8x1 lub tablicę wektorów za pomocą macierzy 8x8? –

+0

@BrettHale Załóżmy, że mamy 8x8 wielokrotności wektora 8x1. W rezultacie chcę uzyskać 8x1. Utknąłem. Czy możecie mnie poprowadzić we właściwym kierunku? Dzięki. – user1012451

Odpowiedz

4

OK ... Posłużę się konwencją matrix-major matrix. Każdy wiersz [m] wymaga (2) __m128 elementów, aby uzyskać 8 elementów pływających. Wektor 8x1 v jest wektorem kolumnowym. Ponieważ używasz instrukcji haddps, zakładam, że SSE3 jest dostępny. Znalezienie r = [m] * v:

void mul (__m128 r[2], const __m128 m[8][2], const __m128 v[2]) 
{ 
    __m128 t0, t1, t2, t3, r0, r1, r2, r3; 

    t0 = _mm_mul_ps(m[0][0], v[0]); 
    t1 = _mm_mul_ps(m[1][0], v[0]); 
    t2 = _mm_mul_ps(m[2][0], v[0]); 
    t3 = _mm_mul_ps(m[3][0], v[0]); 

    t0 = _mm_hadd_ps(t0, t1); 
    t2 = _mm_hadd_ps(t2, t3); 
    r0 = _mm_hadd_ps(t0, t2); 

    t0 = _mm_mul_ps(m[0][1], v[1]); 
    t1 = _mm_mul_ps(m[1][1], v[1]); 
    t2 = _mm_mul_ps(m[2][1], v[1]); 
    t3 = _mm_mul_ps(m[3][1], v[1]); 

    t0 = _mm_hadd_ps(t0, t1); 
    t2 = _mm_hadd_ps(t2, t3); 
    r1 = _mm_hadd_ps(t0, t2); 

    t0 = _mm_mul_ps(m[4][0], v[0]); 
    t1 = _mm_mul_ps(m[5][0], v[0]); 
    t2 = _mm_mul_ps(m[6][0], v[0]); 
    t3 = _mm_mul_ps(m[7][0], v[0]); 

    t0 = _mm_hadd_ps(t0, t1); 
    t2 = _mm_hadd_ps(t2, t3); 
    r2 = _mm_hadd_ps(t0, t2); 

    t0 = _mm_mul_ps(m[4][1], v[1]); 
    t1 = _mm_mul_ps(m[5][1], v[1]); 
    t2 = _mm_mul_ps(m[6][1], v[1]); 
    t3 = _mm_mul_ps(m[7][1], v[1]); 

    t0 = _mm_hadd_ps(t0, t1); 
    t2 = _mm_hadd_ps(t2, t3); 
    r3 = _mm_hadd_ps(t0, t2); 

    r[0] = _mm_add_ps(r0, r1); 
    r[1] = _mm_add_ps(r2, r3); 
} 

Co do wyrównania, zmienna typu __m128 powinny być automatycznie ustawione na stosie. W przypadku pamięci dynamicznej nie jest to bezpieczne założenie. Niektóre implementacje malloc/new mogą zwracać tylko gwarantowaną pamięć wyrównaną do 8 bajtów.

Nagłówek wewnętrzny zawiera _mm_malloc i _mm_free. Parametr wyrównania powinien w tym przypadku wynosić (16).

+0

Dzięki. Mój kod wygląda teraz podobnie do twojego po dwóch dniach pracy ... ale twoje jest dużo jasne. Nauczyłem się. Dzięki. – user1012451

Powiązane problemy