[llvm] r285351 - [APFloat] Add DoubleAPFloat mode to APFloat. NFC.

Tim Shen via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 27 14:39:52 PDT 2016


Author: timshen
Date: Thu Oct 27 16:39:51 2016
New Revision: 285351

URL: http://llvm.org/viewvc/llvm-project?rev=285351&view=rev
Log:
[APFloat] Add DoubleAPFloat mode to APFloat. NFC.

Summary:
This patch adds DoubleAPFloat mode to APFloat.

Now, an APFloat with semantics PPCDoubleDouble will have DoubleAPFloat layout
(APFloat.U.Double), which contains two underlying APFloats as
PPCDoubleDoubleImpl and IEEEdouble semantics. Currently the IEEEdouble APFloat
is not used, and the first APFloat behaves exactly the same before this change.

This patch consists of three kinds of logics:
1) Construction and destruction of APFloat. Now the ctors, dtor, assign
   opertors and factory functions construct different underlying layout
   based on the semantics passed in.
2) s/IEEE/getIEEE()/ for normal, lifetime-unrelated computation functions.
   These functions only access Floats[0] in DoubleAPFloat, which is the
   same as today's semantic.
3) A "Double dispatch" function, APFloat::convert. Converting between two
   different layouts requires appropriate logic.

Neither of these change the external behavior.

Reviewers: hfinkel, kbarton, echristo, iteratee

Subscribers: mehdi_amini, llvm-commits

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

Modified:
    llvm/trunk/include/llvm/ADT/APFloat.h
    llvm/trunk/lib/Support/APFloat.cpp

