[llvm] r292839 - [APFloat] Switch from (PPCDoubleDoubleImpl, IEEEdouble) layout to (IEEEdouble, IEEEdouble)

Tim Shen via llvm-commits llvm-commits at lists.llvm.org
Mon Jan 23 14:39:35 PST 2017


Author: timshen
Date: Mon Jan 23 16:39:35 2017
New Revision: 292839

URL: http://llvm.org/viewvc/llvm-project?rev=292839&view=rev
Log:
[APFloat] Switch from (PPCDoubleDoubleImpl, IEEEdouble) layout to (IEEEdouble, IEEEdouble)

Summary:
This patch changes the layout of DoubleAPFloat, and adjust all
operations to do either:
1) (IEEEdouble, IEEEdouble) -> (uint64_t, uint64_t) -> PPCDoubleDoubleImpl,
   then run the old algorithm.
2) Do the right thing directly.

1) includes multiply, divide, remainder, mod, fusedMultiplyAdd, roundToIntegral,
   convertFromString, next, convertToInteger, convertFromAPInt,
   convertFromSignExtendedInteger, convertFromZeroExtendedInteger,
   convertToHexString, toString, getExactInverse.
2) includes makeZero, makeLargest, makeSmallest, makeSmallestNormalized,
   compare, bitwiseIsEqual, bitcastToAPInt, isDenormal, isSmallest,
   isLargest, isInteger, ilogb, scalbn, frexp, hash_value, Profile.

I could split this into two patches, e.g. use
1) for all operatoins first, then incrementally change some of them to
2). I didn't do that, because 1) involves code that converts data between
PPCDoubleDoubleImpl and (IEEEdouble, IEEEdouble) back and forth, and may
pessimize the compiler. Instead, I find easy functions and use
approach 2) for them directly.

Next step is to implement move multiply and divide from 1) to 2). I don't
have plans for other functions in 1).

Differential Revision: https://reviews.llvm.org/D27872

Modified:
    llvm/trunk/include/llvm/ADT/APFloat.h
    llvm/trunk/lib/Support/APFloat.cpp
    llvm/trunk/test/CodeGen/PowerPC/fp128-bitcast-after-operation.ll
    llvm/trunk/unittests/ADT/APFloatTest.cpp

Modified: llvm/trunk/include/llvm/ADT/APFloat.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/APFloat.h?rev=292839&r1=292838&r2=292839&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/APFloat.h (original)
+++ llvm/trunk/include/llvm/ADT/APFloat.h Mon Jan 23 16:39:35 2017
@@ -235,10 +235,6 @@ public:
 
   /// @}
 
-  /// Used to insert APFloat objects, or objects that contain APFloat objects,
-  /// into FoldingSets.
-  void Profile(FoldingSetNodeID &NID) const;
-
   /// \name Arithmetic
   /// @{
 
@@ -255,53 +251,12 @@ public:
   /// IEEE-754R 5.3.1: nextUp/nextDown.
   opStatus next(bool nextDown);
 
-  /// \brief Operator+ overload which provides the default
-  /// \c nmNearestTiesToEven rounding mode and *no* error checking.
-  IEEEFloat operator+(const IEEEFloat &RHS) const {
-    IEEEFloat Result = *this;
-    Result.add(RHS, rmNearestTiesToEven);
-    return Result;
-  }
-
-  /// \brief Operator- overload which provides the default
-  /// \c nmNearestTiesToEven rounding mode and *no* error checking.
-  IEEEFloat operator-(const IEEEFloat &RHS) const {
-    IEEEFloat Result = *this;
-    Result.subtract(RHS, rmNearestTiesToEven);
-    return Result;
-  }
-
-  /// \brief Operator* overload which provides the default
-  /// \c nmNearestTiesToEven rounding mode and *no* error checking.
-  IEEEFloat operator*(const IEEEFloat &RHS) const {
-    IEEEFloat Result = *this;
-    Result.multiply(RHS, rmNearestTiesToEven);
-    return Result;
-  }
-
-  /// \brief Operator/ overload which provides the default
-  /// \c nmNearestTiesToEven rounding mode and *no* error checking.
-  IEEEFloat operator/(const IEEEFloat &RHS) const {
-    IEEEFloat Result = *this;
-    Result.divide(RHS, rmNearestTiesToEven);
-    return Result;
-  }
-
   /// @}
 
   /// \name Sign operations.
   /// @{
 
   void changeSign();
-  void clearSign();
-  void copySign(const IEEEFloat &);
-
-  /// \brief A static helper to produce a copy of an APFloat value with its sign
-  /// copied from some other APFloat.
-  static IEEEFloat copySign(IEEEFloat Value, const IEEEFloat &Sign) {
-    Value.copySign(Sign);
-    return Value;
-  }
 
   /// @}
 
@@ -311,7 +266,6 @@ public:
   opStatus convert(const fltSemantics &, roundingMode, bool *);
   opStatus convertToInteger(integerPart *, unsigned int, bool, roundingMode,
                             bool *) const;
-  opStatus convertToInteger(APSInt &, roundingMode, bool *) const;
   opStatus convertFromAPInt(const APInt &, bool, roundingMode);
   opStatus convertFromSignExtendedInteger(const integerPart *, unsigned int,
                                           bool, roundingMode);
@@ -443,7 +397,7 @@ public:
 
   /// If this value has an exact multiplicative inverse, store it in inv and
   /// return true.
-  bool getExactInverse(IEEEFloat *inv) const;
+  bool getExactInverse(APFloat *inv) const;
 
   /// \brief Returns the exponent of the internal representation of the APFloat.
   ///
@@ -636,6 +590,13 @@ public:
 
   opStatus add(const DoubleAPFloat &RHS, roundingMode RM);
   opStatus subtract(const DoubleAPFloat &RHS, roundingMode RM);
+  opStatus multiply(const DoubleAPFloat &RHS, roundingMode RM);
+  opStatus divide(const DoubleAPFloat &RHS, roundingMode RM);
+  opStatus remainder(const DoubleAPFloat &RHS);
+  opStatus mod(const DoubleAPFloat &RHS);
+  opStatus fusedMultiplyAdd(const DoubleAPFloat &Multiplicand,
+                            const DoubleAPFloat &Addend, roundingMode RM);
+  opStatus roundToIntegral(roundingMode RM);
   void changeSign();
   cmpResult compareAbsoluteValue(const DoubleAPFloat &RHS) const;
 
@@ -643,9 +604,49 @@ public:
   bool isNegative() const;
 
   void makeInf(bool Neg);
+  void makeZero(bool Neg);
+  void makeLargest(bool Neg);
+  void makeSmallest(bool Neg);
+  void makeSmallestNormalized(bool Neg);
   void makeNaN(bool SNaN, bool Neg, const APInt *fill);
+
+  cmpResult compare(const DoubleAPFloat &RHS) const;
+  bool bitwiseIsEqual(const DoubleAPFloat &RHS) const;
+  APInt bitcastToAPInt() const;
+  opStatus convertFromString(StringRef, roundingMode);
+  opStatus next(bool nextDown);
+
+  opStatus convertToInteger(integerPart *Input, unsigned int Width,
+                            bool IsSigned, roundingMode RM,
+                            bool *IsExact) const;
+  opStatus convertFromAPInt(const APInt &Input, bool IsSigned, roundingMode RM);
+  opStatus convertFromSignExtendedInteger(const integerPart *Input,
+                                          unsigned int InputSize, bool IsSigned,
+                                          roundingMode RM);
+  opStatus convertFromZeroExtendedInteger(const integerPart *Input,
+                                          unsigned int InputSize, bool IsSigned,
+                                          roundingMode RM);
+  unsigned int convertToHexString(char *DST, unsigned int HexDigits,
+                                  bool UpperCase, roundingMode RM) const;
+
+  bool isDenormal() const;
+  bool isSmallest() const;
+  bool isLargest() const;
+  bool isInteger() const;
+
+  void toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision,
+                unsigned FormatMaxPadding) const;
+
+  bool getExactInverse(APFloat *inv) const;
+
+  friend int ilogb(const DoubleAPFloat &Arg);
+  friend DoubleAPFloat scalbn(DoubleAPFloat X, int Exp, roundingMode);
+  friend DoubleAPFloat frexp(const DoubleAPFloat &X, int &Exp, roundingMode);
+  friend hash_code hash_value(const DoubleAPFloat &Arg);
 };
 
