Bug 93681 - Wrong optimization: instability of x87 floating-point results leads to nonsense
Summary: Wrong optimization: instability of x87 floating-point results leads to nonsense
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 10.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2020-02-11 16:32 UTC by Alexander Cherepanov
Modified: 2024-06-28 10:13 UTC (History)
5 users (show)

See Also:
Host:
Target: x86_64-*-*, i?86-*-*
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Alexander Cherepanov 2020-02-11 16:32:11 UTC
x87 floating-point results are effectively unstable due to possible excess precision. Without -fexcess-precision=standard, this instability can taint everything around and lead to nonsense.

Instability is not limited to FP numbers, it extends to integers too:

----------------------------------------------------------------------
#include <stdio.h>

__attribute__((noipa,optnone)) // imagine it in a separate TU
static int opaque(int i) { return i; }

int main()
{
    int z = opaque(1) + 0x1p-60 == 1;

    printf("z = %d\n", z);
    if (z) 
        puts("z is one");
}
----------------------------------------------------------------------
$ gcc -std=gnu11 -pedantic -Wall -Wextra -Wno-attributes -m32 -march=i686 -O3 test.c && ./a.out
z = 0
z is one
----------------------------------------------------------------------
gcc x86-64 version: gcc (GCC) 10.0.1 20200211 (experimental)
----------------------------------------------------------------------
Comment 1 Alexander Cherepanov 2020-02-11 16:34:08 UTC
And instability of integers then easily taints surrounding code:

----------------------------------------------------------------------
#include <stdio.h>

__attribute__((noipa)) // imagine it in a separate TU
static int opaque(int i) { return i; }

int main()
{
    int z = opaque(0);
    int a = opaque(1) + 0x1p-60 == 1;

    printf("z = %d\n", z);
    opaque(a);
    if (z == a) {
        opaque(0);
        if (a)
            printf("z = %d\n", z);
    }
}
----------------------------------------------------------------------
$ gcc -std=gnu11 -pedantic -Wall -Wextra -m32 -march=i686 -O3 test.c && ./a.out
z = 0
z = 1
----------------------------------------------------------------------
gcc x86-64 version: gcc (GCC) 10.0.1 20200211 (experimental)
----------------------------------------------------------------------

clang bug -- https://bugs.llvm.org/show_bug.cgi?id=44873
Comment 2 Tavian Barnes 2020-02-11 20:10:10 UTC
Similar to (dupe of?) https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85957
Comment 3 Alexander Cherepanov 2020-02-11 23:24:26 UTC
Bug 85957 is definitely similar. I've added it and a couple of others to "See Also".

Some differences:
- testcases here use comparisons to jump from FPs to integers while bug 85957 uses casts;
- the exploited discrepancy here is between in-register and in-memory (run-time) results of type `double` while in bug 85957 it's between compile-time and run-time results;
- it's probably possible to fix bug 85957 by enhancing the dom2 pass while it will probably not help here.
Whether it warrants a separate bug report it's hard for me to say.
Comment 4 Vincent Lefèvre 2020-02-26 12:36:49 UTC
Instead of "-m32 -march=i686", one can also compile with "-mfpmath=387". This is useful if one does not have the 32-bit libs.