diff options
author | Sanjay Patel <spatel@rotateright.com> | 2020-09-24 13:44:29 -0400 |
---|---|---|
committer | Sanjay Patel <spatel@rotateright.com> | 2020-09-24 14:02:19 -0400 |
commit | e34bd1e0b03d20a506ada156d87e1b3a96d82fa2 (patch) | |
tree | 5a0cc3e1cc40484c575b65c9a31382b4aa401cc3 /llvm/lib/Support/APFloat.cpp | |
parent | 03f22b08e2a387a415dcbb3cf021e41e629c3d34 (diff) | |
download | llvm-e34bd1e0b03d20a506ada156d87e1b3a96d82fa2.zip llvm-e34bd1e0b03d20a506ada156d87e1b3a96d82fa2.tar.gz llvm-e34bd1e0b03d20a506ada156d87e1b3a96d82fa2.tar.bz2 |
[APFloat] prevent NaN morphing into Inf on conversion (PR43907)
We shift the significand right on a truncation, but that needs to be made NaN-safe:
always set at least 1 bit in the significand.
https://llvm.org/PR43907
See D88238 for the likely follow-up (but needs some plumbing fixes before it can proceed).
Differential Revision: https://reviews.llvm.org/D87835
Diffstat (limited to 'llvm/lib/Support/APFloat.cpp')
-rw-r--r-- | llvm/lib/Support/APFloat.cpp | 15 |
1 files changed, 15 insertions, 0 deletions
diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp index 7a4c8bd..adc6299 100644 --- a/llvm/lib/Support/APFloat.cpp +++ b/llvm/lib/Support/APFloat.cpp @@ -2242,6 +2242,21 @@ IEEEFloat::opStatus IEEEFloat::convert(const fltSemantics &toSemantics, if (!X86SpecialNan && semantics == &semX87DoubleExtended) APInt::tcSetBit(significandParts(), semantics->precision - 1); + // If we are truncating NaN, it is possible that we shifted out all of the + // set bits in a signalling NaN payload. But NaN must remain NaN, so some + // bit in the significand must be set (otherwise it is Inf). + // This can only happen with sNaN. Set the 1st bit after the quiet bit, + // so that we still have an sNaN. + // FIXME: Set quiet and return opInvalidOp (on convert of any sNaN). + // But this requires fixing LLVM to parse 32-bit hex FP or ignoring + // conversions while parsing IR. + if (APInt::tcIsZero(significandParts(), newPartCount)) { + assert(shift < 0 && "Should not lose NaN payload on extend"); + assert(semantics->precision >= 3 && "Unexpectedly narrow significand"); + assert(*losesInfo && "Missing payload should have set lost info"); + APInt::tcSetBit(significandParts(), semantics->precision - 3); + } + // gcc forces the Quiet bit on, which means (float)(double)(float_sNan) // does not give you back the same bits. This is dubious, and we // don't currently do it. You're really supposed to get |