diff --git a/include/llvm/ADT/APFloat.h b/include/llvm/ADT/APFloat.h index a29f15ce30f..be7b457054d 100644 --- a/include/llvm/ADT/APFloat.h +++ b/include/llvm/ADT/APFloat.h @@ -95,6 +95,7 @@ // APInt contains static functions implementing bignum arithmetic. #include "llvm/ADT/APInt.h" +#include "llvm/CodeGen/ValueTypes.h" namespace llvm { @@ -177,8 +178,11 @@ namespace llvm { opStatus subtract(const APFloat &, roundingMode); opStatus multiply(const APFloat &, roundingMode); opStatus divide(const APFloat &, roundingMode); + opStatus mod(const APFloat &, roundingMode); + void copySign(const APFloat &); opStatus fusedMultiplyAdd(const APFloat &, const APFloat &, roundingMode); - void changeSign(); + void changeSign(); // neg + void clearSign(); // abs /* Conversions. */ opStatus convert(const fltSemantics &, roundingMode); diff --git a/include/llvm/CodeGen/SelectionDAGNodes.h b/include/llvm/CodeGen/SelectionDAGNodes.h index d2c2fa28841..d70e3cdb478 100644 --- a/include/llvm/CodeGen/SelectionDAGNodes.h +++ b/include/llvm/CodeGen/SelectionDAGNodes.h @@ -1147,33 +1147,26 @@ public: class ConstantFPSDNode : public SDNode { APFloat Value; virtual void ANCHOR(); // Out-of-line virtual method to give class a home. + // Longterm plan: replace all uses of getValue with getValueAPF, remove + // getValue, rename getValueAPF to getValue. protected: friend class SelectionDAG; - ConstantFPSDNode(bool isTarget, double val, MVT::ValueType VT) - : SDNode(isTarget ? ISD::TargetConstantFP : ISD::ConstantFP, - getSDVTList(VT)), - Value(VT==MVT::f64 ? APFloat(val) : APFloat((float)val)) { - } ConstantFPSDNode(bool isTarget, const APFloat& val, MVT::ValueType VT) : SDNode(isTarget ? ISD::TargetConstantFP : ISD::ConstantFP, getSDVTList(VT)), Value(val) { } public: - // Longterm plan: replace all uses of getValue with getValueAPF, remove - // getValue, rename getValueAPF to getValue. - double getValue() const { - if ( getValueType(0)==MVT::f64) - return Value.convertToDouble(); - else - return Value.convertToFloat(); - } const APFloat& getValueAPF() const { return Value; } /// isExactlyValue - We don't rely on operator== working on double values, as /// it returns true for things that are clearly not equal, like -0.0 and 0.0. /// As such, this method can be used to do an exact bit-for-bit comparison of /// two floating point values. + + /// We leave the version with the double argument here because it's just so + /// convenient to write "2.0" and the like. Without this function we'd + /// have to duplicate its logic everywhere it's called. bool isExactlyValue(double V) const { if (getValueType(0)==MVT::f64) return isExactlyValue(APFloat(V)); diff --git a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 0514bc181be..dae4e2102d6 100644 --- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -410,9 +410,11 @@ static SDOperand GetNegatedExpression(SDOperand Op, SelectionDAG &DAG, assert(Depth <= 6 && "GetNegatedExpression doesn't match isNegatibleForFree"); switch (Op.getOpcode()) { default: assert(0 && "Unknown code"); - case ISD::ConstantFP: - return DAG.getConstantFP(-cast(Op)->getValue(), - Op.getValueType()); + case ISD::ConstantFP: { + APFloat V = cast(Op)->getValueAPF(); + V.changeSign(); + return DAG.getConstantFP(V, Op.getValueType()); + } case ISD::FADD: // FIXME: determine better conditions for this xform. assert(UnsafeFPMath); @@ -432,7 +434,7 @@ static SDOperand GetNegatedExpression(SDOperand Op, SelectionDAG &DAG, // -(0-B) -> B if (ConstantFPSDNode *N0CFP = dyn_cast(Op.getOperand(0))) - if (N0CFP->getValue() == 0.0) + if (N0CFP->getValueAPF().isZero()) return Op.getOperand(1); // -(A-B) -> B-A @@ -3080,7 +3082,7 @@ SDOperand DAGCombiner::visitFSUB(SDNode *N) { if (N0CFP && N1CFP) return DAG.getNode(ISD::FSUB, VT, N0, N1); // fold (0-B) -> -B - if (UnsafeFPMath && N0CFP && N0CFP->getValue() == 0.0) { + if (UnsafeFPMath && N0CFP && N0CFP->getValueAPF().isZero()) { if (isNegatibleForFree(N1)) return GetNegatedExpression(N1, DAG); return DAG.getNode(ISD::FNEG, VT, N1); @@ -3304,7 +3306,7 @@ SDOperand DAGCombiner::visitFP_ROUND_INREG(SDNode *N) { // fold (fp_round_inreg c1fp) -> c1fp if (N0CFP) { - SDOperand Round = DAG.getConstantFP(N0CFP->getValue(), EVT); + SDOperand Round = DAG.getConstantFP(N0CFP->getValueAPF(), EVT); return DAG.getNode(ISD::FP_EXTEND, VT, Round); } return SDOperand(); @@ -4207,7 +4209,7 @@ SDOperand DAGCombiner::SimplifyVBinOp(SDNode *N) { if ((RHSOp.getOpcode() == ISD::Constant && cast(RHSOp.Val)->isNullValue()) || (RHSOp.getOpcode() == ISD::ConstantFP && - !cast(RHSOp.Val)->getValue())) + cast(RHSOp.Val)->getValueAPF().isZero())) break; } Ops.push_back(DAG.getNode(N->getOpcode(), EltType, LHSOp, RHSOp)); diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 156c73959f7..05d5ec0ec20 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -727,7 +727,8 @@ SDOperand SelectionDAG::getConstantFP(const APFloat& V, MVT::ValueType VT, if (!MVT::isVector(VT)) return SDOperand(N, 0); if (!N) { - N = new ConstantFPSDNode(isTarget, Val, EltVT); + N = new ConstantFPSDNode(isTarget, + isDouble ? APFloat(Val) : APFloat((float)Val), EltVT); CSEMap.InsertNode(N, IP); AllNodes.push_back(N); } @@ -1665,27 +1666,44 @@ SDOperand SelectionDAG::getNode(unsigned Opcode, MVT::ValueType VT, } } - // Constant fold unary operations with an floating point constant operand. - if (ConstantFPSDNode *C = dyn_cast(Operand.Val)) + // Constant fold unary operations with a floating point constant operand. + if (ConstantFPSDNode *C = dyn_cast(Operand.Val)) { + APFloat V = C->getValueAPF(); // make copy switch (Opcode) { case ISD::FNEG: - return getConstantFP(-C->getValue(), VT); + V.changeSign(); + return getConstantFP(V, VT); case ISD::FABS: - return getConstantFP(fabs(C->getValue()), VT); + V.clearSign(); + return getConstantFP(V, VT); case ISD::FP_ROUND: case ISD::FP_EXTEND: - return getConstantFP(C->getValue(), VT); + // This can return overflow, underflow, or inexact; we don't care. + // FIXME need to be more flexible about rounding mode. + (void) V.convert(VT==MVT::f32 ? APFloat::IEEEsingle : + APFloat::IEEEdouble, + APFloat::rmNearestTiesToEven); + return getConstantFP(V, VT); case ISD::FP_TO_SINT: - return getConstant((int64_t)C->getValue(), VT); - case ISD::FP_TO_UINT: - return getConstant((uint64_t)C->getValue(), VT); + case ISD::FP_TO_UINT: { + integerPart x; + assert(integerPartWidth >= 64); + // FIXME need to be more flexible about rounding mode. + APFloat::opStatus s = V.convertToInteger(&x, 64U, + Opcode==ISD::FP_TO_SINT, + APFloat::rmTowardZero); + if (s==APFloat::opInvalidOp) // inexact is OK, in fact usual + break; + return getConstant(x, VT); + } case ISD::BIT_CONVERT: if (VT == MVT::i32 && C->getValueType(0) == MVT::f32) - return getConstant(FloatToBits(C->getValue()), VT); + return getConstant(FloatToBits(V.convertToFloat()), VT); else if (VT == MVT::i64 && C->getValueType(0) == MVT::f64) - return getConstant(DoubleToBits(C->getValue()), VT); + return getConstant(DoubleToBits(V.convertToDouble()), VT); break; } + } unsigned OpOpcode = Operand.Val->getOpcode(); switch (Opcode) { @@ -1914,29 +1932,37 @@ SDOperand SelectionDAG::getNode(unsigned Opcode, MVT::ValueType VT, ConstantFPSDNode *N2CFP = dyn_cast(N2.Val); if (N1CFP) { if (N2CFP) { - double C1 = N1CFP->getValue(), C2 = N2CFP->getValue(); + APFloat V1 = N1CFP->getValueAPF(), V2 = N2CFP->getValueAPF(); + APFloat::opStatus s; switch (Opcode) { - case ISD::FADD: return getConstantFP(C1 + C2, VT); - case ISD::FSUB: return getConstantFP(C1 - C2, VT); - case ISD::FMUL: return getConstantFP(C1 * C2, VT); + case ISD::FADD: + s = V1.add(V2, APFloat::rmNearestTiesToEven); + if (s!=APFloat::opInvalidOp) + return getConstantFP(V1, VT); + break; + case ISD::FSUB: + s = V1.subtract(V2, APFloat::rmNearestTiesToEven); + if (s!=APFloat::opInvalidOp) + return getConstantFP(V1, VT); + break; + case ISD::FMUL: + s = V1.multiply(V2, APFloat::rmNearestTiesToEven); + if (s!=APFloat::opInvalidOp) + return getConstantFP(V1, VT); + break; case ISD::FDIV: - if (C2) return getConstantFP(C1 / C2, VT); + s = V1.divide(V2, APFloat::rmNearestTiesToEven); + if (s!=APFloat::opInvalidOp && s!=APFloat::opDivByZero) + return getConstantFP(V1, VT); break; case ISD::FREM : - if (C2) return getConstantFP(fmod(C1, C2), VT); + s = V1.mod(V2, APFloat::rmNearestTiesToEven); + if (s!=APFloat::opInvalidOp && s!=APFloat::opDivByZero) + return getConstantFP(V1, VT); break; - case ISD::FCOPYSIGN: { - union { - double F; - uint64_t I; - } u1; - u1.F = C1; - if (int64_t(DoubleToBits(C2)) < 0) // Sign bit of RHS set? - u1.I |= 1ULL << 63; // Set the sign bit of the LHS. - else - u1.I &= (1ULL << 63)-1; // Clear the sign bit of the LHS. - return getConstantFP(u1.F, VT); - } + case ISD::FCOPYSIGN: + V1.copySign(V2); + return getConstantFP(V1, VT); default: break; } } else { // Cannonicalize constant to RHS if commutative @@ -3688,7 +3714,9 @@ void SDNode::dump(const SelectionDAG *G) const { if (const ConstantSDNode *CSDN = dyn_cast(this)) { cerr << "<" << CSDN->getValue() << ">"; } else if (const ConstantFPSDNode *CSDN = dyn_cast(this)) { - cerr << "<" << CSDN->getValue() << ">"; + cerr << "<" << (&CSDN->getValueAPF().getSemantics()==&APFloat::IEEEsingle ? + CSDN->getValueAPF().convertToFloat() : + CSDN->getValueAPF().convertToDouble()) << ">"; } else if (const GlobalAddressSDNode *GADN = dyn_cast(this)) { int offset = GADN->getOffset();