Maximalwert in einem __m128i-Vektor mit SSE erhalten?
Lesezeit: 4 Minuten
Shane
Ich habe gerade angefangen, SSE zu verwenden, und bin verwirrt, wie ich den maximalen ganzzahligen Wert (max) von a __m128i. Zum Beispiel:
__m128i t = _mm_setr_ps(0,1,2,3);
// max
Herumsuchen führte mich zu MAXPS Anleitung, aber ich kann nicht finden, wie man das mit verwendet "xmmintrin.h".
Gibt es auch eine Dokumentation für "xmmintrin.h" die Sie empfehlen würden, anstatt in die Header-Datei selbst zu schauen?
Die Mischvorgänge, die Sie benötigen, sind die gleichen wie für eine horizontale Summe oder so ziemlich jede andere horizontale Reduktion. Unter stackoverflow.com/questions/6996764/… finden Sie einige optimierte Versionen für Float, Integer und Double mit SSE2, SSE3 und AVX. Auch Diskussion darüber, welche Shuffles auf welchen CPUs optimal sind.
– Peter Cordes
9. September 2017 um 2:36 Uhr
Diese Frage scheint in Bezug auf Float vs. Integer verwirrt zu sein. __m128i ist ein ganzzahliger Vektor. *_ps Und MAXPS sind Einzelschwimmer verpackt. Informationen zur Dokumentation finden Sie im SSE-Tag-Wiki für Links und viele weitere Links unter stackoverflow.com/tags/x86/info. Eine sehr gute Ressource ist Intels Intrinsic Search/Finder die Details darüber enthält, was jeder tut, aber nicht so detailliert wie in der asm-Bedienungsanleitung.
– Peter Cordes
9. September 2017 um 2:39 Uhr
Falls es jemanden interessiert und da Intrinsic heutzutage der richtige Weg zu sein scheint, hier eine Lösung in Bezug auf Intrinsic.
int horizontal_max_Vec4i(__m128i x) {
int result[4] __attribute__((aligned(16))) = {0};
_mm_store_si128((__m128i *) result, x);
return max(max(max(result[0], result[1]), result[2]), result[3]);
}
Paul R
Wenn Sie horizontale Operationen an Vektoren durchführen müssen, insbesondere wenn es sich innerhalb einer inneren Schleife befindet, dann ist es so normalerweise ein Zeichen dafür, dass Sie Ihre SIMD-Implementierung falsch angehen. SIMD operiert gerne elementweise auf Vektoren – “vertikal” wenn man so will, nicht horizontal.
Was die Dokumentation betrifft, so gibt es a sehr nützliche Referenz auf intel.com das alle Opcodes und Intrinsics für alles von MMX über die verschiedenen Varianten von SSE bis hin zu AVX und AVX-512 enthält.
Vielen Dank für den Link. Der horizontale Teil ist nur für eine Schleifenbedingung, aber ich werde meinen Ansatz überarbeiten
@MarkLakata: Danke – Antwort aktualisiert – Ich vermisse den alten Offline-Leitfaden – Neben der Arbeit ohne Internetverbindung war es auch nützlich, dass Sie die Daten für andere Zwecke kratzen konnten. Aber egal – die neue Online-Version ist immer noch gut.
– PaulR
5. Dezember 2014 um 7:28 Uhr
Jens Björnhager
Entsprechend diese Seitegibt es kein horizontales Maximum, und Sie müssen die Elemente vertikal testen:
movhlps xmm1,xmm0 ; Move top two floats to lower part of xmm1
maxps xmm0,xmm1 ; Get the maximum of the two sets of floats
pshufd xmm1,xmm0,$55 ; Move second float to lower part of xmm1
maxps xmm0,xmm1 ; Get the maximum of the two remaining floats
pshufd zwischen maxps Anweisungen haben auf vielen CPUs (einschließlich Intel) eine zusätzliche Latenz. SSE3 movshdup dupliziert den oberen Float in jeder Hälfte des Registers, sodass Sie ihn verwenden können, um eine Movaps-Kopie zu vermeiden.
– Peter Cordes
9. September 2017 um 1:54 Uhr
@PeterCordes, könnten Sie Ihre eigene optimierte Lösung schreiben? Wäre es anders, wenn es ein Float-Vektor wäre? Danke schön.
– Royi
10. Oktober 2017 um 23:05 Uhr
@ Royi: diese Antwort Ist für einen Vektor von float (da die Frage falsch betitelt oder in Bezug auf Float vs. Integer verwechselt ist, siehe meine Kommentare zur Frage). Optimiert für welche Mikroarchitektur(en) und mit welchem SSE-Level? SSE3? Oder auf SSE2 beschränkt? Oder AVX2? Siehe stackoverflow.com/questions/6996764/… (aber ersetzen add mit max) für verschiedene optimierte Float- und Integer-Shuffles.
– Peter Cordes
10. Oktober 2017 um 23:18 Uhr
Sagen wir SSE4. Optimiert für Haswell und höher. Danke schön. PS Ich meinte die Verwendung von SSE Intrinsics, ist das nicht die obige Assembly?
– Royi
10. Oktober 2017 um 23:48 Uhr
@PeterCordes, ich habe es so verwendet, wie es hier gezeigt werden kann – codereview.stackexchange.com/questions/177658. Ist es das, was du meintest? Irgendeine Idee, warum es immer noch so langsam ist?
– Royi
11. Oktober 2017 um 0:58 Uhr
Es gibt keinen horizontalen maximalen Opcode in SSE (zumindest bis zu dem Punkt, an dem ich aufgehört habe, neue SSE-Anweisungen zu verfolgen).
Sie stecken also fest, indem Sie etwas mischen. Was Sie am Ende haben, ist …
movhlps %xmm0, %xmm1 # Move top two floats to lower part of %xmm1
maxps %xmm1, %xmm0 # Get minimum of sets of two floats
pshufd $0x55, %xmm0, %xmm1 # Move second float to lower part of %xmm1
maxps %xmm1, %xmm0 # Get minimum of all four floats originally in %xmm0
Die Mischvorgänge, die Sie benötigen, sind die gleichen wie für eine horizontale Summe oder so ziemlich jede andere horizontale Reduktion. Unter stackoverflow.com/questions/6996764/… finden Sie einige optimierte Versionen für Float, Integer und Double mit SSE2, SSE3 und AVX. Auch Diskussion darüber, welche Shuffles auf welchen CPUs optimal sind.
– Peter Cordes
9. September 2017 um 2:36 Uhr
Diese Frage scheint in Bezug auf Float vs. Integer verwirrt zu sein.
__m128i
ist ein ganzzahliger Vektor.*_ps
UndMAXPS
sind Einzelschwimmer verpackt. Informationen zur Dokumentation finden Sie im SSE-Tag-Wiki für Links und viele weitere Links unter stackoverflow.com/tags/x86/info. Eine sehr gute Ressource ist Intels Intrinsic Search/Finder die Details darüber enthält, was jeder tut, aber nicht so detailliert wie in der asm-Bedienungsanleitung.– Peter Cordes
9. September 2017 um 2:39 Uhr