Modified: llvm/trunk/include/llvm/ADT/APFloat.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/APFloat.h?rev=285351&r1=285350&r2=285351&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/APFloat.h (original)
+++ llvm/trunk/include/llvm/ADT/APFloat.h Thu Oct 27 16:39:51 2016
@@ -18,12 +18,15 @@
 #define LLVM_ADT_APFLOAT_H
 
 #include "llvm/ADT/APInt.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <memory>
 
 namespace llvm {
 
 struct fltSemantics;
 class APSInt;
 class StringRef;
+class APFloat;
 
 template <typename T> class SmallVectorImpl;
 
@@ -206,13 +209,12 @@ struct APFloatBase {
 
 namespace detail {
 
-class IEEEFloat : public APFloatBase {
+class IEEEFloat final : public APFloatBase {
 public:
   /// \name Constructors
   /// @{
 
   IEEEFloat(const fltSemantics &); // Default construct to 0.0
-  IEEEFloat(const fltSemantics &, StringRef);
   IEEEFloat(const fltSemantics &, integerPart);
   IEEEFloat(const fltSemantics &, uninitializedTag);
   IEEEFloat(const fltSemantics &, const APInt &);
@@ -230,74 +232,10 @@ public:
   /// \name Convenience "constructors"
   /// @{
 
-  /// Factory for Positive and Negative Zero.
-  ///
-  /// \param Negative True iff the number should be negative.
-  static IEEEFloat getZero(const fltSemantics &Sem, bool Negative = false) {
-    IEEEFloat Val(Sem, uninitialized);
-    Val.makeZero(Negative);
-    return Val;
-  }
-
-  /// Factory for Positive and Negative Infinity.
-  ///
-  /// \param Negative True iff the number should be negative.
-  static IEEEFloat getInf(const fltSemantics &Sem, bool Negative = false) {
-    IEEEFloat Val(Sem, uninitialized);
-    Val.makeInf(Negative);
-    return Val;
-  }
-
-  /// Factory for QNaN values.
-  ///
-  /// \param Negative - True iff the NaN generated should be negative.
-  /// \param type - The unspecified fill bits for creating the NaN, 0 by
-  /// default.  The value is truncated as necessary.
-  static IEEEFloat getNaN(const fltSemantics &Sem, bool Negative = false,
-                          unsigned type = 0) {
-    if (type) {
-      APInt fill(64, type);
-      return getQNaN(Sem, Negative, &fill);
-    } else {
-      return getQNaN(Sem, Negative, nullptr);
-    }
-  }
-
-  /// Factory for QNaN values.
-  static IEEEFloat getQNaN(const fltSemantics &Sem, bool Negative = false,
-                           const APInt *payload = nullptr) {
-    return makeNaN(Sem, false, Negative, payload);
-  }
-
-  /// Factory for SNaN values.
-  static IEEEFloat getSNaN(const fltSemantics &Sem, bool Negative = false,
-                           const APInt *payload = nullptr) {
-    return makeNaN(Sem, true, Negative, payload);
-  }
-
-  /// Returns the largest finite number in the given semantics.
-  ///
-  /// \param Negative - True iff the number should be negative
-  static IEEEFloat getLargest(const fltSemantics &Sem, bool Negative = false);
-
-  /// Returns the smallest (by magnitude) finite number in the given semantics.
-  /// Might be denormalized, which implies a relative loss of precision.
-  ///
-  /// \param Negative - True iff the number should be negative
-  static IEEEFloat getSmallest(const fltSemantics &Sem, bool Negative = false);
-
-  /// Returns the smallest (by magnitude) normalized finite number in the given
-  /// semantics.
-  ///
-  /// \param Negative - True iff the number should be negative
-  static IEEEFloat getSmallestNormalized(const fltSemantics &Sem,
-                                         bool Negative = false);
-
   /// Returns a float which is bitcasted from an all one value int.
   ///
   /// \param BitWidth - Select float type
-  /// \param isIEEE   - If 128 bit number, select between PPC and IEEE
-  static IEEEFloat getAllOnesValue(unsigned BitWidth, bool isIEEE = false);
+  static IEEEFloat getAllOnesValue(unsigned BitWidth);
 
   /// @}
 
@@ -527,6 +465,25 @@ public:
 
   friend IEEEFloat frexp(const IEEEFloat &X, int &Exp, roundingMode);
 
+  /// \name Special value setters.
+  /// @{
+
+  void makeLargest(bool Neg = false);
+  void makeSmallest(bool Neg = false);
+  void makeNaN(bool SNaN = false, bool Neg = false,
+               const APInt *fill = nullptr);
+  void makeInf(bool Neg = false);
+  void makeZero(bool Neg = false);
+  void makeQuiet();
+
+  /// Returns the smallest (by magnitude) normalized finite number in the given
+  /// semantics.
+  ///
+  /// \param Negative - True iff the number should be negative
+  void makeSmallestNormalized(bool Negative = false);
+
+  /// @}
+
 private:
   /// \name Simple Queries
   /// @{
@@ -569,21 +526,6 @@ private:
 
   /// @}
 
-  /// \name Special value setters.
-  /// @{
-
-  void makeLargest(bool Neg = false);
-  void makeSmallest(bool Neg = false);
-  void makeNaN(bool SNaN = false, bool Neg = false,
-               const APInt *fill = nullptr);
-  static IEEEFloat makeNaN(const fltSemantics &Sem, bool SNaN, bool Negative,
-                           const APInt *fill);
-  void makeInf(bool Neg = false);
-  void makeZero(bool Neg = false);
-  void makeQuiet();
-
-  /// @}
-
   /// \name Miscellany
   /// @{
 
@@ -624,6 +566,7 @@ private:
   void copySignificand(const IEEEFloat &);
   void freeSignificand();
 
+  /// Note: this must be the first data member.
   /// The semantics that this value obeys.
   const fltSemantics *semantics;
 
@@ -653,213 +596,426 @@ int ilogb(const IEEEFloat &Arg);
 IEEEFloat scalbn(IEEEFloat X, int Exp, IEEEFloat::roundingMode);
 IEEEFloat frexp(const IEEEFloat &Val, int &Exp, IEEEFloat::roundingMode RM);
 
+// This mode implements more precise float in terms of two APFloats.
+// The interface and layout is designed for arbitray underlying semantics,
+// though currently only PPCDoubleDouble semantics are supported, whose
+// corresponding underlying semantics are IEEEdouble.
+class DoubleAPFloat final : public APFloatBase {
+  // Note: this must be the first data member.
+  const fltSemantics *Semantics;
+  std::unique_ptr<APFloat[]> Floats;
+
+public:
+  DoubleAPFloat(const fltSemantics &S);
+  DoubleAPFloat(const fltSemantics &S, uninitializedTag);
+  DoubleAPFloat(const fltSemantics &S, integerPart);
+  DoubleAPFloat(const fltSemantics &S, const APInt &I);
+  DoubleAPFloat(const fltSemantics &S, APFloat &&First, APFloat &&Second);
+  DoubleAPFloat(const DoubleAPFloat &RHS);
+  DoubleAPFloat(DoubleAPFloat &&RHS);
+
+  DoubleAPFloat &operator=(const DoubleAPFloat &RHS);
+
+  DoubleAPFloat &operator=(DoubleAPFloat &&RHS) {
+    if (this != &RHS) {
+      this->~DoubleAPFloat();
+      new (this) DoubleAPFloat(std::move(RHS));
+    }
+    return *this;
+  }
+
+  bool needsCleanup() const { return Floats != nullptr; }
+
+  APFloat &getFirst() { return Floats[0]; }
+  const APFloat &getFirst() const { return Floats[0]; }
+};
+
 } // End detail namespace
 
 // This is a interface class that is currently forwarding functionalities from
 // detail::IEEEFloat.
 class APFloat : public APFloatBase {
   typedef detail::IEEEFloat IEEEFloat;
+  typedef detail::DoubleAPFloat DoubleAPFloat;
 
   static_assert(std::is_standard_layout<IEEEFloat>::value, "");
 
-  union {
+  union Storage {
     const fltSemantics *semantics;
     IEEEFloat IEEE;
-  };
+    DoubleAPFloat Double;
 
-  explicit APFloat(IEEEFloat F) : IEEE(std::move(F)) {}
+    explicit Storage(IEEEFloat F) : IEEE(std::move(F)) {}
+    explicit Storage(DoubleAPFloat F) : Double(std::move(F)) {}
 
-public:
-  APFloat(const fltSemantics &Semantics) : APFloat(IEEEFloat(Semantics)) {}
-  APFloat(const fltSemantics &Semantics, StringRef S);
-  APFloat(const fltSemantics &Semantics, integerPart I)
-      : APFloat(IEEEFloat(Semantics, I)) {}
-  APFloat(const fltSemantics &Semantics, uninitializedTag U)
-      : APFloat(IEEEFloat(Semantics, U)) {}
-  APFloat(const fltSemantics &Semantics, const APInt &I)
-      : APFloat(IEEEFloat(Semantics, I)) {}
-  explicit APFloat(double d) : APFloat(IEEEFloat(d)) {}
-  explicit APFloat(float f) : APFloat(IEEEFloat(f)) {}
-  APFloat(const APFloat &RHS) : APFloat(IEEEFloat(RHS.IEEE)) {}
-  APFloat(APFloat &&RHS) : APFloat(IEEEFloat(std::move(RHS.IEEE))) {}
+    template <typename... ArgTypes>
+    Storage(const fltSemantics &Semantics, ArgTypes &&... Args) {
+      if (usesLayout<IEEEFloat>(Semantics)) {
+        new (&IEEE) IEEEFloat(Semantics, std::forward<ArgTypes>(Args)...);
+      } else if (usesLayout<DoubleAPFloat>(Semantics)) {
+        new (&Double) DoubleAPFloat(Semantics, std::forward<ArgTypes>(Args)...);
+      } else {
+        llvm_unreachable("Unexpected semantics");
+      }
+    }
+
+    ~Storage() {
+      if (usesLayout<IEEEFloat>(*semantics)) {
+        IEEE.~IEEEFloat();
+      } else if (usesLayout<DoubleAPFloat>(*semantics)) {
+        Double.~DoubleAPFloat();
+      } else {
+        llvm_unreachable("Unexpected semantics");
+      }
+    }
+
+    Storage(const Storage &RHS) {
+      if (usesLayout<IEEEFloat>(*RHS.semantics)) {
+        new (this) IEEEFloat(RHS.IEEE);
+      } else if (usesLayout<DoubleAPFloat>(*RHS.semantics)) {
+        new (this) DoubleAPFloat(RHS.Double);
+      } else {
+        llvm_unreachable("Unexpected semantics");
+      }
+    }
+
+    Storage(Storage &&RHS) {
+      if (usesLayout<IEEEFloat>(*RHS.semantics)) {
+        new (this) IEEEFloat(std::move(RHS.IEEE));
+      } else if (usesLayout<DoubleAPFloat>(*RHS.semantics)) {
+        new (this) DoubleAPFloat(std::move(RHS.Double));
+      } else {
+        llvm_unreachable("Unexpected semantics");
+      }
+    }
+
+    Storage &operator=(const Storage &RHS) {
+      if (usesLayout<IEEEFloat>(*semantics) &&
+          usesLayout<IEEEFloat>(*RHS.semantics)) {
+        IEEE = RHS.IEEE;
+      } else if (usesLayout<DoubleAPFloat>(*semantics) &&
+                 usesLayout<DoubleAPFloat>(*RHS.semantics)) {
+        Double = RHS.Double;
+      } else if (this != &RHS) {
+        this->~Storage();
+        new (this) Storage(RHS);
+      }
+      return *this;
+    }
+
+    Storage &operator=(Storage &&RHS) {
+      if (usesLayout<IEEEFloat>(*semantics) &&
+          usesLayout<IEEEFloat>(*RHS.semantics)) {
+        IEEE = std::move(RHS.IEEE);
+      } else if (usesLayout<DoubleAPFloat>(*semantics) &&
+                 usesLayout<DoubleAPFloat>(*RHS.semantics)) {
+        Double = std::move(RHS.Double);
+      } else if (this != &RHS) {
+        this->~Storage();
+        new (this) Storage(RHS);
+      }
+      return *this;
+    }
+  } U;
+
+  template <typename T> static bool usesLayout(const fltSemantics &Semantics) {
+    static_assert(std::is_same<T, IEEEFloat>::value ||
+                  std::is_same<T, DoubleAPFloat>::value, "");
+    if (std::is_same<T, DoubleAPFloat>::value) {
+      return &Semantics == &PPCDoubleDouble;
+    }
+    return &Semantics != &PPCDoubleDouble;
+  }
+
+  IEEEFloat &getIEEE() {
+    if (usesLayout<IEEEFloat>(*U.semantics)) {
+      return U.IEEE;
+    } else if (usesLayout<DoubleAPFloat>(*U.semantics)) {
+      return U.Double.getFirst().U.IEEE;
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
+  }
+
+  const IEEEFloat &getIEEE() const {
+    if (usesLayout<IEEEFloat>(*U.semantics)) {
+      return U.IEEE;
+    } else if (usesLayout<DoubleAPFloat>(*U.semantics)) {
+      return U.Double.getFirst().U.IEEE;
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
+  }
 
-  ~APFloat() { IEEE.~IEEEFloat(); }
+  void makeZero(bool Neg) { getIEEE().makeZero(Neg); }
 
-  bool needsCleanup() const { return IEEE.needsCleanup(); }
+  void makeInf(bool Neg) { getIEEE().makeInf(Neg); }
 
+  void makeNaN(bool SNaN, bool Neg, const APInt *fill) {
+    getIEEE().makeNaN(SNaN, Neg, fill);
+  }
+
+  void makeLargest(bool Neg) { getIEEE().makeLargest(Neg); }
+
+  void makeSmallest(bool Neg) { getIEEE().makeSmallest(Neg); }
+
+  void makeSmallestNormalized(bool Neg) {
+    getIEEE().makeSmallestNormalized(Neg);
+  }
+
+  explicit APFloat(IEEEFloat F) : U(std::move(F)) {}
+  explicit APFloat(DoubleAPFloat F) : U(std::move(F)) {}
+
+public:
+  APFloat(const fltSemantics &Semantics) : U(Semantics) {}
+  APFloat(const fltSemantics &Semantics, StringRef S);
+  APFloat(const fltSemantics &Semantics, integerPart I) : U(Semantics, I) {}
+  APFloat(const fltSemantics &Semantics, uninitializedTag)
+      : U(Semantics, uninitialized) {}
+  APFloat(const fltSemantics &Semantics, const APInt &I) : U(Semantics, I) {}
+  explicit APFloat(double d) : U(IEEEFloat(d)) {}
+  explicit APFloat(float f) : U(IEEEFloat(f)) {}
+  APFloat(const APFloat &RHS) = default;
+  APFloat(APFloat &&RHS) = default;
+
+  ~APFloat() = default;
+
+  bool needsCleanup() const {
+    if (usesLayout<IEEEFloat>(getSemantics())) {
+      return U.IEEE.needsCleanup();
+    } else if (usesLayout<DoubleAPFloat>(getSemantics())) {
+      return U.Double.needsCleanup();
+    } else {
+      llvm_unreachable("Unexpected semantics");
+    }
+  }
+
+  /// Factory for Positive and Negative Zero.
+  ///
+  /// \param Negative True iff the number should be negative.
   static APFloat getZero(const fltSemantics &Sem, bool Negative = false) {
-    return APFloat(IEEEFloat::getZero(Sem, Negative));
+    APFloat Val(Sem, uninitialized);
+    Val.makeZero(Negative);
+    return Val;
   }
 
+  /// Factory for Positive and Negative Infinity.
+  ///
+  /// \param Negative True iff the number should be negative.
   static APFloat getInf(const fltSemantics &Sem, bool Negative = false) {
-    return APFloat(IEEEFloat::getInf(Sem, Negative));
+    APFloat Val(Sem, uninitialized);
+    Val.makeInf(Negative);
+    return Val;
   }
 
+  /// Factory for NaN values.
+  ///
+  /// \param Negative - True iff the NaN generated should be negative.
+  /// \param type - The unspecified fill bits for creating the NaN, 0 by
+  /// default.  The value is truncated as necessary.
   static APFloat getNaN(const fltSemantics &Sem, bool Negative = false,
                         unsigned type = 0) {
-    return APFloat(IEEEFloat::getNaN(Sem, Negative, type));
+    if (type) {
+      APInt fill(64, type);
+      return getQNaN(Sem, Negative, &fill);
+    } else {
+      return getQNaN(Sem, Negative, nullptr);
+    }
   }
 
+  /// Factory for QNaN values.
   static APFloat getQNaN(const fltSemantics &Sem, bool Negative = false,
                          const APInt *payload = nullptr) {
-    return APFloat(IEEEFloat::getQNaN(Sem, Negative, payload));
+    APFloat Val(Sem, uninitialized);
+    Val.makeNaN(false, Negative, payload);
+    return Val;
   }
 
+  /// Factory for SNaN values.
   static APFloat getSNaN(const fltSemantics &Sem, bool Negative = false,
                          const APInt *payload = nullptr) {
-    return APFloat(IEEEFloat::getSNaN(Sem, Negative, payload));
+    APFloat Val(Sem, uninitialized);
+    Val.makeNaN(true, Negative, payload);
+    return Val;
   }
 
+  /// Returns the largest finite number in the given semantics.
+  ///
+  /// \param Negative - True iff the number should be negative
   static APFloat getLargest(const fltSemantics &Sem, bool Negative = false) {
-    return APFloat(IEEEFloat::getLargest(Sem, Negative));
+    APFloat Val(Sem, uninitialized);
+    Val.makeLargest(Negative);
+    return Val;
   }
 
+  /// Returns the smallest (by magnitude) finite number in the given semantics.
+  /// Might be denormalized, which implies a relative loss of precision.
+  ///
+  /// \param Negative - True iff the number should be negative
   static APFloat getSmallest(const fltSemantics &Sem, bool Negative = false) {
-    return APFloat(IEEEFloat::getSmallest(Sem, Negative));
+    APFloat Val(Sem, uninitialized);
+    Val.makeSmallest(Negative);
+    return Val;
   }
 
+  /// Returns the smallest (by magnitude) normalized finite number in the given
+  /// semantics.
+  ///
+  /// \param Negative - True iff the number should be negative
   static APFloat getSmallestNormalized(const fltSemantics &Sem,
                                        bool Negative = false) {
-    return APFloat(IEEEFloat::getSmallestNormalized(Sem, Negative));
+    APFloat Val(Sem, uninitialized);
+    Val.makeSmallestNormalized(Negative);
+    return Val;
   }
 
+  /// Returns a float which is bitcasted from an all one value int.
+  ///
+  /// \param BitWidth - Select float type
+  /// \param isIEEE   - If 128 bit number, select between PPC and IEEE
   static APFloat getAllOnesValue(unsigned BitWidth, bool isIEEE = false) {
-    return APFloat(IEEEFloat::getAllOnesValue(BitWidth, isIEEE));
+    if (isIEEE) {
+      return APFloat(IEEEFloat::getAllOnesValue(BitWidth));
+    } else {
+      assert(BitWidth == 128);
+      return APFloat(PPCDoubleDouble, APInt::getAllOnesValue(BitWidth));
+    }
   }
 
-  void Profile(FoldingSetNodeID &NID) const { IEEE.Profile(NID); }
+  void Profile(FoldingSetNodeID &NID) const { getIEEE().Profile(NID); }
 
   opStatus add(const APFloat &RHS, roundingMode RM) {
-    return IEEE.add(RHS.IEEE, RM);
+    return getIEEE().add(RHS.getIEEE(), RM);
   }
   opStatus subtract(const APFloat &RHS, roundingMode RM) {
-    return IEEE.subtract(RHS.IEEE, RM);
+    return getIEEE().subtract(RHS.getIEEE(), RM);
   }
   opStatus multiply(const APFloat &RHS, roundingMode RM) {
-    return IEEE.multiply(RHS.IEEE, RM);
+    return getIEEE().multiply(RHS.getIEEE(), RM);
   }
   opStatus divide(const APFloat &RHS, roundingMode RM) {
-    return IEEE.divide(RHS.IEEE, RM);
+    return getIEEE().divide(RHS.getIEEE(), RM);
+  }
+  opStatus remainder(const APFloat &RHS) {
+    return getIEEE().remainder(RHS.getIEEE());
   }
-  opStatus remainder(const APFloat &RHS) { return IEEE.remainder(RHS.IEEE); }
-  opStatus mod(const APFloat &RHS) { return IEEE.mod(RHS.IEEE); }
+  opStatus mod(const APFloat &RHS) { return getIEEE().mod(RHS.getIEEE()); }
   opStatus fusedMultiplyAdd(const APFloat &Multiplicand, const APFloat &Addend,
                             roundingMode RM) {
-    return IEEE.fusedMultiplyAdd(Multiplicand.IEEE, Addend.IEEE, RM);
+    return getIEEE().fusedMultiplyAdd(Multiplicand.getIEEE(), Addend.getIEEE(),
+                                      RM);
   }
-  opStatus roundToIntegral(roundingMode RM) { return IEEE.roundToIntegral(RM); }
-  opStatus next(bool nextDown) { return IEEE.next(nextDown); }
+  opStatus roundToIntegral(roundingMode RM) {
+    return getIEEE().roundToIntegral(RM);
+  }
+  opStatus next(bool nextDown) { return getIEEE().next(nextDown); }
 
   APFloat operator+(const APFloat &RHS) const {
-    return APFloat(IEEE + RHS.IEEE);
+    return APFloat(getIEEE() + RHS.getIEEE());
   }
 
   APFloat operator-(const APFloat &RHS) const {
-    return APFloat(IEEE - RHS.IEEE);
+    return APFloat(getIEEE() - RHS.getIEEE());
   }
 
   APFloat operator*(const APFloat &RHS) const {
-    return APFloat(IEEE * RHS.IEEE);
+    return APFloat(getIEEE() * RHS.getIEEE());
   }
 
   APFloat operator/(const APFloat &RHS) const {
-    return APFloat(IEEE / RHS.IEEE);
+    return APFloat(getIEEE() / RHS.getIEEE());
   }
 
-  void changeSign() { IEEE.changeSign(); }
-  void clearSign() { IEEE.clearSign(); }
-  void copySign(const APFloat &RHS) { IEEE.copySign(RHS.IEEE); }
+  void changeSign() { getIEEE().changeSign(); }
+  void clearSign() { getIEEE().clearSign(); }
+  void copySign(const APFloat &RHS) { getIEEE().copySign(RHS.getIEEE()); }
 
   static APFloat copySign(APFloat Value, const APFloat &Sign) {
-    return APFloat(IEEEFloat::copySign(Value.IEEE, Sign.IEEE));
+    return APFloat(IEEEFloat::copySign(Value.getIEEE(), Sign.getIEEE()));
   }
 
   opStatus convert(const fltSemantics &ToSemantics, roundingMode RM,
-                   bool *losesInfo) {
-    return IEEE.convert(ToSemantics, RM, losesInfo);
-  }
+                   bool *losesInfo);
   opStatus convertToInteger(integerPart *Input, unsigned int Width,
                             bool IsSigned, roundingMode RM,
                             bool *IsExact) const {
-    return IEEE.convertToInteger(Input, Width, IsSigned, RM, IsExact);
+    return getIEEE().convertToInteger(Input, Width, IsSigned, RM, IsExact);
   }
   opStatus convertToInteger(APSInt &Result, roundingMode RM,
                             bool *IsExact) const {
-    return IEEE.convertToInteger(Result, RM, IsExact);
+    return getIEEE().convertToInteger(Result, RM, IsExact);
   }
   opStatus convertFromAPInt(const APInt &Input, bool IsSigned,
                             roundingMode RM) {
-    return IEEE.convertFromAPInt(Input, IsSigned, RM);
+    return getIEEE().convertFromAPInt(Input, IsSigned, RM);
   }
   opStatus convertFromSignExtendedInteger(const integerPart *Input,
                                           unsigned int InputSize, bool IsSigned,
                                           roundingMode RM) {
-    return IEEE.convertFromSignExtendedInteger(Input, InputSize, IsSigned, RM);
+    return getIEEE().convertFromSignExtendedInteger(Input, InputSize, IsSigned,
+                                                    RM);
   }
   opStatus convertFromZeroExtendedInteger(const integerPart *Input,
                                           unsigned int InputSize, bool IsSigned,
                                           roundingMode RM) {
-    return IEEE.convertFromZeroExtendedInteger(Input, InputSize, IsSigned, RM);
+    return getIEEE().convertFromZeroExtendedInteger(Input, InputSize, IsSigned,
+                                                    RM);
   }
   opStatus convertFromString(StringRef, roundingMode);
-  APInt bitcastToAPInt() const { return IEEE.bitcastToAPInt(); }
-  double convertToDouble() const { return IEEE.convertToDouble(); }
-  float convertToFloat() const { return IEEE.convertToFloat(); }
+  APInt bitcastToAPInt() const { return getIEEE().bitcastToAPInt(); }
+  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 IEEE.compare(RHS.IEEE); }
+  cmpResult compare(const APFloat &RHS) const {
+    return getIEEE().compare(RHS.getIEEE());
+  }
 
   bool bitwiseIsEqual(const APFloat &RHS) const {
-    return IEEE.bitwiseIsEqual(RHS.IEEE);
+    return getIEEE().bitwiseIsEqual(RHS.getIEEE());
   }
 
   unsigned int convertToHexString(char *DST, unsigned int HexDigits,
                                   bool UpperCase, roundingMode RM) const {
-    return IEEE.convertToHexString(DST, HexDigits, UpperCase, RM);
+    return getIEEE().convertToHexString(DST, HexDigits, UpperCase, RM);
   }
 
   bool isZero() const { return getCategory() == fcZero; }
   bool isInfinity() const { return getCategory() == fcInfinity; }
   bool isNaN() const { return getCategory() == fcNaN; }
 
-  bool isNegative() const { return IEEE.isNegative(); }
-  bool isDenormal() const { return IEEE.isDenormal(); }
-  bool isSignaling() const { return IEEE.isSignaling(); }
+  bool isNegative() const { return getIEEE().isNegative(); }
+  bool isDenormal() const { return getIEEE().isDenormal(); }
+  bool isSignaling() const { return getIEEE().isSignaling(); }
 
   bool isNormal() const { return !isDenormal() && isFiniteNonZero(); }
   bool isFinite() const { return !isNaN() && !isInfinity(); }
 
-  fltCategory getCategory() const { return IEEE.getCategory(); }
-  const fltSemantics &getSemantics() const { return *semantics; }
+  fltCategory getCategory() const { return getIEEE().getCategory(); }
+  const fltSemantics &getSemantics() const { return *U.semantics; }
   bool isNonZero() const { return !isZero(); }
   bool isFiniteNonZero() const { return isFinite() && !isZero(); }
   bool isPosZero() const { return isZero() && !isNegative(); }
   bool isNegZero() const { return isZero() && isNegative(); }
-  bool isSmallest() const { return IEEE.isSmallest(); }
-  bool isLargest() const { return IEEE.isLargest(); }
-  bool isInteger() const { return IEEE.isInteger(); }
+  bool isSmallest() const { return getIEEE().isSmallest(); }
+  bool isLargest() const { return getIEEE().isLargest(); }
+  bool isInteger() const { return getIEEE().isInteger(); }
 
-  APFloat &operator=(const APFloat &RHS) {
-    IEEE = RHS.IEEE;
-    return *this;
-  }
-  APFloat &operator=(APFloat &&RHS) {
-    IEEE = std::move(RHS.IEEE);
-    return *this;
-  }
+  APFloat &operator=(const APFloat &RHS) = default;
+  APFloat &operator=(APFloat &&RHS) = default;
 
   void toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision = 0,
                 unsigned FormatMaxPadding = 3) const {
-    return IEEE.toString(Str, FormatPrecision, FormatMaxPadding);
+    return getIEEE().toString(Str, FormatPrecision, FormatMaxPadding);
   }
 
   bool getExactInverse(APFloat *inv) const {
-    return IEEE.getExactInverse(inv ? &inv->IEEE : nullptr);
+    return getIEEE().getExactInverse(inv ? &inv->getIEEE() : nullptr);
   }
 
   friend hash_code hash_value(const APFloat &Arg);
-  friend int ilogb(const APFloat &Arg) { return ilogb(Arg.IEEE); }
+  friend int ilogb(const APFloat &Arg) { return ilogb(Arg.getIEEE()); }
   friend APFloat scalbn(APFloat X, int Exp, roundingMode RM);
   friend APFloat frexp(const APFloat &X, int &Exp, roundingMode RM);
 };
@@ -870,7 +1026,7 @@ public:
 /// xlC compiler.
 hash_code hash_value(const APFloat &Arg);
 inline APFloat scalbn(APFloat X, int Exp, APFloat::roundingMode RM) {
-  return APFloat(scalbn(X.IEEE, Exp, RM));
+  return APFloat(scalbn(X.getIEEE(), Exp, RM));
 }
 
 /// \brief Equivalent of C standard library function.
@@ -878,7 +1034,7 @@ 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.IEEE, Exp, RM));
+  return APFloat(frexp(X.getIEEE(), Exp, RM));
 }
 /// \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=285351&r1=285350&r2=285351&view=diff
