Laut Intels Software Developer Manual (s. 14.9) lockerte AVX die Ausrichtungsanforderungen von Speicherzugriffen. Wenn Daten direkt in eine Verarbeitungsanweisung geladen werden, z.B.
%Vor%Die Ladeadresse muss nicht ausgerichtet werden. Wenn jedoch ein dedizierter ausgerichteter Ladebefehl verwendet wird, z. B.
%Vor%Die Ladeadresse muss ausgerichtet werden (zu Vielfachen von 32), sonst wird eine Ausnahme ausgelöst.
Was mich verwirrt, ist die automatische Codegenerierung aus Intrinsics, in meinem Fall durch gcc / g ++ (4.6.3, Linux). Bitte sehen Sie sich folgenden Testcode an:
%Vor%(Ja, ich weiß, dass der Code fehlerhaft ist, da ich eine ausgerichtete Last für nicht ausgerichtete Adressen verwende, aber bitte ...)
Ich kompiliere den Code mit
%Vor%auf einer CPU mit AVX. Wenn ich den von g ++ generierten Code mit
überprüfe %Vor%Ich sehe, dass der Compiler keine ausgerichtete Ladeanweisung generiert, sondern die Daten direkt in die Vektoradditionsanweisung lädt:
%Vor%Der Code wird ohne Probleme ausgeführt, obwohl die Speicheradressen nicht ausgerichtet sind (OFFSET ist 1). Dies ist klar, da vaddps nicht ausgerichtete Adressen toleriert.
Wenn ich die Zeile mit der zweiten intrinsischen Addition auskommentiere, kann der Compiler die Ladung und die Addition nicht fusionieren, da vaddps nur einen einzigen Speicherquelloperanden haben kann und folgendes erzeugt:
%Vor%Und jetzt die Programm-Seg-Fehler, da ein dedizierter ausgerichteter Ladebefehl verwendet wird, aber die Speicheradresse nicht ausgerichtet ist. (Das Programm segmentiert nicht, wenn ich _mm256_loadu_ps verwende oder wenn ich OFFSET auf 0 setze.)
Dies lässt den Programmierer dem Compiler ausgeliefert und macht das Verhalten meiner Meinung nach unberechenbar.
Meine Frage ist: Gibt es eine Möglichkeit, den C-Compiler zu zwingen, entweder eine direkte Ladung in einer Verarbeitungsanweisung (wie vaddps) zu generieren oder eine dedizierte Ladeanweisung (wie vmovaps) zu generieren?
Es gibt keine Möglichkeit, die Faltung von Lasten mit intrinsischen Eigenschaften explizit zu steuern. Ich halte dies für eine Schwäche der Eigenarten. Wenn Sie die Faltung explizit steuern möchten, müssen Sie Assembly verwenden.
In der vorherigen Version von GCC war ich in der Lage, die Faltung zu einem gewissen Grad unter Verwendung einer ausgerichteten oder nicht ausgerichteten Belastung zu steuern. Dies scheint jedoch nicht mehr der Fall zu sein (GCC 4.9.2). Ich meine zum Beispiel in der Funktion AddDot4x4_vec_block_8wide
hier werden die Lasten gefaltet
Allerdings in einer früheren Version von GCC wurden die Lasten nicht gefaltet:
%Vor%Die richtige Lösung ist natürlich, nur ausgerichtete Lasten zu verwenden, wenn Sie wissen, dass die Daten ausgerichtet sind, und wenn Sie die zusammenfaltbare Baugruppe wirklich explizit steuern möchten.
Zusätzlich zu der Antwort von Z boson kann ich sagen, dass der Compiler zu Recht die Ladefaltung durchführt, weil er annimmt, dass die Speicherregion ausgerichtet ist (wegen __attribute__ ((aligned(32)))
, das das Array markiert). In der Laufzeit funktioniert dieses Attribut jedoch nicht für Werte im Stapel, da der Stapel nur 16 Byte ausgerichtet ist (siehe dieser Fehler). Sie können versuchen, den Compiler dazu zu bringen, den Stack beim Eintrag in main
auf 32 Byte neu auszurichten, indem Sie -mstackrealign
und -mpreferred-stack-boundary=5
angeben (siehe hier ), aber es wird einen Leistungsaufwand verursachen.