+hash_code hash_value(const DoubleAPFloat &Arg);
+
 } // End detail namespace
 
 // This is a interface class that is currently forwarding functionalities from
@@ -770,26 +771,76 @@ class APFloat : public APFloatBase {
     llvm_unreachable("Unexpected semantics");
   }
 
-  void makeZero(bool Neg) { getIEEE().makeZero(Neg); }
+  void makeZero(bool Neg) {
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      U.IEEE.makeZero(Neg);
+      return;
+    }
+    if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      U.Double.makeZero(Neg);
+      return;
+    }
+    llvm_unreachable("Unexpected semantics");
+  }
 
   void makeInf(bool Neg) {
-    if (usesLayout<IEEEFloat>(*U.semantics))
-      return U.IEEE.makeInf(Neg);
-    if (usesLayout<DoubleAPFloat>(*U.semantics))
-      return U.Double.makeInf(Neg);
+    if (usesLayout<IEEEFloat>(*U.semantics)) {
+      U.IEEE.makeInf(Neg);
+      return;
+    }
+    if (usesLayout<DoubleAPFloat>(*U.semantics)) {
+      U.Double.makeInf(Neg);
+      return;
+    }
     llvm_unreachable("Unexpected semantics");
   }
 
   void makeNaN(bool SNaN, bool Neg, const APInt *fill) {
-    getIEEE().makeNaN(SNaN, Neg, fill);
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      U.IEEE.makeNaN(SNaN, Neg, fill);
+      return;
+    }
+    if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.makeNaN(SNaN, Neg, fill);
+      return;
+    }
+    llvm_unreachable("Unexpected semantics");
   }
 
-  void makeLargest(bool Neg) { getIEEE().makeLargest(Neg); }
+  void makeLargest(bool Neg) {
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      U.IEEE.makeLargest(Neg);
+      return;
+    }
+    if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      U.Double.makeLargest(Neg);
+      return;
+    }
+    llvm_unreachable("Unexpected semantics");
+  }
 
-  void makeSmallest(bool Neg) { getIEEE().makeSmallest(Neg); }
+  void makeSmallest(bool Neg) {
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      U.IEEE.makeSmallest(Neg);
+      return;
+    }
+    if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      U.Double.makeSmallest(Neg);
+      return;
+    }
+    llvm_unreachable("Unexpected semantics");
+  }
 
   void makeSmallestNormalized(bool Neg) {
-    getIEEE().makeSmallestNormalized(Neg);
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      U.IEEE.makeSmallestNormalized(Neg);
+      return;
+    }
+    if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      U.Double.makeSmallestNormalized(Neg);
+      return;
+    }
+    llvm_unreachable("Unexpected semantics");
   }
 
   // FIXME: This is due to clang 3.3 (or older version) always checks for the
@@ -921,7 +972,9 @@ public:
   /// \param isIEEE   - If 128 bit number, select between PPC and IEEE
   static APFloat getAllOnesValue(unsigned BitWidth, bool isIEEE = false);
 
-  void Profile(FoldingSetNodeID &NID) const { getIEEE().Profile(NID); }
+  /// Used to insert APFloat objects, or objects that contain APFloat objects,
+  /// into FoldingSets.
+  void Profile(FoldingSetNodeID &NID) const;
 
   opStatus add(const APFloat &RHS, roundingMode RM) {
     assert(&getSemantics() == &RHS.getSemantics() &&
@@ -942,48 +995,127 @@ public:
     llvm_unreachable("Unexpected semantics");
   }
   opStatus multiply(const APFloat &RHS, roundingMode RM) {
-    return getIEEE().multiply(RHS.getIEEE(), RM);
+    assert(&getSemantics() == &RHS.getSemantics() &&
+           "Should only call on two APFloats with the same semantics");
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.multiply(RHS.U.IEEE, RM);
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.multiply(RHS.U.Double, RM);
+    llvm_unreachable("Unexpected semantics");
   }
   opStatus divide(const APFloat &RHS, roundingMode RM) {
-    return getIEEE().divide(RHS.getIEEE(), RM);
+    assert(&getSemantics() == &RHS.getSemantics() &&
+           "Should only call on two APFloats with the same semantics");
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.divide(RHS.U.IEEE, RM);
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.divide(RHS.U.Double, RM);
+    llvm_unreachable("Unexpected semantics");
   }
   opStatus remainder(const APFloat &RHS) {
-    return getIEEE().remainder(RHS.getIEEE());
+    assert(&getSemantics() == &RHS.getSemantics() &&
+           "Should only call on two APFloats with the same semantics");
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.remainder(RHS.U.IEEE);
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.remainder(RHS.U.Double);
+    llvm_unreachable("Unexpected semantics");
+  }
+  opStatus mod(const APFloat &RHS) {
+    assert(&getSemantics() == &RHS.getSemantics() &&
+           "Should only call on two APFloats with the same semantics");
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.mod(RHS.U.IEEE);
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.mod(RHS.U.Double);
+    llvm_unreachable("Unexpected semantics");
   }
-  opStatus mod(const APFloat &RHS) { return getIEEE().mod(RHS.getIEEE()); }
   opStatus fusedMultiplyAdd(const APFloat &Multiplicand, const APFloat &Addend,
                             roundingMode RM) {
-    return getIEEE().fusedMultiplyAdd(Multiplicand.getIEEE(), Addend.getIEEE(),
-                                      RM);
+    assert(&getSemantics() == &Multiplicand.getSemantics() &&
+           "Should only call on APFloats with the same semantics");
+    assert(&getSemantics() == &Addend.getSemantics() &&
+           "Should only call on APFloats with the same semantics");
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.fusedMultiplyAdd(Multiplicand.U.IEEE, Addend.U.IEEE, RM);
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.fusedMultiplyAdd(Multiplicand.U.Double, Addend.U.Double,
+                                       RM);
+    llvm_unreachable("Unexpected semantics");
   }
   opStatus roundToIntegral(roundingMode RM) {
-    return getIEEE().roundToIntegral(RM);
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.roundToIntegral(RM);
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.roundToIntegral(RM);
+    llvm_unreachable("Unexpected semantics");
+  }
+
+  opStatus next(bool nextDown) {
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.next(nextDown);
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.next(nextDown);
+    llvm_unreachable("Unexpected semantics");
   }
-  opStatus next(bool nextDown) { return getIEEE().next(nextDown); }
 
+  /// \brief Operator+ overload which provides the default
+  /// \c rmNearestTiesToEven rounding mode and *no* error checking.
   APFloat operator+(const APFloat &RHS) const {
-    return APFloat(getIEEE() + RHS.getIEEE(), getSemantics());
+    APFloat Result(*this);
+    (void)Result.add(RHS, rmNearestTiesToEven);
+    return Result;
   }
 
+  /// \brief Operator- overload which provides the default
+  /// \c rmNearestTiesToEven rounding mode and *no* error checking.
   APFloat operator-(const APFloat &RHS) const {
-    return APFloat(getIEEE() - RHS.getIEEE(), getSemantics());
+    APFloat Result(*this);
+    (void)Result.subtract(RHS, rmNearestTiesToEven);
+    return Result;
   }
 
+  /// \brief Operator* overload which provides the default
+  /// \c rmNearestTiesToEven rounding mode and *no* error checking.
   APFloat operator*(const APFloat &RHS) const {
-    return APFloat(getIEEE() * RHS.getIEEE(), getSemantics());
+    APFloat Result(*this);
+    (void)Result.multiply(RHS, rmNearestTiesToEven);
+    return Result;
   }
 
+  /// \brief Operator/ overload which provides the default
+  /// \c rmNearestTiesToEven rounding mode and *no* error checking.
   APFloat operator/(const APFloat &RHS) const {
-    return APFloat(getIEEE() / RHS.getIEEE(), getSemantics());
+    APFloat Result(*this);
+    (void)Result.divide(RHS, rmNearestTiesToEven);
+    return Result;
   }
 
-  void changeSign() { getIEEE().changeSign(); }
-  void clearSign() { getIEEE().clearSign(); }
-  void copySign(const APFloat &RHS) { getIEEE().copySign(RHS.getIEEE()); }
+  void changeSign() {
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      U.IEEE.changeSign();
+      return;
+    }
+    if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      U.Double.changeSign();
+      return;
+    }
+    llvm_unreachable("Unexpected semantics");
+  }
+  void clearSign() {
+    if (isNegative())
+      changeSign();
+  }
+  void copySign(const APFloat &RHS) {
+    if (isNegative() != RHS.isNegative())
+      changeSign();
+  }
 
