2016-05-31 10 views
1

Ich kompiliere den gleichen Benchmark mit gcc -O2 -march = native Flags. Interessant ist jedoch, wenn ich den objdump ansehe, er erzeugt tatsächlich einige Anweisungen wie vxorpd etc, die ich denke, sollte nur erscheinen, wenn ftree-vectorize aktiviert ist (und O2 sollte das nicht standardmäßig aktivieren?) Wenn ich -m32 flag addiere Um in einem 32-Bit-Befehl zu kompilieren, verschwanden diese gepackten Anweisungen. Wer auf ähnliche Situationen traf, könnte Erklärungen geben? Vielen Dank.Seltsames gcc6.1 -O2-Kompilierungsverhalten

+0

Ihre Frage wäre einfacher mit einem konkreten Beispiel zu beantworten. –

Antwort

3

XORPD ist die klassische SSE2-Anweisung, die eine bitweise logische XOR-Operation für zwei gepackte Gleitkommawerte mit doppelter Genauigkeit ausführt.

VXORPD ist die Vektorversion derselben Anweisung. Im Wesentlichen ist es die klassische SSE2 XORPD Anweisung mit einer VEX prefix. Das bedeutet das Präfix "V" im Opcode. Es wurde mit AVX (Advanced Vector Extensions) eingeführt und wird auf jeder Architektur unterstützt, die AVX unterstützt. (Es gibt tatsächlich zwei Versionen, die VEX.128-kodierte Version, die auf 128-Bit-AVX-Registern funktioniert, und die VEX.256-kodierte Version, die auf 256-Bit-AVX2-Registern funktioniert.)

Alle Legacy-SSE und SSE2-Anweisungen können ein VEX-Präfix hinzugefügt werden, das ihnen ein Formular mit drei Operanden gibt und es ihnen ermöglicht, mit den anderen neuen AVX-Anweisungen effizienter zu interagieren und zu planen. Es vermeidet auch the high cost of transitions between VEX and non-VEX modes. Ansonsten behalten diese neuen Codierungen das gleiche Verhalten bei. Daher erzeugen Compiler in der Regel VEX-Präfix-Versionen dieser Anweisungen, wenn die Zielarchitektur sie unterstützt. In Ihrem Fall spezifiziert march=native eindeutig eine Architektur, die mindestens AVX unterstützt.

Bei GCC und Clang erhalten Sie diese Anweisungen sogar bei ausgeschalteter Optimierung (-O0), so dass Sie sie sicher erhalten werden, wenn Optimierungen aktiviert sind. Weder der Schalter -ftree-vectorize noch einer der anderen vektorisierungsspezifischen Optimierungsschalter muss aktiviert sein, da dies eigentlich nichts mit der Vektorisierung Ihres Codes zu tun hat. Genauer gesagt hat sich der Codefluss nicht geändert, nur die Codierung der Anweisungen.

Sie können dies sehen mit einfachsten Code vorstellbar:

double Foo() 
{ 
    return 0.0; 
} 
Foo(): 
     vxorpd xmm0, xmm0, xmm0 
     ret 

Also das erklärt, warum Sie VXORPD und seine Freunde zu sehen, wenn Sie ein 64-Bit mit dem -march=native Schalter bauen kompilieren .

dass die Frage der Blätter, warum Sie es nicht tun sehen, wenn Sie die -m32 Schalter werfen (den Code zu erzeugen bedeutet für 32-Bit-Plattformen). SSE- und AVX-Befehle sind immer noch verfügbar, wenn diese Plattformen angesprochen werden. Ich glaube, dass sie unter bestimmten Umständen verwendet werden, aber sie können wegen der erheblichen Unterschiede im 32-Bit-ABI nicht so häufig verwendet werden. Insbesondere erfordert der 32-Bit-ABI, dass Gleitkommawerte auf dem Gleitkomma-Stack x87 zurückgegeben werden. Da dies die Verwendung der Gleitkommaanweisungen x87 erfordert, neigt der Optimierer dazu, bei diesen zu bleiben, es sei denn, es wird ein Codeabschnitt stark vektorisiert. Das ist das einzige Mal, dass es wirklich Sinn macht, Werte vom x87 Stack zu SIMD Registern und wieder zurück zu mischen. Ansonsten ist das ein Leistungsverlust für wenig bis keinen praktischen Nutzen.

Sie können dies auch in Aktion sehen.Schau, was Änderungen in der Ausgabe nur durch den -m32 Schalter werfen:

Foo(): 
     fldz 
     ret 

FLDZ ist die x87 FPU Anweisung für die Konstante Null an der Oberseite des Floating-Point-Stapels geladen wird, wo er bereit ist, zu zurückzusenden der Anrufer.

Offensichtlich ist es wahrscheinlicher, wenn Sie den Code komplizierter machen, die Heuristiken des Optimierers zu ändern und ihn dazu zu überreden, SIMD-Anweisungen auszugeben. Sie sind weitaus wahrscheinlicher, wenn Sie vektorisierungsbasierte Optimierungen aktivieren.

+0

Hallo Cody Grey, Danke für Ihre Antwort. Nur noch eine Frage zu beantworten. Ich sah eine große Geschwindigkeit aufgrund dieser vex-Präfix-Anweisungen beim Kompilieren mit Fastmath. Haben Sie eine Idee, wie diese vex-Präfix-Anweisungen besser abschneiden als die ursprünglichen x87-Befehle? Danke – PST

+0

@PST Nun, die regulären SSE-Anweisungen sind in der Regel schneller als die x87-Anweisungen. Dafür gibt es mehrere komplizierte Gründe. Eine der wichtigsten ist, dass die x87-FPU von einem stackbasierten System mit allen damit verbundenen Einschränkungen ausgeht, während die SSE-Implementierung Register verwendet. Das bedeutet, dass keine Zeit damit verschwendet wird, Werte auf dem Stapel zu verschieben oder Werte an verschiedenen Positionen auf dem Stapel auszutauschen. Ein weiterer Grund, dass SSE schneller als x87 ist, ist einfach, dass es eine neuere Implementierung ist und entsprechend optimiert wurde. –

+0

Dann erklärt meine Antwort bereits, warum die VEX-Präfix-SSE-Anweisungen schneller als normale SSE-Anweisungen sind. Sie profitieren von zwei Leistungsverbesserungen: zuerst von x87 auf SSE und dann von SSE auf VEX-codierte SSE. Die Ingenieure von Intel müssen in den letzten 15 bis 20 Jahren etwas vorgemacht haben. :-) –

1

Wenn Sie nur Cody Gray's very good answer hinzufügen möchten, können Sie die intern aktivierten GCC-Optionen überprüfen, indem Sie sie an Assembler ausgeben und einschalten.

Zum Beispiel:

gcc -O2 -fverbose-asm -S -o test.S test.c 

in test.S alle Optimierungsoptionen aktiviert bei der gewählten Optimierungsebene auflistet (hier -O2).

+0

Siehe auch http://gcc.godbolt.org/, wo man die Compiler-Asm-Ausgabe mit dem entfernten Rauschen sehen kann. –