Index: llvm/include/llvm/ADT/APFloat.h =================================================================== --- llvm/include/llvm/ADT/APFloat.h +++ llvm/include/llvm/ADT/APFloat.h @@ -18,12 +18,15 @@ #define LLVM_ADT_APFLOAT_H #include "llvm/ADT/APInt.h" +#include "llvm/Support/ErrorHandling.h" +#include namespace llvm { struct fltSemantics; class APSInt; class StringRef; +class APFloat; template class SmallVectorImpl; @@ -206,13 +209,12 @@ 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 @@ /// \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 @@ 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 @@ /// @} - /// \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 @@ 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 @@ 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 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::value, ""); - union { + union Storage { const fltSemantics *semantics; IEEEFloat IEEE; - }; + DoubleAPFloat Double; + + explicit Storage(IEEEFloat F) : IEEE(std::move(F)) {} + explicit Storage(DoubleAPFloat F) : Double(std::move(F)) {} + + template + Storage(const fltSemantics &Semantics, ArgTypes &&... Args) { + if (usesLayout(Semantics)) { + new (&IEEE) IEEEFloat(Semantics, std::forward(Args)...); + } else if (usesLayout(Semantics)) { + new (&Double) DoubleAPFloat(Semantics, std::forward(Args)...); + } else { + llvm_unreachable("Unexpected semantics"); + } + } - explicit APFloat(IEEEFloat F) : IEEE(std::move(F)) {} + ~Storage() { + if (usesLayout(*semantics)) { + IEEE.~IEEEFloat(); + } else if (usesLayout(*semantics)) { + Double.~DoubleAPFloat(); + } else { + llvm_unreachable("Unexpected semantics"); + } + } -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))) {} + Storage(const Storage &RHS) { + if (usesLayout(*RHS.semantics)) { + new (this) IEEEFloat(RHS.IEEE); + } else if (usesLayout(*RHS.semantics)) { + new (this) DoubleAPFloat(RHS.Double); + } else { + llvm_unreachable("Unexpected semantics"); + } + } + + Storage(Storage &&RHS) { + if (usesLayout(*RHS.semantics)) { + new (this) IEEEFloat(std::move(RHS.IEEE)); + } else if (usesLayout(*RHS.semantics)) { + new (this) DoubleAPFloat(std::move(RHS.Double)); + } else { + llvm_unreachable("Unexpected semantics"); + } + } + + Storage &operator=(const Storage &RHS) { + if (usesLayout(*semantics) && + usesLayout(*RHS.semantics)) { + IEEE = RHS.IEEE; + } else if (usesLayout(*semantics) && + usesLayout(*RHS.semantics)) { + Double = RHS.Double; + } else if (this != &RHS) { + this->~Storage(); + new (this) Storage(RHS); + } + return *this; + } + + Storage &operator=(Storage &&RHS) { + if (usesLayout(*semantics) && + usesLayout(*RHS.semantics)) { + IEEE = std::move(RHS.IEEE); + } else if (usesLayout(*semantics) && + usesLayout(*RHS.semantics)) { + Double = std::move(RHS.Double); + } else if (this != &RHS) { + this->~Storage(); + new (this) Storage(RHS); + } + return *this; + } + } U; + + template static bool usesLayout(const fltSemantics &Semantics) { + static_assert(std::is_same::value || + std::is_same::value, ""); + if (std::is_same::value) { + return &Semantics == &PPCDoubleDouble; + } + return &Semantics != &PPCDoubleDouble; + } + + IEEEFloat &getIEEE() { + if (usesLayout(*U.semantics)) { + return U.IEEE; + } else if (usesLayout(*U.semantics)) { + return U.Double.getFirst().U.IEEE; + } else { + llvm_unreachable("Unexpected semantics"); + } + } + + const IEEEFloat &getIEEE() const { + if (usesLayout(*U.semantics)) { + return U.IEEE; + } else if (usesLayout(*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(getSemantics())) { + return U.IEEE.needsCleanup(); + } else if (usesLayout(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 &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 @@ /// 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 @@ /// 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) { Index: llvm/lib/Support/APFloat.cpp =================================================================== --- llvm/lib/Support/APFloat.cpp +++ llvm/lib/Support/APFloat.cpp @@ -75,8 +75,18 @@ 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 @@ 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 @@ 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 @@ 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::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 @@ 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 @@ // 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 @@ 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 @@ 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 @@ 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 @@ 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(getSemantics()) && + usesLayout(ToSemantics)) { + return U.IEEE.convert(ToSemantics, RM, losesInfo); + } else if (usesLayout(getSemantics()) && + usesLayout(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(getSemantics()) && + usesLayout(ToSemantics)) { + auto Ret = getIEEE().convert(ToSemantics, RM, losesInfo); + *this = APFloat(std::move(getIEEE())); + return Ret; + } else { + llvm_unreachable("Unexpected semantics"); + } +} } // End llvm namespace