Wie bekomme ich eine intrinsische Funktion für die Funktion exp () in x64-Code?

8

Ich habe den folgenden Code und erwarte, dass die intrinsische Version der Funktion exp() verwendet wird. Leider ist es nicht in einem x64-Build, wodurch es langsamer als ein ähnliches Win32 (d. H. 32-Bit-Build):

%Vor%

Ich verwende die folgenden Schalter für mein Build:

%Vor%

Wie Sie sehen können, habe ich /Oi , /O2 und /fp:fast wie erforderlich für die MSDN Artikel zu intrinsics . Doch trotz meiner Bemühungen wird ein Aufruf an die Standardbibliothek vorgenommen, wodurch exp() bei x64-Builds langsamer arbeitet.

Hier ist die generierte Assembly:

%Vor%

Wie Sie in der obigen Abbildung sehen können, gibt es einen Aufruf an die Funktion exp() . Sehen wir uns nun den Code an, der für diese for -Schleife mit einem 32-Bit-Build generiert wurde:

%Vor%

Viel mehr Code dort, aber es ist schneller. Ein Timing-Test, den ich auf einem Nehalem-EP-Host mit 3,3 GHz durchführte, ergab die folgenden Ergebnisse:

32-Bit:

  

Für Schleifenkörper durchschnittliche Ausführungszeit: 34.849229 Zyklen / 10.560373 ns

64-Bit:

  

Für Schleifenkörper durchschnittliche Ausführungszeit: 45,845323 Zyklen / 13,892522 ns

Sehr seltsames Verhalten, tatsächlich. Warum passiert es?

Update:

Ich habe eine Microsoft Connect Fehlerbericht . Fühlen Sie sich frei, es upvote eine autoritative Antwort von Microsoft selbst über die Verwendung von Gleitkomma-Spezifika zu bekommen, vor allem in x64-Code.

    
Michael Goldshteyn 10.04.2012, 19:51
quelle

3 Antworten

5

Auf x64 wird Fließkomma-Arithmetik mit SSE ausgeführt. Dies hat keine integrierte Operation für exp() und daher ist ein Aufruf der Standardbibliothek unvermeidlich. Ich stelle mir vor, dass der MSDN-Artikel, auf den Sie sich beziehen, mit 32-Bit-Code geschrieben wurde, der 8087 FP berücksichtigt.

    
David Heffernan 10.04.2012, 20:30
quelle
0

BEARBEITEN Ich möchte zu dieser Diskussion den Link zu AMDs x64-Instruktionssatz-Handbücher und Intels Referenz .

Bei einer ersten Überprüfung sollte es möglich sein, F2XM1 zur Berechnung der Exponentialfunktion zu verwenden. Es ist jedoch in der x87-Befehlssatz im x64-Modus versteckt.

Es gibt Hoffnung, MMX / x87 explizit zu verwenden, wie es in einem Beitrag in VirtualDub Diskussionsforen beschrieben ist. Und das ist wie man Asm in VC ++ schreibt.

    
GregC 10.04.2012 20:26
quelle
0

Ich denke, der einzige Grund, warum Microsoft eine intrinsische Version von 32-Bit SSE2 exp () zur Verfügung stellt, sind die Standard-Aufrufkonventionen. Die 32-Bit-Aufrufkonventionen erfordern, dass der Operand auf den Haupt-Stack geschoben wird und das Ergebnis im obersten Register des FPU-Stacks zurückgegeben wird. Wenn Sie die SSE2-Codegenerierung aktiviert haben, wird der Rückgabewert wahrscheinlich aus dem FPU-Stack in den Speicher kopiert und dann von dieser Position in ein SSE2-Register geladen, um die mathematischen Berechnungen auszuführen, die Sie für das Ergebnis durchführen möchten. Offensichtlich ist es schneller, den Operanden in einem SSE2-Register zu übergeben und das Ergebnis in einem SSE2-Register zurückzugeben. Dies ist was __libm_sse2_exp () tut. Im 64-Bit-Code übergibt die Standard-Aufrufkonvention den Operanden und gibt das Ergebnis trotzdem in SSE2-Registern zurück, so dass es keinen Vorteil für eine intrinsische Version gibt.

Der Grund für den Leistungsunterschied zwischen 32-Bit-SSE2- und 64-Bit-Implementierungen von exp () ist, dass Microsoft in den beiden Implementierungen unterschiedliche Algorithmen verwendet. Ich habe keine Ahnung, warum sie das machen, und sie erzeugen für einige Operanden andere Ergebnisse (anders als 1ulp).

    
dc42 24.05.2013 13:26
quelle