GCC x86-64 Suboptimale Baugruppenausgabe, warum?

8

Wenn die Assembly-Ausgabe des folgenden Codes angezeigt wird (keine Optimierungen, erzeugen -O2 und -O3 sehr ähnliche Ergebnisse):

%Vor%

GCC tut etwas, was mir schwer fällt:

%Vor%

Warum verschiebt GCC die Float-Werte zweimal in xmm0 und xmm1 und führt auch zweimal ucomiss aus?

Wäre es nicht schneller, folgendes zu tun?

%Vor%

Ich bin überhaupt kein richtiger Assembler, aber es schien mir komisch, doppelte Anweisungen zu haben. Gibt es ein Problem mit meiner Version des Codes?

Aktualisieren

Wenn Sie das volatile, das ich ursprünglich hatte, entfernen und durch scanf () ersetzen, erhalten Sie die gleichen Ergebnisse:

%Vor%

Und der entsprechende Assembler:

%Vor%

Endgültiges Update

Nachdem wir einige der folgenden Kommentare gelesen haben, scheint Han (der unter Jonathan Lefflers Post kommentierte) dieses Problem zu lösen. GCC macht die Optimierung nicht, weil es nicht möglich ist, sondern weil ich es nicht gesagt habe. Es scheint, dass alles auf IEEE-Gleitkommaregeln beruht und die strengen Bedingungen zu erfüllen GCC kann nicht einfach einen Sprung machen, wenn oberhalb oder unterhalb der ersten UCOMISS springen, weil es alle speziellen Bedingungen von Gleitkommazahlen zu behandeln hat. Bei der Verwendung der han-Empfehlung des -ffast-math-Optimizers (keine der -Ox-Flags ermöglicht -fast-math, da es einige Programme kaputt machen kann) macht GCC genau das, wonach ich gesucht habe:

Die folgende Baugruppe wurde mit GCC 4.3.2 "gcc -S -O3 -ffast-math test.c"

erstellt %Vor%

Beachten Sie, dass die beiden UCOMISS-Anweisungen nun durch einen COMISS direkt gefolgt von einem JA (springe wenn darüber) und JB (springe wenn darunter) ersetzt werden. GCC ist in der Lage, diese Optimierung zu nageln, wenn Sie es -ffast-math verwenden!

UCOMISS gegen COMISS (http://www.softeng.rl.ac.uk/st/archive/SoftEng/SESP/html/SoftwareTools/vtune/users_guide/mergedProjects/analyzer_ec/mergedProjects/reference_olh/mergedProjects/instructions/instruct32_hh /vc315.htm): "Der UCOMISS-Befehl unterscheidet sich vom COMISS-Befehl dadurch, dass er eine ungültige SIMD-Gleitkommaausnahme nur signalisiert, wenn ein Quelloperand ein SNaN ist. Der COMISS-Befehl signalisiert ungültig, wenn ein Quelloperand entweder ein QNaN oder ein ist SNaN. "

Nochmals vielen Dank für die hilfreiche Diskussion.

    
Brandon 19.09.2011, 01:38
quelle

2 Antworten

4

Hier ist ein anderer Grund: Wenn du es dir genau ansiehst, ist es NICHT derselbe Ausdruck.

Sie sind keine Komplemente voneinander. Daher müssen Sie trotzdem zwei Vergleiche durchführen. volatile erzwingt das erneute Laden der Werte.

EDIT: (siehe Kommentare, ich habe vergessen, dass du das mit den Flags machen kannst)

Um die neue Frage zu beantworten:

Die Kombination der beiden ucomiss ist keine vollständig offensichtliche Optimierung aus der Sicht des Compilers.

Um sie zu kombinieren, muss der Compiler:

  1. Erkenne, dass ucomiss %xmm0, %xmm1 das gleiche ist wie ucomiss %xmm1, %xmm0 .
  2. Dann muss es einen gemeinsamen Sub-Expression-Eliminierungs-Durchlauf machen, um es herauszuziehen.

All dies muss getan werden nachdem der Compiler die Befehlsauswahl vornimmt. Und die meisten Optimierungsdurchläufe werden vor der Befehlsauswahl durchgeführt.

Was mich mehr beunruhigt ist, warum f1 und f2 nicht in Registern gehalten werden, nachdem Sie volatiles losgeworden sind. -O3 gibt dir das wirklich?

    
Mysticial 19.09.2011, 01:42
quelle
3

Das volatile -Qualifikationsmerkmal bedeutet, dass sich die Werte von f1 und f2 möglicherweise so ändern, wie der Compiler es nicht erkennt / erwartet. Daher muss es jedes Mal auf den Speicher zugreifen, wenn es f1 oder f2 verwendet. Der generierte Code macht das - so ist es korrekt.

Vergleichen und kontrastieren Sie mit dem Code, den Sie erhalten, wenn Sie die volatile -Qualifikatoren von einer der Variablen oder beiden Variablen entfernen. Möglicherweise müssen Sie die Werte von f1 und f2 von irgendwo lesen, um zu vermeiden, dass der Compiler die Ausdrücke zum Zeitpunkt der Kompilierung auswertet.

Im aktualisierten Code erhalten Sie zwei verschiedene Beschwörungsformeln für die Anweisung ucomiss , obwohl die vorhergehenden Anweisungen movss identisch sind:

%Vor%

Die Reihenfolge der Operanden für die Anweisung ucomiss ist für die umgekehrte Bedingung umgekehrt:

%Vor%

Ich bin nicht davon überzeugt, dass der Optimierer dort optimiert, wo es möglich ist, aber die Frage ist, dass sich meine Frage über mein Fachwissen hinaus verändert.

    
Jonathan Leffler 19.09.2011 01:41
quelle

Tags und Links