APFloat: Fix scalbn handling of denormals

This was incorrect for denormals, and also failed
on longer exponent ranges.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@263369 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Matt Arsenault
2016-03-13 05:11:51 +00:00
parent 1f9d59bf0f
commit 2ef9469788
3 changed files with 152 additions and 37 deletions
+13 -11
View File
@@ -3945,19 +3945,21 @@ APFloat::makeZero(bool Negative) {
APInt::tcSet(significandParts(), 0, partCount());
}
APFloat llvm::scalbn(APFloat X, int Exp) {
if (X.isInfinity() || X.isZero() || X.isNaN())
return X;
APFloat llvm::scalbn(APFloat X, int Exp, APFloat::roundingMode RoundingMode) {
auto MaxExp = X.getSemantics().maxExponent;
auto MinExp = X.getSemantics().minExponent;
if (Exp > (MaxExp - X.exponent))
// Overflow saturates to infinity.
return APFloat::getInf(X.getSemantics(), X.isNegative());
if (Exp < (MinExp - X.exponent))
// Underflow saturates to zero.
return APFloat::getZero(X.getSemantics(), X.isNegative());
X.exponent += Exp;
// If Exp is wildly out-of-scale, simply adding it to X.exponent will
// overflow; clamp it to a safe range before adding, but ensure that the range
// is large enough that the clamp does not change the result. The range we
// need to support is the difference between the largest possible exponent and
// the normalized exponent of half the smallest denormal.
int SignificandBits = X.getSemantics().precision - 1;
int MaxIncrement = MaxExp - (MinExp - SignificandBits) + 1;
// Clamp to one past the range ends to let normalize handle overlflow.
X.exponent += std::min(std::max(Exp, -MaxIncrement - 1), MaxIncrement);
X.normalize(RoundingMode, lfExactlyZero);
return X;
}