==============================================================================
--- llvm/trunk/lib/Support/APFloat.cpp (original)
+++ llvm/trunk/lib/Support/APFloat.cpp Thu Oct 27 16:39:51 2016
@@ -75,8 +75,18 @@ namespace llvm {
      to represent all possible values held by a PPC double-double number,
      for example: (long double) 1.0 + (long double) 0x1p-106
      Should this be replaced by a full emulation of PPC double-double?  */
-  const fltSemantics APFloatBase::PPCDoubleDouble = {1023, -1022 + 53, 53 + 53,
-                                                     128};
+  const fltSemantics APFloatBase::PPCDoubleDouble = {0, 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 PPCDoubleDoubleImpl = {1023, -1022 + 53, 53 + 53,
+                                                   128};
 
   /* A tight upper bound on number of parts required to hold the value
      pow(5, power) is
@@ -677,13 +687,6 @@ void IEEEFloat::makeNaN(bool SNaN, bool
     APInt::tcSetBit(significand, QNaNBit + 1);
 }
 
-IEEEFloat IEEEFloat::makeNaN(const fltSemantics &Sem, bool SNaN, bool Negative,
-                             const APInt *fill) {
-  IEEEFloat value(Sem, uninitialized);
-  value.makeNaN(SNaN, Negative, fill);
-  return value;
-}
-
 IEEEFloat &IEEEFloat::operator=(const IEEEFloat &rhs) {
   if (this != &rhs) {
     if (semantics != rhs.semantics) {
@@ -820,11 +823,6 @@ IEEEFloat::IEEEFloat(const fltSemantics
   initialize(&ourSemantics);
 }
 
-IEEEFloat::IEEEFloat(const fltSemantics &ourSemantics, StringRef text) {
-  initialize(&ourSemantics);
-  convertFromString(text, rmNearestTiesToEven);
-}
-
 IEEEFloat::IEEEFloat(const IEEEFloat &rhs) {
   initialize(rhs.semantics);
   assign(rhs);
@@ -2366,7 +2364,8 @@ IEEEFloat::roundSignificandWithExponent(
     excessPrecision = calcSemantics.precision - semantics->precision;
     truncatedBits = excessPrecision;
 
-    IEEEFloat decSig = IEEEFloat::getZero(calcSemantics, sign);
+    IEEEFloat decSig(calcSemantics, uninitialized);
+    decSig.makeZero(sign);
     IEEEFloat pow5(calcSemantics);
 
     sigStatus = decSig.convertFromUnsignedParts(decSigParts, sigPartCount,
@@ -2821,7 +2820,7 @@ APInt IEEEFloat::convertF80LongDoubleAPF
 }
 
 APInt IEEEFloat::convertPPCDoubleDoubleAPFloatToAPInt() const {
-  assert(semantics == (const llvm::fltSemantics*)&PPCDoubleDouble);
+  assert(semantics == (const llvm::fltSemantics *)&PPCDoubleDoubleImpl);
   assert(partCount()==2);
 
   uint64_t words[2];
@@ -3002,7 +3001,7 @@ APInt IEEEFloat::bitcastToAPInt() const
   if (semantics == (const llvm::fltSemantics*)&IEEEquad)
     return convertQuadrupleAPFloatToAPInt();
 
-  if (semantics == (const llvm::fltSemantics*)&PPCDoubleDouble)
+  if (semantics == (const llvm::fltSemantics *)&PPCDoubleDoubleImpl)
     return convertPPCDoubleDoubleAPFloatToAPInt();
 
   assert(semantics == (const llvm::fltSemantics*)&x87DoubleExtended &&
@@ -3072,14 +3071,14 @@ void IEEEFloat::initFromPPCDoubleDoubleA
 
   // Get the first double and convert to our format.
   initFromDoubleAPInt(APInt(64, i1));
-  fs = convert(PPCDoubleDouble, rmNearestTiesToEven, &losesInfo);
+  fs = convert(PPCDoubleDoubleImpl, rmNearestTiesToEven, &losesInfo);
   assert(fs == opOK && !losesInfo);
   (void)fs;
 
   // Unless we have a special case, add in second double.
   if (isFiniteNonZero()) {
     IEEEFloat v(IEEEdouble, APInt(64, i2));
-    fs = v.convert(PPCDoubleDouble, rmNearestTiesToEven, &losesInfo);
+    fs = v.convert(PPCDoubleDoubleImpl, rmNearestTiesToEven, &losesInfo);
     assert(fs == opOK && !losesInfo);
     (void)fs;
 
@@ -3233,13 +3232,13 @@ void IEEEFloat::initFromAPInt(const fltS
     return initFromF80LongDoubleAPInt(api);
   if (Sem == &IEEEquad)
     return initFromQuadrupleAPInt(api);
-  if (Sem == &PPCDoubleDouble)
+  if (Sem == &PPCDoubleDoubleImpl)
     return initFromPPCDoubleDoubleAPInt(api);
 
   llvm_unreachable(nullptr);
 }
 
-IEEEFloat IEEEFloat::getAllOnesValue(unsigned BitWidth, bool isIEEE) {
+IEEEFloat IEEEFloat::getAllOnesValue(unsigned BitWidth) {
   switch (BitWidth) {
   case 16:
     return IEEEFloat(IEEEhalf, APInt::getAllOnesValue(BitWidth));
@@ -3250,9 +3249,7 @@ IEEEFloat IEEEFloat::getAllOnesValue(uns
   case 80:
     return IEEEFloat(x87DoubleExtended, APInt::getAllOnesValue(BitWidth));
   case 128:
-    if (isIEEE)
-      return IEEEFloat(IEEEquad, APInt::getAllOnesValue(BitWidth));
-    return IEEEFloat(PPCDoubleDouble, APInt::getAllOnesValue(BitWidth));
+    return IEEEFloat(IEEEquad, APInt::getAllOnesValue(BitWidth));
   default:
     llvm_unreachable("Unknown floating bit width");
   }
@@ -3296,43 +3293,18 @@ void IEEEFloat::makeSmallest(bool Negati
   APInt::tcSet(significandParts(), 1, partCount());
 }
 
-IEEEFloat IEEEFloat::getLargest(const fltSemantics &Sem, bool Negative) {
-  // We want (in interchange format):
-  //   sign = {Negative}
-  //   exponent = 1..10
-  //   significand = 1..1
-  IEEEFloat Val(Sem, uninitialized);
-  Val.makeLargest(Negative);
-  return Val;
-}
-
-IEEEFloat IEEEFloat::getSmallest(const fltSemantics &Sem, bool Negative) {
-  // We want (in interchange format):
-  //   sign = {Negative}
-  //   exponent = 0..0
-  //   significand = 0..01
-  IEEEFloat Val(Sem, uninitialized);
-  Val.makeSmallest(Negative);
-  return Val;
-}
-
-IEEEFloat IEEEFloat::getSmallestNormalized(const fltSemantics &Sem,
-                                           bool Negative) {
-  IEEEFloat Val(Sem, uninitialized);
-
+void IEEEFloat::makeSmallestNormalized(bool Negative) {
   // We want (in interchange format):
   //   sign = {Negative}
   //   exponent = 0..0
   //   significand = 10..0
 
-  Val.category = fcNormal;
-  Val.zeroSignificand();
-  Val.sign = Negative;
-  Val.exponent = Sem.minExponent;
-  Val.significandParts()[partCountForBits(Sem.precision)-1] |=
-    (((integerPart) 1) << ((Sem.precision - 1) % integerPartWidth));
-
-  return Val;
+  category = fcNormal;
+  zeroSignificand();
+  sign = Negative;
+  exponent = semantics->minExponent;
+  significandParts()[partCountForBits(semantics->precision) - 1] |=
+      (((integerPart)1) << ((semantics->precision - 1) % integerPartWidth));
 }
 
 IEEEFloat::IEEEFloat(const fltSemantics &Sem, const APInt &API) {
@@ -3868,15 +3840,99 @@ IEEEFloat frexp(const IEEEFloat &Val, in
   return scalbn(Val, -Exp, RM);
 }
 
+DoubleAPFloat::DoubleAPFloat(const fltSemantics &S)
+    : Semantics(&S), Floats(new APFloat[2]{APFloat(PPCDoubleDoubleImpl),
+                                           APFloat(IEEEdouble)}) {
+  assert(Semantics == &PPCDoubleDouble);
+}
+
+DoubleAPFloat::DoubleAPFloat(const fltSemantics &S, uninitializedTag)
+    : Semantics(&S),
+      Floats(new APFloat[2]{APFloat(PPCDoubleDoubleImpl, uninitialized),
+                            APFloat(IEEEdouble, uninitialized)}) {
+  assert(Semantics == &PPCDoubleDouble);
+}
+
+DoubleAPFloat::DoubleAPFloat(const fltSemantics &S, integerPart I)
+    : Semantics(&S), Floats(new APFloat[2]{APFloat(PPCDoubleDoubleImpl, I),
+                                           APFloat(IEEEdouble)}) {
+  assert(Semantics == &PPCDoubleDouble);
+}
+
+DoubleAPFloat::DoubleAPFloat(const fltSemantics &S, const APInt &I)
+    : Semantics(&S), Floats(new APFloat[2]{APFloat(PPCDoubleDoubleImpl, I),
+                                           APFloat(IEEEdouble)}) {
+  assert(Semantics == &PPCDoubleDouble);
+}
+
+DoubleAPFloat::DoubleAPFloat(const fltSemantics &S, APFloat &&First,
+                             APFloat &&Second)
+    : Semantics(&S),
+      Floats(new APFloat[2]{std::move(First), std::move(Second)}) {
+  assert(Semantics == &PPCDoubleDouble);
+  // TODO Check for First == &IEEEdouble once the transition is done.
+  assert(&Floats[0].getSemantics() == &PPCDoubleDoubleImpl);
+  assert(&Floats[1].getSemantics() == &IEEEdouble);
+}
+
+DoubleAPFloat::DoubleAPFloat(const DoubleAPFloat &RHS)
+    : Semantics(RHS.Semantics),
+      Floats(new APFloat[2]{APFloat(RHS.Floats[0]), APFloat(RHS.Floats[1])}) {
+  assert(Semantics == &PPCDoubleDouble);
+}
+
+DoubleAPFloat::DoubleAPFloat(DoubleAPFloat &&RHS)
+    : Semantics(RHS.Semantics), Floats(std::move(RHS.Floats)) {
+  RHS.Semantics = &Bogus;
+  assert(Semantics == &PPCDoubleDouble);
+}
+
+DoubleAPFloat &DoubleAPFloat::operator=(const DoubleAPFloat &RHS) {
+  if (Semantics == RHS.Semantics) {
+    Floats[0] = RHS.Floats[0];
+    Floats[1] = RHS.Floats[1];
+  } else if (this != &RHS) {
+    this->~DoubleAPFloat();
+    new (this) DoubleAPFloat(RHS);
+  }
+  return *this;
+}
+
 } // End detail namespace
 
 APFloat::opStatus APFloat::convertFromString(StringRef Str, roundingMode RM) {
-  return IEEE.convertFromString(Str, RM);
+  return getIEEE().convertFromString(Str, RM);
 }
 
-hash_code hash_value(const APFloat &Arg) { return hash_value(Arg.IEEE); }
+hash_code hash_value(const APFloat &Arg) { return hash_value(Arg.getIEEE()); }
 
 APFloat::APFloat(const fltSemantics &Semantics, StringRef S)
-    : APFloat(IEEEFloat(Semantics, S)) {}
+    : APFloat(Semantics) {
+  convertFromString(S, rmNearestTiesToEven);
+}
+
+APFloat::opStatus APFloat::convert(const fltSemantics &ToSemantics,
+                                   roundingMode RM, bool *losesInfo) {
+  if (&getSemantics() == &ToSemantics)
+    return opOK;
+  if (usesLayout<IEEEFloat>(getSemantics()) &&
+      usesLayout<IEEEFloat>(ToSemantics)) {
+    return U.IEEE.convert(ToSemantics, RM, losesInfo);
+  } else if (usesLayout<IEEEFloat>(getSemantics()) &&
+             usesLayout<DoubleAPFloat>(ToSemantics)) {
+    assert(&ToSemantics == &PPCDoubleDouble);
+    auto Ret = U.IEEE.convert(PPCDoubleDoubleImpl, RM, losesInfo);
+    *this = APFloat(
+        DoubleAPFloat(PPCDoubleDouble, std::move(*this), APFloat(IEEEdouble)));
+    return Ret;
+  } else if (usesLayout<DoubleAPFloat>(getSemantics()) &&
+             usesLayout<IEEEFloat>(ToSemantics)) {
+    auto Ret = getIEEE().convert(ToSemantics, RM, losesInfo);
+    *this = APFloat(std::move(getIEEE()));
+    return Ret;
+  } else {
+    llvm_unreachable("Unexpected semantics");
+  }
+}
 
 } // End llvm namespace




More information about the llvm-commits mailing list