aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Support
diff options
context:
space:
mode:
authorDale Johannesen <dalej@apple.com>2009-01-21 00:35:19 +0000
committerDale Johannesen <dalej@apple.com>2009-01-21 00:35:19 +0000
commited6af24e146a5d358115123f0d2be694c1fa3a84 (patch)
treed5c56e9057df227684d86e572915e0b5defdda95 /lib/Support
parent6cf7c390ecf33cdbe9e65d230e4f61ac548893e6 (diff)
downloadexternal_llvm-ed6af24e146a5d358115123f0d2be694c1fa3a84.zip
external_llvm-ed6af24e146a5d358115123f0d2be694c1fa3a84.tar.gz
external_llvm-ed6af24e146a5d358115123f0d2be694c1fa3a84.tar.bz2
Make special cases (0 inf nan) work for frem.
Besides APFloat, this involved removing code from two places that thought they knew the result of frem(0., x) but were wrong. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@62645 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Support')
-rw-r--r--lib/Support/APFloat.cpp86
1 files changed, 63 insertions, 23 deletions
diff --git a/lib/Support/APFloat.cpp b/lib/Support/APFloat.cpp
index 151f9d5..c296770 100644
--- a/lib/Support/APFloat.cpp
+++ b/lib/Support/APFloat.cpp
@@ -1405,6 +1405,42 @@ APFloat::divideSpecials(const APFloat &rhs)
}
}
+APFloat::opStatus
+APFloat::modSpecials(const APFloat &rhs)
+{
+ switch(convolve(category, rhs.category)) {
+ default:
+ assert(0);
+
+ case convolve(fcNaN, fcZero):
+ case convolve(fcNaN, fcNormal):
+ case convolve(fcNaN, fcInfinity):
+ case convolve(fcNaN, fcNaN):
+ case convolve(fcZero, fcInfinity):
+ case convolve(fcZero, fcNormal):
+ case convolve(fcNormal, fcInfinity):
+ return opOK;
+
+ case convolve(fcZero, fcNaN):
+ case convolve(fcNormal, fcNaN):
+ case convolve(fcInfinity, fcNaN):
+ category = fcNaN;
+ copySignificand(rhs);
+ return opOK;
+
+ case convolve(fcNormal, fcZero):
+ case convolve(fcInfinity, fcZero):
+ case convolve(fcInfinity, fcNormal):
+ case convolve(fcInfinity, fcInfinity):
+ case convolve(fcZero, fcZero):
+ makeNaN();
+ return opInvalidOp;
+
+ case convolve(fcNormal, fcNormal):
+ return opOK;
+ }
+}
+
/* Change sign. */
void
APFloat::changeSign()
@@ -1557,35 +1593,39 @@ APFloat::opStatus
APFloat::mod(const APFloat &rhs, roundingMode rounding_mode)
{
opStatus fs;
- APFloat V = *this;
- unsigned int origSign = sign;
-
assertArithmeticOK(*semantics);
- fs = V.divide(rhs, rmNearestTiesToEven);
- if (fs == opDivByZero)
- return fs;
+ fs = modSpecials(rhs);
- int parts = partCount();
- integerPart *x = new integerPart[parts];
- bool ignored;
- fs = V.convertToInteger(x, parts * integerPartWidth, true,
- rmTowardZero, &ignored);
- if (fs==opInvalidOp)
- return fs;
+ if (category == fcNormal && rhs.category == fcNormal) {
+ APFloat V = *this;
+ unsigned int origSign = sign;
- fs = V.convertFromZeroExtendedInteger(x, parts * integerPartWidth, true,
- rmNearestTiesToEven);
- assert(fs==opOK); // should always work
+ fs = V.divide(rhs, rmNearestTiesToEven);
+ if (fs == opDivByZero)
+ return fs;
- fs = V.multiply(rhs, rounding_mode);
- assert(fs==opOK || fs==opInexact); // should not overflow or underflow
+ int parts = partCount();
+ integerPart *x = new integerPart[parts];
+ bool ignored;
+ fs = V.convertToInteger(x, parts * integerPartWidth, true,
+ rmTowardZero, &ignored);
+ if (fs==opInvalidOp)
+ return fs;
- fs = subtract(V, rounding_mode);
- assert(fs==opOK || fs==opInexact); // likewise
+ fs = V.convertFromZeroExtendedInteger(x, parts * integerPartWidth, true,
+ rmNearestTiesToEven);
+ assert(fs==opOK); // should always work
- if (isZero())
- sign = origSign; // IEEE754 requires this
- delete[] x;
+ fs = V.multiply(rhs, rounding_mode);
+ assert(fs==opOK || fs==opInexact); // should not overflow or underflow
+
+ fs = subtract(V, rounding_mode);
+ assert(fs==opOK || fs==opInexact); // likewise
+
+ if (isZero())
+ sign = origSign; // IEEE754 requires this
+ delete[] x;
+ }
return fs;
}