I haben sehr langen Byte-Arrays, die short
(oder int
) zu einer Ziel-Array vom Typ hinzugefügt werden müssen. Gibt es einen solchen SSE-Befehl? Oder vielleicht ihr Set?SSE-Befehle: Byte + Short
Antwort
Sie müssen jeden Vektor der 8-Bit-Werte in zwei Vektoren mit 16-Bit-Werten entpacken und dann hinzufügen.
__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 }
wo v
ist ein Vektor von 16 x 8-Bit-Werte und vl
, sind die beiden vh
entpackten Vektoren von 8 x 16-Bit-Werte.
Beachten Sie, dass ich davon ausgehe, dass die 8-Bit-Werte unsigned sind, so dass beim Entpacken auf 16 Bits das High-Byte auf 0 gesetzt wird (d. H. Keine Vorzeichenerweiterung).
Wenn Sie viele dieser Vektoren summieren und ein 32-Bit-Ergebnis erhalten möchten, dann ist ein nützlicher Trick, _mm_madd_epi16
mit einem Multiplikator von 1, z.
__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);
Wenn Sie Ihre Byte-Vektoren statt auf Vorzeichen erweitern müssen Null erweitern, verwenden pmovsxbw
(_mm_cvtepi8_epi16
). Im Gegensatz zu den Entpackungs-Hi/Lo-Anweisungen können Sie nur pmovsx aus der unteren Hälfte/Viertel/Achtel eines Src-Registers.
Sie können Pmovsx direkt aus dem Speicher obwohl, obwohl intrinsics machen dies wirklich ungeschickt. Da der Shuffle-Durchsatz bei den meisten CPUs begrenzter ist als der Ladedurchsatz, ist es wahrscheinlich vorzuziehen, zwei Lade- und Pmovsx-Vorgänge durchzuführen, als einen Ladevorgang und drei Shuffle-Vorgänge durchzuführen.
Verzeihen Sie meine Ignoranz aber sind Sie sicher, dass das richtig ist? Dies ist vsum = _mm_madd_epi16 (vh, _mm_set1_epi16 (1)); würde den vorherigen Wert von vsum löschen. – Alexandros
@Alexandros: Du hast Recht, und ich sehe mindestens einen weiteren Fehler drin - ich denke, ich muss es eilig gehabt haben, als ich diese Antwort geschrieben habe - ich werde den Code bald reparieren, aber ich reise weiter Geschenk. –
Danke Paul, keine Eile. Sie haben mir in der Vergangenheit sehr geholfen, also reparieren Sie es, wann immer Sie können. Gute Reise!! – Alexandros