Initialisierung eines __m128-Typs von einem 64-Bit-Zeichen ohne Vorzeichen

8

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.

    
Gideon 05.05.2014, 19:25
quelle

3 Antworten

9

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.

%Vor%     
Z boson 06.05.2014, 14:02
quelle
8

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:

%Vor%     
Paul R 05.05.2014 19:27
quelle
4
  

Ich möchte eine Variable vom Typ __m128 ... initialisieren, wobei x vom Typ uint64_t

ist

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.

    
jww 24.07.2016 01:24
quelle

Tags und Links