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