Mam bardzo długie tablice bajtów, które należy dodać do tablicy docelowej typu short
(lub int
). Czy istnieje taka instrukcja SSE? A może ich zestaw?Instrukcje SSE: Bajt + krótki
Odpowiedz
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);
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.
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
@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. –
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