2013-03-09 8 views
20

Ich trat in den Zusammenbau der transzendentalen mathematischen Funktionen der C-Bibliothek mit MSVC im fp: strict-Modus. Sie alle scheinen dem gleichen Muster zu folgen, hier ist, was passiert für sin.Wie zu bestimmen, ob C Math SSE2 verwendet?

Zuerst gibt es eine Dispatch-Routine aus einer Datei namens "disp_pentium4.inc". Es prüft, ob die Variable ___use_sse2_mathfcns gesetzt wurde; wenn ja, ruft __sin_pentium4, sonst ruft __sin_default.

__sin_pentium4 (in "sin_pentium4.asm") beginnt mit der Übertragung des Arguments von der x87 fpu in das xmm0-Register, führt die Berechnung mit SSE2-Anweisungen durch und lädt das Ergebnis zurück in den fpu.

__sin_default (in "sin.asm") behält die Variable auf dem x87-Stack und ruft einfach fsin.

In beiden Fällen wird der Operand auf den Stack x87 geschoben und zurückgegeben, so dass er für den Aufrufer transparent ist, aber wenn ___use_sse2_mathfcns definiert ist, wird die Operation tatsächlich in SSE2 und nicht in x87 ausgeführt.

Dieses Verhalten ist sehr interessant für mich, weil die x87 transzendentalen Funktionen dafür bekannt sind, je nach Implementierung etwas unterschiedliche Verhaltensweisen zu haben, während ein gegebener Teil des SSE2-Codes immer reproduzierbare Ergebnisse liefern sollte.

Gibt es eine Möglichkeit, entweder beim Kompilieren oder während der Laufzeit festzustellen, ob der SSE2-Codepfad verwendet wird? Ich bin nicht in der Lage, Assembly zu schreiben, wenn also eine Assembly geschrieben wird, wäre ein Codebeispiel wünschenswert.

+0

In welchem ​​Verzeichnis befinden sich diese Dateien? –

+0

"f: \ dd \ vctools \ crt_bld \ SELF_X86 \ crt \ vorkompilierte \ tran \ i386 \" - das ist genau das, was ich im Zerlegen sehen, ich habe nicht die Dateien selbst. – Asik

+2

Nein, unmöglich, eine anständige Frage auf SO ... Ich fühle mich eine peinliche upvote drängen. –

Antwort

7

Ich fand die Antwort durch sorgfältige Untersuchung von math.h. Dies wird durch eine Methode gesteuert, die _set_SSE2_enable genannt wird.Dies ist eine öffentliche Symbol here dokumentiert:

Aktiviert oder deaktiviert die Verwendung von Streaming SIMD Extensions 2 (SSE2) Anweisungen in CRT mathematischen Routinen. (Diese Funktion ist auf x64-Architekturen nicht verfügbar, da SSE2 standardmäßig aktiviert ist.)

Dies bewirkt, dass die aforementionned ___use_sse2_mathfcns Flag an den vorgesehenen Wert eingestellt werden, wodurch effektiv oder Verwendung der _pentium4 SSE2-Routinen zu deaktivieren.

Die Dokumentation erwähnt, dass dies nur bestimmte transzendentale Funktionen betrifft, aber mit Blick auf die Demontage scheint dies jeden von ihnen zu betreffen.

Edit: in jede Funktion Schritt zeigt, dass sie in SSE2 alle verfügbar sind mit Ausnahme der folgenden:

  • fmod
  • sinh
  • cosh
  • tanh
  • sqrt

Sqrt ist der größte Täter, aber es ist trivial zu mir in SSE2 unter Verwendung von intrinsischen Für die anderen gibt es keine einfache Lösung, außer vielleicht die Verwendung einer Drittanbieter-Bibliothek, auf die ich aber wahrscheinlich verzichten kann.

2

Die kurze Antwort ist, dass Sie in IHREM CODE nicht sicher sagen können, was die Bibliothek tun wird, es sei denn, Sie beziehen auch spezifische Details zur Bibliotheksimplementierung ein. Dies würde den Code völlig unportabel machen - sogar zwei verschiedene Builds desselben Compilers können die Interna der Bibliothek verändern.

Natürlich, wenn Portabilität kein Problem ist, dann mit extern <type> ___use_sse2_mathfcns; und prüfen, ob es die wahre wäre klar funktionieren.

Ich erwarte, dass, wenn der Prozessor SSE2 hat und Sie eine modern genug Bibliothek verwenden, es SSE2 wann immer möglich verwenden würde. Aber das zu sagen, ist eine andere Sache.

Wenn dies für Ihren Code entscheidend ist, implementieren Sie Ihre eigenen transzendenten Funktionen und verwenden Sie diese - nur so können Sie das gleiche Ergebnis garantieren. Oder verwenden Sie einen geeigneten Inline-Assembler- (oder transzendenten) Code, um ausgewählte sin, cos usw. Werte zu berechnen und diese mit den Funktionen sin() und cos() zu vergleichen, die von der Bibliothek bereitgestellt werden.

+0

'extern int ___ use_sse2_mathfcns' gibt mir einen Linker-Fehler. Ich weiß nicht, wo das definiert ist, es ist nur ein Name in der Demontage. – Asik

+0

Versuchen Sie es mit einem weniger '_'? –

+0

Das hat auch nicht funktioniert. – Asik

3

Warum nicht eine eigene Bibliothek anstelle der C-Laufzeit verwenden? Dies würde eine noch stärkere Garantie der Konsistenz zwischen den Computern bieten (vermutlich wird die C-Laufzeit als DLL bereitgestellt und kann sich mit der Zeit geringfügig ändern).

Ich würde CRlibm empfehlen. Wenn Sie bereits auf SSE2 abzielen und solange Sie den Rundungsmodus der FPU nicht ändern wollten, sind Sie in den idealen Bedingungen, um sie zu verwenden, und Sie werden keine genauere Implementierung finden.

+0

Ich muss tatsächlich die Präzision und Rundungsmodus der FPU: 53-Bits und auf die nächste Runde. Dies sollte jedoch keine Auswirkungen auf CRlibm-Routinen haben, wenn sie in SSE2 implementiert sind. – Asik

+0

@Dr_Asik Der Emulationsmodus des historischen Gleitkomma-Stack-Befehls ist nicht perfekt: Bei einer Einstellung für 53-Bit-Signifikanz behält der Exponent seinen vollen erweiterten Bereich bei. Insbesondere ist es schwierig, Doppelrunden-Denormale zu vermeiden. Trotzdem ist CRlibm so konzipiert, dass es auch dann funktioniert, wenn es auf das x87 abzielt, solange es in dem Emulationsmodus gesetzt ist, auf den Sie verweisen: http://lipforge.ens-lyon.fr/www/crlibm/start.html –

+1

+1 für CRLibM. Neben garantiert perfekte Genauigkeit ist es in der Regel schneller als GNU libm und Cephes C. Falls Sie eine gewisse Genauigkeit handeln wollen für die Leistung einen Blick auf FDLibM haben. –