diff options
author | Stephen Canon <scanon@apple.com> | 2017-03-31 20:31:33 +0000 |
---|---|---|
committer | Stephen Canon <scanon@apple.com> | 2017-03-31 20:31:33 +0000 |
commit | 157c86913a5d0a9ff9257455600689dc96333321 (patch) | |
tree | a1d4575e6a5e1a32c309ad387e38668c11cf6c93 /llvm/lib/Support/APFloat.cpp | |
parent | 34da36e74f1f5ab5874f825074f04ecde2be50f4 (diff) | |
download | bcm5719-llvm-157c86913a5d0a9ff9257455600689dc96333321.tar.gz bcm5719-llvm-157c86913a5d0a9ff9257455600689dc96333321.zip |
Fix APFloat mod (committing for simonbyrne)
The previous version was prone to intermediate rounding or overflow.
Differential Revision: https://reviews.llvm.org/D29346
llvm-svn: 299256
Diffstat (limited to 'llvm/lib/Support/APFloat.cpp')
-rw-r--r-- | llvm/lib/Support/APFloat.cpp | 42 |
1 files changed, 9 insertions, 33 deletions
diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp index dd878562a1c..904e9bf90ce 100644 --- a/llvm/lib/Support/APFloat.cpp +++ b/llvm/lib/Support/APFloat.cpp @@ -1740,44 +1740,20 @@ IEEEFloat::opStatus IEEEFloat::remainder(const IEEEFloat &rhs) { 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; } |