Wie man den Compiler anweist, nicht ausgerichtete Lasten für __m128 zu generieren

9

Ich habe Code, der mit __m128 -Werten funktioniert. Ich verwende x86-64 SSE intrinsics auf diesen Werten und ich finde, dass wenn die Werte im Speicher nicht ausgerichtet sind, bekomme ich einen Absturz. Dies liegt an meinem Compiler (in diesem Fall clang), der nur ausgerichtete Ladeanweisungen generiert.

Kann ich meinen Compiler anweisen, stattdessen nicht ausgerichtete Lasten zu generieren, entweder global oder für bestimmte Werte (vielleicht mit einer Art Annotation)?

Der Grund, warum ich zuerst Werte nicht ausgerichtet habe, ist, dass ich versuche, Speicher zu sparen. Ich habe ein struct ungefähr wie folgt:

%Vor%

Ich erstelle dann ein Array dieser Strukturen. Das zweite Element im Array beginnt bei 36 Bytes, was kein Vielfaches von 16 ist.

Ich weiß, ich könnte zu einer Struktur der Array-Darstellung wechseln oder das Packing-Pragma entfernen (auf Kosten der Größe der Struktur von 36 auf 48 Byte); aber ich weiß auch, dass unausgerichtete Lasten heutzutage nicht so teuer sind und das zuerst ausprobieren möchten.

Aktualisieren, um einige der folgenden Kommentare zu beantworten:

Mein tatsächlicher Code war näher dran:

%Vor%

Ich habe dann einige nützliche Funktionen wie:

%Vor%

Ich benutze diese Dienstprogramme oft in Kombination. Falsches Beispiel:

%Vor%

Wenn ich mir die Antwort von "Z Bozon" anschaue, hat sich mein Code effektiv in Folgendes verwandelt:

%Vor%

Meine Sorge war, dass, wenn die Dienstprogrammfunktionen in Kombination wie oben verwendet wurden, der generierte Code möglicherweise redundante Lade- / Speicherbefehle hat. Es stellte sich heraus, dass dies kein Problem war. Ich testete meinen Compiler (clang) und hatte alle entfernt. Ich werde Z Bozon's Antwort akzeptieren.

    
pauldoo 24.11.2015, 09:04
quelle

3 Antworten

3

Meiner Meinung nach sollten Sie Ihre Datenstrukturen mit Standard-C ++ - Konstruktionen schreiben (von denen __m128i nicht ist). Wenn Sie intrinsics verwenden möchten, die nicht Standard C ++ sind, "betreten Sie SSE world" über intrinsics wie _mm_loadu_ps und Sie "verlassen SSE world" zurück zu Standard C ++ mit einem intrinsischen wie _mm_storeu_ps . Verlassen Sie sich nicht auf implizite SSE-Lade- und Speichervorgänge. Ich habe zu viele Fehler bei SO dabei gesehen.

In diesem Fall sollten Sie

verwenden %Vor%

dann können Sie

tun %Vor%

In diesem Fall ist foo[1] nicht 16 Byte ausgerichtet, aber wenn Sie SSE verwenden und Standard C ++ verlassen wollen, tun Sie

%Vor%

gehe dann zurück zum Standard C ++.

Eine andere Sache, die Sie in Betracht ziehen können, ist dies

%Vor%

dann, um ein Array von 16 der ursprünglichen Struktur do

zu erhalten %Vor%

In diesem Fall ist das erste Element so ausgerichtet, wie alle anderen Elemente.

Wenn Sie Utility-Funktionen verwenden wollen, die auf SSE-Register wirken, dann verwenden Sie keine expliziten oder impliziten Load / Stores in der Utility-Funktion. Übergeben Sie Const-Referenzen an __m128 und geben Sie __m128 zurück, wenn Sie dies möchten.

%Vor%

Der Grund für die Verwendung einer const-Referenz ist, dass MSVC __m128 nicht nach Wert übergeben kann. Ohne eine const-Referenz erhalten Sie einen Fehler

  

Fehler C2719: formaler Parameter mit __declspec (align ('16 ')) wird nicht ausgerichtet.

__m128 für MSVC ist sowieso eine Union.

%Vor%

Vermutlich sollte MSVC die Union nicht laden müssen, wenn die SSE-Funktionen inline sind.

Basierend auf dem neuesten Code Update des OPs hier ist, was ich vorschlagen würde

%Vor%

Dieser Code basiert auf Ideen von Agner Fogs Vektorklassenbibliothek .

    
Z boson 25.11.2015, 14:37
quelle
0

Sie könnten versuchen, Ihre Struktur zu ändern:

%Vor%

Das hätte natürlich die gleiche Größe und sollte theoretisch das Klirren erzwingen, um nicht ausgerichtete Lasten / Speicher zu erzeugen.

Alternativ könnten Sie explizit nicht ausgerichtete Lade / Speicher, z. ändern:

%Vor%

zu:

%Vor%     
Paul R 24.11.2015 11:01
quelle
0

Wenn Sie die automatische Vektorisierung oder die explizite OpenMP4 / Cilk / Pragma-gesteuerte Vektorisierung verwenden, können Sie den Compiler zwingen, nicht ausgerichtete Lasten für die vektorisierte Schleife zu verwenden, indem Sie Folgendes verwenden:

%Vor%

Dies soll in erster Linie Kompromisse zwischen "ausgerichtet, aber abgezogen" vs. "nicht abgezogen, aber nicht ausgerichtet" steuern. Weitere Informationen finden Sie unter Ссылка

Dies funktioniert nur für Intel Compiler, soweit ich weiß. Intel Compiler haben auch einen internen Kompilierungsschalter -mP2OPT_vec_alignment = 6, um das gleiche für die gesamte Kompilierungseinheit zu tun.

Ich habe nicht überprüft, ob es effektiv auf Implementierungen angewendet werden kann, bei denen die Kombination von Intrinsic und Assembly zusammen mit OpenMP / Cilk verwendet wird.

    
zam 25.11.2015 13:30
quelle

Tags und Links