Index: clang/test/CodeGen/ppc64-complex-parms.c =================================================================== --- clang/test/CodeGen/ppc64-complex-parms.c +++ clang/test/CodeGen/ppc64-complex-parms.c @@ -93,7 +93,7 @@ // CHECK: %[[VAR22:[A-Za-z0-9.]+]] = getelementptr inbounds { ppc_fp128, ppc_fp128 }, { ppc_fp128, ppc_fp128 }* %[[VAR21]], i32 0, i32 0 // CHECK: %[[VAR23:[A-Za-z0-9.]+]] = getelementptr inbounds { ppc_fp128, ppc_fp128 }, { ppc_fp128, ppc_fp128 }* %[[VAR21]], i32 0, i32 1 // CHECK: store ppc_fp128 0xM40000000000000000000000000000000, ppc_fp128* %[[VAR22]] -// CHECK: store ppc_fp128 0xMC0040000000000000000000000000000, ppc_fp128* %[[VAR23]] +// CHECK: store ppc_fp128 0xMC0040000000000008000000000000000, ppc_fp128* %[[VAR23]] // CHECK: %[[VAR24:[A-Za-z0-9.]+]] = getelementptr inbounds { ppc_fp128, ppc_fp128 }, { ppc_fp128, ppc_fp128 }* %[[VAR21]], i32 0, i32 0 // CHECK: %[[VAR25:[A-Za-z0-9.]+]] = load ppc_fp128, ppc_fp128* %[[VAR24]], align 16 // CHECK: %[[VAR26:[A-Za-z0-9.]+]] = getelementptr inbounds { ppc_fp128, ppc_fp128 }, { ppc_fp128, ppc_fp128 }* %[[VAR21]], i32 0, i32 1 Index: llvm/include/llvm/ADT/APFloat.h =================================================================== --- llvm/include/llvm/ADT/APFloat.h +++ llvm/include/llvm/ADT/APFloat.h @@ -235,10 +235,6 @@ /// @} - /// Used to insert APFloat objects, or objects that contain APFloat objects, - /// into FoldingSets. - void Profile(FoldingSetNodeID &NID) const; - /// \name Arithmetic /// @{ @@ -255,53 +251,12 @@ /// 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 @@ 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 @@ /// 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 @@ 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 @@ 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 &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 @@ -766,7 +767,15 @@ } } - void makeZero(bool Neg) { getIEEE().makeZero(Neg); } + void makeZero(bool Neg) { + if (usesLayout(getSemantics())) { + return U.IEEE.makeZero(Neg); + } else if (usesLayout(getSemantics())) { + return U.Double.makeZero(Neg); + } else { + llvm_unreachable("Unexpected semantics"); + } + } void makeInf(bool Neg) { if (usesLayout(*U.semantics)) { @@ -779,15 +788,43 @@ } void makeNaN(bool SNaN, bool Neg, const APInt *fill) { - getIEEE().makeNaN(SNaN, Neg, fill); + if (usesLayout(getSemantics())) { + return U.IEEE.makeNaN(SNaN, Neg, fill); + } else if (usesLayout(getSemantics())) { + return U.Double.makeNaN(SNaN, Neg, fill); + } else { + llvm_unreachable("Unexpected semantics"); + } } - void makeLargest(bool Neg) { getIEEE().makeLargest(Neg); } + void makeLargest(bool Neg) { + if (usesLayout(getSemantics())) { + return U.IEEE.makeLargest(Neg); + } else if (usesLayout(getSemantics())) { + return U.Double.makeLargest(Neg); + } else { + llvm_unreachable("Unexpected semantics"); + } + } - void makeSmallest(bool Neg) { getIEEE().makeSmallest(Neg); } + void makeSmallest(bool Neg) { + if (usesLayout(getSemantics())) { + return U.IEEE.makeSmallest(Neg); + } else if (usesLayout(getSemantics())) { + return U.Double.makeSmallest(Neg); + } else { + llvm_unreachable("Unexpected semantics"); + } + } void makeSmallestNormalized(bool Neg) { - getIEEE().makeSmallestNormalized(Neg); + if (usesLayout(getSemantics())) { + return U.IEEE.makeSmallestNormalized(Neg); + } else if (usesLayout(getSemantics())) { + return U.Double.makeSmallestNormalized(Neg); + } else { + llvm_unreachable("Unexpected semantics"); + } } // FIXME: This is due to clang 3.3 (or older version) always checks for the @@ -802,7 +839,8 @@ : U(std::move(F), S) {} cmpResult compareAbsoluteValue(const APFloat &RHS) const { - assert(&getSemantics() == &RHS.getSemantics()); + assert(&getSemantics() == &RHS.getSemantics() && + "Should only compare APFloats with the same semantics"); if (usesLayout(getSemantics())) { return U.IEEE.compareAbsoluteValue(RHS.U.IEEE); } else if (usesLayout(getSemantics())) { @@ -922,9 +960,13 @@ /// \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() && + "Should only call on two APFloats with the same semantics"); if (usesLayout(getSemantics())) { return U.IEEE.add(RHS.U.IEEE, RM); } else if (usesLayout(getSemantics())) { @@ -934,6 +976,8 @@ } } opStatus subtract(const APFloat &RHS, roundingMode RM) { + assert(&getSemantics() == &RHS.getSemantics() && + "Should only call on two APFloats with the same semantics"); if (usesLayout(getSemantics())) { return U.IEEE.subtract(RHS.U.IEEE, RM); } else if (usesLayout(getSemantics())) { @@ -943,48 +987,139 @@ } } 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(getSemantics())) { + return U.IEEE.multiply(RHS.U.IEEE, RM); + } else if (usesLayout(getSemantics())) { + return U.Double.multiply(RHS.U.Double, RM); + } else { + 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(getSemantics())) { + return U.IEEE.divide(RHS.U.IEEE, RM); + } else if (usesLayout(getSemantics())) { + return U.Double.divide(RHS.U.Double, RM); + } else { + 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(getSemantics())) { + return U.IEEE.remainder(RHS.U.IEEE); + } else if (usesLayout(getSemantics())) { + return U.Double.remainder(RHS.U.Double); + } else { + 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(getSemantics())) { + return U.IEEE.mod(RHS.U.IEEE); + } else if (usesLayout(getSemantics())) { + return U.Double.mod(RHS.U.Double); + } else { + 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(getSemantics())) { + return U.IEEE.fusedMultiplyAdd(Multiplicand.U.IEEE, Addend.U.IEEE, RM); + } else if (usesLayout(getSemantics())) { + return U.Double.fusedMultiplyAdd(Multiplicand.U.Double, Addend.U.Double, + RM); + } else { + llvm_unreachable("Unexpected semantics"); + } } opStatus roundToIntegral(roundingMode RM) { - return getIEEE().roundToIntegral(RM); + if (usesLayout(getSemantics())) { + return U.IEEE.roundToIntegral(RM); + } else if (usesLayout(getSemantics())) { + return U.Double.roundToIntegral(RM); + } else { + llvm_unreachable("Unexpected semantics"); + } } - opStatus next(bool nextDown) { return getIEEE().next(nextDown); } + opStatus next(bool nextDown) { + if (usesLayout(getSemantics())) { + return U.IEEE.next(nextDown); + } else if (usesLayout(getSemantics())) { + return U.Double.next(nextDown); + } else { + llvm_unreachable("Unexpected semantics"); + } + } + + /// \brief Operator+ overload which provides the default + /// \c nmNearestTiesToEven 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 nmNearestTiesToEven 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 nmNearestTiesToEven 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 nmNearestTiesToEven 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(getSemantics())) { + return U.IEEE.changeSign(); + } else if (usesLayout(getSemantics())) { + return U.Double.changeSign(); + } else { + 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, @@ -992,46 +1127,100 @@ opStatus convertToInteger(integerPart *Input, unsigned int Width, bool IsSigned, roundingMode RM, bool *IsExact) const { - return getIEEE().convertToInteger(Input, Width, IsSigned, RM, IsExact); + if (usesLayout(getSemantics())) { + return U.IEEE.convertToInteger(Input, Width, IsSigned, RM, IsExact); + } else if (usesLayout(getSemantics())) { + return U.Double.convertToInteger(Input, Width, IsSigned, RM, IsExact); + } else { + 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(getSemantics())) { + return U.IEEE.convertFromAPInt(Input, IsSigned, RM); + } else if (usesLayout(getSemantics())) { + return U.Double.convertFromAPInt(Input, IsSigned, RM); + } else { + 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(getSemantics())) { + return U.IEEE.convertFromSignExtendedInteger(Input, InputSize, IsSigned, + RM); + } else if (usesLayout(getSemantics())) { + return U.Double.convertFromSignExtendedInteger(Input, InputSize, IsSigned, + RM); + } else { + 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(getSemantics())) { + return U.IEEE.convertFromZeroExtendedInteger(Input, InputSize, IsSigned, + RM); + } else if (usesLayout(getSemantics())) { + return U.Double.convertFromZeroExtendedInteger(Input, InputSize, IsSigned, + RM); + } else { + llvm_unreachable("Unexpected semantics"); + } } opStatus convertFromString(StringRef, roundingMode); - APInt bitcastToAPInt() const { return getIEEE().bitcastToAPInt(); } + APInt bitcastToAPInt() const { + if (usesLayout(getSemantics())) { + return U.IEEE.bitcastToAPInt(); + } else if (usesLayout(getSemantics())) { + return U.Double.bitcastToAPInt(); + } else { + 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(getSemantics())) { + return U.IEEE.compare(RHS.U.IEEE); + } else if (usesLayout(getSemantics())) { + return U.Double.compare(RHS.U.Double); + } else { + llvm_unreachable("Unexpected semantics"); + } } bool bitwiseIsEqual(const APFloat &RHS) const { - return getIEEE().bitwiseIsEqual(RHS.getIEEE()); + if (&getSemantics() != &RHS.getSemantics()) + return false; + if (usesLayout(getSemantics())) { + return U.IEEE.bitwiseIsEqual(RHS.U.IEEE); + } else if (usesLayout(getSemantics())) { + return U.Double.bitwiseIsEqual(RHS.U.Double); + } else { + 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(getSemantics())) { + return U.IEEE.convertToHexString(DST, HexDigits, UpperCase, RM); + } else if (usesLayout(getSemantics())) { + return U.Double.convertToHexString(DST, HexDigits, UpperCase, RM); + } else { + llvm_unreachable("Unexpected semantics"); + } } bool isZero() const { return getCategory() == fcZero; } @@ -1039,7 +1228,15 @@ bool isNaN() const { return getCategory() == fcNaN; } bool isNegative() const { return getIEEE().isNegative(); } - bool isDenormal() const { return getIEEE().isDenormal(); } + bool isDenormal() const { + if (usesLayout(getSemantics())) { + return U.IEEE.isDenormal(); + } else if (usesLayout(getSemantics())) { + return U.Double.isDenormal(); + } else { + llvm_unreachable("Unexpected semantics"); + } + } bool isSignaling() const { return getIEEE().isSignaling(); } bool isNormal() const { return !isDenormal() && isFiniteNonZero(); } @@ -1051,30 +1248,59 @@ 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(getSemantics())) { + return U.IEEE.isSmallest(); + } else if (usesLayout(getSemantics())) { + return U.Double.isSmallest(); + } else { + llvm_unreachable("Unexpected semantics"); + } + } + bool isLargest() const { + if (usesLayout(getSemantics())) { + return U.IEEE.isLargest(); + } else if (usesLayout(getSemantics())) { + return U.Double.isLargest(); + } else { + llvm_unreachable("Unexpected semantics"); + } + } + bool isInteger() const { + if (usesLayout(getSemantics())) { + return U.IEEE.isInteger(); + } else if (usesLayout(getSemantics())) { + return U.Double.isInteger(); + } else { + llvm_unreachable("Unexpected semantics"); + } + } APFloat &operator=(const APFloat &RHS) = default; APFloat &operator=(APFloat &&RHS) = default; void toString(SmallVectorImpl &Str, unsigned FormatPrecision = 0, unsigned FormatMaxPadding = 3) const { - return getIEEE().toString(Str, FormatPrecision, FormatMaxPadding); + if (usesLayout(getSemantics())) { + return U.IEEE.toString(Str, FormatPrecision, FormatMaxPadding); + } else if (usesLayout(getSemantics())) { + return U.Double.toString(Str, FormatPrecision, FormatMaxPadding); + } else { + 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(getSemantics())) { + return U.IEEE.getExactInverse(inv); + } else if (usesLayout(getSemantics())) { + return U.Double.getExactInverse(inv); + } else { + llvm_unreachable("Unexpected semantics"); + } } friend hash_code hash_value(const APFloat &Arg); @@ -1091,7 +1317,13 @@ /// 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(X.getSemantics())) { + return APFloat(scalbn(X.U.IEEE, Exp, RM), X.getSemantics()); + } else if (APFloat::usesLayout(X.getSemantics())) { + return APFloat(scalbn(X.U.Double, Exp, RM), X.getSemantics()); + } else { + llvm_unreachable("Unexpected semantics"); + } } /// \brief Equivalent of C standard library function. @@ -1099,7 +1331,13 @@ /// 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(X.getSemantics())) { + return APFloat(frexp(X.U.IEEE, Exp, RM), X.getSemantics()); + } else if (APFloat::usesLayout(X.getSemantics())) { + return APFloat(frexp(X.U.Double, Exp, RM), X.getSemantics()); + } else { + llvm_unreachable("Unexpected semantics"); + } } /// \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 @@ -858,11 +858,6 @@ 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); } @@ -1607,16 +1602,6 @@ 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, @@ -1836,7 +1821,7 @@ IEEEFloat MagicConstant(*semantics); fs = MagicConstant.convertFromAPInt(IntegerConstant, false, rmNearestTiesToEven); - MagicConstant.copySign(*this); + MagicConstant.sign = sign; if (fs != opOK) return fs; @@ -2181,22 +2166,6 @@ 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 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. */ @@ -3616,7 +3585,7 @@ 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; @@ -3640,7 +3609,7 @@ reciprocal.significandLSB() == reciprocal.semantics->precision - 1); if (inv) - *inv = reciprocal; + *inv = APFloat(reciprocal, *semantics); return true; } @@ -3852,28 +3821,29 @@ } 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); } @@ -3882,9 +3852,7 @@ : 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); } @@ -4029,25 +3997,15 @@ } 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, @@ -4063,6 +4021,82 @@ return Ret; } +APFloat::opStatus DoubleAPFloat::multiply(const DoubleAPFloat &RHS, + APFloat::roundingMode RM) { + if (Semantics == &semPPCDoubleDouble) { + APFloat Tmp(semPPCDoubleDoubleImpl, bitcastToAPInt()); + auto Ret = + Tmp.multiply(APFloat(semPPCDoubleDoubleImpl, RHS.bitcastToAPInt()), RM); + *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt()); + return Ret; + } else { + llvm_unreachable("Only PPCDoubleDouble is supported for now"); + } +} + +APFloat::opStatus DoubleAPFloat::divide(const DoubleAPFloat &RHS, + APFloat::roundingMode RM) { + if (Semantics == &semPPCDoubleDouble) { + APFloat Tmp(semPPCDoubleDoubleImpl, bitcastToAPInt()); + auto Ret = + Tmp.divide(APFloat(semPPCDoubleDoubleImpl, RHS.bitcastToAPInt()), RM); + *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt()); + return Ret; + } else { + llvm_unreachable("Only PPCDoubleDouble is supported for now"); + } +} + +APFloat::opStatus DoubleAPFloat::remainder(const DoubleAPFloat &RHS) { + if (Semantics == &semPPCDoubleDouble) { + APFloat Tmp(semPPCDoubleDoubleImpl, bitcastToAPInt()); + auto Ret = + Tmp.remainder(APFloat(semPPCDoubleDoubleImpl, RHS.bitcastToAPInt())); + *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt()); + return Ret; + } else { + llvm_unreachable("Only PPCDoubleDouble is supported for now"); + } +} + +APFloat::opStatus DoubleAPFloat::mod(const DoubleAPFloat &RHS) { + if (Semantics == &semPPCDoubleDouble) { + APFloat Tmp(semPPCDoubleDoubleImpl, bitcastToAPInt()); + auto Ret = Tmp.mod(APFloat(semPPCDoubleDoubleImpl, RHS.bitcastToAPInt())); + *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt()); + return Ret; + } else { + llvm_unreachable("Only PPCDoubleDouble is supported for now"); + } +} + +APFloat::opStatus +DoubleAPFloat::fusedMultiplyAdd(const DoubleAPFloat &Multiplicand, + const DoubleAPFloat &Addend, + APFloat::roundingMode RM) { + if (Semantics == &semPPCDoubleDouble) { + APFloat Tmp(semPPCDoubleDoubleImpl, bitcastToAPInt()); + auto Ret = Tmp.fusedMultiplyAdd( + APFloat(semPPCDoubleDoubleImpl, Multiplicand.bitcastToAPInt()), + APFloat(semPPCDoubleDoubleImpl, Addend.bitcastToAPInt()), RM); + *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt()); + return Ret; + } else { + llvm_unreachable("Only PPCDoubleDouble is supported for now"); + } +} + +APFloat::opStatus DoubleAPFloat::roundToIntegral(APFloat::roundingMode RM) { + if (Semantics == &semPPCDoubleDouble) { + APFloat Tmp(semPPCDoubleDoubleImpl, bitcastToAPInt()); + auto Ret = Tmp.roundToIntegral(RM); + *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt()); + return Ret; + } else { + llvm_unreachable("Only PPCDoubleDouble is supported for now"); + } +} + void DoubleAPFloat::changeSign() { Floats[0].changeSign(); Floats[1].changeSign(); @@ -4100,11 +4134,249 @@ Floats[1].makeZero(false); } +void DoubleAPFloat::makeZero(bool Neg) { + Floats[0].makeZero(Neg); + Floats[1].makeZero(false); +} + +void DoubleAPFloat::makeLargest(bool Neg) { + if (Semantics == &semPPCDoubleDouble) { + Floats[0] = APFloat(semIEEEdouble, APInt(64, 0x7fefffffffffffffull)); + Floats[1] = APFloat(semIEEEdouble, APInt(64, 0x7c8ffffffffffffeull)); + if (Neg) + changeSign(); + } else { + llvm_unreachable("Only PPCDoubleDouble is supported for now"); + } +} + +void DoubleAPFloat::makeSmallest(bool Neg) { + if (Semantics == &semPPCDoubleDouble) { + Floats[0].makeSmallest(Neg); + Floats[1].makeZero(false); + } else { + llvm_unreachable("Only PPCDoubleDouble is supported for now"); + } +} + +void DoubleAPFloat::makeSmallestNormalized(bool Neg) { + if (Semantics == &semPPCDoubleDouble) { + Floats[0] = APFloat(semIEEEdouble, APInt(64, 0x0360000000000000ull)); + if (Neg) + Floats[0].changeSign(); + Floats[1].makeZero(false); + } else { + llvm_unreachable("Only PPCDoubleDouble is supported for now"); + } +} + 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 { + if (Semantics == &semPPCDoubleDouble) { + uint64_t Data[] = { + Floats[0].bitcastToAPInt().getRawData()[0], + Floats[1].bitcastToAPInt().getRawData()[0], + }; + return APInt(128, 2, Data); + } else { + llvm_unreachable("Only PPCDoubleDouble is supported for now"); + } +} + +APFloat::opStatus DoubleAPFloat::convertFromString(StringRef S, + roundingMode RM) { + if (Semantics == &semPPCDoubleDouble) { + APFloat Tmp(semPPCDoubleDoubleImpl); + auto Ret = Tmp.convertFromString(S, RM); + *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt()); + return Ret; + } else { + llvm_unreachable("Only PPCDoubleDouble is supported for now"); + } +} + +APFloat::opStatus DoubleAPFloat::next(bool nextDown) { + if (Semantics == &semPPCDoubleDouble) { + APFloat Tmp(semPPCDoubleDoubleImpl, bitcastToAPInt()); + auto Ret = Tmp.next(nextDown); + *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt()); + return Ret; + } else { + llvm_unreachable("Only PPCDoubleDouble is supported for now"); + } +} + +APFloat::opStatus DoubleAPFloat::convertToInteger(integerPart *Input, + unsigned int Width, + bool IsSigned, + roundingMode RM, + bool *IsExact) const { + if (Semantics == &semPPCDoubleDouble) { + return APFloat(semPPCDoubleDoubleImpl, bitcastToAPInt()) + .convertToInteger(Input, Width, IsSigned, RM, IsExact); + } else { + llvm_unreachable("Only PPCDoubleDouble is supported for now"); + } +} + +APFloat::opStatus DoubleAPFloat::convertFromAPInt(const APInt &Input, + bool IsSigned, + roundingMode RM) { + if (Semantics == &semPPCDoubleDouble) { + APFloat Tmp(semPPCDoubleDoubleImpl); + auto Ret = Tmp.convertFromAPInt(Input, IsSigned, RM); + *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt()); + return Ret; + } else { + llvm_unreachable("Only PPCDoubleDouble is supported for now"); + } +} + +APFloat::opStatus +DoubleAPFloat::convertFromSignExtendedInteger(const integerPart *Input, + unsigned int InputSize, + bool IsSigned, roundingMode RM) { + if (Semantics == &semPPCDoubleDouble) { + APFloat Tmp(semPPCDoubleDoubleImpl); + auto Ret = + Tmp.convertFromSignExtendedInteger(Input, InputSize, IsSigned, RM); + *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt()); + return Ret; + } else { + llvm_unreachable("Only PPCDoubleDouble is supported for now"); + } +} + +APFloat::opStatus +DoubleAPFloat::convertFromZeroExtendedInteger(const integerPart *Input, + unsigned int InputSize, + bool IsSigned, roundingMode RM) { + if (Semantics == &semPPCDoubleDouble) { + APFloat Tmp(semPPCDoubleDoubleImpl); + auto Ret = + Tmp.convertFromZeroExtendedInteger(Input, InputSize, IsSigned, RM); + *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt()); + return Ret; + } else { + llvm_unreachable("Only PPCDoubleDouble is supported for now"); + } +} + +unsigned int DoubleAPFloat::convertToHexString(char *DST, + unsigned int HexDigits, + bool UpperCase, + roundingMode RM) const { + if (Semantics == &semPPCDoubleDouble) { + return APFloat(semPPCDoubleDoubleImpl, bitcastToAPInt()) + .convertToHexString(DST, HexDigits, UpperCase, RM); + } else { + llvm_unreachable("Only PPCDoubleDouble is supported for now"); + } +} + +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 { + if (Semantics == &semPPCDoubleDouble) { + APFloat Tmp(semPPCDoubleDoubleImpl); + (void)Tmp.add(Floats[0], rmNearestTiesToEven); + (void)Tmp.add(Floats[1], rmNearestTiesToEven); + return Tmp.isInteger(); + } else { + llvm_unreachable("Only PPCDoubleDouble is supported for now"); + } +} + +void DoubleAPFloat::toString(SmallVectorImpl &Str, + unsigned FormatPrecision, + unsigned FormatMaxPadding) const { + if (Semantics == &semPPCDoubleDouble) { + APFloat(semPPCDoubleDoubleImpl, bitcastToAPInt()) + .toString(Str, FormatPrecision, FormatMaxPadding); + } else { + llvm_unreachable("Only PPCDoubleDouble is supported for now"); + } +} + +bool DoubleAPFloat::getExactInverse(APFloat *inv) const { + if (Semantics == &semPPCDoubleDouble) { + APFloat Tmp(semPPCDoubleDoubleImpl, bitcastToAPInt()); + if (!inv) + return Tmp.getExactInverse(nullptr); + APFloat Inv(semPPCDoubleDoubleImpl); + auto Ret = Tmp.getExactInverse(&Inv); + *inv = APFloat(semPPCDoubleDouble, Inv.bitcastToAPInt()); + return Ret; + } else { + llvm_unreachable("Only PPCDoubleDouble is supported for now"); + } +} + +DoubleAPFloat scalbn(DoubleAPFloat Arg, int Exp, APFloat::roundingMode RM) { + if (Arg.Semantics == &semPPCDoubleDouble) { + return DoubleAPFloat(semPPCDoubleDouble, scalbn(Arg.Floats[0], Exp, RM), + scalbn(Arg.Floats[1], Exp, RM)); + } else { + llvm_unreachable("Only PPCDoubleDouble is supported for now"); + } +} + +DoubleAPFloat frexp(const DoubleAPFloat &Arg, int &Exp, + APFloat::roundingMode RM) { + if (Arg.Semantics == &semPPCDoubleDouble) { + 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)); + } else { + llvm_unreachable("Only PPCDoubleDouble is supported for now"); + } +} + } // End detail namespace APFloat::Storage::Storage(IEEEFloat F, const fltSemantics &Semantics) { @@ -4120,10 +4392,24 @@ } APFloat::opStatus APFloat::convertFromString(StringRef Str, roundingMode RM) { - return getIEEE().convertFromString(Str, RM); + if (usesLayout(getSemantics())) { + return U.IEEE.convertFromString(Str, RM); + } else if (usesLayout(getSemantics())) { + return U.Double.convertFromString(Str, RM); + } else { + 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(Arg.getSemantics())) { + return hash_value(Arg.U.IEEE); + } else if (APFloat::usesLayout(Arg.getSemantics())) { + return hash_value(Arg.U.Double); + } else { + llvm_unreachable("Unexpected semantics"); + } +} APFloat::APFloat(const fltSemantics &Semantics, StringRef S) : APFloat(Semantics) { @@ -4141,9 +4427,7 @@ usesLayout(ToSemantics)) { assert(&ToSemantics == &semPPCDoubleDouble); auto Ret = U.IEEE.convert(semPPCDoubleDoubleImpl, RM, losesInfo); - *this = APFloat( - DoubleAPFloat(semPPCDoubleDouble, std::move(*this), APFloat(semIEEEdouble)), - ToSemantics); + *this = APFloat(ToSemantics, U.IEEE.bitcastToAPInt()); return Ret; } else if (usesLayout(getSemantics()) && usesLayout(ToSemantics)) { @@ -4185,4 +4469,24 @@ 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 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 Index: llvm/test/CodeGen/PowerPC/fp128-bitcast-after-operation.ll =================================================================== --- llvm/test/CodeGen/PowerPC/fp128-bitcast-after-operation.ll +++ llvm/test/CodeGen/PowerPC/fp128-bitcast-after-operation.ll @@ -128,7 +128,7 @@ ; 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 } Index: llvm/unittests/ADT/APFloatTest.cpp =================================================================== --- llvm/unittests/ADT/APFloatTest.cpp +++ llvm/unittests/ADT/APFloatTest.cpp @@ -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" @@ -3262,7 +3263,7 @@ << 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 @@ << 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 @@ 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; + + 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 @@ } { 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 @@ } { 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]); +} }