summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Support/APFloat.cpp
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
commitb5721632ee359daa60371b1c00f5758a05fd47ad (patch)
tree8dcbe51c874d8520cfdda9458ee647f172477f26 /llvm/lib/Support/APFloat.cpp
parentf6009ed9696e6caa31e3bb61458fa108783d4b13 (diff)
downloadbcm5719-llvm-b5721632ee359daa60371b1c00f5758a05fd47ad.tar.gz
bcm5719-llvm-b5721632ee359daa60371b1c00f5758a05fd47ad.zip
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. llvm-svn: 62645
Diffstat (limited to 'llvm/lib/Support/APFloat.cpp')
-rw-r--r--llvm/lib/Support/APFloat.cpp86
1 files changed, 63 insertions, 23 deletions
diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp
index 151f9d5b392..c296770385f 100644
--- a/llvm/lib/Support/APFloat.cpp
+++ b/llvm/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;
}
OpenPOWER on IntegriCloud