http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60413
Bug ID: 60413 Summary: extra precision not properly removed on assignment of return value Product: gcc Version: 4.8.2 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: desrt at desrt dot ca This problem has been seen with at least: gcc version 4.8.2 20131212 (Red Hat 4.8.2-7) (GCC) and gcc version 4.8.2 (Ubuntu 4.8.2-16ubuntu4) so I believe it to be an upstream problem. This problem has only been observed to happen on 32bit compilations. There doesn't seem to be a problem with 64bit. Consider this code: ==> get-value.h <== double get_value (void); ==> get-value.c <== #include "get-value.h" #include <stdint.h> int x = 1; double get_value (void) { return x / 1e6; } ==> main.c <== #include "get-value.h" #include <stdlib.h> int main (void) { double a, b; a = get_value (); b = get_value (); if (a != b) abort (); return 0; } and build it with -O2 -m32. You will get an abort. The reason for this is because the return value of the get_value() function comes via a floating point register. These registers have a higher precision than IEEE double. The spec permits "extra range and precision": """ 8 Except for assignment and cast (which remove all extra range and precision), the values of operations with floating operands and values subject to the usual arithmetic conversions and of floating constants are evaluated to a format whose range and precision may be greater than required by the type. """ It seems that GCC is failing to remove the extra precision on the assignment "b = get_value();". Indeed, looking at the code that is output: call get_value movsd %xmm0, 8(%rsp) call get_value movsd 8(%rsp), %xmm1 ucomisd %xmm0, %xmm1 we see that the first call has the return value stored in memory, but the comparison uses the value from the second call directly, without truncating the precision. Adding 'volatile' to the local variables involved is an effective workaround for the problem.