Reference Number : CMPLRS-43756
Version : Intel® C++ Compiler Version 18.0, 17.0 and earlier; Microsoft* Visual C++* Version 2017 and 2015 (at least)
Operating System : Windows*
Problem Description : Calls to 80 bit long double versions of standard math functions under the /Qlong-double Intel compiler option may yield unexpected results due to conflicts with 64 bit long double versions in the Microsoft Visual C++ run-time libraries. Because the function prototypes look the same, there is no warning at compile or link time, so this can lead to run-time errors that may be hard to debug.
Cause : The Intel run-time library contains 32 bit, 64 bit and 80 bit implementations of standard math functions, e.g. sqrtf(), sqrt() and sqrtl(). On Microsoft* Windows* systems, the default length of the long double data type is 64 bits. In the Microsoft run-time library, both sqrt() and sqrtl() functions expect 64 bit arguments in an xmm register and return 64 bit results. The Intel compiler converts calls from sqrtl() for long doubles to sqrt() which also expects 64 bit arguments in xmm registers and returns 64 bit results. However, when the Intel Compiler switch /Qlong-double is set, the long double data type becomes 80 bits long and calls to sqrtl() expect an 80 bit argument on the stack and return an 80 bit result. Thus the Intel and Microsoft entry points for long double versions of math functions such as sqrtl have the same name, but pass arguments and return results in different ways.
In general, the Intel compiler driver tries to link the Intel math run-time library ahead of the Microsoft run-time library, so that the Intel versions of math functions pre-empt the Microsoft versions. In some circumstances, a pragma in Microsoft header files can cause the Microsoft run-time library to be linked ahead of the Intel math library. (An example of this is in use_ansi.h, invoked by cstdio). If /Qlong-double has been set, this leads to an ABI mismatch for long double versions of math functions such as sqrtl(). This can lead to unexpected results for such calls, as seen in the following example:
#include <mathimf.h> #include <cstdio> int main() { long double value = sqrtl(100.0l); printf("Value: %f\n", (double)value); return 0; }
>icl /Od /nologo test.cpp>test Value: 10.000000>icl /Od /Qlong-double /nologo test.cpp>test Value: -nan(ind)
Solution : Caution should be exercised when using 80 bit long double APIs on Windows. This issue can be avoided by linking the Intel math run-time library explicitly, e.g. with /link /DEFAULTLIB:libmmt for the default of linking with a multithreaded, static run-time library (/MT). For the above example:
>icl /Od /Qlong-double /nologo test.cpp /link /defaultlib:libmmt>test Value: 10.000000