Add mod, copysign, abs operations to APFloat.
authorDale Johannesen <dalej@apple.com>
Fri, 31 Aug 2007 23:34:27 +0000 (23:34 +0000)
committerDale Johannesen <dalej@apple.com>
Fri, 31 Aug 2007 23:34:27 +0000 (23:34 +0000)
Implement some constant folding in SelectionDAG and
DAGCombiner using APFloat.  Remove double versions
of constructor and getValue from ConstantFPSDNode.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@41664 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/ADT/APFloat.h
include/llvm/CodeGen/SelectionDAGNodes.h
lib/CodeGen/SelectionDAG/DAGCombiner.cpp
lib/CodeGen/SelectionDAG/SelectionDAG.cpp

index a29f15ce30fb3855a654c6cfd9136bd6c3a332cf..be7b457054d0c44f7e96efaf67d44b5360607653 100644 (file)
@@ -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);
index d2c2fa288414bb0548631e573046edbb4a83f38b..d70e3cdb478002e9909289d5d628dcdab2a8c059 100644 (file)
@@ -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));
index 0514bc181bec0dfcd37d8e83e516931713116013..dae4e2102d6277c9cd5a17229490701dc2e53adf 100644 (file)
@@ -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<ConstantFPSDNode>(Op)->getValue(),
-                             Op.getValueType());
+  case ISD::ConstantFP: {
+    APFloat V = cast<ConstantFPSDNode>(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<ConstantFPSDNode>(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<ConstantSDNode>(RHSOp.Val)->isNullValue()) ||
             (RHSOp.getOpcode() == ISD::ConstantFP &&
-             !cast<ConstantFPSDNode>(RHSOp.Val)->getValue()))
+             cast<ConstantFPSDNode>(RHSOp.Val)->getValueAPF().isZero()))
           break;
       }
       Ops.push_back(DAG.getNode(N->getOpcode(), EltType, LHSOp, RHSOp));
index 156c73959f7c2b2292dbee0be276719841e5f06f..05d5ec0ec20417d940ad91ad5f1ad7bb5dd06b51 100644 (file)
@@ -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<ConstantFPSDNode>(Operand.Val))
+  // Constant fold unary operations with a floating point constant operand.
+  if (ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(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<ConstantFPSDNode>(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<ConstantSDNode>(this)) {
     cerr << "<" << CSDN->getValue() << ">";
   } else if (const ConstantFPSDNode *CSDN = dyn_cast<ConstantFPSDNode>(this)) {
-    cerr << "<" << CSDN->getValue() << ">";
+    cerr << "<" << (&CSDN->getValueAPF().getSemantics()==&APFloat::IEEEsingle ? 
+                    CSDN->getValueAPF().convertToFloat() :
+                    CSDN->getValueAPF().convertToDouble()) << ">";
   } else if (const GlobalAddressSDNode *GADN =
              dyn_cast<GlobalAddressSDNode>(this)) {
     int offset = GADN->getOffset();