Skip to content

Commit

Permalink
[libc] Fix the overflow check condition of ldexp.
Browse files Browse the repository at this point in the history
Targeted tests have been added.

Reviewed By: lntue

Differential Revision: https://reviews.llvm.org/D91752
  • Loading branch information
Siva Chandra Reddy committed Nov 19, 2020
1 parent 8ab2353 commit 4d8dede
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 5 deletions.
24 changes: 24 additions & 0 deletions libc/test/src/math/LdExpTest.h
Expand Up @@ -112,6 +112,30 @@ class LdExpTestTemplate : public __llvm_libc::testing::Test {
T x = NormalFloat(-FPBits::exponentBias + 1, 2 * NormalFloat::one - 1, 0);
ASSERT_FP_EQ(func(x, -1), x / 2);
ASSERT_FP_EQ(func(-x, -1), -x / 2);

// Start with a normal number high exponent but pass a very low number for
// exp. The result should be a subnormal number.
x = NormalFloat(FPBits::exponentBias, NormalFloat::one, 0);
int exp = -FPBits::maxExponent - 5;
T result = func(x, exp);
FPBits resultBits(result);
ASSERT_FALSE(resultBits.isZero());
// Verify that the result is indeed subnormal.
ASSERT_EQ(resultBits.exponent, uint16_t(0));
// But if the exp is so less that normalization leads to zero, then
// the result should be zero.
result = func(x, -FPBits::maxExponent - int(mantissaWidth) - 5);
ASSERT_TRUE(FPBits(result).isZero());

// Start with a subnormal number but pass a very high number for exponent.
// The result should not be infinity.
x = NormalFloat(-FPBits::exponentBias + 1, NormalFloat::one >> 10, 0);
exp = FPBits::maxExponent + 5;
ASSERT_EQ(isinf(func(x, exp)), 0);
// But if the exp is large enough to oversome than the normalization shift,
// then it should result in infinity.
exp = FPBits::maxExponent + 15;
ASSERT_NE(isinf(func(x, exp)), 0);
}
};

Expand Down
13 changes: 8 additions & 5 deletions libc/utils/FPUtil/ManipulationFunctions.h
Expand Up @@ -124,14 +124,17 @@ static inline T ldexp(T x, int exp) {
return x;

// NormalFloat uses int32_t to store the true exponent value. We should ensure
// that adding |exp| to it does not lead to integer rollover. But, we |exp|
// that adding |exp| to it does not lead to integer rollover. But, if |exp|
// value is larger the exponent range for type T, then we can return infinity
// early.
if (exp > FPBits<T>::maxExponent)
// early. Because the result of the ldexp operation can be a subnormal number,
// we need to accommodate the (mantissaWidht + 1) worth of shift in
// calculating the limit.
int expLimit = FPBits<T>::maxExponent + MantissaWidth<T>::value + 1;
if (exp > expLimit)
return bits.sign ? FPBits<T>::negInf() : FPBits<T>::inf();

// Similarly on the negative side.
if (exp < -FPBits<T>::maxExponent)
// Similarly on the negative side we return zero early if |exp| is too small.
if (exp < -expLimit)
return bits.sign ? FPBits<T>::negZero() : FPBits<T>::zero();

// For all other values, NormalFloat to T conversion handles it the right way.
Expand Down

0 comments on commit 4d8dede

Please sign in to comment.