- Visual C++ 2013 hat etwas an der Art geändert, wie float zu int konvertiert wird.
- Diese Konvertierungsfunktionen werden vom Compiler erzeugt. Sie liegen nicht der CRT o.ä. bei und der Quelltext ist nicht einsehbar. Solche Compiler-internen Funktionen (allen voran __chkstk()) werden oft auch direkt in Assembler geschrieben.
- Als eine der Konvertierungsfunktionen für Visual 2013 überarbeitet wurde, hat sich ein Fehler eingeschlichen, der den Floating-Point-Stack ruinieren kann. Siehe Ticket 824658 – cast double to unsigned int cause FPU stack overflow on c++ code compiled with VS2013 x86 toolset - by Cliff Ding.Charles Fu hat geschrieben:We have gotten several reports on this bug, and we have fixed it.
- Betroffen ist ausschließlich x86-32 mit SSE2. Auf anderen Plattformen und ohne SSE2 wird die neue Konvertierung nicht benutzt.
- Als Workaround wird ein versteckter Compiler-Parameter empfohlen:Charles Fu hat geschrieben:As a workaround, if you know which file causes this FP stack overflow, you can compile it with a hidden switch /d2noftol3.
- Dieser Parameter funktioniert auch mit dem aktuellen Visual C++ 2017.
- Das ist insofern interessant, als dass man nun direkt die Auswirkungen auf den Code messen kann. Und das habe ich getan.
- Visual C++ 2017 mit /d2noftol3 (alte Konvertierung) baut in meine Anwendung folgende Symbole ein:in Standardeinstellung (neue Konvertierung)
Code: Alles auswählen
code _ftol2_.obj _ftol2 117 B _ftol2_.obj _ftol2_sse_excpt 26 B _ftol2_.obj _ftol2_pentium4 19 B _ftol2_.obj _ftol2_sse 9 B
Code: Alles auswählen
code _ftol3_.obj _dtol3_work 229 B _ftol3_.obj _ftol3_common 194 B _ftol3_.obj _ftol3_work 134 B _ftol3_.obj _ftol3_except 68 B _ftol3_.obj _ultod3 55 B _ftol3_.obj _ltod3 39 B _ftol3_.obj _dtol3_NaN 29 B _ftol3_.obj _ftol3_NaN 24 B _ftol3_.obj _ftol3_arg_error 18 B _ftol3_.obj _dtoul3 15 B _ftol3_.obj _dtoui3 15 B _ftol3_.obj _ftoul3 15 B _ftol3_.obj _ftoui3 15 B _ftol3_.obj _ftol3 13 B _ftol3_.obj _dtol3 13 B data _ftol3_.obj _Int32ToUInt32 8 B _ftol3_.obj _DP2to32 8 B _ftol3_.obj _MantissaMask 8 B _ftol3_.obj _IntegerBit 8 B _ftol3_.obj _SignBit64 8 B _ftol3_.obj _MinFP64 8 B _ftol3_.obj _MinInt64 8 B _ftol3_.obj _MaxInt64 8 B _ftol3_.obj _MaxUInt64 8 B _ftol3_.obj _MaxFP32 8 B _ftol3_.obj _MinFP32 8 B _ftol3_.obj _MinSubInexact 8 B _ftol3_.obj _FpExcptTable 8 B _ftol3_.obj _i1075 4 B _ftol3_.obj _i1087 4 B _ftol3_.obj _x0800 4 B _ftol3_.obj _x17FF 4 B _ftol3_.obj _CWMask 2 B
- Erstmal scheint die alte version sowohl SSE2 als auch SSE und CPUs ohne SSE zu unterstützen. Die neue Version wird allerdings nur mit SSE2 aktiv.
- Dann sticht ins Auge, dass die neue Version fast fünf Mal so groß ist wie die alte (177 B gegenüber fast 1 KiB). Das geht damit einher, dass meine Programme auf x86-32-SSE2 rund 1 KiB kleiner werden, wenn ich /d2noftol3 nutze.
- Rein vom Bauchgefühl und den spärlichen Symbolinformationen her würde ich auch schätzen, dass ftol3() C++ ist, während ftol2() noch Assembler war.
- Die neue Version scheint double zu unterstützen (_SignBit64, _MantissaMask), obwohl mein Programm keine doubles nutzt. Das schlägt natürlich gut ein.