summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Support/APFloat.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Support/APFloat.cpp')
-rw-r--r--llvm/lib/Support/APFloat.cpp26
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;
}
OpenPOWER on IntegriCloud