diff options
author | Matt Arsenault <Matthew.Arsenault@amd.com> | 2016-03-13 05:11:51 +0000 |
---|---|---|
committer | Matt Arsenault <Matthew.Arsenault@amd.com> | 2016-03-13 05:11:51 +0000 |
commit | afa31cf4ccbb733b18df34a79bb2db710931ea82 (patch) | |
tree | 10f90750a92934e1a9b3ab5d17c1515ce6e23cc5 /llvm/lib/Support | |
parent | fc467e77b8c07b0cdef8b0193d4e99640c4eb84d (diff) | |
download | bcm5719-llvm-afa31cf4ccbb733b18df34a79bb2db710931ea82.tar.gz bcm5719-llvm-afa31cf4ccbb733b18df34a79bb2db710931ea82.zip |
APFloat: Fix scalbn handling of denormals
This was incorrect for denormals, and also failed
on longer exponent ranges.
llvm-svn: 263369
Diffstat (limited to 'llvm/lib/Support')
-rw-r--r-- | llvm/lib/Support/APFloat.cpp | 26 |
1 files changed, 14 insertions, 12 deletions
diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp index 744506ccfa8..95953b6d071 100644 --- a/llvm/lib/Support/APFloat.cpp +++ b/llvm/lib/Support/APFloat.cpp @@ -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; } |