2012-05-17 32 views

Odpowiedz

6

Musisz rozpakować każdy wektor wartości 8-bitowych do dwóch wektorów wartości 16-bitowych, a następnie dodać je.

__m128i v = _mm_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); 
__m128i vl = _mm_unpacklo_epi8(v, _mm_set1_epi8(0)); // vl = { 7, 6, 5, 4, 3, 2, 1, 0 } 
__m128i vh = _mm_unpackhi_epi8(v, _mm_set1_epi8(0)); // vh = { 15, 14, 13, 12, 11, 10, 9, 8 } 

gdzie v jest wektorem wartości 16 x 8 bitów i vl, vh są dwa rozpakowanych wektory wartości 8 x 16 bitów.

Zauważ, że zakładam, że wartości 8-bitowe są niepodpisane, więc przy rozpakowywaniu do 16 bitów, wysoki bajt jest ustawiony na 0 (tj. Bez rozszerzenia znaku).

Jeśli chcesz zsumować wiele z tych wektorów i uzyskać 32-bitowy wynik, użytecznie jest użyć _mm_madd_epi16 z mnożnikiem 1, np.

__m128i vsuml = _mm_set1_epi32(0); 
__m128i vsumh = _mm_set1_epi32(0); 
__m128i vsum; 
int sum; 

for (int i = 0; i < N; i += 16) 
{ 
    __m128i v = _mm_load_si128(&x[i]); 
    __m128i vl = _mm_unpacklo_epi8(v, _mm_set1_epi8(0)); 
    __m128i vh = _mm_unpackhi_epi8(v, _mm_set1_epi8(0)); 
    vsuml = _mm_add_epi32(vsuml, _mm_madd_epi16(vl, _mm_set1_epi16(1))); 
    vsumh = _mm_add_epi32(vsumh, _mm_madd_epi16(vh, _mm_set1_epi16(1))); 
} 
// do horizontal sum of 4 partial sums and store in scalar int 
vsum = _mm_add_epi32(vsuml, vsumh); 
vsum = _mm_add_epi32(vsum, _mm_srli_si128(vsum, 8)); 
vsum = _mm_add_epi32(vsum, _mm_srli_si128(vsum, 4)); 
sum = _mm_cvtsi128_si32(vsum); 
+1

Wybacz moją niewiedzę, ale czy jesteś pewien, że to prawda? Ten vsum = _mm_madd_epi16 (vh, _mm_set1_epi16 (1)); usunie poprzednią wartość vsum. – Alexandros

+0

@Alexandros: masz rację, i widzę co najmniej jeszcze jeden błąd - myślę, że musiałem się spieszyć, kiedy napisałem tę odpowiedź - wkrótce poprawię kod, ale podróżuję w obecny. –

+1

Dzięki Paul, nie spiesz się. Bardzo mi pomogłeś w przeszłości, więc jak tylko możesz, napraw to. Miłej podróży!! – Alexandros

0

Jeśli musisz podpisać - rozszerz swoje wektory bajtów zamiast zerowego przedłużenia, użyj pmovsxbw (_mm_cvtepi8_epi16). W przeciwieństwie do rozpakowywania instrukcji hi/lo, możesz tylko pmovsx z niskiego pół/kwartału/ósmego rejestru src.

Możesz pmovsx bezpośrednio z pamięci, mimo że samoistnie sprawiają, że jest to naprawdę niezgrabne. Ponieważ przepustowość losowa jest bardziej ograniczona niż przepustowość na większości procesorów, prawdopodobnie lepiej jest wykonać dwa obciążenia + pmovsx niż zrobić jedno obciążenie + trzy tasowania.