Die _mm_set_epi64
und ähnliche * _epi64-Anweisungen scheinen zu verwenden und hängen von __m64
-Typen ab. Ich möchte eine Variable vom Typ __m128
initialisieren, so dass die oberen 64 Bits 0 sind, und die unteren 64 Bits davon auf x
gesetzt sind, wobei x
vom Typ uint64_t
(oder ähnlich unsigned) ist 64-Bit-Typ). Was ist der "richtige" Weg?
Vorzugsweise sollte dies in einer Compiler-unabhängigen Weise geschehen.
Beantworten Sie Ihre Frage zum Laden eines 64-Bit-Werts in die unteren 64 Bits eines XMM-Registers, während Sie die oberen 64 Bits _mm_loadl_epi64(&x)
wird genau das tun, was Sie möchten .
In Bezug auf to _mm_set_epi64
habe ich einmal gesagt, dass man sich den Quellcode von Agner Fogs Vector Class Library ansehen kann 95% der Frage auf SSE / AVX auf SO. Agner implementiert dies (aus der Datei vectori128.h) für mehrere Compiler und für 64-Bit und 32-Bit. Beachten Sie, dass die Lösung für MSVC 32-Bit-Agner sagt "das ist ineffizient, aber andere Lösungen sind schlechter". Ich denke, das ist was Mysticial mit "Es gibt keinen guten Weg, es zu tun" gemeint ist.
Der gebräuchlichste "Standard", der dafür typisch ist, ist _mm_set_epi64x .
Für Plattformen, denen _mm_set_epi64x
fehlt, können Sie ein Ersatzmakro wie folgt definieren:
Ich möchte eine Variable vom Typ
ist__m128
... initialisieren, wobei x vom Typuint64_t
Der intrinsische Wert, der uint64_t
annimmt, ist _mm_set_epi64x
(im Gegensatz zu _mm_set_epi64
, was ein __m64
erfordert).
Ich bin kürzlich auf Solaris eingegangen. Sun Studio 12.3 und jünger fehlt _mm_set_epi64x
. Es fehlen auch die Work-arounds wie _mm_cvtsi64_si128
und _m_from_int64
.
Hier ist der Hack, den ich benutzt habe, wenn ich interessiert bin. Die andere Möglichkeit war, SSE2 zu deaktivieren, was nicht besonders ansprechend war (und es war 3x langsamer in Benchmarks):
%Vor%Ich glaube, C ++ 11 könnte zusätzliche Dinge tun, um den Compiler und die Performance zu unterstützen, wie ein konstantes Array zu initialisieren:
%Vor% Es gibt einen großen Vorbehalt ... Ich glaube, es gibt ein undefiniertes Verhalten , weil ein Schreibvorgang mit dem v64
-Member von union, und dann wird mit dem v128
Mitglied der Union gelesen. Testen unter SunCC zeigt, dass der Compiler die erwartete (aber technisch inkorrekte) Sache macht.
Ich glaube, Sie können das undefinierte Verhalten mit memcpy
umgehen, aber das könnte die Leistung beeinträchtigen. Siehe auch die Antwort und Diskussion von Peter Cordes unter Wie man zwei __m128i-Variablen in C ++ 03 vertauscht, da es einen undurchsichtigen Typ und ein Array gibt? .
Das Folgende kann auch eine gute Wahl sein, um zu vermeiden, dass das nicht definierte Verhalten das inaktive Union-Mitglied verwendet. Aber ich bin mir nicht sicher über die Punning.
%Vor% BEARBEITEN (drei Monate später): Solaris und SunCC gefielen die Punning nicht. Es erzeugte schlechten Code für uns, und wir mussten memcpy
den Wert in __m128i
angeben. Unix, Linux, Windows, GCC, Clang, ICC, MSC waren alles in Ordnung. Nur SunCC gab uns Ärger.
Tags und Links c++ sse intrinsics