Due to missing correct rounding in libc, expressions like sin(x) may give different values at compile time and at run time. With GCC optimization, this makes equal values appear to be different (e.g. an integer variable having two different values at the same time). Here's a testcase, inspired by PR85957 Comment 7 (which was about the x87 extended precision). #include <stdio.h> #include <math.h> #define D1 0x1.005023d32fee5p+1 #define D2 0x0.2ef652eba3771p-1 __attribute__((noinline,noclone)) static double opaque(void) { return D1; } __attribute__((noinline,noclone)) static void t1(void) { double a = D1, b = opaque(); if (a != b) printf("uneq"); double sa = sin(a), sb = sin(b); printf("t1: %a %s %a\n", sa, sa == sb ? "==" : "!=", sb); } __attribute__((noinline,noclone)) static void t2(void) { double a = D1, b = opaque(); if (a != b) printf("uneq"); int ia = sin(a) + D2, ib = sin(b) + D2; printf("t2: %d %s %d\n", ia, ia == ib ? "==" : "!=", ib); } __attribute__((noinline,noclone)) static void t3(void) { double a = D1, b = opaque(); if (a != b) printf("uneq"); int ia = sin(a) + D2, ib = sin(b) + D2; printf("t3: ib = %d\n", ib); if (ia == ib) printf("t3: ib = %d\n", ib); } int main(void) { t1(); t2(); t3(); return 0; } Compile with the following options: -O2 -lm -fdisable-tree-dom3 This gives: t1: 0x1.d109ad145c88fp-1 == 0x1.d109ad145c88ep-1 t2: 1 == 0 t3: ib = 0 t3: ib = 1 Tested GCC versions under Debian/unstable: * gcc-8 (Debian 8.4.0-7) 8.4.0 * gcc-9 (Debian 9.4.0-3) 9.4.0 * gcc-10 (Debian 10.3.0-11) 10.3.0 * gcc-11 (Debian 11.2.0-10) 11.2.0 * gcc (Debian 20210918-1) 12.0.0 20210918 (experimental) [master r12-3644-g7afcb534239] If -fdisable-tree-dom3 is not provided, t1 still fails with GCC 8 to 11.
I forgot some information: Debian unstable currently has libc6 2.32-4, where IBM's code for correct rounding was disabled some time ago. This bug might be unreproducible with other glibc versions (or other C libraries[*]). A change of the tested function and argument should make the same kind of issue appear on other platforms. However, I've just done a test on a Debian 10 (buster) machine (libc6 2.28-10), and the bug is reproducible on this machine. [*] A result may be correctly rounded by chance; this completely depends on the implementation.
I think there is nothing that can be done about this, and something like this has been there since forever. While perhaps some double routines in glibc used to be at some point correctly roundded, many others (e.g. float or long double) never were, there is always a chance you get different results from compile time folding vs. runtime evaluation.
(In reply to Jakub Jelinek from comment #2) > I think there is nothing that can be done about this, and something like > this has been there since forever. While perhaps some double routines in > glibc used to be at some point correctly roundded, many others (e.g. float > or long double) never were, there is always a chance you get different > results from compile time folding vs. runtime evaluation. In this case, for its optimizations, GCC shouldn't assume that these results are equal.
On Mon, 25 Oct 2021, vincent-gcc at vinc17 dot net via Gcc-bugs wrote: > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102930 > > --- Comment #3 from Vincent Lefèvre <vincent-gcc at vinc17 dot net> --- > (In reply to Jakub Jelinek from comment #2) > > I think there is nothing that can be done about this, and something like > > this has been there since forever. While perhaps some double routines in > > glibc used to be at some point correctly roundded, many others (e.g. float > > or long double) never were, there is always a chance you get different > > results from compile time folding vs. runtime evaluation. > > In this case, for its optimizations, GCC shouldn't assume that these results > are equal. Indeed. It's fine that different executions of a call to such a function *in the abstract machine* return different values. But each execution of such a call in the abstract machine must return some particular value (possibly different for different executions); it's not valid to optimize the code in a way that's inconsistent with a single return value for each call to the function in the abstract machine. (Likewise for other cases discussed in other bugs such as out-of-range floating-point-to-integer conversions.)
It looks like the usual equivalence issue.