diff options
Diffstat (limited to 'llvm/unittests/ADT/APFloatTest.cpp')
-rw-r--r-- | llvm/unittests/ADT/APFloatTest.cpp | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/llvm/unittests/ADT/APFloatTest.cpp b/llvm/unittests/ADT/APFloatTest.cpp index c2d99f3..0935619 100644 --- a/llvm/unittests/ADT/APFloatTest.cpp +++ b/llvm/unittests/ADT/APFloatTest.cpp @@ -47,6 +47,37 @@ static std::string convertToString(double d, unsigned Prec, unsigned Pad, return std::string(Buffer.data(), Buffer.size()); } +namespace llvm { +namespace detail { +class IEEEFloatUnitTestHelper { +public: + static void runTest(bool subtract, bool lhsSign, + APFloat::ExponentType lhsExponent, + APFloat::integerPart lhsSignificand, bool rhsSign, + APFloat::ExponentType rhsExponent, + APFloat::integerPart rhsSignificand, bool expectedSign, + APFloat::ExponentType expectedExponent, + APFloat::integerPart expectedSignificand, + lostFraction expectedLoss) { + // `addOrSubtractSignificand` only uses the sign, exponent and significand + IEEEFloat lhs(1.0); + lhs.sign = lhsSign; + lhs.exponent = lhsExponent; + lhs.significand.part = lhsSignificand; + IEEEFloat rhs(1.0); + rhs.sign = rhsSign; + rhs.exponent = rhsExponent; + rhs.significand.part = rhsSignificand; + lostFraction resultLoss = lhs.addOrSubtractSignificand(rhs, subtract); + EXPECT_EQ(resultLoss, expectedLoss); + EXPECT_EQ(lhs.sign, expectedSign); + EXPECT_EQ(lhs.exponent, expectedExponent); + EXPECT_EQ(lhs.significand.part, expectedSignificand); + } +}; +} // namespace detail +} // namespace llvm + namespace { TEST(APFloatTest, isSignaling) { @@ -560,6 +591,104 @@ TEST(APFloatTest, FMA) { EXPECT_EQ(-8.85242279E-41f, f1.convertToFloat()); } + // The `addOrSubtractSignificand` can be considered to have 9 possible cases + // when subtracting: all combinations of {cmpLessThan, cmpGreaterThan, + // cmpEqual} and {no loss, loss from lhs, loss from rhs}. Test each reachable + // case here. + + // Regression test for failing the `assert(!carry)` in + // `addOrSubtractSignificand` and normalizing the exponent even when the + // significand is zero if there is a lost fraction. + // This tests cmpEqual, loss from lhs + { + APFloat f1(-1.4728589E-38f); + APFloat f2(3.7105144E-6f); + APFloat f3(5.5E-44f); + f1.fusedMultiplyAdd(f2, f3, APFloat::rmNearestTiesToEven); + EXPECT_EQ(-0.0f, f1.convertToFloat()); + } + + // Test cmpGreaterThan, no loss + { + APFloat f1(2.0f); + APFloat f2(2.0f); + APFloat f3(-3.5f); + f1.fusedMultiplyAdd(f2, f3, APFloat::rmNearestTiesToEven); + EXPECT_EQ(0.5f, f1.convertToFloat()); + } + + // Test cmpLessThan, no loss + { + APFloat f1(2.0f); + APFloat f2(2.0f); + APFloat f3(-4.5f); + f1.fusedMultiplyAdd(f2, f3, APFloat::rmNearestTiesToEven); + EXPECT_EQ(-0.5f, f1.convertToFloat()); + } + + // Test cmpEqual, no loss + { + APFloat f1(2.0f); + APFloat f2(2.0f); + APFloat f3(-4.0f); + f1.fusedMultiplyAdd(f2, f3, APFloat::rmNearestTiesToEven); + EXPECT_EQ(0.0f, f1.convertToFloat()); + } + + // Test cmpLessThan, loss from lhs + { + APFloat f1(2.0000002f); + APFloat f2(2.0000002f); + APFloat f3(-32.0f); + f1.fusedMultiplyAdd(f2, f3, APFloat::rmNearestTiesToEven); + EXPECT_EQ(-27.999998f, f1.convertToFloat()); + } + + // Test cmpGreaterThan, loss from rhs + { + APFloat f1(1e10f); + APFloat f2(1e10f); + APFloat f3(-2.0000002f); + f1.fusedMultiplyAdd(f2, f3, APFloat::rmNearestTiesToEven); + EXPECT_EQ(1e20f, f1.convertToFloat()); + } + + // Test cmpGreaterThan, loss from lhs + { + APFloat f1(1e-36f); + APFloat f2(0.0019531252f); + APFloat f3(-1e-45f); + f1.fusedMultiplyAdd(f2, f3, APFloat::rmNearestTiesToEven); + EXPECT_EQ(1.953124e-39f, f1.convertToFloat()); + } + + // {cmpEqual, cmpLessThan} with loss from rhs can't occur for the usage in + // `fusedMultiplyAdd` as `multiplySignificand` normalises the MSB of lhs to + // one bit below the top. + + // Test cases from #104984 + { + APFloat f1(0.24999998f); + APFloat f2(2.3509885e-38f); + APFloat f3(-1e-45f); + f1.fusedMultiplyAdd(f2, f3, APFloat::rmNearestTiesToEven); + EXPECT_EQ(5.87747e-39f, f1.convertToFloat()); + } + { + APFloat f1(4.4501477170144023e-308); + APFloat f2(0.24999999999999997); + APFloat f3(-8.475904604373977e-309); + f1.fusedMultiplyAdd(f2, f3, APFloat::rmNearestTiesToEven); + EXPECT_EQ(2.64946468816203e-309, f1.convertToDouble()); + } + { + APFloat f1(APFloat::IEEEhalf(), APInt(16, 0x8fffu)); + APFloat f2(APFloat::IEEEhalf(), APInt(16, 0x2bffu)); + APFloat f3(APFloat::IEEEhalf(), APInt(16, 0x0172u)); + f1.fusedMultiplyAdd(f2, f3, APFloat::rmNearestTiesToEven); + EXPECT_EQ(0x808eu, f1.bitcastToAPInt().getZExtValue()); + } + // Test using only a single instance of APFloat. { APFloat F(1.5); @@ -8168,4 +8297,54 @@ TEST(APFloatTest, Float4E2M1FNToFloat) { EXPECT_TRUE(SmallestDenorm.isDenormal()); EXPECT_EQ(0x0.8p0, SmallestDenorm.convertToFloat()); } + +TEST(APFloatTest, AddOrSubtractSignificand) { + typedef detail::IEEEFloatUnitTestHelper Helper; + // Test cases are all combinations of: + // {equal exponents, LHS larger exponent, RHS larger exponent} + // {equal significands, LHS larger significand, RHS larger significand} + // {no loss, loss} + + // Equal exponents (loss cannot occur as their is no shifting) + Helper::runTest(true, false, 1, 0x10, false, 1, 0x5, false, 1, 0xb, + lfExactlyZero); + Helper::runTest(false, false, -2, 0x20, true, -2, 0x20, false, -2, 0, + lfExactlyZero); + Helper::runTest(false, true, 3, 0x20, false, 3, 0x30, false, 3, 0x10, + lfExactlyZero); + + // LHS larger exponent + // LHS significand greater after shitfing + Helper::runTest(true, false, 7, 0x100, false, 3, 0x100, false, 6, 0x1e0, + lfExactlyZero); + Helper::runTest(true, false, 7, 0x100, false, 3, 0x101, false, 6, 0x1df, + lfMoreThanHalf); + // Significands equal after shitfing + Helper::runTest(true, false, 7, 0x100, false, 3, 0x1000, false, 6, 0, + lfExactlyZero); + Helper::runTest(true, false, 7, 0x100, false, 3, 0x1001, true, 6, 0, + lfLessThanHalf); + // RHS significand greater after shitfing + Helper::runTest(true, false, 7, 0x100, false, 3, 0x10000, true, 6, 0x1e00, + lfExactlyZero); + Helper::runTest(true, false, 7, 0x100, false, 3, 0x10001, true, 6, 0x1e00, + lfLessThanHalf); + + // RHS larger exponent + // RHS significand greater after shitfing + Helper::runTest(true, false, 3, 0x100, false, 7, 0x100, true, 6, 0x1e0, + lfExactlyZero); + Helper::runTest(true, false, 3, 0x101, false, 7, 0x100, true, 6, 0x1df, + lfMoreThanHalf); + // Significands equal after shitfing + Helper::runTest(true, false, 3, 0x1000, false, 7, 0x100, false, 6, 0, + lfExactlyZero); + Helper::runTest(true, false, 3, 0x1001, false, 7, 0x100, false, 6, 0, + lfLessThanHalf); + // LHS significand greater after shitfing + Helper::runTest(true, false, 3, 0x10000, false, 7, 0x100, false, 6, 0x1e00, + lfExactlyZero); + Helper::runTest(true, false, 3, 0x10001, false, 7, 0x100, false, 6, 0x1e00, + lfLessThanHalf); +} } // namespace |