diff options
Diffstat (limited to 'llvm')
-rw-r--r-- | llvm/lib/Support/APFloat.cpp | 17 | ||||
-rw-r--r-- | llvm/test/CodeGen/PowerPC/pr16573.ll | 11 |
2 files changed, 28 insertions, 0 deletions
diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp index 8713ede6a17..58f16233ebf 100644 --- a/llvm/lib/Support/APFloat.cpp +++ b/llvm/lib/Support/APFloat.cpp @@ -1956,6 +1956,23 @@ APFloat::convert(const fltSemantics &toSemantics, X86SpecialNan = true; } + // If this is a truncation of a denormal number, and the target semantics + // has larger exponent range than the source semantics (this can happen + // when truncating from PowerPC double-double to double format), the + // right shift could lose result mantissa bits. Adjust exponent instead + // of performing excessive shift. + if (shift < 0 && isFiniteNonZero()) { + int exponentChange = significandMSB() + 1 - fromSemantics.precision; + if (exponent + exponentChange < toSemantics.minExponent) + exponentChange = toSemantics.minExponent - exponent; + if (exponentChange < shift) + exponentChange = shift; + if (exponentChange < 0) { + shift -= exponentChange; + exponent += exponentChange; + } + } + // If this is a truncation, perform the shift before we narrow the storage. if (shift < 0 && (isFiniteNonZero() || category==fcNaN)) lostFraction = shiftRight(significandParts(), oldPartCount, -shift); diff --git a/llvm/test/CodeGen/PowerPC/pr16573.ll b/llvm/test/CodeGen/PowerPC/pr16573.ll new file mode 100644 index 00000000000..7a7a8decc81 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/pr16573.ll @@ -0,0 +1,11 @@ +; RUN: llc < %s | FileCheck %s + +target triple = "powerpc64-unknown-linux-gnu" + +define double @test() { + %1 = fptrunc ppc_fp128 0xM818F2887B9295809800000000032D000 to double + ret double %1 +} + +; CHECK: .quad -9111018957755033591 + |