diff options
author | Joseph Myers <joseph@codesourcery.com> | 2019-12-09 13:59:24 +0000 |
---|---|---|
committer | Joseph Myers <jsm28@gcc.gnu.org> | 2019-12-09 13:59:24 +0000 |
commit | 0fad54f0a88160e81c3150b63c91fd9809665474 (patch) | |
tree | 950d485dda0093ffc3c0d8df0ffdd7264b1ef61d /libdecnumber | |
parent | 8d106dd51fac1a524ede3019769c214668021350 (diff) | |
download | gcc-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
Diffstat (limited to 'libdecnumber')
-rw-r--r-- | libdecnumber/ChangeLog | 8 | ||||
-rw-r--r-- | libdecnumber/bid/bid2dpd_dpd2bid.c | 22 |
2 files changed, 27 insertions, 3 deletions
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]; |