+  /// \brief A static helper to produce a copy of an APFloat value with its sign
+  /// copied from some other APFloat.
   static APFloat copySign(APFloat Value, const APFloat &Sign) {
-    return APFloat(IEEEFloat::copySign(Value.getIEEE(), Sign.getIEEE()),
-                   Value.getSemantics());
+    Value.copySign(Sign);
+    return Value;
   }
 
   opStatus convert(const fltSemantics &ToSemantics, roundingMode RM,
@@ -991,46 +1123,84 @@ public:
   opStatus convertToInteger(integerPart *Input, unsigned int Width,
                             bool IsSigned, roundingMode RM,
                             bool *IsExact) const {
-    return getIEEE().convertToInteger(Input, Width, IsSigned, RM, IsExact);
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.convertToInteger(Input, Width, IsSigned, RM, IsExact);
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.convertToInteger(Input, Width, IsSigned, RM, IsExact);
+    llvm_unreachable("Unexpected semantics");
   }
   opStatus convertToInteger(APSInt &Result, roundingMode RM,
-                            bool *IsExact) const {
-    return getIEEE().convertToInteger(Result, RM, IsExact);
-  }
+                            bool *IsExact) const;
   opStatus convertFromAPInt(const APInt &Input, bool IsSigned,
                             roundingMode RM) {
-    return getIEEE().convertFromAPInt(Input, IsSigned, RM);
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.convertFromAPInt(Input, IsSigned, RM);
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.convertFromAPInt(Input, IsSigned, RM);
+    llvm_unreachable("Unexpected semantics");
   }
   opStatus convertFromSignExtendedInteger(const integerPart *Input,
                                           unsigned int InputSize, bool IsSigned,
                                           roundingMode RM) {
-    return getIEEE().convertFromSignExtendedInteger(Input, InputSize, IsSigned,
-                                                    RM);
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.convertFromSignExtendedInteger(Input, InputSize, IsSigned,
+                                                   RM);
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.convertFromSignExtendedInteger(Input, InputSize, IsSigned,
+                                                     RM);
+    llvm_unreachable("Unexpected semantics");
   }
   opStatus convertFromZeroExtendedInteger(const integerPart *Input,
                                           unsigned int InputSize, bool IsSigned,
                                           roundingMode RM) {
-    return getIEEE().convertFromZeroExtendedInteger(Input, InputSize, IsSigned,
-                                                    RM);
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.convertFromZeroExtendedInteger(Input, InputSize, IsSigned,
+                                                   RM);
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.convertFromZeroExtendedInteger(Input, InputSize, IsSigned,
+                                                     RM);
+    llvm_unreachable("Unexpected semantics");
   }
   opStatus convertFromString(StringRef, roundingMode);
-  APInt bitcastToAPInt() const { return getIEEE().bitcastToAPInt(); }
+  APInt bitcastToAPInt() const {
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.bitcastToAPInt();
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.bitcastToAPInt();
+    llvm_unreachable("Unexpected semantics");
+  }
   double convertToDouble() const { return getIEEE().convertToDouble(); }
   float convertToFloat() const { return getIEEE().convertToFloat(); }
 
   bool operator==(const APFloat &) const = delete;
 
   cmpResult compare(const APFloat &RHS) const {
-    return getIEEE().compare(RHS.getIEEE());
+    assert(&getSemantics() == &RHS.getSemantics() &&
+           "Should only compare APFloats with the same semantics");
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.compare(RHS.U.IEEE);
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.compare(RHS.U.Double);
+    llvm_unreachable("Unexpected semantics");
   }
 
   bool bitwiseIsEqual(const APFloat &RHS) const {
-    return getIEEE().bitwiseIsEqual(RHS.getIEEE());
+    if (&getSemantics() != &RHS.getSemantics())
+      return false;
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.bitwiseIsEqual(RHS.U.IEEE);
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.bitwiseIsEqual(RHS.U.Double);
+    llvm_unreachable("Unexpected semantics");
   }
 
   unsigned int convertToHexString(char *DST, unsigned int HexDigits,
                                   bool UpperCase, roundingMode RM) const {
-    return getIEEE().convertToHexString(DST, HexDigits, UpperCase, RM);
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.convertToHexString(DST, HexDigits, UpperCase, RM);
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.convertToHexString(DST, HexDigits, UpperCase, RM);
+    llvm_unreachable("Unexpected semantics");
   }
 
   bool isZero() const { return getCategory() == fcZero; }
@@ -1038,7 +1208,13 @@ public:
   bool isNaN() const { return getCategory() == fcNaN; }
 
   bool isNegative() const { return getIEEE().isNegative(); }
-  bool isDenormal() const { return getIEEE().isDenormal(); }
+  bool isDenormal() const {
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.isDenormal();
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.isDenormal();
+    llvm_unreachable("Unexpected semantics");
+  }
   bool isSignaling() const { return getIEEE().isSignaling(); }
 
   bool isNormal() const { return !isDenormal() && isFiniteNonZero(); }
@@ -1050,30 +1226,53 @@ public:
   bool isFiniteNonZero() const { return isFinite() && !isZero(); }
   bool isPosZero() const { return isZero() && !isNegative(); }
   bool isNegZero() const { return isZero() && isNegative(); }
-  bool isSmallest() const { return getIEEE().isSmallest(); }
-  bool isLargest() const { return getIEEE().isLargest(); }
-  bool isInteger() const { return getIEEE().isInteger(); }
+  bool isSmallest() const {
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.isSmallest();
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.isSmallest();
+    llvm_unreachable("Unexpected semantics");
+  }
+  bool isLargest() const {
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.isLargest();
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.isLargest();
+    llvm_unreachable("Unexpected semantics");
+  }
+  bool isInteger() const {
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.isInteger();
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.isInteger();
+    llvm_unreachable("Unexpected semantics");
+  }
 
   APFloat &operator=(const APFloat &RHS) = default;
   APFloat &operator=(APFloat &&RHS) = default;
 
   void toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision = 0,
                 unsigned FormatMaxPadding = 3) const {
-    return getIEEE().toString(Str, FormatPrecision, FormatMaxPadding);
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      U.IEEE.toString(Str, FormatPrecision, FormatMaxPadding);
+      return;
+    }
+    if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      U.Double.toString(Str, FormatPrecision, FormatMaxPadding);
+      return;
+    }
+    llvm_unreachable("Unexpected semantics");
   }
 
   void print(raw_ostream &) const;
   void dump() const;
 
   bool getExactInverse(APFloat *inv) const {
-    return getIEEE().getExactInverse(inv ? &inv->getIEEE() : nullptr);
-  }
-
-  // This is for internal test only.
-  // TODO: Remove it after the PPCDoubleDouble transition.
-  const APFloat &getSecondFloat() const {
-    assert(&getSemantics() == &PPCDoubleDouble());
-    return U.Double.getSecond();
+    if (usesLayout<IEEEFloat>(getSemantics()))
+      return U.IEEE.getExactInverse(inv);
+    if (usesLayout<DoubleAPFloat>(getSemantics()))
+      return U.Double.getExactInverse(inv);
+    llvm_unreachable("Unexpected semantics");
   }
 
   friend hash_code hash_value(const APFloat &Arg);
