diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/fold-const.c | 14 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/powerpc/pr95450.c | 29 |
2 files changed, 42 insertions, 1 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 7c4d1ef..78f72f0 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -8328,7 +8328,19 @@ native_interpret_real (tree type, const unsigned char *ptr, int len) } real_from_target (&r, tmp, mode); - return build_real (type, r); + tree ret = build_real (type, r); + if (MODE_COMPOSITE_P (mode)) + { + /* For floating point values in composite modes, punt if this folding + doesn't preserve bit representation. As the mode doesn't have fixed + precision while GCC pretends it does, there could be valid values that + GCC can't really represent accurately. See PR95450. */ + unsigned char buf[24]; + if (native_encode_expr (ret, buf, total_bytes, 0) != total_bytes + || memcmp (ptr, buf, total_bytes) != 0) + ret = NULL_TREE; + } + return ret; } diff --git a/gcc/testsuite/gcc.target/powerpc/pr95450.c b/gcc/testsuite/gcc.target/powerpc/pr95450.c new file mode 100644 index 0000000..569d2b2 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr95450.c @@ -0,0 +1,29 @@ +/* PR target/95450 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* { dg-final { scan-tree-dump-not "return \[0-9.e+]\+;" "optimized" } } */ + +/* Verify this is not optimized for double double into return floating_point_constant, + as while that constant is the maximum normalized floating point value, it needs + 107 bit precision, which is more than GCC supports for this format. */ + +#if __LDBL_MANT_DIG__ == 106 +union U +{ + struct { double hi; double lo; } dd; + long double ld; +}; + +const union U g = { { __DBL_MAX__, __DBL_MAX__ / (double)134217728UL / (double)134217728UL } }; +#else +struct S +{ + long double ld; +} g; +#endif + +long double +foo (void) +{ + return g.ld; +} |