I'm trying to debug a portability issue in the Erlang VM, which uses FP exception status flags to detect various invalid FP operations. In one specific case it converts a double containing 1.475740e+19 to uint64_t through an assignment. This works when compiled by gcc-4.8, but gives an unexpected FE_INVALID exception when compiled by clang-3.6.0. My host is Fedora 20 Linux x86_64, but the issue also occurs on FreeBSD and OSX. I'm trying to determine if the source code invokes undefined behaviour, or if clang miscompiles it. The following standalone testcase illustrates the issue: ==snip== #include <fenv.h> #include <inttypes.h> #include <stdio.h> #include <stdlib.h> double dblval = 1.475740e+19; __attribute__((__noinline__)) uint64_t mytrunc(double d) { uint64_t x; x = d; /* trunc */ return x; } int main(void) { uint64_t result; int excepts; printf("dblval: %f\n", dblval); printf("INT64_MAX: %" PRId64 "\n", INT64_MAX); printf("UINT64_MAX: %" PRIu64 "\n", UINT64_MAX); if (feclearexcept(FE_ALL_EXCEPT) == -1) { perror("feclearexcept"); exit(1); } result = mytrunc(dblval); excepts = fetestexcept(FE_ALL_EXCEPT); printf("mytrunc: %" PRIu64 "\n", result); printf("excepts: %x\n", excepts); if (excepts) abort(); return 0; } ==snip== Compiling with gcc-4.8 and then running it I see: dblval: 14757400000000000000.000000 INT64_MAX: 9223372036854775807 UINT64_MAX: 18446744073709551615 mytrunc: 14757400000000000000 excepts: 0 but with clang-3.6.0 excepts is 1 (FE_INVALID) and it aborts. Reading the C standard (e.g. C1x n1494 section 6.3.1.4), it seems to me that the real value is trivially representible in uint64_t (it's non-negative and in range), so this should not invoke undefined behaviour, and in that case clang is miscompiling the code. gcc-4.8 -O2 generates the following code for mytrunc: 0000000000400840 <mytrunc>: 400840: f2 0f 10 0d 10 01 00 movsd 0x110(%rip),%xmm1 # 400958 <_IO_stdin_used+0x68> 400847: 00 400848: 66 0f 2e c1 ucomisd %xmm1,%xmm0 40084c: 73 0a jae 400858 <mytrunc+0x18> 40084e: f2 48 0f 2c c0 cvttsd2si %xmm0,%rax 400853: c3 retq 400854: 0f 1f 40 00 nopl 0x0(%rax) 400858: f2 0f 5c c1 subsd %xmm1,%xmm0 40085c: 48 ba 00 00 00 00 00 movabs $0x8000000000000000,%rdx 400863: 00 00 80 400866: f2 48 0f 2c c0 cvttsd2si %xmm0,%rax 40086b: 48 31 d0 xor %rdx,%rax 40086e: c3 retq 40086f: 90 nop which seems to perform range reduction before the cvttsd2si, while clang-3.6.0 -O2 generates: 0000000000400770 <mytrunc>: 400770: f2 0f 10 0d 68 01 00 movsd 0x168(%rip),%xmm1 # 4008e0 <__dso_handle+0x8> 400777: 00 400778: 0f 28 d0 movaps %xmm0,%xmm2 40077b: f2 0f 5c d1 subsd %xmm1,%xmm2 40077f: f2 48 0f 2c c2 cvttsd2si %xmm2,%rax 400784: 48 b9 00 00 00 00 00 movabs $0x8000000000000000,%rcx 40078b: 00 00 80 40078e: 48 31 c1 xor %rax,%rcx 400791: f2 48 0f 2c c0 cvttsd2si %xmm0,%rax 400796: 66 0f 2e c1 ucomisd %xmm1,%xmm0 40079a: 48 0f 43 c1 cmovae %rcx,%rax 40079e: c3 retq 40079f: 90 nop which seems to perform two conversions, one on the original parameter and one on a range-reduced version, and then selects the correct integer to return afterwards, but then the FP exception will already have been signalled (by the cvttsd2si at 0x400791). So, is the source code broken or did clang miscompile it?