@@ -1090,7 +1289,11 @@ public:
 /// xlC compiler.
 hash_code hash_value(const APFloat &Arg);
 inline APFloat scalbn(APFloat X, int Exp, APFloat::roundingMode RM) {
-  return APFloat(scalbn(X.getIEEE(), Exp, RM), X.getSemantics());
+  if (APFloat::usesLayout<detail::IEEEFloat>(X.getSemantics()))
+    return APFloat(scalbn(X.U.IEEE, Exp, RM), X.getSemantics());
+  if (APFloat::usesLayout<detail::DoubleAPFloat>(X.getSemantics()))
+    return APFloat(scalbn(X.U.Double, Exp, RM), X.getSemantics());
+  llvm_unreachable("Unexpected semantics");
 }
 
 /// \brief Equivalent of C standard library function.
@@ -1098,7 +1301,11 @@ inline APFloat scalbn(APFloat X, int Exp
 /// While the C standard says Exp is an unspecified value for infinity and nan,
 /// this returns INT_MAX for infinities, and INT_MIN for NaNs.
 inline APFloat frexp(const APFloat &X, int &Exp, APFloat::roundingMode RM) {
-  return APFloat(frexp(X.getIEEE(), Exp, RM), X.getSemantics());
+  if (APFloat::usesLayout<detail::IEEEFloat>(X.getSemantics()))
+    return APFloat(frexp(X.U.IEEE, Exp, RM), X.getSemantics());
+  if (APFloat::usesLayout<detail::DoubleAPFloat>(X.getSemantics()))
+    return APFloat(frexp(X.U.Double, Exp, RM), X.getSemantics());
+  llvm_unreachable("Unexpected semantics");
 }
 /// \brief Returns the absolute value of the argument.
 inline APFloat abs(APFloat X) {

Modified: llvm/trunk/lib/Support/APFloat.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/APFloat.cpp?rev=292839&r1=292838&r2=292839&view=diff
==============================================================================
--- llvm/trunk/lib/Support/APFloat.cpp (original)
+++ llvm/trunk/lib/Support/APFloat.cpp Mon Jan 23 16:39:35 2017
@@ -83,16 +83,26 @@ namespace llvm {
      and we heavily rely on them having distinct addresses.             */
   static const fltSemantics semPPCDoubleDouble = {-1, 0, 0, 0};
 
-  /* There are temporary semantics for the real PPCDoubleDouble implementation.
-     Currently, APFloat of PPCDoubleDouble holds one PPCDoubleDoubleImpl as the
-     high part of double double, and one IEEEdouble as the low part, so that
-     the old operations operate on PPCDoubleDoubleImpl, while the newly added
-     operations also populate the IEEEdouble.
-
-     TODO: Once all functions support DoubleAPFloat mode, we'll change all
-     PPCDoubleDoubleImpl to IEEEdouble and remove PPCDoubleDoubleImpl.  */
-  static const fltSemantics semPPCDoubleDoubleImpl = {1023, -1022 + 53, 53 + 53,
-                                                      128};
+  /* These are legacy semantics for the fallback, inaccrurate implementation of
+     IBM double-double, if the accurate semPPCDoubleDouble doesn't handle the
+     case. It's equivalent to have an IEEE number with consecutive 106 bits of
+     mantissa, and 11 bits of exponent. It's not accurate, becuase the two
+     53-bit mantissa parts don't actually have to be consecutive,
+     e.g. 1 + epsilon.
+
+     Currently, these semantics are used in the following way:
+
+       (IEEEdouble, IEEEdouble) -> (64-bit APInt, 64-bit APInt) ->
+       (128-bit APInt) -> semPPCDoubleDoubleLegacy -> IEEE operations
+
+     We use bitcastToAPInt() to get the bit representation (in APInt) of the
+     underlying IEEEdouble, then use the APInt constructor to construct the
+     legacy IEEE float.
+
+     TODO: Implement all operations in semPPCDoubleDouble, and delete these
+     semantics.  */
+  static const fltSemantics semPPCDoubleDoubleLegacy = {1023, -1022 + 53,
+                                                        53 + 53, 128};
 
   const fltSemantics &APFloatBase::IEEEhalf() {
     return semIEEEhalf;
@@ -862,11 +872,6 @@ IEEEFloat::IEEEFloat(IEEEFloat &&rhs) :
 
 IEEEFloat::~IEEEFloat() { freeSignificand(); }
 
-// Profile - This method 'profiles' an APFloat for use with FoldingSet.
-void IEEEFloat::Profile(FoldingSetNodeID &ID) const {
-  ID.Add(bitcastToAPInt());
-}
-
 unsigned int IEEEFloat::partCount() const {
   return partCountForBits(semantics->precision + 1);
 }
@@ -1611,16 +1616,6 @@ void IEEEFloat::changeSign() {
   sign = !sign;
 }
 
-void IEEEFloat::clearSign() {
-  /* So is this one. */
-  sign = 0;
-}
-
-void IEEEFloat::copySign(const IEEEFloat &rhs) {
-  /* And this one. */
-  sign = rhs.sign;
-}
-
 /* Normalized addition or subtraction.  */
 IEEEFloat::opStatus IEEEFloat::addOrSubtract(const IEEEFloat &rhs,
                                              roundingMode rounding_mode,
@@ -1840,7 +1835,7 @@ IEEEFloat::opStatus IEEEFloat::roundToIn
   IEEEFloat MagicConstant(*semantics);
   fs = MagicConstant.convertFromAPInt(IntegerConstant, false,
                                       rmNearestTiesToEven);
-  MagicConstant.copySign(*this);
+  MagicConstant.sign = sign;
 
   if (fs != opOK)
     return fs;
@@ -2185,22 +2180,6 @@ IEEEFloat::opStatus IEEEFloat::convertTo
   return fs;
 }
 
-/* Same as convertToInteger(integerPart*, ...), except the result is returned in
-   an APSInt, whose initial bit-width and signed-ness are used to determine the
-   precision of the conversion.
- */
-IEEEFloat::opStatus IEEEFloat::convertToInteger(APSInt &result,
-                                                roundingMode rounding_mode,
-                                                bool *isExact) const {
-  unsigned bitWidth = result.getBitWidth();
-  SmallVector<uint64_t, 4> parts(result.getNumWords());
-  opStatus status = convertToInteger(
-    parts.data(), bitWidth, result.isSigned(), rounding_mode, isExact);
-  // Keeps the original signed-ness.
-  result = APInt(bitWidth, parts);
-  return status;
-}
-
 /* Convert an unsigned integer SRC to a floating point number,
    rounding according to ROUNDING_MODE.  The sign of the floating
    point number is not modified.  */
@@ -2852,7 +2831,7 @@ APInt IEEEFloat::convertF80LongDoubleAPF
 }
 
 APInt IEEEFloat::convertPPCDoubleDoubleAPFloatToAPInt() const {
-  assert(semantics == (const llvm::fltSemantics *)&semPPCDoubleDoubleImpl);
+  assert(semantics == (const llvm::fltSemantics *)&semPPCDoubleDoubleLegacy);
   assert(partCount()==2);
 
   uint64_t words[2];
@@ -3033,7 +3012,7 @@ APInt IEEEFloat::bitcastToAPInt() const
   if (semantics == (const llvm::fltSemantics*)&semIEEEquad)
     return convertQuadrupleAPFloatToAPInt();
 
-  if (semantics == (const llvm::fltSemantics *)&semPPCDoubleDoubleImpl)
+  if (semantics == (const llvm::fltSemantics *)&semPPCDoubleDoubleLegacy)
     return convertPPCDoubleDoubleAPFloatToAPInt();
 
   assert(semantics == (const llvm::fltSemantics*)&semX87DoubleExtended &&
@@ -3103,14 +3082,14 @@ void IEEEFloat::initFromPPCDoubleDoubleA
 
   // Get the first double and convert to our format.
   initFromDoubleAPInt(APInt(64, i1));
-  fs = convert(semPPCDoubleDoubleImpl, rmNearestTiesToEven, &losesInfo);
+  fs = convert(semPPCDoubleDoubleLegacy, rmNearestTiesToEven, &losesInfo);
   assert(fs == opOK && !losesInfo);
   (void)fs;
 
   // Unless we have a special case, add in second double.
   if (isFiniteNonZero()) {
     IEEEFloat v(semIEEEdouble, APInt(64, i2));
-    fs = v.convert(semPPCDoubleDoubleImpl, rmNearestTiesToEven, &losesInfo);
+    fs = v.convert(semPPCDoubleDoubleLegacy, rmNearestTiesToEven, &losesInfo);
     assert(fs == opOK && !losesInfo);
     (void)fs;
 
@@ -3264,7 +3243,7 @@ void IEEEFloat::initFromAPInt(const fltS
     return initFromF80LongDoubleAPInt(api);
   if (Sem == &semIEEEquad)
     return initFromQuadrupleAPInt(api);
-  if (Sem == &semPPCDoubleDoubleImpl)
+  if (Sem == &semPPCDoubleDoubleLegacy)
     return initFromPPCDoubleDoubleAPInt(api);
 
   llvm_unreachable(nullptr);
@@ -3620,7 +3599,7 @@ void IEEEFloat::toString(SmallVectorImpl
     Str.push_back(buffer[NDigits-I-1]);
 }
 
-bool IEEEFloat::getExactInverse(IEEEFloat *inv) const {
+bool IEEEFloat::getExactInverse(APFloat *inv) const {
   // Special floats and denormals have no exact inverse.
   if (!isFiniteNonZero())
     return false;
@@ -3644,7 +3623,7 @@ bool IEEEFloat::getExactInverse(IEEEFloa
          reciprocal.significandLSB() == reciprocal.semantics->precision - 1);
 
   if (inv)
-    *inv = reciprocal;
+    *inv = APFloat(reciprocal, *semantics);
 
   return true;
 }
@@ -3856,28 +3835,29 @@ IEEEFloat frexp(const IEEEFloat &Val, in
 }
 
 DoubleAPFloat::DoubleAPFloat(const fltSemantics &S)
-    : Semantics(&S), Floats(new APFloat[2]{APFloat(semPPCDoubleDoubleImpl),
-                                           APFloat(semIEEEdouble)}) {
+    : Semantics(&S),
+      Floats(new APFloat[2]{APFloat(semIEEEdouble), APFloat(semIEEEdouble)}) {
   assert(Semantics == &semPPCDoubleDouble);
 }
 
 DoubleAPFloat::DoubleAPFloat(const fltSemantics &S, uninitializedTag)
     : Semantics(&S),
-      Floats(new APFloat[2]{APFloat(semPPCDoubleDoubleImpl, uninitialized),
+      Floats(new APFloat[2]{APFloat(semIEEEdouble, uninitialized),
                             APFloat(semIEEEdouble, uninitialized)}) {
   assert(Semantics == &semPPCDoubleDouble);
 }
 
 DoubleAPFloat::DoubleAPFloat(const fltSemantics &S, integerPart I)
-    : Semantics(&S), Floats(new APFloat[2]{APFloat(semPPCDoubleDoubleImpl, I),
+    : Semantics(&S), Floats(new APFloat[2]{APFloat(semIEEEdouble, I),
                                            APFloat(semIEEEdouble)}) {
   assert(Semantics == &semPPCDoubleDouble);
 }
 
 DoubleAPFloat::DoubleAPFloat(const fltSemantics &S, const APInt &I)
-    : Semantics(&S), Floats(new APFloat[2]{
-                         APFloat(semPPCDoubleDoubleImpl, I),
-                         APFloat(semIEEEdouble, APInt(64, I.getRawData()[1]))}) {
+    : Semantics(&S),
+      Floats(new APFloat[2]{
+          APFloat(semIEEEdouble, APInt(64, I.getRawData()[0])),
+          APFloat(semIEEEdouble, APInt(64, I.getRawData()[1]))}) {
   assert(Semantics == &semPPCDoubleDouble);
 }
 
@@ -3886,9 +3866,7 @@ DoubleAPFloat::DoubleAPFloat(const fltSe
     : Semantics(&S),
       Floats(new APFloat[2]{std::move(First), std::move(Second)}) {
   assert(Semantics == &semPPCDoubleDouble);
-  // TODO Check for First == &IEEEdouble once the transition is done.
-  assert(&Floats[0].getSemantics() == &semPPCDoubleDoubleImpl ||
-         &Floats[0].getSemantics() == &semIEEEdouble);
+  assert(&Floats[0].getSemantics() == &semIEEEdouble);
   assert(&Floats[1].getSemantics() == &semIEEEdouble);
 }
 
@@ -4033,25 +4011,15 @@ APFloat::opStatus DoubleAPFloat::addWith
   }
   assert(LHS.getCategory() == fcNormal && RHS.getCategory() == fcNormal);
 
-  // These conversions will go away once PPCDoubleDoubleImpl goes away.
-  // (PPCDoubleDoubleImpl, IEEEDouble) -> (IEEEDouble, IEEEDouble)
-  APFloat A(semIEEEdouble,
-            APInt(64, LHS.Floats[0].bitcastToAPInt().getRawData()[0])),
-      AA(LHS.Floats[1]),
-      C(semIEEEdouble, APInt(64, RHS.Floats[0].bitcastToAPInt().getRawData()[0])),
+  APFloat A(LHS.Floats[0]), AA(LHS.Floats[1]), C(RHS.Floats[0]),
       CC(RHS.Floats[1]);
+  assert(&A.getSemantics() == &semIEEEdouble);
   assert(&AA.getSemantics() == &semIEEEdouble);
+  assert(&C.getSemantics() == &semIEEEdouble);
   assert(&CC.getSemantics() == &semIEEEdouble);
-  Out.Floats[0] = APFloat(semIEEEdouble);
+  assert(&Out.Floats[0].getSemantics() == &semIEEEdouble);
   assert(&Out.Floats[1].getSemantics() == &semIEEEdouble);
-
-  auto Ret = Out.addImpl(A, AA, C, CC, RM);
-
-  // (IEEEDouble, IEEEDouble) -> (PPCDoubleDoubleImpl, IEEEDouble)
-  uint64_t Buffer[] = {Out.Floats[0].bitcastToAPInt().getRawData()[0],
-                       Out.Floats[1].bitcastToAPInt().getRawData()[0]};
-  Out.Floats[0] = APFloat(semPPCDoubleDoubleImpl, APInt(128, 2, Buffer));
-  return Ret;
+  return Out.addImpl(A, AA, C, CC, RM);
 }
 
 APFloat::opStatus DoubleAPFloat::add(const DoubleAPFloat &RHS,
@@ -4067,6 +4035,64 @@ APFloat::opStatus DoubleAPFloat::subtrac
   return Ret;
 }
 
+APFloat::opStatus DoubleAPFloat::multiply(const DoubleAPFloat &RHS,
+                                          APFloat::roundingMode RM) {
+  assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+  APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt());
+  auto Ret =
+      Tmp.multiply(APFloat(semPPCDoubleDoubleLegacy, RHS.bitcastToAPInt()), RM);
+  *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+  return Ret;
+}
+
+APFloat::opStatus DoubleAPFloat::divide(const DoubleAPFloat &RHS,
+                                        APFloat::roundingMode RM) {
+  assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+  APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt());
+  auto Ret =
+      Tmp.divide(APFloat(semPPCDoubleDoubleLegacy, RHS.bitcastToAPInt()), RM);
+  *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+  return Ret;
+}
+
+APFloat::opStatus DoubleAPFloat::remainder(const DoubleAPFloat &RHS) {
+  assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+  APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt());
+  auto Ret =
+      Tmp.remainder(APFloat(semPPCDoubleDoubleLegacy, RHS.bitcastToAPInt()));
+  *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+  return Ret;
+}
+
+APFloat::opStatus DoubleAPFloat::mod(const DoubleAPFloat &RHS) {
+  assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+  APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt());
+  auto Ret = Tmp.mod(APFloat(semPPCDoubleDoubleLegacy, RHS.bitcastToAPInt()));
+  *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+  return Ret;
+}
+
+APFloat::opStatus
+DoubleAPFloat::fusedMultiplyAdd(const DoubleAPFloat &Multiplicand,
+                                const DoubleAPFloat &Addend,
+                                APFloat::roundingMode RM) {
+  assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+  APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt());
+  auto Ret = Tmp.fusedMultiplyAdd(
+      APFloat(semPPCDoubleDoubleLegacy, Multiplicand.bitcastToAPInt()),
+      APFloat(semPPCDoubleDoubleLegacy, Addend.bitcastToAPInt()), RM);
+  *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+  return Ret;
+}
+
+APFloat::opStatus DoubleAPFloat::roundToIntegral(APFloat::roundingMode RM) {
+  assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+  APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt());
+  auto Ret = Tmp.roundToIntegral(RM);
+  *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+  return Ret;
+}
+
 void DoubleAPFloat::changeSign() {
   Floats[0].changeSign();
   Floats[1].changeSign();
@@ -4104,11 +4130,198 @@ void DoubleAPFloat::makeInf(bool Neg) {
   Floats[1].makeZero(false);
 }
 
+void DoubleAPFloat::makeZero(bool Neg) {
+  Floats[0].makeZero(Neg);
+  Floats[1].makeZero(false);
+}
+
+void DoubleAPFloat::makeLargest(bool Neg) {
+  assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+  Floats[0] = APFloat(semIEEEdouble, APInt(64, 0x7fefffffffffffffull));
+  Floats[1] = APFloat(semIEEEdouble, APInt(64, 0x7c8ffffffffffffeull));
+  if (Neg)
+    changeSign();
+}
+
+void DoubleAPFloat::makeSmallest(bool Neg) {
+  assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+  Floats[0].makeSmallest(Neg);
+  Floats[1].makeZero(false);
+}
+
+void DoubleAPFloat::makeSmallestNormalized(bool Neg) {
+  assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+  Floats[0] = APFloat(semIEEEdouble, APInt(64, 0x0360000000000000ull));
+  if (Neg)
+    Floats[0].changeSign();
+  Floats[1].makeZero(false);
+}
+
 void DoubleAPFloat::makeNaN(bool SNaN, bool Neg, const APInt *fill) {
   Floats[0].makeNaN(SNaN, Neg, fill);
   Floats[1].makeZero(false);
 }
 
+APFloat::cmpResult DoubleAPFloat::compare(const DoubleAPFloat &RHS) const {
+  auto Result = Floats[0].compare(RHS.Floats[0]);
+  if (Result == APFloat::cmpEqual)
+    return Floats[1].compare(RHS.Floats[1]);
+  return Result;
+}
+
+bool DoubleAPFloat::bitwiseIsEqual(const DoubleAPFloat &RHS) const {
+  return Floats[0].bitwiseIsEqual(RHS.Floats[0]) &&
+         Floats[1].bitwiseIsEqual(RHS.Floats[1]);
+}
+
+hash_code hash_value(const DoubleAPFloat &Arg) {
+  if (Arg.Floats)
+    return hash_combine(hash_value(Arg.Floats[0]), hash_value(Arg.Floats[1]));
+  return hash_combine(Arg.Semantics);
+}
+
+APInt DoubleAPFloat::bitcastToAPInt() const {
+  assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+  uint64_t Data[] = {
+      Floats[0].bitcastToAPInt().getRawData()[0],
+      Floats[1].bitcastToAPInt().getRawData()[0],
+  };
+  return APInt(128, 2, Data);
+}
+
+APFloat::opStatus DoubleAPFloat::convertFromString(StringRef S,
+                                                   roundingMode RM) {
+  assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+  APFloat Tmp(semPPCDoubleDoubleLegacy);
+  auto Ret = Tmp.convertFromString(S, RM);
+  *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+  return Ret;
+}
+
+APFloat::opStatus DoubleAPFloat::next(bool nextDown) {
+  assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+  APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt());
+  auto Ret = Tmp.next(nextDown);
+  *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+  return Ret;
+}
+
+APFloat::opStatus DoubleAPFloat::convertToInteger(integerPart *Input,
+                                                  unsigned int Width,
+                                                  bool IsSigned,
+                                                  roundingMode RM,
+                                                  bool *IsExact) const {
+  assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+  return APFloat(semPPCDoubleDoubleLegacy, bitcastToAPInt())
+      .convertToInteger(Input, Width, IsSigned, RM, IsExact);
+}
+
+APFloat::opStatus DoubleAPFloat::convertFromAPInt(const APInt &Input,
+                                                  bool IsSigned,
+                                                  roundingMode RM) {
+  assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+  APFloat Tmp(semPPCDoubleDoubleLegacy);
+  auto Ret = Tmp.convertFromAPInt(Input, IsSigned, RM);
+  *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+  return Ret;
+}
+
+APFloat::opStatus
+DoubleAPFloat::convertFromSignExtendedInteger(const integerPart *Input,
+                                              unsigned int InputSize,
+                                              bool IsSigned, roundingMode RM) {
+  assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+  APFloat Tmp(semPPCDoubleDoubleLegacy);
+  auto Ret = Tmp.convertFromSignExtendedInteger(Input, InputSize, IsSigned, RM);
+  *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+  return Ret;
+}
+
+APFloat::opStatus
+DoubleAPFloat::convertFromZeroExtendedInteger(const integerPart *Input,
+                                              unsigned int InputSize,
+                                              bool IsSigned, roundingMode RM) {
+  assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+  APFloat Tmp(semPPCDoubleDoubleLegacy);
+  auto Ret = Tmp.convertFromZeroExtendedInteger(Input, InputSize, IsSigned, RM);
+  *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt());
+  return Ret;
+}
+
+unsigned int DoubleAPFloat::convertToHexString(char *DST,
+                                               unsigned int HexDigits,
+                                               bool UpperCase,
+                                               roundingMode RM) const {
+  assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+  return APFloat(semPPCDoubleDoubleLegacy, bitcastToAPInt())
+      .convertToHexString(DST, HexDigits, UpperCase, RM);
+}
+
+bool DoubleAPFloat::isDenormal() const {
+  return getCategory() == fcNormal &&
+         (Floats[0].isDenormal() || Floats[1].isDenormal() ||
+          Floats[0].compare(Floats[0] + Floats[1]) != cmpEqual);
+}
+
+bool DoubleAPFloat::isSmallest() const {
+  if (getCategory() != fcNormal)
+    return false;
+  DoubleAPFloat Tmp(*this);
+  Tmp.makeSmallest(this->isNegative());
+  return Tmp.compare(*this) == cmpEqual;
+}
+
+bool DoubleAPFloat::isLargest() const {
+  if (getCategory() != fcNormal)
+    return false;
+  DoubleAPFloat Tmp(*this);
+  Tmp.makeLargest(this->isNegative());
+  return Tmp.compare(*this) == cmpEqual;
+}
+
+bool DoubleAPFloat::isInteger() const {
+  assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+  APFloat Tmp(semPPCDoubleDoubleLegacy);
+  (void)Tmp.add(Floats[0], rmNearestTiesToEven);
+  (void)Tmp.add(Floats[1], rmNearestTiesToEven);
+  return Tmp.isInteger();
+}
+
+void DoubleAPFloat::toString(SmallVectorImpl<char> &Str,
+                             unsigned FormatPrecision,
+                             unsigned FormatMaxPadding) const {
+  assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+  APFloat(semPPCDoubleDoubleLegacy, bitcastToAPInt())
+      .toString(Str, FormatPrecision, FormatMaxPadding);
+}
+
+bool DoubleAPFloat::getExactInverse(APFloat *inv) const {
+  assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+  APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt());
+  if (!inv)
+    return Tmp.getExactInverse(nullptr);
+  APFloat Inv(semPPCDoubleDoubleLegacy);
+  auto Ret = Tmp.getExactInverse(&Inv);
+  *inv = APFloat(semPPCDoubleDouble, Inv.bitcastToAPInt());
+  return Ret;
+}
+
+DoubleAPFloat scalbn(DoubleAPFloat Arg, int Exp, APFloat::roundingMode RM) {
+  assert(Arg.Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+  return DoubleAPFloat(semPPCDoubleDouble, scalbn(Arg.Floats[0], Exp, RM),
+                       scalbn(Arg.Floats[1], Exp, RM));
+}
+
+DoubleAPFloat frexp(const DoubleAPFloat &Arg, int &Exp,
+                    APFloat::roundingMode RM) {
+  assert(Arg.Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
+  APFloat First = frexp(Arg.Floats[0], Exp, RM);
+  APFloat Second = Arg.Floats[1];
+  if (Arg.getCategory() == APFloat::fcNormal)
+    Second = scalbn(Second, -Exp, RM);
+  return DoubleAPFloat(semPPCDoubleDouble, std::move(First), std::move(Second));
+}
+
 } // End detail namespace
 
 APFloat::Storage::Storage(IEEEFloat F, const fltSemantics &Semantics) {
@@ -4126,10 +4339,20 @@ APFloat::Storage::Storage(IEEEFloat F, c
 }
 
 APFloat::opStatus APFloat::convertFromString(StringRef Str, roundingMode RM) {
-  return getIEEE().convertFromString(Str, RM);
+  if (usesLayout<IEEEFloat>(getSemantics()))
+    return U.IEEE.convertFromString(Str, RM);
+  if (usesLayout<DoubleAPFloat>(getSemantics()))
+    return U.Double.convertFromString(Str, RM);
+  llvm_unreachable("Unexpected semantics");
 }
 
-hash_code hash_value(const APFloat &Arg) { return hash_value(Arg.getIEEE()); }
+hash_code hash_value(const APFloat &Arg) {
+  if (APFloat::usesLayout<detail::IEEEFloat>(Arg.getSemantics()))
+    return hash_value(Arg.U.IEEE);
+  if (APFloat::usesLayout<detail::DoubleAPFloat>(Arg.getSemantics()))
+    return hash_value(Arg.U.Double);
+  llvm_unreachable("Unexpected semantics");
+}
 
 APFloat::APFloat(const fltSemantics &Semantics, StringRef S)
     : APFloat(Semantics) {
@@ -4146,10 +4369,8 @@ APFloat::opStatus APFloat::convert(const
   if (usesLayout<IEEEFloat>(getSemantics()) &&
       usesLayout<DoubleAPFloat>(ToSemantics)) {
     assert(&ToSemantics == &semPPCDoubleDouble);
-    auto Ret = U.IEEE.convert(semPPCDoubleDoubleImpl, RM, losesInfo);
-    *this = APFloat(DoubleAPFloat(semPPCDoubleDouble, std::move(*this),
-                                  APFloat(semIEEEdouble)),
-                    ToSemantics);
+    auto Ret = U.IEEE.convert(semPPCDoubleDoubleLegacy, RM, losesInfo);
+    *this = APFloat(ToSemantics, U.IEEE.bitcastToAPInt());
     return Ret;
   }
   if (usesLayout<DoubleAPFloat>(getSemantics()) &&
@@ -4191,4 +4412,24 @@ void APFloat::print(raw_ostream &OS) con
 
 void APFloat::dump() const { print(dbgs()); }
 
+void APFloat::Profile(FoldingSetNodeID &NID) const {
+  NID.Add(bitcastToAPInt());
+}
+
+/* Same as convertToInteger(integerPart*, ...), except the result is returned in
+   an APSInt, whose initial bit-width and signed-ness are used to determine the
+   precision of the conversion.
+ */
+APFloat::opStatus APFloat::convertToInteger(APSInt &result,
+                                            roundingMode rounding_mode,
+                                            bool *isExact) const {
+  unsigned bitWidth = result.getBitWidth();
+  SmallVector<uint64_t, 4> parts(result.getNumWords());
+  opStatus status = convertToInteger(parts.data(), bitWidth, result.isSigned(),
+                                     rounding_mode, isExact);
+  // Keeps the original signed-ness.
+  result = APInt(bitWidth, parts);
+  return status;
+}
+
 } // End llvm namespace

Modified: llvm/trunk/test/CodeGen/PowerPC/fp128-bitcast-after-operation.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/PowerPC/fp128-bitcast-after-operation.ll?rev=292839&r1=292838&r2=292839&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/PowerPC/fp128-bitcast-after-operation.ll (original)
+++ llvm/trunk/test/CodeGen/PowerPC/fp128-bitcast-after-operation.ll Mon Jan 23 16:39:35 2017
@@ -128,7 +128,7 @@ entry:
 ; PPC32-DAG: oris {{[0-9]+}}, [[FLIP_BIT]], 16399
 ; PPC32-DAG: xoris {{[0-9]+}}, [[FLIP_BIT]], 48304
 ; PPC32: blr
-	%0 = tail call ppc_fp128 @llvm.copysign.ppcf128(ppc_fp128 0xMBCB0000000000000400F000000000000, ppc_fp128 %x)
+	%0 = tail call ppc_fp128 @llvm.copysign.ppcf128(ppc_fp128 0xM400F000000000000BCB0000000000000, ppc_fp128 %x)
 	%1 = bitcast ppc_fp128 %0 to i128
 	ret i128 %1
 }

Modified: llvm/trunk/unittests/ADT/APFloatTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/APFloatTest.cpp?rev=292839&r1=292838&r2=292839&view=diff
==============================================================================
--- llvm/trunk/unittests/ADT/APFloatTest.cpp (original)
+++ llvm/trunk/unittests/ADT/APFloatTest.cpp Mon Jan 23 16:39:35 2017
@@ -9,6 +9,7 @@
 
 #include "llvm/ADT/APFloat.h"
 #include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/Hashing.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/raw_ostream.h"
@@ -3181,7 +3182,7 @@ TEST(APFloatTest, PPCDoubleDoubleAddSpec
                       0x7948000000000000ull, 0ull, APFloat::fcInfinity,
                       APFloat::rmNearestTiesToEven),
       // TODO: change the 4th 0x75effffffffffffe to 0x75efffffffffffff when
-      // PPCDoubleDoubleImpl is gone.
+      // semPPCDoubleDoubleLegacy is gone.
       // LDBL_MAX + (1.011111... >> (1023 - 106) + (1.1111111...0 >> (1023 -
       // 160))) = fcNormal
       std::make_tuple(0x7fefffffffffffffull, 0x7c8ffffffffffffeull,
@@ -3234,14 +3235,14 @@ TEST(APFloatTest, PPCDoubleDoubleAdd) {
                       0x3ff0000000000000ull, 0x0000000000000001ull,
                       APFloat::rmNearestTiesToEven),
       // TODO: change 0xf950000000000000 to 0xf940000000000000, when
-      // PPCDoubleDoubleImpl is gone.
+      // semPPCDoubleDoubleLegacy is gone.
       // (DBL_MAX - 1 << (1023 - 105)) + (1 << (1023 - 53) + 0) = DBL_MAX +
       // 1.11111... << (1023 - 52)
       std::make_tuple(0x7fefffffffffffffull, 0xf950000000000000ull,
                       0x7c90000000000000ull, 0, 0x7fefffffffffffffull,
                       0x7c8ffffffffffffeull, APFloat::rmNearestTiesToEven),
       // TODO: change 0xf950000000000000 to 0xf940000000000000, when
-      // PPCDoubleDoubleImpl is gone.
+      // semPPCDoubleDoubleLegacy is gone.
       // (1 << (1023 - 53) + 0) + (DBL_MAX - 1 << (1023 - 105)) = DBL_MAX +
       // 1.11111... << (1023 - 52)
       std::make_tuple(0x7c90000000000000ull, 0, 0x7fefffffffffffffull,
@@ -3262,7 +3263,7 @@ TEST(APFloatTest, PPCDoubleDoubleAdd) {
         << formatv("({0:x} + {1:x}) + ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
                    Op2[1])
                .str();
-    EXPECT_EQ(Expected[1], A1.getSecondFloat().bitcastToAPInt().getRawData()[0])
+    EXPECT_EQ(Expected[1], A1.bitcastToAPInt().getRawData()[1])
         << formatv("({0:x} + {1:x}) + ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
                    Op2[1])
                .str();
@@ -3296,7 +3297,7 @@ TEST(APFloatTest, PPCDoubleDoubleSubtrac
         << formatv("({0:x} + {1:x}) - ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
                    Op2[1])
                .str();
-    EXPECT_EQ(Expected[1], A1.getSecondFloat().bitcastToAPInt().getRawData()[0])
+    EXPECT_EQ(Expected[1], A1.bitcastToAPInt().getRawData()[1])
         << formatv("({0:x} + {1:x}) - ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
                    Op2[1])
                .str();
@@ -3496,12 +3497,53 @@ TEST(APFloatTest, PPCDoubleDoubleCompare
     APFloat A1(APFloat::PPCDoubleDouble(), APInt(128, 2, Op1));
     APFloat A2(APFloat::PPCDoubleDouble(), APInt(128, 2, Op2));
     EXPECT_EQ(Expected, A1.compare(A2))
-        << formatv("({0:x} + {1:x}) - ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
+        << formatv("compare(({0:x} + {1:x}), ({2:x} + {3:x}))", Op1[0], Op1[1],
+                   Op2[0], Op2[1])
+               .str();
+  }
+}
+
+TEST(APFloatTest, PPCDoubleDoubleBitwiseIsEqual) {
+  using DataType = std::tuple<uint64_t, uint64_t, uint64_t, uint64_t, bool>;
+
+  DataType Data[] = {
+      // (1 + 0) = (1 + 0)
+      std::make_tuple(0x3ff0000000000000ull, 0, 0x3ff0000000000000ull, 0, true),
+      // (1 + 0) != (1.00...1 + 0)
+      std::make_tuple(0x3ff0000000000000ull, 0, 0x3ff0000000000001ull, 0,
+                      false),
+      // NaN = NaN
+      std::make_tuple(0x7ff8000000000000ull, 0, 0x7ff8000000000000ull, 0, true),
+      // NaN != NaN with a different bit pattern
+      std::make_tuple(0x7ff8000000000000ull, 0, 0x7ff8000000000000ull,
+                      0x3ff0000000000000ull, false),
+      // Inf = Inf
+      std::make_tuple(0x7ff0000000000000ull, 0, 0x7ff0000000000000ull, 0, true),
+  };
+
+  for (auto Tp : Data) {
+    uint64_t Op1[2], Op2[2];
+    bool Expected;
+    std::tie(Op1[0], Op1[1], Op2[0], Op2[1], Expected) = Tp;
+
+    APFloat A1(APFloat::PPCDoubleDouble(), APInt(128, 2, Op1));
+    APFloat A2(APFloat::PPCDoubleDouble(), APInt(128, 2, Op2));
+    EXPECT_EQ(Expected, A1.bitwiseIsEqual(A2))
+        << formatv("({0:x} + {1:x}) = ({2:x} + {3:x})", Op1[0], Op1[1], Op2[0],
                    Op2[1])
                .str();
   }
 }
 
+TEST(APFloatTest, PPCDoubleDoubleHashValue) {
+  uint64_t Data1[] = {0x3ff0000000000001ull, 0x0000000000000001ull};
+  uint64_t Data2[] = {0x3ff0000000000001ull, 0};
+  // The hash values are *hopefully* different.
+  EXPECT_NE(
+      hash_value(APFloat(APFloat::PPCDoubleDouble(), APInt(128, 2, Data1))),
+      hash_value(APFloat(APFloat::PPCDoubleDouble(), APInt(128, 2, Data2))));
+}
+
 TEST(APFloatTest, PPCDoubleDoubleChangeSign) {
   uint64_t Data[] = {
       0x400f000000000000ull, 0xbcb0000000000000ull,
@@ -3531,6 +3573,13 @@ TEST(APFloatTest, PPCDoubleDoubleFactori
   }
   {
     uint64_t Data[] = {
+        0x7fefffffffffffffull, 0x7c8ffffffffffffeull,
+    };
+    EXPECT_EQ(APInt(128, 2, Data),
+              APFloat::getLargest(APFloat::PPCDoubleDouble()).bitcastToAPInt());
+  }
+  {
+    uint64_t Data[] = {
         0x0000000000000001ull, 0,
     };
     EXPECT_EQ(
@@ -3553,24 +3602,72 @@ TEST(APFloatTest, PPCDoubleDoubleFactori
   }
   {
     uint64_t Data[] = {
+        0xffefffffffffffffull, 0xfc8ffffffffffffeull,
+    };
+    EXPECT_EQ(
+        APInt(128, 2, Data),
+        APFloat::getLargest(APFloat::PPCDoubleDouble(), true).bitcastToAPInt());
+  }
+  {
+    uint64_t Data[] = {
         0x8000000000000001ull, 0x0000000000000000ull,
     };
     EXPECT_EQ(APInt(128, 2, Data),
               APFloat::getSmallest(APFloat::PPCDoubleDouble(), true)
                   .bitcastToAPInt());
   }
-
-  EXPECT_EQ(0x8360000000000000ull,
-            APFloat::getSmallestNormalized(APFloat::PPCDoubleDouble(), true)
-                .bitcastToAPInt()
-                .getRawData()[0]);
-  EXPECT_EQ(0x0000000000000000ull,
-            APFloat::getSmallestNormalized(APFloat::PPCDoubleDouble(), true)
-                .getSecondFloat()
-                .bitcastToAPInt()
-                .getRawData()[0]);
-
+  {
+    uint64_t Data[] = {
+        0x8360000000000000ull, 0x0000000000000000ull,
+    };
+    EXPECT_EQ(APInt(128, 2, Data),
+              APFloat::getSmallestNormalized(APFloat::PPCDoubleDouble(), true)
+                  .bitcastToAPInt());
+  }
   EXPECT_TRUE(APFloat::getSmallest(APFloat::PPCDoubleDouble()).isSmallest());
   EXPECT_TRUE(APFloat::getLargest(APFloat::PPCDoubleDouble()).isLargest());
 }
+
+TEST(APFloatTest, PPCDoubleDoubleIsDenormal) {
+  EXPECT_TRUE(APFloat::getSmallest(APFloat::PPCDoubleDouble()).isDenormal());
+  EXPECT_FALSE(APFloat::getLargest(APFloat::PPCDoubleDouble()).isDenormal());
+  EXPECT_FALSE(
+      APFloat::getSmallestNormalized(APFloat::PPCDoubleDouble()).isDenormal());
+  {
+    // (4 + 3) is not normalized
+    uint64_t Data[] = {
+        0x4010000000000000ull, 0x4008000000000000ull,
+    };
+    EXPECT_TRUE(
+        APFloat(APFloat::PPCDoubleDouble(), APInt(128, 2, Data)).isDenormal());
+  }
+}
+
+TEST(APFloatTest, PPCDoubleDoubleScalbn) {
+  // 3.0 + 3.0 << 53
+  uint64_t Input[] = {
+      0x4008000000000000ull, 0x3cb8000000000000ull,
+  };
+  APFloat Result =
+      scalbn(APFloat(APFloat::PPCDoubleDouble(), APInt(128, 2, Input)), 1,
+             APFloat::rmNearestTiesToEven);
+  // 6.0 + 6.0 << 53
+  EXPECT_EQ(0x4018000000000000ull, Result.bitcastToAPInt().getRawData()[0]);
+  EXPECT_EQ(0x3cc8000000000000ull, Result.bitcastToAPInt().getRawData()[1]);
+}
+
+TEST(APFloatTest, PPCDoubleDoubleFrexp) {
+  // 3.0 + 3.0 << 53
+  uint64_t Input[] = {
+      0x4008000000000000ull, 0x3cb8000000000000ull,
+  };
+  int Exp;
+  // 0.75 + 0.75 << 53
+  APFloat Result =
+      frexp(APFloat(APFloat::PPCDoubleDouble(), APInt(128, 2, Input)), Exp,
+            APFloat::rmNearestTiesToEven);
+  EXPECT_EQ(2, Exp);
+  EXPECT_EQ(0x3fe8000000000000ull, Result.bitcastToAPInt().getRawData()[0]);
+  EXPECT_EQ(0x3c98000000000000ull, Result.bitcastToAPInt().getRawData()[1]);
+}
 }




More information about the llvm-commits mailing list