aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/fold-const.c14
-rw-r--r--gcc/testsuite/gcc.target/powerpc/pr95450.c29
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;
+}