aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2019-12-09 13:59:24 +0000
committerJoseph Myers <jsm28@gcc.gnu.org>2019-12-09 13:59:24 +0000
commit0fad54f0a88160e81c3150b63c91fd9809665474 (patch)
tree950d485dda0093ffc3c0d8df0ffdd7264b1ef61d
parent8d106dd51fac1a524ede3019769c214668021350 (diff)
downloadgcc-0fad54f0a88160e81c3150b63c91fd9809665474.zip
gcc-0fad54f0a88160e81c3150b63c91fd9809665474.tar.gz
gcc-0fad54f0a88160e81c3150b63c91fd9809665474.tar.bz2
Fix libdecnumber handling of non-canonical BID significands (PR middle-end/91226).
As reported in bug 91226, the libdecnumber code used on the host to interpret DFP values in the BID encoding fails, for _Decimal64 and _Decimal128, to check for the case where a significand is too large and so specified in IEEE 754 to be a non-canonical encoding of the zero significand. This patch adds the required handling of that case, together with tests both using -O2 (testing this host code) and -O0 (testing libgcc code, which already worked before the patch); the tests also cover _Decimal32, which already had the required check. In the _Decimal128 case, where the code previously completely ignored the case where the first four bits of the combination field are 1100, 1101 or 1110, the logic for determining the correct quantum exponent in that case is also newly added by this patch, so tests are added for that as well (again, libgcc already handled it correctly when the conversion was done at runtime rather than at compile time). Bootstrapped with no regressions for x86_64-pc-linux-gnu. PR middle-end/91226 libdecnumber: * bid/bid2dpd_dpd2bid.c (_bid_to_dpd64): Handle non-canonical significands. (_bid_to_dpd128): Likewise. Check for case where combination field starts 1100, 1101 or 1110. gcc/testsuite: * gcc.dg/dfp/bid-non-canonical-d128-1.c, gcc.dg/dfp/bid-non-canonical-d128-2.c, gcc.dg/dfp/bid-non-canonical-d128-3.c, gcc.dg/dfp/bid-non-canonical-d128-4.c, gcc.dg/dfp/bid-non-canonical-d32-1.c, gcc.dg/dfp/bid-non-canonical-d32-2.c, gcc.dg/dfp/bid-non-canonical-d64-1.c, gcc.dg/dfp/bid-non-canonical-d64-2.c: New tests. From-SVN: r279129
-rw-r--r--gcc/testsuite/ChangeLog12
-rw-r--r--gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d128-1.c30
-rw-r--r--gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d128-2.c42
-rw-r--r--gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d128-3.c5
-rw-r--r--gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d128-4.c6
-rw-r--r--gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d32-1.c26
-rw-r--r--gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d32-2.c5
-rw-r--r--gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d64-1.c26
-rw-r--r--gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d64-2.c5
-rw-r--r--libdecnumber/ChangeLog8
-rw-r--r--libdecnumber/bid/bid2dpd_dpd2bid.c22
11 files changed, 184 insertions, 3 deletions
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 8361b78..6cda5be 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,15 @@
+2019-12-09 Joseph Myers <joseph@codesourcery.com>
+
+ PR middle-end/91226
+ * gcc.dg/dfp/bid-non-canonical-d128-1.c,
+ gcc.dg/dfp/bid-non-canonical-d128-2.c,
+ gcc.dg/dfp/bid-non-canonical-d128-3.c,
+ gcc.dg/dfp/bid-non-canonical-d128-4.c,
+ gcc.dg/dfp/bid-non-canonical-d32-1.c,
+ gcc.dg/dfp/bid-non-canonical-d32-2.c,
+ gcc.dg/dfp/bid-non-canonical-d64-1.c,
+ gcc.dg/dfp/bid-non-canonical-d64-2.c: New tests.
+
2019-12-09 Matthew Malcomson <matthew.malcomson@arm.com>
PR middle-end/92410
diff --git a/gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d128-1.c b/gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d128-1.c
new file mode 100644
index 0000000..eee5471
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d128-1.c
@@ -0,0 +1,30 @@
+/* Test non-canonical BID significands: _Decimal128. Bug 91226. */
+/* { dg-do run { target { { i?86-*-* x86_64-*-* } && lp64 } } } */
+/* { dg-options "-std=gnu2x -O2" } */
+
+extern void abort (void);
+extern void exit (int);
+
+union u
+{
+ _Decimal128 d128;
+ unsigned __int128 u128;
+};
+
+#define U128(hi, lo) (((unsigned __int128) lo) \
+ | (((unsigned __int128) hi) << 64))
+
+int
+main (void)
+{
+ unsigned __int128 i = U128 (0x3041ed09bead87c0ULL, 0x378d8e6400000001ULL);
+ union u x;
+ _Decimal128 d128;
+ x.u128 = i;
+ d128 = x.d128;
+ volatile double d = d128;
+ if (d == 0)
+ exit (0);
+ else
+ abort ();
+}
diff --git a/gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d128-2.c b/gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d128-2.c
new file mode 100644
index 0000000..6267121
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d128-2.c
@@ -0,0 +1,42 @@
+/* Test non-canonical BID significands: _Decimal128, case where
+ combination field starts 11. Bug 91226. */
+/* { dg-do run { target { { i?86-*-* x86_64-*-* } && lp64 } } } */
+/* { dg-options "-std=gnu2x -O2" } */
+
+extern void abort (void);
+extern void exit (int);
+
+union u
+{
+ _Decimal128 d128;
+ unsigned __int128 u128;
+};
+
+#define U128(hi, lo) (((unsigned __int128) lo) \
+ | (((unsigned __int128) hi) << 64))
+
+int
+main (void)
+{
+ unsigned __int128 i = U128 (0x6e79000000000000ULL, 0x1ULL);
+ union u x;
+ _Decimal128 d128;
+ x.u128 = i;
+ d128 = x.d128;
+ volatile double d = d128;
+ if (d != 0)
+ abort ();
+ /* The above number should have quantum exponent 1234. */
+ _Decimal128 t1233 = 0.e1233DL, t1234 = 0.e1234DL, t1235 = 0.e1235DL;
+ _Decimal128 dx;
+ dx = d128 + t1233;
+ if (__builtin_memcmp (&dx, &t1233, 16) != 0)
+ abort ();
+ dx = d128 + t1234;
+ if (__builtin_memcmp (&dx, &t1234, 16) != 0)
+ abort ();
+ dx = d128 + t1235;
+ if (__builtin_memcmp (&dx, &t1234, 16) != 0)
+ abort ();
+ exit (0);
+}
diff --git a/gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d128-3.c b/gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d128-3.c
new file mode 100644
index 0000000..9190dae
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d128-3.c
@@ -0,0 +1,5 @@
+/* Test non-canonical BID significands: _Decimal128. Bug 91226. */
+/* { dg-do run { target { { i?86-*-* x86_64-*-* } && lp64 } } } */
+/* { dg-options "-std=gnu2x -O0" } */
+
+#include "bid-non-canonical-d128-1.c"
diff --git a/gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d128-4.c b/gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d128-4.c
new file mode 100644
index 0000000..b148ce4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d128-4.c
@@ -0,0 +1,6 @@
+/* Test non-canonical BID significands: _Decimal128, case where
+ combination field starts 11. Bug 91226. */
+/* { dg-do run { target { { i?86-*-* x86_64-*-* } && lp64 } } } */
+/* { dg-options "-std=gnu2x -O0" } */
+
+#include "bid-non-canonical-d128-2.c"
diff --git a/gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d32-1.c b/gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d32-1.c
new file mode 100644
index 0000000..b46b71c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d32-1.c
@@ -0,0 +1,26 @@
+/* Test non-canonical BID significands: _Decimal32. Bug 91226. */
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-std=gnu2x -O2" } */
+
+extern void abort (void);
+extern void exit (int);
+
+union u
+{
+ _Decimal32 d32;
+ unsigned int u32;
+};
+
+int
+main (void)
+{
+ union u x;
+ _Decimal32 d32;
+ x.u32 = 0x6cb89681U;
+ d32 = x.d32;
+ volatile double d = d32;
+ if (d == 0)
+ exit (0);
+ else
+ abort ();
+}
diff --git a/gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d32-2.c b/gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d32-2.c
new file mode 100644
index 0000000..11d64dc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d32-2.c
@@ -0,0 +1,5 @@
+/* Test non-canonical BID significands: _Decimal32. Bug 91226. */
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-std=gnu2x -O0" } */
+
+#include "bid-non-canonical-d32-1.c"
diff --git a/gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d64-1.c b/gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d64-1.c
new file mode 100644
index 0000000..87b1069
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d64-1.c
@@ -0,0 +1,26 @@
+/* Test non-canonical BID significands: _Decimal64. Bug 91226. */
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-std=gnu2x -O2" } */
+
+extern void abort (void);
+extern void exit (int);
+
+union u
+{
+ _Decimal64 d64;
+ unsigned long long int u64;
+};
+
+int
+main (void)
+{
+ union u x;
+ _Decimal64 d64;
+ x.u64 = 0x6c7386f26fc10001ULL;
+ d64 = x.d64;
+ volatile double d = d64;
+ if (d == 0)
+ exit (0);
+ else
+ abort ();
+}
diff --git a/gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d64-2.c b/gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d64-2.c
new file mode 100644
index 0000000..3c10145
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/dfp/bid-non-canonical-d64-2.c
@@ -0,0 +1,5 @@
+/* Test non-canonical BID significands: _Decimal64. Bug 91226. */
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-std=gnu2x -O0" } */
+
+#include "bid-non-canonical-d64-1.c"
diff --git a/libdecnumber/ChangeLog b/libdecnumber/ChangeLog
index 62a2e57..6c61788 100644
--- a/libdecnumber/ChangeLog
+++ b/libdecnumber/ChangeLog
@@ -1,3 +1,11 @@
+2019-12-09 Joseph Myers <joseph@codesourcery.com>
+
+ PR middle-end/91226
+ * bid/bid2dpd_dpd2bid.c (_bid_to_dpd64): Handle non-canonical
+ significands.
+ (_bid_to_dpd128): Likewise. Check for case where combination
+ field starts 1100, 1101 or 1110.
+
2019-01-01 Jakub Jelinek <jakub@redhat.com>
Update copyright years.
diff --git a/libdecnumber/bid/bid2dpd_dpd2bid.c b/libdecnumber/bid/bid2dpd_dpd2bid.c
index 63d3cec..36aa56c 100644
--- a/libdecnumber/bid/bid2dpd_dpd2bid.c
+++ b/libdecnumber/bid/bid2dpd_dpd2bid.c
@@ -189,6 +189,8 @@ _bid_to_dpd64 (_Decimal64 *pres, _Decimal64 *px) {
if ((comb & 0xc00) == 0xc00) { /* G0..G1 = 11 -> exp is G2..G11 */
exp = (comb) & 0x3ff;
bcoeff = (x & 0x0007ffffffffffffull) | 0x0020000000000000ull;
+ if (bcoeff >= 10000000000000000ull)
+ bcoeff = 0;
} else {
exp = (comb >> 2) & 0x3ff;
bcoeff = (x & 0x001fffffffffffffull);
@@ -298,9 +300,23 @@ _bid_to_dpd128 (_Decimal128 *pres, _Decimal128 *px) {
if ((comb & 0x1e000) == 0x1e000) {
res = x;
} else { /* normal number */
- exp = ((x.w[1] & 0x7fff000000000000ull) >> 49) & 0x3fff;
- bcoeff.w[1] = (x.w[1] & 0x0001ffffffffffffull);
- bcoeff.w[0] = x.w[0];
+ if ((comb & 0x18000) == 0x18000) {
+ /* Noncanonical significand (prepending 8 or 9 to any 110-bit
+ trailing significand field produces a value above 10^34). */
+ exp = (comb & 0x7fff) >> 1;
+ bcoeff.w[1] = 0;
+ bcoeff.w[0] = 0;
+ } else {
+ exp = ((x.w[1] & 0x7fff000000000000ull) >> 49) & 0x3fff;
+ bcoeff.w[1] = (x.w[1] & 0x0001ffffffffffffull);
+ bcoeff.w[0] = x.w[0];
+ if (bcoeff.w[1] > 0x1ed09bead87c0ull
+ || (bcoeff.w[1] == 0x1ed09bead87c0ull
+ && bcoeff.w[0] >= 0x378d8e6400000000ull)) {
+ bcoeff.w[1] = 0;
+ bcoeff.w[0] = 0;
+ }
+ }
d1018 = reciprocals10_128[18];
__mul_128x128_high (BH, bcoeff, d1018);
amount = recip_scale[18];