summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Support/APFloat.cpp
diff options
context:
space:
mode:
authorStephen Canon <scanon@apple.com>2017-03-31 20:31:33 +0000
committerStephen Canon <scanon@apple.com>2017-03-31 20:31:33 +0000
commit157c86913a5d0a9ff9257455600689dc96333321 (patch)
treea1d4575e6a5e1a32c309ad387e38668c11cf6c93 /llvm/lib/Support/APFloat.cpp
parent34da36e74f1f5ab5874f825074f04ecde2be50f4 (diff)
downloadbcm5719-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.cpp42
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;
}
OpenPOWER on IntegriCloud