Answered by:
VC++ 2013 tan() causes illegal instruction exception in x64

Question
-
I've encountered what I believe to be a compiler bug, but am unsure at the moment.
Background:
I've got a program which builds and runs fine in VS2010 for both debug/release on Win32/64.
I recently upgraded to VS 2013, update 3 and am now getting illegal instruction exceptions that crash my program.
This only happens when building for x64, and not for Win32. The bug can be reproduced very easily with this code:
float f = 8388608.0; float f2 = tan(f);//Crashes
This doesn't happen when using double, only with float, and only on x64.
I'm stumped as to what could be the problem and am suspecting the compiler.
My CPU: AMD Phenom II
Any help is greatly appreciated. Thanks.
Answers
-
Can you see in the debugger which assembly instruction has triggered the exception? Probably it's an SSE/AVX instruction which is not available on your CPU.
To report compiler bugs you can use the Connect site: https://connect.microsoft.com/VisualStudio
- Marked as answer by May Wang - MSFT Friday, September 12, 2014 7:44 AM
All replies
-
Can you see in the debugger which assembly instruction has triggered the exception? Probably it's an SSE/AVX instruction which is not available on your CPU.
To report compiler bugs you can use the Connect site: https://connect.microsoft.com/VisualStudio
- Marked as answer by May Wang - MSFT Friday, September 12, 2014 7:44 AM
-
I suspect your suggestion is correct, but the assembly looks pretty innocent. It's just calling into the standard tan() function:
00082 e8 00 00 00 00 call ?tan@@YAMM@Z ; tan
00087 c6 44 24 44 01 mov BYTE PTR $T10[rsp], 1
0008c f3 0f 11 44 24
20 movss DWORD PTR f2$5[rsp], xmm0And here is the implementation of tan():
; Function compile flags: /Odsp /RTCsu
; File c:\program files (x86)\microsoft visual studio 12.0\vc\include\math.h
; COMDAT ?tan@@YAMM@Z
_TEXT SEGMENT
_X$ = 64
?tan@@YAMM@Z PROC ; tan, COMDAT
; 1138 : {return (tanf(_X)); }
$LN3:
00000 f3 0f 11 44 24
08 movss DWORD PTR [rsp+8], xmm0
00006 57 push rdi
00007 48 83 ec 30 sub rsp, 48 ; 00000030H
0000b 48 8b fc mov rdi, rsp
0000e b9 0c 00 00 00 mov ecx, 12
00013 b8 cc cc cc cc mov eax, -858993460 ; ccccccccH
00018 f3 ab rep stosd
0001a f3 0f 10 44 24
40 movss xmm0, DWORD PTR _X$[rsp]
00020 ff 15 00 00 00
00 call QWORD PTR __imp_tanf
00026 48 83 c4 30 add rsp, 48 ; 00000030H
0002a 5f pop rdi
0002b c3 ret 0
?tan@@YAMM@Z ENDP ; tan
_TEXT ENDSI submitted a bug on connect like you suggested.
-
-
-
-
I've encountered what I believe to be a compiler bug, but am unsure at the moment.
float f = 8388608.0; float f2 = tan(f);//Crashes
Any help is greatly appreciated. Thanks.
David Wilkinson | Visual C++ MVP
-
Does this happen for smaller arguments? It is not easy to accurately calculate the trigonometric functions for large radian arguments.
It happens for 8388608 and above. The tan() documentation mentions something about losing precision. But this throws an exception that can only be caught with (...). The strange thing is that it's not present on Win32 builds, and not with VS2010 either. Only with float on x64 in VS2013.
If I can't find a fix for this, I'll just write a custom tan function that is sin(x)/cos(x). Not ideal, but it can be a workaround for now.
Thanks.
-
Does this happen for smaller arguments? It is not easy to accurately calculate the trigonometric functions for large radian arguments.
It happens for 8388608 and above. The tan() documentation mentions something about losing precision.
This loss of accuracy is not a minor matter. If you run the program
#include <math.h> int main() { float f = 8388608.1f; float f2 = tan(f); double d = 8388608.1; double d2 = tan(d); return 0; }
you will find that f2 and d2 are completely different (no figures in common).
David Wilkinson | Visual C++ MVP
-