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
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::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::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;
 }
 
diff --git a/lib/Transforms/Scalar/InstructionCombining.cpp b/lib/Transforms/Scalar/InstructionCombining.cpp
index c02fabd..f038cd0 100644
--- a/lib/Transforms/Scalar/InstructionCombining.cpp
+++ b/lib/Transforms/Scalar/InstructionCombining.cpp
@@ -2954,11 +2954,6 @@
 Instruction *InstCombiner::commonRemTransforms(BinaryOperator &I) {
   Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
 
-  // 0 % X == 0 for integer, we don't need to preserve faults!
-  if (Constant *LHS = dyn_cast<Constant>(Op0))
-    if (LHS->isNullValue())
-      return ReplaceInstUsesWith(I, Constant::getNullValue(I.getType()));
-
   if (isa<UndefValue>(Op0)) {             // undef % X -> 0
     if (I.getType()->isFPOrFPVector())
       return ReplaceInstUsesWith(I, Op0);  // X % undef -> undef (could be SNaN)
@@ -2984,6 +2979,11 @@
   if (Instruction *common = commonRemTransforms(I))
     return common;
 
+  // 0 % X == 0 for integer, we don't need to preserve faults!
+  if (Constant *LHS = dyn_cast<Constant>(Op0))
+    if (LHS->isNullValue())
+      return ReplaceInstUsesWith(I, Constant::getNullValue(I.getType()));
+
   if (ConstantInt *RHS = dyn_cast<ConstantInt>(Op1)) {
     // X % 0 == undef, we don't need to preserve faults!
     if (RHS->equalsInt(0))
diff --git a/lib/VMCore/ConstantFold.cpp b/lib/VMCore/ConstantFold.cpp
index 0c5297f..5c1578f 100644
--- a/lib/VMCore/ConstantFold.cpp
+++ b/lib/VMCore/ConstantFold.cpp
@@ -802,16 +802,6 @@
         (void)C3V.divide(C2V, APFloat::rmNearestTiesToEven);
         return ConstantFP::get(C3V);
       case Instruction::FRem:
-        if (C2V.isZero()) {
-          // IEEE 754, Section 7.1, #5
-          if (CFP1->getType() == Type::DoubleTy)
-            return ConstantFP::get(APFloat(std::numeric_limits<double>::
-                                           quiet_NaN()));
-          if (CFP1->getType() == Type::FloatTy)
-            return ConstantFP::get(APFloat(std::numeric_limits<float>::
-                                           quiet_NaN()));
-          break;
-        }
         (void)C3V.mod(C2V, APFloat::rmNearestTiesToEven);
         return ConstantFP::get(C3V);
       }