Index: llvm/trunk/lib/Support/APFloat.cpp =================================================================== --- llvm/trunk/lib/Support/APFloat.cpp +++ llvm/trunk/lib/Support/APFloat.cpp @@ -1740,44 +1740,20 @@ return fs; } -/* Normalized llvm frem (C fmod). - This is not currently correct in all cases. */ +/* Normalized llvm frem (C fmod). */ IEEEFloat::opStatus IEEEFloat::mod(const IEEEFloat &rhs) { opStatus fs; fs = modSpecials(rhs); - if (isFiniteNonZero() && rhs.isFiniteNonZero()) { - IEEEFloat V = *this; - unsigned int origSign = sign; - - fs = V.divide(rhs, rmNearestTiesToEven); - if (fs == opDivByZero) - return fs; - - int parts = partCount(); - integerPart *x = new integerPart[parts]; - bool ignored; - fs = V.convertToInteger(makeMutableArrayRef(x, parts), - parts * integerPartWidth, true, rmTowardZero, - &ignored); - if (fs == opInvalidOp) { - delete[] x; - return fs; - } - - fs = V.convertFromZeroExtendedInteger(x, parts * integerPartWidth, true, - rmNearestTiesToEven); - assert(fs==opOK); // should always work - - fs = V.multiply(rhs, rmNearestTiesToEven); - assert(fs==opOK || fs==opInexact); // should not overflow or underflow - + while (isFiniteNonZero() && rhs.isFiniteNonZero() && + compareAbsoluteValue(rhs) != cmpLessThan) { + IEEEFloat V = scalbn(rhs, ilogb(*this) - ilogb(rhs), rmNearestTiesToEven); + if (compareAbsoluteValue(V) == cmpLessThan) + V = scalbn(V, -1, rmNearestTiesToEven); + V.sign = sign; + fs = subtract(V, rmNearestTiesToEven); - assert(fs==opOK || fs==opInexact); // likewise - - if (isZero()) - sign = origSign; // IEEE754 requires this - delete[] x; + assert(fs==opOK); } return fs; } Index: llvm/trunk/unittests/ADT/APFloatTest.cpp =================================================================== --- llvm/trunk/unittests/ADT/APFloatTest.cpp +++ llvm/trunk/unittests/ADT/APFloatTest.cpp @@ -3192,10 +3192,73 @@ EXPECT_TRUE(APFloat(APFloat::IEEEdouble(), "0x1.c60f120d9f87cp-1").bitwiseIsEqual(Frac)); } +TEST(APFloatTest, mod) { + { + APFloat f1(APFloat::IEEEdouble(), "1.5"); + APFloat f2(APFloat::IEEEdouble(), "1.0"); + APFloat expected(APFloat::IEEEdouble(), "0.5"); + EXPECT_EQ(f1.mod(f2), APFloat::opOK); + EXPECT_TRUE(f1.bitwiseIsEqual(expected)); + } + { + APFloat f1(APFloat::IEEEdouble(), "0.5"); + APFloat f2(APFloat::IEEEdouble(), "1.0"); + APFloat expected(APFloat::IEEEdouble(), "0.5"); + EXPECT_EQ(f1.mod(f2), APFloat::opOK); + EXPECT_TRUE(f1.bitwiseIsEqual(expected)); + } + { + APFloat f1(APFloat::IEEEdouble(), "0x1.3333333333333p-2"); // 0.3 + APFloat f2(APFloat::IEEEdouble(), "0x1.47ae147ae147bp-7"); // 0.01 + APFloat expected(APFloat::IEEEdouble(), + "0x1.47ae147ae1471p-7"); // 0.009999999999999983 + EXPECT_EQ(f1.mod(f2), APFloat::opOK); + EXPECT_TRUE(f1.bitwiseIsEqual(expected)); + } + { + APFloat f1(APFloat::IEEEdouble(), "0x1p64"); // 1.8446744073709552e19 + APFloat f2(APFloat::IEEEdouble(), "1.5"); + APFloat expected(APFloat::IEEEdouble(), "1.0"); + EXPECT_EQ(f1.mod(f2), APFloat::opOK); + EXPECT_TRUE(f1.bitwiseIsEqual(expected)); + } + { + APFloat f1(APFloat::IEEEdouble(), "0x1p1000"); + APFloat f2(APFloat::IEEEdouble(), "0x1p-1000"); + APFloat expected(APFloat::IEEEdouble(), "0.0"); + EXPECT_EQ(f1.mod(f2), APFloat::opOK); + EXPECT_TRUE(f1.bitwiseIsEqual(expected)); + } + { + APFloat f1(APFloat::IEEEdouble(), "0.0"); + APFloat f2(APFloat::IEEEdouble(), "1.0"); + APFloat expected(APFloat::IEEEdouble(), "0.0"); + EXPECT_EQ(f1.mod(f2), APFloat::opOK); + EXPECT_TRUE(f1.bitwiseIsEqual(expected)); + } + { + APFloat f1(APFloat::IEEEdouble(), "1.0"); + APFloat f2(APFloat::IEEEdouble(), "0.0"); + EXPECT_EQ(f1.mod(f2), APFloat::opInvalidOp); + EXPECT_TRUE(f1.isNaN()); + } + { + APFloat f1(APFloat::IEEEdouble(), "0.0"); + APFloat f2(APFloat::IEEEdouble(), "0.0"); + EXPECT_EQ(f1.mod(f2), APFloat::opInvalidOp); + EXPECT_TRUE(f1.isNaN()); + } + { + APFloat f1 = APFloat::getInf(APFloat::IEEEdouble(), false); + APFloat f2(APFloat::IEEEdouble(), "1.0"); + EXPECT_EQ(f1.mod(f2), APFloat::opInvalidOp); + EXPECT_TRUE(f1.isNaN()); + } +} + TEST(APFloatTest, PPCDoubleDoubleAddSpecial) { using DataType = std::tuple; - DataType Data[] = { + APFloat::fltCategory, APFloat::roundingMode>; DataType Data[] = { // (1 + 0) + (-1 + 0) = fcZero std::make_tuple(0x3ff0000000000000ull, 0, 0xbff0000000000000ull, 0, APFloat::fcZero, APFloat::rmNearestTiesToEven),