Chris / Jeff,

No need to file a bug. Here's a patch that I think solves this. Could
you (preferably both) review this to make sure I've interpreted the IEEE
754 standard correctly?

Thanks,

Reid.

On Thu, 2007-03-22 at 18:42 -0800, Chris Lattner wrote:
> On Thu, 22 Mar 2007, Jeff Cohen wrote:
> > Jeff Cohen wrote:
> >>  The standard apparently doesn't explicitly handle 0/0, but the position 
> >> of 
> >>  the IEEE appears to be that it should yield a NaN of the appropriate 
> >> sign. 
> >>  See http://standards.ieee.org/reading/ieee/interp/754-1985.html
> >
> > OK, it does explicitly handle it.  My reading comprehension seems to be 
> > lacking right now :(
> >
> > http://754r.ucbtest.org/standards/754xml.html#invalid-exception
> >
> > The above lists all operations that yield a NaN.
> 
> Sounds like a bug, please file it or fix it :)  The code in question is 
> VMCore/ConstantFold.cpp:654.  It should produce the appropriately signed 
> NaN instead of Inf.
> 
> -Chris
> 
Index: ConstantFold.cpp
===================================================================
RCS file: /var/cvs/llvm/llvm/lib/VMCore/ConstantFold.cpp,v
retrieving revision 1.147
diff -t -d -u -p -5 -r1.147 ConstantFold.cpp
--- ConstantFold.cpp	3 Mar 2007 08:32:46 -0000	1.147
+++ ConstantFold.cpp	23 Mar 2007 03:07:48 -0000
@@ -440,10 +440,42 @@ static Constant *EvalVectorOp(const Cons
     Res.push_back(FP(const_cast<Constant*>(V1->getOperand(i)),
                      const_cast<Constant*>(V2->getOperand(i))));
   return ConstantVector::get(Res);
 }
 
+/// checkDivision - This function handles IEEE 754 rules for various div by zero
+/// and illegal operations related to divide. This is used to ensure we return
+/// infinity or NaN for certain divisions by ConstantFoldBinaryInstruction for 
+/// the FDiv and FRem cases.
+static Constant* checkDivision(const ConstantFP* C1, const ConstantFP* C2, 
+                               bool isRem = false) {
+
+  double Inf = std::numeric_limits<double>::infinity();
+
+  /// IEEE 754, Section 7.2 Division By Zero
+  if (C2->isExactlyValue(0.0) && !C1->isExactlyValue(Inf) && 
+      !C1->isExactlyValue(-Inf) && !C1->isExactlyValue(0.0) && 
+      !C1->isExactlyValue(-0.0))
+    return ConstantFP::get(C1->getType(), (C1->getValue() < 0.0 ?  -Inf : Inf));
+
+  if (isRem) {
+    // IEEE 754, Section 7.1 Invalid Operation, Item #5
+    if (C2->isExactlyValue(0.0) || C2->isExactlyValue(-0.0) ||
+        C1->isExactlyValue(Inf) || C1->isExactlyValue(-Inf))
+      return ConstantFP::get(C1->getType(), 
+                             std::numeric_limits<double>::quiet_NaN());
+  } else {
+    // IEEE 754, Section 7.1 Invalid Operation, Item #4
+    if ((C1->isExactlyValue(0.0) || C1->isExactlyValue(-0.0)) &&
+        (C2->isExactlyValue(0.0) || C2->isExactlyValue(-0.0)))
+      return ConstantFP::get(C1->getType(),
+                             std::numeric_limits<double>::quiet_NaN());
+  }
+
+  return 0;
+}
+
 Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode,
                                               const Constant *C1,
                                               const Constant *C2) {
   // Handle UndefValue up front
   if (isa<UndefValue>(C1) || isa<UndefValue>(C2)) {
@@ -649,20 +681,16 @@ Constant *llvm::ConstantFoldBinaryInstru
       case Instruction::Sub:     
         return ConstantFP::get(CFP1->getType(), C1Val - C2Val);
       case Instruction::Mul:     
         return ConstantFP::get(CFP1->getType(), C1Val * C2Val);
       case Instruction::FDiv:
-        if (CFP2->isExactlyValue(0.0)) 
-          return ConstantFP::get(CFP1->getType(),
-                                 std::numeric_limits<double>::infinity());
-        if (CFP2->isExactlyValue(-0.0))
-          return ConstantFP::get(CFP1->getType(),
-                                 -std::numeric_limits<double>::infinity());
+        if (Constant *C = checkDivision(CFP1, CFP2, false))
+          return C;
         return ConstantFP::get(CFP1->getType(), C1Val / C2Val);
       case Instruction::FRem:
-        if (CFP2->isNullValue()) 
-          return 0;
+        if (Constant *C = checkDivision(CFP1, CFP2, true))
+          return C;
         return ConstantFP::get(CFP1->getType(), std::fmod(C1Val, C2Val));
       }
     }
   } else if (const ConstantVector *CP1 = dyn_cast<ConstantVector>(C1)) {
     if (const ConstantVector *CP2 = dyn_cast<ConstantVector>(C2)) {
_______________________________________________
llvm-commits mailing list
llvm-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits

Reply via email to